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