1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 
45 #include "toolShade.h"
46 
47 #include <errno.h>
48 #include <string.h>
49 
50 #include <pango/pango.h>
51 
52 #include <visu_configFile.h>
53 #include "toolConfigFile.h"
54 #include "toolColor.h"
55 
56 /**
57  * SECTION:toolShade
58  * @short_description: ToolShades are color gradients.
59  *
60  * <para>This module allow V_Sim to deal with color gradients. Such a
61  * gradient is defined by a linear transformation of color space. This
62  * space can be RBG or HSV (see the enum #ToolShadeColorMode). This linear
63  * transformation can be written [resulting color vector] = [vectB] +
64  * lambda.[vectA], where lambda denotes the input variable of the
65  * gradient (ranging from 0 to 1). Resulting color vector are clamped
66  * to [0;1] if needed.</para>
67  * <para>Use tool_shade_new() to create a new shade, giving the arguments as
68  * defined above.</para>
69  * <para>To share color gradients between modules in V_Sim, you can
70  * find a global list of stored shades with tool_shade_getStorage().
71  * This is a #ToolPool object. Use tool_pool_add() to add a new shade
72  * to it.</para>
73  */
74 
75 
76 #define SHADE_LEGEND_WIDTH 0.05
77 #define SHADE_LEGEND_HEIGHT 0.3
78 #define SHADE_LEGEND_N_QUADS 20
79 
80 #define FLAG_SHADE "shade_palette"
81 #define DESC_SHADE "Define a new shade by giving colours to points ; label (val [name|#rgb|#rrggbb|...], ...)"
82 static void exportParameters(GString *data, VisuData *dataObj);
83 static gboolean readShade(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines,int position,
84                           GError **error);
85 static gboolean parseValue(gchar *line, float *index, float rgb[3], GError **error);
86 static void _buildPresetList(void);
87 
88 struct _ToolShade
89 {
90   gchar* labelUTF8;
91   ToolShadeColorMode colorMode;
92   ToolShadeMode mode;
93 
94   /* The linear storage. */
95   float vectA[3], vectB[3];
96   /* The array storage. */
97   float *index;
98   float *vectCh[3];
99   guint nVals;
100 
101   /* Some user defined values. */
102   gboolean userDefined;
103   gchar *steps;
104 };
105 
106 static ToolPool *shadePool = NULL;
107 
108 /**
109  * tool_shade_get_type:
110  *
111  * Create and retrieve a #GType for a #ToolShade object.
112  *
113  * Since: 3.7
114  *
115  * Returns: a new type for #ToolShade structures.
116  */
tool_shade_get_type(void)117 GType tool_shade_get_type(void)
118 {
119   static GType g_define_type_id = 0;
120   VisuConfigFileEntry *entry;
121 
122   if (g_define_type_id == 0)
123     {
124       g_define_type_id = g_boxed_type_register_static("ToolShade",
125                                                       (GBoxedCopyFunc)tool_shade_copy,
126                                                       (GBoxedFreeFunc)tool_shade_free);
127 
128       /* Set private variables. */
129       entry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE,
130                                         FLAG_SHADE, DESC_SHADE,
131                                         1, readShade);
132       visu_config_file_entry_setVersion(entry, 3.7f);
133       visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE,
134                                          exportParameters);
135     }
136 
137   return g_define_type_id;
138 }
139 
140 /**
141  * tool_shade_getById:
142  * @id: an id.
143  *
144  * Convenience function calling tool_pool_getById() on the default
145  * #ToolShade storage.
146  *
147  * Since: 3.8
148  *
149  * Returns: a #ToolShade from the pool.
150  **/
tool_shade_getById(guint id)151 const ToolShade* tool_shade_getById(guint id)
152 {
153   return tool_pool_getById(tool_shade_getStorage(), id);
154 }
155 
156 /**
157  * tool_shade_new:
158  * @labelUTF8: a UTF8 string that shortly named this new shade ;
159  * @vectA: an array of three floating point values ;
160  * @vectB: an array of three floating point values ;
161  * @colorMode: an integer that describes the color code (see #ToolShadeColorMode enumeration).
162  *
163  * Create a linear shade. Its profile is given by an AX+B formula,
164  * dealing on three channels. These channels are defined by the
165  * @colorMode parameter. All given values are copied when the new
166  * shade is created.
167  *
168  * Returns: the newly created ToolShade.
169  */
tool_shade_new(const gchar * labelUTF8,float vectA[3],float vectB[3],ToolShadeColorMode colorMode)170 ToolShade* tool_shade_new(const gchar* labelUTF8, float vectA[3], float vectB[3],
171                           ToolShadeColorMode colorMode)
172 {
173   ToolShade *shade;
174   int i;
175 
176   g_return_val_if_fail(labelUTF8 && vectA && vectB &&
177 		       colorMode < TOOL_SHADE_COLOR_MODE_N_VALUES, (ToolShade*)0);
178 
179   DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (linear):");
180   shade = g_malloc(sizeof(ToolShade));
181   shade->labelUTF8 = g_strdup(labelUTF8);
182   for (i = 0; i < 3; i++)
183     {
184       shade->vectA[i] = vectA[i];
185       shade->vectB[i] = vectB[i];
186     }
187   shade->index     = (float*)0;
188   shade->vectCh[0] = (float*)0;
189   shade->vectCh[1] = (float*)0;
190   shade->vectCh[2] = (float*)0;
191   shade->colorMode = colorMode;
192   shade->mode      = TOOL_SHADE_MODE_LINEAR;
193   shade->userDefined = TRUE;
194   shade->steps     = (gchar*)0;
195 
196   DBG_fprintf(stderr, " %p.\n", (gpointer)shade);
197   return shade;
198 }
199 /**
200  * tool_shade_newFromData:
201  * @labelUTF8: a UTF8 string that shortly named this new shade ;
202  * @len: the size of arguments @vectCh1, @vectCh2 and @vectCh3 ;
203  * @vectCh1: an array of floating point values for the first channel ;
204  * @vectCh2: an array of floating point values for the second channel ;
205  * @vectCh3: an array of floating point values for the third channel ;
206  * @colorMode: an integer that describes the color code (see
207  * #ToolShadeColorMode enumeration).
208  *
209  * Create a #ToolShade from direct data for three channels. These channels
210  * are defined by the @colorMode parameter. All given values are
211  * copied when the new shade is created.
212  *
213  * Returns: the newly created ToolShade.
214  */
tool_shade_newFromData(const gchar * labelUTF8,guint len,float * vectCh1,float * vectCh2,float * vectCh3,ToolShadeColorMode colorMode)215 ToolShade* tool_shade_newFromData(const gchar* labelUTF8, guint len, float *vectCh1,
216                                   float *vectCh2, float *vectCh3, ToolShadeColorMode colorMode)
217 {
218   ToolShade *shade;
219   guint i;
220 
221   g_return_val_if_fail(labelUTF8 && vectCh1 && vectCh2 && vectCh3 &&
222 		       colorMode < TOOL_SHADE_COLOR_MODE_N_VALUES && len > 0, (ToolShade*)0);
223 
224   DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (array):");
225   shade = g_malloc(sizeof(ToolShade));
226   shade->labelUTF8 = g_strdup(labelUTF8);
227   shade->colorMode = colorMode;
228   shade->mode      = TOOL_SHADE_MODE_ARRAY;
229   shade->nVals     = len;
230   shade->index     = g_malloc(sizeof(float) * len);
231   shade->vectCh[0] = g_malloc(sizeof(float) * len);
232   shade->vectCh[1] = g_malloc(sizeof(float) * len);
233   shade->vectCh[2] = g_malloc(sizeof(float) * len);
234   for (i = 0; i < len; i++)
235     shade->index[i] = (float)i / (float)(len - 1);
236   memcpy(shade->vectCh[0], vectCh1, sizeof(float) * len);
237   memcpy(shade->vectCh[1], vectCh2, sizeof(float) * len);
238   memcpy(shade->vectCh[2], vectCh3, sizeof(float) * len);
239   shade->userDefined = TRUE;
240   shade->steps     = (gchar*)0;
241 
242   DBG_fprintf(stderr, " %p.\n", (gpointer)shade);
243   return shade;
244 }
245 /**
246  * tool_shade_newFromSteps:
247  * @labelUTF8: a UTF8 string that shortly named this new shade ;
248  * @lst: (transfer none) (element-type ToolShadeStep*): a list of
249  * color steps.
250  * @colorMode: a #ToolShadeColorMode mode.
251  *
252  * Create a #ToolShade from a set of steps defining colours at given
253  * indexes. These channels are defined by the @colorMode
254  * parameter. All given values are copied when the new shade is
255  * created. The values of indexes will be normalised by this call to
256  * range in [0;1]. Colour channel values must be in [0;1] for each step.
257  *
258  * Since: 3.7
259  *
260  * Returns: (transfer full): the newly created ToolShade.
261  */
tool_shade_newFromSteps(const gchar * labelUTF8,GList * lst,ToolShadeColorMode colorMode)262 ToolShade* tool_shade_newFromSteps(const gchar* labelUTF8, GList *lst,
263                                    ToolShadeColorMode colorMode)
264 {
265   ToolShade *shade;
266   float minVal, maxVal, f;
267   GList *tmp;
268   ToolShadeStep *step;
269   guint i;
270 
271   g_return_val_if_fail(labelUTF8 && lst && (g_list_length(lst) > 1), (ToolShade*)0);
272 
273   DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (array):\n");
274   shade = g_malloc(sizeof(ToolShade));
275   shade->labelUTF8 = g_strdup(labelUTF8);
276   shade->nVals     = g_list_length(lst);
277   shade->index     = g_malloc(sizeof(float) * shade->nVals);
278   shade->vectCh[0] = g_malloc(sizeof(float) * shade->nVals);
279   shade->vectCh[1] = g_malloc(sizeof(float) * shade->nVals);
280   shade->vectCh[2] = g_malloc(sizeof(float) * shade->nVals);
281   shade->colorMode = colorMode;
282   shade->mode      = TOOL_SHADE_MODE_ARRAY;
283   shade->userDefined = TRUE;
284   shade->steps     = (gchar*)0;
285 
286   /* Normalise entry. */
287   minVal =  G_MAXFLOAT;
288   maxVal = -G_MAXFLOAT;
289   for (tmp = lst; tmp; tmp = g_list_next(tmp))
290     {
291       minVal = MIN(minVal, ((ToolShadeStep*)tmp->data)->index);
292       maxVal = MAX(maxVal, ((ToolShadeStep*)tmp->data)->index);
293     }
294   f = 1.f / (maxVal - minVal);
295   DBG_fprintf(stderr, " | applying factor %g to index\n", f);
296 
297   for (tmp = lst, i = 0; tmp; tmp = g_list_next(tmp), i++)
298     {
299       step = (ToolShadeStep*)tmp->data;
300       shade->index[i] = (step->index - minVal) * f;
301       shade->vectCh[0][i] = CLAMP(step->channels[0], 0.f, 1.f);
302       shade->vectCh[1][i] = CLAMP(step->channels[1], 0.f, 1.f);
303       shade->vectCh[2][i] = CLAMP(step->channels[2], 0.f, 1.f);
304     }
305 
306   DBG_fprintf(stderr, " | done %p.\n", (gpointer)shade);
307   return shade;
308 }
309 /**
310  * tool_shade_newFromString:
311  * @labelUTF8: a UTF8 string that shortly named this new shade ;
312  * @descr: a string with the shade description.
313  * @colorMode: a #ToolShadeColorMode mode.
314  * @error: (allow-none): a location for an error.
315  *
316  * As tool_shade_newFromSteps() routine, but it takes an unparsed
317  * string describing the steps in @descr.
318  *
319  * Since: 3.7
320  *
321  * Returns: (transfer full): the newly created ToolShade.
322  */
tool_shade_newFromString(const gchar * labelUTF8,const gchar * descr,ToolShadeColorMode colorMode,GError ** error)323 ToolShade* tool_shade_newFromString(const gchar* labelUTF8, const gchar *descr,
324                                     ToolShadeColorMode colorMode, GError **error)
325 {
326   ToolShade *shade;
327   gchar **tokens;
328   guint i;
329   GList *lst;
330   ToolShadeStep *step;
331 
332   g_return_val_if_fail(labelUTF8 && descr && error, (ToolShade*)0);
333 
334   DBG_fprintf(stderr, "Tool ToolShade: create a new ToolShade object (string): %s\n", descr);
335 
336   /* Read @size boolean values from @line. */
337   lst = (GList*)0;
338   tokens = g_strsplit_set(descr, ",", TOOL_MAX_LINE_LENGTH);
339   for (i = 0; tokens[i]; i++)
340     if (tokens[i][0])
341       {
342         step = g_malloc(sizeof(ToolShadeStep));
343         lst = g_list_append(lst, step);
344         if (!parseValue(tokens[i], &(step->index), step->channels, error))
345           {
346             g_strfreev(tokens);
347             g_list_free_full(lst, g_free);
348             return FALSE;
349           }
350       }
351 
352   shade = tool_shade_newFromSteps(labelUTF8, lst, colorMode);
353   if (shade)
354     shade->steps = g_strdup(descr);
355 
356   g_strfreev(tokens);
357   g_list_free_full(lst, g_free);
358 
359   return shade;
360 }
361 /**
362  * tool_shade_free:
363  * @shade: a #ToolShade.
364  *
365  * Free all dynamic memory from @shade and free @shade itself.
366  */
tool_shade_free(ToolShade * shade)367 void tool_shade_free(ToolShade *shade)
368 {
369   if (shade)
370     {
371       DBG_fprintf(stderr, "Tool Shade: freeing %p.\n", (gpointer)shade);
372       g_free(shade->labelUTF8);
373       g_free(shade->index);
374       g_free(shade->vectCh[0]);
375       g_free(shade->vectCh[1]);
376       g_free(shade->vectCh[2]);
377       g_free(shade->steps);
378       g_free(shade);
379     }
380 }
381 /**
382  * tool_shade_copy:
383  * @shade: a #ToolShade.
384  *
385  * Create a new shade deep copy of the first.
386  *
387  * Returns: a newly created shade.
388  */
tool_shade_copy(const ToolShade * shade)389 ToolShade* tool_shade_copy(const ToolShade *shade)
390 {
391   ToolShade *out;
392 
393   if (!shade)
394     return (ToolShade*)0;
395 
396   out = g_malloc(sizeof(ToolShade));
397   out->labelUTF8 = g_strdup(shade->labelUTF8);
398   out->colorMode = shade->colorMode;
399   out->mode      = shade->mode;
400   out->nVals     = shade->nVals;
401   out->vectA[0]  = shade->vectA[0];
402   out->vectA[1]  = shade->vectA[1];
403   out->vectA[2]  = shade->vectA[2];
404   out->vectB[0]  = shade->vectB[0];
405   out->vectB[1]  = shade->vectB[1];
406   out->vectB[2]  = shade->vectB[2];
407   out->index     = g_memdup(shade->index,     sizeof(float) * out->nVals);
408   out->vectCh[0] = g_memdup(shade->vectCh[0], sizeof(float) * out->nVals);
409   out->vectCh[1] = g_memdup(shade->vectCh[1], sizeof(float) * out->nVals);
410   out->vectCh[2] = g_memdup(shade->vectCh[2], sizeof(float) * out->nVals);
411   out->userDefined = shade->userDefined;
412   out->steps     = g_strdup(shade->steps);
413 
414   return out;
415 }
_compare(const ToolShade * sh1,const ToolShade * sh2)416 static gint _compare(const ToolShade* sh1, const ToolShade *sh2)
417 {
418   guint i;
419   gboolean equal;
420 
421   if (!sh1 && !sh2)
422     return 0;
423   if (!sh1)
424     return -1;
425   if (!sh2)
426     return +1;
427 
428   if (sh1->mode != sh2->mode)
429     return (sh2 - sh1);
430   if (sh1->colorMode != sh2->colorMode)
431     return (sh2 - sh1);
432 
433   if (sh1->mode == TOOL_SHADE_MODE_LINEAR)
434     return (sh1->vectA[0] == sh2->vectA[0] &&
435 	    sh1->vectA[1] == sh2->vectA[1] &&
436 	    sh1->vectA[2] == sh2->vectA[2] &&
437 	    sh1->vectB[0] == sh2->vectB[0] &&
438 	    sh1->vectB[1] == sh2->vectB[1] &&
439 	    sh1->vectB[2] == sh2->vectB[2]) ? 0 : (sh2 - sh1);
440   else
441     {
442       if (sh1->nVals != sh2->nVals)
443 	return (sh2 - sh1);
444       equal = TRUE;
445       for (i = 0; i < sh1->nVals && equal; i++)
446 	equal = equal && (sh1->index[i] == sh2->index[i]) &&
447           (sh1->vectCh[0][i] == sh2->vectCh[0][i]) &&
448 	  (sh1->vectCh[1][i] == sh2->vectCh[1][i]) &&
449 	  (sh1->vectCh[2][i] == sh2->vectCh[2][i]);
450       return equal ? 0 : (sh2 - sh1);
451     }
452 }
453 /**
454  * tool_shade_compare:
455  * @sh1: a #ToolShade ;
456  * @sh2: a #ToolShade.
457  *
458  * Compare if the two shade are identical (first, smae mode, then same
459  * values).
460  *
461  * Returns: TRUE if @shade1 is equivalent to @shade2.
462  */
tool_shade_compare(const ToolShade * sh1,const ToolShade * sh2)463 gboolean tool_shade_compare(const ToolShade* sh1, const ToolShade *sh2)
464 {
465   return (_compare(sh1, sh2) == 0);
466 }
467 /**
468  * tool_shade_getLabel:
469  * @shade: a valid #ToolShade object.
470  *
471  * Get the name (in UTF8) of the shade.
472  *
473  * Returns: a string naming the shade.
474  */
tool_shade_getLabel(ToolShade * shade)475 gchar* tool_shade_getLabel(ToolShade *shade)
476 {
477   g_return_val_if_fail(shade, (gchar*)0);
478   return shade->labelUTF8;
479 }
480 /**
481  * tool_shade_getColorMode:
482  * @shade: a valid #ToolShade object.
483  *
484  * Get the color mode of the shade (RGB or HSV).
485  *
486  * Returns: the color mode.
487  */
tool_shade_getColorMode(ToolShade * shade)488 ToolShadeColorMode tool_shade_getColorMode(ToolShade *shade)
489 {
490   g_return_val_if_fail(shade, (int)0);
491   return shade->colorMode;
492 }
493 /**
494  * tool_shade_getMode:
495  * @shade: a valid #ToolShade object.
496  *
497  * Get the mode of the shade (linear, array...).
498  *
499  * Returns: the mode.
500  */
tool_shade_getMode(const ToolShade * shade)501 ToolShadeMode tool_shade_getMode(const ToolShade *shade)
502 {
503   g_return_val_if_fail(shade, (int)0);
504   return shade->mode;
505 }
506 /**
507  * tool_shade_setColorMode:
508  * @shade: a #ToolShade ;
509  * @mode: a new mode for the shade.
510  *
511  * Change the mode of the shade, see #ToolShadeColorMode.
512  *
513  * Returns: TRUE if @mode is different from previous @shade mode.
514  */
tool_shade_setColorMode(ToolShade * shade,ToolShadeColorMode mode)515 gboolean tool_shade_setColorMode(ToolShade *shade, ToolShadeColorMode mode)
516 {
517   g_return_val_if_fail(shade, FALSE);
518 
519   if (shade->colorMode == mode)
520     return FALSE;
521 
522   shade->colorMode = mode;
523   return TRUE;
524 }
525 /**
526  * tool_shade_getLinearCoeff:
527  * @shade: a valid #ToolShade object ;
528  * @vectA: a pointer to a floating point values array to store vect in AX+B ;
529  * @vectB: a pointer to a floating point values array to store vect in AX+B.
530  *
531  * This methods can get the linear color transformation. The given
532  * arrays (@vectA, @vectB) are read-only. This method return
533  * FALSE if the @shade is not in a #TOOL_SHADE_MODE_LINEAR state.
534  *
535  * Returns: TRUE if @vectA, @vectB and @vectX have been set correctly.
536  */
tool_shade_getLinearCoeff(const ToolShade * shade,const float ** vectA,const float ** vectB)537 gboolean tool_shade_getLinearCoeff(const ToolShade *shade,
538                                    const float **vectA, const float **vectB)
539 {
540   g_return_val_if_fail(shade, FALSE);
541   g_return_val_if_fail(shade->mode == TOOL_SHADE_MODE_LINEAR, FALSE);
542   g_return_val_if_fail(vectA && vectB, FALSE);
543 
544   *vectA = shade->vectA;
545   *vectB = shade->vectB;
546   return TRUE;
547 }
548 /**
549  * tool_shade_setLinearCoeff:
550  * @shade: a #ToolShade ;
551  * @coeff: a new value ;
552  * @channel: either RGBA (from 0 to 3) ;
553  * @order: the order in the linear approx (0 means constant and 1 is
554  * the linear coeeficient).
555  *
556  * Change one value @coeff of the linear mode for the given @shade.
557  *
558  * Returns: TRUE if the new value changes anything.
559  */
tool_shade_setLinearCoeff(ToolShade * shade,float coeff,int channel,int order)560 gboolean tool_shade_setLinearCoeff(ToolShade *shade, float coeff, int channel, int order)
561 {
562   float *pt;
563 
564   g_return_val_if_fail(shade, FALSE);
565   g_return_val_if_fail(channel >= 0 && channel < 3 && order >= 0 && order < 2, FALSE);
566 
567   if (order == 0)
568     pt = shade->vectB + channel;
569   else
570     pt = shade->vectA + channel;
571 
572   DBG_fprintf(stderr, "Tool ToolShade: set the %d value of vect[%d]"
573 	      " to %f (previuosly %f).\n", channel, order, coeff, *pt);
574 
575   if (*pt == coeff)
576     return FALSE;
577 
578   *pt = coeff;
579   return TRUE;
580 }
581 /**
582  * tool_shade_channelToRGB:
583  * @shade: a #ToolShade ;
584  * @rgba: a location to store the result of the colour transformation ;
585  * @values: inout values.
586  *
587  * Like tool_shade_valueToRGB() but here, the three values
588  * are applied respectivly for the Red, the Green and the Blue
589  * channel.
590  */
tool_shade_channelToRGB(const ToolShade * shade,float rgba[4],float values[3])591 void tool_shade_channelToRGB(const ToolShade *shade, float rgba[4], float values[3])
592 {
593   guint i;
594 
595   g_return_if_fail(shade);
596 
597   /* DBG_fprintf(stderr, "Tool Shade: get RGB from (%g ; %g ; %g).\n", */
598   /*             values[0], values[1], values[2]); */
599   if (shade->mode == TOOL_SHADE_MODE_LINEAR)
600     {
601       rgba[0] = CLAMP(shade->vectA[0] * values[0] + shade->vectB[0], 0.f, 1.f);
602       rgba[1] = CLAMP(shade->vectA[1] * values[1] + shade->vectB[1], 0.f, 1.f);
603       rgba[2] = CLAMP(shade->vectA[2] * values[2] + shade->vectB[2], 0.f, 1.f);
604     }
605   else
606     {
607       for (i = 1; i < shade->nVals - 1; i++)
608         if (values[0] < shade->index[i])
609           break;
610       rgba[0] = CLAMP(shade->vectCh[0][i - 1] +
611 		      (shade->vectCh[0][i] - shade->vectCh[0][i - 1]) *
612 		      (values[0] - shade->index[i - 1]) /
613                       (shade->index[i] - shade->index[i - 1]), 0.f, 1.f);
614       for (i = 1; i < shade->nVals - 1; i++)
615         if (values[1] < shade->index[i])
616           break;
617       rgba[1] = CLAMP(shade->vectCh[1][i - 1] +
618 		      (shade->vectCh[1][i] - shade->vectCh[1][i - 1]) *
619 		      (values[1] - shade->index[i - 1]) /
620                       (shade->index[i] - shade->index[i - 1]), 0.f, 1.f);
621       for (i = 1; i < shade->nVals - 1; i++)
622         if (values[2] < shade->index[i])
623           break;
624       rgba[2] = CLAMP(shade->vectCh[2][i - 1] +
625 		      (shade->vectCh[2][i] - shade->vectCh[2][i - 1]) *
626 		      (values[2] - shade->index[i - 1]) /
627                       (shade->index[i] - shade->index[i - 1]), 0.f, 1.f);
628     }
629   /* Don't use alpha channel at present time. */
630   rgba[3] = 1.;
631   /* Transform if required. */
632   if (shade->colorMode == TOOL_SHADE_COLOR_MODE_HSV)
633     tool_color_convertHSVtoRGB(rgba, rgba);
634 }
635 /**
636  * tool_shade_valueToRGB:
637  * @shade: a valid #ToolShade object ;
638  * @rgba: an array of size [4] ;
639  * @value: the value ranged in [0;1].
640  *
641  * Give a RGBA vector for the given value.
642  */
tool_shade_valueToRGB(const ToolShade * shade,float rgba[4],float value)643 void tool_shade_valueToRGB(const ToolShade *shade, float rgba[4], float value)
644 {
645   float vals[3];
646 
647   vals[0] = value;
648   vals[1] = value;
649   vals[2] = value;
650   tool_shade_channelToRGB(shade, rgba, vals);
651 }
652 
653 /*********************************************/
654 /* Methods to deal with internal shade list. */
655 /*********************************************/
656 /**
657  * tool_shade_getStorage:
658  *
659  * It returns a read-only pointer to the internal shade list. Use tool_shade_appendList()
660  * to add new shades to this list.
661  *
662  * Since: 3.8
663  *
664  * Returns: (transfer none): a pointer to the internal shade list.
665  */
tool_shade_getStorage(void)666 ToolPool* tool_shade_getStorage(void)
667 {
668   if (!shadePool)
669     _buildPresetList();
670 
671   return shadePool;
672 }
_buildPresetList(void)673 static void _buildPresetList(void)
674 {
675   ToolShade *shade;
676   float vectA[3], vectB[3];
677 
678   /* Zero Centred Colored. */
679   #define zccLn 3
680   float zccH[zccLn] = {0.f, 0.333f, 0.667f};
681   float zccS[zccLn] = {1.0f, 0.0f, 1.0f};
682   float zccV[zccLn] = {1.f, 1.f, 1.f};
683 
684   /* Zero Centred Light. */
685   #define zclLn 3
686   float zclR[zclLn] = {1.f, 1.f, 0.f};
687   float zclG[zclLn] = {0.0f, 1.0f, 0.0f};
688   float zclB[zclLn] = {0.f, 1.f, 1.f};
689 
690   /* Jet colour shade. */
691   #define jetn 9
692   float jetR[jetn] = {0.f, 0.f, 0.f, 0.f, 0.5f, 1.f, 1.f, 1.f, 0.5f};
693   float jetG[jetn] = {0.f, 0.f, 0.5f, 1.f, 1.f, 1.f, 0.5f, 0.f, 0.f};
694   float jetB[jetn] = {0.5f, 1.f, 1.f, 1.f, 0.5f, 0.f, 0.f, 0.f, 0.f};
695 
696   shadePool = tool_pool_new(TOOL_TYPE_SHADE, (GCompareFunc)_compare);
697 
698   /* Create a blue to red color range. */
699   vectA[0] = -0.66667;
700   vectA[1] = 0.;
701   vectA[2] = 0.;
702   vectB[0] = 0.66667;
703   vectB[1] = 1.;
704   vectB[2] = 1.;
705   shade = tool_shade_new(_("blue to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
706   shade->userDefined = FALSE;
707   tool_pool_take(shadePool, shade);
708 
709   /* Create a black to white (through yellow and red) color range. */
710   vectA[0] = 2.66667;
711   vectA[1] = 2.66667;
712   vectA[2] = 4.;
713   vectB[0] = 0.;
714   vectB[1] = -1.;
715   vectB[2] = -3.;
716   shade = tool_shade_new(_("hot color"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB);
717   shade->userDefined = FALSE;
718   tool_pool_take(shadePool, shade);
719 
720   /* Create a blue to yellow (through dark purple) color range. */
721   vectA[0] = 1.33333;
722   vectA[1] = 2.;
723   vectA[2] = -2;
724   vectB[0] = 0.;
725   vectB[1] = -1.;
726   vectB[2] = 1.;
727   shade = tool_shade_new(_("blue to yellow"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB);
728   shade->userDefined = FALSE;
729   tool_pool_take(shadePool, shade);
730 
731   /* Create a blue and red shade with black zero centred. */
732   vectA[0] = -2.;
733   vectA[1] = 0.;
734   vectA[2] = 2.;
735   vectB[0] = 1.;
736   vectB[1] = 0.;
737   vectB[2] = -1.;
738   shade = tool_shade_new(_("zero centred dark"), vectA, vectB, TOOL_SHADE_COLOR_MODE_RGB);
739   shade->userDefined = FALSE;
740   tool_pool_take(shadePool, shade);
741 
742   /* Create a blue and red shade with withe zero centred. */
743   shade = tool_shade_newFromData(_("zero centred light"), zclLn,
744                                  zclR, zclG, zclB, TOOL_SHADE_COLOR_MODE_RGB);
745   shade->userDefined = FALSE;
746   tool_pool_take(shadePool, shade);
747 
748   shade = tool_shade_newFromData(_("zero centred coloured"), zccLn,
749 			    zccH, zccS, zccV, TOOL_SHADE_COLOR_MODE_HSV);
750   shade->userDefined = FALSE;
751   tool_pool_take(shadePool, shade);
752 
753   /* Create a green to red color range. */
754   vectA[0] = -.3333;
755   vectA[1] = 0.;
756   vectA[2] = 0.;
757   vectB[0] = 0.3333;
758   vectB[1] = 1.;
759   vectB[2] = 1.;
760   shade = tool_shade_new(_("green to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
761   shade->userDefined = FALSE;
762   tool_pool_take(shadePool, shade);
763 
764   /* Create a white to red color range. */
765   vectA[0] = -.3333;
766   vectA[1] = 0.8;
767   vectA[2] = 0.;
768   vectB[0] = 0.3333;
769   vectB[1] = 0.1;
770   vectB[2] = 1.;
771   shade = tool_shade_new(_("light green to red"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
772   shade->userDefined = FALSE;
773   tool_pool_take(shadePool, shade);
774 
775   /* Create a black to white color range. */
776   vectA[0] = 0.;
777   vectA[1] = 0.;
778   vectA[2] = 1.;
779   vectB[0] = 0.;
780   vectB[1] = 0.;
781   vectB[2] = 0.;
782   shade = tool_shade_new(_("black to white"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
783   shade->userDefined = FALSE;
784   tool_pool_take(shadePool, shade);
785 
786   /* Create a black to white color range. */
787   vectA[0] = 0.;
788   vectA[1] = 0.;
789   vectA[2] = -1.;
790   vectB[0] = 0.;
791   vectB[1] = 0.;
792   vectB[2] = 1.;
793   shade = tool_shade_new(_("white to black"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
794   shade->userDefined = FALSE;
795   tool_pool_take(shadePool, shade);
796 
797   /* Create a black to red (through purple) color range. */
798   vectA[0] = 1.;
799   vectA[1] = 1.;
800   vectA[2] = 1.;
801   vectB[0] = 0.;
802   vectB[1] = 0.;
803   vectB[2] = 0.;
804   shade = tool_shade_new(_("purple color"), vectA, vectB, TOOL_SHADE_COLOR_MODE_HSV);
805   shade->userDefined = FALSE;
806   tool_pool_take(shadePool, shade);
807 
808   /* Create the so-called Jet colour map. */
809   shade = tool_shade_newFromData(_("Jet map"), jetn,
810                                  jetR, jetG, jetB, TOOL_SHADE_COLOR_MODE_RGB);
811   shade->userDefined = FALSE;
812   tool_pool_take(shadePool, shade);
813 }
814 
parseValue(gchar * line,float * index,float rgb[3],GError ** error)815 static gboolean parseValue(gchar *line, float *index, float rgb[3], GError **error)
816 {
817   gchar *name;
818   PangoColor color;
819   double index_;
820 
821   DBG_fprintf(stderr, "Tool Shade: parse step from '%s'\n", line);
822   index_ = g_ascii_strtod(line, &name);
823   if (errno != 0 || name == line)
824     {
825       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ,
826                            _("1 floating point value should start a step '%s'.\n"), line);
827       return FALSE;
828     }
829   *index = (float)index_;
830   DBG_fprintf(stderr, " | index %g\n", *index);
831 
832   name += 1;
833   g_strdelimit(name, "\"'", ' ');
834   g_strstrip(name);
835   if (!pango_color_parse(&color, name))
836     {
837       *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_READ,
838                            _("cannot read a color from '%s' (name, #rgb, #rrggbb ... awaited).\n"),
839                            name);
840       return FALSE;
841     }
842   rgb[0] = (float)color.red   / (float)G_MAXUINT16;
843   rgb[1] = (float)color.green / (float)G_MAXUINT16;
844   rgb[2] = (float)color.blue  / (float)G_MAXUINT16;
845   DBG_fprintf(stderr, " | color %fx%fx%f\n", rgb[0], rgb[1], rgb[2]);
846 
847   return TRUE;
848 }
exportParameters(GString * data,VisuData * dataObj _U_)849 static void exportParameters(GString *data, VisuData *dataObj _U_)
850 {
851   GList *lst;
852   ToolShade *shade;
853   guint i;
854   PangoColor pcolor;
855   gchar *color;
856   GString *buf;
857 
858   visu_config_file_exportComment(data, DESC_SHADE);
859   for (lst = tool_pool_asList(shadePool); lst; lst = g_list_next(lst))
860     if (((ToolShade*)lst->data)->userDefined)
861       {
862         shade = (ToolShade*)lst->data;
863         buf = g_string_new("");
864         if (shade->userDefined)
865           g_string_append(buf, shade->steps);
866         else
867           for (i = 0; i < shade->nVals ; i++)
868             {
869               if (i != 0)
870                 g_string_append_printf(buf, ", ");
871               pcolor.red   = (guint16)(shade->vectCh[0][i] * (gfloat)G_MAXUINT16);
872               pcolor.green = (guint16)(shade->vectCh[1][i] * (gfloat)G_MAXUINT16);
873               pcolor.blue  = (guint16)(shade->vectCh[2][i] * (gfloat)G_MAXUINT16);
874               color = pango_color_to_string(&pcolor);
875               g_string_append_printf(buf, "%g %s", shade->index[i], color);
876               g_free(color);
877             }
878         visu_config_file_exportEntry(data, FLAG_SHADE, shade->labelUTF8,
879                                      "%s", buf->str);
880         g_string_free(buf, TRUE);
881       }
882   visu_config_file_exportComment(data, "");
883 }
readShade(VisuConfigFileEntry * entry,gchar ** lines,int nbLines _U_,int position _U_,GError ** error)884 static gboolean readShade(VisuConfigFileEntry *entry, gchar **lines, int nbLines _U_, int position _U_,
885                           GError **error)
886 {
887   gchar *name, *descr;
888   char *startDef, *endDef;
889   ToolShade *shade;
890   ToolPool *pool;
891 
892   name = g_strdup(visu_config_file_entry_getLabel(entry));
893 
894   startDef = strchr(lines[0], '(');
895   if (!startDef)
896     startDef = lines[0];
897   else
898     startDef += 1;
899   endDef = strchr(startDef, ')');
900   if (endDef)
901     descr = g_strndup(startDef, endDef - startDef);
902   else
903     descr = g_strdup(startDef);
904 
905   shade = tool_shade_newFromString(g_strstrip(name), descr,
906                                    TOOL_SHADE_COLOR_MODE_RGB, error);
907   g_free(name);
908   g_free(descr);
909 
910   if (!shade)
911     return FALSE;
912   pool = tool_shade_getStorage();
913   tool_pool_take(pool, shade);
914 
915   return TRUE;
916 }
917