]> git.tdb.fi Git - libs/gl.git/blob - source/shadowmap.cpp
Use the TexGen wrapper in ShadowMap
[libs/gl.git] / source / shadowmap.cpp
1 #include <cmath>
2 #include <cstdlib>
3 #include "light.h"
4 #include "matrix.h"
5 #include "misc.h"
6 #include "renderer.h"
7 #include "scene.h"
8 #include "shadowmap.h"
9 #include "texgen.h"
10 #include "texunit.h"
11
12 using namespace std;
13
14 namespace Msp {
15 namespace GL {
16
17 ShadowMap::ShadowMap(unsigned s, const Renderable &r, const Light &l):
18         Effect(r),
19         size(s),
20         light(l),
21         unit(3),
22         radius(1)
23 {
24         depth_buf.set_min_filter(LINEAR);
25         depth_buf.set_compare_enabled(true);
26         depth_buf.set_compare_func(LEQUAL);
27         depth_buf.set_wrap(CLAMP_TO_EDGE);
28         depth_buf.storage(DEPTH_COMPONENT, size, size);
29         fbo.attach(DEPTH_ATTACHMENT, depth_buf, 0);
30 }
31
32 void ShadowMap::set_target(const Vector3 &t, float r)
33 {
34         target = t;
35         radius = r;
36 }
37
38 void ShadowMap::set_texture_unit(unsigned u)
39 {
40         unit = u;
41 }
42
43 void ShadowMap::render(Renderer &renderer, const Tag &tag) const
44 {
45         if(!enabled_passes.count(tag))
46                 return renderable.render(renderer, tag);
47
48         Vector4 lpos = light.get_position();
49         if(lpos.w)
50         {
51                 /* XXX Not really proper way to support positional lights, but good
52                 enough when the light source is far away */
53                 lpos.x -= target.x;
54                 lpos.y -= target.y;
55                 lpos.z -= target.z;
56                 float d = sqrt(lpos.x*lpos.x+lpos.y*lpos.y+lpos.z*lpos.z);
57                 lpos.x /= d;
58                 lpos.y /= d;
59                 lpos.z /= d;
60         }
61
62         float matrix[16];
63         if(abs(lpos.z)>=abs(lpos.x) && abs(lpos.z)>=abs(lpos.y))
64         {
65                 float d = sqrt(lpos.x*lpos.x+lpos.z*lpos.z);
66                 matrix[0] = lpos.z/d;
67                 matrix[4] = 0;
68                 matrix[8] = -lpos.x/d;
69                 matrix[1] = -lpos.x*lpos.y/d;
70                 matrix[5] = d;
71                 matrix[9] = -lpos.z*lpos.y/d;
72         }
73         else
74         {
75                 float d = sqrt(lpos.x*lpos.x+lpos.y*lpos.y);
76                 matrix[0] = -lpos.y/d;
77                 matrix[4] = lpos.x/d;
78                 matrix[8] = 0;
79                 matrix[1] = -lpos.x*lpos.z/d;
80                 matrix[5] = -lpos.y*lpos.z/d;
81                 matrix[9] = d;
82         }
83
84         matrix[2] = lpos.x;
85         matrix[6] = lpos.y;
86         matrix[10] = lpos.z;
87
88         matrix[12] = -(target.x*matrix[0]+target.y*matrix[4]+target.z*matrix[8]);
89         matrix[13] = -(target.x*matrix[1]+target.y*matrix[5]+target.z*matrix[9]);
90         matrix[14] = -(target.x*matrix[2]+target.y*matrix[6]+target.z*matrix[10]);
91         matrix[3] = 0;
92         matrix[7] = 0;
93         matrix[11] = 0;
94         matrix[15] = 1;
95
96         renderer.escape();
97
98         {
99                 MatrixStack::Push push_mv(MatrixStack::modelview());
100                 MatrixStack::Push push_proj(MatrixStack::projection());
101
102                 MatrixStack::projection() = Matrix::ortho(-radius, radius, -radius, radius, -radius, radius);
103                 MatrixStack::modelview() = matrix;
104
105                 Bind bind_fbo(fbo, true);
106                 fbo.clear(DEPTH_BUFFER_BIT);
107                 renderable.render("shadow");
108         }
109
110         // Has side effect of changing the current unit
111         depth_buf.bind_to(unit);
112         float diam = radius*2;
113         TexGen tg_s, tg_t, tg_r;
114         tg_s.set_plane(Vector4(matrix[0]/diam, matrix[4]/diam, matrix[8]/diam, matrix[12]/diam+0.5f));
115         tg_t.set_plane(Vector4(matrix[1]/diam, matrix[5]/diam, matrix[9]/diam, matrix[13]/diam+0.5f));
116         tg_r.set_plane(Vector4(-matrix[2]/diam, -matrix[6]/diam, -matrix[10]/diam, 0.5f-matrix[14]/diam-4.0f/size));
117         tg_s.bind_to(SCOORD);
118         tg_t.bind_to(TCOORD);
119         tg_r.bind_to(RCOORD);
120         TexUnit::activate(0);
121
122         renderable.render(renderer, tag);
123
124         Texture::unbind_from(unit);
125         TexGen::unbind_from(SCOORD);
126         TexGen::unbind_from(TCOORD);
127         TexGen::unbind_from(RCOORD);
128         TexUnit::activate(0);
129 }
130
131 } // namespace GL
132 } // namespace Msp