FreeWRL/FreeX3D  3.0.0
Component_Lighting.c
1 /*
2 
3 
4 X3D Lighting Component
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 
29 #include <config.h>
30 #include <system.h>
31 #include <display.h>
32 #include <internal.h>
33 
34 #include <libFreeWRL.h>
35 
36 #include "../vrml_parser/Structs.h"
37 #include "../main/headers.h"
38 #include "../opengl/OpenGL_Utils.h"
39 #include "RenderFuncs.h"
40 //#include "../opengl/OpenGL_Utils.h"
41 #include "LinearAlgebra.h"
42 
43 #define RETURN_IF_LIGHT_STATE_NOT_US \
44  if (renderstate()->render_light== VF_globalLight) { \
45  if (!node->global) return;\
46  /* printf ("and this is a global light\n"); */\
47  } else if (node->global) return; \
48  /* else printf ("and this is a local light\n"); */
49 
50 #define CHBOUNDS(aaa) \
51  if (aaa.c[0]>1.0) aaa.c[0] = 1.0; \
52  if (aaa.c[0]<0.0) aaa.c[0] = 0.0; \
53  if (aaa.c[1]>1.0) aaa.c[1] = 1.0; \
54  if (aaa.c[1]<0.0) aaa.c[1] = 0.0; \
55  if (aaa.c[2]>1.0) aaa.c[2] = 1.0; \
56  if (aaa.c[2]<0.0) aaa.c[3] = 0.0;
57 
58 
59 void compile_DirectionalLight (struct X3D_DirectionalLight *node) {
60  struct point_XYZ vec;
61 
62  vec.x = (double) -((node->direction).c[0]);
63  vec.y = (double) -((node->direction).c[1]);
64  vec.z = (double) -((node->direction).c[2]);
65  normalize_vector(&vec);
66  node->_dir.c[0] = (float) vec.x;
67  node->_dir.c[1] = (float) vec.y;
68  node->_dir.c[2] = (float) vec.z;
69  node->_dir.c[3] = 0.0f;/* 0.0 = this is a vector, not a position */
70 
71  node->_col.c[0] = ((node->color).c[0]) * (node->intensity);
72  node->_col.c[1] = ((node->color).c[1]) * (node->intensity);
73  node->_col.c[2] = ((node->color).c[2]) * (node->intensity);
74  node->_col.c[3] = 1;
75  CHBOUNDS(node->_col);
76 
77 
78  node->_amb.c[0] = ((node->color).c[0]) * (node->ambientIntensity);
79  node->_amb.c[1] = ((node->color).c[1]) * (node->ambientIntensity);
80  node->_amb.c[2] = ((node->color).c[2]) * (node->ambientIntensity);
81  node->_amb.c[3] = 1;
82  CHBOUNDS(node->_amb);
83  MARK_NODE_COMPILED;
84 }
85 
86 
87 void render_DirectionalLight (struct X3D_DirectionalLight *node) {
88  /* if we are doing global lighting, is this one for us? */
89  RETURN_IF_LIGHT_STATE_NOT_US
90  /*
91  if (renderstate()->render_light== VF_globalLight) {
92  if (!node->global){
93  printf("x local dir,we want global %u\n",node);
94  return;
95  }
96  printf ("* global dir, we want global %u\n",node);
97  } else {
98  if (node->global){
99  printf("x global dir, we want local %u\n",node);
100  return;
101  }
102  else {
103  printf ("* local dir, we want local %u\n",node);
104  }
105  }
106  */
107  COMPILE_IF_REQUIRED;
108 
109  if(node->on) {
110  int light = nextlight();
111  if(light >= 0) {
112  float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f};
113  setLightState(light,TRUE);
114  setLightType(light,2);
115  FW_GL_LIGHTFV(light, GL_SPOT_DIRECTION, (GLfloat* )node->_dir.c);
116  FW_GL_LIGHTFV(light, GL_POSITION, (GLfloat* )pos);
117  FW_GL_LIGHTFV(light, GL_DIFFUSE, node->_col.c);
118  FW_GL_LIGHTFV(light, GL_SPECULAR, node->_col.c);
119  FW_GL_LIGHTFV(light, GL_AMBIENT, node->_amb.c);
120  /* used to test if a PointLight, SpotLight or DirectionalLight in shader */
121  // was used, using lightType now //FW_GL_LIGHTF(light, GL_SPOT_CUTOFF, 0);
122  setLightChangedFlag(light);
123  // not used in directionlight calc //FW_GL_LIGHTF(light,GL_LIGHT_RADIUS,100000.0); /* make it very large */
124  }
125  }
126 }
127 
128 /* global lights are done before the rendering of geometry */
129 void prep_DirectionalLight (struct X3D_DirectionalLight *node) {
130  if (!renderstate()->render_light) return;
131  render_DirectionalLight(node);
132 }
133 
134 void compile_PointLight (struct X3D_PointLight *node) {
135  int i;
136 
137  for (i=0; i<3; i++) node->_loc.c[i] = node->location.c[i];
138  node->_loc.c[3] = 1.0f;/* 1 == this is a position, not a vector */
139 
140  //ConsoleMessage("compile_PointLight, loc %f %f %f %f",node->_loc.c[0],node->_loc.c[1],node->_loc.c[2],node->_loc.c[3]);
141 
142  node->_col.c[0] = ((node->color).c[0]) * (node->intensity);
143  node->_col.c[1] = ((node->color).c[1]) * (node->intensity);
144  node->_col.c[2] = ((node->color).c[2]) * (node->intensity);
145  node->_col.c[3] = 1;
146  CHBOUNDS(node->_col);
147 
148 
149  node->_amb.c[0] = ((node->color).c[0]) * (node->ambientIntensity);
150  node->_amb.c[1] = ((node->color).c[1]) * (node->ambientIntensity);
151  node->_amb.c[2] = ((node->color).c[2]) * (node->ambientIntensity);
152  node->_amb.c[3] = 1;
153  CHBOUNDS(node->_amb);
154  MARK_NODE_COMPILED;
155 
156  /* ConsoleMessage ("compile_PointLight, attenuation %f %f %f",
157  node->attenuation.c[0],
158  node->attenuation.c[1],
159  node->attenuation.c[2]);*/
160 
161 
162  /* ConsoleMessage ("compile_PointLight, col %f %f %f %f amb %f %f %f %f",
163  node->_col.c[0],
164  node->_col.c[1],
165  node->_col.c[2],
166  node->_col.c[3],
167  node->_amb.c[0],
168  node->_amb.c[1],
169  node->_amb.c[2],
170  node->_amb.c[3]);
171  */
172 }
173 
174 
175 void render_PointLight (struct X3D_PointLight *node) {
176 
177  /* if we are doing global lighting, is this one for us? */
178  RETURN_IF_LIGHT_STATE_NOT_US
179  /*
180  if (renderstate()->render_light== VF_globalLight) {
181  if (!node->global) {
182  printf("x local point, we want global %u\n", node);
183  return;
184  }
185  printf ("* global point, we want global %u\n", node);
186  } else {
187  if (node->global){
188  printf("x global point, we want local %u\n", node);
189  return;
190  }else {
191  printf ("* local point, we want local %u\n", node);
192  }
193  }
194  */
195  COMPILE_IF_REQUIRED;
196 
197  if(node->on) {
198  int light = nextlight();
199  if(light >= 0) {
200  float vec[4] = {0.0f, 0.0f, -1.0f, 1.0f};
201 
202  setLightState(light,TRUE);
203  setLightType(light,0);
204  FW_GL_LIGHTFV(light, GL_SPOT_DIRECTION, vec);
205  FW_GL_LIGHTFV(light, GL_POSITION, node->_loc.c);
206 
207  FW_GL_LIGHTF(light, GL_CONSTANT_ATTENUATION,
208  ((node->attenuation).c[0]));
209  FW_GL_LIGHTF(light, GL_LINEAR_ATTENUATION,
210  ((node->attenuation).c[1]));
211  FW_GL_LIGHTF(light, GL_QUADRATIC_ATTENUATION,
212  ((node->attenuation).c[2]));
213 
214 
215  FW_GL_LIGHTFV(light, GL_DIFFUSE, node->_col.c);
216  FW_GL_LIGHTFV(light, GL_SPECULAR, node->_col.c);
217  FW_GL_LIGHTFV(light, GL_AMBIENT, node->_amb.c);
218 
219  /* used to test if a PointLight, SpotLight or DirectionalLight in shader */
220  // was used, using lightType now //FW_GL_LIGHTF(light, GL_SPOT_CUTOFF, 0);
221 
222  FW_GL_LIGHTF(light,GL_LIGHT_RADIUS,node->radius);
223  setLightChangedFlag(light);
224  }
225  }
226 }
227 
228 /* pointLights are done before the rendering of geometry */
229 void prep_PointLight (struct X3D_PointLight *node) {
230 
231  if (!renderstate()->render_light) return;
232  /* this will be a global light here... */
233  render_PointLight(node);
234 }
235 
236 void compile_SpotLight (struct X3D_SpotLight *node) {
237  struct point_XYZ vec;
238  float dlen;
239  int i;
240 
241  for (i=0; i<3; i++) node->_loc.c[i] = node->location.c[i];
242  node->_loc.c[3] = 1.0f;/* 1 == this is a position, not a vector */
243 
244  vec.x = (double) node->direction.c[0];
245  vec.y = (double) node->direction.c[1];
246  vec.z = (double) node->direction.c[2];
247  dlen = veclength(vec);
248  if(dlen < .1f) {
249  vec.x = 0.0; vec.y = 0.0, vec.z = -1.0;
250  }
251  normalize_vector(&vec);
252  node->_dir.c[0] = (float) vec.x;
253  node->_dir.c[1] = (float) vec.y;
254  node->_dir.c[2] = (float) vec.z;
255  node->_dir.c[3] = 1.0f;/* 1.0 = SpotLight */
256 
257  node->_col.c[0] = ((node->color).c[0]) * (node->intensity);
258  node->_col.c[1] = ((node->color).c[1]) * (node->intensity);
259  node->_col.c[2] = ((node->color).c[2]) * (node->intensity);
260  node->_col.c[3] = 1;
261  CHBOUNDS(node->_col);
262 
263 
264  node->_amb.c[0] = ((node->color).c[0]) * (node->ambientIntensity);
265  node->_amb.c[1] = ((node->color).c[1]) * (node->ambientIntensity);
266  node->_amb.c[2] = ((node->color).c[2]) * (node->ambientIntensity);
267  node->_amb.c[3] = 1;
268  CHBOUNDS(node->_amb);
269 
270  MARK_NODE_COMPILED;
271 }
272 
273 
274 void render_SpotLight(struct X3D_SpotLight *node) {
275  float ft;
276 
277  /* if we are doing global lighting, is this one for us? */
278  RETURN_IF_LIGHT_STATE_NOT_US
279 
280  COMPILE_IF_REQUIRED;
281 
282  if(node->on) {
283  int light = nextlight();
284  if(light >= 0) {
285  setLightState(light,TRUE);
286  setLightType(light,1);
287  FW_GL_LIGHTFV(light, GL_SPOT_DIRECTION, node->_dir.c);
288  FW_GL_LIGHTFV(light, GL_POSITION, node->_loc.c);
289 
290  FW_GL_LIGHTF(light, GL_CONSTANT_ATTENUATION,
291  ((node->attenuation).c[0]));
292  FW_GL_LIGHTF(light, GL_LINEAR_ATTENUATION,
293  ((node->attenuation).c[1]));
294  FW_GL_LIGHTF(light, GL_QUADRATIC_ATTENUATION,
295  ((node->attenuation).c[2]));
296 
297  FW_GL_LIGHTFV(light, GL_DIFFUSE, node->_col.c);
298  FW_GL_LIGHTFV(light, GL_SPECULAR, node->_col.c);
299  FW_GL_LIGHTFV(light, GL_AMBIENT, node->_amb.c);
300 
301  //ft =(float)cos((node->beamWidth)/2.0); /* / (PI/4.0); */
302  ft = cosf(node->beamWidth);
303  FW_GL_LIGHTF(light, GL_SPOT_BEAMWIDTH,ft);
304  //ConsoleMessage ("spotLight, bw %f, cuta %f, PI/4 %f", node->beamWidth,node->cutOffAngle, PI/4.0);
305 
306  /* create a ratio of light in relation to PI/4.0 */
307  //ft = (float)cos(node->cutOffAngle/2.0); /* / (PI/4.0); */
308  ft = cosf(node->cutOffAngle);
309  FW_GL_LIGHTF(light, GL_SPOT_CUTOFF, ft);
310  setLightChangedFlag(light);
311  //not used in spotlight calculation FW_GL_LIGHTF(light,GL_LIGHT_RADIUS,node->radius);
312  }
313  }
314 }
315 /* SpotLights are done before the rendering of geometry */
316 void prep_SpotLight (struct X3D_SpotLight *node) {
317  if (!renderstate()->render_light) return;
318  render_SpotLight(node);
319 }
320 
321 int getLocalLight();
322 void pushLocalLight(int lastlight);
323 void popLocalLight();
324 
325 
326 void sib_prep_DirectionalLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
327  int lastlight;
328  //if ((parent->_renderFlags & VF_localLight)==VF_localLight && renderstate()->render_light != VF_globalLight){
329  if ( renderstate()->render_light != VF_globalLight){
330  saveLightState2(&lastlight);
331  pushLocalLight(lastlight);
332  render_DirectionalLight((struct X3D_DirectionalLight*)sibAffector);
333  }
334 }
335 void sib_prep_SpotlLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
336  int lastlight;
337  if ( renderstate()->render_light != VF_globalLight){
338  saveLightState2(&lastlight);
339  pushLocalLight(lastlight);
340  render_SpotLight((struct X3D_SpotLight*)sibAffector);
341  }
342 
343 }
344 void sib_prep_PointLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
345  int lastlight;
346  if ( renderstate()->render_light != VF_globalLight){
347  saveLightState2(&lastlight);
348  pushLocalLight(lastlight);
349  render_PointLight((struct X3D_PointLight*)sibAffector);
350  }
351 }
352 
353 
354 void sib_fin_DirectionalLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
355  int lastlight;
356  if ( renderstate()->render_light != VF_globalLight) {
357  lastlight = getLocalLight();
358  if(numberOfLights() > lastlight) {
359  setLightChangedFlag(numberOfLights()-1);
360  refreshLightUniforms();
361  }
362  restoreLightState2(lastlight);
363  popLocalLight();
364  }
365 }
366 void sib_fin_SpotlLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
367  int lastlight;
368  if (renderstate()->render_light != VF_globalLight) {
369  lastlight = getLocalLight();
370  if(numberOfLights() > lastlight) {
371  setLightChangedFlag(numberOfLights()-1);
372  refreshLightUniforms();
373  }
374  restoreLightState2(lastlight);
375  popLocalLight();
376  }
377 }
378 void sib_fin_PointLight(struct X3D_Node *parent, struct X3D_Node *sibAffector){
379  int lastlight;
380  if (renderstate()->render_light != VF_globalLight) {
381  lastlight = getLocalLight();
382  if(numberOfLights() > lastlight) {
383  setLightChangedFlag(numberOfLights()-1);
384  refreshLightUniforms();
385  }
386  popLocalLight();
387  restoreLightState2(lastlight);
388  }
389 }
390