dungeon_crawler

view prototype/src/light.cc @ 77:d89b403f630b

added gamma correction (without dialing the lighting down yet) fixed the incorrect PointLight sphere radius
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 26 Oct 2012 03:03:52 +0300
parents f55ddab0f3a4
children 12a1dcfe91fa
line source
1 #include <stdlib.h>
2 #include "opengl.h"
3 #include "light.h"
4 #include "renderer.h"
5 #include "timer.h"
7 unsigned int PointLight::sph_vbo = 0;
8 int PointLight::subdiv = 8;
10 Light::Light(const Color &col)
11 : color(col)
12 {
13 intensity = 1.0;
14 vbo = 0;
15 num_faces = 0;
17 flicker_offset = 2.0 * (float)rand() / (float)RAND_MAX;
18 }
20 Light::~Light() {}
22 void Light::set_intensity(float val)
23 {
24 intensity = val;
25 }
27 void Light::set_color(const Color &col)
28 {
29 color = col;
30 }
32 Color Light::get_color(bool with_intensity) const
33 {
34 return with_intensity ? color * intensity : color;
35 }
37 void Light::use(int id) const
38 {
39 glLightfv(GL_LIGHT0 + id, GL_DIFFUSE, &color.x);
40 glLightfv(GL_LIGHT0 + id, GL_SPECULAR, &color.x);
41 }
43 void Light::draw() const
44 {
45 if(!vbo) {
46 if(!((Light*)this)->create_mesh()) {
47 return;
48 }
49 }
51 glEnableClientState(GL_VERTEX_ARRAY);
52 glBindBuffer(GL_ARRAY_BUFFER, vbo);
53 glVertexPointer(3, GL_FLOAT, 0, 0);
55 glDrawArrays(GL_TRIANGLES, 0, num_faces * 3);
57 glBindBuffer(GL_ARRAY_BUFFER, 0);
58 glDisableClientState(GL_VERTEX_ARRAY);
59 }
61 bool Light::create_mesh()
62 {
63 fprintf(stderr, "%s: undefined\n", __FUNCTION__);
64 return false;
65 }
68 PointLight::PointLight()
69 : Light(Color(1.0, 1.0, 1.0))
70 {
71 atten[0] = 1.0f;
72 atten[1] = 0.0f;
73 atten[2] = 0.0f;
74 radius = 1.0;
75 }
77 PointLight::PointLight(const Vector3 &pos, const Color &col)
78 : Light(col)
79 {
80 this->pos = pos;
81 atten[0] = 1.0f;
82 atten[1] = 0.0f;
83 atten[2] = 0.0f;
84 radius = 1.0;
85 }
87 void PointLight::set_position(const Vector3 &pos)
88 {
89 this->pos = pos;
90 }
92 const Vector3 &PointLight::get_position() const
93 {
94 return pos;
95 }
97 void PointLight::set_attenuation(float att_const, float att_lin, float att_quad)
98 {
99 atten[0] = att_const;
100 atten[1] = att_lin;
101 atten[2] = att_quad;
102 }
104 void PointLight::set_radius(float rad)
105 {
106 radius = rad;
107 }
109 float PointLight::get_radius() const
110 {
111 return radius;
112 }
114 void PointLight::use(int id) const
115 {
116 float lpos[] = {pos.x, pos.y, pos.z, 1.0f};
117 glLightfv(GL_LIGHT0 + id, GL_POSITION, lpos);
118 glLightf(GL_LIGHT0 + id, GL_CONSTANT_ATTENUATION, atten[0]);
119 glLightf(GL_LIGHT0 + id, GL_LINEAR_ATTENUATION, atten[1]);
120 glLightf(GL_LIGHT0 + id, GL_QUADRATIC_ATTENUATION, atten[2]);
121 }
123 void PointLight::draw() const
124 {
125 unsigned int sdr = rend->get_current_program();
126 if(sdr) {
127 int loc;
128 if((loc = glGetUniformLocation(sdr, "light_radius")) != -1) {
129 glUniform1f(loc, radius);
130 }
131 if((loc = glGetUniformLocation(sdr, "light_color")) != -1) {
132 float t = get_time_msec() / 1000.0 + flicker_offset * 4.0;
133 float intens = fbm1(t * 2.0, 2) * 0.5 + 1.0;
134 glUniform3f(loc, color.x * intens, color.y * intens, color.z * intens);
135 }
136 }
138 glMatrixMode(GL_MODELVIEW);
139 glPushMatrix();
140 glTranslatef(pos.x, pos.y, pos.z);
142 // scale by the hypotenuse of the triangle with adjacent side: radius
143 // and angle M_PI / subdiv
144 float s = radius / cos(M_PI / subdiv);
145 glScalef(s, s, s);
147 Light::draw();
149 glPopMatrix();
150 }
154 Vector3 sphvertex(float u, float v)
155 {
156 float theta = u * M_PI * 2.0;
157 float phi = v * M_PI;
159 Vector3 res;
160 res.x = sin(theta) * sin(phi);
161 res.y = cos(phi);
162 res.z = cos(theta) * sin(phi);
163 return res;
164 }
167 bool PointLight::create_mesh()
168 {
169 /*if(sph_vbo) {
170 vbo = sph_vbo;
171 return true;
172 }*/
174 printf("building sphere mesh for point light drawing\n");
176 const static int udiv = subdiv;
177 const static int vdiv = udiv / 2;
179 int nquads = udiv * vdiv;
180 num_faces = nquads * 2;
181 int nverts = num_faces * 3;
183 float du = 1.0 / (float)udiv;
184 float dv = 1.0 / (float)vdiv;
186 glGenBuffers(1, &sph_vbo);
187 glBindBuffer(GL_ARRAY_BUFFER, sph_vbo);
188 glBufferData(GL_ARRAY_BUFFER, nverts * sizeof(Vector3), 0, GL_STATIC_DRAW);
190 Vector3 *vptr = (Vector3*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
192 for(int i=0; i<vdiv; i++) {
193 float v = (float)i / (float)vdiv;
194 for(int j=0; j<udiv; j++) {
195 float u = (float)j / (float)udiv;
197 *vptr++ = sphvertex(u, v + dv);
198 *vptr++ = sphvertex(u + du, v);
199 *vptr++ = sphvertex(u, v);
201 *vptr++ = sphvertex(u, v + dv);
202 *vptr++ = sphvertex(u + du, v + dv);
203 *vptr++ = sphvertex(u + du, v);
204 }
205 }
206 glUnmapBuffer(GL_ARRAY_BUFFER);
207 glBindBuffer(GL_ARRAY_BUFFER, 0);
209 vbo = sph_vbo;
210 return true;
211 }
213 void set_light(int id, const Light *lt)
214 {
215 if(lt) {
216 glDisable(GL_LIGHT0 + id);
217 } else {
218 glEnable(GL_LIGHT0 + id);
219 lt->use(id);
220 }
221 }