1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Damien
3 	CALISTE, laboratoire L_Sim, (2001-2009)
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, (2001-2009)
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 COPYING.
41 */
42 #include "shade.h"
43 
44 #include <string.h>
45 
46 #include <openGLFunctions/objectList.h>
47 #include <openGLFunctions/text.h>
48 #include <coreTools/toolColor.h>
49 
50 /**
51  * SECTION:shade
52  * @short_description: Draw a frame with the representation of a color shade.
53  *
54  * <para>This extension draws a frame on top of the rendering area
55  * with a color shade. One can setup printed values and draw
56  * additional marks inside the shade.</para>
57  *
58  * Since: 3.7
59  */
60 
61 #define SHADE_LEGEND_N_QUADS 50
62 
63 /**
64  * VisuGlExtShadeClass:
65  * @parent: the parent class;
66  *
67  * A short way to identify #_VisuGlExtShadeClass structure.
68  *
69  * Since: 3.7
70  */
71 /**
72  * VisuGlExtShade:
73  *
74  * An opaque structure.
75  *
76  * Since: 3.7
77  */
78 /**
79  * VisuGlExtShadePrivate:
80  *
81  * Private fields for #VisuGlExtShade objects.
82  *
83  * Since: 3.7
84  */
85 struct _VisuGlExtShadePrivate
86 {
87   /* Shade definition. */
88   ToolShade *shade;
89 
90   /* Parameters. */
91   float minMax[2];
92   ToolMatrixScalingFlag scaling;
93   GArray *marks;
94 };
95 
96 enum {
97   PROP_0,
98   PROP_SHADE,
99   PROP_MM,
100   N_PROPS
101 };
102 static GParamSpec *_properties[N_PROPS];
103 
104 static void visu_gl_ext_shade_finalize(GObject* obj);
105 static void visu_gl_ext_shade_get_property(GObject* obj, guint property_id,
106                                            GValue *value, GParamSpec *pspec);
107 static void visu_gl_ext_shade_set_property(GObject* obj, guint property_id,
108                                            const GValue *value, GParamSpec *pspec);
109 static gboolean visu_gl_ext_shade_isValid(const VisuGlExtFrame *frame);
110 static void visu_gl_ext_shade_draw(const VisuGlExtFrame *frame);
111 static void visu_gl_ext_shade_rebuild(VisuGlExt *ext);
112 
G_DEFINE_TYPE_WITH_CODE(VisuGlExtShade,visu_gl_ext_shade,VISU_TYPE_GL_EXT_FRAME,G_ADD_PRIVATE (VisuGlExtShade))113 G_DEFINE_TYPE_WITH_CODE(VisuGlExtShade, visu_gl_ext_shade, VISU_TYPE_GL_EXT_FRAME,
114                         G_ADD_PRIVATE(VisuGlExtShade))
115 
116 static void visu_gl_ext_shade_class_init(VisuGlExtShadeClass *klass)
117 {
118   DBG_fprintf(stderr, "Extension Shade: creating the class of the object.\n");
119   /* DBG_fprintf(stderr, "                - adding new signals ;\n"); */
120 
121   /* DBG_fprintf(stderr, "                - adding new resources ;\n"); */
122 
123   /* Connect the overloading methods. */
124   G_OBJECT_CLASS(klass)->finalize = visu_gl_ext_shade_finalize;
125   G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_shade_set_property;
126   G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_shade_get_property;
127   VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_shade_rebuild;
128   VISU_GL_EXT_FRAME_CLASS(klass)->isValid = visu_gl_ext_shade_isValid;
129   VISU_GL_EXT_FRAME_CLASS(klass)->draw = visu_gl_ext_shade_draw;
130 
131   /**
132    * VisuGlExtShade::shade:
133    *
134    * The colour shade.
135    *
136    * Since: 3.8
137    */
138   _properties[PROP_SHADE] =
139     g_param_spec_boxed("shade", "Shade", "colorization scheme",
140                        TOOL_TYPE_SHADE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
141   /**
142    * VisuGlExtShade::range-min-max:
143    *
144    * Min / max range as used to normalise data.
145    *
146    * Since: 3.8
147    */
148   _properties[PROP_MM] = g_param_spec_boxed("range-min-max", "Range min/max",
149                                             "min / max range to normalise data",
150                                             G_TYPE_ARRAY,
151                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
152 
153   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties);
154 }
155 
visu_gl_ext_shade_init(VisuGlExtShade * obj)156 static void visu_gl_ext_shade_init(VisuGlExtShade *obj)
157 {
158   DBG_fprintf(stderr, "Extension Shade: initializing a new object (%p).\n",
159 	      (gpointer)obj);
160 
161   obj->priv = visu_gl_ext_shade_get_instance_private(obj);
162 
163   /* Private data. */
164   obj->priv->marks      = g_array_new(FALSE, FALSE, sizeof(float));
165   obj->priv->scaling    = TOOL_MATRIX_SCALING_LINEAR;
166   obj->priv->minMax[0]  = G_MAXFLOAT;
167   obj->priv->minMax[1]  = -G_MAXFLOAT;
168   obj->priv->shade      = (ToolShade*)0;
169 }
visu_gl_ext_shade_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)170 static void visu_gl_ext_shade_get_property(GObject* obj, guint property_id,
171                                            GValue *value, GParamSpec *pspec)
172 {
173   VisuGlExtShade *self = VISU_GL_EXT_SHADE(obj);
174   GArray *arr;
175 
176   DBG_fprintf(stderr, "Extension Shade: get property '%s' -> ",
177 	      g_param_spec_get_name(pspec));
178   switch (property_id)
179     {
180     case PROP_SHADE:
181       g_value_set_boxed(value, self->priv->shade);
182       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->shade);
183       break;
184     case PROP_MM:
185       DBG_fprintf(stderr, "%g / %g.\n", self->priv->minMax[0], self->priv->minMax[1]);
186       arr = g_array_sized_new(FALSE, FALSE, sizeof(float), 2);
187       g_array_index(arr, float, 0) = self->priv->minMax[0];
188       g_array_index(arr, float, 1) = self->priv->minMax[1];
189       g_value_take_boxed(value, arr);
190       break;
191     default:
192       /* We don't have any other property... */
193       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
194       break;
195     }
196 }
visu_gl_ext_shade_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)197 static void visu_gl_ext_shade_set_property(GObject* obj, guint property_id,
198                                            const GValue *value, GParamSpec *pspec)
199 {
200   VisuGlExtShade *self = VISU_GL_EXT_SHADE(obj);
201   GArray *arr;
202 
203   DBG_fprintf(stderr, "Visu Data Colorizer Fragment: set property '%s' -> ",
204 	      g_param_spec_get_name(pspec));
205   switch (property_id)
206     {
207     case PROP_SHADE:
208       DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
209       visu_gl_ext_shade_setShade(self, (ToolShade*)g_value_get_boxed(value));
210       break;
211     case PROP_MM:
212       DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
213       arr = (GArray*)g_value_get_boxed(value);
214       visu_gl_ext_shade_setMinMax(self, g_array_index(arr, float, 0),
215                                   g_array_index(arr, float, 1));
216       break;
217     default:
218       /* We don't have any other property... */
219       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
220       break;
221     }
222 }
223 
visu_gl_ext_shade_finalize(GObject * obj)224 static void visu_gl_ext_shade_finalize(GObject* obj)
225 {
226   VisuGlExtShade *shade;
227 
228   g_return_if_fail(obj);
229 
230   DBG_fprintf(stderr, "Extension Shade: finalize object %p.\n", (gpointer)obj);
231 
232   shade = VISU_GL_EXT_SHADE(obj);
233 
234   /* Free privs elements. */
235   DBG_fprintf(stderr, "Extension Shade: free private shade.\n");
236   tool_shade_free(shade->priv->shade);
237   g_array_unref(shade->priv->marks);
238 
239   /* Chain up to the parent class */
240   DBG_fprintf(stderr, "Extension Shade: chain to parent.\n");
241   G_OBJECT_CLASS(visu_gl_ext_shade_parent_class)->finalize(obj);
242   DBG_fprintf(stderr, "Extension Shade: freeing ... OK.\n");
243 }
244 
245 /**
246  * visu_gl_ext_shade_new:
247  * @name: (allow-none): the name to give to the extension (default is #VISU_GL_EXT_SHADE_ID).
248  *
249  * Creates a new #VisuGlExt to draw a shade.
250  *
251  * Since: 3.7
252  *
253  * Returns: a pointer to the #VisuGlExt it created or
254  * NULL otherwise.
255  */
visu_gl_ext_shade_new(const gchar * name)256 VisuGlExtShade* visu_gl_ext_shade_new(const gchar *name)
257 {
258   char *name_ = VISU_GL_EXT_SHADE_ID;
259   char *description = _("Draw the legend of a color shade.");
260   VisuGlExt *shade;
261 #define SHADE_LEGEND_WIDTH  20.f
262 #define SHADE_LEGEND_HEIGHT 175.f
263 
264   DBG_fprintf(stderr,"Extension Shade: new object.\n");
265 
266   shade = g_object_new(VISU_TYPE_GL_EXT_SHADE,
267                        "name", (name)?name:name_, "label", _(name),
268                        "description", description, "saveState", TRUE,
269                        "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LAST, NULL);
270   visu_gl_ext_frame_setPosition(VISU_GL_EXT_FRAME(shade), 0.f, 0.f);
271   visu_gl_ext_frame_setRequisition(VISU_GL_EXT_FRAME(shade),
272                                    SHADE_LEGEND_WIDTH + 5 + 12 * 7,
273                                    SHADE_LEGEND_HEIGHT);
274 
275   return VISU_GL_EXT_SHADE(shade);
276 }
277 /**
278  * visu_gl_ext_shade_setShade:
279  * @ext: The #VisuGlExtShade to attached to.
280  * @shade: the shade to get the color of.
281  *
282  * Attach an #VisuGlView to render to and setup the shade.
283  *
284  * Since: 3.7
285  *
286  * Returns: TRUE if internal shade is changed.
287  **/
visu_gl_ext_shade_setShade(VisuGlExtShade * ext,const ToolShade * shade)288 gboolean visu_gl_ext_shade_setShade(VisuGlExtShade *ext, const ToolShade *shade)
289 {
290   g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(ext), FALSE);
291 
292   if (tool_shade_compare(ext->priv->shade, shade))
293     return FALSE;
294 
295   tool_shade_free(ext->priv->shade);
296   ext->priv->shade = tool_shade_copy(shade);
297 
298   g_object_notify_by_pspec(G_OBJECT(ext), _properties[PROP_SHADE]);
299 
300   visu_gl_ext_setDirty(VISU_GL_EXT(ext), TRUE);
301   return TRUE;
302 }
303 /**
304  * visu_gl_ext_shade_setMinMax:
305  * @shade: the #VisuGlExtShade to update.
306  * @minV: a value.
307  * @maxV: another value.
308  *
309  * Change the minimum and maximum values used on the legend.
310  *
311  * Since: 3.7
312  *
313  * Returns: TRUE if value is actually changed.
314  **/
visu_gl_ext_shade_setMinMax(VisuGlExtShade * shade,float minV,float maxV)315 gboolean visu_gl_ext_shade_setMinMax(VisuGlExtShade *shade, float minV, float maxV)
316 {
317   g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE);
318   g_return_val_if_fail(minV <= maxV, FALSE);
319 
320   if (shade->priv->minMax[0] == minV && shade->priv->minMax[1] == maxV)
321     return FALSE;
322 
323   shade->priv->minMax[0] = minV;
324   shade->priv->minMax[1] = maxV;
325 
326   g_object_notify_by_pspec(G_OBJECT(shade), _properties[PROP_MM]);
327 
328   visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE);
329   return TRUE;
330 }
331 /**
332  * visu_gl_ext_shade_setScaling:
333  * @shade: the #VisuGlExtShade to update.
334  * @scaling: a #ToolMatrixScalingFlag value.
335  *
336  * Change the scaling variation of the shade between the minimum and
337  * the maximum values, see visu_gl_ext_shade_setMinMax().
338  *
339  * Since: 3.7
340  *
341  * Returns: TRUE if value is actually changed.
342  **/
visu_gl_ext_shade_setScaling(VisuGlExtShade * shade,ToolMatrixScalingFlag scaling)343 gboolean visu_gl_ext_shade_setScaling(VisuGlExtShade *shade, ToolMatrixScalingFlag scaling)
344 {
345   g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE);
346 
347   if (shade->priv->scaling == scaling)
348     return FALSE;
349 
350   shade->priv->scaling = scaling;
351 
352   visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE);
353   return TRUE;
354 }
355 /**
356  * visu_gl_ext_shade_setMarks:
357  * @shade: the #VisuGlExtShade to update.
358  * @marks: (array length=n): a list of float values in [0;1].
359  * @n: the length of @marks.
360  *
361  * The legend can draw additional marks in the shade. Setup these
362  * marks with this routine. The first and the last marks of the list will be
363  * rendered bigger than the next ones.
364  *
365  * Since: 3.7
366  *
367  * Returns: TRUE if value is actually changed.
368  **/
visu_gl_ext_shade_setMarks(VisuGlExtShade * shade,float * marks,guint n)369 gboolean visu_gl_ext_shade_setMarks(VisuGlExtShade *shade, float *marks, guint n)
370 {
371   g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(shade), FALSE);
372 
373   g_array_set_size(shade->priv->marks, n);
374   memcpy(shade->priv->marks->data, marks, sizeof(float) * n);
375 
376   visu_gl_ext_setDirty(VISU_GL_EXT(shade), TRUE);
377   return TRUE;
378 }
379 
visu_gl_ext_shade_rebuild(VisuGlExt * ext)380 static void visu_gl_ext_shade_rebuild(VisuGlExt *ext)
381 {
382   visu_gl_text_rebuildFontList();
383   if (VISU_GL_EXT_GET_CLASS(ext)->draw)
384     VISU_GL_EXT_GET_CLASS(ext)->draw(ext);
385 }
386 
visu_gl_ext_shade_isValid(const VisuGlExtFrame * frame)387 static gboolean visu_gl_ext_shade_isValid(const VisuGlExtFrame *frame)
388 {
389   VisuGlExtShade *shade;
390 
391   g_return_val_if_fail(VISU_IS_GL_EXT_SHADE(frame), FALSE);
392   shade = VISU_GL_EXT_SHADE(frame);
393 
394   return (shade->priv->shade && shade->priv->minMax[0] < shade->priv->minMax[1]);
395 }
396 
visu_gl_ext_shade_draw(const VisuGlExtFrame * frame)397 static void visu_gl_ext_shade_draw(const VisuGlExtFrame *frame)
398 {
399   guint i;
400   float yStep, xbuf, scale, sW;
401   float rgba[4];
402   char value[16];
403   tool_matrix_getScaledValue get_inv;
404   VisuGlExtShade *shade;
405 
406   g_return_if_fail(VISU_IS_GL_EXT_SHADE(frame));
407   shade = VISU_GL_EXT_SHADE(frame);
408 
409   scale = visu_gl_ext_frame_getScale(frame);
410   sW = SHADE_LEGEND_WIDTH * scale;
411 
412   /* We draw the colored bar. */
413   tool_shade_valueToRGB(shade->priv->shade, rgba, 0.);
414   glColor4fv(rgba);
415   yStep = (float)frame->height / (float)SHADE_LEGEND_N_QUADS;
416   glBegin(GL_QUAD_STRIP);
417   for (i = 0; i <= SHADE_LEGEND_N_QUADS; i++)
418     {
419       glVertex2f(0, (float)i * yStep);
420       glVertex2f(sW, (float)i * yStep);
421       tool_shade_valueToRGB(shade->priv->shade, rgba,
422                             (float)i / (float)SHADE_LEGEND_N_QUADS);
423       glColor4fv(rgba);
424     }
425   glEnd();
426 
427   switch (shade->priv->scaling)
428     {
429     case TOOL_MATRIX_SCALING_LINEAR:
430       get_inv = tool_matrix_getScaledLinearInv;
431       break;
432     case TOOL_MATRIX_SCALING_LOG:
433       get_inv = tool_matrix_getScaledLogInv;
434       break;
435     case TOOL_MATRIX_SCALING_ZERO_CENTRED_LOG:
436       get_inv = tool_matrix_getScaledZeroCentredLogInv;
437       break;
438     default:
439       get_inv = (tool_matrix_getScaledValue)0;
440       break;
441     }
442   g_return_if_fail(get_inv);
443 
444   glDisable(GL_LINE_SMOOTH);
445 
446   /* We draw some marks. */
447   if (shade->priv->marks)
448     {
449       DBG_fprintf(stderr, "Extension Shade: put %d marks.\n", shade->priv->marks->len);
450       xbuf = 0.f;
451       for (i = 0; i < shade->priv->marks->len; i++)
452 	{
453           if (i == 0 || i == shade->priv->marks->len - 1)
454             {
455               glLineWidth(2 * scale);
456               xbuf = 3.f;
457             }
458           else if (i == 1)
459             {
460               glLineWidth(scale);
461               xbuf = 8.f;
462             }
463 	  yStep = CLAMP(g_array_index(shade->priv->marks, float, i), 0., 1.);
464 	  tool_shade_valueToRGB(shade->priv->shade, rgba, yStep);
465 	  rgba[0] = 1. - rgba[0];
466 	  rgba[1] = 1. - rgba[1];
467 	  rgba[2] = 1. - rgba[2];
468 	  glColor4fv(rgba);
469 	  yStep *= (float)frame->height;
470           yStep = CLAMP(yStep, 2.f * scale, frame->height - scale);
471           glBegin(GL_LINES);
472 	  glVertex2f(xbuf, yStep);
473           glVertex2f(sW - xbuf, yStep);
474           DBG_fprintf(stderr, " - %g.\n", yStep);
475           glEnd();
476 	}
477     }
478 
479   glColor3fv(frame->fontRGB);
480   glLineWidth(scale);
481 
482   /* We draw the frame around. */
483   DBG_fprintf(stderr, "Extension Shade: frame actual size is %dx%d.\n",
484               frame->width, frame->height);
485   glBegin(GL_LINE_STRIP);
486   glVertex2i(1, 1);
487   glVertex2i(sW, 1);
488   glVertex2i(sW, frame->height);
489   glVertex2i(1, frame->height);
490   glVertex2i(1, 1);
491   glEnd();
492   /* We draw the tics. */
493   glBegin(GL_LINES);
494   glVertex2i(sW    , 1);
495   glVertex2i(sW + 3, 1);
496   glVertex2i(sW    , frame->height / 3);
497   glVertex2i(sW + 3, frame->height / 3);
498   glVertex2i(sW    , 2 * frame->height / 3);
499   glVertex2i(sW + 3, 2 * frame->height / 3);
500   glVertex2i(sW    , frame->height);
501   glVertex2i(sW + 3, frame->height);
502   glEnd();
503 
504   /* We print the labels. */
505   sprintf(value, "%.3g", get_inv(0.f, shade->priv->minMax));
506   glRasterPos2i(sW + 5, 0);
507   visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL);
508   sprintf(value, "%.3g", get_inv(0.33333f, shade->priv->minMax));
509   glRasterPos2i(sW + 5, frame->height / 3 - 5);
510   visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL);
511   sprintf(value, "%.3g", get_inv(0.66667f, shade->priv->minMax));
512   glRasterPos2i(sW + 5, 2 * frame->height / 3 - 5);
513   visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL);
514   sprintf(value, "%.3g", get_inv(1.f, shade->priv->minMax));
515   glRasterPos2i(sW + 5, frame->height - 10);
516   visu_gl_text_drawChars(value, VISU_GL_TEXT_NORMAL);
517 }
518