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