"Fossies" - the Fresh Open Source Software Archive 
Member "gamgi0.17.5x/src/expat/gamgi_expat_import_object.c" (23 Feb 2022, 226813 Bytes) of package /linux/misc/gamgi-all-0.17.5x.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /************************************************
2 *
3 * $GAMGI/src/expat/gamgi_expat_import_object.c
4 *
5 * Copyright (C) 2004 Carlos Pereira
6 *
7 * Distributed under the terms of the GNU
8 * General Public License: $GAMGI/LICENSE
9 *
10 */
11
12 #include "gamgi_engine.h"
13 #include "gamgi_gtk.h"
14 #include "gamgi_mesa.h"
15 #include "gamgi_math.h"
16 #include "gamgi_chem.h"
17 #include "gamgi_phys.h"
18 #include "gamgi_io.h"
19 #include "gamgi_expat.h"
20 #include "gamgi_global.h"
21
22 #include "gamgi_engine_create.h"
23 #include "gamgi_engine_start.h"
24 #include "gamgi_engine_list.h"
25 #include "gamgi_gtk_dialog.h"
26 #include "gamgi_gtk_history.h"
27 #include "gamgi_gtk_cell_symmetry.h"
28 #include "gamgi_mesa_start.h"
29 #include "gamgi_mesa_atom.h"
30 #include "gamgi_mesa_bond.h"
31 #include "gamgi_mesa_render.h"
32 #include "gamgi_mesa_text.h"
33 #include "gamgi_math_vector.h"
34 #include "gamgi_math_matrix.h"
35 #include "gamgi_math_euler.h"
36 #include "gamgi_math_quaternion.h"
37 #include "gamgi_math_hash.h"
38 #include "gamgi_math_cell.h"
39 #include "gamgi_math_position.h"
40 #include "gamgi_math_node.h"
41 #include "gamgi_math_polygon.h"
42 #include "gamgi_chem_atom.h"
43 #include "gamgi_chem_orbital.h"
44 #include "gamgi_phys_cell.h"
45 #include "gamgi_phys_projection.h"
46 #include "gamgi_phys_direction.h"
47 #include "gamgi_io_token.h"
48 #include "gamgi_io_error.h"
49 #include "gamgi_expat_import.h"
50 #include "gamgi_expat_import_config.h"
51 #include "gamgi_global_copy.h"
52
53 static gamgi_bool static_gml_end (const char *element, gamgi_gml *gml)
54 {
55 /************************************************
56 * parent stack ends here: output parent = NULL *
57 ************************************************/
58
59 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
60
61 /**********************************************************
62 * link objects to external parents indicated by id names *
63 **********************************************************/
64
65 return gamgi_expat_import_connect (gml);
66 }
67
68 static gamgi_bool static_gml_start (const char *element,
69 const char **attributes, gamgi_gml *gml)
70 {
71 int fileline;
72
73 /******************************************
74 * used only in error messages: file line *
75 * indicates where current element starts *
76 ******************************************/
77
78 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
79
80 /***********************************
81 * gml should be the first element *
82 ***********************************/
83
84 if (gamgi_expat_import_parent_gml (GAMGI_EXPAT_GML, gml) == FALSE)
85 return gamgi_io_error_child (gml->ml.filename,
86 fileline, gml->ml.window);
87
88 /****************************
89 * object queue starts here *
90 ****************************/
91
92 gml->object_end = gamgi_engine_dlist_add_end (NULL);
93 gml->object_end->data = NULL;
94
95 gml->object_start = gml->object_end;
96
97 /****************************
98 * parent stack starts here *
99 ****************************/
100
101 gml->ml.parent = gamgi_engine_slist_add_start (NULL);
102 gml->ml.parent->data = NULL;
103
104 /*********************************
105 * gml should have no attributes *
106 *********************************/
107
108 if (attributes[0] != NULL)
109 return gamgi_io_error_attribute (attributes[0],
110 gml->ml.filename, fileline, gml->ml.window);
111
112 return gml->ml.valid;
113 }
114
115 static gamgi_bool static_gamgi_start (const char *element,
116 const char **attributes, gamgi_gml *gml)
117 {
118 gamgi_gamgi_class *gamgi_class;
119 gamgi_object *object;
120 int fileline, i;
121 int button = 0;
122 int background = 0, foreground = 0;
123 int title = 0, bold = 0, link = 0;
124
125 /******************************************
126 * used only in error messages: file line *
127 * indicates where current element starts *
128 ******************************************/
129
130 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
131
132 /***********************
133 * parent stack: check *
134 ***********************/
135
136 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_GAMGI, gml) == FALSE)
137 return gamgi_io_error_child (gml->ml.filename,
138 fileline, gml->ml.window);
139
140 /*************************************************
141 * gamgi_class contains the current config info, *
142 * which is gamgi->gamgi unless new config info *
143 * has been previously stored in object->object. *
144 *************************************************/
145
146 object = GAMGI_CAST_OBJECT gamgi->gamgi;
147 if (object->object == NULL)
148 {
149 gamgi_class = gamgi_global_copy_gamgi (gamgi->gamgi);
150 object->object = GAMGI_CAST_OBJECT gamgi_class;
151 }
152 else gamgi_class = (gamgi_gamgi_class *) object->object;
153
154 /************************
155 * parent stack: update *
156 ************************/
157
158 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
159 gml->ml.parent->data = gamgi_class;
160
161 /******************************************************
162 * parser is entering a gamgi (configuration) block: *
163 * switch the data handlers to configuration handlers *
164 ******************************************************/
165
166 XML_SetStartElementHandler (gml->ml.parser, gamgi_expat_import_config_start);
167 XML_SetEndElementHandler (gml->ml.parser, gamgi_expat_import_config_end);
168
169 /**********************************
170 * attribute array: check, update *
171 **********************************/
172
173 for (i = 0; attributes[i] != NULL; i += 2)
174 {
175 /*******************************
176 * mouse parameters: *
177 * beep sound, pick tolerance, *
178 * left, middle, right buttons *
179 *******************************/
180
181 if (strcmp (attributes[i], "sound") == 0)
182 {
183 /*********
184 * reset *
185 *********/
186
187 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
188 gamgi_class->beep = gamgi->gamgi->beep;
189
190 /**********
191 * update *
192 **********/
193
194 else if (gamgi_io_token_bool_scan (attributes[i + 1],
195 &gamgi_class->beep) == FALSE)
196 return gamgi_io_error_value (attributes[i + 1],
197 gml->ml.filename, fileline, gml->ml.window);
198 }
199
200 else if (strcmp (attributes[i], "tolerance") == 0)
201 {
202 /*********
203 * reset *
204 *********/
205
206 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
207 gamgi_class->tolerance = gamgi->gamgi->tolerance;
208
209 /**********
210 * update *
211 **********/
212
213 else if (gamgi_io_token_int_scan (attributes[i + 1],
214 &gamgi_class->tolerance, 0, GAMGI_MESA_PICK_TOLERANCE_MAX) == FALSE)
215 return gamgi_io_error_value (attributes[i + 1],
216 gml->ml.filename, fileline, gml->ml.window);
217 }
218
219 else if (strcmp (attributes[i], "button1") == 0)
220 {
221 button++;
222
223 /*********
224 * reset *
225 *********/
226
227 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
228 gamgi_class->button1 = gamgi->gamgi->button1;
229
230 /**********
231 * update *
232 **********/
233
234 else if (gamgi_io_token_int_scan (attributes[i + 1],
235 &gamgi_class->button1, 1, 3) == FALSE)
236 return gamgi_io_error_value (attributes[i + 1],
237 gml->ml.filename, fileline, gml->ml.window);
238
239 /***********************************************************
240 * convert 1,2,3 to BUTTON1_MASK,BUTTON2_MASK,BUTTON3_MASK *
241 ***********************************************************/
242
243 else gamgi_class->button1 =
244 gamgi_gtk_dialog_button_mask (gamgi_class->button1);
245 }
246
247 else if (strcmp (attributes[i], "button2") == 0)
248 {
249 button++;
250
251 /*********
252 * reset *
253 *********/
254
255 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
256 gamgi_class->button2 = gamgi->gamgi->button2;
257
258 /**********
259 * update *
260 **********/
261
262 else if (gamgi_io_token_int_scan (attributes[i + 1],
263 &gamgi_class->button2, 1, 3) == FALSE)
264 return gamgi_io_error_value (attributes[i + 1],
265 gml->ml.filename, fileline, gml->ml.window);
266
267 /***********************************************************
268 * convert 1,2,3 to BUTTON1_MASK,BUTTON2_MASK,BUTTON3_MASK *
269 ***********************************************************/
270
271 else gamgi_class->button2 =
272 gamgi_gtk_dialog_button_mask (gamgi_class->button2);
273 }
274
275 else if (strcmp (attributes[i], "button3") == 0)
276 {
277 button++;
278
279 /*********
280 * reset *
281 *********/
282
283 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
284 gamgi_class->button3 = gamgi->gamgi->button3;
285
286 /**********
287 * update *
288 **********/
289
290 else if (gamgi_io_token_int_scan (attributes[i + 1],
291 &gamgi_class->button3, 1, 3) == FALSE)
292 return gamgi_io_error_value (attributes[i + 1],
293 gml->ml.filename, fileline, gml->ml.window);
294
295 /***********************************************************
296 * convert 1,2,3 to BUTTON1_MASK,BUTTON2_MASK,BUTTON3_MASK *
297 ***********************************************************/
298
299 else gamgi_class->button3 =
300 gamgi_gtk_dialog_button_mask (gamgi_class->button3);
301 }
302
303 /*******************************
304 * number of decimal figures: *
305 * length, angle, charge, mass *
306 *******************************/
307
308 else if (strcmp (attributes[i], "length") == 0)
309 {
310 /*********
311 * reset *
312 *********/
313
314 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
315 gamgi_class->length = gamgi->gamgi->length;
316
317 /**********
318 * update *
319 **********/
320
321 else if (gamgi_io_token_int_scan (attributes[i + 1],
322 &gamgi_class->length, 0, GAMGI_MATH_DECIMAL_MAX) == FALSE)
323 return gamgi_io_error_value (attributes[i + 1],
324 gml->ml.filename, fileline, gml->ml.window);
325 }
326
327 else if (strcmp (attributes[i], "angle") == 0)
328 {
329 /*********
330 * reset *
331 *********/
332
333 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
334 gamgi_class->angle = gamgi->gamgi->angle;
335
336 /**********
337 * update *
338 **********/
339
340 else if (gamgi_io_token_int_scan (attributes[i + 1],
341 &gamgi_class->angle, 0, GAMGI_MATH_DECIMAL_MAX) == FALSE)
342 return gamgi_io_error_value (attributes[i + 1],
343 gml->ml.filename, fileline, gml->ml.window);
344 }
345
346 else if (strcmp (attributes[i], "mass") == 0)
347 {
348 /*********
349 * reset *
350 *********/
351
352 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
353 gamgi_class->mass = gamgi->gamgi->mass;
354
355 /**********
356 * update *
357 **********/
358
359 else if (gamgi_io_token_int_scan (attributes[i + 1],
360 &gamgi_class->mass, 0, GAMGI_MATH_DECIMAL_MAX) == FALSE)
361 return gamgi_io_error_value (attributes[i + 1],
362 gml->ml.filename, fileline, gml->ml.window);
363 }
364
365 else if (strcmp (attributes[i], "charge") == 0)
366 {
367 /*********
368 * reset *
369 *********/
370
371 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
372 gamgi_class->charge = gamgi->gamgi->charge;
373
374 /**********
375 * update *
376 **********/
377
378 else if (gamgi_io_token_int_scan (attributes[i + 1],
379 &gamgi_class->charge, 0, GAMGI_MATH_DECIMAL_MAX) == FALSE)
380 return gamgi_io_error_value (attributes[i + 1],
381 gml->ml.filename, fileline, gml->ml.window);
382 }
383
384 /*********************************
385 * color parameters: background, *
386 * foreground, title, bold, link *
387 *********************************/
388
389 /****************************************
390 * red,green,blue background (optional) *
391 ****************************************/
392
393 else if (strcmp (attributes[i], "base_r") == 0)
394 {
395 background++;
396
397 /*********
398 * reset *
399 *********/
400
401 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
402 gamgi_class->background[0] = gamgi->gamgi->background[0];
403
404 /**********
405 * update *
406 **********/
407
408 else if (gamgi_io_token_float_scan (attributes[i + 1],
409 &gamgi_class->background[0], 0.0, 1.0) == FALSE)
410 return gamgi_io_error_value (attributes[i + 1],
411 gml->ml.filename, fileline, gml->ml.window);
412 }
413
414 else if (strcmp (attributes[i], "base_g") == 0)
415 {
416 background++;
417
418 /*********
419 * reset *
420 *********/
421
422 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
423 gamgi_class->background[1] = gamgi->gamgi->background[1];
424
425 /**********
426 * update *
427 **********/
428
429 else if (gamgi_io_token_float_scan (attributes[i + 1],
430 &gamgi_class->background[1], 0.0, 1.0) == FALSE)
431 return gamgi_io_error_value (attributes[i + 1],
432 gml->ml.filename, fileline, gml->ml.window);
433 }
434
435 else if (strcmp (attributes[i], "base_b") == 0)
436 {
437 background++;
438
439 /*********
440 * reset *
441 *********/
442
443 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
444 gamgi_class->background[2] = gamgi->gamgi->background[2];
445
446 /**********
447 * update *
448 **********/
449
450 else if (gamgi_io_token_float_scan (attributes[i + 1],
451 &gamgi_class->background[2], 0.0, 1.0) == FALSE)
452 return gamgi_io_error_value (attributes[i + 1],
453 gml->ml.filename, fileline, gml->ml.window);
454 }
455
456 /****************************************
457 * red,green,blue foreground (optional) *
458 ****************************************/
459
460 else if (strcmp (attributes[i], "text_r") == 0)
461 {
462 foreground++;
463
464 /*********
465 * reset *
466 *********/
467
468 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
469 gamgi_class->foreground[0] = gamgi->gamgi->foreground[0];
470
471 /**********
472 * update *
473 **********/
474
475 else if (gamgi_io_token_float_scan (attributes[i + 1],
476 &gamgi_class->foreground[0], 0.0, 1.0) == FALSE)
477 return gamgi_io_error_value (attributes[i + 1],
478 gml->ml.filename, fileline, gml->ml.window);
479 }
480
481 else if (strcmp (attributes[i], "text_g") == 0)
482 {
483 foreground++;
484
485 /*********
486 * reset *
487 *********/
488
489 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
490 gamgi_class->foreground[1] = gamgi->gamgi->foreground[1];
491
492 /**********
493 * update *
494 **********/
495
496 else if (gamgi_io_token_float_scan (attributes[i + 1],
497 &gamgi_class->foreground[1], 0.0, 1.0) == FALSE)
498 return gamgi_io_error_value (attributes[i + 1],
499 gml->ml.filename, fileline, gml->ml.window);
500 }
501
502 else if (strcmp (attributes[i], "text_b") == 0)
503 {
504 foreground++;
505
506 /*********
507 * reset *
508 *********/
509
510 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
511 gamgi_class->foreground[2] = gamgi->gamgi->foreground[2];
512
513 /**********
514 * update *
515 **********/
516
517 else if (gamgi_io_token_float_scan (attributes[i + 1],
518 &gamgi_class->foreground[2], 0.0, 1.0) == FALSE)
519 return gamgi_io_error_value (attributes[i + 1],
520 gml->ml.filename, fileline, gml->ml.window);
521 }
522
523 /***********************************
524 * red,green,blue title (optional) *
525 ***********************************/
526
527 else if (strcmp (attributes[i], "title_r") == 0)
528 {
529 title++;
530
531 /*********
532 * reset *
533 *********/
534
535 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
536 gamgi_class->title[0] = gamgi->gamgi->title[0];
537
538 /**********
539 * update *
540 **********/
541
542 else if (gamgi_io_token_float_scan (attributes[i + 1],
543 &gamgi_class->title[0], 0.0, 1.0) == FALSE)
544 return gamgi_io_error_value (attributes[i + 1],
545 gml->ml.filename, fileline, gml->ml.window);
546 }
547
548 else if (strcmp (attributes[i], "title_g") == 0)
549 {
550 title++;
551
552 /*********
553 * reset *
554 *********/
555
556 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
557 gamgi_class->title[1] = gamgi->gamgi->title[1];
558
559 /**********
560 * update *
561 **********/
562
563 else if (gamgi_io_token_float_scan (attributes[i + 1],
564 &gamgi_class->title[1], 0.0, 1.0) == FALSE)
565 return gamgi_io_error_value (attributes[i + 1],
566 gml->ml.filename, fileline, gml->ml.window);
567 }
568
569 else if (strcmp (attributes[i], "title_b") == 0)
570 {
571 title++;
572
573 /*********
574 * reset *
575 *********/
576
577 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
578 gamgi_class->title[2] = gamgi->gamgi->title[2];
579
580 /**********
581 * update *
582 **********/
583
584 else if (gamgi_io_token_float_scan (attributes[i + 1],
585 &gamgi_class->title[2], 0.0, 1.0) == FALSE)
586 return gamgi_io_error_value (attributes[i + 1],
587 gml->ml.filename, fileline, gml->ml.window);
588 }
589
590 /**********************************
591 * red,green,blue bold (optional) *
592 **********************************/
593
594 else if (strcmp (attributes[i], "bold_r") == 0)
595 {
596 bold++;
597
598 /*********
599 * reset *
600 *********/
601
602 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
603 gamgi_class->bold[0] = gamgi->gamgi->bold[0];
604
605 /**********
606 * update *
607 **********/
608
609 else if (gamgi_io_token_float_scan (attributes[i + 1],
610 &gamgi_class->bold[0], 0.0, 1.0) == FALSE)
611 return gamgi_io_error_value (attributes[i + 1],
612 gml->ml.filename, fileline, gml->ml.window);
613 }
614
615 else if (strcmp (attributes[i], "bold_g") == 0)
616 {
617 bold++;
618
619 /*********
620 * reset *
621 *********/
622
623 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
624 gamgi_class->bold[1] = gamgi->gamgi->bold[1];
625
626 /**********
627 * update *
628 **********/
629
630 else if (gamgi_io_token_float_scan (attributes[i + 1],
631 &gamgi_class->bold[1], 0.0, 1.0) == FALSE)
632 return gamgi_io_error_value (attributes[i + 1],
633 gml->ml.filename, fileline, gml->ml.window);
634 }
635
636 else if (strcmp (attributes[i], "bold_b") == 0)
637 {
638 bold++;
639
640 /*********
641 * reset *
642 *********/
643
644 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
645 gamgi_class->bold[2] = gamgi->gamgi->bold[2];
646
647 /**********
648 * update *
649 **********/
650
651 else if (gamgi_io_token_float_scan (attributes[i + 1],
652 &gamgi_class->bold[2], 0.0, 1.0) == FALSE)
653 return gamgi_io_error_value (attributes[i + 1],
654 gml->ml.filename, fileline, gml->ml.window);
655 }
656
657 /**********************************
658 * red,green,blue link (optional) *
659 **********************************/
660
661 else if (strcmp (attributes[i], "link_r") == 0)
662 {
663 link++;
664
665 /*********
666 * reset *
667 *********/
668
669 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
670 gamgi_class->link[0] = gamgi->gamgi->link[0];
671
672 /**********
673 * update *
674 **********/
675
676 else if (gamgi_io_token_float_scan (attributes[i + 1],
677 &gamgi_class->link[0], 0.0, 1.0) == FALSE)
678 return gamgi_io_error_value (attributes[i + 1],
679 gml->ml.filename, fileline, gml->ml.window);
680 }
681
682 else if (strcmp (attributes[i], "link_g") == 0)
683 {
684 link++;
685
686 /*********
687 * reset *
688 *********/
689
690 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
691 gamgi_class->link[1] = gamgi->gamgi->link[1];
692
693 /**********
694 * update *
695 **********/
696
697 else if (gamgi_io_token_float_scan (attributes[i + 1],
698 &gamgi_class->link[1], 0.0, 1.0) == FALSE)
699 return gamgi_io_error_value (attributes[i + 1],
700 gml->ml.filename, fileline, gml->ml.window);
701 }
702
703 else if (strcmp (attributes[i], "link_b") == 0)
704 {
705 link++;
706
707 /*********
708 * reset *
709 *********/
710
711 if (gamgi_io_token_check (attributes[i + 1]) == FALSE)
712 gamgi_class->link[2] = gamgi->gamgi->link[2];
713
714 /**********
715 * update *
716 **********/
717
718 else if (gamgi_io_token_float_scan (attributes[i + 1],
719 &gamgi_class->link[2], 0.0, 1.0) == FALSE)
720 return gamgi_io_error_value (attributes[i + 1],
721 gml->ml.filename, fileline, gml->ml.window);
722 }
723
724 else return gamgi_io_error_attribute (attributes[i],
725 gml->ml.filename, fileline, gml->ml.window);
726 }
727
728 /******************************
729 * global: missing attributes *
730 ******************************/
731
732 /*************************************************
733 * button1, button2, button3 (coupled, optional) *
734 *************************************************/
735
736 if (button == 1 || button == 2)
737 return gamgi_io_error_missing (gml->ml.filename,
738 fileline, gml->ml.window);
739
740 /************************************************************************
741 * background, foreground, title, bold, link colors (coupled, optional) *
742 ************************************************************************/
743
744 if (background == 1 || background == 2)
745 return gamgi_io_error_missing (gml->ml.filename,
746 fileline, gml->ml.window);
747
748 if (foreground == 1 || foreground == 2)
749 return gamgi_io_error_missing (gml->ml.filename,
750 fileline, gml->ml.window);
751
752 if (title == 1 || title == 2)
753 return gamgi_io_error_missing (gml->ml.filename,
754 fileline, gml->ml.window);
755
756 if (bold == 1 || bold == 2)
757 return gamgi_io_error_missing (gml->ml.filename,
758 fileline, gml->ml.window);
759
760 if (link == 1 || link == 2)
761 return gamgi_io_error_missing (gml->ml.filename,
762 fileline, gml->ml.window);
763
764 /***********************************
765 * global: incompatible attributes *
766 ***********************************/
767
768 /*******************************************
769 * (button1,button2,button3) must point to *
770 * one of the six valid (1,2,3) sequences. *
771 *******************************************/
772
773 if (gamgi_class->button1 == gamgi_class->button2 ||
774 gamgi_class->button1 == gamgi_class->button3 ||
775 gamgi_class->button2 == gamgi_class->button3)
776 return gamgi_io_error_incompatible (gml->ml.filename,
777 fileline, gml->ml.window);
778
779 return gml->ml.valid;
780 }
781
782 static gamgi_bool static_window_end (const char *element, gamgi_gml *gml)
783 {
784 int fileline;
785
786 /******************************************
787 * used only in error messages: file line *
788 * indicates where current element starts *
789 ******************************************/
790
791 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
792
793 /*****************************************************
794 * <window/> or <window></window> is not acceptable, *
795 * windows must own at least an empty layer. This *
796 * error is not detected by parent checking, so we *
797 * need to compare the parent (which must be window) *
798 with the last object (which must not be window). *
799 *****************************************************/
800
801 if (gml->object_end->data == gml->ml.parent->data)
802 return gamgi_io_error_empty (gml->ml.filename,
803 fileline, gml->ml.window);
804
805 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
806
807 return gml->ml.valid;
808 }
809
810 static gamgi_bool static_window_start (const char *element,
811 const char **attributes, gamgi_gml *gml)
812 {
813 gamgi_window *window;
814 gamgi_window_class *window_class;
815 gamgi_object *object;
816 char token[GAMGI_ENGINE_TOKEN];
817 int fileline, i;
818 int origin = 0, size = 0;
819 unsigned int hash;
820
821 /******************************************
822 * used only in error messages: file line *
823 * indicates where current element starts *
824 ******************************************/
825
826 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
827
828 /***********************
829 * parent stack: check *
830 ***********************/
831
832 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_WINDOW, gml) == FALSE)
833 return gamgi_io_error_child (gml->ml.filename,
834 fileline, gml->ml.window);
835
836 /**************************************************
837 * window_class contains the current config info, *
838 * which is gamgi->window unless new config info *
839 * has been previously stored in object->object. *
840 **************************************************/
841
842 object = GAMGI_CAST_OBJECT gamgi->window;
843 if (object->object == NULL) window_class = gamgi->window;
844 else window_class = (gamgi_window_class *) object->object;
845
846 /******************
847 * object: create *
848 ******************/
849
850 window = gamgi_engine_create_window ();
851 gamgi_engine_start_window (window);
852 gamgi_mesa_start_window (window, window_class);
853
854 window->object.object = GAMGI_CAST_OBJECT gml->ml.parent->data;
855
856 /************************
857 * object queue: update *
858 ************************/
859
860 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
861 gml->object_end->data = window;
862
863 /************************
864 * parent stack: update *
865 ************************/
866
867 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
868 gml->ml.parent->data = window;
869
870 /**********************************
871 * attribute array: check, update *
872 **********************************/
873
874 for (i = 0; attributes[i] != NULL; i += 2)
875 {
876 /********
877 * name *
878 ********/
879
880 if (strcmp (attributes[i], "name") == 0)
881 {
882 if (gamgi_io_token_alpha_scan (attributes[i + 1],
883 window->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
884 return gamgi_io_error_value (attributes[i + 1],
885 gml->ml.filename, fileline, gml->ml.window);
886 }
887
888 /*****************
889 * id (optional) *
890 *****************/
891
892 else if (strcmp (attributes[i], "id") == 0)
893 {
894 if (gamgi_io_token_alpha_scan (attributes[i + 1],
895 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
896 return gamgi_io_error_value (attributes[i + 1],
897 gml->ml.filename, fileline, gml->ml.window);
898
899 hash = gamgi_math_hash_value (token,
900 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
901
902 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
903 return gamgi_io_error_multiple (gml->ml.filename,
904 fileline, gml->ml.window);
905
906 gamgi_expat_import_id_add (token, gml, hash);
907 }
908
909 /****************************************************
910 * geometry parameters *
911 * *
912 * origin: x, y must be in the ranges *
913 * [-screen_width, +screen_width] *
914 * [-screen_height, +screen_height] *
915 * *
916 * size: w, h must be in the ranges *
917 * [GAMGI_GTK_WINDOW_WIDTH_MIN, 2 * screen_width] *
918 * [GAMGI_GTK_WINDOW_HEIGHT_MIN, 2 * screen_height] *
919 ****************************************************/
920
921 else if (strcmp (attributes[i], "x") == 0)
922 {
923 origin++;
924 if (gamgi_io_token_int_scan (attributes[i + 1],
925 &window->origin_x, -gamgi->width, gamgi->width) == FALSE)
926 return gamgi_io_error_value (attributes[i + 1],
927 gml->ml.filename, fileline, gml->ml.window);
928 }
929
930 else if (strcmp (attributes[i], "y") == 0)
931 {
932 origin++;
933 if (gamgi_io_token_int_scan (attributes[i + 1],
934 &window->origin_y, -gamgi->height, gamgi->height) == FALSE)
935 return gamgi_io_error_value (attributes[i + 1],
936 gml->ml.filename, fileline, gml->ml.window);
937 }
938
939 else if (strcmp (attributes[i], "width") == 0)
940 {
941 size++;
942 if (gamgi_io_token_int_scan (attributes[i + 1], &window->width,
943 GAMGI_GTK_WINDOW_WIDTH_MIN, 2 * gamgi->width) == FALSE)
944 return gamgi_io_error_value (attributes[i + 1],
945 gml->ml.filename, fileline, gml->ml.window);
946 }
947
948 else if (strcmp (attributes[i], "height") == 0)
949 {
950 size++;
951 if (gamgi_io_token_int_scan (attributes[i + 1], &window->height,
952 GAMGI_GTK_WINDOW_HEIGHT_MIN, 2 * gamgi->height) == FALSE)
953 return gamgi_io_error_value (attributes[i + 1],
954 gml->ml.filename, fileline, gml->ml.window);
955 }
956
957 /***********************
958 * show parameters: *
959 * top, medium, bottom *
960 ***********************/
961
962 else if (strcmp (attributes[i], "top") == 0)
963 {
964 if (gamgi_io_token_bool_scan (attributes[i + 1],
965 &window->top_flag) == FALSE)
966 return gamgi_io_error_value (attributes[i + 1],
967 gml->ml.filename, fileline, gml->ml.window);
968 }
969
970 else if (strcmp (attributes[i], "medium") == 0)
971 {
972 if (gamgi_io_token_bool_scan (attributes[i + 1],
973 &window->medium_flag) == FALSE)
974 return gamgi_io_error_value (attributes[i + 1],
975 gml->ml.filename, fileline, gml->ml.window);
976 }
977
978 else if (strcmp (attributes[i], "bottom") == 0)
979 {
980 if (gamgi_io_token_bool_scan (attributes[i + 1],
981 &window->bottom_flag) == FALSE)
982 return gamgi_io_error_value (attributes[i + 1],
983 gml->ml.filename, fileline, gml->ml.window);
984 }
985
986 else return gamgi_io_error_attribute (attributes[i],
987 gml->ml.filename, fileline, gml->ml.window);
988 }
989
990 /*****************************************
991 * global tests: incompatible attributes *
992 *****************************************/
993
994 if (origin == 1)
995 return gamgi_io_error_incompatible (gml->ml.filename,
996 fileline, gml->ml.window);
997
998 if (size == 1)
999 return gamgi_io_error_incompatible (gml->ml.filename,
1000 fileline, gml->ml.window);
1001
1002 return gml->ml.valid;
1003 }
1004
1005 static gamgi_bool static_layer_end (const char *element, gamgi_gml *gml)
1006 {
1007 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
1008
1009 return gml->ml.valid;
1010 }
1011
1012 static gamgi_bool static_layer_start (const char *element,
1013 const char **attributes, gamgi_gml *gml)
1014 {
1015 gamgi_layer *layer;
1016 gamgi_layer_class *layer_class;
1017 gamgi_object *object;
1018 char token[GAMGI_ENGINE_TOKEN];
1019 double x[3], z[3], up_z[3];
1020 double length;
1021 int fileline, i;
1022 int eye = 0, center = 0, up = 0, color = 0;
1023 unsigned int hash;
1024
1025 /******************************************
1026 * used only in error messages: file line *
1027 * indicates where current element starts *
1028 ******************************************/
1029
1030 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
1031
1032 /***********************
1033 * parent stack: check *
1034 ***********************/
1035
1036 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_LAYER, gml) == FALSE)
1037 return gamgi_io_error_child (gml->ml.filename,
1038 fileline, gml->ml.window);
1039
1040 /*************************************************
1041 * layer_class contains the current config info, *
1042 * which is gamgi->layer unless new config info *
1043 * has been previously stored in object->object. *
1044 *************************************************/
1045
1046 object = GAMGI_CAST_OBJECT gamgi->layer;
1047 if (object->object == NULL) layer_class = gamgi->layer;
1048 else layer_class = (gamgi_layer_class *) object->object;
1049
1050 /******************
1051 * object: create *
1052 ******************/
1053
1054 layer = gamgi_engine_create_layer ();
1055 gamgi_engine_start_layer (layer);
1056 gamgi_mesa_start_layer (layer, layer_class);
1057
1058 /************************************************************
1059 * by default, each new layer belongs to the current window *
1060 ************************************************************/
1061
1062 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
1063 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window;
1064 layer->object.object = object;
1065
1066 /************************
1067 * object queue: update *
1068 ************************/
1069
1070 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
1071 gml->object_end->data = layer;
1072
1073 /************************
1074 * parent stack: update *
1075 ************************/
1076
1077 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
1078 gml->ml.parent->data = layer;
1079
1080 /**********************************
1081 * start undo and save mechanisms *
1082 **********************************/
1083
1084 gamgi_gtk_history_start (layer);
1085
1086 /*************************************************************
1087 * new top layer: we cannot update gml->ml.window->layer *
1088 * untill we are sure that the file is good. For new windows *
1089 * this problem does not exist, as its whole contents will *
1090 * be removed if the file is bad. When the import operation *
1091 * ends ok, the top layer becomes also the curret object *
1092 *************************************************************/
1093
1094 if (object != GAMGI_CAST_OBJECT gml->ml.window)
1095 (GAMGI_CAST_WINDOW object)->layer = layer;
1096
1097 /**********************************
1098 * attribute array: check, update *
1099 **********************************/
1100
1101 for (i = 0; attributes[i] != NULL; i += 2)
1102 {
1103 /*******************
1104 * name (optional) *
1105 *******************/
1106
1107 if (strcmp (attributes[i], "name") == 0)
1108 {
1109 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1110 layer->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1111 return gamgi_io_error_value (attributes[i + 1],
1112 gml->ml.filename, fileline, gml->ml.window);
1113 }
1114
1115 /*****************
1116 * id (optional) *
1117 *****************/
1118
1119 else if (strcmp (attributes[i], "id") == 0)
1120 {
1121 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1122 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1123 return gamgi_io_error_value (attributes[i + 1],
1124 gml->ml.filename, fileline, gml->ml.window);
1125
1126 hash = gamgi_math_hash_value (token,
1127 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
1128
1129 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
1130 return gamgi_io_error_multiple (gml->ml.filename,
1131 fileline, gml->ml.window);
1132
1133 gamgi_expat_import_id_add (token, gml, hash);
1134 }
1135
1136 /*********************
1137 * parent (optional) *
1138 *********************/
1139
1140 else if (strcmp (attributes[i], "parent") == 0)
1141 {
1142 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1143 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1144 return gamgi_io_error_value (attributes[i + 1],
1145 gml->ml.filename, fileline, gml->ml.window);
1146
1147 gamgi_expat_import_ref_add (token, gml);
1148 }
1149
1150 /*************************************************
1151 * perspective, top, near, far planes (optional) *
1152 *************************************************/
1153
1154 else if (strcmp (attributes[i], "perspective") == 0)
1155 {
1156 if (gamgi_io_token_bool_scan (attributes[i + 1],
1157 &layer->perspective) == FALSE)
1158 return gamgi_io_error_value (attributes[i + 1],
1159 gml->ml.filename, fileline, gml->ml.window);
1160 }
1161
1162 else if (strcmp (attributes[i], "top") == 0)
1163 {
1164 if (gamgi_io_token_double_scan (attributes[i + 1],
1165 &layer->top, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
1166 return gamgi_io_error_value (attributes[i + 1],
1167 gml->ml.filename, fileline, gml->ml.window);
1168 }
1169
1170 else if (strcmp (attributes[i], "near") == 0)
1171 {
1172 if (gamgi_io_token_double_scan (attributes[i + 1],
1173 &layer->near, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
1174 return gamgi_io_error_value (attributes[i + 1],
1175 gml->ml.filename, fileline, gml->ml.window);
1176 }
1177
1178 else if (strcmp (attributes[i], "far") == 0)
1179 {
1180 if (gamgi_io_token_double_scan (attributes[i + 1],
1181 &layer->far, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
1182 return gamgi_io_error_value (attributes[i + 1],
1183 gml->ml.filename, fileline, gml->ml.window);
1184 }
1185
1186 /**********************************
1187 * eye_x, eye_y, eye_z (optional) *
1188 **********************************/
1189
1190 else if (strcmp (attributes[i], "eye_x") == 0)
1191 {
1192 eye++;
1193 if (gamgi_io_token_double_scan (attributes[i + 1],
1194 &layer->eye[0], -DBL_MAX, DBL_MAX) == FALSE)
1195 return gamgi_io_error_value (attributes[i + 1],
1196 gml->ml.filename, fileline, gml->ml.window);
1197 }
1198
1199 else if (strcmp (attributes[i], "eye_y") == 0)
1200 {
1201 eye++;
1202 if (gamgi_io_token_double_scan (attributes[i + 1],
1203 &layer->eye[1], -DBL_MAX, DBL_MAX) == FALSE)
1204 return gamgi_io_error_value (attributes[i + 1],
1205 gml->ml.filename, fileline, gml->ml.window);
1206 }
1207
1208 else if (strcmp (attributes[i], "eye_z") == 0)
1209 {
1210 eye++;
1211 if (gamgi_io_token_double_scan (attributes[i + 1],
1212 &layer->eye[2], -DBL_MAX, DBL_MAX) == FALSE)
1213 return gamgi_io_error_value (attributes[i + 1],
1214 gml->ml.filename, fileline, gml->ml.window);
1215 }
1216
1217 /*******************************************
1218 * center_x, center_y, center_z (optional) *
1219 *******************************************/
1220
1221 else if (strcmp (attributes[i], "center_x") == 0)
1222 {
1223 center++;
1224 if (gamgi_io_token_double_scan (attributes[i + 1],
1225 &layer->center[0], -DBL_MAX, DBL_MAX) == FALSE)
1226 return gamgi_io_error_value (attributes[i + 1],
1227 gml->ml.filename, fileline, gml->ml.window);
1228 }
1229
1230 else if (strcmp (attributes[i], "center_y") == 0)
1231 {
1232 center++;
1233 if (gamgi_io_token_double_scan (attributes[i + 1],
1234 &layer->center[1], -DBL_MAX, DBL_MAX) == FALSE)
1235 return gamgi_io_error_value (attributes[i + 1],
1236 gml->ml.filename, fileline, gml->ml.window);
1237 }
1238
1239 else if (strcmp (attributes[i], "center_z") == 0)
1240 {
1241 center++;
1242 if (gamgi_io_token_double_scan (attributes[i + 1],
1243 &layer->center[2], -DBL_MAX, DBL_MAX) == FALSE)
1244 return gamgi_io_error_value (attributes[i + 1],
1245 gml->ml.filename, fileline, gml->ml.window);
1246 }
1247
1248 /*******************************
1249 * up_x, up_y, up_z (optional) *
1250 *******************************/
1251
1252 else if (strcmp (attributes[i], "up_x") == 0)
1253 {
1254 up++;
1255 if (gamgi_io_token_double_scan (attributes[i + 1],
1256 &layer->up[0], -DBL_MAX, DBL_MAX) == FALSE)
1257 return gamgi_io_error_value (attributes[i + 1],
1258 gml->ml.filename, fileline, gml->ml.window);
1259 }
1260
1261 else if (strcmp (attributes[i], "up_y") == 0)
1262 {
1263 up++;
1264 if (gamgi_io_token_double_scan (attributes[i + 1],
1265 &layer->up[1], -DBL_MAX, DBL_MAX) == FALSE)
1266 return gamgi_io_error_value (attributes[i + 1],
1267 gml->ml.filename, fileline, gml->ml.window);
1268 }
1269
1270 else if (strcmp (attributes[i], "up_z") == 0)
1271 {
1272 up++;
1273 if (gamgi_io_token_double_scan (attributes[i + 1],
1274 &layer->up[2], -DBL_MAX, DBL_MAX) == FALSE)
1275 return gamgi_io_error_value (attributes[i + 1],
1276 gml->ml.filename, fileline, gml->ml.window);
1277 }
1278
1279 /*******************************************
1280 * visibility_in,visibility_out (optional) *
1281 *******************************************/
1282
1283 else if (strcmp (attributes[i], "visibility_in") == 0)
1284 {
1285 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1286 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1287 return gamgi_io_error_value (attributes[i + 1],
1288 gml->ml.filename, fileline, gml->ml.window);
1289
1290 else if (strcmp (token, "all") == 0)
1291 layer->visibility_in = GAMGI_GTK_ALL;
1292 else if (strcmp (token, "partial") == 0)
1293 layer->visibility_in = GAMGI_GTK_PARTIAL;
1294 else if (strcmp (token, "none") == 0)
1295 layer->visibility_in = GAMGI_GTK_NONE;
1296 else return gamgi_io_error_value (attributes[i + 1],
1297 gml->ml.filename, fileline, gml->ml.window);
1298 }
1299
1300 else if (strcmp (attributes[i], "visibility_out") == 0)
1301 {
1302 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1303 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1304 return gamgi_io_error_value (attributes[i + 1],
1305 gml->ml.filename, fileline, gml->ml.window);
1306
1307 else if (strcmp (token, "all") == 0)
1308 layer->visibility_out = GAMGI_GTK_ALL;
1309 else if (strcmp (token, "partial") == 0)
1310 layer->visibility_out = GAMGI_GTK_PARTIAL;
1311 else if (strcmp (token, "none") == 0)
1312 layer->visibility_out = GAMGI_GTK_NONE;
1313 else return gamgi_io_error_value (attributes[i + 1],
1314 gml->ml.filename, fileline, gml->ml.window);
1315 }
1316
1317 /*****************************
1318 * red,green,blue (optional) *
1319 *****************************/
1320
1321 else if (strcmp (attributes[i], "red") == 0)
1322 {
1323 color++;
1324 if (gamgi_io_token_float_scan (attributes[i + 1],
1325 &layer->color[0], 0.0, 1.0) == FALSE)
1326 return gamgi_io_error_value (attributes[i + 1],
1327 gml->ml.filename, fileline, gml->ml.window);
1328 }
1329
1330 else if (strcmp (attributes[i], "green") == 0)
1331 {
1332 color++;
1333 if (gamgi_io_token_float_scan (attributes[i + 1],
1334 &layer->color[1], 0.0, 1.0) == FALSE)
1335 return gamgi_io_error_value (attributes[i + 1],
1336 gml->ml.filename, fileline, gml->ml.window);
1337 }
1338
1339 else if (strcmp (attributes[i], "blue") == 0)
1340 {
1341 color++;
1342 if (gamgi_io_token_float_scan (attributes[i + 1],
1343 &layer->color[2], 0.0, 1.0) == FALSE)
1344 return gamgi_io_error_value (attributes[i + 1],
1345 gml->ml.filename, fileline, gml->ml.window);
1346 }
1347
1348 /*******************
1349 * axes (optional) *
1350 *******************/
1351
1352 else if (strcmp (attributes[i], "axes") == 0)
1353 {
1354 if (gamgi_io_token_bool_scan (attributes[i + 1],
1355 &layer->axes) == FALSE)
1356 return gamgi_io_error_value (attributes[i + 1],
1357 gml->ml.filename, fileline, gml->ml.window);
1358 }
1359
1360 /********************
1361 * scale (optional) *
1362 ********************/
1363
1364 else if (strcmp (attributes[i], "scale") == 0)
1365 {
1366 if (gamgi_io_token_double_scan (attributes[i + 1],
1367 &layer->object.scale, GAMGI_MESA_SCALE_LOWER,
1368 GAMGI_MESA_SCALE_UPPER) == FALSE)
1369 return gamgi_io_error_value (attributes[i + 1],
1370 gml->ml.filename, fileline, gml->ml.window);
1371 }
1372
1373 else return gamgi_io_error_attribute (attributes[i],
1374 gml->ml.filename, fileline, gml->ml.window);
1375 }
1376
1377 /***********************************
1378 * global: incompatible attributes *
1379 ***********************************/
1380
1381 if (layer->near + GAMGI_MATH_TOLERANCE_LENGTH > layer->far)
1382 return gamgi_io_error_incompatible (gml->ml.filename,
1383 fileline, gml->ml.window);
1384
1385 if (eye == 1 || eye == 2)
1386 return gamgi_io_error_incompatible (gml->ml.filename,
1387 fileline, gml->ml.window);
1388
1389 if (center == 1 || center == 2)
1390 return gamgi_io_error_incompatible (gml->ml.filename,
1391 fileline, gml->ml.window);
1392
1393 if (up == 1 || up == 2)
1394 return gamgi_io_error_incompatible (gml->ml.filename,
1395 fileline, gml->ml.window);
1396
1397 if (color == 1 || color == 2)
1398 return gamgi_io_error_incompatible (gml->ml.filename,
1399 fileline, gml->ml.window);
1400
1401 /************************************************************
1402 * check view parameters: *
1403 * 1) the distance eye-center must be in the near-far range *
1404 * 2) the up component normal to eye-center cannot be zero *
1405 ************************************************************/
1406
1407 gamgi_math_vector_sub (layer->eye, layer->center, z);
1408 length = gamgi_math_vector_length (z);
1409 if (length < layer->near || length > layer->far)
1410 return gamgi_io_error_incompatible (gml->ml.filename,
1411 fileline, gml->ml.window);
1412 gamgi_math_vector_normal (z);
1413
1414 length = gamgi_math_vector_dot (layer->up, z);
1415 gamgi_math_vector_scale (z, up_z, length);
1416 gamgi_math_vector_sub (layer->up, up_z, layer->up);
1417 length = gamgi_math_vector_length (layer->up);
1418 if (length < GAMGI_MATH_TOLERANCE_LENGTH)
1419 return gamgi_io_error_incompatible (gml->ml.filename,
1420 fileline, gml->ml.window);
1421 gamgi_math_vector_normal (layer->up);
1422
1423 gamgi_math_vector_cross (layer->up, z, x);
1424 gamgi_math_matrix_absolute (layer->referential,
1425 x[0], layer->up[0], z[0], x[1], layer->up[1], z[1], x[2], layer->up[2], z[2]);
1426
1427 return gml->ml.valid;
1428 }
1429
1430 static gamgi_bool static_light_end (const char *element, gamgi_gml *gml)
1431 {
1432 /**********************
1433 * handle parent list *
1434 **********************/
1435
1436 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
1437
1438 return gml->ml.valid;
1439 }
1440
1441 static gamgi_bool static_light_start (const char *element,
1442 const char **attributes, gamgi_gml *gml)
1443 {
1444 gamgi_light *light;
1445 gamgi_light_class *light_class;
1446 gamgi_object *object;
1447 char token[GAMGI_ENGINE_TOKEN];
1448 int fileline, i;
1449 int ref = 0;
1450 int direction = 0, position = 0;
1451 int ambient = 0, diffuse = 0, specular = 0;
1452 int constant = 0, linear = 0, quadratic = 0, radial = 0;
1453 unsigned int hash;
1454
1455 /******************************************
1456 * used only in error messages: file line *
1457 * indicates where current element starts *
1458 ******************************************/
1459
1460 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
1461
1462 /***********************
1463 * parent stack: check *
1464 ***********************/
1465
1466 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_LIGHT, gml) == FALSE)
1467 return gamgi_io_error_child (gml->ml.filename,
1468 fileline, gml->ml.window);
1469
1470 /*************************************************
1471 * light_class contains the current config info, *
1472 * which is gamgi->light unless new config info *
1473 * has been previously stored in object->object. *
1474 *************************************************/
1475
1476 object = GAMGI_CAST_OBJECT gamgi->light;
1477 if (object->object == NULL) light_class = gamgi->light;
1478 else light_class = (gamgi_light_class *) object->object;
1479
1480 /******************
1481 * object: create *
1482 ******************/
1483
1484 light = gamgi_engine_create_light ();
1485 gamgi_engine_start_light (light);
1486 gamgi_mesa_start_light (light, light_class);
1487
1488 /***********************************************************
1489 * by default, each new light belongs to the current layer *
1490 ***********************************************************/
1491
1492 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
1493 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
1494 light->object.object = object;
1495
1496 /************************
1497 * object queue: update *
1498 ************************/
1499
1500 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
1501 gml->object_end->data = light;
1502
1503 /************************
1504 * parent stack: update *
1505 ************************/
1506
1507 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
1508 gml->ml.parent->data = light;
1509
1510 /**********************************
1511 * attribute array: check, update *
1512 **********************************/
1513
1514 for (i = 0; attributes[i] != NULL; i += 2)
1515 {
1516 /*******************
1517 * name (optional) *
1518 *******************/
1519
1520 if (strcmp (attributes[i], "name") == 0)
1521 {
1522 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1523 light->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1524 return gamgi_io_error_value (attributes[i + 1],
1525 gml->ml.filename, fileline, gml->ml.window);
1526 }
1527
1528 /*****************
1529 * id (optional) *
1530 *****************/
1531
1532 else if (strcmp (attributes[i], "id") == 0)
1533 {
1534 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1535 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1536 return gamgi_io_error_value (attributes[i + 1],
1537 gml->ml.filename, fileline, gml->ml.window);
1538
1539 hash = gamgi_math_hash_value (token,
1540 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
1541
1542 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
1543 return gamgi_io_error_multiple (gml->ml.filename,
1544 fileline, gml->ml.window);
1545
1546 gamgi_expat_import_id_add (token, gml, hash);
1547 }
1548
1549 /*********************
1550 * parent (optional) *
1551 *********************/
1552
1553 else if (strcmp (attributes[i], "parent") == 0)
1554 {
1555 ref++;
1556 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1557 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1558 return gamgi_io_error_value (attributes[i + 1],
1559 gml->ml.filename, fileline, gml->ml.window);
1560
1561 gamgi_expat_import_ref_add (token, gml);
1562 }
1563
1564 /***************************************
1565 * red,green,blue ambient (coupled, *
1566 * one type required, others optional) *
1567 ***************************************/
1568
1569 else if (strcmp (attributes[i], "ambient_r") == 0)
1570 {
1571 ambient++;
1572 if (gamgi_io_token_float_scan (attributes[i + 1],
1573 &light->ambient[0], 0.0, 1.0) == FALSE)
1574 return gamgi_io_error_value (attributes[i + 1],
1575 gml->ml.filename, fileline, gml->ml.window);
1576 }
1577
1578 else if (strcmp (attributes[i], "ambient_g") == 0)
1579 {
1580 ambient++;
1581 if (gamgi_io_token_float_scan (attributes[i + 1],
1582 &light->ambient[1], 0.0, 1.0) == FALSE)
1583 return gamgi_io_error_value (attributes[i + 1],
1584 gml->ml.filename, fileline, gml->ml.window);
1585 }
1586
1587 else if (strcmp (attributes[i], "ambient_b") == 0)
1588 {
1589 ambient++;
1590 if (gamgi_io_token_float_scan (attributes[i + 1],
1591 &light->ambient[2], 0.0, 1.0) == FALSE)
1592 return gamgi_io_error_value (attributes[i + 1],
1593 gml->ml.filename, fileline, gml->ml.window);
1594 }
1595
1596 /***************************************
1597 * red,green,blue diffuse (coupled, *
1598 * one type required, others optional) *
1599 ***************************************/
1600
1601 else if (strcmp (attributes[i], "diffuse_r") == 0)
1602 {
1603 diffuse++;
1604 if (gamgi_io_token_float_scan (attributes[i + 1],
1605 &light->diffuse[0], 0.0, 1.0) == FALSE)
1606 return gamgi_io_error_value (attributes[i + 1],
1607 gml->ml.filename, fileline, gml->ml.window);
1608 }
1609
1610 else if (strcmp (attributes[i], "diffuse_g") == 0)
1611 {
1612 diffuse++;
1613 if (gamgi_io_token_float_scan (attributes[i + 1],
1614 &light->diffuse[1], 0.0, 1.0) == FALSE)
1615 return gamgi_io_error_value (attributes[i + 1],
1616 gml->ml.filename, fileline, gml->ml.window);
1617 }
1618
1619 else if (strcmp (attributes[i], "diffuse_b") == 0)
1620 {
1621 diffuse++;
1622 if (gamgi_io_token_float_scan (attributes[i + 1],
1623 &light->diffuse[2], 0.0, 1.0) == FALSE)
1624 return gamgi_io_error_value (attributes[i + 1],
1625 gml->ml.filename, fileline, gml->ml.window);
1626 }
1627
1628 /***************************************
1629 * red,green,blue specular (coupled, *
1630 * one type required, others optional) *
1631 ***************************************/
1632
1633 else if (strcmp (attributes[i], "specular_r") == 0)
1634 {
1635 specular++;
1636 if (gamgi_io_token_float_scan (attributes[i + 1],
1637 &light->specular[0], 0.0, 1.0) == FALSE)
1638 return gamgi_io_error_value (attributes[i + 1],
1639 gml->ml.filename, fileline, gml->ml.window);
1640 }
1641
1642 else if (strcmp (attributes[i], "specular_g") == 0)
1643 {
1644 specular++;
1645 if (gamgi_io_token_float_scan (attributes[i + 1],
1646 &light->specular[1], 0.0, 1.0) == FALSE)
1647 return gamgi_io_error_value (attributes[i + 1],
1648 gml->ml.filename, fileline, gml->ml.window);
1649 }
1650
1651 else if (strcmp (attributes[i], "specular_b") == 0)
1652 {
1653 specular++;
1654 if (gamgi_io_token_float_scan (attributes[i + 1],
1655 &light->specular[2], 0.0, 1.0) == FALSE)
1656 return gamgi_io_error_value (attributes[i + 1],
1657 gml->ml.filename, fileline, gml->ml.window);
1658 }
1659
1660 /*****************************************
1661 * geometry: direction, position, angle *
1662 * (coupled, required, according to type) *
1663 ******************************************/
1664
1665 else if (strcmp (attributes[i], "direction_x") == 0)
1666 {
1667 direction++;
1668 if (gamgi_io_token_float_scan (attributes[i + 1],
1669 &light->direction[0], -FLT_MAX, FLT_MAX) == FALSE)
1670 return gamgi_io_error_value (attributes[i + 1],
1671 gml->ml.filename, fileline, gml->ml.window);
1672 }
1673
1674 else if (strcmp (attributes[i], "direction_y") == 0)
1675 {
1676 direction++;
1677 if (gamgi_io_token_float_scan (attributes[i + 1],
1678 &light->direction[1], -FLT_MAX, FLT_MAX) == FALSE)
1679 return gamgi_io_error_value (attributes[i + 1],
1680 gml->ml.filename, fileline, gml->ml.window);
1681 }
1682
1683 else if (strcmp (attributes[i], "direction_z") == 0)
1684 {
1685 direction++;
1686 if (gamgi_io_token_float_scan (attributes[i + 1],
1687 &light->direction[2], -FLT_MAX, FLT_MAX) == FALSE)
1688 return gamgi_io_error_value (attributes[i + 1],
1689 gml->ml.filename, fileline, gml->ml.window);
1690 }
1691
1692 else if (strcmp (attributes[i], "position_x") == 0)
1693 {
1694 position++;
1695 if (gamgi_io_token_float_scan (attributes[i + 1],
1696 &light->position[0], -FLT_MAX, FLT_MAX) == FALSE)
1697 return gamgi_io_error_value (attributes[i + 1],
1698 gml->ml.filename, fileline, gml->ml.window);
1699 }
1700
1701 else if (strcmp (attributes[i], "position_y") == 0)
1702 {
1703 position++;
1704 if (gamgi_io_token_float_scan (attributes[i + 1],
1705 &light->position[1], -FLT_MAX, FLT_MAX) == FALSE)
1706 return gamgi_io_error_value (attributes[i + 1],
1707 gml->ml.filename, fileline, gml->ml.window);
1708 }
1709
1710 else if (strcmp (attributes[i], "position_z") == 0)
1711 {
1712 position++;
1713 if (gamgi_io_token_float_scan (attributes[i + 1],
1714 &light->position[2], -FLT_MAX, FLT_MAX) == FALSE)
1715 return gamgi_io_error_value (attributes[i + 1],
1716 gml->ml.filename, fileline, gml->ml.window);
1717 }
1718
1719 else if (strcmp (attributes[i], "angle") == 0)
1720 {
1721 if (gamgi_io_token_float_scan (attributes[i + 1],
1722 &light->angle, 0.0, 90.0) == FALSE)
1723 return gamgi_io_error_value (attributes[i + 1],
1724 gml->ml.filename, fileline, gml->ml.window);
1725 }
1726
1727 /***************************************************************
1728 * attenuation: constant, linear, quadratic, radial (optional) *
1729 ***************************************************************/
1730
1731 else if (strcmp (attributes[i], "constant") == 0)
1732 {
1733 constant++;
1734 if (gamgi_io_token_float_scan (attributes[i + 1],
1735 &light->constant, 0.0, FLT_MAX) == FALSE)
1736 return gamgi_io_error_value (attributes[i + 1],
1737 gml->ml.filename, fileline, gml->ml.window);
1738 }
1739
1740 else if (strcmp (attributes[i], "linear") == 0)
1741 {
1742 linear++;
1743 if (gamgi_io_token_float_scan (attributes[i + 1],
1744 &light->linear, 0.0, FLT_MAX) == FALSE)
1745 return gamgi_io_error_value (attributes[i + 1],
1746 gml->ml.filename, fileline, gml->ml.window);
1747 }
1748
1749 else if (strcmp (attributes[i], "quadratic") == 0)
1750 {
1751 quadratic++;
1752 if (gamgi_io_token_float_scan (attributes[i + 1],
1753 &light->quadratic, 0.0, FLT_MAX) == FALSE)
1754 return gamgi_io_error_value (attributes[i + 1],
1755 gml->ml.filename, fileline, gml->ml.window);
1756 }
1757
1758 else if (strcmp (attributes[i], "radial") == 0)
1759 {
1760 radial++;
1761 if (gamgi_io_token_float_scan (attributes[i + 1],
1762 &light->radial, 0.0, FLT_MAX) == FALSE)
1763 return gamgi_io_error_value (attributes[i + 1],
1764 gml->ml.filename, fileline, gml->ml.window);
1765 }
1766
1767 else return gamgi_io_error_attribute (attributes[i],
1768 gml->ml.filename, fileline, gml->ml.window);
1769 }
1770
1771 /******************************
1772 * global: missing attributes *
1773 ******************************/
1774
1775 if (light->ambient[0] + light->ambient[1] + light->ambient[2] == 0
1776 && light->diffuse[0] + light->diffuse[1] + light->diffuse[2] == 0
1777 && light->specular[0] + light->specular[1] + light->specular[2] == 0)
1778 return gamgi_io_error_missing (gml->ml.filename,
1779 fileline, gml->ml.window);
1780
1781 if (ambient == 1 || diffuse == 1 || specular == 1 ||
1782 ambient == 2 || diffuse == 2 || specular == 2)
1783 return gamgi_io_error_missing (gml->ml.filename,
1784 fileline, gml->ml.window);
1785
1786 if (position == 0 && direction == 0)
1787 return gamgi_io_error_missing (gml->ml.filename,
1788 fileline, gml->ml.window);
1789
1790 if (position == 1 || direction == 1 ||
1791 position == 2 || direction == 2)
1792 return gamgi_io_error_missing (gml->ml.filename,
1793 fileline, gml->ml.window);
1794
1795 /******************************
1796 * global: default attributes *
1797 ******************************/
1798
1799 if (position == 3) light->position[3] = 1.0;
1800 else
1801 {
1802 /***************************************************
1803 * OpenGL saves geometric data for directional and *
1804 * positional lights in the same array (position), *
1805 * using only a second array (direction) for spot *
1806 * lights. For directional lights, the direction *
1807 * data, collected in the direction array, must *
1808 * therefore be transfered to the position array *
1809 * and the direction array must be re-initialised. *
1810 ***************************************************/
1811
1812 /************************************************************
1813 * invert the vector direction, so it has the same physical *
1814 * meaning in directional and positional lights, always *
1815 * pointing from the light source to the light destination *
1816 ************************************************************/
1817
1818 light->position[0] = -light->direction[0];
1819 light->position[1] = -light->direction[1];
1820 light->position[2] = -light->direction[2];
1821
1822 light->position[3] = 0.0;
1823
1824 light->direction[0] = GAMGI_MESA_LIGHT_DIRECTION_X;
1825 light->direction[1] = GAMGI_MESA_LIGHT_DIRECTION_Y;
1826 light->direction[2] = GAMGI_MESA_LIGHT_DIRECTION_Z;
1827 }
1828
1829 /***********************************
1830 * global: incompatible attributes *
1831 ***********************************/
1832
1833 if (position == 0 &&
1834 (light->angle != 180.0 || constant > 0
1835 || linear > 0 || quadratic || radial > 0))
1836 return gamgi_io_error_incompatible (gml->ml.filename,
1837 fileline, gml->ml.window);
1838
1839 if (position == 3 && light->angle == 180.0 &&
1840 (direction > 0 || radial > 0))
1841 return gamgi_io_error_incompatible (gml->ml.filename,
1842 fileline, gml->ml.window);
1843
1844 if (light->direction[0] == 0.0 &&
1845 light->direction[1] == 0.0 && light->direction[2] == 0.0)
1846 return gamgi_io_error_incompatible (gml->ml.filename,
1847 fileline, gml->ml.window);
1848
1849 /***************************************************
1850 * each layer cannot have more than gamgi->lights *
1851 * (at least 8, as defined by OpenGL). *
1852 * *
1853 * layer->light is automatically updated everytime *
1854 * layer is rendered, so even if an error is found *
1855 * there is no danger of corrupting the layer data *
1856 ***************************************************/
1857
1858 if (gamgi->max_lights == (GAMGI_CAST_LAYER light->object.object)->light++)
1859 return gamgi_io_error_resources (gml->ml.filename,
1860 fileline, gml->ml.window);
1861
1862 return gml->ml.valid;
1863 }
1864
1865 static gamgi_bool static_assembly_end (const char *element, gamgi_gml *gml)
1866 {
1867 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
1868
1869 return gml->ml.valid;
1870 }
1871
1872 static gamgi_bool static_assembly_start (const char *element,
1873 const char **attributes, gamgi_gml *gml)
1874 {
1875 gamgi_assembly *assembly;
1876 gamgi_assembly_class *assembly_class;
1877 gamgi_object *object;
1878 char token[GAMGI_ENGINE_TOKEN];
1879 int fileline, i;
1880 unsigned int hash;
1881
1882 /******************************************
1883 * used only in error messages: file line *
1884 * indicates where current element starts *
1885 ******************************************/
1886
1887 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
1888
1889 /******************************
1890 * parent list: check, update *
1891 ******************************/
1892
1893 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_ASSEMBLY, gml) == FALSE)
1894 return gamgi_io_error_child (gml->ml.filename,
1895 fileline, gml->ml.window);
1896
1897 /****************************************************
1898 * assembly_class contains the current config info, *
1899 * which is gamgi->assembly unless new config info *
1900 * has been previously stored in object->object. *
1901 ****************************************************/
1902
1903 object = GAMGI_CAST_OBJECT gamgi->assembly;
1904 if (object->object == NULL) assembly_class = gamgi->assembly;
1905 else assembly_class = (gamgi_assembly_class *) object->object;
1906
1907 /*****************
1908 * object create *
1909 *****************/
1910
1911 assembly = gamgi_engine_create_assembly ();
1912 gamgi_engine_start_assembly (assembly);
1913 gamgi_mesa_start_assembly (assembly, assembly_class);
1914
1915 /**************************************************************
1916 * by default, each new assembly belongs to the current layer *
1917 **************************************************************/
1918
1919 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
1920 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
1921 assembly->object.object = object;
1922
1923 /************************
1924 * object queue: update *
1925 ************************/
1926
1927 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
1928 gml->object_end->data = assembly;
1929
1930 /************************
1931 * parent stack: update *
1932 ************************/
1933
1934 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
1935 gml->ml.parent->data = assembly;
1936
1937 /**********************************
1938 * attribute array: check, update *
1939 **********************************/
1940
1941 for (i = 0; attributes[i] != NULL; i += 2)
1942 {
1943 /********
1944 * name *
1945 ********/
1946
1947 if (strcmp (attributes[i], "name") == 0)
1948 {
1949 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1950 assembly->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1951 return gamgi_io_error_value (attributes[i + 1],
1952 gml->ml.filename, fileline, gml->ml.window);
1953 }
1954
1955 /*****************
1956 * id (optional) *
1957 *****************/
1958
1959 else if (strcmp (attributes[i], "id") == 0)
1960 {
1961 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1962 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1963 return gamgi_io_error_value (attributes[i + 1],
1964 gml->ml.filename, fileline, gml->ml.window);
1965
1966 hash = gamgi_math_hash_value (token,
1967 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
1968
1969 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
1970 return gamgi_io_error_multiple (gml->ml.filename,
1971 fileline, gml->ml.window);
1972
1973 gamgi_expat_import_id_add (token, gml, hash);
1974 }
1975
1976 /*********************
1977 * parent (optional) *
1978 *********************/
1979
1980 else if (strcmp (attributes[i], "parent") == 0)
1981 {
1982 if (gamgi_io_token_alpha_scan (attributes[i + 1],
1983 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
1984 return gamgi_io_error_value (attributes[i + 1],
1985 gml->ml.filename, fileline, gml->ml.window);
1986
1987 gamgi_expat_import_ref_add (token, gml);
1988 }
1989
1990 /********************
1991 * scale (optional) *
1992 ********************/
1993
1994 else if (strcmp (attributes[i], "scale") == 0)
1995 {
1996 if (gamgi_io_token_double_scan (attributes[i + 1],
1997 &assembly->object.scale, GAMGI_MESA_SCALE_LOWER,
1998 GAMGI_MESA_SCALE_UPPER) == FALSE)
1999 return gamgi_io_error_value (attributes[i + 1],
2000 gml->ml.filename, fileline, gml->ml.window);
2001 }
2002
2003 else return gamgi_io_error_attribute (attributes[i],
2004 gml->ml.filename, fileline, gml->ml.window);
2005 }
2006
2007 /************************************
2008 * global tests: missing attributes *
2009 ************************************/
2010
2011 /*****************************************
2012 * global tests: incompatible attributes *
2013 *****************************************/
2014
2015 return gml->ml.valid;
2016 }
2017
2018 static gamgi_bool static_graph_end (const char *element, gamgi_gml *gml)
2019 {
2020 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
2021
2022 return gml->ml.valid;
2023 }
2024
2025 static gamgi_bool static_graph_start (const char *element,
2026 const char **attributes, gamgi_gml *gml)
2027 {
2028 gamgi_graph *graph;
2029 gamgi_graph_class *graph_class;
2030 gamgi_object *object;
2031 char token[GAMGI_ENGINE_TOKEN];
2032 int fileline, i;
2033 unsigned int hash;
2034
2035 /******************************************
2036 * used only in error messages: file line *
2037 * indicates where current element starts *
2038 ******************************************/
2039
2040 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
2041
2042 /******************************
2043 * parent list: check, update *
2044 ******************************/
2045
2046 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_GRAPH, gml) == FALSE)
2047 return gamgi_io_error_child (gml->ml.filename,
2048 fileline, gml->ml.window);
2049
2050 /*************************************************
2051 * graph_class contains the current config info, *
2052 * which is gamgi->graph unless new config info *
2053 * has been previously stored in object->object. *
2054 *************************************************/
2055
2056 object = GAMGI_CAST_OBJECT gamgi->graph;
2057 if (object->object == NULL) graph_class = gamgi->graph;
2058 else graph_class = (gamgi_graph_class *) object->object;
2059
2060 /*****************
2061 * object create *
2062 *****************/
2063
2064 graph = gamgi_engine_create_graph ();
2065 gamgi_engine_start_graph (graph);
2066 gamgi_mesa_start_graph (graph, graph_class);
2067
2068 /***********************************************************
2069 * by default, each new graph belongs to the current layer *
2070 ***********************************************************/
2071
2072 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
2073 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
2074 graph->object.object = object;
2075
2076 /************************
2077 * object queue: update *
2078 ************************/
2079
2080 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
2081 gml->object_end->data = graph;
2082
2083 /************************
2084 * parent stack: update *
2085 ************************/
2086
2087 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
2088 gml->ml.parent->data = graph;
2089
2090 /**********************************
2091 * attribute array: check, update *
2092 **********************************/
2093
2094 for (i = 0; attributes[i] != NULL; i += 2)
2095 {
2096 /*******************
2097 * name (optional) *
2098 *******************/
2099
2100 if (strcmp (attributes[i], "name") == 0)
2101 {
2102 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2103 graph->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2104 return gamgi_io_error_value (attributes[i + 1],
2105 gml->ml.filename, fileline, gml->ml.window);
2106 }
2107
2108 /*****************
2109 * id (optional) *
2110 *****************/
2111
2112 else if (strcmp (attributes[i], "id") == 0)
2113 {
2114 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2115 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2116 return gamgi_io_error_value (attributes[i + 1],
2117 gml->ml.filename, fileline, gml->ml.window);
2118
2119 hash = gamgi_math_hash_value (token,
2120 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
2121
2122 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
2123 return gamgi_io_error_multiple (gml->ml.filename,
2124 fileline, gml->ml.window);
2125
2126 gamgi_expat_import_id_add (token, gml, hash);
2127 }
2128
2129 /*********************
2130 * parent (optional) *
2131 *********************/
2132
2133 else if (strcmp (attributes[i], "parent") == 0)
2134 {
2135 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2136 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2137 return gamgi_io_error_value (attributes[i + 1],
2138 gml->ml.filename, fileline, gml->ml.window);
2139
2140 gamgi_expat_import_ref_add (token, gml);
2141 }
2142
2143 /********************
2144 * scale (optional) *
2145 ********************/
2146
2147 else if (strcmp (attributes[i], "scale") == 0)
2148 {
2149 if (gamgi_io_token_double_scan (attributes[i + 1],
2150 &graph->object.scale, GAMGI_MESA_SCALE_LOWER,
2151 GAMGI_MESA_SCALE_UPPER) == FALSE)
2152 return gamgi_io_error_value (attributes[i + 1],
2153 gml->ml.filename, fileline, gml->ml.window);
2154 }
2155
2156 else return gamgi_io_error_attribute (attributes[i],
2157 gml->ml.filename, fileline, gml->ml.window);
2158 }
2159
2160 /************************************
2161 * global tests: missing attributes *
2162 ************************************/
2163
2164 /*****************************************
2165 * global tests: incompatible attributes *
2166 *****************************************/
2167
2168 return gml->ml.valid;
2169 }
2170
2171 static gamgi_bool static_shape_end (const char *element, gamgi_gml *gml)
2172 {
2173 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
2174
2175 return gml->ml.valid;
2176 }
2177
2178 static gamgi_bool static_shape_start (const char *element,
2179 const char **attributes, gamgi_gml *gml)
2180 {
2181 gamgi_shape *shape;
2182 gamgi_shape_class *shape_class;
2183 gamgi_object *object;
2184 char token[GAMGI_ENGINE_TOKEN];
2185 int fileline, i;
2186 unsigned int hash;
2187
2188 /******************************************
2189 * used only in error messages: file line *
2190 * indicates where current element starts *
2191 ******************************************/
2192
2193 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
2194
2195 /******************************
2196 * parent list: check, update *
2197 ******************************/
2198
2199 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_SHAPE, gml) == FALSE)
2200 return gamgi_io_error_child (gml->ml.filename,
2201 fileline, gml->ml.window);
2202
2203 /*************************************************
2204 * shape_class contains the current config info, *
2205 * which is gamgi->shape unless new config info *
2206 * has been previously stored in object->object. *
2207 *************************************************/
2208
2209 object = GAMGI_CAST_OBJECT gamgi->shape;
2210 if (object->object == NULL) shape_class = gamgi->shape;
2211 else shape_class = (gamgi_shape_class *) object->object;
2212
2213 /*****************
2214 * object create *
2215 *****************/
2216
2217 shape = gamgi_engine_create_shape ();
2218 gamgi_engine_start_shape (shape);
2219 gamgi_mesa_start_shape (shape, shape_class);
2220
2221 /***********************************************************
2222 * by default, each new shape belongs to the current layer *
2223 ***********************************************************/
2224
2225 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
2226 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
2227 shape->object.object = object;
2228
2229 /************************
2230 * object queue: update *
2231 ************************/
2232
2233 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
2234 gml->object_end->data = shape;
2235
2236 /************************
2237 * parent stack: update *
2238 ************************/
2239
2240 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
2241 gml->ml.parent->data = shape;
2242
2243 /**********************************
2244 * attribute array: check, update *
2245 **********************************/
2246
2247 for (i = 0; attributes[i] != NULL; i += 2)
2248 {
2249 /*******************
2250 * name (optional) *
2251 *******************/
2252
2253 if (strcmp (attributes[i], "name") == 0)
2254 {
2255 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2256 shape->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2257 return gamgi_io_error_value (attributes[i + 1],
2258 gml->ml.filename, fileline, gml->ml.window);
2259 }
2260
2261 /*****************
2262 * id (optional) *
2263 *****************/
2264
2265 else if (strcmp (attributes[i], "id") == 0)
2266 {
2267 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2268 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2269 return gamgi_io_error_value (attributes[i + 1],
2270 gml->ml.filename, fileline, gml->ml.window);
2271
2272 hash = gamgi_math_hash_value (token,
2273 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
2274
2275 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
2276 return gamgi_io_error_multiple (gml->ml.filename,
2277 fileline, gml->ml.window);
2278
2279 gamgi_expat_import_id_add (token, gml, hash);
2280 }
2281
2282 /*********************
2283 * parent (optional) *
2284 *********************/
2285
2286 else if (strcmp (attributes[i], "parent") == 0)
2287 {
2288 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2289 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2290 return gamgi_io_error_value (attributes[i + 1],
2291 gml->ml.filename, fileline, gml->ml.window);
2292
2293 gamgi_expat_import_ref_add (token, gml);
2294 }
2295
2296 /********************
2297 * scale (optional) *
2298 ********************/
2299
2300 else if (strcmp (attributes[i], "scale") == 0)
2301 {
2302 if (gamgi_io_token_double_scan (attributes[i + 1],
2303 &shape->object.scale, GAMGI_MESA_SCALE_LOWER,
2304 GAMGI_MESA_SCALE_UPPER) == FALSE)
2305 return gamgi_io_error_value (attributes[i + 1],
2306 gml->ml.filename, fileline, gml->ml.window);
2307 }
2308
2309 else return gamgi_io_error_attribute (attributes[i],
2310 gml->ml.filename, fileline, gml->ml.window);
2311 }
2312
2313 /************************************
2314 * global tests: missing attributes *
2315 ************************************/
2316
2317 /*****************************************
2318 * global tests: incompatible attributes *
2319 *****************************************/
2320
2321 return gml->ml.valid;
2322 }
2323
2324 static gamgi_bool static_arrow_end (const char *element, gamgi_gml *gml)
2325 {
2326 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
2327
2328 return gml->ml.valid;
2329 }
2330
2331 static gamgi_bool static_arrow_start (const char *element,
2332 const char **attributes, gamgi_gml *gml)
2333 {
2334 gamgi_arrow *arrow;
2335 gamgi_arrow_class *arrow_class;
2336 gamgi_object *object;
2337 char token[GAMGI_ENGINE_TOKEN];
2338 int fileline, i;
2339 unsigned int hash;
2340
2341 /******************************************
2342 * used only in error messages: file line *
2343 * indicates where current element starts *
2344 ******************************************/
2345
2346 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
2347
2348 /******************************
2349 * parent list: check, update *
2350 ******************************/
2351
2352 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_ARROW, gml) == FALSE)
2353 return gamgi_io_error_child (gml->ml.filename,
2354 fileline, gml->ml.window);
2355
2356 /*************************************************
2357 * arrow_class contains the current config info, *
2358 * which is gamgi->arrow unless new config info *
2359 * has been previously stored in object->object. *
2360 *************************************************/
2361
2362 object = GAMGI_CAST_OBJECT gamgi->arrow;
2363 if (object->object == NULL) arrow_class = gamgi->arrow;
2364 else arrow_class = (gamgi_arrow_class *) object->object;
2365
2366 /*****************
2367 * object create *
2368 *****************/
2369
2370 arrow = gamgi_engine_create_arrow ();
2371 gamgi_engine_start_arrow (arrow);
2372 gamgi_mesa_start_arrow (arrow, arrow_class);
2373
2374 /***********************************************************
2375 * by default, each new arrow belongs to the current layer *
2376 ***********************************************************/
2377
2378 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
2379 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
2380 arrow->object.object = object;
2381
2382 /************************
2383 * object queue: update *
2384 ************************/
2385
2386 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
2387 gml->object_end->data = arrow;
2388
2389 /************************
2390 * parent stack: update *
2391 ************************/
2392
2393 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
2394 gml->ml.parent->data = arrow;
2395
2396 /**********************************
2397 * attribute array: check, update *
2398 **********************************/
2399
2400 for (i = 0; attributes[i] != NULL; i += 2)
2401 {
2402 /*******************
2403 * name (optional) *
2404 *******************/
2405
2406 if (strcmp (attributes[i], "name") == 0)
2407 {
2408 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2409 arrow->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2410 return gamgi_io_error_value (attributes[i + 1],
2411 gml->ml.filename, fileline, gml->ml.window);
2412 }
2413
2414 /*****************
2415 * id (optional) *
2416 *****************/
2417
2418 else if (strcmp (attributes[i], "id") == 0)
2419 {
2420 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2421 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2422 return gamgi_io_error_value (attributes[i + 1],
2423 gml->ml.filename, fileline, gml->ml.window);
2424
2425 hash = gamgi_math_hash_value (token,
2426 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
2427
2428 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
2429 return gamgi_io_error_multiple (gml->ml.filename,
2430 fileline, gml->ml.window);
2431
2432 gamgi_expat_import_id_add (token, gml, hash);
2433 }
2434
2435 /*********************
2436 * parent (optional) *
2437 *********************/
2438
2439 else if (strcmp (attributes[i], "parent") == 0)
2440 {
2441 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2442 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2443 return gamgi_io_error_value (attributes[i + 1],
2444 gml->ml.filename, fileline, gml->ml.window);
2445
2446 gamgi_expat_import_ref_add (token, gml);
2447 }
2448
2449 /********************
2450 * scale (optional) *
2451 ********************/
2452
2453 else if (strcmp (attributes[i], "scale") == 0)
2454 {
2455 if (gamgi_io_token_double_scan (attributes[i + 1],
2456 &arrow->object.scale, GAMGI_MESA_SCALE_LOWER,
2457 GAMGI_MESA_SCALE_UPPER) == FALSE)
2458 return gamgi_io_error_value (attributes[i + 1],
2459 gml->ml.filename, fileline, gml->ml.window);
2460 }
2461
2462 else return gamgi_io_error_attribute (attributes[i],
2463 gml->ml.filename, fileline, gml->ml.window);
2464 }
2465
2466 /************************************
2467 * global tests: missing attributes *
2468 ************************************/
2469
2470 /*****************************************
2471 * global tests: incompatible attributes *
2472 *****************************************/
2473
2474 return gml->ml.valid;
2475 }
2476
2477 static gamgi_bool static_cell_end (const char *element, gamgi_gml *gml)
2478 {
2479 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
2480
2481 return gml->ml.valid;
2482 }
2483
2484 static gamgi_bool static_cell_start (const char *element,
2485 const char **attributes, gamgi_gml *gml)
2486 {
2487 gamgi_cell *cell;
2488 gamgi_cell_class *cell_class;
2489 gamgi_object *object;
2490 char token[GAMGI_ENGINE_TOKEN];
2491 char system[GAMGI_ENGINE_TOKEN] = "";
2492 char lattice[GAMGI_ENGINE_TOKEN] = "";
2493 double origin[3], euler[3];
2494 int o1 = 0, o2 = 0, o3 = 0;
2495 int o123 = 0;
2496 gamgi_enum o4 = FALSE;
2497 int fileline, i;
2498 int number = 0, volume = 0;
2499 int position = 0, angle = 0, color = 0;
2500 int nodes = 0, faces = 0, borders = 0;
2501 int origin_vectors = 0, axes_vectors = 0;
2502 unsigned int hash;
2503
2504 /******************************************
2505 * used only in error messages: file line *
2506 * indicates where current element starts *
2507 ******************************************/
2508
2509 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
2510
2511 /******************************
2512 * parent list: check, update *
2513 ******************************/
2514
2515 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_CELL, gml) == FALSE)
2516 return gamgi_io_error_child (gml->ml.filename,
2517 fileline, gml->ml.window);
2518
2519 /*************************************************
2520 * cell_class contains the current config info, *
2521 * which is gamgi->cell unless new config info *
2522 * has been previously stored in object->object. *
2523 *************************************************/
2524
2525 object = GAMGI_CAST_OBJECT gamgi->cell;
2526 if (object->object == NULL) cell_class = gamgi->cell;
2527 else cell_class = (gamgi_cell_class *) object->object;
2528
2529 /*****************
2530 * object create *
2531 *****************/
2532
2533 cell = gamgi_engine_create_cell ();
2534 gamgi_engine_start_cell (cell);
2535 gamgi_mesa_start_cell (cell, cell_class);
2536
2537 /**********************************************************
2538 * by default, each new cell belongs to the current layer *
2539 **********************************************************/
2540
2541 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
2542 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
2543 cell->object.object = object;
2544
2545 /************************
2546 * object queue: update *
2547 ************************/
2548
2549 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
2550 gml->object_end->data = cell;
2551
2552 /************************
2553 * parent stack: update *
2554 ************************/
2555
2556 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
2557 gml->ml.parent->data = cell;
2558
2559 /**********************************
2560 * attribute array: check, update *
2561 **********************************/
2562
2563 for (i = 0; attributes[i] != NULL; i += 2)
2564 {
2565 /*******************
2566 * name (optional) *
2567 *******************/
2568
2569 if (strcmp (attributes[i], "name") == 0)
2570 {
2571 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2572 cell->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2573 return gamgi_io_error_value (attributes[i + 1],
2574 gml->ml.filename, fileline, gml->ml.window);
2575 }
2576
2577 /*****************
2578 * id (optional) *
2579 *****************/
2580
2581 else if (strcmp (attributes[i], "id") == 0)
2582 {
2583 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2584 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2585 return gamgi_io_error_value (attributes[i + 1],
2586 gml->ml.filename, fileline, gml->ml.window);
2587
2588 hash = gamgi_math_hash_value (token,
2589 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
2590
2591 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
2592 return gamgi_io_error_multiple (gml->ml.filename,
2593 fileline, gml->ml.window);
2594
2595 gamgi_expat_import_id_add (token, gml, hash);
2596 }
2597
2598 /*********************
2599 * parent (optional) *
2600 *********************/
2601
2602 else if (strcmp (attributes[i], "parent") == 0)
2603 {
2604 if (gamgi_io_token_alpha_scan (attributes[i + 1],
2605 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2606 return gamgi_io_error_value (attributes[i + 1],
2607 gml->ml.filename, fileline, gml->ml.window);
2608
2609 gamgi_expat_import_ref_add (token, gml);
2610 }
2611
2612 /********************
2613 * Symmetry section *
2614 ********************/
2615
2616 /*********************
2617 * system (optional) *
2618 *********************/
2619
2620 else if (strcmp (attributes[i], "system") == 0)
2621 {
2622 if (gamgi_io_token_alpha_scan (attributes[i + 1], system,
2623 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2624 return gamgi_io_error_value (attributes[i + 1],
2625 gml->ml.filename, fileline, gml->ml.window);
2626 }
2627
2628 /**********************
2629 * lattice (optional) *
2630 **********************/
2631
2632 else if (strcmp (attributes[i], "lattice") == 0)
2633 {
2634 if (gamgi_io_token_alpha_scan (attributes[i + 1], lattice,
2635 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2636 return gamgi_io_error_value (attributes[i + 1],
2637 gml->ml.filename, fileline, gml->ml.window);
2638 }
2639
2640 /********************
2641 * group (optional) *
2642 ********************/
2643
2644 else if (strcmp (attributes[i], "group") == 0)
2645 {
2646 if (gamgi_io_token_int_scan (attributes[i + 1],
2647 &cell->group, 0, 230) == FALSE)
2648 return gamgi_io_error_value (attributes[i + 1],
2649 gml->ml.filename, fileline, gml->ml.window);
2650 }
2651
2652 /***************************************************
2653 * a,b,c,ab,ac,bc (required, depending on lattice) *
2654 ***************************************************/
2655
2656 else if (strcmp (attributes[i], "a") == 0)
2657 {
2658 if (gamgi_io_token_double_scan (attributes[i + 1],
2659 &cell->a, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2660 return gamgi_io_error_value (attributes[i + 1],
2661 gml->ml.filename, fileline, gml->ml.window);
2662 }
2663
2664 else if (strcmp (attributes[i], "b") == 0)
2665 {
2666 if (gamgi_io_token_double_scan (attributes[i + 1],
2667 &cell->b, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2668 return gamgi_io_error_value (attributes[i + 1],
2669 gml->ml.filename, fileline, gml->ml.window);
2670 }
2671
2672 else if (strcmp (attributes[i], "c") == 0)
2673 {
2674 if (gamgi_io_token_double_scan (attributes[i + 1],
2675 &cell->c, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2676 return gamgi_io_error_value (attributes[i + 1],
2677 gml->ml.filename, fileline, gml->ml.window);
2678 }
2679
2680 else if (strcmp (attributes[i], "ab") == 0)
2681 {
2682 if (gamgi_io_token_double_scan (attributes[i + 1],
2683 &cell->ab, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2684 return gamgi_io_error_value (attributes[i + 1],
2685 gml->ml.filename, fileline, gml->ml.window);
2686 }
2687
2688 else if (strcmp (attributes[i], "ac") == 0)
2689 {
2690 if (gamgi_io_token_double_scan (attributes[i + 1],
2691 &cell->ac, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2692 return gamgi_io_error_value (attributes[i + 1],
2693 gml->ml.filename, fileline, gml->ml.window);
2694 }
2695
2696 else if (strcmp (attributes[i], "bc") == 0)
2697 {
2698 if (gamgi_io_token_double_scan (attributes[i + 1],
2699 &cell->bc, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2700 return gamgi_io_error_value (attributes[i + 1],
2701 gml->ml.filename, fileline, gml->ml.window);
2702 }
2703
2704 else if (strcmp (attributes[i], "reciprocal") == 0)
2705 {
2706 if (gamgi_io_token_double_scan (attributes[i + 1],
2707 &cell->reciprocal, GAMGI_MATH_TOLERANCE_LENGTH,
2708 DBL_MAX) == FALSE)
2709 return gamgi_io_error_value (attributes[i + 1],
2710 gml->ml.filename, fileline, gml->ml.window);
2711 }
2712
2713 /******************
2714 * Volume section *
2715 ******************/
2716
2717 /*********
2718 * model *
2719 *********/
2720
2721 else if (strcmp (attributes[i], "model") == 0)
2722 {
2723 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
2724 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2725 return gamgi_io_error_value (attributes[i + 1],
2726 gml->ml.filename, fileline, gml->ml.window);
2727
2728 if (strcmp (token, "conventional") == 0)
2729 cell->model = GAMGI_PHYS_CONVENTIONAL;
2730 else if (strcmp (token, "primitive") == 0)
2731 cell->model = GAMGI_PHYS_PRIMITIVE;
2732 else if (strcmp (token, "wigner") == 0)
2733 cell->model = GAMGI_PHYS_WIGNER;
2734 else if (strcmp (token, "parallelepiped") == 0)
2735 cell->model = GAMGI_PHYS_PARALLELEPIPED;
2736 else if (strcmp (token, "sphere") == 0)
2737 cell->model = GAMGI_PHYS_SPHERE;
2738 else if (strcmp (token, "projection") == 0)
2739 cell->model = GAMGI_PHYS_PROJECTION;
2740
2741 else return gamgi_io_error_value (attributes[i + 1],
2742 gml->ml.filename, fileline, gml->ml.window);
2743 }
2744
2745 /********************************
2746 * n1,n2,n3 (optional, coupled) *
2747 ********************************/
2748
2749 else if (strcmp (attributes[i], "n1") == 0)
2750 {
2751 number++;
2752 if (gamgi_io_token_int_scan (attributes[i + 1],
2753 &cell->n1, 1, INT_MAX) == FALSE)
2754 return gamgi_io_error_value (attributes[i + 1],
2755 gml->ml.filename, fileline, gml->ml.window);
2756 }
2757
2758 else if (strcmp (attributes[i], "n2") == 0)
2759 {
2760 number++;
2761 if (gamgi_io_token_int_scan (attributes[i + 1],
2762 &cell->n2, 1, INT_MAX) == FALSE)
2763 return gamgi_io_error_value (attributes[i + 1],
2764 gml->ml.filename, fileline, gml->ml.window);
2765 }
2766
2767 else if (strcmp (attributes[i], "n3") == 0)
2768 {
2769 number++;
2770 if (gamgi_io_token_int_scan (attributes[i + 1],
2771 &cell->n3, 1, INT_MAX) == FALSE)
2772 return gamgi_io_error_value (attributes[i + 1],
2773 gml->ml.filename, fileline, gml->ml.window);
2774 }
2775
2776 /***************************************************************
2777 * volume: v1,v2,v3,v12,13,v23 (required, depending of volume) *
2778 ***************************************************************/
2779
2780 else if (strcmp (attributes[i], "v1") == 0)
2781 {
2782 volume++;
2783 if (gamgi_io_token_double_scan (attributes[i + 1],
2784 &cell->v1, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2785 return gamgi_io_error_value (attributes[i + 1],
2786 gml->ml.filename, fileline, gml->ml.window);
2787 }
2788
2789 else if (strcmp (attributes[i], "v2") == 0)
2790 {
2791 volume++;
2792 if (gamgi_io_token_double_scan (attributes[i + 1],
2793 &cell->v2, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2794 return gamgi_io_error_value (attributes[i + 1],
2795 gml->ml.filename, fileline, gml->ml.window);
2796 }
2797
2798 else if (strcmp (attributes[i], "v3") == 0)
2799 {
2800 volume++;
2801 if (gamgi_io_token_double_scan (attributes[i + 1],
2802 &cell->v3, GAMGI_MATH_TOLERANCE_LENGTH, DBL_MAX) == FALSE)
2803 return gamgi_io_error_value (attributes[i + 1],
2804 gml->ml.filename, fileline, gml->ml.window);
2805 }
2806
2807 else if (strcmp (attributes[i], "v12") == 0)
2808 {
2809 volume++;
2810 if (gamgi_io_token_double_scan (attributes[i + 1],
2811 &cell->v12, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2812 return gamgi_io_error_value (attributes[i + 1],
2813 gml->ml.filename, fileline, gml->ml.window);
2814 }
2815
2816 else if (strcmp (attributes[i], "v13") == 0)
2817 {
2818 volume++;
2819 if (gamgi_io_token_double_scan (attributes[i + 1],
2820 &cell->v13, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2821 return gamgi_io_error_value (attributes[i + 1],
2822 gml->ml.filename, fileline, gml->ml.window);
2823 }
2824
2825 else if (strcmp (attributes[i], "v23") == 0)
2826 {
2827 volume++;
2828 if (gamgi_io_token_double_scan (attributes[i + 1],
2829 &cell->v23, GAMGI_MATH_TOLERANCE_ANGLE, 180.0) == FALSE)
2830 return gamgi_io_error_value (attributes[i + 1],
2831 gml->ml.filename, fileline, gml->ml.window);
2832 }
2833
2834 /*********************
2835 * Positions section *
2836 *********************/
2837
2838 /*************************************
2839 * origin: x,y,z (optional, coupled) *
2840 *************************************/
2841
2842 else if (strcmp (attributes[i], "x") == 0)
2843 {
2844 position++;
2845 if (gamgi_io_token_double_scan (attributes[i + 1],
2846 &origin[0], -DBL_MAX, DBL_MAX) == FALSE)
2847 return gamgi_io_error_value (attributes[i + 1],
2848 gml->ml.filename, fileline, gml->ml.window);
2849 }
2850
2851 else if (strcmp (attributes[i], "y") == 0)
2852 {
2853 position++;
2854 if (gamgi_io_token_double_scan (attributes[i + 1],
2855 &origin[1], -DBL_MAX, DBL_MAX) == FALSE)
2856 return gamgi_io_error_value (attributes[i + 1],
2857 gml->ml.filename, fileline, gml->ml.window);
2858 }
2859
2860 else if (strcmp (attributes[i], "z") == 0)
2861 {
2862 position++;
2863 if (gamgi_io_token_double_scan (attributes[i + 1],
2864 &origin[2], -DBL_MAX, DBL_MAX) == FALSE)
2865 return gamgi_io_error_value (attributes[i + 1],
2866 gml->ml.filename, fileline, gml->ml.window);
2867 }
2868
2869 /**********************************************
2870 * Euler angles: e1,e2,e3 (optional, coupled) *
2871 **********************************************/
2872
2873 else if (strcmp (attributes[i], "e1") == 0)
2874 {
2875 angle++;
2876 if (gamgi_io_token_double_scan (attributes[i + 1],
2877 &euler[0], 0.0, 180.0) == FALSE)
2878 return gamgi_io_error_value (attributes[i + 1],
2879 gml->ml.filename, fileline, gml->ml.window);
2880 }
2881
2882 else if (strcmp (attributes[i], "e2") == 0)
2883 {
2884 angle++;
2885 if (gamgi_io_token_double_scan (attributes[i + 1],
2886 &euler[1], 0.0, 360.0) == FALSE)
2887 return gamgi_io_error_value (attributes[i + 1],
2888 gml->ml.filename, fileline, gml->ml.window);
2889 }
2890
2891 else if (strcmp (attributes[i], "e3") == 0)
2892 {
2893 angle++;
2894 if (gamgi_io_token_double_scan (attributes[i + 1],
2895 &euler[2], 0.0, 360.0) == FALSE)
2896 return gamgi_io_error_value (attributes[i + 1],
2897 gml->ml.filename, fileline, gml->ml.window);
2898 }
2899
2900 /******************
2901 * Origin section *
2902 ******************/
2903
2904 /***************************************
2905 * o1,o2,o3 offset (optional, coupled) *
2906 ***************************************/
2907
2908 else if (strcmp (attributes[i], "o1") == 0)
2909 {
2910 o123++;
2911 if (gamgi_io_token_int_scan (attributes[i + 1],
2912 &o1, -INT_MAX, INT_MAX) == FALSE)
2913 return gamgi_io_error_value (attributes[i + 1],
2914 gml->ml.filename, fileline, gml->ml.window);
2915 }
2916
2917 else if (strcmp (attributes[i], "o2") == 0)
2918 {
2919 o123++;
2920 if (gamgi_io_token_int_scan (attributes[i + 1],
2921 &o2, -INT_MAX, INT_MAX) == FALSE)
2922 return gamgi_io_error_value (attributes[i + 1],
2923 gml->ml.filename, fileline, gml->ml.window);
2924 }
2925
2926 else if (strcmp (attributes[i], "o3") == 0)
2927 {
2928 o123++;
2929 if (gamgi_io_token_int_scan (attributes[i + 1],
2930 &o3, -INT_MAX, INT_MAX) == FALSE)
2931 return gamgi_io_error_value (attributes[i + 1],
2932 gml->ml.filename, fileline, gml->ml.window);
2933 }
2934
2935 /************************
2936 * o4 offset (optional) *
2937 ************************/
2938
2939 else if (strcmp (attributes[i], "o4") == 0)
2940 {
2941 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
2942 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2943 return gamgi_io_error_value (attributes[i + 1],
2944 gml->ml.filename, fileline, gml->ml.window);
2945
2946 if (strcmp (token, "000") == 0)
2947 o4 = FALSE;
2948 else if (strcmp (token, "110") == 0)
2949 o4 = GAMGI_PHYS_110;
2950 else if (strcmp (token, "101") == 0)
2951 o4 = GAMGI_PHYS_101;
2952 else if (strcmp (token, "011") == 0)
2953 o4 = GAMGI_PHYS_011;
2954 else if (strcmp (token, "111") == 0)
2955 o4 = GAMGI_PHYS_111;
2956 else if (strcmp (token, "211") == 0)
2957 o4 = GAMGI_PHYS_211;
2958 else if (strcmp (token, "122") == 0)
2959 o4 = GAMGI_PHYS_122;
2960
2961 else return gamgi_io_error_value (attributes[i + 1],
2962 gml->ml.filename, fileline, gml->ml.window);
2963 }
2964
2965 /*****************************
2966 * origin vectors (optional) *
2967 *****************************/
2968
2969 else if (strcmp (attributes[i], "origin_vectors") == 0)
2970 {
2971 origin_vectors++;
2972 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
2973 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
2974 return gamgi_io_error_value (attributes[i + 1],
2975 gml->ml.filename, fileline, gml->ml.window);
2976
2977 if (strcmp (token, "conventional") == 0)
2978 cell->origin_vectors = GAMGI_PHYS_CONVENTIONAL;
2979 else if (strcmp (token, "primitive") == 0)
2980 cell->origin_vectors = GAMGI_PHYS_PRIMITIVE;
2981
2982 else return gamgi_io_error_value (attributes[i + 1],
2983 gml->ml.filename, fileline, gml->ml.window);
2984 }
2985
2986 /*******************
2987 * axes (optional) *
2988 *******************/
2989
2990 else if (strcmp (attributes[i], "axes") == 0)
2991 {
2992 if (gamgi_io_token_bool_scan (attributes[i + 1],
2993 &cell->axes) == FALSE)
2994 return gamgi_io_error_value (attributes[i + 1],
2995 gml->ml.filename, fileline, gml->ml.window);
2996 }
2997
2998 /***************************
2999 * axes vectors (optional) *
3000 ***************************/
3001
3002 else if (strcmp (attributes[i], "axes_vectors") == 0)
3003 {
3004 axes_vectors++;
3005 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
3006 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3007 return gamgi_io_error_value (attributes[i + 1],
3008 gml->ml.filename, fileline, gml->ml.window);
3009
3010 if (strcmp (token, "conventional") == 0)
3011 cell->axes_vectors = GAMGI_PHYS_CONVENTIONAL;
3012 else if (strcmp (token, "primitive") == 0)
3013 cell->axes_vectors = GAMGI_PHYS_PRIMITIVE;
3014
3015 else return gamgi_io_error_value (attributes[i + 1],
3016 gml->ml.filename, fileline, gml->ml.window);
3017 }
3018
3019 /****************
3020 * View section *
3021 ****************/
3022
3023 /**********************
3024 * borders (optional) *
3025 **********************/
3026
3027 else if (strcmp (attributes[i], "borders") == 0)
3028 {
3029 borders++;
3030 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
3031 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3032 return gamgi_io_error_value (attributes[i + 1],
3033 gml->ml.filename, fileline, gml->ml.window);
3034
3035 if (strcmp (token, "all") == 0)
3036 cell->borders = GAMGI_PHYS_ALL;
3037 else if (strcmp (token, "faces") == 0)
3038 cell->borders = GAMGI_PHYS_FACES;
3039 else if (strcmp (token, "edges") == 0)
3040 cell->borders = GAMGI_PHYS_EDGES;
3041 else if (strcmp (token, "none") == 0)
3042 cell->borders = GAMGI_PHYS_NONE;
3043
3044 else return gamgi_io_error_value (attributes[i + 1],
3045 gml->ml.filename, fileline, gml->ml.window);
3046 }
3047
3048 /***************************
3049 * nodes, faces (optional) *
3050 ***************************/
3051
3052 else if (strcmp (attributes[i], "nodes") == 0)
3053 {
3054 nodes++;
3055 if (gamgi_io_token_bool_scan (attributes[i + 1], &cell->nodes) == FALSE)
3056 return gamgi_io_error_value (attributes[i + 1],
3057 gml->ml.filename, fileline, gml->ml.window);
3058 }
3059
3060 else if (strcmp (attributes[i], "faces") == 0)
3061 {
3062 faces++;
3063 if (gamgi_io_token_bool_scan (attributes[i + 1], &cell->faces) == FALSE)
3064 return gamgi_io_error_value (attributes[i + 1],
3065 gml->ml.filename, fileline, gml->ml.window);
3066 }
3067
3068 /*****************************
3069 * red,green,blue (optional) *
3070 *****************************/
3071
3072 else if (strcmp (attributes[i], "red") == 0)
3073 {
3074 color++;
3075 if (gamgi_io_token_float_scan (attributes[i + 1],
3076 &cell->red, 0.0, 1.0) == FALSE)
3077 return gamgi_io_error_value (attributes[i + 1],
3078 gml->ml.filename, fileline, gml->ml.window);
3079 }
3080
3081 else if (strcmp (attributes[i], "green") == 0)
3082 {
3083 color++;
3084 if (gamgi_io_token_float_scan (attributes[i + 1],
3085 &cell->green, 0.0, 1.0) == FALSE)
3086 return gamgi_io_error_value (attributes[i + 1],
3087 gml->ml.filename, fileline, gml->ml.window);
3088 }
3089
3090 else if (strcmp (attributes[i], "blue") == 0)
3091 {
3092 color++;
3093 if (gamgi_io_token_float_scan (attributes[i + 1],
3094 &cell->blue, 0.0, 1.0) == FALSE)
3095 return gamgi_io_error_value (attributes[i + 1],
3096 gml->ml.filename, fileline, gml->ml.window);
3097 }
3098
3099 /********************
3100 * scale (optional) *
3101 ********************/
3102
3103 else if (strcmp (attributes[i], "scale") == 0)
3104 {
3105 if (gamgi_io_token_double_scan (attributes[i + 1],
3106 &cell->object.scale, GAMGI_MESA_SCALE_LOWER,
3107 GAMGI_MESA_SCALE_UPPER) == FALSE)
3108 return gamgi_io_error_value (attributes[i + 1],
3109 gml->ml.filename, fileline, gml->ml.window);
3110 }
3111
3112 else return gamgi_io_error_attribute (attributes[i],
3113 gml->ml.filename, fileline, gml->ml.window);
3114 }
3115
3116 /******************************
3117 * global: missing attributes *
3118 ******************************/
3119
3120 if (cell->model == GAMGI_PHYS_PARALLELEPIPED && volume != 6)
3121 return gamgi_io_error_missing (gml->ml.filename,
3122 fileline, gml->ml.window);
3123
3124 if (cell->model == GAMGI_PHYS_SPHERE && cell->v1 == 0.0)
3125 return gamgi_io_error_missing (gml->ml.filename,
3126 fileline, gml->ml.window);
3127
3128 /***********************************
3129 * global: incompatible attributes *
3130 ***********************************/
3131
3132 if (gamgi_gtk_cell_symmetry_import (system,
3133 lattice, &cell->group, &cell->lattice) == FALSE)
3134 return gamgi_io_error_incompatible (gml->ml.filename,
3135 fileline, gml->ml.window);
3136
3137 if (gamgi_gtk_cell_symmetry_parameters (cell, cell->lattice,
3138 &cell->a, &cell->b, &cell->c, &cell->ab, &cell->ac, &cell->bc) == FALSE)
3139 return gamgi_io_error_incompatible (gml->ml.filename,
3140 fileline, gml->ml.window);
3141
3142 if (position == 1 || position == 2)
3143 return gamgi_io_error_incompatible (gml->ml.filename,
3144 fileline, gml->ml.window);
3145
3146 if (angle == 1 || angle == 2)
3147 return gamgi_io_error_incompatible (gml->ml.filename,
3148 fileline, gml->ml.window);
3149
3150 if (number == 1 || number == 2)
3151 return gamgi_io_error_incompatible (gml->ml.filename,
3152 fileline, gml->ml.window);
3153
3154 if (o123 == 1 || o123 == 2)
3155 return gamgi_io_error_incompatible (gml->ml.filename,
3156 fileline, gml->ml.window);
3157
3158 if (o4 != FALSE && cell->origin_vectors == GAMGI_PHYS_PRIMITIVE)
3159 return gamgi_io_error_incompatible (gml->ml.filename,
3160 fileline, gml->ml.window);
3161
3162 if (o4 != FALSE && gamgi_math_node_check (cell->lattice, o4) == FALSE)
3163 return gamgi_io_error_incompatible (gml->ml.filename,
3164 fileline, gml->ml.window);
3165
3166 /****************************************
3167 * Wigner-Seitz cells are not available *
3168 * yet for these more complex lattices *
3169 ****************************************/
3170
3171 if (cell->model == GAMGI_PHYS_WIGNER)
3172 {
3173 if (cell->lattice == GAMGI_PHYS_TRICLINIC_P ||
3174 cell->lattice == GAMGI_PHYS_MONOCLINIC_P ||
3175 cell->lattice == GAMGI_PHYS_MONOCLINIC_C)
3176 return gamgi_io_error_incompatible (gml->ml.filename,
3177 fileline, gml->ml.window);
3178 }
3179
3180 if (cell->model == GAMGI_PHYS_PARALLELEPIPED)
3181 {
3182 /*********************************************************
3183 * the 3 angles together cannot be too close to 0 or 360 *
3184 * *
3185 * each angle cannot be larger than the sum of the other *
3186 * two, or smaller than the difference of the other two *
3187 *********************************************************/
3188
3189 if (cell->v12 + cell->v13 + cell->v23 > 360.0 - GAMGI_MATH_TOLERANCE_ANGLE)
3190 return gamgi_io_error_incompatible (gml->ml.filename,
3191 fileline, gml->ml.window);
3192
3193 if (cell->v12 + GAMGI_MATH_TOLERANCE_ANGLE > cell->v13 + cell->v23
3194 || cell->v13 + GAMGI_MATH_TOLERANCE_ANGLE > cell->v12 + cell->v23
3195 || cell->v23 + GAMGI_MATH_TOLERANCE_ANGLE > cell->v12 + cell->v13)
3196 return gamgi_io_error_incompatible (gml->ml.filename,
3197 fileline, gml->ml.window);
3198
3199 if (cell->v12 - GAMGI_MATH_TOLERANCE_ANGLE < abs (cell->v13 - cell->v23)
3200 || cell->v13 - GAMGI_MATH_TOLERANCE_ANGLE < abs (cell->v12 - cell->v23)
3201 || cell->v23 - GAMGI_MATH_TOLERANCE_ANGLE < abs (cell->v12 - cell->v13))
3202 return gamgi_io_error_incompatible (gml->ml.filename,
3203 fileline, gml->ml.window);
3204 }
3205
3206 if (cell->model != GAMGI_PHYS_PARALLELEPIPED &&
3207 cell->model != GAMGI_PHYS_SPHERE && volume != 0)
3208 return gamgi_io_error_incompatible (gml->ml.filename,
3209 fileline, gml->ml.window);
3210
3211 if (cell->model == GAMGI_PHYS_SPHERE && volume != 1)
3212 return gamgi_io_error_incompatible (gml->ml.filename,
3213 fileline, gml->ml.window);
3214
3215 if (cell->model == GAMGI_PHYS_PARALLELEPIPED
3216 || cell->model == GAMGI_PHYS_SPHERE)
3217 {
3218 if (number != 0)
3219 return gamgi_io_error_incompatible (gml->ml.filename,
3220 fileline, gml->ml.window);
3221
3222 if (cell->borders == GAMGI_PHYS_ALL
3223 || cell->borders == GAMGI_PHYS_FACES)
3224 return gamgi_io_error_incompatible (gml->ml.filename,
3225 fileline, gml->ml.window);
3226
3227 if (cell->faces == TRUE)
3228 return gamgi_io_error_incompatible (gml->ml.filename,
3229 fileline, gml->ml.window);
3230 }
3231
3232 if (cell->model == GAMGI_PHYS_PROJECTION)
3233 {
3234 if (number != 0)
3235 return gamgi_io_error_incompatible (gml->ml.filename,
3236 fileline, gml->ml.window);
3237
3238 if (cell->reciprocal != 0.0)
3239 return gamgi_io_error_incompatible (gml->ml.filename,
3240 fileline, gml->ml.window);
3241
3242 if (cell->axes == TRUE)
3243 return gamgi_io_error_incompatible (gml->ml.filename,
3244 fileline, gml->ml.window);
3245
3246 if (o123 != 0 || o4 != FALSE)
3247 return gamgi_io_error_incompatible (gml->ml.filename,
3248 fileline, gml->ml.window);
3249
3250 if (borders == 1 && cell->borders != GAMGI_PHYS_EDGES)
3251 return gamgi_io_error_incompatible (gml->ml.filename,
3252 fileline, gml->ml.window);
3253
3254 cell->borders = GAMGI_PHYS_EDGES;
3255
3256 if (cell->faces == TRUE)
3257 return gamgi_io_error_incompatible (gml->ml.filename,
3258 fileline, gml->ml.window);
3259
3260 if (nodes == 1 && cell->nodes != FALSE)
3261 return gamgi_io_error_incompatible (gml->ml.filename,
3262 fileline, gml->ml.window);
3263
3264 cell->nodes = FALSE;
3265 }
3266
3267 if (cell->faces == TRUE && cell->borders == GAMGI_PHYS_ALL)
3268 return gamgi_io_error_incompatible (gml->ml.filename,
3269 fileline, gml->ml.window);
3270
3271 /*****************************************
3272 * Something in the cell must be visible *
3273 *****************************************/
3274
3275 if (faces + nodes + borders == 3 && cell->faces == FALSE &&
3276 cell->nodes == FALSE && cell->borders == GAMGI_PHYS_NONE)
3277 return gamgi_io_error_incompatible (gml->ml.filename,
3278 fileline, gml->ml.window);
3279
3280 if (color == 1 || color == 2)
3281 return gamgi_io_error_incompatible (gml->ml.filename,
3282 fileline, gml->ml.window);
3283
3284 /******************************
3285 * global: default attributes *
3286 ******************************/
3287
3288 if (position == 0) gamgi_math_vector_zero (origin);
3289 if (angle == 0) gamgi_math_vector_zero (euler);
3290
3291 if (origin_vectors == 0)
3292 {
3293 if (cell->model == GAMGI_PHYS_CONVENTIONAL ||
3294 cell->model == GAMGI_PHYS_PARALLELEPIPED ||
3295 cell->model == GAMGI_PHYS_SPHERE ||
3296 cell->model == GAMGI_PHYS_PROJECTION || o4 != FALSE)
3297 cell->origin_vectors = GAMGI_PHYS_CONVENTIONAL;
3298
3299 else cell->origin_vectors = GAMGI_PHYS_PRIMITIVE;
3300 }
3301
3302 if (axes_vectors == 0)
3303 {
3304 if (cell->model == GAMGI_PHYS_CONVENTIONAL ||
3305 cell->model == GAMGI_PHYS_PARALLELEPIPED ||
3306 cell->model == GAMGI_PHYS_SPHERE ||
3307 cell->model == GAMGI_PHYS_PROJECTION)
3308 cell->axes_vectors = GAMGI_PHYS_CONVENTIONAL;
3309
3310 else cell->axes_vectors = GAMGI_PHYS_PRIMITIVE;
3311 }
3312
3313 if (cell->model == GAMGI_PHYS_CONVENTIONAL ||
3314 cell->model == GAMGI_PHYS_PRIMITIVE ||
3315 cell->model == GAMGI_PHYS_WIGNER)
3316 {
3317 if (borders == 0 && cell->faces == TRUE && cell->borders == GAMGI_PHYS_ALL)
3318 cell->borders = GAMGI_PHYS_FACES;
3319 }
3320
3321 if (cell->model == GAMGI_PHYS_PARALLELEPIPED ||
3322 cell->model == GAMGI_PHYS_SPHERE)
3323 {
3324 if (faces == 0) cell->faces = FALSE;
3325 if (borders == 0 && cell->borders != GAMGI_PHYS_NONE)
3326 cell->borders = GAMGI_PHYS_EDGES;
3327 }
3328
3329 if (cell->model == GAMGI_PHYS_PROJECTION)
3330 {
3331 if (nodes == 0) cell->nodes = FALSE;
3332 if (faces == 0) cell->faces = FALSE;
3333 if (borders == 0) cell->borders = GAMGI_PHYS_EDGES;
3334 }
3335
3336 /**************
3337 * build cell *
3338 **************/
3339
3340 if (cell->origin_vectors == GAMGI_PHYS_PRIMITIVE)
3341 { cell->o1 = o1; cell->o2 = o2; cell->o3 = o3; }
3342 if (cell->origin_vectors == GAMGI_PHYS_CONVENTIONAL)
3343 gamgi_math_node_primitive (cell->lattice,
3344 o1, o2, o3, o4, &cell->o1, &cell->o2, &cell->o3);
3345
3346 gamgi_phys_cell_create (cell);
3347 gamgi_math_position_cell_rotation_set (cell, euler);
3348 gamgi_math_position_cell_translation_set (cell, origin);
3349
3350 return gml->ml.valid;
3351 }
3352
3353 static gamgi_bool static_cluster_end (const char *element, gamgi_gml *gml)
3354 {
3355 gamgi_cluster *cluster;
3356 int fileline;
3357
3358 cluster = GAMGI_CAST_CLUSTER gml->ml.parent->data;
3359 if (cluster->reference == GAMGI_CHEM_POLYTOPE)
3360 {
3361 /******************************************
3362 * used only in error messages: file line *
3363 * indicates where current element starts *
3364 ******************************************/
3365
3366 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
3367
3368 /****************************************
3369 * check arrays built from cdata blocks *
3370 ****************************************/
3371
3372 if (gamgi_math_polygon_check_loops (cluster->loops,
3373 cluster->n_loops, cluster->points, cluster->n_points) == FALSE)
3374 return gamgi_io_error_incompatible (gml->ml.filename,
3375 fileline, gml->ml.window);
3376
3377 if (gamgi_math_polygon_check_colors (cluster->loops,
3378 cluster->n_loops, cluster->colors, cluster->n_colors,
3379 cluster->paints, cluster->n_paints) == FALSE)
3380 return gamgi_io_error_incompatible (gml->ml.filename,
3381 fileline, gml->ml.window);
3382 }
3383
3384 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
3385
3386 return gml->ml.valid;
3387 }
3388
3389 static gamgi_bool static_cluster_start (const char *element,
3390 const char **attributes, gamgi_gml *gml)
3391 {
3392 gamgi_cluster *cluster;
3393 gamgi_cluster_class *cluster_class;
3394 gamgi_object *object;
3395 char token[GAMGI_ENGINE_TOKEN];
3396 double rotation[9];
3397 double euler[3];
3398 int position = 0, center = 0, angle = 0;
3399 int fileline, i;
3400 unsigned int hash;
3401
3402 /******************************************
3403 * used only in error messages: file line *
3404 * indicates where current element starts *
3405 ******************************************/
3406
3407 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
3408
3409 /******************************
3410 * parent list: check, update *
3411 ******************************/
3412
3413 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_CLUSTER, gml) == FALSE)
3414 return gamgi_io_error_child (gml->ml.filename,
3415 fileline, gml->ml.window);
3416
3417 /***************************************************
3418 * cluster_class contains the current config info, *
3419 * which is gamgi->cluster unless new config info *
3420 * has been previously stored in object->object. *
3421 ***************************************************/
3422
3423 object = GAMGI_CAST_OBJECT gamgi->cluster;
3424 if (object->object == NULL) cluster_class = gamgi->cluster;
3425 else cluster_class = (gamgi_cluster_class *) object->object;
3426
3427 /*****************
3428 * object create *
3429 *****************/
3430
3431 cluster = gamgi_engine_create_cluster ();
3432 gamgi_engine_start_cluster (cluster);
3433 gamgi_mesa_start_cluster (cluster, cluster_class);
3434
3435 /*************************************************************
3436 * by default, each new cluster belongs to the current layer *
3437 *************************************************************/
3438
3439 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
3440 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
3441 cluster->object.object = object;
3442
3443 /************************
3444 * object queue: update *
3445 ************************/
3446
3447 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
3448 gml->object_end->data = cluster;
3449
3450 /************************
3451 * parent stack: update *
3452 ************************/
3453
3454 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
3455 gml->ml.parent->data = cluster;
3456
3457 /**********************************
3458 * attribute array: check, update *
3459 **********************************/
3460
3461 for (i = 0; attributes[i] != NULL; i += 2)
3462 {
3463 /*******************
3464 * name (optional) *
3465 *******************/
3466
3467 if (strcmp (attributes[i], "name") == 0)
3468 {
3469 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3470 cluster->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3471 return gamgi_io_error_value (attributes[i + 1],
3472 gml->ml.filename, fileline, gml->ml.window);
3473 }
3474
3475 /*****************
3476 * id (optional) *
3477 *****************/
3478
3479 else if (strcmp (attributes[i], "id") == 0)
3480 {
3481 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3482 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3483 return gamgi_io_error_value (attributes[i + 1],
3484 gml->ml.filename, fileline, gml->ml.window);
3485
3486 hash = gamgi_math_hash_value (token,
3487 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
3488
3489 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
3490 return gamgi_io_error_multiple (gml->ml.filename,
3491 fileline, gml->ml.window);
3492
3493 gamgi_expat_import_id_add (token, gml, hash);
3494 }
3495
3496 /*********************
3497 * parent (optional) *
3498 *********************/
3499
3500 else if (strcmp (attributes[i], "parent") == 0)
3501 {
3502 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3503 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3504 return gamgi_io_error_value (attributes[i + 1],
3505 gml->ml.filename, fileline, gml->ml.window);
3506
3507 gamgi_expat_import_ref_add (token, gml);
3508 }
3509
3510 /************************
3511 * reference (optional) *
3512 ************************/
3513
3514 else if (strcmp (attributes[i], "reference") == 0)
3515 {
3516 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3517 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3518 return gamgi_io_error_value (attributes[i + 1],
3519 gml->ml.filename, fileline, gml->ml.window);
3520
3521 else if (strcmp (token, "container") == 0)
3522 cluster->reference = GAMGI_CHEM_CONTAINER;
3523 else if (strcmp (token, "polytope") == 0)
3524 cluster->reference = GAMGI_CHEM_POLYTOPE;
3525 else return gamgi_io_error_value (attributes[i + 1],
3526 gml->ml.filename, fileline, gml->ml.window);
3527 }
3528
3529 /*************************************
3530 * origin: x,y,z (optional, coupled) *
3531 *************************************/
3532
3533 else if (strcmp (attributes[i], "x") == 0)
3534 {
3535 position++;
3536 if (gamgi_io_token_double_scan (attributes[i + 1],
3537 &cluster->origin[0], -DBL_MAX, DBL_MAX) == FALSE)
3538 return gamgi_io_error_value (attributes[i + 1],
3539 gml->ml.filename, fileline, gml->ml.window);
3540 }
3541
3542 else if (strcmp (attributes[i], "y") == 0)
3543 {
3544 position++;
3545 if (gamgi_io_token_double_scan (attributes[i + 1],
3546 &cluster->origin[1], -DBL_MAX, DBL_MAX) == FALSE)
3547 return gamgi_io_error_value (attributes[i + 1],
3548 gml->ml.filename, fileline, gml->ml.window);
3549 }
3550
3551 else if (strcmp (attributes[i], "z") == 0)
3552 {
3553 position++;
3554 if (gamgi_io_token_double_scan (attributes[i + 1],
3555 &cluster->origin[2], -DBL_MAX, DBL_MAX) == FALSE)
3556 return gamgi_io_error_value (attributes[i + 1],
3557 gml->ml.filename, fileline, gml->ml.window);
3558 }
3559
3560 /*************************************
3561 * center: x,y,z (optional, coupled) *
3562 *************************************/
3563
3564 else if (strcmp (attributes[i], "center_x") == 0)
3565 {
3566 center++;
3567 if (gamgi_io_token_double_scan (attributes[i + 1],
3568 &cluster->center[0], -DBL_MAX, DBL_MAX) == FALSE)
3569 return gamgi_io_error_value (attributes[i + 1],
3570 gml->ml.filename, fileline, gml->ml.window);
3571 }
3572
3573 else if (strcmp (attributes[i], "center_y") == 0)
3574 {
3575 center++;
3576 if (gamgi_io_token_double_scan (attributes[i + 1],
3577 &cluster->center[1], -DBL_MAX, DBL_MAX) == FALSE)
3578 return gamgi_io_error_value (attributes[i + 1],
3579 gml->ml.filename, fileline, gml->ml.window);
3580 }
3581
3582 else if (strcmp (attributes[i], "center_z") == 0)
3583 {
3584 center++;
3585 if (gamgi_io_token_double_scan (attributes[i + 1],
3586 &cluster->center[2], -DBL_MAX, DBL_MAX) == FALSE)
3587 return gamgi_io_error_value (attributes[i + 1],
3588 gml->ml.filename, fileline, gml->ml.window);
3589 }
3590
3591 /**********************************************
3592 * Euler angles: e1,e2,e3 (optional, coupled) *
3593 **********************************************/
3594
3595 else if (strcmp (attributes[i], "e1") == 0)
3596 {
3597 angle++;
3598 if (gamgi_io_token_double_scan (attributes[i + 1],
3599 &euler[0], 0.0, 180.0) == FALSE)
3600 return gamgi_io_error_value (attributes[i + 1],
3601 gml->ml.filename, fileline, gml->ml.window);
3602 }
3603
3604 else if (strcmp (attributes[i], "e2") == 0)
3605 {
3606 angle++;
3607 if (gamgi_io_token_double_scan (attributes[i + 1],
3608 &euler[1], 0.0, 360.0) == FALSE)
3609 return gamgi_io_error_value (attributes[i + 1],
3610 gml->ml.filename, fileline, gml->ml.window);
3611 }
3612
3613 else if (strcmp (attributes[i], "e3") == 0)
3614 {
3615 angle++;
3616 if (gamgi_io_token_double_scan (attributes[i + 1],
3617 &euler[2], 0.0, 360.0) == FALSE)
3618 return gamgi_io_error_value (attributes[i + 1],
3619 gml->ml.filename, fileline, gml->ml.window);
3620 }
3621
3622 /***************************
3623 * atoms, faces (optional) *
3624 ***************************/
3625
3626 else if (strcmp (attributes[i], "atoms") == 0)
3627 {
3628 if (gamgi_io_token_int_scan (attributes[i + 1],
3629 &cluster->atoms, 0, INT_MAX) == FALSE)
3630 return gamgi_io_error_value (attributes[i + 1],
3631 gml->ml.filename, fileline, gml->ml.window);
3632 }
3633
3634 else if (strcmp (attributes[i], "faces") == 0)
3635 {
3636 if (gamgi_io_token_bool_scan (attributes[i + 1], &cluster->faces) == FALSE)
3637 return gamgi_io_error_value (attributes[i + 1],
3638 gml->ml.filename, fileline, gml->ml.window);
3639 }
3640
3641 /********************
3642 * scale (optional) *
3643 ********************/
3644
3645 else if (strcmp (attributes[i], "scale") == 0)
3646 {
3647 if (gamgi_io_token_double_scan (attributes[i + 1],
3648 &cluster->object.scale, GAMGI_MESA_SCALE_LOWER,
3649 GAMGI_MESA_SCALE_UPPER) == FALSE)
3650 return gamgi_io_error_value (attributes[i + 1],
3651 gml->ml.filename, fileline, gml->ml.window);
3652 }
3653
3654 else return gamgi_io_error_attribute (attributes[i],
3655 gml->ml.filename, fileline, gml->ml.window);
3656 }
3657
3658 /************************************
3659 * global tests: missing attributes *
3660 ************************************/
3661
3662 /*****************************************
3663 * global tests: incompatible attributes *
3664 *****************************************/
3665
3666 /*****************************************
3667 * coupled parameters: enter all or none *
3668 *****************************************/
3669
3670 if (position == 1 || position == 2)
3671 return gamgi_io_error_incompatible (gml->ml.filename,
3672 fileline, gml->ml.window);
3673
3674 if (center == 1 || center == 2)
3675 return gamgi_io_error_incompatible (gml->ml.filename,
3676 fileline, gml->ml.window);
3677
3678 if (angle == 1 || angle == 2)
3679 return gamgi_io_error_incompatible (gml->ml.filename,
3680 fileline, gml->ml.window);
3681
3682 /******************************
3683 * global: default attributes *
3684 ******************************/
3685
3686 if (angle == 0)
3687 { euler[0] = 0.0; euler[1] = 0.0; euler[2] = 0.0; }
3688
3689 /*****************************
3690 * set quaternion from euler *
3691 *****************************/
3692
3693 gamgi_math_euler_to_matrix (euler, rotation);
3694 gamgi_math_quaternion_from_matrix (rotation, cluster->quaternion);
3695
3696 return gml->ml.valid;
3697 }
3698
3699 static gamgi_bool static_molecule_end (const char *element, gamgi_gml *gml)
3700 {
3701 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
3702
3703 return gml->ml.valid;
3704 }
3705
3706 static gamgi_bool static_molecule_start (const char *element,
3707 const char **attributes, gamgi_gml *gml)
3708 {
3709 gamgi_molecule *molecule;
3710 gamgi_molecule_class *molecule_class;
3711 gamgi_object *object;
3712 char token[GAMGI_ENGINE_TOKEN];
3713 int fileline, i;
3714 unsigned int hash;
3715
3716 /******************************************
3717 * used only in error messages: file line *
3718 * indicates where current element starts *
3719 ******************************************/
3720
3721 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
3722
3723 /******************************
3724 * parent list: check, update *
3725 ******************************/
3726
3727 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_MOLECULE, gml) == FALSE)
3728 return gamgi_io_error_child (gml->ml.filename,
3729 fileline, gml->ml.window);
3730
3731 /****************************************************
3732 * molecule_class contains the current config info, *
3733 * which is gamgi->molecule unless new config info *
3734 * has been previously stored in object->object. *
3735 ****************************************************/
3736
3737 object = GAMGI_CAST_OBJECT gamgi->molecule;
3738 if (object->object == NULL) molecule_class = gamgi->molecule;
3739 else molecule_class = (gamgi_molecule_class *) object->object;
3740
3741 /*****************
3742 * object create *
3743 *****************/
3744
3745 molecule = gamgi_engine_create_molecule ();
3746 gamgi_engine_start_molecule (molecule);
3747 gamgi_mesa_start_molecule (molecule, molecule_class);
3748
3749 /**************************************************************
3750 * by default, each new molecule belongs to the current layer *
3751 **************************************************************/
3752
3753 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
3754 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
3755 molecule->object.object = object;
3756
3757 /************************
3758 * object queue: update *
3759 ************************/
3760
3761 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
3762 gml->object_end->data = molecule;
3763
3764 /************************
3765 * parent stack: update *
3766 ************************/
3767
3768 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
3769 gml->ml.parent->data = molecule;
3770
3771 /**********************************
3772 * attribute array: check, update *
3773 **********************************/
3774
3775 for (i = 0; attributes[i] != NULL; i += 2)
3776 {
3777 /*******************
3778 * name (optional) *
3779 *******************/
3780
3781 if (strcmp (attributes[i], "name") == 0)
3782 {
3783 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3784 molecule->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3785 return gamgi_io_error_value (attributes[i + 1],
3786 gml->ml.filename, fileline, gml->ml.window);
3787 }
3788
3789 /*****************
3790 * id (optional) *
3791 *****************/
3792
3793 else if (strcmp (attributes[i], "id") == 0)
3794 {
3795 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3796 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3797 return gamgi_io_error_value (attributes[i + 1],
3798 gml->ml.filename, fileline, gml->ml.window);
3799
3800 hash = gamgi_math_hash_value (token,
3801 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
3802
3803 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
3804 return gamgi_io_error_multiple (gml->ml.filename,
3805 fileline, gml->ml.window);
3806
3807 gamgi_expat_import_id_add (token, gml, hash);
3808 }
3809
3810 /*********************
3811 * parent (optional) *
3812 *********************/
3813
3814 else if (strcmp (attributes[i], "parent") == 0)
3815 {
3816 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3817 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3818 return gamgi_io_error_value (attributes[i + 1],
3819 gml->ml.filename, fileline, gml->ml.window);
3820
3821 gamgi_expat_import_ref_add (token, gml);
3822 }
3823
3824 /********************
3825 * scale (optional) *
3826 ********************/
3827
3828 else if (strcmp (attributes[i], "scale") == 0)
3829 {
3830 if (gamgi_io_token_double_scan (attributes[i + 1],
3831 &molecule->object.scale, GAMGI_MESA_SCALE_LOWER,
3832 GAMGI_MESA_SCALE_UPPER) == FALSE)
3833 return gamgi_io_error_value (attributes[i + 1],
3834 gml->ml.filename, fileline, gml->ml.window);
3835 }
3836
3837 else return gamgi_io_error_attribute (attributes[i],
3838 gml->ml.filename, fileline, gml->ml.window);
3839 }
3840
3841 /************************************
3842 * global tests: missing attributes *
3843 ************************************/
3844
3845 /*****************************************
3846 * global tests: incompatible attributes *
3847 *****************************************/
3848
3849 return gml->ml.valid;
3850 }
3851
3852 static gamgi_bool static_group_end (const char *element, gamgi_gml *gml)
3853 {
3854 gamgi_group *group;
3855 int fileline;
3856
3857 group = GAMGI_CAST_GROUP gml->ml.parent->data;
3858 if (group->reference == GAMGI_CHEM_POLYTOPE)
3859 {
3860 /******************************************
3861 * used only in error messages: file line *
3862 * indicates where current element starts *
3863 ******************************************/
3864
3865 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
3866
3867 /****************************************
3868 * check arrays built from cdata blocks *
3869 ****************************************/
3870
3871 if (gamgi_math_polygon_check_loops (group->loops,
3872 group->n_loops, group->points, group->n_points) == FALSE)
3873 return gamgi_io_error_incompatible (gml->ml.filename,
3874 fileline, gml->ml.window);
3875 }
3876
3877 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
3878
3879 return gml->ml.valid;
3880 }
3881
3882 static gamgi_bool static_group_start (const char *element,
3883 const char **attributes, gamgi_gml *gml)
3884 {
3885 gamgi_group *group;
3886 gamgi_group_class *group_class;
3887 gamgi_object *object;
3888 char token[GAMGI_ENGINE_TOKEN];
3889 double rotation[9];
3890 double euler[3];
3891 int position = 0, center = 0, angle = 0, color = 0;
3892 int fileline, i;
3893 unsigned int hash;
3894
3895 /******************************************
3896 * used only in error messages: file line *
3897 * indicates where current element starts *
3898 ******************************************/
3899
3900 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
3901
3902 /******************************
3903 * parent list: check, update *
3904 ******************************/
3905
3906 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_GROUP, gml) == FALSE)
3907 return gamgi_io_error_child (gml->ml.filename,
3908 fileline, gml->ml.window);
3909
3910 /*************************************************
3911 * group_class contains the current config info, *
3912 * which is gamgi->group unless new config info *
3913 * has been previously stored in object->object. *
3914 *************************************************/
3915
3916 object = GAMGI_CAST_OBJECT gamgi->group;
3917 if (object->object == NULL) group_class = gamgi->group;
3918 else group_class = (gamgi_group_class *) object->object;
3919
3920 /*****************
3921 * object create *
3922 *****************/
3923
3924 group = gamgi_engine_create_group ();
3925 gamgi_engine_start_group (group);
3926 gamgi_mesa_start_group (group, group_class);
3927
3928 /***********************************************************
3929 * by default, each new group belongs to the current layer *
3930 ***********************************************************/
3931
3932 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
3933 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
3934 group->object.object = object;
3935
3936 /************************
3937 * object queue: update *
3938 ************************/
3939
3940 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
3941 gml->object_end->data = group;
3942
3943 /************************
3944 * parent stack: update *
3945 ************************/
3946
3947 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
3948 gml->ml.parent->data = group;
3949
3950 /**********************************
3951 * attribute array: check, update *
3952 **********************************/
3953
3954 for (i = 0; attributes[i] != NULL; i += 2)
3955 {
3956 /*******************
3957 * name (optional) *
3958 *******************/
3959
3960 if (strcmp (attributes[i], "name") == 0)
3961 {
3962 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3963 group->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3964 return gamgi_io_error_value (attributes[i + 1],
3965 gml->ml.filename, fileline, gml->ml.window);
3966 }
3967
3968 /*****************
3969 * id (optional) *
3970 *****************/
3971
3972 else if (strcmp (attributes[i], "id") == 0)
3973 {
3974 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3975 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3976 return gamgi_io_error_value (attributes[i + 1],
3977 gml->ml.filename, fileline, gml->ml.window);
3978
3979 hash = gamgi_math_hash_value (token,
3980 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
3981
3982 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
3983 return gamgi_io_error_multiple (gml->ml.filename,
3984 fileline, gml->ml.window);
3985
3986 gamgi_expat_import_id_add (token, gml, hash);
3987 }
3988
3989 /*********************
3990 * parent (optional) *
3991 *********************/
3992
3993 else if (strcmp (attributes[i], "parent") == 0)
3994 {
3995 if (gamgi_io_token_alpha_scan (attributes[i + 1],
3996 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
3997 return gamgi_io_error_value (attributes[i + 1],
3998 gml->ml.filename, fileline, gml->ml.window);
3999
4000 gamgi_expat_import_ref_add (token, gml);
4001 }
4002
4003 /************************
4004 * reference (optional) *
4005 ************************/
4006
4007 else if (strcmp (attributes[i], "reference") == 0)
4008 {
4009 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4010 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4011 return gamgi_io_error_value (attributes[i + 1],
4012 gml->ml.filename, fileline, gml->ml.window);
4013
4014 else if (strcmp (token, "container") == 0)
4015 group->reference = GAMGI_CHEM_CONTAINER;
4016 else if (strcmp (token, "polytope") == 0)
4017 group->reference = GAMGI_CHEM_POLYTOPE;
4018 else return gamgi_io_error_value (attributes[i + 1],
4019 gml->ml.filename, fileline, gml->ml.window);
4020 }
4021
4022 /*************************************
4023 * origin: x,y,z (optional, coupled) *
4024 *************************************/
4025
4026 else if (strcmp (attributes[i], "x") == 0)
4027 {
4028 position++;
4029 if (gamgi_io_token_double_scan (attributes[i + 1],
4030 &group->origin[0], -DBL_MAX, DBL_MAX) == FALSE)
4031 return gamgi_io_error_value (attributes[i + 1],
4032 gml->ml.filename, fileline, gml->ml.window);
4033 }
4034
4035 else if (strcmp (attributes[i], "y") == 0)
4036 {
4037 position++;
4038 if (gamgi_io_token_double_scan (attributes[i + 1],
4039 &group->origin[1], -DBL_MAX, DBL_MAX) == FALSE)
4040 return gamgi_io_error_value (attributes[i + 1],
4041 gml->ml.filename, fileline, gml->ml.window);
4042 }
4043
4044 else if (strcmp (attributes[i], "z") == 0)
4045 {
4046 position++;
4047 if (gamgi_io_token_double_scan (attributes[i + 1],
4048 &group->origin[2], -DBL_MAX, DBL_MAX) == FALSE)
4049 return gamgi_io_error_value (attributes[i + 1],
4050 gml->ml.filename, fileline, gml->ml.window);
4051 }
4052
4053 /*************************************
4054 * center: x,y,z (optional, coupled) *
4055 *************************************/
4056
4057 else if (strcmp (attributes[i], "center_x") == 0)
4058 {
4059 center++;
4060 if (gamgi_io_token_double_scan (attributes[i + 1],
4061 &group->center[0], -DBL_MAX, DBL_MAX) == FALSE)
4062 return gamgi_io_error_value (attributes[i + 1],
4063 gml->ml.filename, fileline, gml->ml.window);
4064 }
4065
4066 else if (strcmp (attributes[i], "center_y") == 0)
4067 {
4068 center++;
4069 if (gamgi_io_token_double_scan (attributes[i + 1],
4070 &group->center[1], -DBL_MAX, DBL_MAX) == FALSE)
4071 return gamgi_io_error_value (attributes[i + 1],
4072 gml->ml.filename, fileline, gml->ml.window);
4073 }
4074
4075 else if (strcmp (attributes[i], "center_z") == 0)
4076 {
4077 center++;
4078 if (gamgi_io_token_double_scan (attributes[i + 1],
4079 &group->center[2], -DBL_MAX, DBL_MAX) == FALSE)
4080 return gamgi_io_error_value (attributes[i + 1],
4081 gml->ml.filename, fileline, gml->ml.window);
4082 }
4083
4084 /**********************************************
4085 * Euler angles: e1,e2,e3 (optional, coupled) *
4086 **********************************************/
4087
4088 else if (strcmp (attributes[i], "e1") == 0)
4089 {
4090 angle++;
4091 if (gamgi_io_token_double_scan (attributes[i + 1],
4092 &euler[0], 0.0, 180.0) == FALSE)
4093 return gamgi_io_error_value (attributes[i + 1],
4094 gml->ml.filename, fileline, gml->ml.window);
4095 }
4096
4097 else if (strcmp (attributes[i], "e2") == 0)
4098 {
4099 angle++;
4100 if (gamgi_io_token_double_scan (attributes[i + 1],
4101 &euler[1], 0.0, 360.0) == FALSE)
4102 return gamgi_io_error_value (attributes[i + 1],
4103 gml->ml.filename, fileline, gml->ml.window);
4104 }
4105
4106 else if (strcmp (attributes[i], "e3") == 0)
4107 {
4108 angle++;
4109 if (gamgi_io_token_double_scan (attributes[i + 1],
4110 &euler[2], 0.0, 360.0) == FALSE)
4111 return gamgi_io_error_value (attributes[i + 1],
4112 gml->ml.filename, fileline, gml->ml.window);
4113 }
4114
4115 /********************
4116 * style (optional) *
4117 ********************/
4118
4119 else if (strcmp (attributes[i], "faces") == 0)
4120 {
4121 if (gamgi_io_token_bool_scan (attributes[i + 1], &group->faces) == FALSE)
4122 return gamgi_io_error_value (attributes[i + 1],
4123 gml->ml.filename, fileline, gml->ml.window);
4124 }
4125
4126 /*****************************
4127 * red,green,blue (optional) *
4128 *****************************/
4129
4130 else if (strcmp (attributes[i], "red") == 0)
4131 {
4132 color++;
4133 if (gamgi_io_token_float_scan (attributes[i + 1],
4134 &group->red, 0.0, 1.0) == FALSE)
4135 return gamgi_io_error_value (attributes[i + 1],
4136 gml->ml.filename, fileline, gml->ml.window);
4137 }
4138
4139 else if (strcmp (attributes[i], "green") == 0)
4140 {
4141 color++;
4142 if (gamgi_io_token_float_scan (attributes[i + 1],
4143 &group->green, 0.0, 1.0) == FALSE)
4144 return gamgi_io_error_value (attributes[i + 1],
4145 gml->ml.filename, fileline, gml->ml.window);
4146 }
4147
4148 else if (strcmp (attributes[i], "blue") == 0)
4149 {
4150 color++;
4151 if (gamgi_io_token_float_scan (attributes[i + 1],
4152 &group->blue, 0.0, 1.0) == FALSE)
4153 return gamgi_io_error_value (attributes[i + 1],
4154 gml->ml.filename, fileline, gml->ml.window);
4155 }
4156
4157 /********************
4158 * scale (optional) *
4159 ********************/
4160
4161 else if (strcmp (attributes[i], "scale") == 0)
4162 {
4163 if (gamgi_io_token_double_scan (attributes[i + 1],
4164 &group->object.scale, GAMGI_MESA_SCALE_LOWER,
4165 GAMGI_MESA_SCALE_UPPER) == FALSE)
4166 return gamgi_io_error_value (attributes[i + 1],
4167 gml->ml.filename, fileline, gml->ml.window);
4168 }
4169
4170 else return gamgi_io_error_attribute (attributes[i],
4171 gml->ml.filename, fileline, gml->ml.window);
4172 }
4173
4174 /************************************
4175 * global tests: missing attributes *
4176 ************************************/
4177
4178 /*****************************************
4179 * global tests: incompatible attributes *
4180 *****************************************/
4181
4182 /*****************************************
4183 * coupled parameters: enter all or none *
4184 *****************************************/
4185
4186 if (position == 1 || position == 2)
4187 return gamgi_io_error_incompatible (gml->ml.filename,
4188 fileline, gml->ml.window);
4189
4190 if (center == 1 || center == 2)
4191 return gamgi_io_error_incompatible (gml->ml.filename,
4192 fileline, gml->ml.window);
4193
4194 if (angle == 1 || angle == 2)
4195 return gamgi_io_error_incompatible (gml->ml.filename,
4196 fileline, gml->ml.window);
4197
4198 if (color == 1 || color == 2)
4199 return gamgi_io_error_incompatible (gml->ml.filename,
4200 fileline, gml->ml.window);
4201
4202 /******************************
4203 * global: default attributes *
4204 ******************************/
4205
4206 if (angle == 0)
4207 { euler[0] = 0.0; euler[1] = 0.0; euler[2] = 0.0; }
4208
4209 /*****************************
4210 * set quaternion from euler *
4211 *****************************/
4212
4213 gamgi_math_euler_to_matrix (euler, rotation);
4214 gamgi_math_quaternion_from_matrix (rotation, group->quaternion);
4215
4216 return gml->ml.valid;
4217 }
4218
4219 static gamgi_bool static_plane_end (const char *element, gamgi_gml *gml)
4220 {
4221 gamgi_plane *plane;
4222 int fileline;
4223
4224 plane = GAMGI_CAST_PLANE gml->ml.parent->data;
4225 if (plane->model == GAMGI_PHYS_POLYGON)
4226 {
4227 /******************************************
4228 * used only in error messages: file line *
4229 * indicates where current element starts *
4230 ******************************************/
4231
4232 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
4233
4234 /****************************************
4235 * check arrays built from cdata blocks *
4236 ****************************************/
4237
4238 if (plane->loops == NULL || plane->loops[0] > 1)
4239 return gamgi_io_error_incompatible (gml->ml.filename,
4240 fileline, gml->ml.window);
4241
4242 if (gamgi_math_polygon_check_loops (plane->loops,
4243 plane->n_loops, plane->points, plane->n_points) == FALSE)
4244 return gamgi_io_error_incompatible (gml->ml.filename,
4245 fileline, gml->ml.window);
4246 }
4247
4248 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
4249
4250 return gml->ml.valid;
4251 }
4252
4253 static gamgi_bool static_plane_start (const char *element,
4254 const char **attributes, gamgi_gml *gml)
4255 {
4256 gamgi_plane *plane;
4257 gamgi_plane_class *plane_class;
4258 gamgi_object *object;
4259 char token[GAMGI_ENGINE_TOKEN];
4260 double rotation[9], euler[3];
4261 int fileline, i;
4262 int parent = 0;
4263 int hkl = 0, color = 0, order = 0;
4264 int vectors = 0, net = 0;
4265 int position = 0, center = 0, angle = 0;
4266 unsigned int hash;
4267
4268 /******************************************
4269 * used only in error messages: file line *
4270 * indicates where current element starts *
4271 ******************************************/
4272
4273 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
4274
4275 /******************************
4276 * parent list: check, update *
4277 ******************************/
4278
4279 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_PLANE, gml) == FALSE)
4280 return gamgi_io_error_child (gml->ml.filename,
4281 fileline, gml->ml.window);
4282
4283 /*************************************************
4284 * plane_class contains the current config info, *
4285 * which is gamgi->plane unless new config info *
4286 * has been previously stored in object->object. *
4287 *************************************************/
4288
4289 object = GAMGI_CAST_OBJECT gamgi->plane;
4290 if (object->object == NULL) plane_class = gamgi->plane;
4291 else plane_class = (gamgi_plane_class *) object->object;
4292
4293 /*****************
4294 * object create *
4295 *****************/
4296
4297 plane = gamgi_engine_create_plane ();
4298 gamgi_engine_start_plane (plane);
4299 gamgi_mesa_start_plane (plane, plane_class);
4300
4301 /***********************************************************
4302 * by default, each new plane belongs to the current layer *
4303 ***********************************************************/
4304
4305 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
4306 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
4307 plane->object.object = object;
4308
4309 /************************
4310 * object queue: update *
4311 ************************/
4312
4313 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
4314 gml->object_end->data = plane;
4315
4316 /************************
4317 * parent stack: update *
4318 ************************/
4319
4320 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
4321 gml->ml.parent->data = plane;
4322
4323 /**********************************
4324 * attribute array: check, update *
4325 **********************************/
4326
4327 for (i = 0; attributes[i] != NULL; i += 2)
4328 {
4329 /*******************
4330 * name (optional) *
4331 *******************/
4332
4333 if (strcmp (attributes[i], "name") == 0)
4334 {
4335 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4336 plane->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4337 return gamgi_io_error_value (attributes[i + 1],
4338 gml->ml.filename, fileline, gml->ml.window);
4339 }
4340
4341 /*****************
4342 * id (optional) *
4343 *****************/
4344
4345 else if (strcmp (attributes[i], "id") == 0)
4346 {
4347 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4348 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4349 return gamgi_io_error_value (attributes[i + 1],
4350 gml->ml.filename, fileline, gml->ml.window);
4351
4352 hash = gamgi_math_hash_value (token,
4353 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
4354
4355 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
4356 return gamgi_io_error_multiple (gml->ml.filename,
4357 fileline, gml->ml.window);
4358
4359 gamgi_expat_import_id_add (token, gml, hash);
4360 }
4361
4362 /*********************
4363 * parent (optional) *
4364 *********************/
4365
4366 else if (strcmp (attributes[i], "parent") == 0)
4367 {
4368 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4369 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4370 return gamgi_io_error_value (attributes[i + 1],
4371 gml->ml.filename, fileline, gml->ml.window);
4372
4373 gamgi_expat_import_ref_add (token, gml);
4374 }
4375
4376 /************************
4377 * reference (optional) *
4378 ***********************/
4379
4380 else if (strcmp (attributes[i], "reference") == 0)
4381 {
4382 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4383 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4384 return gamgi_io_error_value (attributes[i + 1],
4385 gml->ml.filename, fileline, gml->ml.window);
4386
4387 if (strcmp (token, "cell") == 0)
4388 plane->reference = GAMGI_ENGINE_CELL;
4389 else if (strcmp (token, "atoms") == 0)
4390 plane->reference = GAMGI_ENGINE_ATOM;
4391
4392 else return gamgi_io_error_value (attributes[i + 1],
4393 gml->ml.filename, fileline, gml->ml.window);
4394 }
4395
4396 /**********************************************
4397 * hkl (required for crystallographic planes) *
4398 **********************************************/
4399
4400 else if (strcmp (attributes[i], "h") == 0)
4401 {
4402 hkl++;
4403 if (gamgi_io_token_int_scan (attributes[i + 1],
4404 &plane->hkl[0], -INT_MAX, INT_MAX) == FALSE)
4405 return gamgi_io_error_value (attributes[i + 1],
4406 gml->ml.filename, fileline, gml->ml.window);
4407 }
4408
4409 else if (strcmp (attributes[i], "k") == 0)
4410 {
4411 hkl++;
4412 if (gamgi_io_token_int_scan (attributes[i + 1],
4413 &plane->hkl[1], -INT_MAX, INT_MAX) == FALSE)
4414 return gamgi_io_error_value (attributes[i + 1],
4415 gml->ml.filename, fileline, gml->ml.window);
4416 }
4417
4418 else if (strcmp (attributes[i], "l") == 0)
4419 {
4420 hkl++;
4421 if (gamgi_io_token_int_scan (attributes[i + 1],
4422 &plane->hkl[2], -INT_MAX, INT_MAX) == FALSE)
4423 return gamgi_io_error_value (attributes[i + 1],
4424 gml->ml.filename, fileline, gml->ml.window);
4425 }
4426
4427 /**********************
4428 * vectors (optional) *
4429 **********************/
4430
4431 else if (strcmp (attributes[i], "vectors") == 0)
4432 {
4433 vectors++;
4434 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4435 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4436 return gamgi_io_error_value (attributes[i + 1],
4437 gml->ml.filename, fileline, gml->ml.window);
4438
4439 if (strcmp (token, "conventional") == 0)
4440 plane->vectors = GAMGI_PHYS_CONVENTIONAL;
4441 else if (strcmp (token, "primitive") == 0)
4442 plane->vectors = GAMGI_PHYS_PRIMITIVE;
4443
4444 else return gamgi_io_error_value (attributes[i + 1],
4445 gml->ml.filename, fileline, gml->ml.window);
4446 }
4447
4448 /********************
4449 * model (optional) *
4450 ********************/
4451
4452 else if (strcmp (attributes[i], "model") == 0)
4453 {
4454 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
4455 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4456 return gamgi_io_error_value (attributes[i + 1],
4457 gml->ml.filename, fileline, gml->ml.window);
4458
4459 if (strcmp (token, "polygon") == 0)
4460 plane->model = GAMGI_PHYS_POLYGON;
4461 else if (strcmp (token, "trace") == 0)
4462 plane->model = GAMGI_PHYS_TRACE;
4463 else if (strcmp (token, "pole") == 0)
4464 plane->model = GAMGI_PHYS_POLE;
4465 else if (strcmp (token, "vector") == 0)
4466 plane->model = GAMGI_PHYS_VECTOR;
4467
4468 else return gamgi_io_error_value (attributes[i + 1],
4469 gml->ml.filename, fileline, gml->ml.window);
4470 }
4471
4472 /*****************************
4473 * projection net (optional) *
4474 *****************************/
4475
4476 else if (strcmp (attributes[i], "net") == 0)
4477 {
4478 net++;
4479 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4480 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4481 return gamgi_io_error_value (attributes[i + 1],
4482 gml->ml.filename, fileline, gml->ml.window);
4483
4484 if (strcmp (token, "wulff") == 0)
4485 plane->net = gamgi_phys_projection_wulff;
4486 else if (strcmp (token, "schmidt") == 0)
4487 plane->net = gamgi_phys_projection_schmidt;
4488
4489 else return gamgi_io_error_value (attributes[i + 1],
4490 gml->ml.filename, fileline, gml->ml.window);
4491 }
4492
4493 /********************
4494 * order (optional) *
4495 ********************/
4496
4497 else if (strcmp (attributes[i], "order") == 0)
4498 {
4499 order++;
4500 if (gamgi_io_token_int_scan (attributes[i + 1],
4501 &plane->order, -INT_MAX, INT_MAX) == FALSE)
4502 return gamgi_io_error_value (attributes[i + 1],
4503 gml->ml.filename, fileline, gml->ml.window);
4504 }
4505
4506 /*************************************
4507 * origin: x,y,z (optional, coupled) *
4508 *************************************/
4509
4510 else if (strcmp (attributes[i], "x") == 0)
4511 {
4512 position++;
4513 if (gamgi_io_token_double_scan (attributes[i + 1],
4514 &plane->origin[0], -DBL_MAX, DBL_MAX) == FALSE)
4515 return gamgi_io_error_value (attributes[i + 1],
4516 gml->ml.filename, fileline, gml->ml.window);
4517 }
4518
4519 else if (strcmp (attributes[i], "y") == 0)
4520 {
4521 position++;
4522 if (gamgi_io_token_double_scan (attributes[i + 1],
4523 &plane->origin[1], -DBL_MAX, DBL_MAX) == FALSE)
4524 return gamgi_io_error_value (attributes[i + 1],
4525 gml->ml.filename, fileline, gml->ml.window);
4526 }
4527
4528 else if (strcmp (attributes[i], "z") == 0)
4529 {
4530 position++;
4531 if (gamgi_io_token_double_scan (attributes[i + 1],
4532 &plane->origin[2], -DBL_MAX, DBL_MAX) == FALSE)
4533 return gamgi_io_error_value (attributes[i + 1],
4534 gml->ml.filename, fileline, gml->ml.window);
4535 }
4536
4537 /*************************************
4538 * center: x,y,z (optional, coupled) *
4539 *************************************/
4540
4541 else if (strcmp (attributes[i], "center_x") == 0)
4542 {
4543 center++;
4544 if (gamgi_io_token_double_scan (attributes[i + 1],
4545 &plane->center[0], -DBL_MAX, DBL_MAX) == FALSE)
4546 return gamgi_io_error_value (attributes[i + 1],
4547 gml->ml.filename, fileline, gml->ml.window);
4548 }
4549
4550 else if (strcmp (attributes[i], "center_y") == 0)
4551 {
4552 center++;
4553 if (gamgi_io_token_double_scan (attributes[i + 1],
4554 &plane->center[1], -DBL_MAX, DBL_MAX) == FALSE)
4555 return gamgi_io_error_value (attributes[i + 1],
4556 gml->ml.filename, fileline, gml->ml.window);
4557 }
4558
4559 else if (strcmp (attributes[i], "center_z") == 0)
4560 {
4561 center++;
4562 if (gamgi_io_token_double_scan (attributes[i + 1],
4563 &plane->center[2], -DBL_MAX, DBL_MAX) == FALSE)
4564 return gamgi_io_error_value (attributes[i + 1],
4565 gml->ml.filename, fileline, gml->ml.window);
4566 }
4567
4568 /**********************************************
4569 * Euler angles: e1,e2,e3 (optional, coupled) *
4570 **********************************************/
4571
4572 else if (strcmp (attributes[i], "e1") == 0)
4573 {
4574 angle++;
4575 if (gamgi_io_token_double_scan (attributes[i + 1],
4576 &euler[0], 0.0, 180.0) == FALSE)
4577 return gamgi_io_error_value (attributes[i + 1],
4578 gml->ml.filename, fileline, gml->ml.window);
4579 }
4580
4581 else if (strcmp (attributes[i], "e2") == 0)
4582 {
4583 angle++;
4584 if (gamgi_io_token_double_scan (attributes[i + 1],
4585 &euler[1], 0.0, 360.0) == FALSE)
4586 return gamgi_io_error_value (attributes[i + 1],
4587 gml->ml.filename, fileline, gml->ml.window);
4588 }
4589
4590 else if (strcmp (attributes[i], "e3") == 0)
4591 {
4592 angle++;
4593 if (gamgi_io_token_double_scan (attributes[i + 1],
4594 &euler[2], 0.0, 360.0) == FALSE)
4595 return gamgi_io_error_value (attributes[i + 1],
4596 gml->ml.filename, fileline, gml->ml.window);
4597 }
4598
4599 /*****************************
4600 * red,green,blue (optional) *
4601 *****************************/
4602
4603 else if (strcmp (attributes[i], "red") == 0)
4604 {
4605 color++;
4606 if (gamgi_io_token_float_scan (attributes[i + 1],
4607 &plane->red, 0.0, 1.0) == FALSE)
4608 return gamgi_io_error_value (attributes[i + 1],
4609 gml->ml.filename, fileline, gml->ml.window);
4610 }
4611
4612 else if (strcmp (attributes[i], "green") == 0)
4613 {
4614 color++;
4615 if (gamgi_io_token_float_scan (attributes[i + 1],
4616 &plane->green, 0.0, 1.0) == FALSE)
4617 return gamgi_io_error_value (attributes[i + 1],
4618 gml->ml.filename, fileline, gml->ml.window);
4619 }
4620
4621 else if (strcmp (attributes[i], "blue") == 0)
4622 {
4623 color++;
4624 if (gamgi_io_token_float_scan (attributes[i + 1],
4625 &plane->blue, 0.0, 1.0) == FALSE)
4626 return gamgi_io_error_value (attributes[i + 1],
4627 gml->ml.filename, fileline, gml->ml.window);
4628 }
4629
4630 /********************
4631 * scale (optional) *
4632 ********************/
4633
4634 else if (strcmp (attributes[i], "scale") == 0)
4635 {
4636 if (gamgi_io_token_double_scan (attributes[i + 1],
4637 &plane->object.scale, GAMGI_MESA_SCALE_LOWER,
4638 GAMGI_MESA_SCALE_UPPER) == FALSE)
4639 return gamgi_io_error_value (attributes[i + 1],
4640 gml->ml.filename, fileline, gml->ml.window);
4641 }
4642
4643 else return gamgi_io_error_attribute (attributes[i],
4644 gml->ml.filename, fileline, gml->ml.window);
4645 }
4646
4647 /************************************
4648 * global tests: missing attributes *
4649 ************************************/
4650
4651 /*****************************************
4652 * global tests: incompatible attributes *
4653 *****************************************/
4654
4655 if (plane->reference == GAMGI_ENGINE_CELL)
4656 {
4657 if (hkl != 3)
4658 return gamgi_io_error_incompatible (gml->ml.filename,
4659 fileline, gml->ml.window);
4660
4661 if (gamgi_phys_direction_zero (plane->hkl) == TRUE)
4662 return gamgi_io_error_incompatible (gml->ml.filename,
4663 fileline, gml->ml.window);
4664 }
4665
4666 if (plane->reference == GAMGI_ENGINE_ATOM)
4667 {
4668 if (hkl != 0 || vectors != 0 || net != 0 || order != 0)
4669 return gamgi_io_error_incompatible (gml->ml.filename,
4670 fileline, gml->ml.window);
4671
4672 if (plane->model == GAMGI_PHYS_POLE || plane->model == GAMGI_PHYS_TRACE
4673 || plane->model == GAMGI_PHYS_VECTOR)
4674 return gamgi_io_error_incompatible (gml->ml.filename,
4675 fileline, gml->ml.window);
4676
4677 if (plane->net != NULL)
4678 return gamgi_io_error_incompatible (gml->ml.filename,
4679 fileline, gml->ml.window);
4680
4681 if (plane->model == FALSE) plane->model = GAMGI_PHYS_POLYGON;
4682 }
4683
4684 if (parent == 0 && gamgi_expat_import_plane (plane,
4685 object, gml->ml.filename, fileline, gml) == FALSE) return FALSE;
4686
4687 /*****************************
4688 * check position parameters *
4689 *****************************/
4690
4691 if (position == 1 || position == 2)
4692 return gamgi_io_error_incompatible (gml->ml.filename,
4693 fileline, gml->ml.window);
4694
4695 if (center == 1 || center == 2)
4696 return gamgi_io_error_incompatible (gml->ml.filename,
4697 fileline, gml->ml.window);
4698
4699 if (angle == 1 || angle == 2)
4700 return gamgi_io_error_incompatible (gml->ml.filename,
4701 fileline, gml->ml.window);
4702
4703 /********************************************************
4704 * by default origin is 0,0,0 and quaternion is 0,0,0,1 *
4705 * so it is not needed to initialize both before using *
4706 * them to temporarily store the origin and euler data. *
4707 ********************************************************/
4708
4709 /******************************
4710 * global: default attributes *
4711 ******************************/
4712
4713 if (strcmp (plane->object.name, "") == 0)
4714 {
4715 if (plane->reference == GAMGI_ENGINE_CELL)
4716 sprintf (token, "(%d.%d.%d)", plane->hkl[0], plane->hkl[1], plane->hkl[2]);
4717 else
4718 sprintf (token, "Plane");
4719
4720 strcpy (plane->object.name, token);
4721 }
4722
4723 /************************************************
4724 * the plane (vector, pole, trace, polygon) can *
4725 * be built only when the cell parent is known *
4726 ************************************************/
4727
4728 /*********************************************************************
4729 * rotation/translation data is now set (origin, center, quaternion) *
4730 *********************************************************************/
4731
4732 gamgi_math_euler_to_matrix (euler, rotation);
4733 gamgi_math_quaternion_from_matrix (rotation, plane->quaternion);
4734
4735 return gml->ml.valid;
4736 }
4737
4738 static gamgi_bool static_direction_end (const char *element, gamgi_gml *gml)
4739 {
4740 gml->ml.parent = gamgi_engine_slist_remove_start (gml->ml.parent);
4741
4742 return gml->ml.valid;
4743 }
4744
4745 static gamgi_bool static_direction_start (const char *element,
4746 const char **attributes, gamgi_gml *gml)
4747 {
4748 gamgi_direction *direction;
4749 gamgi_direction_class *direction_class;
4750 gamgi_object *object;
4751 double rotation[9], euler[3];
4752 double points[6];
4753 char token[GAMGI_ENGINE_TOKEN];
4754 int fileline, i;
4755 int parent = 0;
4756 int xyz = 0;
4757 int uvw = 0, color = 0;
4758 int vectors = 0, net = 0;
4759 int o123 = 0, o4 = 0;
4760 int position = 0, center = 0, angle = 0;
4761 unsigned int hash;
4762
4763 /******************************************
4764 * used only in error messages: file line *
4765 * indicates where current element starts *
4766 ******************************************/
4767
4768 fileline = XML_GetCurrentLineNumber (gml->ml.parser);
4769
4770 /******************************
4771 * parent list: check, update *
4772 ******************************/
4773
4774 if (gamgi_expat_import_parent_gml (GAMGI_ENGINE_DIRECTION, gml) == FALSE)
4775 return gamgi_io_error_child (gml->ml.filename,
4776 fileline, gml->ml.window);
4777
4778 /*****************************************************
4779 * direction_class contains the current config info, *
4780 * which is gamgi->direction unless new config info *
4781 * has been previously stored in object->object. *
4782 *****************************************************/
4783
4784 object = GAMGI_CAST_OBJECT gamgi->direction;
4785 if (object->object == NULL) direction_class = gamgi->direction;
4786 else direction_class = (gamgi_direction_class *) object->object;
4787
4788 /*****************
4789 * object create *
4790 *****************/
4791
4792 direction = gamgi_engine_create_direction ();
4793 gamgi_engine_start_direction (direction);
4794 gamgi_mesa_start_direction (direction, direction_class);
4795
4796 /***************************************************************
4797 * by default, each new direction belongs to the current layer *
4798 ***************************************************************/
4799
4800 object = GAMGI_CAST_OBJECT gml->ml.parent->data;
4801 if (object == NULL) object = GAMGI_CAST_OBJECT gml->ml.window->layer;
4802 direction->object.object = object;
4803
4804 /************************
4805 * object queue: update *
4806 ************************/
4807
4808 gml->object_end = gamgi_engine_dlist_add_end (gml->object_end);
4809 gml->object_end->data = direction;
4810
4811 /************************
4812 * parent stack: update *
4813 ************************/
4814
4815 gml->ml.parent = gamgi_engine_slist_add_start (gml->ml.parent);
4816 gml->ml.parent->data = direction;
4817
4818 /**********************************
4819 * attribute array: check, update *
4820 **********************************/
4821
4822 for (i = 0; attributes[i] != NULL; i += 2)
4823 {
4824 /*******************
4825 * name (optional) *
4826 *******************/
4827
4828 if (strcmp (attributes[i], "name") == 0)
4829 {
4830 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4831 direction->object.name, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4832 return gamgi_io_error_value (attributes[i + 1],
4833 gml->ml.filename, fileline, gml->ml.window);
4834 }
4835
4836 /*****************
4837 * id (optional) *
4838 *****************/
4839
4840 else if (strcmp (attributes[i], "id") == 0)
4841 {
4842 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4843 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4844 return gamgi_io_error_value (attributes[i + 1],
4845 gml->ml.filename, fileline, gml->ml.window);
4846
4847 hash = gamgi_math_hash_value (token,
4848 GAMGI_EXPAT_HASH_MULTIPLIER, GAMGI_EXPAT_HASH_SIZE);
4849
4850 if (gamgi_expat_import_id_get (token, gml, hash) != NULL)
4851 return gamgi_io_error_multiple (gml->ml.filename,
4852 fileline, gml->ml.window);
4853
4854 gamgi_expat_import_id_add (token, gml, hash);
4855 }
4856
4857 /*********************
4858 * parent (optional) *
4859 *********************/
4860
4861 else if (strcmp (attributes[i], "parent") == 0)
4862 {
4863 parent++;
4864 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4865 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4866 return gamgi_io_error_value (attributes[i + 1],
4867 gml->ml.filename, fileline, gml->ml.window);
4868
4869 gamgi_expat_import_ref_add (token, gml);
4870 }
4871
4872 /************************
4873 * reference (optional) *
4874 ***********************/
4875
4876 else if (strcmp (attributes[i], "reference") == 0)
4877 {
4878 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4879 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4880 return gamgi_io_error_value (attributes[i + 1],
4881 gml->ml.filename, fileline, gml->ml.window);
4882
4883 if (strcmp (token, "cell") == 0)
4884 direction->reference = GAMGI_ENGINE_CELL;
4885 else if (strcmp (token, "atoms") == 0)
4886 direction->reference = GAMGI_ENGINE_ATOM;
4887
4888 else return gamgi_io_error_value (attributes[i + 1],
4889 gml->ml.filename, fileline, gml->ml.window);
4890 }
4891
4892 /******************
4893 * uvw (optional) *
4894 ******************/
4895
4896 else if (strcmp (attributes[i], "u") == 0)
4897 {
4898 uvw++;
4899 if (gamgi_io_token_int_scan (attributes[i + 1],
4900 &direction->uvw[0], -INT_MAX, INT_MAX) == FALSE)
4901 return gamgi_io_error_value (attributes[i + 1],
4902 gml->ml.filename, fileline, gml->ml.window);
4903 }
4904
4905 else if (strcmp (attributes[i], "v") == 0)
4906 {
4907 uvw++;
4908 if (gamgi_io_token_int_scan (attributes[i + 1],
4909 &direction->uvw[1], -INT_MAX, INT_MAX) == FALSE)
4910 return gamgi_io_error_value (attributes[i + 1],
4911 gml->ml.filename, fileline, gml->ml.window);
4912 }
4913
4914 else if (strcmp (attributes[i], "w") == 0)
4915 {
4916 uvw++;
4917 if (gamgi_io_token_int_scan (attributes[i + 1],
4918 &direction->uvw[2], -INT_MAX, INT_MAX) == FALSE)
4919 return gamgi_io_error_value (attributes[i + 1],
4920 gml->ml.filename, fileline, gml->ml.window);
4921 }
4922
4923 /**********************
4924 * vectors (optional) *
4925 **********************/
4926
4927 else if (strcmp (attributes[i], "vectors") == 0)
4928 {
4929 vectors++;
4930 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4931 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4932 return gamgi_io_error_value (attributes[i + 1],
4933 gml->ml.filename, fileline, gml->ml.window);
4934
4935 if (strcmp (token, "conventional") == 0)
4936 direction->vectors = GAMGI_PHYS_CONVENTIONAL;
4937 else if (strcmp (token, "primitive") == 0)
4938 direction->vectors = GAMGI_PHYS_PRIMITIVE;
4939
4940 else return gamgi_io_error_value (attributes[i + 1],
4941 gml->ml.filename, fileline, gml->ml.window);
4942 }
4943
4944 /********************
4945 * model (optional) *
4946 ********************/
4947
4948 else if (strcmp (attributes[i], "model") == 0)
4949 {
4950 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
4951 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4952 return gamgi_io_error_value (attributes[i + 1],
4953 gml->ml.filename, fileline, gml->ml.window);
4954
4955 if (strcmp (token, "line") == 0)
4956 direction->model = GAMGI_PHYS_LINE;
4957 else if (strcmp (token, "trace") == 0)
4958 direction->model = GAMGI_PHYS_TRACE;
4959 else if (strcmp (token, "pole") == 0)
4960 direction->model = GAMGI_PHYS_POLE;
4961
4962 else return gamgi_io_error_value (attributes[i + 1],
4963 gml->ml.filename, fileline, gml->ml.window);
4964 }
4965
4966 /*****************************
4967 * projection net (optional) *
4968 *****************************/
4969
4970 else if (strcmp (attributes[i], "net") == 0)
4971 {
4972 net++;
4973 if (gamgi_io_token_alpha_scan (attributes[i + 1],
4974 token, GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
4975 return gamgi_io_error_value (attributes[i + 1],
4976 gml->ml.filename, fileline, gml->ml.window);
4977
4978 if (strcmp (token, "wulff") == 0)
4979 direction->net = gamgi_phys_projection_wulff;
4980 else if (strcmp (token, "schmidt") == 0)
4981 direction->net = gamgi_phys_projection_schmidt;
4982
4983 else return gamgi_io_error_value (attributes[i + 1],
4984 gml->ml.filename, fileline, gml->ml.window);
4985 }
4986
4987 /***************************************
4988 * o1,o2,o3 offset (optional, coupled) *
4989 ***************************************/
4990
4991 else if (strcmp (attributes[i], "o1") == 0)
4992 {
4993 o123++;
4994 if (gamgi_io_token_int_scan (attributes[i + 1],
4995 &direction->node[0], -INT_MAX, INT_MAX) == FALSE)
4996 return gamgi_io_error_value (attributes[i + 1],
4997 gml->ml.filename, fileline, gml->ml.window);
4998 }
4999
5000 else if (strcmp (attributes[i], "o2") == 0)
5001 {
5002 o123++;
5003 if (gamgi_io_token_int_scan (attributes[i + 1],
5004 &direction->node[1], -INT_MAX, INT_MAX) == FALSE)
5005 return gamgi_io_error_value (attributes[i + 1],
5006 gml->ml.filename, fileline, gml->ml.window);
5007 }
5008
5009 else if (strcmp (attributes[i], "o3") == 0)
5010 {
5011 o123++;
5012 if (gamgi_io_token_int_scan (attributes[i + 1],
5013 &direction->node[2], -INT_MAX, INT_MAX) == FALSE)
5014 return gamgi_io_error_value (attributes[i + 1],
5015 gml->ml.filename, fileline, gml->ml.window);
5016 }
5017
5018 /************************
5019 * o4 offset (optional) *
5020 ************************/
5021
5022 else if (strcmp (attributes[i], "o4") == 0)
5023 {
5024 o4++;
5025 if (gamgi_io_token_alpha_scan (attributes[i + 1], token,
5026 GAMGI_IO_TEXT, GAMGI_ENGINE_TOKEN) == FALSE)
5027 return gamgi_io_error_value (attributes[i + 1],
5028 gml->ml.filename, fileline, gml->ml.window);
5029
5030 if (strcmp (token, "000") == 0)
5031 direction->node[3] = FALSE;
5032 else if (strcmp (token, "011") == 0)
5033 direction->node[3] = GAMGI_PHYS_011;
5034 else if (strcmp (token, "101") == 0)
5035 direction->node[3] = GAMGI_PHYS_101;
5036 else if (strcmp (token, "110") == 0)
5037 direction->node[3] = GAMGI_PHYS_110;
5038 else if (strcmp (token, "111") == 0)
5039 direction->node[3] = GAMGI_PHYS_111;
5040 else if (strcmp (token, "122") == 0)
5041 direction->node[3] = GAMGI_PHYS_122;
5042 else if (strcmp (token, "211") == 0)
5043 direction->node[3] = GAMGI_PHYS_211;
5044
5045 else return gamgi_io_error_value (attributes[i + 1],
5046 gml->ml.filename, fileline, gml->ml.window);
5047 }
5048
5049 /**************************************************
5050 * segment: x0,y0,z0,x1,y1,z1 (required, coupled) *
5051 **************************************************/
5052
5053 else if (strcmp (attributes[i], "begin_x") == 0)
5054 {
5055 xyz++;
5056 if (gamgi_io_token_double_scan (attributes[i + 1],
5057 &points[0], -DBL_MAX, DBL_MAX) == FALSE)
5058 return gamgi_io_error_value (attributes[i + 1],
5059 gml->ml.filename, fileline, gml->ml.window);
5060 }
5061
5062 else if (strcmp (attributes[i], "begin_y") == 0)
5063 {
5064 xyz++;
5065 if (gamgi_io_token_double_scan (attributes[i + 1],
5066 &points[1], -DBL_MAX, DBL_MAX) == FALSE)
5067 return gamgi_io_error_value (attributes[i + 1],
5068 gml->ml.filename, fileline, gml->ml.window);
5069 }
5070
5071 else if (strcmp (attributes[i], "begin_z") == 0)
5072 {
5073 xyz++;
5074 if (gamgi_io_token_double_scan (attributes[i + 1],
5075 &points[2], -DBL_MAX, DBL_MAX) == FALSE)
5076 return gamgi_io_error_value (attributes[i + 1],
5077 gml->ml.filename, fileline, gml->ml.window);
5078 }
5079
5080 else if (strcmp (attributes[i], "end_x") == 0)
5081 {
5082 xyz++;
5083 if (gamgi_io_token_double_scan (attributes[i + 1],
5084 &points[3], -DBL_MAX, DBL_MAX) == FALSE)
5085 return gamgi_io_error_value (attributes[i + 1],
5086 gml->ml.filename, fileline, gml->ml.window);
5087 }
5088
5089 else if (strcmp (attributes[i], "end_y") == 0)
5090 {
5091 xyz++;
5092 if (gamgi_io_token_double_scan (attributes[i + 1],
5093 &points[4], -DBL_MAX, DBL_MAX) == FALSE)
5094 return gamgi_io_error_value (attributes[i + 1],
5095 gml->ml.filename, fileline, gml->ml.window);
5096 }
5097
5098 else if (strcmp (attributes[i], "end_z") == 0)
5099 {
5100 xyz++;
5101 if (gamgi_io_token_double_scan (attributes[i + 1],
5102 &points[5], -DBL_MAX, DBL_MAX) == FALSE)
5103 return gamgi_io_error_value (attributes[i + 1],
5104 gml->ml.filename, fileline, gml->ml.window);
5105 }
5106
5107 /*************************************
5108 * origin: x,y,z (optional, coupled) *
5109 *************************************/
5110
5111 else if (strcmp (attributes[i], "x") == 0)
5112 {
5113 position++;
5114 if (gamgi_io_token_double_scan (attributes[i + 1],
5115 &direction->origin[0], -DBL_MAX, DBL_MAX) == FALSE)
5116 return gamgi_io_error_value (attributes[i + 1],
5117 gml->ml.filename, fileline, gml->ml.window);
5118 }
5119
5120 else if (strcmp (attributes[i], "y") == 0)
5121 {
5122 position++;
5123 if (gamgi_io_token_double_scan (attributes[i + 1],
5124 &direction->origin[1], -DBL_MAX, DBL_MAX) == FALSE)
5125 return gamgi_io_error_value (attributes[i + 1],
5126 gml->ml.filename, fileline, gml->ml.window);
5127 }
5128
5129 else if (strcmp (attributes[i], "z") == 0)
5130 {
5131 position++;
5132 if (gamgi_io_token_double_scan (attributes[i + 1],
5133 &direction->origin[2], -DBL_MAX, DBL_MAX) == FALSE)
5134 return gamgi_io_error_value (attributes[i + 1],
5135 gml->ml.filename, fileline, gml->ml.window);
5136 }
5137
5138 /*************************************
5139 * center: x,y,z (optional, coupled) *
5140 *************************************/
5141
5142 else if (strcmp (attributes[i], "center_x") == 0)
5143 {
5144 center++;
5145 if (gamgi_io_token_double_scan (attributes[i + 1],
5146 &direction->center[0], -DBL_MAX, DBL_MAX) == FALSE)
5147 return gamgi_io_error_value (attributes[i + 1],
5148 gml->ml.filename, fileline, gml->ml.window);
5149 }
5150
5151 else if (strcmp (attributes[i], "center_y") == 0)
5152 {
5153 center++;
5154 if (gamgi_io_token_double_scan (attributes[i +