1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Damien
3 	CALISTE, laboratoire L_Sim, (2015)
4 
5 	Adresse mèl :
6 	CALISTE, damien P caliste AT cea P fr.
7 
8 	Ce logiciel est un programme informatique servant à visualiser des
9 	structures atomiques dans un rendu pseudo-3D.
10 
11 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
12 	respectant les principes de diffusion des logiciels libres. Vous pouvez
13 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
14 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
15 	sur le site "http://www.cecill.info".
16 
17 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
18 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
19 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
20 */
21 
22 /*   LICENCE SUM UP
23 	Copyright CEA, contributors : Damien
24 	CALISTE, laboratoire L_Sim, (2015)
25 
26 	E-mail address:
27 	CALISTE, damien P caliste AT cea P fr.
28 
29 	This software is a computer program whose purpose is to visualize atomic
30 	configurations in 3D.
31 
32 	This software is governed by the CeCILL  license under French law and
33 	abiding by the rules of distribution of free software.  You can  use,
34 	modify and/ or redistribute the software under the terms of the CeCILL
35 	license as circulated by CEA, CNRS and INRIA at the following URL
36 	"http://www.cecill.info".
37 
38 	The fact that you are presently reading this means that you have had
39 	knowledge of the CeCILL license and that you accept its terms. You can
40 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
41 */
42 
43 #include "visu_extset.h"
44 
45 #include <GL/gl.h>
46 #include <string.h>
47 
48 #include "opengl.h"
49 #include "visu_tools.h"
50 #include "iface_boxed.h"
51 #include "visu_configFile.h"
52 #include "openGLFunctions/objectList.h"
53 #include "coreTools/toolConfigFile.h"
54 #include "OSOpenGL/visu_openGL.h"
55 
56 #include "extensions/mapset.h"
57 
58 /**
59  * SECTION:visu_extset
60  * @short_description: Defines a storage object to handle a bunch of
61  * #VisuGlExt objects.
62  *
63  * <para>A storage to display several #VisuGlExt objects. It takes
64  * care of ordering display, following priority of each object.</para>
65  */
66 
67 /* Parameters & resources*/
68 /* A resource to control the color of the background. */
69 #define FLAG_RESOURCE_BG_COLOR   "backgroundColor_color"
70 #define DESC_RESOURCE_BG_COLOR   "Set the background of the background ; four floating point values (0. <= v <= 1.)"
71 static float bgRGBDefault[4] = {0., 0., 0., 1.};
72 
73 /* This is a boolean to control is the axes is render or not. */
74 #define FLAG_RESOURCE_FOG_USED   "fog_is_on"
75 #define DESC_RESOURCE_FOG_USED   "Control if the fog is used ; boolean (0 or 1)"
76 static gboolean fogActiveDefault = TRUE;
77 
78 #define FLAG_RESOURCE_FOG_SPECIFIC   "fog_color_is_specific"
79 #define DESC_RESOURCE_FOG_SPECIFIC   "Control if the fog uses a specific color ; boolean (0 or 1)"
80 static gboolean fogSpecificDefault = FALSE;
81 
82 #define FLAG_RESOURCE_FOG_COLOR   "fog_specific_color"
83 #define DESC_RESOURCE_FOG_COLOR   "Define the color of the fog ; four floating point values (0. <= v <= 1.)"
84 static float fogRGBDefault[4] = {0.f, 0.f, 0.f, 1.f};
85 
86 #define FLAG_RESOURCE_FOG_STARTEND "fog_start_end"
87 #define DESC_RESOURCE_FOG_STARTEND "Define the position of the fog ; two floating point values (0. <= v <= 1.)"
88 static float fogStartEndDefault[2] = {0.3f, 0.7f};
89 
90 struct _GlExt {
91   VisuGlExt *ext;
92   gulong priority_sig, dirty_sig, active_sig;
93 };
94 
95 struct _VisuGlExtSetPrivate
96 {
97   gboolean dispose_has_run;
98 
99   /* A list to store all the available OpenGL extensions. */
100   GArray *set;
101   gboolean reorderingNeeded, dirty;
102   guint dirtyPending;
103 
104   /* The view extensions are rendered on. */
105   VisuGlView *view;
106   gulong widthHeight_signal, chg_signal;
107 
108   /* Handling the background color and the fog. */
109   float bgRGB[4];
110   int chessList;
111   gboolean bgDirty;
112   gboolean fogActive;
113   float fogStartEnd[2];
114   gboolean fogFollowsBg;
115   float fogRGB[4];
116 };
117 
118 enum
119   {
120     PROP_0,
121     BG_R_PROP,
122     BG_G_PROP,
123     BG_B_PROP,
124     BG_A_PROP,
125     FOG_ACTIVE_PROP,
126     FOG_START_PROP,
127     FOG_FULL_PROP,
128     FOG_FOLLOWS_PROP,
129     FOG_R_PROP,
130     FOG_G_PROP,
131     FOG_B_PROP,
132     FOG_A_PROP,
133     DIRTY_PROP,
134     N_PROP
135   };
136 static GParamSpec *properties[N_PROP];
137 
138 static VisuGlExtSet *defaultSet = NULL;
139 static GLuint texName = 0;
140 
141 static void visu_gl_ext_set_dispose     (GObject* obj);
142 static void visu_gl_ext_set_finalize    (GObject* obj);
143 static void visu_gl_ext_set_get_property(GObject* obj, guint property_id,
144                                          GValue *value, GParamSpec *pspec);
145 static void visu_gl_ext_set_set_property(GObject* obj, guint property_id,
146                                          const GValue *value, GParamSpec *pspec);
147 static void visu_gl_ext_initContext     (VisuGl *gl);
148 
149 /* Local callbacks */
150 static void onWidthHeight(VisuGlView *view, gpointer data);
151 static void onCamera(VisuGlView *view, gpointer data);
152 static void onEntryBgColor(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj);
153 static void onEntryFogActive(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj);
154 static void onEntryFogSpecific(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj);
155 static void onEntryFogColor(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj);
156 static void onEntryFogStartEnd(VisuGlExtSet *set, VisuConfigFileEntry *entry, VisuConfigFile *obj);
157 
158 static void _appendDirty(VisuGlExtSet *set);
159 static void _chessDraw(VisuGlExtSet *set);
160 static void exportResources(GString *data, VisuData *dataObj);
161 
G_DEFINE_TYPE_WITH_CODE(VisuGlExtSet,visu_gl_ext_set,VISU_TYPE_GL,G_ADD_PRIVATE (VisuGlExtSet))162 G_DEFINE_TYPE_WITH_CODE(VisuGlExtSet, visu_gl_ext_set, VISU_TYPE_GL,
163                         G_ADD_PRIVATE(VisuGlExtSet))
164 
165 static void visu_gl_ext_set_class_init(VisuGlExtSetClass *klass)
166 {
167   float rgColor[2] = {0.f, 1.f};
168 
169   DBG_fprintf(stderr, "Visu Extension Set: creating the class of the object.\n");
170   /* DBG_fprintf(stderr, "                - adding new signals ;\n"); */
171 
172   /* Parameters */
173   visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
174                                       FLAG_RESOURCE_BG_COLOR,
175                                       DESC_RESOURCE_BG_COLOR,
176                                       4, bgRGBDefault, rgColor, FALSE);
177   visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE,
178                                    FLAG_RESOURCE_FOG_USED,
179                                    DESC_RESOURCE_FOG_USED,
180                                    &fogActiveDefault, FALSE);
181   visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_RESOURCE,
182                                    FLAG_RESOURCE_FOG_SPECIFIC,
183                                    DESC_RESOURCE_FOG_SPECIFIC,
184                                    &fogSpecificDefault, FALSE);
185   visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
186                                       FLAG_RESOURCE_FOG_COLOR,
187                                       DESC_RESOURCE_FOG_COLOR,
188                                       4, fogRGBDefault, rgColor, FALSE);
189   visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
190                                       FLAG_RESOURCE_FOG_STARTEND,
191                                       DESC_RESOURCE_FOG_STARTEND,
192                                       2, fogStartEndDefault, rgColor, FALSE);
193   visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources);
194 
195   /* Connect the overloading methods. */
196   G_OBJECT_CLASS(klass)->dispose  = visu_gl_ext_set_dispose;
197   G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_set_finalize;
198   G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_set_set_property;
199   G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_set_get_property;
200   VISU_GL_CLASS(klass)->initContext = visu_gl_ext_initContext;
201 
202   /**
203    * VisuGlExtSet::dirty:
204    *
205    * TRUE when at least one of the active #VisuGlExt gets dirty.
206    *
207    * Since: 3.8
208    */
209   properties[DIRTY_PROP] = g_param_spec_boolean("dirty", "Dirty",
210                                                 "one of the object rendering is out of date",
211                                                 FALSE, G_PARAM_READABLE);
212   g_object_class_install_property(G_OBJECT_CLASS(klass), DIRTY_PROP, properties[DIRTY_PROP]);
213   /**
214    * VisuGlExtSet::bg-red:
215    *
216    * Store the red channel of the background color.
217    *
218    * Since: 3.8
219    */
220   properties[BG_R_PROP] = g_param_spec_float("bg-red", "red channel",
221                                              "background red channel",
222                                              0., 1., 0., G_PARAM_READWRITE);
223   g_object_class_install_property(G_OBJECT_CLASS(klass), BG_R_PROP,
224 				  properties[BG_R_PROP]);
225   /**
226    * VisuGlExtSet::bg-green:
227    *
228    * Store the green channel of the background color.
229    *
230    * Since: 3.8
231    */
232   properties[BG_G_PROP] = g_param_spec_float("bg-green", "green channel",
233                                              "background green channel",
234                                              0., 1., 0., G_PARAM_READWRITE);
235   g_object_class_install_property(G_OBJECT_CLASS(klass), BG_G_PROP,
236 				  properties[BG_G_PROP]);
237   /**
238    * VisuGlExtSet::bg-blue:
239    *
240    * Store the blue channel of the background color.
241    *
242    * Since: 3.8
243    */
244   properties[BG_B_PROP] = g_param_spec_float("bg-blue", "blue channel",
245                                              "background blue channel",
246                                              0., 1., 0., G_PARAM_READWRITE);
247   g_object_class_install_property(G_OBJECT_CLASS(klass), BG_B_PROP,
248 				  properties[BG_B_PROP]);
249   /**
250    * VisuGlExtSet::bg-alpha:
251    *
252    * Store the alpha channel of the background color.
253    *
254    * Since: 3.8
255    */
256   properties[BG_A_PROP] = g_param_spec_float("bg-alpha", "alpha channel",
257                                              "background alpha channel",
258                                              0., 1., 0., G_PARAM_READWRITE);
259   g_object_class_install_property(G_OBJECT_CLASS(klass), BG_A_PROP,
260 				  properties[BG_A_PROP]);
261   /**
262    * VisuGlExtSet::fog-active:
263    *
264    * Store if the fog is used.
265    *
266    * Since: 3.8
267    */
268   properties[FOG_ACTIVE_PROP] = g_param_spec_boolean("fog-active", "Fog active",
269                                                       "Fog is used",
270                                                       TRUE, G_PARAM_READWRITE);
271   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_ACTIVE_PROP,
272 				  properties[FOG_ACTIVE_PROP]);
273   /**
274    * VisuGlExtSet::fog-start:
275    *
276    * Store the starting depth of the fog.
277    *
278    * Since: 3.8
279    */
280   properties[FOG_START_PROP] = g_param_spec_float("fog-start", "Fog start",
281                                                   "starting fog depth",
282                                                   0., 1., 0.3, G_PARAM_READWRITE);
283   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_START_PROP,
284 				  properties[FOG_START_PROP]);
285   /**
286    * VisuGlExtSet::fog-full:
287    *
288    * Store the depth where the fog hides all.
289    *
290    * Since: 3.8
291    */
292   properties[FOG_FULL_PROP] = g_param_spec_float("fog-full", "Fog full",
293                                                   "depth where fog hides all",
294                                                   0., 1., 0.7, G_PARAM_READWRITE);
295   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_FULL_PROP,
296 				  properties[FOG_FULL_PROP]);
297   /**
298    * VisuGlExtSet::fog-follows-bg:
299    *
300    * Store if the fog follows the background color.
301    *
302    * Since: 3.8
303    */
304   properties[FOG_FOLLOWS_PROP] = g_param_spec_boolean("fog-follows-bg", "Fog follows bg",
305                                                       "Fog color is the bg color",
306                                                       TRUE, G_PARAM_READWRITE);
307   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_FOLLOWS_PROP,
308 				  properties[FOG_FOLLOWS_PROP]);
309   /**
310    * VisuGlExtSet::fog-red:
311    *
312    * Store the red channel of the specific fog color.
313    *
314    * Since: 3.8
315    */
316   properties[FOG_R_PROP] = g_param_spec_float("fog-red", "red channel",
317                                               "specific fog red channel",
318                                               0., 1., 0., G_PARAM_READWRITE);
319   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_R_PROP,
320 				  properties[FOG_R_PROP]);
321   /**
322    * VisuGlExtSet::fog-green:
323    *
324    * Store the green channel of the specific fog color.
325    *
326    * Since: 3.8
327    */
328   properties[FOG_G_PROP] = g_param_spec_float("fog-green", "green channel",
329                                               "specific fog green channel",
330                                               0., 1., 0., G_PARAM_READWRITE);
331   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_G_PROP,
332 				  properties[FOG_G_PROP]);
333   /**
334    * VisuGlExtSet::fog-blue:
335    *
336    * Store the blue channel of the specific fog color.
337    *
338    * Since: 3.8
339    */
340   properties[FOG_B_PROP] = g_param_spec_float("fog-blue", "blue channel",
341                                               "specific fog blue channel",
342                                               0., 1., 0., G_PARAM_READWRITE);
343   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_B_PROP,
344 				  properties[FOG_B_PROP]);
345   /**
346    * VisuGlExtSet::fog-alpha:
347    *
348    * Store the alpha channel of the specific fog color.
349    *
350    * Since: 3.8
351    */
352   properties[FOG_A_PROP] = g_param_spec_float("fog-alpha", "alpha channel",
353                                               "specific fog alpha channel",
354                                               0., 1., 1., G_PARAM_READWRITE);
355   g_object_class_install_property(G_OBJECT_CLASS(klass), FOG_A_PROP,
356 				  properties[FOG_A_PROP]);
357 
358   visu_gl_objectlist_init();
359 }
360 
visu_gl_ext_set_init(VisuGlExtSet * ext)361 static void visu_gl_ext_set_init(VisuGlExtSet *ext)
362 {
363   DBG_fprintf(stderr, "Visu Extension Set: initializing a new object (%p).\n",
364 	      (gpointer)ext);
365   ext->priv = visu_gl_ext_set_get_instance_private(ext);
366   ext->priv->dispose_has_run = FALSE;
367 
368   ext->priv->set = g_array_new(FALSE, FALSE, sizeof(struct _GlExt));
369   ext->priv->reorderingNeeded = FALSE;
370   ext->priv->dirty = FALSE;
371   ext->priv->dirtyPending = 0;
372   ext->priv->view = (VisuGlView*)0;
373   g_signal_connect(G_OBJECT(ext), "notify::lights",
374                    G_CALLBACK(_appendDirty), (gpointer)0);
375   g_signal_connect(G_OBJECT(ext), "notify::antialias",
376                    G_CALLBACK(_appendDirty), (gpointer)0);
377   g_signal_connect(G_OBJECT(ext), "notify::immediate",
378                    G_CALLBACK(_appendDirty), (gpointer)0);
379   g_signal_connect(G_OBJECT(ext), "notify::true-transparency",
380                    G_CALLBACK(_appendDirty), (gpointer)0);
381   g_signal_connect(G_OBJECT(ext), "notify::stereo",
382                    G_CALLBACK(_appendDirty), (gpointer)0);
383   g_signal_connect(G_OBJECT(ext), "notify::stereo-angle",
384                    G_CALLBACK(_appendDirty), (gpointer)0);
385   g_signal_connect(G_OBJECT(ext), "notify::mode",
386                    G_CALLBACK(_appendDirty), (gpointer)0);
387 
388   ext->priv->bgRGB[0] = bgRGBDefault[0];
389   ext->priv->bgRGB[1] = bgRGBDefault[1];
390   ext->priv->bgRGB[2] = bgRGBDefault[2];
391   ext->priv->bgRGB[3] = bgRGBDefault[3];
392   g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_BG_COLOR,
393                           G_CALLBACK(onEntryBgColor), (gpointer)ext, G_CONNECT_SWAPPED);
394   ext->priv->chessList = visu_gl_objectlist_new(1);
395   ext->priv->bgDirty = FALSE;
396 
397   ext->priv->fogActive      = fogActiveDefault;
398   ext->priv->fogStartEnd[0] = fogStartEndDefault[0];
399   ext->priv->fogStartEnd[1] = fogStartEndDefault[1];
400   ext->priv->fogFollowsBg   = !fogSpecificDefault;
401   ext->priv->fogRGB[0]      = fogRGBDefault[0];
402   ext->priv->fogRGB[1]      = fogRGBDefault[1];
403   ext->priv->fogRGB[2]      = fogRGBDefault[2];
404   ext->priv->fogRGB[3]      = fogRGBDefault[3];
405   g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_USED,
406                           G_CALLBACK(onEntryFogActive), (gpointer)ext, G_CONNECT_SWAPPED);
407   g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_SPECIFIC,
408                           G_CALLBACK(onEntryFogSpecific), (gpointer)ext, G_CONNECT_SWAPPED);
409   g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_COLOR,
410                           G_CALLBACK(onEntryFogColor), (gpointer)ext, G_CONNECT_SWAPPED);
411   g_signal_connect_object(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_RESOURCE_FOG_STARTEND,
412                           G_CALLBACK(onEntryFogStartEnd), (gpointer)ext, G_CONNECT_SWAPPED);
413 
414   if (!defaultSet)
415     defaultSet = ext;
416 }
417 
418 /* This method can be called several times.
419    It should unref all of its reference to
420    GObjects. */
visu_gl_ext_set_dispose(GObject * obj)421 static void visu_gl_ext_set_dispose(GObject* obj)
422 {
423   VisuGlExtSet *ext;
424   guint i;
425   struct _GlExt *s;
426   gchar *name;
427 
428   DBG_fprintf(stderr, "Visu Extension Set: dispose object %p.\n", (gpointer)obj);
429 
430   ext = VISU_GL_EXT_SET(obj);
431   if (ext->priv->dispose_has_run)
432     return;
433   ext->priv->dispose_has_run = TRUE;
434 
435   visu_gl_ext_set_setGlView(ext, (VisuGlView*)0);
436 
437   DBG_fprintf(stderr, "Visu Extension Set: releasing %d extensions.\n", ext->priv->set->len);
438   for (i = 0; i < ext->priv->set->len; i++)
439     {
440       s = &g_array_index(ext->priv->set, struct _GlExt, i);
441       if (DEBUG)
442         {
443           DBG_fprintf(stderr, "Visu Extension Set: releasing extension %p.\n",
444                       (gpointer)s->ext);
445           g_object_get(s->ext, "name", &name, NULL);
446           DBG_fprintf(stderr, " | %s (%d)\n", name, G_OBJECT(s->ext)->ref_count);
447           g_free(name);
448         }
449       g_signal_handler_disconnect(G_OBJECT(s->ext), s->priority_sig);
450       g_signal_handler_disconnect(G_OBJECT(s->ext), s->dirty_sig);
451       g_signal_handler_disconnect(G_OBJECT(s->ext), s->active_sig);
452       g_object_unref(G_OBJECT(s->ext));
453     }
454 
455   /* Chain up to the parent class */
456   G_OBJECT_CLASS(visu_gl_ext_set_parent_class)->dispose(obj);
457 }
458 /* This method is called once only. */
visu_gl_ext_set_finalize(GObject * obj)459 static void visu_gl_ext_set_finalize(GObject* obj)
460 {
461   VisuGlExtSetPrivate *ext;
462 
463   g_return_if_fail(obj);
464 
465   DBG_fprintf(stderr, "Visu Extension Set: finalize object %p.\n", (gpointer)obj);
466   ext = VISU_GL_EXT_SET(obj)->priv;
467 
468   if (ext->dirtyPending)
469     g_source_remove(ext->dirtyPending);
470   g_array_free(ext->set, TRUE);
471   glDeleteLists(ext->chessList, 1);
472 
473   /* Chain up to the parent class */
474   DBG_fprintf(stderr, "Visu Extension Set: chain to parent.\n");
475   G_OBJECT_CLASS(visu_gl_ext_set_parent_class)->finalize(obj);
476   DBG_fprintf(stderr, "Visu Extension Set: freeing ... OK.\n");
477 }
visu_gl_ext_set_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)478 static void visu_gl_ext_set_get_property(GObject* obj, guint property_id,
479                                          GValue *value, GParamSpec *pspec)
480 {
481   VisuGlExtSet *self = VISU_GL_EXT_SET(obj);
482 
483   DBG_fprintf(stderr, "Visu Extension Set: get property '%s' -> ",
484 	      g_param_spec_get_name(pspec));
485   switch (property_id)
486     {
487     case DIRTY_PROP:
488       g_value_set_boolean(value, (self->priv->dirtyPending > 0));
489       DBG_fprintf(stderr, "%d.\n", (self->priv->dirtyPending > 0));
490       break;
491     case BG_R_PROP:
492       g_value_set_float(value, self->priv->bgRGB[0]);
493       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[0]);
494       break;
495     case BG_G_PROP:
496       g_value_set_float(value, self->priv->bgRGB[1]);
497       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[1]);
498       break;
499     case BG_B_PROP:
500       g_value_set_float(value, self->priv->bgRGB[2]);
501       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[2]);
502       break;
503     case BG_A_PROP:
504       g_value_set_float(value, self->priv->bgRGB[3]);
505       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[3]);
506       break;
507     case FOG_ACTIVE_PROP:
508       g_value_set_boolean(value, self->priv->fogActive);
509       DBG_fprintf(stderr, "%d.\n", self->priv->fogActive);
510       break;
511     case FOG_START_PROP:
512       g_value_set_float(value, self->priv->fogStartEnd[0]);
513       DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[0]);
514       break;
515     case FOG_FULL_PROP:
516       g_value_set_float(value, self->priv->fogStartEnd[1]);
517       DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[1]);
518       break;
519     case FOG_FOLLOWS_PROP:
520       g_value_set_boolean(value, self->priv->fogFollowsBg);
521       DBG_fprintf(stderr, "%d.\n", self->priv->fogFollowsBg);
522       break;
523     case FOG_R_PROP:
524       g_value_set_float(value, self->priv->fogRGB[0]);
525       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[0]);
526       break;
527     case FOG_G_PROP:
528       g_value_set_float(value, self->priv->fogRGB[1]);
529       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[1]);
530       break;
531     case FOG_B_PROP:
532       g_value_set_float(value, self->priv->fogRGB[2]);
533       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[2]);
534       break;
535     case FOG_A_PROP:
536       g_value_set_float(value, self->priv->fogRGB[3]);
537       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[3]);
538       break;
539     default:
540       /* We don't have any other property... */
541       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
542       break;
543     }
544 }
visu_gl_ext_set_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)545 static void visu_gl_ext_set_set_property(GObject* obj, guint property_id,
546                                          const GValue *value, GParamSpec *pspec)
547 {
548   VisuGlExtSet *self = VISU_GL_EXT_SET(obj);
549   float rgba[4], startEnd[2];
550 
551   DBG_fprintf(stderr, "Visu Extension Set: set property '%s' -> ",
552 	      g_param_spec_get_name(pspec));
553   switch (property_id)
554     {
555     case BG_R_PROP:
556       rgba[0] = g_value_get_float(value);
557       visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_R);
558       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[0]);
559       break;
560     case BG_G_PROP:
561       rgba[1] = g_value_get_float(value);
562       visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_G);
563       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[1]);
564       break;
565     case BG_B_PROP:
566       rgba[2] = g_value_get_float(value);
567       visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_B);
568       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[2]);
569       break;
570     case BG_A_PROP:
571       rgba[3] = g_value_get_float(value);
572       visu_gl_ext_set_setBgColor(self, rgba, TOOL_COLOR_MASK_A);
573       DBG_fprintf(stderr, "%g.\n", self->priv->bgRGB[3]);
574       break;
575     case FOG_ACTIVE_PROP:
576       visu_gl_ext_set_setFogActive(self, g_value_get_boolean(value));
577       DBG_fprintf(stderr, "%d.\n", self->priv->fogActive);
578       break;
579     case FOG_START_PROP:
580       startEnd[0] = g_value_get_float(value);
581       visu_gl_ext_set_setFogStartFull(self, startEnd, VISU_GL_EXT_SET_FOG_MASK_START);
582       DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[0]);
583       break;
584     case FOG_FULL_PROP:
585       startEnd[1] = g_value_get_float(value);
586       visu_gl_ext_set_setFogStartFull(self, startEnd, VISU_GL_EXT_SET_FOG_MASK_FULL);
587       DBG_fprintf(stderr, "%g.\n", self->priv->fogStartEnd[1]);
588       break;
589     case FOG_FOLLOWS_PROP:
590       visu_gl_ext_set_setFogFollowsBg(self, g_value_get_boolean(value));
591       DBG_fprintf(stderr, "%d.\n", self->priv->fogFollowsBg);
592       break;
593     case FOG_R_PROP:
594       rgba[0] = g_value_get_float(value);
595       visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_R);
596       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[0]);
597       break;
598     case FOG_G_PROP:
599       rgba[1] = g_value_get_float(value);
600       visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_G);
601       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[1]);
602       break;
603     case FOG_B_PROP:
604       rgba[2] = g_value_get_float(value);
605       visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_B);
606       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[2]);
607       break;
608     case FOG_A_PROP:
609       rgba[3] = g_value_get_float(value);
610       visu_gl_ext_set_setFogColor(self, rgba, TOOL_COLOR_MASK_A);
611       DBG_fprintf(stderr, "%g.\n", self->priv->fogRGB[3]);
612       break;
613     default:
614       /* We don't have any other property... */
615       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
616       break;
617     }
618 }
visu_gl_ext_initContext(VisuGl * gl)619 static void visu_gl_ext_initContext(VisuGl *gl)
620 {
621   VisuGlExtSet *self = VISU_GL_EXT_SET(gl);
622   guint i;
623 
624   g_return_if_fail(VISU_IS_GL_EXT_SET(self));
625 
626   VISU_GL_CLASS(visu_gl_ext_set_parent_class)->initContext(gl);
627 
628   if (self->priv->view)
629     visu_gl_view_initContext(self->priv->view);
630   for (i = 0; i < self->priv->set->len; i++)
631     visu_gl_ext_rebuild(g_array_index(self->priv->set, struct _GlExt, i).ext);
632 }
633 
634 /**
635  * visu_gl_ext_set_new:
636  *
637  * Create an object to handle a set of #VisuGlExt objects and draw
638  * them together.
639  *
640  * Since: 3.8
641  *
642  * Returns: (transfer full): a newly created #VisuGlExtSet object.
643  **/
visu_gl_ext_set_new()644 VisuGlExtSet* visu_gl_ext_set_new()
645 {
646   VisuGlExtSet *set;
647 
648   set = VISU_GL_EXT_SET(g_object_new(VISU_TYPE_GL_EXT_SET, NULL));
649   return set;
650 }
651 
652 /**
653  * visu_gl_ext_set_setGlView:
654  * @set: a #VisuGlExtSet object.
655  * @view: a #VisuGlView object.
656  *
657  * Apply the given @view on all #VisuGlExt objects stored in @set.
658  *
659  * Since: 3.8
660  *
661  * Returns: TRUE if the @view actually change.
662  **/
visu_gl_ext_set_setGlView(VisuGlExtSet * set,VisuGlView * view)663 gboolean visu_gl_ext_set_setGlView(VisuGlExtSet *set, VisuGlView *view)
664 {
665   guint i;
666 
667   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
668 
669   if (set->priv->view == view)
670     return FALSE;
671 
672   if (set->priv->view)
673     {
674       g_object_unref(G_OBJECT(set->priv->view));
675       g_signal_handler_disconnect(G_OBJECT(set->priv->view), set->priv->widthHeight_signal);
676       g_signal_handler_disconnect(G_OBJECT(set->priv->view), set->priv->chg_signal);
677     }
678   if (view)
679     {
680       g_object_ref(G_OBJECT(view));
681       set->priv->widthHeight_signal =
682         g_signal_connect(G_OBJECT(view), "WidthHeightChanged",
683                          G_CALLBACK(onWidthHeight), (gpointer)set);
684       set->priv->chg_signal =
685         g_signal_connect(G_OBJECT(view), "changed",
686                          G_CALLBACK(onCamera), (gpointer)set);
687     }
688   set->priv->view = view;
689 
690   for (i = 0; i < set->priv->set->len; i++)
691     visu_gl_ext_setGlView(g_array_index(set->priv->set, struct _GlExt, i).ext, view);
692 
693   return TRUE;
694 }
695 
696 /**
697  * visu_gl_ext_set_getAll:
698  * @set: a #VisuGlExtSet object.
699  *
700  * Retrieve as a #GList all the #VisuGlExt objects drawn by @set.
701  *
702  * Since: 3.8
703  *
704  * Returns: (transfer container) (element-type VisuGlExt*): only the
705  * container list should be freed after.
706  **/
visu_gl_ext_set_getAll(VisuGlExtSet * set)707 GList* visu_gl_ext_set_getAll(VisuGlExtSet *set)
708 {
709   GList *lst;
710   guint i;
711 
712   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (GList*)0);
713 
714   lst = (GList*)0;
715   for (i = 0; i < set->priv->set->len; i++)
716     lst = g_list_append(lst, g_array_index(set->priv->set, struct _GlExt, i).ext);
717   return lst;
718 }
719 
720 /**
721  * visu_gl_ext_set_getByName:
722  * @set: a #VisuGlExtSet object.
723  * @name: a name to look for.
724  *
725  * Retrieve the #VisuGlExt object with @name that is stored in
726  * @set. If several #VisuGlExt objects have the same name, the first
727  * one is returned.
728  *
729  * Since: 3.8
730  *
731  * Returns: (transfer none): a #VisuGlExt with @name.
732  **/
visu_gl_ext_set_getByName(const VisuGlExtSet * set,const gchar * name)733 VisuGlExt* visu_gl_ext_set_getByName(const VisuGlExtSet *set, const gchar *name)
734 {
735   guint i;
736 
737   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (VisuGlExt*)0);
738 
739   for (i = 0; i < set->priv->set->len; i++)
740     if (!strcmp(visu_gl_ext_getName(g_array_index(set->priv->set, struct _GlExt, i).ext), name))
741       return g_array_index(set->priv->set, struct _GlExt, i).ext;
742   return (VisuGlExt*)0;
743 }
744 
_emitDirty(gpointer data)745 static gboolean _emitDirty(gpointer data)
746 {
747   /* if (!VISU_GL_EXT_SET(data)->priv->dirty) */
748   /*   return FALSE; */
749   g_object_notify_by_pspec(G_OBJECT(data), properties[DIRTY_PROP]);
750 
751   VISU_GL_EXT_SET(data)->priv->dirtyPending = 0;
752   return FALSE;
753 }
_appendDirty(VisuGlExtSet * set)754 static void _appendDirty(VisuGlExtSet *set)
755 {
756   /* if (set->priv->dirtyPending) */
757   /*   g_source_remove(set->priv->dirtyPending); */
758   set->priv->dirty = TRUE;
759   if (!set->priv->dirtyPending)
760     set->priv->dirtyPending =
761       g_idle_add_full(G_PRIORITY_HIGH_IDLE, _emitDirty, (gpointer)set, (GDestroyNotify)0);
762 }
onExtPriority(VisuGlExtSet * set)763 static void onExtPriority(VisuGlExtSet *set)
764 {
765   set->priv->reorderingNeeded = TRUE;
766 }
onExtDirty(VisuGlExtSet * set,GParamSpec * pspec _U_,VisuGlExt * ext)767 static void onExtDirty(VisuGlExtSet *set, GParamSpec *pspec _U_, VisuGlExt *ext)
768 {
769   if (!visu_gl_ext_getActive(ext))
770     return;
771   DBG_fprintf(stderr, "Visu Extension Set: extension '%s' is dirty.\n",
772               visu_gl_ext_getName(ext));
773   _appendDirty(set);
774 }
775 
776 /**
777  * visu_gl_ext_set_add:
778  * @set: a #VisuGlExtSet object.
779  * @ext: a #VisuGlExt object.
780  *
781  * Add @ext in the list of drawn #VisuGlExt by @set.
782  *
783  * Since: 3.8
784  *
785  * Returns: TRUE if not already existing.
786  **/
visu_gl_ext_set_add(VisuGlExtSet * set,VisuGlExt * ext)787 gboolean visu_gl_ext_set_add(VisuGlExtSet *set, VisuGlExt *ext)
788 {
789   struct _GlExt s;
790   guint i;
791 
792   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
793 
794   /* Lookup first for ext in the set. */
795   for (i = 0; i < set->priv->set->len; i++)
796     if (g_array_index(set->priv->set, struct _GlExt, i).ext == ext)
797       return FALSE;
798 
799   g_object_ref(G_OBJECT(ext));
800   s.ext = ext;
801   s.priority_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::priority",
802                                             G_CALLBACK(onExtPriority), set);
803   s.dirty_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::dirty",
804                                          G_CALLBACK(onExtDirty), set);
805   s.active_sig = g_signal_connect_swapped(G_OBJECT(ext), "notify::active",
806                                           G_CALLBACK(_appendDirty), set);
807   if (set->priv->view)
808     visu_gl_ext_setGlView(ext, set->priv->view);
809   visu_gl_ext_setGlContext(ext, VISU_GL(set));
810 
811   set->priv->reorderingNeeded = TRUE;
812 
813   g_array_append_val(set->priv->set, s);
814 
815   if (VISU_GL_EXT_SET_GET_CLASS(set)->added)
816     VISU_GL_EXT_SET_GET_CLASS(set)->added(set, ext);
817 
818   onExtDirty(set, NULL, ext);
819 
820   return TRUE;
821 }
822 
823 /**
824  * visu_gl_ext_set_remove:
825  * @set: a #VisuGlExtSet object.
826  * @ext: a #VisuGlExt object.
827  *
828  * Remove @ext in the list of drawn #VisuGlExt by @set.
829  *
830  * Since: 3.8
831  *
832  * Returns: TRUE if successfully removed.
833  **/
visu_gl_ext_set_remove(VisuGlExtSet * set,VisuGlExt * ext)834 gboolean visu_gl_ext_set_remove(VisuGlExtSet *set, VisuGlExt *ext)
835 {
836   struct _GlExt *s;
837   guint i;
838   gboolean dirty;
839 
840   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
841 
842   for (i = 0; i < set->priv->set->len; i++)
843     {
844       s = &g_array_index(set->priv->set, struct _GlExt, i);
845       if (s->ext == ext)
846         {
847           dirty = visu_gl_ext_getActive(s->ext);
848           g_signal_handler_disconnect(G_OBJECT(s->ext), s->priority_sig);
849           g_signal_handler_disconnect(G_OBJECT(s->ext), s->dirty_sig);
850           g_signal_handler_disconnect(G_OBJECT(s->ext), s->active_sig);
851           g_object_unref(s->ext);
852           g_array_remove_index(set->priv->set, i);
853           if (dirty)
854             _appendDirty(set);
855           if (VISU_GL_EXT_SET_GET_CLASS(set)->removed)
856             VISU_GL_EXT_SET_GET_CLASS(set)->removed(set, ext);
857           return TRUE;
858         }
859     }
860   return FALSE;
861 }
862 
compareExtensionPriority(gconstpointer a,gconstpointer b)863 static gint compareExtensionPriority(gconstpointer a, gconstpointer b)
864 {
865   guint pa = visu_gl_ext_getPriority(((struct _GlExt*)a)->ext);
866   guint pb = visu_gl_ext_getPriority(((struct _GlExt*)b)->ext);
867 
868   if (pa < pb)
869     return (gint)-1;
870   else if (pa > pb)
871     return (gint)+1;
872   else
873     return (gint)0;
874 }
875 
mayReorder(VisuGlExtSet * set)876 static void mayReorder(VisuGlExtSet *set)
877 {
878   if (set->priv->reorderingNeeded)
879     {
880       DBG_fprintf(stderr, "Visu Extension Set: sorting known extension"
881                   " depending on their priority.\n");
882       g_array_sort(set->priv->set, compareExtensionPriority);
883       set->priv->reorderingNeeded = FALSE;
884     }
885 }
886 
887 /**
888  * visu_gl_ext_set_draw:
889  * @set: a #VisuGlExtSet object.
890  *
891  * Basic drawing method : it clears the OpenGL area and call all lists
892  * stored in @set.
893  *
894  * Since: 3.8
895  */
visu_gl_ext_set_draw(VisuGlExtSet * set)896 void visu_gl_ext_set_draw(VisuGlExtSet *set)
897 {
898   int i_stereo, stereo;
899   guint i;
900   static int stereo_buf[2] = {GL_BACK_LEFT, GL_BACK_RIGHT};
901   GLboolean glStereo;
902   float centre[3];
903   VisuBox *box;
904   float start, stop, bSize, fogCentre;
905 #if DEBUG == 1
906   GTimer *timer;
907   gulong fractionTimer;
908 #endif
909 
910   g_return_if_fail(VISU_IS_GL_EXT_SET(set) && set->priv->view);
911 
912 #if DEBUG == 1
913   timer = g_timer_new();
914   g_timer_start(timer);
915 #endif
916 
917   mayReorder(set);
918 
919   box = visu_boxed_getBox(VISU_BOXED(set->priv->view));
920   if (box)
921     visu_box_getCentre(box, centre);
922   else
923     {
924       centre[0] = 0.f;
925       centre[1] = 0.f;
926       centre[2] = 0.f;
927     }
928 
929   _chessDraw(set);
930 
931   glClearColor(set->priv->bgRGB[0], set->priv->bgRGB[1],
932                set->priv->bgRGB[2], set->priv->bgRGB[3]);
933   if (set->priv->fogActive && set->priv->view &&
934       visu_boxed_getBox(VISU_BOXED(set->priv->view)))
935     {
936       glEnable(GL_FOG);
937       glFogi(GL_FOG_MODE, GL_LINEAR);
938 /*       glFogi(GL_FOG_MODE, GL_EXP);  */
939 /*       glFogf(GL_FOG_DENSITY, 0.03f);  */
940       if (set->priv->fogFollowsBg)
941         glFogfv(GL_FOG_COLOR, set->priv->bgRGB);
942       else
943         glFogfv(GL_FOG_COLOR, set->priv->fogRGB);
944 
945       bSize = visu_box_getGlobalSize(visu_boxed_getBox(VISU_BOXED(set->priv->view)), FALSE);
946       fogCentre = ((set->priv->view->camera.d_red > 100.f) ?
947                    100.f : set->priv->view->camera.d_red) * set->priv->view->camera.length0;
948 
949       start = fogCentre - bSize + 2.f * bSize * set->priv->fogStartEnd[0];
950       stop  = fogCentre - bSize + 2.f * bSize * set->priv->fogStartEnd[1];
951 /*   start = visuBox->extens * visuCamera->d_red * (1. - fog_start); */
952 /*   stop = visuBox->extens * visuCamera->d_red * (1. + fog_end); */
953 /*   start = visuBox->extens * visuCamera->d_red * (1. - 1 / 1.1); */
954 /*   stop = visuBox->extens * visuCamera->d_red * (1. + 1 / 1.1); */
955 /*   fprintf(stderr, "----------> %f %f %f %f\n", (float)(view->window->near + */
956 /* 						       (view->window->far - view->window->near) * fog_start), (float)(view->window->near + */
957 /* 														  (view->window->far - view->window->near) * fog_end), start, stop); */
958       glFogf(GL_FOG_START, start);
959       glFogf(GL_FOG_END, stop);
960     }
961   else
962     glDisable(GL_FOG);
963 
964   glGetBooleanv(GL_STEREO, &glStereo);
965   stereo = (set->priv->view && glStereo && visu_gl_getStereo(VISU_GL(set))) ? 1 : 0;
966   for(i_stereo = 0; i_stereo <= stereo; i_stereo++)
967     {
968       if (stereo == 1)
969         {
970           glRotatef(visu_gl_getStereoAngle(VISU_GL(set)) * (2.f * i_stereo - 1.f),
971         	    set->priv->view->camera.up[0],
972         	    set->priv->view->camera.up[1],
973         	    set->priv->view->camera.up[2]);
974           glDrawBuffer(stereo_buf[i_stereo]);
975           DBG_fprintf(stderr, "Visu Extension Set: draw on buffer %d.\n", i_stereo);
976         }
977       else
978         glDrawBuffer(GL_BACK);
979 
980       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
981 
982       glPushAttrib(GL_ENABLE_BIT);
983       glCallList(set->priv->chessList);
984       glPopAttrib();
985 
986       glPushMatrix();
987       glTranslated(-centre[0], -centre[1], -centre[2]);
988 
989       glEnable(GL_DEPTH_TEST);
990 
991       /* if (!lists && !trueTransparency) */
992       /*   { */
993       /*     visu_gl_ext_callAll(FALSE); */
994       /*     visu_gl_ext_callAll(TRUE); */
995       /*   } */
996       /* else if (!lists && trueTransparency) */
997       /*   { */
998       /*     glDepthMask(1); */
999       /*     glEnable(GL_ALPHA_TEST); */
1000       /*     glAlphaFunc(GL_EQUAL, 1.); */
1001       /*     visu_gl_ext_callAll(FALSE); */
1002       /*     DBG_fprintf(stderr, "OpenGL: second pass for transparency.\n"); */
1003       /*     glAlphaFunc(GL_LESS, 1.); */
1004       /*     glDepthMask(0); */
1005       /*     visu_gl_ext_callAll(FALSE); */
1006       /*     glDepthMask(1); */
1007       /*     glAlphaFunc(GL_ALWAYS, 1.); */
1008       /*     glDisable(GL_ALPHA_TEST); */
1009       /*     visu_gl_ext_callAll(TRUE); */
1010       /*   } */
1011       /* else */ if (!visu_gl_getTrueTransparency(VISU_GL(set)))
1012         for (i = 0; i < set->priv->set->len; i++)
1013           visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE);
1014       else
1015         {
1016           glDepthMask(1);
1017           glEnable(GL_ALPHA_TEST);
1018           glAlphaFunc(GL_EQUAL, 1.);
1019           for (i = 0; i < set->priv->set->len; i++)
1020             visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE);
1021           DBG_fprintf(stderr, "Visu Extension Set: second pass for transparency.\n");
1022           glAlphaFunc(GL_LESS, 1.);
1023           glDepthMask(0);
1024           for (i = 0; i < set->priv->set->len; i++)
1025             visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, FALSE);
1026           glDepthMask(1);
1027           glAlphaFunc(GL_ALWAYS, 1.);
1028           glDisable(GL_ALPHA_TEST);
1029         }
1030       for (i = 0; i < set->priv->set->len; i++)
1031         visu_gl_ext_call(g_array_index(set->priv->set, struct _GlExt, i).ext, TRUE);
1032 
1033       glPopMatrix();
1034     }
1035   set->priv->dirty = FALSE;
1036 
1037 #if DEBUG == 1
1038   glFlush();
1039   g_timer_stop(timer);
1040   fprintf(stderr, "Visu Extension Set: lists drawn in %g micro-s.\n",
1041           g_timer_elapsed(timer, &fractionTimer)*1e6);
1042   g_timer_destroy(timer);
1043 #endif
1044 }
1045 
1046 /**
1047  * visu_gl_ext_set_setBgColor:
1048  * @set: a #VisuGlExtSet object.
1049  * @rgba: (in) (array fixed-size=4): a three floats array with values
1050  * (0 <= values <= 1) for the red, the green and the blue color. Only
1051  * values specified by the mask are really relevant.
1052  * @mask: use #TOOL_COLOR_MASK_R, #TOOL_COLOR_MASK_G,
1053  * #TOOL_COLOR_MASK_B, #TOOL_COLOR_MASK_RGBA or a combinaison to
1054  * indicate what values in the rgb array must be taken into account.
1055  *
1056  * Method used to change the value of the parameter background_color.
1057  *
1058  * Since: 3.8
1059  *
1060  * Returns: TRUE if changed.
1061  */
visu_gl_ext_set_setBgColor(VisuGlExtSet * set,float rgba[4],int mask)1062 gboolean visu_gl_ext_set_setBgColor(VisuGlExtSet *set, float rgba[4], int mask)
1063 {
1064   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1065 
1066   g_object_freeze_notify(G_OBJECT(set));
1067   if (mask & TOOL_COLOR_MASK_R && set->priv->bgRGB[0] != rgba[0])
1068     {
1069       set->priv->bgRGB[0] = CLAMP(rgba[0], 0.f, 1.f);
1070       g_object_notify_by_pspec(G_OBJECT(set), properties[BG_R_PROP]);
1071       set->priv->bgDirty = TRUE;
1072     }
1073   if (mask & TOOL_COLOR_MASK_G && set->priv->bgRGB[1] != rgba[1])
1074     {
1075       set->priv->bgRGB[1] = CLAMP(rgba[1], 0.f, 1.f);
1076       g_object_notify_by_pspec(G_OBJECT(set), properties[BG_G_PROP]);
1077       set->priv->bgDirty = TRUE;
1078     }
1079   if (mask & TOOL_COLOR_MASK_B && set->priv->bgRGB[2] != rgba[2])
1080     {
1081       set->priv->bgRGB[2] = CLAMP(rgba[2], 0.f, 1.f);
1082       g_object_notify_by_pspec(G_OBJECT(set), properties[BG_B_PROP]);
1083       set->priv->bgDirty = TRUE;
1084     }
1085   if (mask & TOOL_COLOR_MASK_A && set->priv->bgRGB[3] != rgba[3])
1086     {
1087       set->priv->bgRGB[3] = CLAMP(rgba[3], 0.f, 1.f);
1088       g_object_notify_by_pspec(G_OBJECT(set), properties[BG_A_PROP]);
1089       set->priv->bgDirty = TRUE;
1090     }
1091   g_object_thaw_notify(G_OBJECT(set));
1092   if (set->priv->bgDirty)
1093     _appendDirty(set);
1094   return set->priv->bgDirty;
1095 }
1096 
1097 /**
1098  * visu_gl_ext_set_getBgColor:
1099  * @set: a #VisuGlExtSet object.
1100  * @rgba: (array fixed-size=4) (out): a storage for four values.
1101  *
1102  * Read the RGBA value of the specific background colour (in [0;1]).
1103  *
1104  * Since: 3.8
1105  */
visu_gl_ext_set_getBgColor(const VisuGlExtSet * set,float rgba[4])1106 void visu_gl_ext_set_getBgColor(const VisuGlExtSet *set, float rgba[4])
1107 {
1108   g_return_if_fail(VISU_IS_GL_EXT_SET(set));
1109 
1110   memcpy(rgba, set->priv->bgRGB, sizeof(float) * 4);
1111 }
1112 
_chessDraw(VisuGlExtSet * set)1113 static void _chessDraw(VisuGlExtSet *set)
1114 {
1115   GLubyte chessboard[32][32][3];
1116   int viewport[4];
1117   int i, j, c;
1118 
1119   if (!set->priv->bgDirty)
1120     return;
1121 
1122   if (set->priv->bgRGB[3] < 1.f && !(visu_gl_getHint(VISU_GL(set)) & VISU_GL_OFFSCREEN))
1123     {
1124       DBG_fprintf(stderr, "Visu Extension Set: set background chess board (alpha = %g).\n",
1125                   set->priv->bgRGB[3]);
1126 
1127       if (texName == 0)
1128         glGenTextures(1, &texName);
1129 
1130       /* We create the chessboard texture with the right colour. */
1131       for (i = 0; i < 32; i++)
1132         for (j = 0; j < 32; j++)
1133           {
1134             c = 128 + ( ((i&0x10)==0) ^ ((j&0x10) == 0) ) * 64;
1135             chessboard[i][j][0] =
1136               (GLubyte)(255.f * set->priv->bgRGB[0] * set->priv->bgRGB[3] +
1137                         (1.f - set->priv->bgRGB[3]) * c);
1138             chessboard[i][j][1] =
1139               (GLubyte)(255.f * set->priv->bgRGB[1] * set->priv->bgRGB[3] +
1140                         (1.f - set->priv->bgRGB[3]) * c);
1141             chessboard[i][j][2] =
1142               (GLubyte)(255.f * set->priv->bgRGB[2] * set->priv->bgRGB[3] +
1143                         (1.f - set->priv->bgRGB[3]) * c);
1144           }
1145       /* We bind the texture. */
1146       glBindTexture(GL_TEXTURE_2D, texName);
1147       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1148       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1149       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1150       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1151 
1152       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1153       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 32, 32, 0,
1154                    GL_RGB, GL_UNSIGNED_BYTE, chessboard);
1155 
1156       glGetIntegerv(GL_VIEWPORT, viewport);
1157 
1158       glNewList(set->priv->chessList, GL_COMPILE);
1159       glDisable(GL_CULL_FACE);
1160       glDisable(GL_LIGHTING);
1161 
1162       glEnable(GL_TEXTURE_2D);
1163       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1164       glBindTexture(GL_TEXTURE_2D, texName);
1165 
1166       glMatrixMode(GL_PROJECTION);
1167       glPushMatrix();
1168       glLoadIdentity();
1169       gluOrtho2D(0., (float)viewport[2], 0., (float)viewport[3]);
1170       glMatrixMode(GL_MODELVIEW);
1171       glPushMatrix();
1172       glLoadIdentity();
1173 
1174       glDepthMask(0);
1175       glBegin(GL_QUADS);
1176       glTexCoord2f(0.0, 0.0);
1177       glVertex3f(0.0, 0.0, 0.0);
1178       glTexCoord2f(0.0, (float)viewport[3] / 32.f);
1179       glVertex3f(0.0, (float)viewport[3], 0.0);
1180       glTexCoord2f((float)viewport[2] / 32.f, (float)viewport[3] / 32.f);
1181       glVertex3f((float)viewport[2], (float)viewport[3], 0.0);
1182       glTexCoord2f((float)viewport[2] / 32.f, 0.0);
1183       glVertex3f((float)viewport[2], 0.0, 0.0);
1184       glEnd();
1185       glDepthMask(1);
1186 
1187       glPopMatrix();
1188       glMatrixMode(GL_PROJECTION);
1189       glPopMatrix();
1190       glMatrixMode(GL_MODELVIEW);
1191 
1192       glDisable(GL_TEXTURE_2D);
1193       glEndList();
1194     }
1195   else
1196     glDeleteLists(set->priv->chessList, 1);
1197   set->priv->bgDirty = FALSE;
1198 }
1199 
1200 /**
1201  * visu_gl_ext_set_setFogColor:
1202  * @set: a #VisuGlExtSet object.
1203  * @rgba: (array fixed-size=4): four [0;1] float values.
1204  * @mask: a mask, see %TOOL_COLOR_MASK_R for instance.
1205  *
1206  * Change the fog specific colour. Activate it with
1207  * visu_gl_ext_set_setFogFollowsBg().
1208  *
1209  * Since: 3.8
1210  *
1211  * Returns: TRUE if value is actually changed.
1212  **/
visu_gl_ext_set_setFogColor(VisuGlExtSet * set,float rgba[4],int mask)1213 gboolean visu_gl_ext_set_setFogColor(VisuGlExtSet *set, float rgba[4], int mask)
1214 {
1215   gboolean diff;
1216 
1217   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1218 
1219   diff = FALSE;
1220   g_object_freeze_notify(G_OBJECT(set));
1221   if (mask & TOOL_COLOR_MASK_R && set->priv->fogRGB[0] != rgba[0])
1222     {
1223       set->priv->fogRGB[0] = CLAMP(rgba[0], 0.f, 1.f);
1224       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_R_PROP]);
1225       diff = TRUE;
1226     }
1227   if (mask & TOOL_COLOR_MASK_G && set->priv->fogRGB[1] != rgba[1])
1228     {
1229       set->priv->fogRGB[1] = CLAMP(rgba[1], 0.f, 1.f);
1230       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_G_PROP]);
1231       diff = TRUE;
1232     }
1233   if (mask & TOOL_COLOR_MASK_B && set->priv->fogRGB[2] != rgba[2])
1234     {
1235       set->priv->fogRGB[2] = CLAMP(rgba[2], 0.f, 1.f);
1236       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_B_PROP]);
1237       diff = TRUE;
1238     }
1239   if (mask & TOOL_COLOR_MASK_A && set->priv->fogRGB[3] != rgba[3])
1240     {
1241       set->priv->fogRGB[3] = CLAMP(rgba[3], 0.f, 1.f);
1242       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_A_PROP]);
1243       diff = TRUE;
1244     }
1245   g_object_thaw_notify(G_OBJECT(set));
1246   if (diff && set->priv->fogActive)
1247     _appendDirty(set);
1248   return diff;
1249 }
1250 /**
1251  * visu_gl_ext_set_setFogActive:
1252  * @set: a #VisuGlExtSet object.
1253  * @value: a boolean.
1254  *
1255  * Activates the fog rendering, or not.
1256  *
1257  * Since: 3.8
1258  *
1259  * Returns: TRUE if value is actually changed.
1260  **/
visu_gl_ext_set_setFogActive(VisuGlExtSet * set,gboolean value)1261 gboolean visu_gl_ext_set_setFogActive(VisuGlExtSet *set, gboolean value)
1262 {
1263   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1264 
1265   if (set->priv->fogActive == value)
1266     return FALSE;
1267 
1268   set->priv->fogActive = value;
1269   g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_ACTIVE_PROP]);
1270   _appendDirty(set);
1271   return TRUE;
1272 }
1273 /**
1274  * visu_gl_ext_set_setFogFollowsBg:
1275  * @set: a #VisuGlExtSet object.
1276  * @value: a boolean.
1277  *
1278  * Specifies if the fog is coloured with the background colour or with
1279  * its own colour, see visu_gl_ext_set_setFogColor().
1280  *
1281  * Since: 3.8
1282  *
1283  * Returns: TRUE if value is actually changed.
1284  **/
visu_gl_ext_set_setFogFollowsBg(VisuGlExtSet * set,gboolean value)1285 gboolean visu_gl_ext_set_setFogFollowsBg(VisuGlExtSet *set, gboolean value)
1286 {
1287   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1288 
1289   if (set->priv->fogFollowsBg == value)
1290     return FALSE;
1291 
1292   set->priv->fogFollowsBg = value;
1293   g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_FOLLOWS_PROP]);
1294   if (set->priv->fogActive)
1295     _appendDirty(set);
1296   return TRUE;
1297 }
1298 /**
1299  * visu_gl_ext_set_setFogStartFull:
1300  * @set: a #VisuGlExtSet object.
1301  * @startEnd: (array fixed-size=2): two [0;1] floating point values.
1302  * @mask: a mask, see %VISU_GL_EXT_SET_FOG_MASK_START and
1303  * %VISU_GL_EXT_SET_FOG_MASK_FULL.
1304  *
1305  * Change the starting and ending point of fog.
1306  *
1307  * Since: 3.8
1308  *
1309  * Returns: TRUE if values are actually changed.
1310  **/
visu_gl_ext_set_setFogStartFull(VisuGlExtSet * set,float startEnd[2],int mask)1311 gboolean visu_gl_ext_set_setFogStartFull(VisuGlExtSet *set, float startEnd[2], int mask)
1312 {
1313   gboolean diff;
1314 
1315   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1316 
1317   diff = FALSE;
1318   g_object_freeze_notify(G_OBJECT(set));
1319   if (mask & VISU_GL_EXT_SET_FOG_MASK_START && set->priv->fogStartEnd[0] != startEnd[0])
1320     {
1321       set->priv->fogStartEnd[0] = CLAMP(startEnd[0], 0.f, 1.f);
1322       if (mask & VISU_GL_EXT_SET_FOG_MASK_FULL)
1323 	{
1324 	  if (set->priv->fogStartEnd[0] >= startEnd[1])
1325 	    set->priv->fogStartEnd[0] = startEnd[1] - 0.001;
1326 	}
1327       else
1328 	if (set->priv->fogStartEnd[0] >= set->priv->fogStartEnd[1])
1329 	  set->priv->fogStartEnd[0] = set->priv->fogStartEnd[1] - 0.001;
1330       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_START_PROP]);
1331       diff = TRUE;
1332     }
1333   if (mask & VISU_GL_EXT_SET_FOG_MASK_FULL && set->priv->fogStartEnd[1] != startEnd[1])
1334     {
1335       set->priv->fogStartEnd[1] = CLAMP(startEnd[1], 0.f, 1.f);
1336       if (set->priv->fogStartEnd[1] <= set->priv->fogStartEnd[0])
1337 	set->priv->fogStartEnd[1] = set->priv->fogStartEnd[0] + 0.001;
1338       g_object_notify_by_pspec(G_OBJECT(set), properties[FOG_FULL_PROP]);
1339       diff = TRUE;
1340     }
1341   g_object_thaw_notify(G_OBJECT(set));
1342   if (diff && set->priv->fogActive)
1343     _appendDirty(set);
1344   return diff;
1345 }
1346 
1347 /**
1348  * visu_gl_ext_set_getFogColor:
1349  * @set: a #VisuGlExtSet object.
1350  * @rgba: (out) (array fixed-size=4): a storage for three values.
1351  *
1352  * Gives the actual fog color, for the specific color, use
1353  * visu_gl_ext_set_getFogSpecificColor().
1354  *
1355  * Since: 3.8
1356  */
visu_gl_ext_set_getFogColor(VisuGlExtSet * set,float rgba[4])1357 void visu_gl_ext_set_getFogColor(VisuGlExtSet *set, float rgba[4])
1358 {
1359   g_return_if_fail(VISU_IS_GL_EXT_SET(set));
1360   if (set->priv->fogFollowsBg)
1361     memcpy(rgba, set->priv->bgRGB, sizeof(float) * 4);
1362   else
1363     memcpy(rgba, set->priv->fogRGB, sizeof(float) * 4);
1364 }
1365 /**
1366  * visu_gl_ext_set_getFogSpecificColor:
1367  * @set: a #VisuGlExtSet object.
1368  * @rgba: (out) (array fixed-size=4): a storage for three values.
1369  *
1370  * Gives the specific fog color, for the actual color, use
1371  * visu_gl_ext_set_getFogColor().
1372  *
1373  * Since: 3.8
1374  */
visu_gl_ext_set_getFogSpecificColor(VisuGlExtSet * set,float rgba[4])1375 void visu_gl_ext_set_getFogSpecificColor(VisuGlExtSet *set, float rgba[4])
1376 {
1377   g_return_if_fail(VISU_IS_GL_EXT_SET(set));
1378   memcpy(rgba, set->priv->fogRGB, sizeof(float) * 4);
1379 }
1380 /**
1381  * visu_gl_ext_set_getFogActive:
1382  * @set: a #VisuGlExtSet object.
1383  *
1384  * Read if fog is used or not.
1385  *
1386  * Since: 3.8
1387  *
1388  * Returns: TRUE if the fog is rendered, FALSE otherwise.
1389  */
visu_gl_ext_set_getFogActive(VisuGlExtSet * set)1390 gboolean visu_gl_ext_set_getFogActive(VisuGlExtSet *set)
1391 {
1392   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1393   return set->priv->fogActive;
1394 }
1395 /**
1396  * visu_gl_ext_set_getFogFollowsBg:
1397  * @set: a #VisuGlExtSet object.
1398  *
1399  * Read if fog uses a specific colour or not.
1400  *
1401  * Since: 3.8
1402  *
1403  * Returns: TRUE if the fog uses its own color or FALSE if it uses
1404  * the color of the background.
1405  */
visu_gl_ext_set_getFogFollowsBg(VisuGlExtSet * set)1406 gboolean visu_gl_ext_set_getFogFollowsBg(VisuGlExtSet *set)
1407 {
1408   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), FALSE);
1409   return set->priv->fogFollowsBg;
1410 }
1411 /**
1412  * visu_gl_ext_set_getFogStartFull:
1413  * @set: a #VisuGlExtSet object.
1414  * @startFull: (out caller-allocates) (array fixed-size=2): two float
1415  * location.
1416  *
1417  * Retrieves the starting and ending value (reduced) of fog extension.
1418  *
1419  * Since: 3.8
1420  **/
visu_gl_ext_set_getFogStartFull(VisuGlExtSet * set,float startFull[2])1421 void visu_gl_ext_set_getFogStartFull(VisuGlExtSet *set, float startFull[2])
1422 {
1423   g_return_if_fail(VISU_IS_GL_EXT_SET(set));
1424   memcpy(startFull, set->priv->fogStartEnd, sizeof(float) * 2);
1425 }
1426 
1427 /**
1428  * visu_gl_ext_set_getPixmapData:
1429  * @set: a #VisuGlExtSet object ;
1430  * @width: the desired width or 0 for current ;
1431  * @height: the desired height or 0 for current ;
1432  * @hasAlpha: if TRUE, the returned data is RGBA, else only RGB.
1433  *
1434  * Create an image from the OpenGL area. The size can be changed, using @width and
1435  * @height. If these pointers contains positive values, then they are used to set the
1436  * size for the image. If not, the size of the current #VisuGlView is used and
1437  * stored in these pointers.
1438  *
1439  * Since: 3.8
1440  *
1441  * Returns: (transfer full) (element-type int): image data, row by row.
1442  */
visu_gl_ext_set_getPixmapData(VisuGlExtSet * set,guint width,guint height,gboolean hasAlpha)1443 GArray* visu_gl_ext_set_getPixmapData(VisuGlExtSet *set, guint width,
1444                                       guint height, gboolean hasAlpha)
1445 {
1446   GArray *image;
1447   VisuPixmapContext *dumpData;
1448   guint row_length;
1449   gint m, n1, n2;
1450   guchar *row_tab;
1451   guint oldW, oldH;
1452 
1453   g_return_val_if_fail(VISU_IS_GL_EXT_SET(set), (GArray*)0);
1454   g_return_val_if_fail(VISU_IS_GL_VIEW(set->priv->view), (GArray*)0);
1455 
1456   /* We may change the actual drawing size. */
1457   width  = (width > 0)  ? width  : set->priv->view->window.width;
1458   height = (height > 0) ? height : set->priv->view->window.height;
1459   oldW = set->priv->view->window.width;
1460   oldH = set->priv->view->window.height;
1461   visu_gl_view_setViewport(set->priv->view, width, height);
1462 
1463   /* We create a pixmap context and make this context current. */
1464   dumpData = visu_pixmap_context_new(width, height);
1465   if (!dumpData)
1466     {
1467       g_warning("can't create off-screen pixmap.");
1468       return (GArray*)0;
1469     }
1470   /* We set the glViewport of this new context. */
1471   visu_gl_initContext(VISU_GL(set));
1472   /* We call the given draw method. */
1473   visu_gl_ext_set_draw(set);
1474   /* We copy the pixmap into generic data. */
1475   if (hasAlpha)
1476     row_length = 4 * width;
1477   else
1478     row_length = 3 * width;
1479   row_tab = g_malloc(sizeof(guchar) * row_length);
1480 
1481   image = g_array_sized_new(FALSE, FALSE, sizeof(guchar), row_length * height);
1482 
1483   glPixelStorei(GL_PACK_ALIGNMENT, 1); /* just in case */
1484 
1485   /* Copy the image into our buffer */
1486   n2 = 0;
1487   for(m = height - 1; m >= 0; m--)
1488     {
1489       if (hasAlpha)
1490 	glReadPixels(0, m, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row_tab);
1491       else
1492 	glReadPixels(0, m, width, 1, GL_RGB, GL_UNSIGNED_BYTE, row_tab);
1493       n1 = n2;
1494       n2 = n1 + row_length;
1495       image = g_array_insert_vals(image, n1, row_tab, n2 - n1);
1496     }
1497   g_free(row_tab);
1498 
1499   DBG_fprintf(stderr, " | save to array %p.\n", (gpointer)image);
1500   /* We free the pixmap context. */
1501   visu_pixmap_context_free(dumpData);
1502 
1503   /* We put back the viewport. */
1504   visu_gl_view_setViewport(set->priv->view, oldW, oldH);
1505 
1506   return image;
1507 }
1508 
1509 /***************************/
1510 /* Dealing with parameters */
1511 /***************************/
onEntryBgColor(VisuGlExtSet * set,VisuConfigFileEntry * entry _U_,VisuConfigFile * obj _U_)1512 static void onEntryBgColor(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
1513 {
1514   visu_gl_ext_set_setBgColor(set, bgRGBDefault, TOOL_COLOR_MASK_RGBA);
1515 }
onEntryFogActive(VisuGlExtSet * set,VisuConfigFileEntry * entry _U_,VisuConfigFile * obj _U_)1516 static void onEntryFogActive(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
1517 {
1518   visu_gl_ext_set_setFogActive(set, fogActiveDefault);
1519 }
onEntryFogSpecific(VisuGlExtSet * set,VisuConfigFileEntry * entry _U_,VisuConfigFile * obj _U_)1520 static void onEntryFogSpecific(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
1521 {
1522   visu_gl_ext_set_setFogFollowsBg(set, !fogSpecificDefault);
1523 }
onEntryFogColor(VisuGlExtSet * set,VisuConfigFileEntry * entry _U_,VisuConfigFile * obj _U_)1524 static void onEntryFogColor(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
1525 {
1526   visu_gl_ext_set_setFogColor(set, fogRGBDefault, TOOL_COLOR_MASK_RGBA);
1527 }
onEntryFogStartEnd(VisuGlExtSet * set,VisuConfigFileEntry * entry _U_,VisuConfigFile * obj _U_)1528 static void onEntryFogStartEnd(VisuGlExtSet *set, VisuConfigFileEntry *entry _U_, VisuConfigFile *obj _U_)
1529 {
1530   visu_gl_ext_set_setFogStartFull(set, fogStartEndDefault,
1531                                   VISU_GL_EXT_SET_FOG_MASK_START |
1532                                   VISU_GL_EXT_SET_FOG_MASK_FULL);
1533 }
onWidthHeight(VisuGlView * view _U_,gpointer data)1534 static void onWidthHeight(VisuGlView *view _U_, gpointer data)
1535 {
1536   VisuGlExtSetPrivate *priv = VISU_GL_EXT_SET(data)->priv;
1537 
1538   DBG_fprintf(stderr, "Visu Extension Set: caught the 'WidthHeightChanged' signal.\n");
1539 
1540   if (priv->bgRGB[3] < 1.f)
1541     priv->bgDirty = TRUE;
1542 }
onCamera(VisuGlView * view _U_,gpointer data)1543 static void onCamera(VisuGlView *view _U_, gpointer data)
1544 {
1545   _appendDirty(VISU_GL_EXT_SET(data));
1546 }
1547 
exportResources(GString * data,VisuData * dataObj _U_)1548 static void exportResources(GString *data, VisuData *dataObj _U_)
1549 {
1550   if (!defaultSet)
1551     return;
1552 
1553   visu_config_file_exportComment(data, DESC_RESOURCE_BG_COLOR);
1554   visu_config_file_exportEntry(data, FLAG_RESOURCE_BG_COLOR, NULL,
1555                                "%4.3f %4.3f %4.3f %4.3f",
1556                                defaultSet->priv->bgRGB[0], defaultSet->priv->bgRGB[1],
1557                                defaultSet->priv->bgRGB[2], defaultSet->priv->bgRGB[3]);
1558 
1559   visu_config_file_exportComment(data, DESC_RESOURCE_FOG_USED);
1560   visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_USED, NULL,
1561                                "%d", defaultSet->priv->fogActive);
1562   visu_config_file_exportComment(data, DESC_RESOURCE_FOG_SPECIFIC);
1563   visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_SPECIFIC, NULL,
1564                                "%d", !defaultSet->priv->fogFollowsBg);
1565   visu_config_file_exportComment(data, DESC_RESOURCE_FOG_COLOR);
1566   visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_COLOR, NULL,
1567                                "%4.3f %4.3f %4.3f %4.3f",
1568                                defaultSet->priv->fogRGB[0], defaultSet->priv->fogRGB[1],
1569                                defaultSet->priv->fogRGB[2], defaultSet->priv->fogRGB[3]);
1570   visu_config_file_exportComment(data, DESC_RESOURCE_FOG_STARTEND);
1571   visu_config_file_exportEntry(data, FLAG_RESOURCE_FOG_STARTEND, NULL,
1572                                "%4.3f %4.3f", defaultSet->priv->fogStartEnd[0],
1573                                defaultSet->priv->fogStartEnd[1]);
1574 
1575   visu_config_file_exportComment(data, "");
1576 }
1577