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