1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Luc BILLARD et Damien
3 	CALISTE, laboratoire L_Sim, (2001-2005)
4 
5 	Adresse mèl :
6 	BILLARD, non joignable par mèl ;
7 	CALISTE, damien P caliste AT cea P fr.
8 
9 	Ce logiciel est un programme informatique servant à visualiser des
10 	structures atomiques dans un rendu pseudo-3D.
11 
12 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
13 	respectant les principes de diffusion des logiciels libres. Vous pouvez
14 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
15 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16 	sur le site "http://www.cecill.info".
17 
18 	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 	pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22 
23 /*   LICENCE SUM UP
24 	Copyright CEA, contributors : Luc BILLARD et Damien
25 	CALISTE, laboratoire L_Sim, (2001-2005)
26 
27 	E-mail address:
28 	BILLARD, not reachable any more ;
29 	CALISTE, damien P caliste AT cea P fr.
30 
31 	This software is a computer program whose purpose is to visualize atomic
32 	configurations in 3D.
33 
34 	This software is governed by the CeCILL  license under French law and
35 	abiding by the rules of distribution of free software.  You can  use,
36 	modify and/ or redistribute the software under the terms of the CeCILL
37 	license as circulated by CEA, CNRS and INRIA at the following URL
38 	"http://www.cecill.info".
39 
40 	The fact that you are presently reading this means that you have had
41 	knowledge of the CeCILL license and that you accept its terms. You can
42 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 #include "visu_elements.h"
45 
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #include "visu_configFile.h"
50 #include "coreTools/toolColor.h"
51 
52 /**
53  * SECTION:visu_elements
54  * @short_description: defines methods to create and acccess to
55  * #VisuElement.
56  *
57  * <para>V_Sim is used to rendered at given position several object of
58  * the same kind. The #VisuElement object is used to control that
59  * kind. Typically, it corresponds to chemical element. It can
60  * represent the silicon, the iron...</para>
61  *
62  * <para>#VisuElement are defined by their name and have some
63  * characteristic like if they are rendered or not, or masked or not.</para>
64  */
65 
66 /**
67  * VisuElement:
68  *
69  * Structure to stores #VisuElement objects.
70  */
71 /**
72  * VisuElementClass:
73  * @parent: the parent.
74  *
75  * An opaque structure representing the class of #VisuElement objects.
76  */
77 
78 #define FLAG_ELEMENT_PROPERTIES "element_properties"
79 #define DESC_ELEMENT_PROPERTIES "Define some properties ; rendered (0 or 1) masked" \
80   "(0 or 1)."
81 static gboolean _elementProperties[3];
82 
83 static void exportResources(GString *data, VisuData* dataObj);
84 
85 /**
86  * _VisuElement:
87  * @parent: the parent.
88  * @name: Name of the key used in the hashtable to find
89  *   this element. The int variable is the number
90  *   of this type.
91  * @typeNumber: An integer unique for each VisuElement, it is
92  *   used as a name for the opengl material associated
93  *   with it.
94  * @rgb: main color of the element  in [r, g, b, a] format.
95  * @material: lighting effects for material in [amb, dif, shi, spe,
96  * emi] format.
97  * @rendered: A flag to store if all nodes of this element are rendered or not.
98  *   Its default value is TRUE.
99  * @sensitiveToPlanes: a flag to say if nodes of this element are sensitive
100  *   to the masking effect of planes (default is TRUE).
101  * @physical: TRUE if the element is a physical one.
102  * @dispose_has_run: internal.
103  *
104  * Structure to store the description of an element.
105  */
106 
107 enum {
108   PROP_0,
109   PROP_RENDERED,
110   PROP_MASKABLE,
111   PROP_COLORIZABLE,
112   N_PROPS
113 };
114 static GParamSpec *_properties[N_PROPS];
115 
116 enum {
117   ELEMENT_NEW_SIGNAL,
118   LAST_SIGNAL
119 };
120 
121 /* This hashtable contains a list of all different
122    elements loaded in visu. */
123 static GHashTable *allElements_table = NULL;
124 static GList *allElements_list = NULL;
125 
126 /* These functions write all the element list to export there associated resources. */
127 static void visu_element_finalize(GObject* obj);
128 static void visu_element_get_property(GObject* obj, guint property_id,
129                                       GValue *value, GParamSpec *pspec);
130 static void visu_element_set_property(GObject* obj, guint property_id,
131                                       const GValue *value, GParamSpec *pspec);
132 
133 static void onEntryProperties(VisuConfigFile *obj, VisuConfigFileEntry *entry, gpointer data);
134 
135 static guint visu_element_signals[LAST_SIGNAL] = { 0 };
136 
G_DEFINE_TYPE(VisuElement,visu_element,VISU_TYPE_OBJECT)137 G_DEFINE_TYPE(VisuElement, visu_element, VISU_TYPE_OBJECT)
138 
139 static void visu_element_class_init(VisuElementClass *klass)
140 {
141   VisuConfigFileEntry *resourceEntry, *oldEntry;
142 
143   DBG_fprintf(stderr, "Visu Element: creating the class of the object.\n");
144   DBG_fprintf(stderr, "                - adding new signals ;\n");
145   /**
146    * VisuElement::ElementNew:
147    * @element: the object emitting the signal.
148    *
149    * A new element is available.
150    *
151    * Since: 3.6
152    */
153   visu_element_signals[ELEMENT_NEW_SIGNAL] =
154     g_signal_new("ElementNew",
155                  G_TYPE_FROM_CLASS (klass),
156                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
157                  0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
158                  G_TYPE_NONE, 0);
159 
160 
161   /* Connect the overloading methods. */
162   G_OBJECT_CLASS(klass)->finalize = visu_element_finalize;
163   G_OBJECT_CLASS(klass)->set_property = visu_element_set_property;
164   G_OBJECT_CLASS(klass)->get_property = visu_element_get_property;
165 
166   /**
167    * VisuElement::rendered:
168    *
169    * If element is rendered or not.
170    *
171    * Since: 3.8
172    */
173   _properties[PROP_RENDERED] =
174     g_param_spec_boolean("rendered", "Rendered",
175                          "if element is rendered", TRUE, G_PARAM_READWRITE);
176   /**
177    * VisuElement::maskable:
178    *
179    * If element is maskable by planes or not.
180    *
181    * Since: 3.8
182    */
183   _properties[PROP_MASKABLE] =
184     g_param_spec_boolean("maskable", "Maskable",
185                          "if element is maskable", TRUE, G_PARAM_READWRITE);
186   /**
187    * VisuElement::colorizable:
188    *
189    * If element is colorizable or not.
190    *
191    * Since: 3.8
192    */
193   _properties[PROP_COLORIZABLE] =
194     g_param_spec_boolean("colorizable", "Colorizable",
195                          "if element is colorizable", TRUE, G_PARAM_READWRITE);
196 
197   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROPS, _properties);
198 
199   oldEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_RESOURCE,
200                                        "element_is_rendered",
201                                        "Obsolete entry included in element_properties",
202                                        1, NULL);
203   visu_config_file_entry_setVersion(oldEntry, 3.1f);
204   resourceEntry = visu_config_file_addBooleanArrayEntry(VISU_CONFIG_FILE_RESOURCE,
205                                                         FLAG_ELEMENT_PROPERTIES,
206                                                         DESC_ELEMENT_PROPERTIES,
207                                                         2, _elementProperties, TRUE);
208   visu_config_file_entry_setVersion(resourceEntry, 3.4f);
209   visu_config_file_entry_setReplace(resourceEntry, oldEntry);
210   g_signal_connect(VISU_CONFIG_FILE_RESOURCE, "parsed::" FLAG_ELEMENT_PROPERTIES,
211                    G_CALLBACK(onEntryProperties), (gpointer)0);
212   visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE, exportResources);
213 
214   /* Set internal parameters. */
215   allElements_table =
216     g_hash_table_new_full(g_str_hash, g_str_equal,
217 			  NULL, (GDestroyNotify)g_object_unref);
218 }
219 
visu_element_init(VisuElement * ele)220 static void visu_element_init(VisuElement *ele)
221 {
222   DBG_fprintf(stderr, "Visu Element: initializing a new object (%p).\n",
223 	      (gpointer)ele);
224   ele->physical = TRUE;
225   ele->_rendered = TRUE;
226   ele->_maskable = TRUE;
227   ele->_colorizable = TRUE;
228 }
229 
230 /* This method is called once only. */
visu_element_finalize(GObject * obj)231 static void visu_element_finalize(GObject* obj)
232 {
233   VisuElement *ele;
234 
235   g_return_if_fail(obj);
236   DBG_fprintf(stderr, "Visu Element: finalize object %p.\n", (gpointer)obj);
237 
238   ele = VISU_ELEMENT(obj);
239   g_free(ele->name);
240   g_hash_table_steal(allElements_table, ele);
241   allElements_list = g_list_remove(allElements_list, ele);
242 
243   /* Chain up to the parent class */
244   DBG_fprintf(stderr, "Visu Element: chain to parent.\n");
245   G_OBJECT_CLASS(visu_element_parent_class)->finalize(obj);
246   DBG_fprintf(stderr, "Visu Element: freeing ... OK.\n");
247 }
visu_element_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)248 static void visu_element_get_property(GObject* obj, guint property_id,
249                                       GValue *value, GParamSpec *pspec)
250 {
251   VisuElement *self = VISU_ELEMENT(obj);
252 
253   DBG_fprintf(stderr, "Visu Element: get property '%s' -> ",
254 	      g_param_spec_get_name(pspec));
255   switch (property_id)
256     {
257     case PROP_RENDERED:
258       g_value_set_boolean(value, self->_rendered);
259       DBG_fprintf(stderr, "%d.\n", self->_rendered);
260       break;
261     case PROP_MASKABLE:
262       g_value_set_boolean(value, self->_maskable);
263       DBG_fprintf(stderr, "%d.\n", self->_maskable);
264       break;
265     case PROP_COLORIZABLE:
266       g_value_set_boolean(value, self->_colorizable);
267       DBG_fprintf(stderr, "%d.\n", self->_colorizable);
268       break;
269     default:
270       /* We don't have any other property... */
271       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
272       break;
273     }
274 }
visu_element_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)275 static void visu_element_set_property(GObject* obj, guint property_id,
276                                       const GValue *value, GParamSpec *pspec)
277 {
278   VisuElement *self = VISU_ELEMENT(obj);
279 
280   DBG_fprintf(stderr, "Visu Element: set property '%s' -> ",
281 	      g_param_spec_get_name(pspec));
282   switch (property_id)
283     {
284     case PROP_RENDERED:
285       DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
286       visu_element_setRendered(self, g_value_get_boolean(value));
287       break;
288     case PROP_MASKABLE:
289       DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
290       visu_element_setMaskable(self, g_value_get_boolean(value));
291       break;
292     case PROP_COLORIZABLE:
293       DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
294       visu_element_setColorizable(self, g_value_get_boolean(value));
295       break;
296     default:
297       /* We don't have any other property... */
298       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
299       break;
300     }
301 }
302 
303 /**
304  * visu_element_new:
305  * @key: the name of the new element to create.
306  *
307  * Allocate a new visuElement with the specified name. Remember
308  * that names must be unique since they identify the element.
309  *
310  * Returns: (transfer none): the newly created VisuElement or 0 if something goes
311  * wrong in the process (if the name already exist for example).
312  */
visu_element_new(const char * key)313 VisuElement *visu_element_new(const char *key)
314 {
315   VisuElement *ele;
316 
317   ele = visu_element_lookup(key);
318   if (ele)
319     {
320       g_warning("Element '%s' already exists.", key);
321       return ele;
322     }
323 
324   ele = VISU_ELEMENT(g_object_new(VISU_TYPE_ELEMENT, NULL));
325   ele->name       = g_strdup((key[0] == '%')?key + 1:key);
326   ele->physical   = (key[0] != '%') && strcmp(key, "g") && strcmp(key, "G");
327   g_hash_table_insert(allElements_table, (gpointer)ele->name, (gpointer)ele);
328   allElements_list = g_list_append(allElements_list, (gpointer)ele);
329 
330   DBG_fprintf(stderr, "Visu Elements: create a new VisuElement '%s' -> %p.\n",
331 	      key, (gpointer)ele);
332   g_signal_emit(G_OBJECT(ele), visu_element_signals[ELEMENT_NEW_SIGNAL], 0, NULL);
333   DBG_fprintf(stderr, "Visu Elements: new element signal OK.\n");
334 
335   return ele;
336 }
337 
338 /**
339  * visu_element_getAllElements:
340  *
341  * This method returns a list of all the registered #VisuElement.
342  * The returned list is read-only.
343  *
344  * Returns: (element-type VisuElement) (transfer none): the list of
345  * all known #VisuElement.
346  */
visu_element_getAllElements(void)347 const GList *visu_element_getAllElements(void)
348 {
349   return allElements_list;
350 }
351 /**
352  * visu_element_pool_finalize: (skip)
353  *
354  * Destroy the internal list of existing #VisuElement.
355  *
356  * Since: 3.8
357  **/
visu_element_pool_finalize(void)358 void visu_element_pool_finalize(void)
359 {
360   GList *lst;
361 
362   lst = g_list_copy(allElements_list);
363   g_list_free_full(lst, (GDestroyNotify)g_object_unref);
364 }
365 
366 /**
367  * visu_element_retrieveFromName:
368  * @name: a string that identify the #VisuElement (in UTF8) ;
369  * @nw: (out caller-allocates): a location to store a boolean.
370  *
371  * Try to find a #VisuElement already associated to that @name or
372  * create a new one if none has been found. If @nw is not NULL it is
373  * set to FALSE if @name was found.
374  *
375  * Returns: (transfer none): a #VisuElement associated to this @name.
376  */
visu_element_retrieveFromName(const gchar * name,gboolean * nw)377 VisuElement *visu_element_retrieveFromName(const gchar *name, gboolean *nw)
378 {
379   VisuElement *ele;
380 
381   if (!allElements_table)
382     g_type_class_ref(VISU_TYPE_ELEMENT);
383 
384   DBG_fprintf(stderr, "Visu Element: retrieve '%s' (%d).\n", name,
385               g_hash_table_size(allElements_table));
386 
387   if (nw)
388     *nw = FALSE;
389 
390   ele = g_hash_table_lookup(allElements_table, (name[0] == '%')?name + 1:name);
391   if (ele)
392     return ele;
393 
394   if (nw)
395     *nw = TRUE;
396 
397   return visu_element_new(name);
398 }
399 
400 /**
401  * visu_element_lookup:
402  * @name: a string.
403  *
404  * Lookup for element @name in the base. Do not create it if not
405  * found. To do this, use visu_element_retrieveFromName().
406  *
407  * Since: 3.6
408  *
409  * Returns: (transfer none): the found #VisuElement or NULL.
410  */
visu_element_lookup(const gchar * name)411 VisuElement *visu_element_lookup(const gchar *name)
412 {
413   if (!allElements_table)
414     g_type_class_ref(VISU_TYPE_ELEMENT);
415 
416   DBG_fprintf(stderr, "Visu Element: lookup '%s' (%d).\n",
417               name, g_hash_table_size(allElements_table));
418   return g_hash_table_lookup(allElements_table, (name[0] == '%')?name + 1:name);
419 }
420 
421 /**
422  * visu_element_getName:
423  * @ele: a #VisuElement object.
424  *
425  * This routines returns the name of the given @ele.
426  *
427  * Since: 3.7
428  *
429  * Returns: a string owned by V_Sim.
430  */
visu_element_getName(const VisuElement * ele)431 const gchar* visu_element_getName(const VisuElement *ele)
432 {
433   g_return_val_if_fail(VISU_IS_ELEMENT(ele), (const gchar*)0);
434 
435   return ele->name;
436 }
437 /**
438  * visu_element_getPhysical:
439  * @ele: a #VisuElement object.
440  *
441  * This routine gets if @ele is physical or not. A not physical
442  * element can be used for instance to represent specific points...
443  *
444  * Since: 3.7
445  *
446  * Returns: TRUE if @ele is indeed physical.
447  */
visu_element_getPhysical(VisuElement * ele)448 gboolean visu_element_getPhysical(VisuElement *ele)
449 {
450   g_return_val_if_fail(VISU_IS_ELEMENT(ele), FALSE);
451 
452   return ele->physical;
453 }
454 /**
455  * visu_element_getRendered:
456  * @self: a #VisuElement object.
457  *
458  * Retrieve wether all #VisuNode of @self are currently hidden or not.
459  *
460  * Since: 3.8
461  *
462  * Returns: TRUE if @self is hidden or not.
463  **/
visu_element_getRendered(const VisuElement * self)464 gboolean visu_element_getRendered(const VisuElement *self)
465 {
466   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
467 
468   return self->_rendered;
469 }
470 /**
471  * visu_element_setRendered:
472  * @self: a #VisuElement object.
473  * @val: a boolean.
474  *
475  * Changes if all #VisuNode of type @self are hidden or not.
476  *
477  * Since: 3.8
478  *
479  * Returns: TRUE if value is actually changed.
480  **/
visu_element_setRendered(VisuElement * self,gboolean val)481 gboolean visu_element_setRendered(VisuElement *self, gboolean val)
482 {
483   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
484 
485   if (self->_rendered == val)
486     return FALSE;
487 
488   self->_rendered = val;
489   g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_RENDERED]);
490   return TRUE;
491 }
492 /**
493  * visu_element_getMaskable:
494  * @self: a #VisuElement object.
495  *
496  * Retrieve whether #VisuNode of type @self can be hidden by planes or any
497  * #VisuNodeMasker object.
498  *
499  * Since: 3.8
500  *
501  * Returns: TRUE if @self is maskable.
502  **/
visu_element_getMaskable(const VisuElement * self)503 gboolean visu_element_getMaskable(const VisuElement *self)
504 {
505   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
506 
507   return self->_maskable;
508 }
509 /**
510  * visu_element_setMaskable:
511  * @self: a #VisuElement object.
512  * @val: a boolean value.
513  *
514  * Changes if all #VisuNode of type @self can be affected by a
515  * #VisuNodeMasker object.
516  *
517  * Since: 3.8
518  *
519  * Returns: TRUE if value is actually changed.
520  **/
visu_element_setMaskable(VisuElement * self,gboolean val)521 gboolean visu_element_setMaskable(VisuElement *self, gboolean val)
522 {
523   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
524 
525   if (self->_maskable == val)
526     return FALSE;
527 
528   self->_maskable = val;
529   g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_MASKABLE]);
530   return TRUE;
531 }
532 
533 /**
534  * visu_element_getColorizable:
535  * @self: a #VisuElement object.
536  *
537  * Retrieve whether #VisuNode of type @self can be colorized by any
538  * #VisuDataColorizer object.
539  *
540  * Since: 3.8
541  *
542  * Returns: TRUE if @self is colorizable.
543  **/
visu_element_getColorizable(const VisuElement * self)544 gboolean visu_element_getColorizable(const VisuElement *self)
545 {
546   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
547 
548   return self->_colorizable;
549 }
550 /**
551  * visu_element_setColorizable:
552  * @self: a #VisuElement object.
553  * @val: a boolean value.
554  *
555  * Changes if all #VisuNode of type @self can be affected by a
556  * #VisuDataColorizer object.
557  *
558  * Since: 3.8
559  *
560  * Returns: TRUE if value is actually changed.
561  **/
visu_element_setColorizable(VisuElement * self,gboolean val)562 gboolean visu_element_setColorizable(VisuElement *self, gboolean val)
563 {
564   g_return_val_if_fail(VISU_IS_ELEMENT(self), FALSE);
565 
566   if (self->_colorizable == val)
567     return FALSE;
568 
569   self->_colorizable = val;
570   g_object_notify_by_pspec(G_OBJECT(self), _properties[PROP_COLORIZABLE]);
571 
572   return TRUE;
573 }
574 
onEntryProperties(VisuConfigFile * obj _U_,VisuConfigFileEntry * entry,gpointer data _U_)575 static void onEntryProperties(VisuConfigFile *obj _U_, VisuConfigFileEntry *entry,
576                               gpointer data _U_)
577 {
578   VisuElement *ele;
579 
580   ele = visu_element_retrieveFromName(visu_config_file_entry_getLabel(entry), (int*)0);
581   if (!ele)
582     return;
583   visu_element_setRendered(ele, _elementProperties[0]);
584   visu_element_setMaskable(ele, _elementProperties[1]);
585   /* visu_element_setColorizable(ele, _elementProperties[2]); */
586 }
exportResources(GString * data,VisuData * dataObj)587 static void exportResources(GString *data, VisuData *dataObj)
588 {
589   GList *pos;
590   VisuElement *ele;
591 
592   visu_config_file_exportComment(data, DESC_ELEMENT_PROPERTIES);
593   for (pos = allElements_list; pos; pos = g_list_next(pos))
594     {
595       ele = VISU_ELEMENT(pos->data);
596       if (!dataObj || visu_node_array_containsElement(VISU_NODE_ARRAY(dataObj), ele))
597         visu_config_file_exportEntry(data, FLAG_ELEMENT_PROPERTIES, ele->name,
598                                      "%d %d %d", ele->_rendered, ele->_maskable,
599                                      ele->_colorizable);
600     }
601   visu_config_file_exportComment(data, "");
602 }
603