0022819: Redesign of OpenGl driver
[occt.git] / src / OpenGl / OpenGl_LightBox.cxx
1 /***********************************************************************
2
3 FONCTION :
4 ----------
5 Gestion des light sous OpenGL
6
7
8 REMARQUES:
9 ---------- 
10
11 - We can't take in account GL_QUADRATIC_ATTENUATION.    
12
13 - Position des lumieres. Il faut faire le glLight(GL_POSITION) apres la 
14 gestion des matrices de transformation (GL_MODELVIEW).
15
16 - Se mefier de GL_POSITION pour les lumieres directionelle. GL_POSITION
17 indique bien la position ou se trouve la lumiere. Comme on a une direction
18 comme valeur il faut l'inverser. 
19
20
21 FONCTIONNEMENT:
22 ---------------
23 - La variable lightOn permet d'optimiser le changement d'etat des lumieres.
24 Ceci permet d'eviter d'appeler glIsEnable(GL_LIGHTING). Il faut bien sur
25 que l'on utilise les 2 points d'entree LightOn() et LightOff().
26 L'init de la variable est faite par call_func_redraw_all_structs (OpenGl_funcs.c)
27
28
29 HISTORIQUE DES MODIFICATIONS   :
30 --------------------------------
31 20-06-97 : PCT ; creation
32 30-06-96 : FMN ; Integration
33 18-07-96 : FMN, PCT ; Correction indice,  ajout IsLightOn()
34 25-07-97 : CAL ; Portage NT (include OpenGl_tgl_all.h)
35 07-10-97 : FMN ; Simplification WNT
36
37 ************************************************************************/
38
39 /*----------------------------------------------------------------------*/
40 /*
41 * Includes
42 */
43
44 #include <OpenGl_tgl_all.hxx>
45
46 #include <stdio.h>
47 #include <stdlib.h>
48
49 #include <math.h>
50 #include <memory.h>
51
52 #include <OpenGl_LightBox.hxx>
53 #include <OpenGl_Memory.hxx>
54
55 /*----------------------------------------------------------------------*/
56 /*
57 * Constantes
58 */
59 #ifndef DEBUG
60 #define DEBUG 0
61 #endif
62
63 #define NO_PRINT_DEBUG
64
65 #define GROW_SIZE_WKS 10
66 #define GROW_SIZE_LIGHT 8
67
68 /*----------------------------------------------------------------------*/
69 /*
70 * Types definis
71 */
72 struct TEL_LIGHT_DATA
73 {
74   Tint LightID;
75   TEL_LIGHT light;
76   IMPLEMENT_MEMORY_OPERATORS
77 };
78
79 struct TEL_LIGHT_WKS
80 {
81   Tint wks;
82   int lights_count;
83   int lights_size;
84   TEL_LIGHT_DATA *lights;
85   IMPLEMENT_MEMORY_OPERATORS
86 };
87
88
89 /*----------------------------------------------------------------------*/
90 /*
91 * Variables statiques
92 */
93
94 static TEL_LIGHT_WKS *wks = NULL;
95 static int wks_count = 0;
96 static int wks_size = 0;
97
98 static GLfloat default_amb[4]    = { 0.0, 0.0, 0.0, 1.0 };
99 static GLfloat default_sptdir[3] = { 0.0, 0.0, -1.0 };
100 static GLfloat default_sptexpo   = 0.0;
101 static GLfloat default_sptcutoff = 180.0;
102
103 static GLboolean lightOn = GL_FALSE;
104
105 /*----------------------------------------------------------------------*/
106 /*
107 * Fonctions privees
108 */
109
110 /*-----------------------------------------------------------------*/
111 /*
112 *  Set des lumieres
113 */
114 static void bind_light(TEL_LIGHT *lptr, int *gl_lid)
115 {
116   GLfloat data_amb[4];
117   GLfloat data_diffu[4];
118   GLfloat data_pos[4];
119   GLfloat data_sptdir[3];
120   GLfloat data_sptexpo;
121   GLfloat data_sptcutoff;
122   GLfloat data_constantattenuation;
123   GLfloat data_linearattenuation;
124   GLint cur_matrix;
125
126
127   /* on n'a droit qu'a 8 lights avec OpenGL... */
128   if (*gl_lid > GL_LIGHT7) return;
129
130
131   /* la light est une headlight ? */
132   if (lptr->HeadLight)
133   {
134     glGetIntegerv(GL_MATRIX_MODE, &cur_matrix);
135     glMatrixMode(GL_MODELVIEW);
136     glPushMatrix();
137     glLoadIdentity();
138   }
139
140
141   /* set la light en fonction de son type */
142   switch (lptr->type)
143   {
144   case TLightAmbient:
145     data_amb[0] = lptr->col.rgb[0];
146     data_amb[1] = lptr->col.rgb[1];
147     data_amb[2] = lptr->col.rgb[2];
148     data_amb[3] = 1.0;
149
150     /*------------------------- Ambient ---------------------------*/
151     /*
152     * The GL_AMBIENT parameter refers to RGBA intensity of the ambient
153     * light.
154     */
155     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data_amb); 
156
157 #if DEBUG
158     printf("OpenGL_LightBox::bind_light:LightAmbient \n");
159     printf("\tGL_LIGHT_MODEL_AMBIENT %f %f %f \n", data_amb[0], data_amb[1], data_amb[2]);  
160 #endif
161     break;
162
163
164   case TLightDirectional:
165     data_diffu[0] = lptr->col.rgb[0];
166     data_diffu[1] = lptr->col.rgb[1];
167     data_diffu[2] = lptr->col.rgb[2];
168     data_diffu[3] = 1.0;
169
170     /*------------------------- Direction ---------------------------*/
171     /* From Open GL Programming Rev 1 Guide Chapt 6 :
172     Lighting The Mathematics of Lighting ( p 168 )
173
174     Directional Light Source ( Infinite ) :
175     if the last parameter of GL_POSITION , w , is zero, the
176     corresponding light source is a Directional one.
177
178     GL_SPOT_CUTOFF a 180 signifie que ce n'est pas un spot.
179     To create a realistic effect,  set the GL_SPECULAR parameter 
180     to the same value as the GL_DIFFUSE.
181     */
182
183     data_pos[0] = -lptr->dir[0];
184     data_pos[1] = -lptr->dir[1];
185     data_pos[2] = -lptr->dir[2];
186     data_pos[3] = 0.0;
187
188     glLightfv(*gl_lid, GL_AMBIENT, default_amb);
189     glLightfv(*gl_lid, GL_DIFFUSE, data_diffu);
190     glLightfv(*gl_lid, GL_SPECULAR, data_diffu);
191
192     glLightfv(*gl_lid, GL_POSITION, data_pos);
193     glLightfv(*gl_lid, GL_SPOT_DIRECTION, default_sptdir);
194     glLightf(*gl_lid, GL_SPOT_EXPONENT, default_sptexpo);
195     glLightf(*gl_lid, GL_SPOT_CUTOFF, default_sptcutoff);
196
197 #if DEBUG
198     printf("OpenGL_LightBox::bind_light:LightDirection \n");
199     printf("\tGL_AMBIENT %f %f %f \n", default_amb[0], default_amb[1], default_amb[2]); 
200     printf("\tGL_DIFFUSE %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]);  
201     printf("\tGL_SPECULAR %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]); 
202     printf("\tGL_POSITION %f %f %f \n", data_pos[0], data_pos[1], data_pos[2]); 
203 #endif
204     break;
205
206
207   case TLightPositional:
208     data_diffu[0] = lptr->col.rgb[0];
209     data_diffu[1] = lptr->col.rgb[1];
210     data_diffu[2] = lptr->col.rgb[2];
211     data_diffu[3] = 1.0;
212
213     /*------------------------- Position -----------------------------*/
214     /* From Open GL Programming Rev 1 Guide Chapt 6 :
215     Lighting The Mathematics of Lighting ( p 168 )
216     Positional Light Source :
217     if the last parameter of GL_POSITION , w , is nonzero,
218     the corresponding light source is a Positional one.
219
220     GL_SPOT_CUTOFF a 180 signifie que ce n'est pas un spot.
221
222     To create a realistic effect,  set the GL_SPECULAR parameter 
223     to the same value as the GL_DIFFUSE.
224     */
225
226     data_pos[0] = lptr->pos[0];
227     data_pos[1] = lptr->pos[1];
228     data_pos[2] = lptr->pos[2];
229     data_pos[3] = 1.0;
230
231     data_constantattenuation = lptr->atten[0];
232     data_linearattenuation = lptr->atten[1];
233
234     glLightfv(*gl_lid, GL_AMBIENT, default_amb);
235     glLightfv(*gl_lid, GL_DIFFUSE, data_diffu);
236     glLightfv(*gl_lid, GL_SPECULAR, data_diffu);
237
238     glLightfv(*gl_lid, GL_POSITION, data_pos);
239     glLightfv(*gl_lid, GL_SPOT_DIRECTION, default_sptdir);
240     glLightf(*gl_lid, GL_SPOT_EXPONENT, default_sptexpo);
241     glLightf(*gl_lid, GL_SPOT_CUTOFF, default_sptcutoff);
242     glLightf(*gl_lid, GL_CONSTANT_ATTENUATION, data_constantattenuation);
243     glLightf(*gl_lid, GL_LINEAR_ATTENUATION, data_linearattenuation);
244     glLightf(*gl_lid, GL_QUADRATIC_ATTENUATION, 0.0); 
245
246 #if DEBUG
247     printf("OpenGL_LightBox::bind_light:LightPosition \n");
248     printf("\tGL_AMBIENT %f %f %f \n", default_amb[0], default_amb[1], default_amb[2]); 
249     printf("\tGL_DIFFUSE %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]);  
250     printf("\tGL_SPECULAR %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]); 
251     printf("\tGL_POSITION %f %f %f \n", data_pos[0], data_pos[1], data_pos[2]); 
252 #endif
253     break;
254
255
256   case TLightSpot:
257     data_diffu[0] = lptr->col.rgb[0];
258     data_diffu[1] = lptr->col.rgb[1];
259     data_diffu[2] = lptr->col.rgb[2];
260     data_diffu[3] = 1.0;
261
262     data_pos[0] = lptr->pos[0];
263     data_pos[1] = lptr->pos[1];
264     data_pos[2] = lptr->pos[2];
265     data_pos[3] = 1.0;
266
267     data_sptdir[0] = lptr->dir[0];
268     data_sptdir[1] = lptr->dir[1];
269     data_sptdir[2] = lptr->dir[2];
270
271     data_sptexpo = ( float )lptr->shine * 128.0F;
272     data_sptcutoff = ( float )(lptr->angle * 180.0F)/( float )M_PI;
273
274     data_constantattenuation = lptr->atten[0];
275     data_linearattenuation = lptr->atten[1];
276
277     glLightfv(*gl_lid, GL_AMBIENT, default_amb);
278     glLightfv(*gl_lid, GL_DIFFUSE, data_diffu);
279     glLightfv(*gl_lid, GL_SPECULAR, data_diffu);   
280
281     glLightfv(*gl_lid, GL_POSITION, data_pos);      
282     glLightfv(*gl_lid, GL_SPOT_DIRECTION, data_sptdir);
283     glLightf(*gl_lid, GL_SPOT_EXPONENT, data_sptexpo);
284     glLightf(*gl_lid, GL_SPOT_CUTOFF, data_sptcutoff);
285     glLightf(*gl_lid, GL_CONSTANT_ATTENUATION, data_constantattenuation);
286     glLightf(*gl_lid, GL_LINEAR_ATTENUATION, data_linearattenuation);
287     glLightf(*gl_lid, GL_QUADRATIC_ATTENUATION, 0.0); 
288
289 #if DEBUG
290     printf("OpenGL_LightBox::bind_light:LightSpot \n");
291     printf("\tGL_AMBIENT %f %f %f \n", default_amb[0], default_amb[1], default_amb[2]); 
292     printf("\tGL_DIFFUSE %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]);  
293     printf("\tGL_SPECULAR %f %f %f \n", data_diffu[0], data_diffu[1], data_diffu[2]); 
294     printf("\tGL_POSITION %f %f %f \n", data_pos[0], data_pos[1], data_pos[2]); 
295     printf("\tGL_SPOT_DIRECTION %f %f %f \n", data_sptdir[0], data_sptdir[1], data_sptdir[2]);  
296     printf("\tGL_SPOT_EXPONENT %f \n", data_sptexpo); 
297     printf("\tGL_SPOT_CUTOFF   %f \n", data_sptcutoff); 
298     printf("\tGL_CONSTANT_ATTENUATION %f \n", data_constantattenuation);  
299     printf("\tGL_LINEAR_ATTENUATION   %f \n", data_linearattenuation);  
300 #endif
301     break;
302   }
303
304
305   if (lptr->type != TLightAmbient) 
306   {  
307 #if DEBUG
308     printf("OpenGL_LightBox::bind_light:glEnable %d \n", *gl_lid);
309 #endif
310     glEnable(*gl_lid);
311     (*gl_lid)++;
312   }
313
314
315   /* si la light etait une headlight alors restaure la matrice precedente */
316   if (lptr->HeadLight)
317   {
318     glPopMatrix();
319     glMatrixMode(cur_matrix);
320   }
321 }
322
323
324 /*-----------------------------------------------------------------*/
325 /*
326 * recherche de la liste de lampe d'une wks, creation d'une liste si non existante
327 */
328 static int find_wks(Tint WksID, int alloc)
329 {
330   int i;
331
332   /* recherche la wks dans la liste si elle existe */
333   for (i=0; i<wks_count; i++)
334     if (wks[i].wks == WksID)
335       return i;
336
337   if (!alloc) return -1;
338
339   /* la wks n'existe pas => on fait de la place si yen a plus */
340   if (wks_count == wks_size )
341   {
342     wks_size += GROW_SIZE_WKS;
343     if (!wks)
344       wks = new TEL_LIGHT_WKS[wks_size];
345     else
346 #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
347       wks = (TEL_LIGHT_WKS*)realloc(wks, wks_size*sizeof(TEL_LIGHT_WKS));
348 #else
349       wks = cmn_resizemem<TEL_LIGHT_WKS>(wks, wks_size);
350 #endif
351
352     if (!wks)
353       return -1;
354   }
355
356   wks[wks_count].wks = WksID;
357   wks[wks_count].lights = NULL;
358   wks[wks_count].lights_size = 0;
359   wks[wks_count].lights_count = 0;
360
361   return wks_count++;
362 }
363
364 /*-----------------------------------------------------------------*/
365 /*
366 * recherche une lampe d'une wks, creation d'une lampe si elle n'existe pas
367 */
368 static int find_light(int WksIdx, Tint LightID, int alloc)
369 {
370   int i;
371   TEL_LIGHT_DATA *lights;
372
373
374   /* recherche la light dans la liste de la wks */
375   lights = wks[WksIdx].lights;
376   for (i=0; i<wks[WksIdx].lights_count; i++)
377     if (lights[i].LightID == LightID)
378       return i;
379
380   if (!alloc) return -1;
381
382   /* la lampe n'existe pas => on cree une lampe */
383   if (wks[WksIdx].lights_count == wks[WksIdx].lights_size)
384   {
385     wks[WksIdx].lights_size += GROW_SIZE_LIGHT;
386     if (!wks[WksIdx].lights)
387       wks[WksIdx].lights = new TEL_LIGHT_DATA[wks[WksIdx].lights_size];
388     else
389       wks[WksIdx].lights =
390 #if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530)
391       (TEL_LIGHT_DATA*)realloc( wks[WksIdx].lights,
392       wks[WksIdx].lights_size*sizeof(TEL_LIGHT_DATA) );
393 #else
394       cmn_resizemem<TEL_LIGHT_DATA>( wks[WksIdx].lights,
395       wks[WksIdx].lights_size );
396 #endif
397     if (!wks[WksIdx].lights)
398       return -1;
399   }
400
401   return wks[WksIdx].lights_count++;
402 }
403
404
405 /*----------------------------------------------------------------------*/
406 /*
407 * Fonctions publiques 
408 */
409
410
411 /*-----------------------------------------------------------------*/
412 /*
413 * Ajout d'une lumiere dans la Wks
414 */
415 TStatus AddLight(Tint WksID, Tint LightID, tel_light light)
416 {
417   int wks_entry;
418   int light_entry;
419
420 #if DEBUG
421   printf("AddLight %d dans wks %d  [wds_count=%d]\n", LightID, WksID, wks_count);
422 #endif
423
424   /* obtient le numero de la liste de lights de la wks */
425   wks_entry = find_wks(WksID, 1);
426   if (wks_entry == -1) return TFailure;
427
428   /* recherche le numero de la lampe si elle existe */
429   light_entry = find_light(wks_entry, LightID, 1);
430   if (light_entry == -1) return TFailure;
431
432   /* met a jour la light */
433   wks[wks_entry].lights[light_entry].LightID = LightID;
434   wks[wks_entry].lights[light_entry].light = *light;
435
436 #if DEBUG
437   printf("ajout ok\n");
438 #endif
439   return TSuccess;
440 }
441
442
443 /*-----------------------------------------------------------------*/
444 /*
445 * Maj des lumieres de la Wks
446 */
447 TStatus UpdateLight(Tint WksID)
448 {
449   int wks_entry;
450   int i;
451   int gl_lid;
452
453
454 #if DEBUG
455   printf("UpdateLight %d\n", WksID);
456 #endif
457
458   /* vire toutes les lights des le depart avant une re-init complete */
459   for (i=GL_LIGHT0; i<=GL_LIGHT7; i++)
460     glDisable(i);
461   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, default_amb); 
462
463   /* recherche la liste de light de la wks */
464   wks_entry = find_wks(WksID, 0);
465   if (wks_entry == -1) return TFailure;
466
467 #if DEBUG
468   printf("*** Update:  nb = %d\n", wks[wks_entry].lights_count);
469 #endif
470
471   /* set les lights */
472   gl_lid = GL_LIGHT0;
473   for (i=0; i<wks[wks_entry].lights_count; i++)
474   {
475 #if DEBUG
476     printf("binding light %d\n", i);
477 #endif
478     bind_light(&wks[wks_entry].lights[i].light, &gl_lid);
479   }
480
481   if (wks[wks_entry].lights_count > 0) LightOn(); 
482
483 #if DEBUG
484   printf("update ok\n");
485 #endif
486
487   return TSuccess;
488 }
489
490
491 /*-----------------------------------------------------------------*/
492 /*
493 * Remove une lumiere de la Wks
494 */
495 TStatus RemoveLight(Tint WksID, Tint LightID)
496 {
497   int wks_entry;
498   int light_entry;
499
500
501   /* recherche de la wks */
502   wks_entry = find_wks(WksID, 0);
503   if (wks_entry == -1) return TFailure;
504
505   /* recherche de la light */
506   light_entry = find_light(wks_entry, LightID, 0);
507   if (light_entry == -1) return TFailure;
508
509   /* retire la light */
510   memcpy(&wks[wks_entry].lights[light_entry],
511     &wks[wks_entry].lights[light_entry+1],
512     (wks[wks_entry].lights_count - light_entry - 1)*sizeof(TEL_LIGHT_DATA));  
513   wks[wks_entry].lights_count--;
514
515 #if DEBUG
516   printf("RemoveLight %d dans wks %d  [wds_count=%d]\n", LightID, WksID, wks_count);
517 #endif
518
519   return TSuccess;
520 }
521
522
523 /*-----------------------------------------------------------------*/
524 /*
525 * Remove des lumieres de la Wks
526 */
527 TStatus RemoveWksLight(Tint WksID)
528 {
529   int wks_entry;
530
531   /* recherche de la wks */
532   wks_entry = find_wks(WksID, 0);
533   if (wks_entry == -1) return TFailure;
534
535   /* destruction de toute la wks */
536   free(wks[wks_entry].lights);
537   memcpy(&wks[wks_entry],
538     &wks[wks_entry+1],
539     (wks_count - wks_entry - 1)*sizeof(TEL_LIGHT_WKS));
540   wks_count--;
541
542   return TSuccess;
543 }
544
545
546 /*-----------------------------------------------------------------*/
547 /*
548 * Reset de toutes les lights d'une Wks
549 */
550 TStatus ResetWksLight(Tint WksID)
551 {
552   int wks_entry;
553
554   /* recherche de la wks */
555   wks_entry = find_wks(WksID, 0);
556   if (wks_entry == -1) return TFailure;
557
558   /* destruction de toutes les lights */  
559   wks[wks_entry].lights_count = 0;
560
561   return TSuccess;
562 }
563
564
565 /*-----------------------------------------------------------------*/
566 /*
567 * Enable des lights
568 */
569 void LightOn(void)
570 {
571 #ifdef PRINT_DEBUG
572   if(IsLightOn())
573     printf("LightOn(): lighting already enabled!");
574   else
575     printf("LightOn() succeeded");
576 #endif
577   glEnable(GL_LIGHTING);
578 }
579
580
581 /*-----------------------------------------------------------------*/
582 /*
583 * Disable des lights
584 */
585 void LightOff(void)
586 {
587 #ifdef PRINT_DEBUG
588   if(!IsLightOn())
589     printf("LightOff(): lighting already disabled!");
590   else
591     printf("LightOff() succeeded");
592 #endif
593   glDisable(GL_LIGHTING);
594 }
595 /*-----------------------------------------------------------------*/
596
597 /*
598 * IsEnable des lights
599 */
600
601 GLboolean IsLightOn(void)
602 {
603   return glIsEnabled(GL_LIGHTING);
604 }
605 /*-----------------------------------------------------------------*/