]> git.tdb.fi Git - libs/gl.git/blob - source/light.cpp
Unbind things if they are deleted while current
[libs/gl.git] / source / light.cpp
1 #include <stdexcept>
2 #include <msp/strings/format.h>
3 #include "light.h"
4 #include "lightunit.h"
5 #include "matrix.h"
6 #include "misc.h"
7 #include "programdata.h"
8
9 using namespace std;
10
11 namespace Msp {
12 namespace GL {
13
14 Light::Light():
15         diffuse(1),
16         specular(1),
17         position(0, 0, 1, 0),
18         spot_dir(0, 0, -1),
19         spot_exp(0),
20         spot_cutoff(180)
21 {
22         attenuation[0] = 1;
23         attenuation[1] = 0;
24         attenuation[2] = 0;
25 }
26
27 Light::~Light()
28 {
29         while(LightUnit *unit = LightUnit::find_unit(this))
30                 unbind_from(unit->get_index());
31 }
32
33 void Light::update_parameter(int mask, int index) const
34 {
35         if(index<0)
36         {
37                 LightUnit *unit = LightUnit::find_unit(this);
38                 if(!unit)
39                         return;
40
41                 index = unit->get_index();
42         }
43
44         GLenum l = GL_LIGHT0+index;
45         if(mask&DIFFUSE)
46                 glLightfv(l, GL_DIFFUSE, &diffuse.r);
47         if(mask&SPECULAR)
48                 glLightfv(l, GL_SPECULAR, &specular.r);
49         if(mask&POSITION)
50                 glLightfv(l, GL_POSITION, &position.x);
51         if(mask&SPOT_DIR)
52                 glLightfv(l, GL_SPOT_DIRECTION, &spot_dir.x);
53         if(mask&SPOT_EXP)
54                 glLightf(l, GL_SPOT_EXPONENT, spot_exp);
55         if(mask&SPOT_CUTOFF)
56                 glLightf(l, GL_SPOT_CUTOFF, spot_cutoff);
57         if(mask&ATTENUATION)
58         {
59                 glLightf(l, GL_CONSTANT_ATTENUATION, attenuation[0]);
60                 glLightf(l, GL_LINEAR_ATTENUATION, attenuation[1]);
61                 glLightf(l, GL_QUADRATIC_ATTENUATION, attenuation[2]);
62         }
63 }
64
65 void Light::set_diffuse(const Color &c)
66 {
67         diffuse = c;
68         update_parameter(DIFFUSE);
69 }
70
71 void Light::set_specular(const Color &c)
72 {
73         specular = c;
74         update_parameter(SPECULAR);
75 }
76
77 void Light::set_position(const Vector4 &p)
78 {
79         position = p;
80         update_parameter(POSITION);
81 }
82
83 void Light::set_spot_direction(const Vector3 &d)
84 {
85         spot_dir = d;
86         update_parameter(SPOT_DIR);
87 }
88
89 void Light::set_spot_exponent(float e)
90 {
91         spot_exp = e;
92         update_parameter(SPOT_EXP);
93 }
94
95 void Light::set_spot_cutoff(float c)
96 {
97         spot_cutoff = c;
98         update_parameter(SPOT_CUTOFF);
99 }
100
101 void Light::set_attenuation(float c, float l, float q)
102 {
103         attenuation[0] = c;
104         attenuation[1] = l;
105         attenuation[2] = q;
106         update_parameter(ATTENUATION);
107 }
108
109 void Light::update_shader_data(ProgramData &shdata, const Matrix &view_matrix, unsigned i) const
110 {
111         string base = format("light_sources[%d]", i);
112         shdata.uniform(base+".position", view_matrix*position);
113         shdata.uniform(base+".diffuse", diffuse);
114         shdata.uniform(base+".specular", specular);
115 }
116
117 void Light::bind_to(unsigned i) const
118 {
119         LightUnit &unit = LightUnit::get_unit(i);
120         if(unit.set_light(this))
121         {
122                 enable(GL_LIGHT0+unit.get_index());
123                 update_parameter(-1, unit.get_index());
124         }
125 }
126
127 const Light *Light::current(unsigned i)
128 {
129         return LightUnit::get_unit(i).get_light();
130 }
131
132 void Light::unbind_from(unsigned i)
133 {
134         LightUnit &unit = LightUnit::get_unit(i);
135         if(unit.set_light(0))
136                 disable(GL_LIGHT0+unit.get_index());
137 }
138
139 } // namespace GL
140 } // namespace Msp