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