Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / ligo / primitive.cpp
blobc9c4f8180ff7f39f759a7e26a685152fc346603b
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdligo.h"
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/hierarchical_timer.h"
24 #include "nel/ligo/primitive.h"
25 #include "nel/ligo/ligo_config.h"
26 #include "nel/ligo/primitive_class.h"
27 #include "nel/misc/i_xml.h"
28 #include "nel/misc/path.h"
30 using namespace NLMISC;
31 using namespace std;
33 const uint32 NLLIGO_PRIMITIVE_VERSION = 1;
35 #ifdef DEBUG_NEW
36 #define new DEBUG_NEW
37 #endif
39 namespace NLLIGO
42 CPrimitiveContext *CPrimitiveContext::_Instance = NULL;
45 // ***************************************************************************
46 // XML helpers
47 // ***************************************************************************
49 void Error (const std::string &filename, const char *format, ...)
51 va_list args;
52 va_start( args, format );
53 char buffer[1024];
54 vsnprintf( buffer, 1024, format, args );
55 va_end( args );
57 nlwarning ("In File (%s) %s", filename.c_str(), buffer);
60 // ***************************************************************************
62 void XMLError (xmlNodePtr xmlNode, const std::string &filename, const char *format, ... )
64 va_list args;
65 va_start( args, format );
66 char buffer[1024];
67 vsnprintf( buffer, 1024, format, args );
68 va_end( args );
70 Error (filename, "node (%s), line (%d) : %s", xmlNode->name, xmlNode->line, buffer);
74 // ***************************************************************************
76 xmlNodePtr GetFirstChildNode (xmlNodePtr xmlNode, const std::string &filename, const std::string &childName)
78 // Call the CIXml version
79 xmlNodePtr result = CIXml::getFirstChildNode (xmlNode, childName);
80 if (result) return result;
82 // Output a formated error
83 XMLError (xmlNode, filename.c_str(), "Can't find XML node named (%s)", childName.c_str());
84 return NULL;
87 // ***************************************************************************
89 bool GetPropertyString (string &result, const std::string &filename, xmlNodePtr xmlNode, const std::string &propName)
91 // Call the CIXml version
92 if (!CIXml::getPropertyString (result, xmlNode, propName))
94 // Output a formated error
95 XMLError (xmlNode, filename, "Can't find XML node property (%s)", propName.c_str());
96 return false;
98 return true;
101 // ***************************************************************************
103 bool ReadInt (const std::string &propName, int &result, const std::string &filename, xmlNodePtr xmlNode)
105 string value;
106 if (GetPropertyString (value, filename, xmlNode, propName))
108 result = atoi (value.c_str ());
109 return true;
111 return false;
114 // ***************************************************************************
116 void WriteInt (const std::string &propName, int value, xmlNodePtr xmlNode)
118 // Set properties
119 xmlSetProp (xmlNode, (const xmlChar*)propName.c_str(), (const xmlChar*)(toString (value).c_str ()));
122 // ***************************************************************************
124 bool ReadUInt (const std::string &propName, uint &result, const std::string &filename, xmlNodePtr xmlNode)
126 string value;
127 if (GetPropertyString (value, filename, xmlNode, propName))
129 result = strtoul (value.c_str (), NULL, 10);
130 return true;
132 return false;
135 // ***************************************************************************
137 void WriteUInt (const std::string &propName, uint value, xmlNodePtr xmlNode)
139 // Set properties
140 xmlSetProp (xmlNode, (const xmlChar*)propName.c_str(), (const xmlChar*)(toString (value).c_str ()));
143 // ***************************************************************************
145 bool ReadFloat (const std::string &propName, float &result, const std::string &filename, xmlNodePtr xmlNode)
147 string value;
148 if (GetPropertyString (value, filename, xmlNode, propName))
150 NLMISC::fromString(value, result);
151 return true;
153 return false;
156 // ***************************************************************************
158 void WriteFloat (const std::string &propName, float value, xmlNodePtr xmlNode)
160 // Set properties
161 xmlSetProp (xmlNode, (const xmlChar*)propName.c_str(), (const xmlChar*)(toString (value).c_str ()));
164 // ***************************************************************************
166 bool ReadVector (CPrimVector &point, const std::string &filename, xmlNodePtr xmlNode)
168 CPrimVector pos;
169 if (ReadFloat ("X", pos.x, filename, xmlNode))
171 if (ReadFloat ("Y", pos.y, filename, xmlNode))
173 if (ReadFloat ("Z", pos.z, filename, xmlNode))
175 pos.Selected = false;
176 string result;
177 if (CIXml::getPropertyString (result, xmlNode, "SELECTED"))
179 if (result == "true")
180 pos.Selected = true;
182 point = pos;
183 return true;
187 return false;
190 // ***************************************************************************
192 void WriteVector (const CPrimVector &point, xmlNodePtr xmlNode)
194 // Set properties
195 xmlSetProp (xmlNode, (const xmlChar*)"X", (const xmlChar*)(toString (point.x).c_str ()));
196 xmlSetProp (xmlNode, (const xmlChar*)"Y", (const xmlChar*)(toString (point.y).c_str ()));
197 xmlSetProp (xmlNode, (const xmlChar*)"Z", (const xmlChar*)(toString (point.z).c_str ()));
198 if (point.Selected)
199 xmlSetProp (xmlNode, (const xmlChar*)"SELECTED", (const xmlChar*)"true");
203 // ***************************************************************************
205 bool GetNodeString (string &result, const std::string &filename, xmlNodePtr xmlNode, const std::string &nodeName)
207 // Look for the node
208 xmlNodePtr node = CIXml::getFirstChildNode (xmlNode, nodeName);
209 if (!node)
211 XMLError (xmlNode, filename, "Can't find XML node named (%s)", nodeName.c_str());
212 return false;
215 // Get the node string
216 if (!CIXml::getContentString (result, node))
218 XMLError (xmlNode, filename, "Can't find any text in the node named (%s)", nodeName.c_str());
219 return false;
222 return true;
225 // ***************************************************************************
227 bool GetContentString (string &result, const std::string &filename, xmlNodePtr xmlNode)
229 // Get the node string
230 if (!CIXml::getContentString (result, xmlNode))
232 XMLError (xmlNode, filename, "Can't find any text in the node");
233 return false;
236 return true;
239 // ***************************************************************************
240 // CPropertyString
241 // ***************************************************************************
243 CPropertyString::CPropertyString (const std::string &str)
245 String = str;
248 // ***************************************************************************
250 CPropertyString::CPropertyString (const std::string &str, bool _default)
252 String = str;
253 Default = _default;
256 // ***************************************************************************
257 // CPropertyStringArray
258 // ***************************************************************************
260 CPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray)
262 StringArray = stringArray;
265 // ***************************************************************************
267 CPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray, bool _default)
269 StringArray = stringArray;
270 Default = _default;
273 // ***************************************************************************
275 void CPrimPoint::serial (NLMISC::IStream &f)
277 // serial base info
278 IPrimitive::serial(f);
279 f.serial(Point);
280 f.serial(Angle);
283 // ***************************************************************************
284 void CPrimPath::serial (NLMISC::IStream &f)
286 IPrimitive::serial(f);
287 f.serialCont(VPoints);
290 // ***************************************************************************
292 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points)
294 uint32 i;
295 CVector vMin, vMax;
297 // Point or line can't contains !
298 if (points.size() < 3)
299 return false;
301 // Get the bounding rectangle of the zone
302 vMax = vMin = points[0];
303 for (i = 0; i < points.size(); ++i)
305 if (vMin.x > points[i].x)
306 vMin.x = points[i].x;
307 if (vMin.y > points[i].y)
308 vMin.y = points[i].y;
310 if (vMax.x < points[i].x)
311 vMax.x = points[i].x;
312 if (vMax.y < points[i].y)
313 vMax.y = points[i].y;
316 if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
317 return false;
319 uint32 nNbIntersection = 0;
320 for (i = 0; i < points.size(); ++i)
322 const CVector &p1 = points[i];
323 const CVector &p2 = points[(i+1)%points.size()];
325 if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
326 continue;
327 if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
328 continue;
329 float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
330 if (xinter > v.x)
331 ++nNbIntersection;
333 if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
334 return true;
335 else
336 return false;
339 // ***************************************************************************
341 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<NLMISC::CVector> &points)
343 uint32 i;
344 CVector vMin, vMax;
346 // Point or line can't contains !
347 if (points.size() < 3)
348 return false;
350 // Get the bounding rectangle of the zone
351 vMax = vMin = points[0];
352 for (i = 0; i < points.size(); ++i)
354 if (vMin.x > points[i].x)
355 vMin.x = points[i].x;
356 if (vMin.y > points[i].y)
357 vMin.y = points[i].y;
359 if (vMax.x < points[i].x)
360 vMax.x = points[i].x;
361 if (vMax.y < points[i].y)
362 vMax.y = points[i].y;
365 if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
366 return false;
368 uint32 nNbIntersection = 0;
369 for (i = 0; i < points.size(); ++i)
371 const CVector &p1 = points[i];
372 const CVector &p2 = points[(i+1)%points.size()];
374 if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
375 continue;
376 if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
377 continue;
378 float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
379 if (xinter > v.x)
380 ++nNbIntersection;
382 if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
383 return true;
384 else
385 return false;
388 // ***************************************************************************
389 // CPrimNode
390 // ***************************************************************************
392 bool CPrimNode::read (xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
394 return IPrimitive::read (xmlNode, filename, version, config);
397 // ***************************************************************************
399 uint CPrimNode::getNumVector () const
401 return 0;
404 // ***************************************************************************
406 const CPrimVector *CPrimNode::getPrimVector () const
408 return NULL;
411 // ***************************************************************************
413 CPrimVector *CPrimNode::getPrimVector ()
415 return NULL;
418 // ***************************************************************************
420 NLLIGO::IPrimitive *CPrimNode::copy () const
422 return new CPrimNode (*this);
426 // ***************************************************************************
427 // CPrimNode
428 // ***************************************************************************
430 /*void CPrimNode::operator= (const CPrimNode &node)
432 // Copy the IPrimitive
433 IPrimitive::operator= (node);
436 // ***************************************************************************
438 void CPrimPoint::operator= (const CPrimPoint &node)
440 // Copy the IPrimitive
441 IPrimitive::operator= (node);
444 // ***************************************************************************
446 void CPrimPath::operator= (const CPrimPath &node)
448 // Copy the IPrimitive
451 // ***************************************************************************
453 void CPrimZone::operator= (const CPrimZone &node)
455 // Copy the IPrimitive
456 IPrimitive::operator= (node);
460 // ***************************************************************************
462 uint CPrimPoint::getNumVector () const
464 return 1;
467 // ***************************************************************************
469 const CPrimVector *CPrimPoint::getPrimVector () const
471 return &Point;
474 // ***************************************************************************
476 CPrimVector *CPrimPoint::getPrimVector ()
478 return &Point;
481 // ***************************************************************************
483 NLLIGO::IPrimitive *CPrimPoint::copy () const
485 return new CPrimPoint (*this);
488 // ***************************************************************************
490 bool CPrimPoint::read(xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
492 // Read points
493 xmlNodePtr ptNode = GetFirstChildNode (xmlNode, filename, "PT");
494 if (ptNode)
496 // Read a vector
497 if (!ReadVector (Point, filename, ptNode))
498 return false;
500 ptNode = CIXml::getFirstChildNode (xmlNode, "ANGLE");
501 if (ptNode)
503 // Read a float
504 if (!ReadFloat ("VALUE", Angle, filename, ptNode))
505 return false;
507 else
508 Angle = 0;
510 else
512 return false;
515 return IPrimitive::read (xmlNode, filename, version, config);
518 // ***************************************************************************
520 void CPrimPoint::write (xmlNodePtr xmlNode, const std::string &filename) const
522 // Save the point
523 xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
524 WriteVector (Point, ptNode);
526 // Save the angle
527 if (Angle != 0)
529 xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"ANGLE", NULL);
530 WriteFloat ("VALUE", Angle, ptNode);
533 IPrimitive::write (xmlNode, filename);
536 // ***************************************************************************
537 // CPrimPath
538 // ***************************************************************************
540 uint CPrimPath::getNumVector () const
542 return (uint)VPoints.size ();
545 // ***************************************************************************
547 const CPrimVector *CPrimPath::getPrimVector () const
549 if (VPoints.empty())
550 return NULL;
551 return &(VPoints[0]);
554 // ***************************************************************************
556 NLLIGO::IPrimitive *CPrimPath::copy () const
558 return new CPrimPath (*this);
561 // ***************************************************************************
563 CPrimVector *CPrimPath::getPrimVector ()
565 if (VPoints.empty())
566 return NULL;
567 return &(VPoints[0]);
570 // ***************************************************************************
572 bool CPrimPath::read (xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
574 // Read points
575 VPoints.clear ();
576 VPoints.reserve (CIXml::countChildren (xmlNode, "PT"));
577 xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "PT");
578 if (ptNode)
582 // Read a vector
583 VPoints.push_back (CPrimVector ());
584 if (!ReadVector (VPoints.back (), filename, ptNode))
585 return false;
587 ptNode = CIXml::getNextChildNode (ptNode, "PT");
589 while (ptNode);
592 return IPrimitive::read (xmlNode, filename, version, config);
595 // ***************************************************************************
597 void CPrimPath::write (xmlNodePtr xmlNode, const std::string &filename) const
599 // Save the points
600 for (uint i=0; i<VPoints.size (); i++)
602 xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
603 WriteVector (VPoints[i], ptNode);
606 IPrimitive::write (xmlNode, filename);
609 // ***************************************************************************
610 // CPrimZone
611 // ***************************************************************************
613 uint CPrimZone::getNumVector () const
615 return (uint)VPoints.size ();
618 // ***************************************************************************
620 const CPrimVector *CPrimZone::getPrimVector () const
622 if (VPoints.empty())
623 return NULL;
624 return &(VPoints[0]);
627 // ***************************************************************************
629 NLLIGO::IPrimitive *CPrimZone::copy () const
631 return new CPrimZone (*this);
634 // ***************************************************************************
636 CPrimVector *CPrimZone::getPrimVector ()
638 if(VPoints.empty()) return 0;
639 return &(VPoints[0]);
642 // ***************************************************************************
644 bool CPrimZone::read (xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
646 // Read points
647 VPoints.clear ();
648 VPoints.reserve (CIXml::countChildren (xmlNode, "PT"));
649 xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "PT");
650 if (ptNode)
654 // Read a vector
655 VPoints.push_back (CPrimVector ());
656 if (!ReadVector (VPoints.back (), filename, ptNode))
657 return false;
659 ptNode = CIXml::getNextChildNode (ptNode, "PT");
661 while (ptNode);
664 return IPrimitive::read (xmlNode, filename, version, config);
667 // ***************************************************************************
669 void CPrimZone::write (xmlNodePtr xmlNode, const std::string &filename) const
671 // Save the points
672 for (uint i=0; i<VPoints.size (); i++)
674 xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL);
675 WriteVector (VPoints[i], ptNode);
678 IPrimitive::write (xmlNode, filename);
681 // ***************************************************************************
683 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)
685 H_AUTO(NLLIGO_Contains1)
686 uint32 i;
687 CVector vMin, vMax;
688 float nearest = FLT_MAX;
689 CVector pos;
691 // Point or line can't contains !
692 if (points.size() < 3 || isPath)
694 // only compute the distance.
695 if (points.size() == 1)
697 distance = (points[0] - v).norm();
698 nearPos = points[0];
700 else if (points.size() == 2)
702 distance = getSegmentDist(v, points[0], points[1], nearPos);
704 else
706 // compute nearest segment
707 for (i = 0; i < points.size()-1; ++i)
709 const CVector &p1 = points[i];
710 const CVector &p2 = points[i+1];
712 float dist = getSegmentDist(v, p1, p2, pos);
713 if( dist < nearest)
715 nearest = dist;
716 nearPos = pos;
719 distance = nearest;
721 return false;
724 // Get the bounding rectangle of the zone
725 vMax = vMin = points[0];
726 for (i = 0; i < points.size(); ++i)
728 vMin.x = min(vMin.x, points[i].x);
729 vMin.y = min(vMin.y, points[i].y);
730 vMax.x = max(vMax.x, points[i].x);
731 vMax.y = max(vMax.y, points[i].y);
734 if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
736 // find the nearest distance of all segment
737 for (uint i=0; i<points.size(); ++i)
739 float dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);
741 if (dist < nearest)
743 nearest = dist;
744 nearPos = pos;
747 distance = nearest;
748 return false;
751 uint32 nNbIntersection = 0;
752 for (i = 0; i < points.size(); ++i)
754 const CVector &p1 = points[i];
755 const CVector &p2 = points[(i+1)%points.size()];
757 float dist = getSegmentDist(v, p1, p2, pos);
758 if( dist < nearest)
760 nearest = dist;
761 nearPos = pos;
764 if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
765 continue;
766 if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
767 continue;
768 float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
769 if (xinter > v.x)
770 ++nNbIntersection;
773 distance = nearest;
774 if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
775 return true;
776 else
777 return false;
780 // ***************************************************************************
782 bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)
784 H_AUTO(NLLIGO_Contains2)
785 uint32 i;
786 CVector vMin, vMax;
787 float nearest = FLT_MAX;
788 CVector pos;
790 // Point or line can't contains !
791 if (points.size() < 3 || isPath)
793 // only compute the distance.
794 if (points.size() == 1)
796 distance = (points[0] - v).norm();
797 nearPos = points[0];
799 else if (points.size() == 2)
801 distance = getSegmentDist(v, points[0], points[1], nearPos);
803 else
805 // compute nearest segment
806 for (i = 0; i < points.size()-1; ++i)
808 const CVector &p1 = points[i];
809 const CVector &p2 = points[i+1];
811 float dist = getSegmentDist(v, p1, p2, pos);
812 if( dist < nearest)
814 nearest = dist;
815 nearPos = pos;
818 distance = nearest;
820 return false;
823 // Get the bounding rectangle of the zone
824 vMax = vMin = points[0];
825 for (i = 0; i < points.size(); ++i)
827 vMin.x = min(vMin.x, points[i].x);
828 vMin.y = min(vMin.y, points[i].y);
829 vMax.x = max(vMax.x, points[i].x);
830 vMax.y = max(vMax.y, points[i].y);
833 if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))
835 // find the nearest distance of all segment
836 for (uint i=0; i<points.size(); ++i)
838 float dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);
840 if (dist < nearest)
842 nearest = dist;
843 nearPos = pos;
846 distance = nearest;
847 return false;
850 uint32 nNbIntersection = 0;
851 for (i = 0; i < points.size(); ++i)
853 const CVector &p1 = points[i];
854 const CVector &p2 = points[(i+1)%points.size()];
856 float dist = getSegmentDist(v, p1, p2, pos);
857 if( dist < nearest)
859 nearest = dist;
860 nearPos = pos;
863 if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))
864 continue;
865 if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))
866 continue;
867 float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));
868 if (xinter > v.x)
869 ++nNbIntersection;
872 distance = nearest;
873 if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside
874 return true;
875 else
876 return false;
879 // ***************************************************************************
881 float CPrimZone::getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos)
883 // two points, compute distance to the segment.
884 CVector V = (p2-p1).normed();
885 double length= (p2-p1).norm();
886 float distance;
888 // case where p1==p2
889 if(length==0.0)
891 nearPos= p1;
892 distance = (p1-v).norm();
894 // standard case
895 else
897 float t = (float)((double)((v-p1)*V)/length);
898 if (t < 0.0f)
900 nearPos = p1;
901 distance = (p1-v).norm();
903 else if (t > 1.0f)
905 nearPos = p2;
906 distance = (p2-v).norm();
908 else
910 nearPos = p1 + t*(p2-p1);
911 distance = (v-nearPos).norm();
915 return distance;
919 // ***************************************************************************
920 NLMISC::CVector CPrimZone::getBarycentre() const
922 CVector sum( CVector::Null );
923 uint n = (uint)VPoints.size();
924 if ( n != 0 )
926 for ( uint i=0; i!=n; ++i )
927 sum += VPoints[i];
928 return sum / (float)n;
930 else
931 return sum;
934 // ***************************************************************************
935 void CPrimZone::getAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const
937 cornerMin.x = FLT_MAX;
938 cornerMin.y = FLT_MAX;
939 cornerMin.z = 0;
940 cornerMax.x = -FLT_MAX;
941 cornerMax.y = -FLT_MAX;
942 cornerMax.z = 0;
943 for ( uint i=0; i!=VPoints.size(); ++i )
945 const CVector& p = VPoints[i];
946 if ( p.x < cornerMin.x )
947 cornerMin.x = p.x;
948 if ( p.x > cornerMax.x )
949 cornerMax.x = p.x;
950 if ( p.y < cornerMin.y )
951 cornerMin.y = p.y;
952 if ( p.y > cornerMax.y )
953 cornerMax.y = p.y;
958 // ***************************************************************************
959 float CPrimZone::getAreaOfAABox() const
961 CVector cornerMin, cornerMax;
962 getAABox( cornerMin, cornerMax );
963 return (cornerMax.x-cornerMin.x) * (cornerMax.y-cornerMin.y);
967 // ***************************************************************************
968 void CPrimZone::serial (NLMISC::IStream &f)
970 IPrimitive::serial(f);
971 f.serialCont(VPoints);
974 // ***************************************************************************
975 void CPrimRegion::serial (NLMISC::IStream &f)
977 f.xmlPushBegin ("REGION");
979 f.xmlSetAttrib ("NAME");
980 f.serial (Name);
982 f.xmlPushEnd();
984 sint version = 2;
985 version = f.serialVersion (version);
986 string check = "REGION";
987 f.serialCheck (check);
989 f.xmlPush ("POINTS");
990 f.serialCont (VPoints);
991 f.xmlPop ();
992 f.xmlPush ("PATHES");
993 f.serialCont (VPaths);
994 f.xmlPop ();
995 f.xmlPush ("ZONES");
996 f.serialCont (VZones);
997 f.xmlPop ();
999 if (version > 1)
1001 f.xmlPush ("HIDEPOINTS");
1002 f.serialCont (VHidePoints);
1003 f.xmlPop ();
1004 f.xmlPush ("HIDEZONES");
1005 f.serialCont (VHideZones);
1006 f.xmlPop ();
1007 f.xmlPush ("HIDEPATHS");
1008 f.serialCont (VHidePaths);
1009 f.xmlPop ();
1011 else
1013 VHidePoints.resize (VPoints.size(), false);
1014 VHideZones.resize (VZones.size(), false);
1015 VHidePaths.resize (VPaths.size(), false);
1019 // ***************************************************************************
1020 // IPrimitive
1021 // ***************************************************************************
1023 IPrimitive::IPrimitive ()
1025 _Parent = NULL;
1029 IPrimitive::IPrimitive (const IPrimitive &node) : IStreamable()
1031 _Parent = NULL;
1032 IPrimitive::operator= (node);
1035 // ***************************************************************************
1037 void IPrimitive::serial (NLMISC::IStream &f)
1039 // NB : unparsed parameters are not binary serialized !
1041 // serialize the property container
1042 if (f.isReading())
1044 uint32 size;
1045 f.serial(size);
1046 for (uint i=0; i<size; ++i)
1048 std::string s;
1049 f.serial(s);
1050 IProperty *&pp = _Properties[s];
1051 f.serialPolyPtr(pp);
1054 else
1056 uint32 size = (uint32)_Properties.size();
1057 f.serial(size);
1058 std::map<std::string, IProperty*>::iterator first(_Properties.begin()), last(_Properties.end());
1059 for (; first != last; ++first)
1061 std::string &s = const_cast<std::string&>(first->first);
1063 f.serial(s);
1064 f.serialPolyPtr(first->second);
1067 f.serial(_ChildId);
1069 // f.serial(Layer);
1070 // f.serial(Name);
1071 // f.serial(Expanded);
1073 // serial the childrens
1074 if (f.isReading())
1076 std::vector<IPrimitive*> children;
1077 f.serialContPolyPtr(children);
1078 uint index = 0;
1079 for(std::vector<IPrimitive*>::iterator it = children.begin(); it != children.end(); ++it, ++index)
1081 insertChild(*it, index);
1084 else
1086 f.serialContPolyPtr(_Children);
1089 if (f.isReading())
1091 // reloc child link
1092 vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
1093 for (; first != last; ++first)
1095 if (*first)
1096 (*first)->_Parent = this;
1102 // ***************************************************************************
1104 void IPrimitive::updateChildId (uint index)
1106 uint i;
1107 uint count = (uint)_Children.size ();
1108 for (i=index; i<count; i++)
1109 _Children[i]->_ChildId = i;
1112 // ***************************************************************************
1114 void IPrimitive::branchLink()
1116 onBranchLink();
1117 std::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
1118 for (; first != last; ++first)
1120 (*first)->branchLink();
1124 // ***************************************************************************
1126 void IPrimitive::branchUnlink()
1128 onBranchUnlink();
1129 std::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());
1130 for (; first != last; ++first)
1132 (*first)->branchUnlink();
1137 // ***************************************************************************
1139 void IPrimitive::operator= (const IPrimitive &node)
1141 // Clean dest
1142 removeChildren ();
1143 removeProperties ();
1145 // copy deprecated param
1146 // Layer = node.Layer;
1147 // Name = node.Name;
1149 // copy unparsed properties
1150 _UnparsedProperties = node._UnparsedProperties;
1152 // Copy the flags
1153 // Expanded = node.Expanded;
1154 _ChildId = node._ChildId;
1156 // Copy children
1157 _Children.resize (node._Children.size ());
1158 for (uint child = 0; child < node._Children.size (); child++)
1160 // Copy the child
1161 _Children[child] = node._Children[child]->copy ();
1163 // Set the parent
1164 _Children[child]->_Parent = this;
1167 // Copy properties
1168 std::map<std::string, IProperty*>::const_iterator ite = node._Properties.begin ();
1169 while (ite != node._Properties.end ())
1171 // Get the property
1172 CPropertyString *propString = dynamic_cast<CPropertyString *>(ite->second);
1173 if (propString)
1175 // New property
1176 CPropertyString *newProp = new CPropertyString ();
1177 *newProp = *propString;
1178 _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
1180 else
1182 CPropertyStringArray *propStringArray = dynamic_cast<CPropertyStringArray *>(ite->second);
1183 if (propStringArray)
1185 // New property
1186 CPropertyStringArray *newProp = new CPropertyStringArray ();
1187 *newProp = *propStringArray;
1188 _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
1190 else
1192 CPropertyColor *propColor = dynamic_cast<CPropertyColor *>(ite->second);
1193 nlverify (propColor);
1195 // New property
1196 CPropertyColor *newProp = new CPropertyColor ();
1197 *newProp = *propColor;
1198 _Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));
1202 ite++;
1205 #ifdef NLLIGO_DEBUG
1206 _DebugClassName = node._DebugClassName;
1207 _DebugPrimitiveName = node._DebugPrimitiveName;
1208 #endif
1212 const IPrimitive *IPrimitive::getPrimitive (const std::string &absoluteOrRelativePath) const
1214 const IPrimitive *cursor=this;
1215 string path=absoluteOrRelativePath;
1217 if (path.find("//")==0) // an absolute path.
1219 while (cursor->getParent())
1220 cursor=cursor->getParent();
1221 path.erase(0,2);
1224 while (!path.empty())
1226 if (path.find("/")==0)
1228 path.erase(0,1);
1229 continue;
1231 if (path.find("..")==0)
1233 cursor=cursor->getParent();
1234 if (!cursor)
1235 return NULL;
1237 path.erase(0,2);
1238 continue;
1241 string::size_type indexStr=path.find("/");
1242 string childName;
1243 if (indexStr==string::npos)
1245 childName=path;
1246 path.clear();
1248 else
1250 childName=path.substr(0,indexStr);
1251 path.erase(0, indexStr);
1253 childName=toUpperAscii(childName);
1254 const IPrimitive*child=NULL;
1255 uint childIndex;
1256 for (childIndex=0;childIndex<cursor->getNumChildren();childIndex++)
1258 cursor->getChild(child,childIndex);
1259 nlassert(child);
1260 string name;
1261 if ( child->getPropertyByName("class", name)
1262 && toUpperAscii(name)==childName )
1263 break;
1265 if (childIndex>=cursor->getNumChildren())
1266 return NULL;
1268 cursor=child;
1270 return cursor;
1273 // ***************************************************************************
1275 bool IPrimitive::getProperty (uint index, std::string &property_name, const IProperty *&result) const
1277 // Look for the property
1278 std::map<std::string, IProperty*>::const_iterator ite = _Properties.begin ();
1279 while (ite != _Properties.end ())
1281 if (index == 0)
1283 property_name = ite->first;
1284 result = ite->second;
1285 return true;
1287 index--;
1288 ite ++;
1290 nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %u, size : %u).", index, (uint)_Properties.size ());
1291 return false;
1294 // ***************************************************************************
1296 bool IPrimitive::getProperty (uint index, std::string &property_name, IProperty *&result)
1298 // Look for the property
1299 std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
1300 while (ite != _Properties.end ())
1302 if (index == 0)
1304 property_name = ite->first;
1305 result = ite->second;
1306 return true;
1308 index--;
1309 ite ++;
1311 nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %u, size : %u).", index, (uint)_Properties.size ());
1312 return false;
1315 // ***************************************************************************
1317 bool IPrimitive::getPropertyByName (const std::string &property_name, const IProperty *&result) const
1319 // Look for the property
1320 std::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);
1321 if (ite != _Properties.end ())
1323 result = ite->second;
1324 return true;
1326 return false;
1329 // ***************************************************************************
1331 bool IPrimitive::getPropertyByName (const std::string &property_name, IProperty *&result) const
1333 // Look for the property
1334 std::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);
1335 if (ite != _Properties.end ())
1337 result = ite->second;
1338 return true;
1340 return false;
1343 // ***************************************************************************
1345 bool IPrimitive::getPropertyByName (const std::string &property_name, std::string *&result) const
1347 // Get the property
1348 IProperty *prop;
1349 if (getPropertyByName (property_name, prop))
1351 CPropertyString *strProp = dynamic_cast<CPropertyString *> (prop);
1352 if (strProp)
1354 result = &(strProp->String);
1355 return true;
1357 else
1359 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name.c_str());
1362 return false;
1365 // ***************************************************************************
1367 bool IPrimitive::getPropertyByName (const std::string &property_name, std::string &result) const
1369 // Get the property
1370 const IProperty *prop;
1371 if (getPropertyByName (property_name, prop))
1373 const CPropertyString *strProp = dynamic_cast<const CPropertyString *> (prop);
1374 if (strProp)
1376 result = strProp->String;
1377 return true;
1379 else
1381 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name.c_str());
1384 return false;
1387 // ***************************************************************************
1389 bool IPrimitive::getPropertyByName (const std::string &property_name, std::vector<std::string> *&result) const
1391 // Get the property
1392 IProperty *prop;
1393 if (getPropertyByName (property_name, prop))
1395 CPropertyStringArray *strProp = dynamic_cast<CPropertyStringArray *> (prop);
1396 if (strProp)
1398 result = &(strProp->StringArray);
1399 return true;
1401 else
1403 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name.c_str());
1406 return false;
1409 // ***************************************************************************
1411 bool IPrimitive::getPropertyByName (const std::string &property_name, const std::vector<std::string> *&result) const
1413 // Get the property
1414 IProperty *prop;
1415 if (getPropertyByName (property_name, prop))
1417 const CPropertyStringArray *strProp = dynamic_cast<const CPropertyStringArray *> (prop);
1418 if (strProp)
1420 result = &(strProp->StringArray);
1421 return true;
1423 else
1425 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name.c_str());
1428 return false;
1431 // ***************************************************************************
1433 bool IPrimitive::getPropertyByName (const std::string &property_name, NLMISC::CRGBA &result) const
1435 // Get the property
1436 IProperty *prop;
1437 if (getPropertyByName (property_name, prop))
1439 const CPropertyColor *colorProp = dynamic_cast<const CPropertyColor *> (prop);
1440 if (colorProp)
1442 result = colorProp->Color;
1443 return true;
1445 else
1447 nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a color.", property_name.c_str());
1450 return false;
1453 // ***************************************************************************
1455 bool IPrimitive::removeProperty (uint index)
1457 // Look for the property
1458 std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
1459 while (ite != _Properties.end ())
1461 if (index == 0)
1463 _Properties.erase (ite);
1464 return true;
1466 index--;
1467 ite ++;
1469 nlwarning ("NLLIGO::IPrimitive::removeProperty : invalid index (index : %u, size : %u).", index, (uint)_Properties.size ());
1470 return false;
1473 // ***************************************************************************
1475 bool IPrimitive::removePropertyByName (const std::string &property_name)
1477 // Look for the property
1478 std::map<std::string, IProperty*>::iterator ite = _Properties.find (property_name);
1479 if (ite != _Properties.end ())
1481 _Properties.erase (ite);
1482 return true;
1484 return false;
1487 // ***************************************************************************
1489 void IPrimitive::removeProperties ()
1491 std::map<std::string, IProperty*>::iterator ite = _Properties.begin ();
1492 while (ite != _Properties.end ())
1494 delete ite->second;
1495 ite++;
1497 _Properties.clear ();
1500 // ***************************************************************************
1502 bool IPrimitive::getChild (const IPrimitive *&result, uint childId) const
1504 if (childId < _Children.size ())
1506 result = _Children[childId];
1507 return true;
1509 else
1511 nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %u, size %u).", childId, (uint)_Children.size ());
1513 return false;
1516 // ***************************************************************************
1518 bool IPrimitive::getChild (IPrimitive *&result, uint childId)
1520 if (childId < _Children.size ())
1522 result = _Children[childId];
1523 return true;
1525 else
1527 nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %u, size %u).", childId, (uint)_Children.size ());
1529 return false;
1532 // ***************************************************************************
1534 bool IPrimitive::removeChild (IPrimitive *child)
1536 uint childId;
1537 if (getChildId(childId, child))
1539 return removeChild(childId);
1541 else
1543 nlwarning("NLLIGO::IPrimitive::removeChild : invalid child, can't remove (child : %p)", child);
1545 return false;
1548 // ***************************************************************************
1550 bool IPrimitive::removeChild (uint childId)
1552 if (childId < _Children.size ())
1554 delete _Children[childId];
1555 _Children.erase (_Children.begin()+childId);
1556 updateChildId (childId);
1557 return true;
1559 else
1561 nlwarning ("NLLIGO::IPrimitive::removeChild : invalid index (index : %u, size %u).", childId, (uint)_Children.size ());
1563 return false;
1566 // ***************************************************************************
1568 void IPrimitive::removeChildren ()
1570 // Erase children
1571 for (uint i=0; i<_Children.size (); i++)
1573 delete _Children[i];
1575 _Children.clear ();
1578 // ***************************************************************************
1580 bool IPrimitive::unlinkChild(IPrimitive *child)
1582 uint childId;
1583 if (getChildId(childId, child))
1585 child->onUnlinkFromParent();
1586 child->branchUnlink();
1587 _Children.erase (_Children.begin()+childId);
1588 updateChildId (childId);
1589 child->_Parent = NULL;
1590 child->_ChildId = 0;
1591 return true;
1593 else
1595 nlwarning("NLLIGO::IPrimitive::unlinkChild : invalid child, can't unlink (child : %p)", child);
1597 return false;
1600 // ***************************************************************************
1602 bool IPrimitive::insertChild (IPrimitive *primitive, uint index)
1604 // At the end ?
1605 if (index == AtTheEnd)
1606 index = (uint)_Children.size ();
1608 // Index valid ?
1609 if (index>_Children.size ())
1610 return false;
1612 // Insert
1613 _Children.insert (_Children.begin () + index, primitive);
1615 // Update child id
1616 updateChildId (index);
1618 // Link to the parent
1619 primitive->_Parent = this;
1621 // signaling
1622 primitive->onLinkToParent();
1623 primitive->branchLink();
1625 return true;
1628 // ***************************************************************************
1630 IPrimitive::~IPrimitive ()
1632 // Remove children
1633 removeChildren ();
1635 // Erase properties
1636 removeProperties ();
1639 // ***************************************************************************
1640 bool IPrimitive::checkProperty(const std::string &property_name) const
1642 if (_Properties.find(property_name) == _Properties.end())
1643 return false;
1644 return true;
1647 // ***************************************************************************
1649 bool IPrimitive::addPropertyByName (const std::string &property_name, IProperty *result)
1651 bool inserted = _Properties.insert (std::map<std::string, IProperty*>::value_type (property_name, result)).second;
1652 if (inserted)
1654 return true;
1656 return false;
1659 // ***************************************************************************
1661 bool IPrimitive::read (xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
1663 // Erase old properties
1664 _Properties.clear ();
1666 // Read the unparsed properties (for editor view)
1667 xmlNodePtr commentNode = CIXml::getFirstChildNode(xmlNode, XML_COMMENT_NODE);
1668 if (commentNode)
1670 if (!CIXml::getContentString(_UnparsedProperties, commentNode))
1671 _UnparsedProperties.clear();
1674 // Read the expanded flag
1675 // string expanded;
1676 // Expanded = true;
1677 // if (CIXml::getPropertyString (expanded, xmlNode, "EXPANDED"))
1678 // Expanded = (expanded != "false");
1680 // Read the properties
1681 xmlNodePtr propNode;
1682 propNode = CIXml::getFirstChildNode (xmlNode, "PROPERTY");
1683 if (propNode)
1687 // Read the name
1688 string name;
1689 if (GetNodeString (name, filename, propNode, "NAME"))
1691 // Get the property type
1692 string type;
1693 if (GetPropertyString (type, filename, propNode, "TYPE"))
1695 // The property
1696 IProperty *property = NULL;
1698 // Check the type
1699 if (type == "string")
1701 // Create a new property
1702 CPropertyString *propertyString = new CPropertyString;
1703 property = propertyString;
1705 // Read it
1706 if (!GetNodeString (propertyString->String, filename, propNode, "STRING"))
1708 return false;
1711 else if (type == "string_array")
1713 // Create a new property
1714 CPropertyStringArray *propertyStringArray = new CPropertyStringArray;
1715 property = propertyStringArray;
1717 // Read strings
1718 xmlNodePtr stringNode;
1719 propertyStringArray->StringArray.reserve (CIXml::countChildren (propNode, "STRING"));
1720 stringNode = CIXml::getFirstChildNode (propNode, "STRING");
1721 if (stringNode)
1725 // Add the string
1726 string content;
1727 GetContentString (content, filename, stringNode);
1728 propertyStringArray->StringArray.push_back (content);
1730 stringNode = CIXml::getNextChildNode (stringNode, "STRING");
1732 while (stringNode);
1735 else if (type == "color")
1737 // Create a new property
1738 CPropertyColor *propertyColor= new CPropertyColor;
1739 property = propertyColor;
1741 // Read strings
1742 xmlNodePtr colorNode;
1743 colorNode = CIXml::getFirstChildNode (xmlNode, "COLOR");
1744 string R, G, B, A;
1745 if (GetPropertyString (R, filename, colorNode, "R") &&
1746 GetPropertyString (G, filename, colorNode, "G") &&
1747 GetPropertyString (B, filename, colorNode, "B") &&
1748 GetPropertyString (A, filename, colorNode, "A"))
1750 sint32 sR=0, sG=0, sB=0, sA=255;
1751 sR = atoi (R.c_str ());
1752 clamp (sR, 0, 255);
1753 sG = atoi (G.c_str ());
1754 clamp (sG, 0, 255);
1755 sB = atoi (B.c_str ());
1756 clamp (sB, 0, 255);
1757 sA = atoi (A.c_str ());
1758 clamp (sR, 0, 255);
1759 propertyColor->Color.R = (uint8)sR;
1760 propertyColor->Color.G = (uint8)sG;
1761 propertyColor->Color.B = (uint8)sB;
1762 propertyColor->Color.A = (uint8)sA;
1764 else
1765 return false;
1768 // Property found ?
1769 if (property == NULL)
1771 XMLError (propNode, filename, "IPrimitive::read : Unknown property type (%s)", type.c_str ());
1772 return false;
1775 // Add it
1776 _Properties.insert (std::map<std::string, IProperty*>::value_type (name, property));
1778 else
1780 return false;
1783 else
1785 return false;
1788 propNode = CIXml::getNextChildNode (propNode, "PROPERTY");
1790 while (propNode);
1793 // Initialise default value
1794 initDefaultValues (config);
1796 // Read children
1797 xmlNodePtr childNode;
1798 childNode = CIXml::getFirstChildNode (xmlNode, "CHILD");
1799 if (childNode)
1803 // Get the property class
1804 string type;
1805 if (GetPropertyString (type, filename, childNode, "TYPE"))
1807 // Primitive
1808 if (type=="node")
1809 type="CPrimNode";
1810 if (type=="point")
1811 type="CPrimPoint";
1812 if (type=="path")
1813 type="CPrimPath";
1814 if (type=="zone")
1815 type="CPrimZone";
1816 if (type=="alias")
1817 type="CPrimAlias";
1818 IPrimitive *primitive = static_cast<IPrimitive *> (CClassRegistry::create (type));
1820 // Primitive type not found ?
1821 if (primitive == NULL)
1823 XMLError (childNode, filename, "IPrimitive::read : Unknown primitive type (%s)", type.c_str ());
1824 return false;
1827 // Read it
1828 primitive->read (childNode, filename, version, config);
1830 // Add it
1831 insertChild (primitive);
1834 else
1836 return false;
1839 childNode = CIXml::getNextChildNode (childNode, "CHILD");
1841 while (childNode);
1844 #ifdef NLLIGO_DEBUG
1845 // store debug data
1846 getPropertyByName("class", _DebugClassName);
1847 getPropertyByName("name", _DebugPrimitiveName);
1848 #endif
1849 // Done
1850 return true;
1853 // ***************************************************************************
1855 void IPrimitive::initDefaultValues (CLigoConfig &config)
1857 // Get the primitive class
1858 const CPrimitiveClass *primitiveClass = config.getPrimitiveClass (*this);
1859 if (primitiveClass)
1861 // For each properties
1862 uint count = (uint)primitiveClass->Parameters.size ();
1863 uint i;
1864 for (i=0; i<count; i++)
1866 const CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];
1868 // Get the property
1869 IProperty *result;
1870 if (!getPropertyByName (parameter.Name.c_str(), result))
1872 // Create the property
1873 if ((parameter.Type == CPrimitiveClass::CParameter::StringArray) || (parameter.Type == CPrimitiveClass::CParameter::ConstStringArray))
1874 result = new CPropertyStringArray();
1875 else
1876 result = new CPropertyString();
1877 nlverify (addPropertyByName (parameter.Name.c_str(), result));
1881 // Set the default values
1882 for (i=0; i<count; i++)
1884 const CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];
1886 CPropertyString *pString = NULL;
1887 CPropertyStringArray *pStringArray = NULL;
1889 IProperty *result;
1890 nlverify (getPropertyByName (parameter.Name.c_str(), result));
1891 pString = dynamic_cast<CPropertyString*>(result);
1892 if (!pString)
1893 pStringArray = dynamic_cast<CPropertyStringArray*>(result);
1895 // Property have default values ?
1896 if (pString)
1898 // Empty string ?
1899 if (pString->String.empty())
1901 // Set as default
1902 pString->Default = true;
1903 parameter.getDefaultValue (pString->String, *this, *primitiveClass);
1906 else if (pStringArray)
1908 // Empty string array ?
1909 if (pStringArray->StringArray.empty())
1911 // Set as default
1912 pStringArray->Default = true;
1913 parameter.getDefaultValue (pStringArray->StringArray, *this, *primitiveClass);
1920 // ***************************************************************************
1922 void IPrimitive::write (xmlNodePtr xmlNode, const std::string &filename) const
1924 // Save the expanded flag
1925 // if (!Expanded)
1926 // xmlSetProp (xmlNode, (const xmlChar*)"EXPANDED", (const xmlChar*)"false");
1928 // Set the type
1929 xmlSetProp (xmlNode, (const xmlChar*)"TYPE", (const xmlChar*)(const_cast<IPrimitive*> (this)->getClassName ().c_str ()));
1931 // Save the unparsed property
1932 if (!_UnparsedProperties.empty())
1934 xmlNodePtr commentNode = xmlNewComment((const xmlChar*)(_UnparsedProperties.c_str()));
1935 nlverify(commentNode);
1936 xmlAddChild(xmlNode, commentNode);
1939 // Save the properties
1940 std::map<std::string, IProperty*>::const_iterator ite = _Properties.begin ();
1941 while (ite != _Properties.end ())
1943 // Not a default property ?
1944 if (!ite->second->Default)
1946 // Create new nodes
1947 xmlNodePtr propNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PROPERTY", NULL);
1948 xmlNodePtr nameNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"NAME", NULL);
1949 xmlNodePtr textNode = xmlNewText ((const xmlChar *)(ite->first.c_str ()));
1950 xmlAddChild (nameNode, textNode);
1952 // Type
1953 const CPropertyString *str = dynamic_cast<const CPropertyString *> (ite->second);
1954 if (str)
1956 // Set the type
1957 xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string");
1959 // Create new nodes
1960 xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL);
1961 xmlNodePtr textNode = xmlNewText ((const xmlChar *)(str->String.c_str ()));
1962 xmlAddChild (stringNode, textNode);
1964 else
1966 // Should be an array
1967 const CPropertyStringArray *array = dynamic_cast<const CPropertyStringArray *> (ite->second);
1968 if (array)
1970 // Set the type
1971 xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string_array");
1973 // For each strings in the array
1974 for (uint i=0; i<array->StringArray.size (); i++)
1976 // Create new nodes
1977 xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL);
1978 xmlNodePtr textNode = xmlNewText ((const xmlChar *)(array->StringArray[i].c_str ()));
1979 xmlAddChild (stringNode, textNode);
1982 else
1984 // Should be a color
1985 const CPropertyColor *color = safe_cast<const CPropertyColor *> (ite->second);
1987 // Set the type
1988 xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"color");
1990 // Create new nodes
1991 xmlNodePtr colorNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"COLOR", NULL);
1992 xmlSetProp (colorNode, (const xmlChar*)"R", (const xmlChar*)toString (color->Color.R).c_str ());
1993 xmlSetProp (colorNode, (const xmlChar*)"G", (const xmlChar*)toString (color->Color.G).c_str ());
1994 xmlSetProp (colorNode, (const xmlChar*)"B", (const xmlChar*)toString (color->Color.B).c_str ());
1995 xmlSetProp (colorNode, (const xmlChar*)"A", (const xmlChar*)toString (color->Color.A).c_str ());
2000 ite++;
2003 // Save the children
2004 for (uint i=0; i<_Children.size (); i++)
2006 // New node
2007 xmlNodePtr childNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"CHILD", NULL);
2009 // Write it
2010 _Children[i]->write (childNode, filename);
2014 // ***************************************************************************
2016 bool IPrimitive::getChildId (uint &childId, const IPrimitive *child) const
2018 childId = child->_ChildId;
2019 return true;
2022 // ***************************************************************************
2024 uint IPrimitive::getNumProperty () const
2026 return (uint)_Properties.size ();
2029 // ***************************************************************************
2031 std::string IPrimitive::getName() const
2033 std::string ret;
2034 getPropertyByName("name", ret);
2035 return ret;
2038 // ***************************************************************************
2040 const std::string &IPrimitive::getUnparsedProperties() const
2042 return _UnparsedProperties;
2045 // ***************************************************************************
2047 void IPrimitive::setUnparsedProperties(const std::string &unparsedProperties) const
2049 _UnparsedProperties = unparsedProperties;
2052 // ***************************************************************************
2053 // CPrimAlias
2054 // ***************************************************************************
2056 CPrimAlias::CPrimAlias() :
2057 _Alias(0),
2058 _Container(NULL)
2062 CPrimAlias::CPrimAlias(const CPrimAlias &other)
2063 : IPrimitive(other)
2065 // clear the container reference and alias
2066 _Container = NULL;
2067 _Alias = other._Alias;
2070 CPrimAlias::~CPrimAlias()
2072 if (_Container)
2073 onBranchUnlink();
2076 void CPrimAlias::onBranchLink()
2078 CPrimitiveContext &ctx = CPrimitiveContext::instance();
2079 // context must be set when handling alias
2080 nlassert(ctx.CurrentPrimitive);
2081 nlassert(_Container == NULL || _Container == ctx.CurrentPrimitive);
2083 _Container = ctx.CurrentPrimitive;
2085 // generate a new alias, eventually keeping the current one if any and if still available
2086 _Alias = _Container->genAlias(this, _Alias);
2089 void CPrimAlias::onBranchUnlink()
2091 nlassert(_Container != NULL);
2092 _Container->releaseAlias(this, _Alias);
2093 _Container = NULL;
2095 // NB : we keep the alias value for next linkage
2098 uint32 CPrimAlias::getAlias() const
2100 return _Alias;
2103 uint32 CPrimAlias::getFullAlias() const
2105 nlassert(_Container != NULL);
2106 return _Container->buildFullAlias(_Alias);
2109 void CPrimAlias::regenAlias()
2111 // container must exist
2112 nlassert(_Container);
2113 // generate a new alias, eventually keeping the current one if any and if still available
2114 _Alias = _Container->genAlias(this, _Alias);
2118 // Read the primitive
2119 bool CPrimAlias::read (xmlNodePtr xmlNode, const std::string &filename, uint version, CLigoConfig &config)
2121 // Read alias
2122 xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "ALIAS");
2123 if (ptNode)
2125 sint val = 0;
2126 if (ReadInt ("VALUE", val, filename, ptNode))
2128 _Alias = uint32(val);
2130 // nlassert( CPrimitiveContext::instance().CurrentPrimitive);
2131 //// nlassert(_Container);
2132 // CPrimitiveContext::instance().CurrentPrimitive->reserveAlias(_Alias);
2133 // // set to null, it will be rewrited by onBranchLink callback
2134 //// _Container = NULL;
2136 else
2138 // error in format !
2139 nlwarning("CPrimAlias::read: Can't find xml property 'VALUE' in element <ALIAS>");
2140 return false;
2143 else
2145 // error in format !
2146 nlwarning("CPrimAlias::read: Can't find xml element <ALIAS>");
2147 return false;
2150 return IPrimitive::read (xmlNode, filename, version, config);
2152 // Write the primitive
2153 void CPrimAlias::write (xmlNodePtr xmlNode, const std::string &filename) const
2155 // Write alias
2156 xmlNodePtr ptNode = xmlNewChild(xmlNode, NULL, (const xmlChar*)"ALIAS", NULL);
2157 WriteInt("VALUE", int(_Alias), ptNode);
2159 IPrimitive::write (xmlNode, filename);
2162 // Create a copy of this primitive
2163 IPrimitive *CPrimAlias::copy () const
2165 // NB : this will not call the reserveAlias on the container
2166 CPrimAlias *pa = new CPrimAlias(*this);
2168 // clear the alias and container reference
2169 // pa->_Alias = 0;
2170 // pa->_Container = 0;
2172 return pa;
2174 // serial for binary save
2175 void CPrimAlias::serial (NLMISC::IStream &f)
2177 IPrimitive::serial(f);
2179 f.serial(_Alias);
2181 // if (f.isReading())
2182 // {
2183 // nlassert(_Container);
2184 // _Container->reserveAlias(_Alias);
2185 // }
2189 // ***************************************************************************
2190 // CPrimitives
2191 // ***************************************************************************
2193 CPrimitives::CPrimitives () :
2194 _LigoConfig(NULL)
2196 // init the alias generator
2197 _LastGeneratedAlias = 0;
2198 _AliasStaticPart = 0;
2200 RootNode = static_cast<CPrimNode *> (CClassRegistry::create ("CPrimNode"));
2202 // get the current ligo context (if any)
2203 _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
2206 // ***************************************************************************
2208 CPrimitives::CPrimitives (const CPrimitives &other)
2210 operator =(other);
2211 // _LastGeneratedAlias = other._LastGeneratedAlias;
2212 // // get the current ligo context (if any)
2213 // _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
2215 // CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;
2216 // CPrimitiveContext::instance().CurrentPrimitive = this;
2217 // // copy the nodes
2218 // RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
2219 // RootNode->branchLink();
2221 // CPrimitiveContext::instance().CurrentPrimitive = temp;
2224 // ***************************************************************************
2226 CPrimitives::~CPrimitives ()
2228 delete RootNode;
2231 // ***************************************************************************
2233 uint32 CPrimitives::getAliasStaticPart()
2235 return _AliasStaticPart;
2238 // ***************************************************************************
2240 void CPrimitives::setAliasStaticPart(uint32 staticPart)
2242 _AliasStaticPart = staticPart;
2245 // ***************************************************************************
2247 uint32 CPrimitives::buildFullAlias(uint32 dynamicPart)
2249 if (_LigoConfig)
2251 return _LigoConfig->buildAlias(_AliasStaticPart, dynamicPart, true);
2253 else
2254 return dynamicPart;
2258 // ***************************************************************************
2260 uint32 CPrimitives::genAlias(IPrimitive *prim, uint32 preferedAlias)
2262 nlassert(_LigoConfig);
2263 uint32 ret;
2265 if (preferedAlias != 0)
2267 // only dynamic part allowed here
2268 nlassert(preferedAlias == (preferedAlias & _LigoConfig->getDynamicAliasMask()));
2269 // check is the prefered alias is not already in use
2270 map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(preferedAlias));
2271 if (it == _AliasInUse.end())
2273 // this alias is available, just use it
2274 // nldebug("Alias: added alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
2275 _AliasInUse.insert(make_pair(preferedAlias, prim));
2276 return preferedAlias;
2278 else
2280 // check who own the alias now
2281 if (it->second == prim)
2283 // ok, the alias is already own by this primitive
2284 // nldebug("Alias: using alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1);
2285 return preferedAlias;
2290 // make sure there are some free aliases
2291 uint32 mask = _LigoConfig->getDynamicAliasMask();
2292 nlassert(_AliasInUse.size() < mask);
2294 // increment alias counter
2295 ++_LastGeneratedAlias;
2296 // mask with the dynamic alias mask
2297 _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();
2299 ret = _LastGeneratedAlias;
2301 while (_AliasInUse.find(ret) != _AliasInUse.end())
2303 // this alias is already in use ! generate a new one
2304 // increment, mask, affect...
2305 ++_LastGeneratedAlias;
2306 _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();
2307 ret = _LastGeneratedAlias;
2310 // insert the alias
2311 // nldebug("Alias: added alias %u, %u alias in use", ret, _AliasInUse.size()+1);
2312 _AliasInUse.insert(make_pair(ret, prim));
2314 // callback
2315 prim->onModifyPrimitive (*this);
2317 return ret;
2320 //void CPrimitives::reserveAlias(uint32 dynamicAlias)
2322 // // need ligo config
2323 // nlassert(_LigoConfig);
2324 // // only dynamic part allowed here
2325 // nlassert(dynamicAlias == (dynamicAlias & _LigoConfig->getDynamicAliasMask()));
2326 // std::set<uint32>::iterator it(_AliasInUse.find(dynamicAlias));
2327 // // warn if already found
2328 // if (it != _AliasInUse.end())
2329 // {
2330 // const string &fileName = _LigoConfig->getFileNameForStaticAlias(_AliasStaticPart);
2331 // if (fileName.empty())
2332 // nlwarning("Dynamic Alias %u is already in use");
2333 // else
2334 // nlwarning("Dynamic Alias %u is already in use in file '%s'",
2335 // dynamicAlias,
2336 // fileName.c_str());
2337 // return;
2338 // }
2340 // // insert the alias
2341 // nldebug("Alias: added alias %u, %u alias in use", dynamicAlias, _AliasInUse.size()+1);
2342 // _AliasInUse.insert(dynamicAlias);
2345 void CPrimitives::releaseAlias(IPrimitive *prim, uint32 alias)
2347 // need ligo config
2348 nlassert(_LigoConfig);
2349 // only dynamic part allowed here
2350 nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));
2351 std::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));
2352 // need to be found
2353 nlassert(it != _AliasInUse.end());
2355 if (it->second != prim)
2357 nlwarning("CPrimitives::releaseAlias: The alias %u is own by another primitive !", alias);
2358 return;
2361 // remove this alias
2362 // nldebug("Alias: remove alias %u, %u alias left", it->first, _AliasInUse.size()-1);
2363 _AliasInUse.erase(it);
2366 // ***************************************************************************
2368 void CPrimitives::forceAlias(CPrimAlias *prim, uint32 alias)
2370 // need ligo config
2371 nlassert(_LigoConfig);
2372 // only dynamic part allowed here
2373 nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));
2375 // store the alias in the primitive
2376 prim->_Alias = alias;
2378 std::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));
2379 if (it != _AliasInUse.end() && it->second != prim)
2381 // we need to alloc and set a new alias for the current alias holder
2382 CPrimAlias *pa = static_cast<CPrimAlias*>(const_cast<IPrimitive*>(it->second));
2384 // reserve the alias for the new primitive
2385 it->second = prim;
2388 // and regen an alias for the old
2389 pa->regenAlias();
2391 else
2393 // just store the association
2394 _AliasInUse.insert(make_pair(alias, prim));
2399 // ***************************************************************************
2401 uint32 CPrimitives::getLastGeneratedAlias()
2403 return _LastGeneratedAlias;
2406 // ***************************************************************************
2408 IPrimitive *CPrimitives::getPrimitiveByAlias(uint32 primAlias)
2410 // check the static part of the alias
2411 uint32 staticAlias = _LigoConfig->getStaticAliasMask() & primAlias;
2412 staticAlias = staticAlias >> _LigoConfig->getDynamicAliasSize();
2413 if (staticAlias != _AliasStaticPart)
2414 return NULL;
2416 // clear the static part before searching
2417 primAlias &= _LigoConfig->getDynamicAliasMask();
2419 std::map<uint32, IPrimitive*>::const_iterator it(_AliasInUse.find(primAlias));
2421 if (it != _AliasInUse.end())
2422 return it->second->getParent();
2423 else
2424 return NULL;
2427 // ***************************************************************************
2429 void CPrimitives::buildPrimitiveWithAliasList(std::map<uint32, IPrimitive*> &result)
2431 nlassert(_LigoConfig != NULL);
2433 std::map<uint32, IPrimitive*>::iterator first(_AliasInUse.begin()), last(_AliasInUse.end());
2434 for (; first != last; ++first)
2436 result.insert(make_pair(_LigoConfig->buildAlias(_AliasStaticPart, first->first), first->second->getParent()));
2440 // ***************************************************************************
2442 CPrimitives& CPrimitives::operator= (const CPrimitives &other)
2444 // RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
2445 // return *this;
2447 _AliasStaticPart = other._AliasStaticPart;
2448 _LastGeneratedAlias = other._LastGeneratedAlias;
2449 // get the current ligo context (if any)
2450 _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;
2452 CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;
2453 CPrimitiveContext::instance().CurrentPrimitive = this;
2454 // copy the nodes
2455 RootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());
2456 RootNode->branchLink();
2458 CPrimitiveContext::instance().CurrentPrimitive = temp;
2460 return *this;
2463 // ***************************************************************************
2465 bool CPrimitives::read (xmlNodePtr xmlNode, const std::string &filename, CLigoConfig &config)
2467 nlassert (xmlNode);
2469 _Filename = CFile::getFilename(filename);
2470 if (_LigoConfig)
2472 // try to get the static alias mapping
2473 _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(CFile::getFilename(filename));
2476 // Clear the primitives
2477 RootNode->removeChildren ();
2478 RootNode->removeProperties ();
2480 // Get the name
2481 if (strcmp ((const char*)xmlNode->name, "PRIMITIVES") == 0)
2483 // Get the version
2484 string versionName = "0";
2485 if (GetPropertyString (versionName, filename, xmlNode, "VERSION"))
2487 // Get the version
2488 uint32 version = atoi (versionName.c_str ());
2490 // Check the version
2491 if (version <= NLLIGO_PRIMITIVE_VERSION)
2493 // Read the primitives
2494 xmlNode = GetFirstChildNode (xmlNode, filename, "ROOT_PRIMITIVE");
2495 if (xmlNode)
2497 if (version > 0)
2499 xmlNodePtr subNode = GetFirstChildNode(xmlNode, filename, "ALIAS");
2500 if (subNode)
2502 uint temp;
2503 ReadUInt("LAST_GENERATED", temp, filename, subNode);
2504 _LastGeneratedAlias = temp;
2506 else
2507 _LastGeneratedAlias = 0;
2509 else
2510 _LastGeneratedAlias = 0;
2512 // Read the primitive tree
2513 ((IPrimitive*)RootNode)->read (xmlNode, filename, version, config);
2516 else
2518 Error (filename, "CPrimitives::read : Unknown file version (%u)", version);
2519 return false;
2522 else
2524 return false;
2527 else
2529 XMLError (xmlNode, filename, "This XML document is not a NeL primitive file");
2530 return false;
2533 return true;
2536 // ***************************************************************************
2538 void CPrimitives::write (xmlDocPtr doc, const std::string &filename) const
2540 nlassert (doc);
2542 // Primitive node
2543 xmlNodePtr primNode = xmlNewDocNode (doc, NULL, (const xmlChar*)"PRIMITIVES", NULL);
2544 xmlDocSetRootElement (doc, primNode);
2546 write (primNode, filename);
2549 // ***************************************************************************
2551 void CPrimitives::write (xmlNodePtr root, const std::string &filename) const
2553 nlassert (root);
2555 // Version node
2556 xmlSetProp (root, (const xmlChar*)"VERSION", (const xmlChar*)toString (NLLIGO_PRIMITIVE_VERSION).c_str ());
2558 // The primitive root node
2559 xmlNodePtr nameNode = xmlNewChild ( root, NULL, (const xmlChar*)"ROOT_PRIMITIVE", NULL);
2560 xmlNodePtr subNode = xmlNewChild ( nameNode, NULL, (const xmlChar*)"ALIAS", NULL);
2561 WriteUInt("LAST_GENERATED", _LastGeneratedAlias, subNode);
2563 // Write the primitive tree
2564 ((IPrimitive*)RootNode)->write (nameNode, filename);
2567 // ***************************************************************************
2569 void CPrimitives::serial(NLMISC::IStream &f)
2571 uint currentVersion = NLLIGO_PRIMITIVE_VERSION;
2572 f.serialVersion(currentVersion);
2574 if (currentVersion == 0)
2576 f.serial(_LastGeneratedAlias);
2579 if (f.isReading())
2581 RootNode->removeChildren ();
2582 RootNode->removeProperties ();
2584 f.serialPolyPtr(RootNode);
2585 f.serial(_Filename);
2586 if (f.isReading() && _LigoConfig)
2588 _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(_Filename);
2592 // ***************************************************************************
2594 void CPrimitives::convertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden)
2596 // The primitve
2597 IPrimitive *primitive = NULL;
2599 // What kind of primitive ?
2600 const CPrimPoint *oldPoint = dynamic_cast<const CPrimPoint *>(prim);
2601 if (oldPoint)
2603 // Create a primitive
2604 CPrimPoint *point = static_cast<CPrimPoint *> (CClassRegistry::create ("CPrimPoint"));
2605 primitive = point;
2607 // Copy it
2608 *point = *oldPoint;
2610 else
2612 // Path ?
2613 const CPrimPath *oldPath = dynamic_cast<const CPrimPath *>(prim);
2614 if (oldPath)
2616 // Create a primitive
2617 CPrimPath *path = static_cast<CPrimPath *> (CClassRegistry::create ("CPrimPath"));
2618 primitive = path;
2620 // Copy it
2621 *path = *oldPath;
2623 else
2625 const CPrimZone *oldZone = safe_cast<const CPrimZone *>(prim);
2626 if (oldZone)
2628 // Create a primitive
2629 CPrimZone *zone = static_cast<CPrimZone *> (CClassRegistry::create ("CPrimZone"));
2630 primitive = zone;
2632 // Copy it
2633 *zone = *oldZone;
2638 // Primitive has been created ?
2639 if (primitive)
2641 // Create a property for the name
2642 CPropertyString *nameProp = new CPropertyString;
2643 // nameProp->String = prim->Name;
2645 // Add the property
2646 primitive->addPropertyByName ("name", nameProp);
2648 // The primitive is hidden ?
2649 if (hidden)
2651 // Create a property for hidden
2652 nameProp = new CPropertyString;
2654 // Add the property
2655 primitive->addPropertyByName ("hidden", nameProp);
2658 // Add the child
2659 child->insertChild (primitive);
2663 // ***************************************************************************
2665 void CPrimitives::convertPrimitive (const IPrimitive *prim, bool hidden)
2667 // Look for the group
2668 uint numChildren = RootNode->getNumChildren ();
2669 uint j;
2670 for (j=0; j<numChildren; j++)
2672 IPrimitive *child;
2673 nlverify (RootNode->getChild (child, j));
2674 const IProperty *prop;
2675 if (child->getPropertyByName ("name", prop))
2677 // Prop string
2678 const CPropertyString *name = dynamic_cast<const CPropertyString *>(prop);
2679 if (name)
2681 // This one ?
2682 /* if (name->String == prim->Layer)
2684 convertAddPrimitive (child, prim, hidden);
2685 break;
2687 */ }
2691 // Not found ?
2692 if (j==numChildren)
2694 // Create a node
2695 CPrimNode *primNode = static_cast<CPrimNode *> (CClassRegistry::create ("CPrimNode"));
2697 // Create a property for the layer
2698 CPropertyString *nameProp = new CPropertyString;
2699 // nameProp->String = prim->Layer;
2701 // Add the property
2702 primNode->addPropertyByName ("name", nameProp);
2704 // Add the child
2705 RootNode->insertChild (primNode);
2707 // Add the primitive
2708 convertAddPrimitive (primNode, prim, hidden);
2712 // ***************************************************************************
2714 void CPrimitives::convert (const CPrimRegion &region)
2716 // Delete
2717 RootNode->removeChildren ();
2718 RootNode->removeProperties ();
2720 // For each primitives
2721 uint i;
2722 for (i=0; i<region.VPoints.size (); i++)
2724 convertPrimitive (&(region.VPoints[i]), region.VHidePoints[i]);
2726 for (i=0; i<region.VPaths.size (); i++)
2728 convertPrimitive (&(region.VPaths[i]), region.VHidePaths[i]);
2730 for (i=0; i<region.VZones.size (); i++)
2732 convertPrimitive (&(region.VZones[i]), region.VHideZones[i]);
2736 // ***************************************************************************
2738 CPrimitiveContext::CPrimitiveContext():
2739 CurrentLigoConfig(NULL),
2740 CurrentPrimitive(NULL)
2745 static bool LIGORegistered = false;
2748 void Register ()
2750 if( LIGORegistered )
2752 nlinfo( "LIGO classes have already been registered." );
2753 return;
2756 NLMISC_REGISTER_CLASS(CPropertyString);
2757 NLMISC_REGISTER_CLASS(CPropertyStringArray);
2758 NLMISC_REGISTER_CLASS(CPropertyColor);
2759 NLMISC_REGISTER_CLASS(CPrimNode);
2760 NLMISC_REGISTER_CLASS(CPrimPoint);
2761 NLMISC_REGISTER_CLASS(CPrimPath);
2762 NLMISC_REGISTER_CLASS(CPrimZone);
2763 NLMISC_REGISTER_CLASS(CPrimAlias);
2765 LIGORegistered = true;
2768 // ***************************************************************************
2770 } // namespace NLLIGO