1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 #include "light.h"
45 
46 #include <GL/gl.h>
47 #include <GL/glu.h>
48 
49 #include <glib.h>
50 
51 #include <visu_tools.h>
52 
53 /**
54  * SECTION:light
55  * @short_description: Controls the use of lights in the rendering
56  * window.
57  *
58  * <para>One can defines several lights in OpenGL. The
59  * #VisuGlLights is an object that stores several of them and
60  * that can be applied to the current OpenGL context using
61  * visu_gl_lights_apply(). The lights that are created with
62  * visu_gl_light_newDefault() are ambiant light with a white colour. The
63  * multiplier coefficient is use to soften lights when several are
64  * used together. It is used as a factor for all light parameters
65  * (ambient, diffuse...) ecept the specular one.</para>
66  */
67 
68 /**
69  * VisuGlLight:
70  * @enabled: if the light is used or not ;
71  * @ambient: the ambient color of the light ;
72  * @diffuse: the diffuse color of the light ;
73  * @specular: the specular color of the light ;
74  * @position: the position in space of the light ;
75  * @multiplier: a value that multiply all color values (should be in [0;1]).
76  *
77  * This structure is convenient to store lights as defined by OpenGL.
78  */
79 
80 /**
81  * VisuGlLights:
82  *
83  * A short way to access #_VisuGlLights objects.
84  */
85 struct _VisuGlLights
86 {
87   guint refCount;
88 
89   GList* list;
90   /* Current size of the list. */
91   gint nbStoredVisuGlLights;
92   /* Number of lights called by glEnable() when last applied. */
93   gint nbEnabledVisuGlLights;
94 };
95 
visu_data_loader_xyz_getStatic(void)96 /* Local methods. */
97 static void lighting_set(gpointer data, gpointer user_data);
98 static VisuGlLight* light_copy(VisuGlLight *light);
99 
100 /**
101  * visu_gl_lights_get_type:
102  *
103  * Create and retrieve a #GType for a #VisuGlLights object.
104  *
105  * Since: 3.7
106  *
loadXyz(VisuDataLoader * self _U_,VisuDataLoadable * data,guint type,guint nSet,GCancellable * cancel _U_,GError ** error)107  * Returns: a new type for #VisuGlLights structures.
108  */
109 GType visu_gl_lights_get_type(void)
110 {
111   static GType g_define_type_id = 0;
112 
113   if (g_define_type_id == 0)
114     g_define_type_id =
115       g_boxed_type_register_static("VisuGlLights",
116                                    (GBoxedCopyFunc)visu_gl_lights_ref,
117                                    (GBoxedFreeFunc)visu_gl_lights_unref);
118   return g_define_type_id;
119 }
120 /**
121  * visu_gl_lights_new:
122  *
123  * Create a new #VisuGlLights object. It contains no light when created.
124  * Use visu_gl_lights_add() to add new lights and
125  * visu_gl_lights_remove() to remove others.
126  *
127  * Returns: a newly created #VisuGlLights. Use visu_gl_lights_free()
128  *          to free such an object.
129  */
130 VisuGlLights* visu_gl_lights_new()
readNextLine(ToolFiles * flux,gboolean mandatory,GString * line,GIOStatus * status,GError ** error)131 {
132   VisuGlLights *env;
133 
134   env = g_malloc(sizeof(VisuGlLights));
135   env->refCount = 1;
136   env->list = (GList*)0;
137   env->nbStoredVisuGlLights = 0;
138   env->nbEnabledVisuGlLights = 0;
139 
140   return env;
141 }
142 /**
143  * visu_gl_lights_ref:
144  * @env: a #VisuGlLights object.
145  *
146  * Increase the ref counter.
147  *
148  * Since: 3.7
149  *
150  * Returns: itself.
151  **/
152 VisuGlLights* visu_gl_lights_ref(VisuGlLights *env)
153 {
154   env->refCount += 1;
155   return env;
readUnit(const gchar * line)156 }
157 /**
158  * visu_gl_lights_unref:
159  * @env: a #VisuGlLights object.
160  *
161  * Decrease the ref counter, free all memory if counter reachs zero.
162  *
163  * Since: 3.7
164  **/
165 void visu_gl_lights_unref(VisuGlLights *env)
166 {
167   env->refCount -= 1;
168   if (!env->refCount)
169     visu_gl_lights_free(env);
170 }
171 /**
172  * visu_gl_lights_free:
readReduced(const gchar * line)173  * @env: a #VisuGlLights object.
174  *
175  * Free memory occupied by the given environnement.
176  */
177 void visu_gl_lights_free(VisuGlLights *env)
178 {
179   g_return_if_fail(env);
180 
181   visu_gl_lights_removeAll(env);
182   /* Need to apply to disable all previously enbaled lights before
183      freeing the object. */
184   visu_gl_lights_apply(env);
185   g_free(env);
186 }
187 /**
188  * visu_gl_lights_available:
readEnergy(const gchar * line)189  * @env: a #VisuGlLights object.
190  *
191  * Inquire if one can add more lights to the scene.
192  *
193  * Since: 3.8
194  *
195  * Returns: TRUE if the maximum number of lights allowed by OpenGL
196  * implementation is not reached yet.
197  **/
198 gboolean visu_gl_lights_available(VisuGlLights *env)
199 {
200   g_return_val_if_fail(env, FALSE);
201   return (env->nbStoredVisuGlLights < GL_MAX_LIGHTS);
202 }
203 /**
204  * visu_gl_lights_add:
205  * @env: a #VisuGlLights object ;
readBoundary(const gchar * line,const gchar * keyword,VisuBoxBoundaries bc,gdouble box[3])206  * @light: a #VisuGlLight object.
207  *
208  * This method adds the given @light to the list of known lights declared
209  * in the given environnement. The light is not copied and should not be freed
210  * when stored in the environnement.
211  *
212  * Returns: TRUE if visu_gl_lights_apply() should be called.
213  */
214 gboolean visu_gl_lights_add(VisuGlLights *env, VisuGlLight *light)
215 {
216   g_return_val_if_fail(env && light, FALSE);
217   g_return_val_if_fail(env->nbStoredVisuGlLights < GL_MAX_LIGHTS, FALSE);
218 
219   DBG_fprintf(stderr, "VisuGlLight : add a new light (%p).\n", (gpointer)light);
220   env->list = g_list_append(env->list, light);
221   env->nbStoredVisuGlLights += 1;
222 
223   return TRUE;
224 }
225 /**
226  * visu_gl_lights_remove:
227  * @env: a #VisuGlLights object ;
228  * @light: a #VisuGlLight object.
229  *
230  * This method removes the given @light from the list of known lights  declared
231  * in the given environnement. The @light argument is first removed and then freed
232  * by a call to g_free().
233  *
234  * Returns: TRUE if visu_gl_lights_apply() should be called.
235  */
236 gboolean visu_gl_lights_remove(VisuGlLights *env, VisuGlLight *light)
237 {
238   g_return_val_if_fail(env && light, FALSE);
239 
240   DBG_fprintf(stderr, "VisuGlLight : remove a light (%p).\n", (gpointer)light);
241   env->list = g_list_remove(env->list, light);
readCoord(const gchar * line,guint iNodes,guint nNodes,float * xyz,GArray ** dxyz,VisuDataLoaderIter * iter,VisuElement ** nodeTypes,gchar ** label,GError ** error)242   g_free(light);
243   env->nbStoredVisuGlLights -= 1;
244 
245   return TRUE;
246 }
247 /**
248  * visu_gl_lights_getList:
249  * @env: a #VisuGlLights object.
250  *
251  * Retrieve the list of known #VisuGlLight used by the given environnement.
252  *
253  * Returns: (transfer none) (element-type VisuGlLight*): a list of
254  * #VisuGlLight objects. Should not be freed.
255  */
256 GList* visu_gl_lights_getList(VisuGlLights *env)
257 {
258   g_return_val_if_fail(env, (GList*)0);
259 
260   return env->list;
261 }
262 /**
263  * visu_gl_lights_removeAll:
264  * @env: a #VisuGlLights object.
265  *
266  * Empty the list of stored lights. All stored lights objects are freed.
267  *
268  * Returns: TRUE if the visu_gl_lights_apply() should be called.
269  */
270 gboolean visu_gl_lights_removeAll(VisuGlLights *env)
271 {
272   GList *list;
273   int n;
274 
275   g_return_val_if_fail(env, FALSE);
276 
277   if (!env->list)
278     return FALSE;
279 
280   DBG_fprintf(stderr, "VisuGlLight : emptying list of stored lights of"
281 	      " environnement %p.\n", (gpointer)env);
282   list = env->list;
283   n = 0;
284   while (list)
285     {
286       DBG_fprintf(stderr, " | removing light %p\n", list->data);
287       g_free(list->data);
288       n += 1;
289       list = g_list_next(list);
290     }
291   g_list_free(env->list);
292   env->list = (GList*)0;
293   env->nbStoredVisuGlLights = 0;
294 
295   return TRUE;
296 }
297 /**
298  * visu_gl_lights_apply:
299  * @env: a #VisuGlLights object.
300  *
301  * Apply all stored informations about lights to the current OpenGL context.
302  *
303  * Returns: TRUE if OpenGL context has been changed.
304  */
readForces(ToolFiles * flux,GString * line,guint nNodes,GArray ** forces,GIOStatus * status,GError ** error)305 gboolean visu_gl_lights_apply(VisuGlLights *env)
306 {
307   gint nb;
308   float lmodel_ambient[4] = {0.2f, 0.2f, 0.2f, 1.0f};
309 
310   g_return_val_if_fail(env, FALSE);
311 
312   if (env->nbEnabledVisuGlLights == 0 && !env->list)
313     return FALSE;
314 
315   /* glPushMatrix(); */
316   /* glLoadIdentity(); */
317 
318   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
319   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
320   glEnable(GL_LIGHTING);
321 
322   for (nb = 0; nb < env->nbEnabledVisuGlLights; nb++)
323     glDisable(GL_LIGHT0 + nb);
324 
325   g_list_foreach(env->list, lighting_set, (gpointer)env);
326 
327   env->nbEnabledVisuGlLights = env->nbStoredVisuGlLights;
328 
329   /* glPopMatrix(); */
330 
331   return TRUE;
332 }
333 
334 /**
335  * visu_gl_light_newDefault:
336  *
337  * Create a new light with default value (white color and position in
338  * the front, right, top position of the screen).
339  *
340  * Returns: the newly created #VisuGlLight. Use g_free() to deallocate this light.
341  */
342 VisuGlLight* visu_gl_light_newDefault()
343 {
344   float params[16] =  {1.0f, 1.0f, 1.0f, 1.0f,
read_Xyz_File(VisuDataLoadable * data,guint iType,guint nSet,GError ** error)345 		       1.0f, 1.0f, 1.0f, 1.0f,
346 		       1.0f, 1.0f, 1.0f, 1.0f,
347 		       3.0f, 2.0f, 1.7f, 0.0f};
348   VisuGlLight *light;
349   int i;
350 
351   light = g_malloc(sizeof(VisuGlLight));
352   light->enabled = TRUE;
353   light->multiplier = 1.;
354   for(i = 0; i < 4; i++)
355     {
356       light->ambient[i] = params[i];
357       light->diffuse[i] = params[4 + i];
358       light->specular[i] = params[8 + i];
359       light->position[i] = params[12 + i];
360     }
361   return light;
362 }
363 /**
364  * visu_gl_light_get_type:
365  *
366  * Create and retrieve a #GType for a #VisuGlLight object.
367  *
368  * Since: 3.7
369  *
370  * Returns: a new type for #VisuGlLight structures.
371  */
372 GType visu_gl_light_get_type(void)
373 {
374   static GType g_define_type_id = 0;
375 
376   if (g_define_type_id == 0)
377     g_define_type_id =
378       g_boxed_type_register_static("VisuGlLight",
379                                    (GBoxedCopyFunc)light_copy,
380                                    (GBoxedFreeFunc)g_free);
381   return g_define_type_id;
382 }
383 static VisuGlLight* light_copy(VisuGlLight *light)
384 {
385   VisuGlLight *out;
386 
387   out = g_malloc(sizeof(VisuGlLight));
388   *out = *light;
389   return out;
390 }
391 
392 static void lighting_set(gpointer data, gpointer user_data)
393 {
394   VisuGlLight *light0 = data;
395   int n;
396   float values[4];
397   int i;
398   VisuGlLights *env;
399 
400   g_return_if_fail(user_data);
401   env = (VisuGlLights*)user_data;
402 
403   n = g_list_index(env->list, light0);
404   if(light0->enabled == FALSE)
405     {
406       /* From glLightfv man page : "It is always the case that GL_LIGHTi = GL_LIGHT0 + i." */
407       glDisable(GL_LIGHT0 + n);
408       return;
409     }
410 
411   glEnable(GL_LIGHT0 + n);
412   for (i = 0; i < 4; i++) values[i] = light0->ambient[i] * light0->multiplier;
413   glLightfv(GL_LIGHT0 + n, GL_AMBIENT,  values);
414   for (i = 0; i < 4; i++) values[i] = light0->diffuse[i] * light0->multiplier;
415   glLightfv(GL_LIGHT0 + n, GL_DIFFUSE, values);
416   for (i = 0; i < 4; i++) values[i] = light0->specular[i] * 1.;
417   glLightfv(GL_LIGHT0 + n, GL_SPECULAR, values);
418   glLightfv(GL_LIGHT0 + n, GL_POSITION, light0->position);
419   DBG_fprintf(stderr, "VisuGlLight : set light [%f][%f][%f][%f]\n", light0->position[0],
420 	      light0->position[1], light0->position[2], light0->multiplier);
421 }
422