2 #include <msp/gl/extensions/msp_legacy_features.h>
3 #include <msp/strings/format.h>
8 #include "programdata.h"
21 spot_cutoff(Geometry::Angle<float>::straight())
30 while(LightUnit *unit = LightUnit::find_unit(this))
31 unbind_from(unit->get_index());
34 void Light::update_parameter(int mask, int index) const
38 LightUnit *unit = LightUnit::find_unit(this);
42 index = unit->get_index();
45 GLenum l = GL_LIGHT0+index;
47 glLightfv(l, GL_DIFFUSE, &diffuse.r);
49 glLightfv(l, GL_SPECULAR, &specular.r);
51 glLightfv(l, GL_POSITION, &position.x);
53 glLightfv(l, GL_SPOT_DIRECTION, &spot_dir.x);
55 glLightf(l, GL_SPOT_EXPONENT, spot_exp);
57 glLightf(l, GL_SPOT_CUTOFF, spot_cutoff.degrees());
60 glLightf(l, GL_CONSTANT_ATTENUATION, attenuation[0]);
61 glLightf(l, GL_LINEAR_ATTENUATION, attenuation[1]);
62 glLightf(l, GL_QUADRATIC_ATTENUATION, attenuation[2]);
66 void Light::update_matrix()
69 if(20*abs(direction.z)>abs(direction.x)+abs(direction.y))
73 Vector3 right_dir = normalize(cross(direction, up_dir));
76 columns[0] = compose(right_dir, 0.0f);
77 columns[1] = compose(cross(right_dir, direction), 0.0f);
78 columns[2] = compose(-direction, 0.0f);
79 columns[3] = position;
80 matrix = Matrix::from_columns(columns);
83 void Light::set_diffuse(const Color &c)
86 update_parameter(DIFFUSE);
89 void Light::set_specular(const Color &c)
92 update_parameter(SPECULAR);
95 void Light::set_matrix(const Matrix &m)
97 Placeable::set_matrix(m);
98 position = matrix.column(3);
99 spot_dir = normalize(-matrix.column(2).slice<3>(0));
100 direction = (position.w ? spot_dir : normalize(-position.slice<3>(0)));
101 update_parameter(POSITION|SPOT_DIR);
105 void Light::set_position(const Vector4 &p)
108 update_parameter(POSITION);
110 direction = normalize(-position.slice<3>(0));
114 void Light::set_spot_direction(const Vector3 &d)
116 spot_dir = normalize(d);
118 direction = spot_dir;
119 update_parameter(SPOT_DIR);
123 void Light::set_spot_exponent(float e)
126 throw invalid_argument("Light::set_spot_exponent");
129 update_parameter(SPOT_EXP);
132 void Light::set_spot_cutoff(float c)
134 set_spot_cutoff(Geometry::Angle<float>::from_degrees(c));
137 void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
139 if(c<Geometry::Angle<float>::zero() || (c>Geometry::Angle<float>::right() && c!=Geometry::Angle<float>::straight()))
140 throw invalid_argument("Light::set_spot_cutoff");
143 update_parameter(SPOT_CUTOFF);
146 void Light::disable_spot_cutoff()
148 set_spot_cutoff(Geometry::Angle<float>::straight());
151 void Light::set_attenuation(float c, float l, float q)
156 update_parameter(ATTENUATION);
159 void Light::update_shader_data(ProgramData &shdata, const Matrix &view_matrix, unsigned i) const
161 string base = format("light_sources[%d]", i);
162 shdata.uniform(base+".position", view_matrix*position);
163 shdata.uniform(base+".diffuse", diffuse);
164 shdata.uniform(base+".specular", specular);
167 void Light::bind_to(unsigned i) const
169 static Require _req(MSP_legacy_features);
171 LightUnit &unit = LightUnit::get_unit(i);
172 if(unit.set_light(this))
174 enable(GL_LIGHT0+unit.get_index());
175 update_parameter(-1, unit.get_index());
179 const Light *Light::current(unsigned i)
181 return LightUnit::get_unit(i).get_light();
184 void Light::unbind_from(unsigned i)
186 LightUnit &unit = LightUnit::get_unit(i);
187 if(unit.set_light(0))
188 disable(GL_LIGHT0+unit.get_index());
192 Light::Loader::Loader(Light &l):
193 DataFile::ObjectLoader<Light>(l)
195 add("attenuation", &Loader::attenuation);
196 add("diffuse", &Loader::diffuse);
197 add("position", &Loader::position);
198 add("specular", &Loader::specular);
199 add("spot_direction", &Loader::spot_direction);
200 add("spot_exponent", &Loader::spot_exponent);
201 add("spot_cutoff", &Loader::spot_cutoff);
204 void Light::Loader::attenuation(float c, float l, float q)
206 obj.set_attenuation(c, l, q);
209 void Light::Loader::diffuse(float r, float g, float b)
211 obj.set_diffuse(Color(r, g, b));
214 void Light::Loader::position(float x, float y, float z, float w)
216 obj.set_position(Vector4(x, y, z, w));
219 void Light::Loader::specular(float r, float g, float b)
221 obj.set_specular(Color(r, g, b));
224 void Light::Loader::spot_direction(float x, float y, float z)
226 obj.set_spot_direction(Vector3(x, y, z));
229 void Light::Loader::spot_exponent(float e)
231 obj.set_spot_exponent(e);
234 void Light::Loader::spot_cutoff(float c)
236 obj.set_spot_cutoff(Geometry::Angle<float>::from_degrees(c));