]> git.tdb.fi Git - libs/gl.git/blob - source/lighting.cpp
Bind textures in the modern way when shaders are used
[libs/gl.git] / source / lighting.cpp
1 #include <stdexcept>
2 #include <cmath>
3 #include <msp/gl/extensions/msp_legacy_features.h>
4 #include "error.h"
5 #include "light.h"
6 #include "lighting.h"
7 #include "lightunit.h"
8 #include "matrix.h"
9 #include "misc.h"
10
11 using namespace std;
12
13 namespace Msp {
14 namespace GL {
15
16 Lighting::Lighting():
17         ambient(0.2),
18         zenith_direction(0, 0, 1),
19         horizon_angle(Geometry::Angle<float>::zero()),
20         fog_color(0.0f, 0.0f, 0.0f, 0.0f),
21         fog_density(0.0f)
22 { }
23
24 Lighting::~Lighting()
25 {
26         for(vector<Light *>::iterator i=owned_data.begin(); i!=owned_data.end(); ++i)
27                 delete *i;
28 }
29
30 void Lighting::set_ambient(const Color &a)
31 {
32         ambient = a;
33 }
34
35 void Lighting::set_sky_color(const Color &s)
36 {
37         sky_color = s;
38 }
39
40 void Lighting::set_zenith_direction(const Vector3 &d)
41 {
42         zenith_direction = d;
43 }
44
45 void Lighting::set_horizon_angle(const Geometry::Angle<float> &a)
46 {
47         horizon_angle = a;
48 }
49
50 void Lighting::set_fog_color(const Color &c)
51 {
52         fog_color = c;
53 }
54
55 void Lighting::set_fog_density(float d)
56 {
57         if(d<0)
58                 throw invalid_argument("Lighting::set_fog_density");
59
60         fog_density = d;
61 }
62
63 void Lighting::set_fog_half_distance(float d)
64 {
65         set_fog_density(-log(pow(0.5, 1.0/d)));
66 }
67
68 void Lighting::attach(unsigned i, const Light &l)
69 {
70         if(i>=lights.size())
71                 lights.resize(i+1);
72
73         lights[i] = &l;
74         if(current()==this)
75                 l.bind_to(i);
76 }
77
78 void Lighting::detach(unsigned i)
79 {
80         if(i>=lights.size())
81                 return;
82
83         lights[i] = 0;
84         if(current()==this)
85                 Light::unbind_from(i);
86 }
87
88 const Light *Lighting::get_attached_light(unsigned i) const
89 {
90         return i<lights.size() ? lights[i] : 0;
91 }
92
93 void Lighting::update_shader_data(ProgramData &shdata, const Matrix &view_matrix) const
94 {
95         shdata.uniform("ambient_color", ambient);
96         shdata.uniform("sky_color", sky_color);
97         shdata.uniform("eye_zenith_dir", view_matrix.block<3, 3>(0, 0)*zenith_direction);
98         shdata.uniform("horizon_limit", horizon_angle.radians());
99         shdata.uniform("fog_color", fog_color);
100         shdata.uniform("fog_density", fog_density);
101
102         // For backwards compatibility
103         shdata.uniform("eye_sky_dir", view_matrix.block<3, 3>(0, 0)*zenith_direction);
104
105         for(unsigned i=0; i<lights.size(); ++i)
106                 if(lights[i])
107                         lights[i]->update_shader_data(shdata, view_matrix, i);
108 }
109
110 void Lighting::bind() const
111 {
112         static Require _req(MSP_legacy_features);
113         if(lights.size()>LightUnit::get_n_units())
114                 throw invalid_operation("Lighting::bind");
115
116         const Lighting *old = current();
117         if(!set_current(this))
118                 return;
119
120         enable(GL_LIGHTING);
121         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &ambient.r);
122         for(unsigned i=0; i<lights.size(); ++i)
123         {
124                 if(lights[i])
125                         lights[i]->bind_to(i);
126                 else
127                         Light::unbind_from(i);
128         }
129
130         if(old)
131         {
132                 for(unsigned i=lights.size(); i<old->lights.size(); ++i)
133                         Light::unbind_from(i);
134         }
135
136         if(fog_density)
137         {
138                 enable(GL_FOG);
139                 glFogi(GL_FOG_MODE, GL_EXP);
140                 glFogf(GL_FOG_DENSITY, fog_density);
141                 glFogfv(GL_FOG_COLOR, &fog_color.r);
142         }
143 }
144
145 void Lighting::unbind()
146 {
147         const Lighting *old = current();
148         if(!set_current(0))
149                 return;
150
151         for(unsigned i=0; i<old->lights.size(); ++i)
152                 if(old->lights[i])
153                         Light::unbind_from(i);
154
155         disable(GL_LIGHTING);
156         if(old->fog_density)
157                 disable(GL_FOG);
158 }
159
160
161 Lighting::Loader::Loader(Lighting &l):
162         DataFile::ObjectLoader<Lighting>(l)
163 {
164         add("ambient", &Loader::ambient);
165         add("fog_color", &Loader::fog_color);
166         add("fog_density", &Loader::fog_density);
167         add("fog_half_distance", &Loader::fog_half_distance);
168         add("horizon_angle", &Loader::horizon_angle);
169         add("light", &Loader::light);
170         add("sky_color", &Loader::sky_color);
171         add("zenith_direction", &Loader::zenith_direction);
172 }
173
174 void Lighting::Loader::ambient(float r, float g, float b)
175 {
176         obj.ambient = Color(r, g, b);
177 }
178
179 void Lighting::Loader::fog_color(float r, float g, float b)
180 {
181         obj.set_fog_color(Color(r, g, b));
182 }
183
184 void Lighting::Loader::fog_density(float d)
185 {
186         obj.set_fog_density(d);
187 }
188
189 void Lighting::Loader::fog_half_distance(float d)
190 {
191         obj.set_fog_half_distance(d);
192 }
193
194 void Lighting::Loader::horizon_angle(float a)
195 {
196         obj.set_horizon_angle(Geometry::Angle<float>::from_degrees(a));
197 }
198
199 void Lighting::Loader::light(unsigned i)
200 {
201         RefPtr<Light> lgt = new Light;
202         load_sub(*lgt);
203         obj.attach(i, *lgt);
204         obj.owned_data.push_back(lgt.release());
205 }
206
207 void Lighting::Loader::sky_color(float r, float g, float b)
208 {
209         obj.set_sky_color(Color(r, g, b));
210 }
211
212 void Lighting::Loader::zenith_direction(float x, float y, float z)
213 {
214         obj.set_sky_direction(Vector3(x, y, z));
215 }
216
217 } // namespace GL
218 } // namespace Msp