// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdligo.h" #include "nel/misc/types_nl.h" #include "nel/misc/hierarchical_timer.h" #include "nel/ligo/primitive.h" #include "nel/ligo/ligo_config.h" #include "nel/ligo/primitive_class.h" #include "nel/misc/i_xml.h" #include "nel/misc/path.h" using namespace NLMISC; using namespace std; const uint32 NLLIGO_PRIMITIVE_VERSION = 1; namespace NLLIGO { CPrimitiveContext *CPrimitiveContext::_Instance = NULL; // *************************************************************************** // XML helpers // *************************************************************************** void Error (const char *filename, const char *format, ...) { va_list args; va_start( args, format ); char buffer[1024]; vsnprintf( buffer, 1024, format, args ); va_end( args ); nlwarning ("In File (%s) %s", filename, buffer); } // *************************************************************************** void XMLError (xmlNodePtr xmlNode, const char *filename, const char *format, ... ) { va_list args; va_start( args, format ); char buffer[1024]; vsnprintf( buffer, 1024, format, args ); va_end( args ); Error (filename, "node (%s), line (%p) : %s", xmlNode->name, xmlNode->content, buffer); } // *************************************************************************** xmlNodePtr GetFirstChildNode (xmlNodePtr xmlNode, const char *filename, const char *childName) { // Call the CIXml version xmlNodePtr result = CIXml::getFirstChildNode (xmlNode, childName); if (result) return result; // Output a formated error XMLError (xmlNode, filename, "Can't find XML node named (%s)", childName); return NULL; } // *************************************************************************** bool GetPropertyString (string &result, const char *filename, xmlNodePtr xmlNode, const char *propName) { // Call the CIXml version if (!CIXml::getPropertyString (result, xmlNode, propName)) { // Output a formated error XMLError (xmlNode, filename, "Can't find XML node property (%s)", propName); return false; } return true; } // *************************************************************************** bool ReadInt (const char *propName, int &result, const char *filename, xmlNodePtr xmlNode) { string value; if (GetPropertyString (value, filename, xmlNode, propName)) { result = atoi (value.c_str ()); return true; } return false; } // *************************************************************************** void WriteInt (const char *propName, int value, xmlNodePtr xmlNode) { // Set properties xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ())); } // *************************************************************************** bool ReadUInt (const char *propName, uint &result, const char *filename, xmlNodePtr xmlNode) { string value; if (GetPropertyString (value, filename, xmlNode, propName)) { result = strtoul (value.c_str (), NULL, 10); return true; } return false; } // *************************************************************************** void WriteUInt (const char *propName, uint value, xmlNodePtr xmlNode) { // Set properties xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ())); } // *************************************************************************** bool ReadFloat (const char *propName, float &result, const char *filename, xmlNodePtr xmlNode) { string value; if (GetPropertyString (value, filename, xmlNode, propName)) { NLMISC::fromString(value, result); return true; } return false; } // *************************************************************************** void WriteFloat (const char *propName, float value, xmlNodePtr xmlNode) { // Set properties xmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ())); } // *************************************************************************** bool ReadVector (CPrimVector &point, const char *filename, xmlNodePtr xmlNode) { CPrimVector pos; if (ReadFloat ("X", pos.x, filename, xmlNode)) { if (ReadFloat ("Y", pos.y, filename, xmlNode)) { if (ReadFloat ("Z", pos.z, filename, xmlNode)) { pos.Selected = false; string result; if (CIXml::getPropertyString (result, xmlNode, "SELECTED")) { if (result == "true") pos.Selected = true; } point = pos; return true; } } } return false; } // *************************************************************************** void WriteVector (const CPrimVector &point, xmlNodePtr xmlNode) { // Set properties xmlSetProp (xmlNode, (const xmlChar*)"X", (const xmlChar*)(toString (point.x).c_str ())); xmlSetProp (xmlNode, (const xmlChar*)"Y", (const xmlChar*)(toString (point.y).c_str ())); xmlSetProp (xmlNode, (const xmlChar*)"Z", (const xmlChar*)(toString (point.z).c_str ())); if (point.Selected) xmlSetProp (xmlNode, (const xmlChar*)"SELECTED", (const xmlChar*)"true"); } // *************************************************************************** bool GetNodeString (string &result, const char *filename, xmlNodePtr xmlNode, const char *nodeName) { // Look for the node xmlNodePtr node = CIXml::getFirstChildNode (xmlNode, nodeName); if (!node) { XMLError (xmlNode, filename, "Can't find XML node named (%s)", nodeName); return false; } // Get the node string if (!CIXml::getContentString (result, node)) { XMLError (xmlNode, filename, "Can't find any text in the node named (%s)", nodeName); return false; } return true; } // *************************************************************************** bool GetContentString (string &result, const char *filename, xmlNodePtr xmlNode) { // Get the node string if (!CIXml::getContentString (result, xmlNode)) { XMLError (xmlNode, filename, "Can't find any text in the node"); return false; } return true; } // *************************************************************************** // CPropertyString // *************************************************************************** CPropertyString::CPropertyString (const char *str) { String = str; } CPropertyString::CPropertyString (const std::string &str) { String = str; } // *************************************************************************** CPropertyString::CPropertyString (const char *str, bool _default) { String = str; Default = _default; } // *************************************************************************** // CPropertyStringArray // *************************************************************************** CPropertyStringArray::CPropertyStringArray (const std::vector &stringArray) { StringArray = stringArray; } // *************************************************************************** CPropertyStringArray::CPropertyStringArray (const std::vector &stringArray, bool _default) { StringArray = stringArray; Default = _default; } // *************************************************************************** void CPrimPoint::serial (NLMISC::IStream &f) { // serial base info IPrimitive::serial(f); f.serial(Point); f.serial(Angle); } // *************************************************************************** void CPrimPath::serial (NLMISC::IStream &f) { IPrimitive::serial(f); f.serialCont(VPoints); } // *************************************************************************** bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector &points) { uint32 i; CVector vMin, vMax; // Point or line can't contains ! if (points.size() < 3) return false; // Get the bounding rectangle of the zone vMax = vMin = points[0]; for (i = 0; i < points.size(); ++i) { if (vMin.x > points[i].x) vMin.x = points[i].x; if (vMin.y > points[i].y) vMin.y = points[i].y; if (vMax.x < points[i].x) vMax.x = points[i].x; if (vMax.y < points[i].y) vMax.y = points[i].y; } if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y)) return false; uint32 nNbIntersection = 0; for (i = 0; i < points.size(); ++i) { const CVector &p1 = points[i]; const CVector &p2 = points[(i+1)%points.size()]; if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0)) continue; if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0)) continue; float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y)); if (xinter > v.x) ++nNbIntersection; } if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside return true; else return false; } // *************************************************************************** bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector &points) { uint32 i; CVector vMin, vMax; // Point or line can't contains ! if (points.size() < 3) return false; // Get the bounding rectangle of the zone vMax = vMin = points[0]; for (i = 0; i < points.size(); ++i) { if (vMin.x > points[i].x) vMin.x = points[i].x; if (vMin.y > points[i].y) vMin.y = points[i].y; if (vMax.x < points[i].x) vMax.x = points[i].x; if (vMax.y < points[i].y) vMax.y = points[i].y; } if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y)) return false; uint32 nNbIntersection = 0; for (i = 0; i < points.size(); ++i) { const CVector &p1 = points[i]; const CVector &p2 = points[(i+1)%points.size()]; if (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0)) continue; if (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0)) continue; float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y)); if (xinter > v.x) ++nNbIntersection; } if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside return true; else return false; } // *************************************************************************** // CPrimNode // *************************************************************************** bool CPrimNode::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config) { return IPrimitive::read (xmlNode, filename, version, config); } // *************************************************************************** uint CPrimNode::getNumVector () const { return 0; } // *************************************************************************** const CPrimVector *CPrimNode::getPrimVector () const { return NULL; } // *************************************************************************** CPrimVector *CPrimNode::getPrimVector () { return NULL; } // *************************************************************************** NLLIGO::IPrimitive *CPrimNode::copy () const { return new CPrimNode (*this); } // *************************************************************************** // CPrimNode // *************************************************************************** /*void CPrimNode::operator= (const CPrimNode &node) { // Copy the IPrimitive IPrimitive::operator= (node); } // *************************************************************************** void CPrimPoint::operator= (const CPrimPoint &node) { // Copy the IPrimitive IPrimitive::operator= (node); } // *************************************************************************** void CPrimPath::operator= (const CPrimPath &node) { // Copy the IPrimitive } // *************************************************************************** void CPrimZone::operator= (const CPrimZone &node) { // Copy the IPrimitive IPrimitive::operator= (node); } */ // *************************************************************************** uint CPrimPoint::getNumVector () const { return 1; } // *************************************************************************** const CPrimVector *CPrimPoint::getPrimVector () const { return &Point; } // *************************************************************************** CPrimVector *CPrimPoint::getPrimVector () { return &Point; } // *************************************************************************** NLLIGO::IPrimitive *CPrimPoint::copy () const { return new CPrimPoint (*this); } // *************************************************************************** bool CPrimPoint::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config) { // Read points xmlNodePtr ptNode = GetFirstChildNode (xmlNode, filename, "PT"); if (ptNode) { // Read a vector if (!ReadVector (Point, filename, ptNode)) return false; ptNode = CIXml::getFirstChildNode (xmlNode, "ANGLE"); if (ptNode) { // Read a float if (!ReadFloat ("VALUE", Angle, filename, ptNode)) return false; } else Angle = 0; } else { return false; } return IPrimitive::read (xmlNode, filename, version, config); } // *************************************************************************** void CPrimPoint::write (xmlNodePtr xmlNode, const char *filename) const { // Save the point xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PT", NULL); WriteVector (Point, ptNode); // Save the angle if (Angle != 0) { xmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"ANGLE", NULL); WriteFloat ("VALUE", Angle, ptNode); } IPrimitive::write (xmlNode, filename); } // *************************************************************************** // CPrimPath // *************************************************************************** uint CPrimPath::getNumVector () const { return (uint)VPoints.size (); } // *************************************************************************** const CPrimVector *CPrimPath::getPrimVector () const { if (VPoints.empty()) return NULL; return &(VPoints[0]); } // *************************************************************************** NLLIGO::IPrimitive *CPrimPath::copy () const { return new CPrimPath (*this); } // *************************************************************************** CPrimVector *CPrimPath::getPrimVector () { if (VPoints.empty()) return NULL; return &(VPoints[0]); } // *************************************************************************** bool CPrimPath::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config) { // Read points VPoints.clear (); VPoints.reserve (CIXml::countChildren (xmlNode, "PT")); xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "PT"); if (ptNode) { do { // Read a vector VPoints.push_back (CPrimVector ()); if (!ReadVector (VPoints.back (), filename, ptNode)) return false; ptNode = CIXml::getNextChildNode (ptNode, "PT"); } while (ptNode); } return IPrimitive::read (xmlNode, filename, version, config); } // *************************************************************************** void CPrimPath::write (xmlNodePtr xmlNode, const char *filename) const { // Save the points for (uint i=0; i &points, float &distance, NLMISC::CVector &nearPos, bool isPath) { H_AUTO(NLLIGO_Contains1) uint32 i; CVector vMin, vMax; float nearest = FLT_MAX; CVector pos; // Point or line can't contains ! if (points.size() < 3 || isPath) { // only compute the distance. if (points.size() == 1) { distance = (points[0] - v).norm(); nearPos = points[0]; } else if (points.size() == 2) { distance = getSegmentDist(v, points[0], points[1], nearPos); } else { // compute nearest segment for (i = 0; i < points.size()-1; ++i) { const CVector &p1 = points[i]; const CVector &p2 = points[i+1]; float dist = getSegmentDist(v, p1, p2, pos); if( dist < nearest) { nearest = dist; nearPos = pos; } } distance = nearest; } return false; } // Get the bounding rectangle of the zone vMax = vMin = points[0]; for (i = 0; i < points.size(); ++i) { vMin.x = min(vMin.x, points[i].x); vMin.y = min(vMin.y, points[i].y); vMax.x = max(vMax.x, points[i].x); vMax.y = max(vMax.y, points[i].y); } if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y)) { // find the nearest distance of all segment for (uint i=0; i 0.0)&&((p2.y-v.y) > 0.0)) continue; float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y)); if (xinter > v.x) ++nNbIntersection; } distance = nearest; if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside return true; else return false; } // *************************************************************************** bool CPrimZone::contains (const NLMISC::CVector &v, const std::vector &points, float &distance, NLMISC::CVector &nearPos, bool isPath) { H_AUTO(NLLIGO_Contains2) uint32 i; CVector vMin, vMax; float nearest = FLT_MAX; CVector pos; // Point or line can't contains ! if (points.size() < 3 || isPath) { // only compute the distance. if (points.size() == 1) { distance = (points[0] - v).norm(); nearPos = points[0]; } else if (points.size() == 2) { distance = getSegmentDist(v, points[0], points[1], nearPos); } else { // compute nearest segment for (i = 0; i < points.size()-1; ++i) { const CVector &p1 = points[i]; const CVector &p2 = points[i+1]; float dist = getSegmentDist(v, p1, p2, pos); if( dist < nearest) { nearest = dist; nearPos = pos; } } distance = nearest; } return false; } // Get the bounding rectangle of the zone vMax = vMin = points[0]; for (i = 0; i < points.size(); ++i) { vMin.x = min(vMin.x, points[i].x); vMin.y = min(vMin.y, points[i].y); vMax.x = max(vMax.x, points[i].x); vMax.y = max(vMax.y, points[i].y); } if ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y)) { // find the nearest distance of all segment for (uint i=0; i 0.0)&&((p2.y-v.y) > 0.0)) continue; float xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y)); if (xinter > v.x) ++nNbIntersection; } distance = nearest; if ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside return true; else return false; } // *************************************************************************** float CPrimZone::getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos) { // two points, compute distance to the segment. CVector V = (p2-p1).normed(); double length= (p2-p1).norm(); float distance; // case where p1==p2 if(length==0.0) { nearPos= p1; distance = (p1-v).norm(); } // standard case else { float t = (float)((double)((v-p1)*V)/length); if (t < 0.0f) { nearPos = p1; distance = (p1-v).norm(); } else if (t > 1.0f) { nearPos = p2; distance = (p2-v).norm(); } else { nearPos = p1 + t*(p2-p1); distance = (v-nearPos).norm(); } } return distance; } // *************************************************************************** NLMISC::CVector CPrimZone::getBarycentre() const { CVector sum( CVector::Null ); uint n = (uint)VPoints.size(); if ( n != 0 ) { for ( uint i=0; i!=n; ++i ) sum += VPoints[i]; return sum / (float)n; } else return sum; } // *************************************************************************** void CPrimZone::getAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const { cornerMin.x = FLT_MAX; cornerMin.y = FLT_MAX; cornerMin.z = 0; cornerMax.x = -FLT_MAX; cornerMax.y = -FLT_MAX; cornerMax.z = 0; for ( uint i=0; i!=VPoints.size(); ++i ) { const CVector& p = VPoints[i]; if ( p.x < cornerMin.x ) cornerMin.x = p.x; if ( p.x > cornerMax.x ) cornerMax.x = p.x; if ( p.y < cornerMin.y ) cornerMin.y = p.y; if ( p.y > cornerMax.y ) cornerMax.y = p.y; } } // *************************************************************************** float CPrimZone::getAreaOfAABox() const { CVector cornerMin, cornerMax; getAABox( cornerMin, cornerMax ); return (cornerMax.x-cornerMin.x) * (cornerMax.y-cornerMin.y); } // *************************************************************************** void CPrimZone::serial (NLMISC::IStream &f) { IPrimitive::serial(f); f.serialCont(VPoints); } // *************************************************************************** void CPrimRegion::serial (NLMISC::IStream &f) { f.xmlPushBegin ("REGION"); f.xmlSetAttrib ("NAME"); f.serial (Name); f.xmlPushEnd(); sint version = 2; version = f.serialVersion (version); string check = "REGION"; f.serialCheck (check); f.xmlPush ("POINTS"); f.serialCont (VPoints); f.xmlPop (); f.xmlPush ("PATHES"); f.serialCont (VPaths); f.xmlPop (); f.xmlPush ("ZONES"); f.serialCont (VZones); f.xmlPop (); if (version > 1) { f.xmlPush ("HIDEPOINTS"); f.serialCont (VHidePoints); f.xmlPop (); f.xmlPush ("HIDEZONES"); f.serialCont (VHideZones); f.xmlPop (); f.xmlPush ("HIDEPATHS"); f.serialCont (VHidePaths); f.xmlPop (); } else { VHidePoints.resize (VPoints.size(), false); VHideZones.resize (VZones.size(), false); VHidePaths.resize (VPaths.size(), false); } } // *************************************************************************** // IPrimitive // *************************************************************************** IPrimitive::IPrimitive () { _Parent = NULL; } IPrimitive::IPrimitive (const IPrimitive &node) : IStreamable() { _Parent = NULL; IPrimitive::operator= (node); } // *************************************************************************** void IPrimitive::serial (NLMISC::IStream &f) { // NB : unparsed parameters are not binary serialized ! // serialize the property container if (f.isReading()) { uint32 size; f.serial(size); for (uint i=0; i::iterator first(_Properties.begin()), last(_Properties.end()); for (; first != last; ++first) { std::string &s = const_cast(first->first); f.serial(s); f.serialPolyPtr(first->second); } } f.serial(_ChildId); // f.serial(Layer); // f.serial(Name); // f.serial(Expanded); // serial the childrens if (f.isReading()) { std::vector children; f.serialContPolyPtr(children); uint index = 0; for(std::vector::iterator it = children.begin(); it != children.end(); ++it, ++index) { insertChild(*it, index); } } else { f.serialContPolyPtr(_Children); } if (f.isReading()) { // reloc child link vector::iterator first(_Children.begin()), last(_Children.end()); for (; first != last; ++first) { if (*first) (*first)->_Parent = this; } } } // *************************************************************************** void IPrimitive::updateChildId (uint index) { uint i; uint count = (uint)_Children.size (); for (i=index; i_ChildId = i; } // *************************************************************************** void IPrimitive::branchLink() { onBranchLink(); std::vector::iterator first(_Children.begin()), last(_Children.end()); for (; first != last; ++first) { (*first)->branchLink(); } } // *************************************************************************** void IPrimitive::branchUnlink() { onBranchUnlink(); std::vector::iterator first(_Children.begin()), last(_Children.end()); for (; first != last; ++first) { (*first)->branchUnlink(); } } // *************************************************************************** void IPrimitive::operator= (const IPrimitive &node) { // Clean dest removeChildren (); removeProperties (); // copy deprecated param // Layer = node.Layer; // Name = node.Name; // copy unparsed properties _UnparsedProperties = node._UnparsedProperties; // Copy the flags // Expanded = node.Expanded; _ChildId = node._ChildId; // Copy children _Children.resize (node._Children.size ()); for (uint child = 0; child < node._Children.size (); child++) { // Copy the child _Children[child] = node._Children[child]->copy (); // Set the parent _Children[child]->_Parent = this; } // Copy properties std::map::const_iterator ite = node._Properties.begin (); while (ite != node._Properties.end ()) { // Get the property CPropertyString *propString = dynamic_cast(ite->second); if (propString) { // New property CPropertyString *newProp = new CPropertyString (); *newProp = *propString; _Properties.insert (std::map::value_type (ite->first, newProp)); } else { CPropertyStringArray *propStringArray = dynamic_cast(ite->second); if (propStringArray) { // New property CPropertyStringArray *newProp = new CPropertyStringArray (); *newProp = *propStringArray; _Properties.insert (std::map::value_type (ite->first, newProp)); } else { CPropertyColor *propColor = dynamic_cast(ite->second); nlverify (propColor); // New property CPropertyColor *newProp = new CPropertyColor (); *newProp = *propColor; _Properties.insert (std::map::value_type (ite->first, newProp)); } } ite++; } #ifdef NLLIGO_DEBUG _DebugClassName = node._DebugClassName; _DebugPrimitiveName = node._DebugPrimitiveName; #endif } const IPrimitive *IPrimitive::getPrimitive (const std::string &absoluteOrRelativePath) const { const IPrimitive *cursor=this; string path=absoluteOrRelativePath; if (path.find("//")==0) // an absolute path. { while (cursor->getParent()) cursor=cursor->getParent(); path.erase(0,2); } while (!path.empty()) { if (path.find("/")==0) { path.erase(0,1); continue; } if (path.find("..")==0) { cursor=cursor->getParent(); if (!cursor) return NULL; path.erase(0,2); continue; } string::size_type indexStr=path.find("/"); string childName; if (indexStr==string::npos) { childName=path; path=""; } else { childName=path.substr(0,indexStr); path.erase(0, indexStr); } childName=toUpper(childName); const IPrimitive*child=NULL; uint childIndex; for (childIndex=0;childIndexgetNumChildren();childIndex++) { cursor->getChild(child,childIndex); string name; if ( child->getPropertyByName("class", name) && toUpper(name)==childName ) break; } if (childIndex>=cursor->getNumChildren()) return NULL; cursor=child; } return cursor; } // *************************************************************************** bool IPrimitive::getProperty (uint index, std::string &property_name, const IProperty *&result) const { // Look for the property std::map::const_iterator ite = _Properties.begin (); while (ite != _Properties.end ()) { if (index == 0) { property_name = ite->first; result = ite->second; return true; } index--; ite ++; } nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).", index, _Properties.size ()); return false; } // *************************************************************************** bool IPrimitive::getProperty (uint index, std::string &property_name, IProperty *&result) { // Look for the property std::map::iterator ite = _Properties.begin (); while (ite != _Properties.end ()) { if (index == 0) { property_name = ite->first; result = ite->second; return true; } index--; ite ++; } nlwarning ("NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).", index, _Properties.size ()); return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, const IProperty *&result) const { // Look for the property std::map::const_iterator ite = _Properties.find (property_name); if (ite != _Properties.end ()) { result = ite->second; return true; } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, IProperty *&result) const { // Look for the property std::map::const_iterator ite = _Properties.find (property_name); if (ite != _Properties.end ()) { result = ite->second; return true; } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, std::string *&result) const { // Get the property IProperty *prop; if (getPropertyByName (property_name, prop)) { CPropertyString *strProp = dynamic_cast (prop); if (strProp) { result = &(strProp->String); return true; } else { nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name); } } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, std::string &result) const { // Get the property const IProperty *prop; if (getPropertyByName (property_name, prop)) { const CPropertyString *strProp = dynamic_cast (prop); if (strProp) { result = strProp->String; return true; } else { nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name); } } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, std::vector *&result) const { // Get the property IProperty *prop; if (getPropertyByName (property_name, prop)) { CPropertyStringArray *strProp = dynamic_cast (prop); if (strProp) { result = &(strProp->StringArray); return true; } else { nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name); } } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, const std::vector *&result) const { // Get the property IProperty *prop; if (getPropertyByName (property_name, prop)) { const CPropertyStringArray *strProp = dynamic_cast (prop); if (strProp) { result = &(strProp->StringArray); return true; } else { nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.", property_name); } } return false; } // *************************************************************************** bool IPrimitive::getPropertyByName (const char *property_name, NLMISC::CRGBA &result) const { // Get the property IProperty *prop; if (getPropertyByName (property_name, prop)) { const CPropertyColor *colorProp = dynamic_cast (prop); if (colorProp) { result = colorProp->Color; return true; } else { nlwarning ("NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a color.", property_name); } } return false; } // *************************************************************************** bool IPrimitive::removeProperty (uint index) { // Look for the property std::map::iterator ite = _Properties.begin (); while (ite != _Properties.end ()) { if (index == 0) { _Properties.erase (ite); return true; } index--; ite ++; } nlwarning ("NLLIGO::IPrimitive::removeProperty : invalid index (index : %d, size : %d).", index, _Properties.size ()); return false; } // *************************************************************************** bool IPrimitive::removePropertyByName (const char *property_name) { // Look for the property std::map::iterator ite = _Properties.find (property_name); if (ite != _Properties.end ()) { _Properties.erase (ite); return true; } return false; } // *************************************************************************** void IPrimitive::removeProperties () { std::map::iterator ite = _Properties.begin (); while (ite != _Properties.end ()) { delete ite->second; ite++; } _Properties.clear (); } // *************************************************************************** bool IPrimitive::getChild (const IPrimitive *&result, uint childId) const { if (childId < _Children.size ()) { result = _Children[childId]; return true; } else { nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).", childId, _Children.size ()); } return false; } // *************************************************************************** bool IPrimitive::getChild (IPrimitive *&result, uint childId) { if (childId < _Children.size ()) { result = _Children[childId]; return true; } else { nlwarning ("NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).", childId, _Children.size ()); } return false; } // *************************************************************************** bool IPrimitive::removeChild (IPrimitive *child) { uint childId; if (getChildId(childId, child)) { return removeChild(childId); } else { nlwarning("NLLIGO::IPrimitive::removeChild : invalid child, can't remove (child : %p)", child); } return false; } // *************************************************************************** bool IPrimitive::removeChild (uint childId) { if (childId < _Children.size ()) { delete _Children[childId]; _Children.erase (_Children.begin()+childId); updateChildId (childId); return true; } else { nlwarning ("NLLIGO::IPrimitive::removeChild : invalid index (index : %d, size %d).", childId, _Children.size ()); } return false; } // *************************************************************************** void IPrimitive::removeChildren () { // Erase children for (uint i=0; i<_Children.size (); i++) { delete _Children[i]; } _Children.clear (); } // *************************************************************************** bool IPrimitive::unlinkChild(IPrimitive *child) { uint childId; if (getChildId(childId, child)) { child->onUnlinkFromParent(); child->branchUnlink(); _Children.erase (_Children.begin()+childId); updateChildId (childId); child->_Parent = NULL; child->_ChildId = 0; return true; } else { nlwarning("NLLIGO::IPrimitive::unlinkChild : invalid child, can't unlink (child : %p)", child); } return false; } // *************************************************************************** bool IPrimitive::insertChild (IPrimitive *primitive, uint index) { // At the end ? if (index == AtTheEnd) index = (uint)_Children.size (); // Index valid ? if (index>_Children.size ()) return false; // Insert _Children.insert (_Children.begin () + index, primitive); // Update child id updateChildId (index); // Link to the parent primitive->_Parent = this; // signaling primitive->onLinkToParent(); primitive->branchLink(); return true; } // *************************************************************************** IPrimitive::~IPrimitive () { // Remove children removeChildren (); // Erase properties removeProperties (); } // *************************************************************************** bool IPrimitive::checkProperty(const std::string &property_name) const { if (_Properties.find(property_name) == _Properties.end()) return false; return true; } // *************************************************************************** bool IPrimitive::addPropertyByName (const char *property_name, IProperty *result) { bool inserted = _Properties.insert (std::map::value_type (property_name, result)).second; if (inserted) { return true; } return false; } // *************************************************************************** bool IPrimitive::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config) { // Erase old properties _Properties.clear (); // Read the unparsed properties (for editor view) xmlNodePtr commentNode = CIXml::getFirstChildNode(xmlNode, XML_COMMENT_NODE); if (commentNode) { if (!CIXml::getContentString(_UnparsedProperties, commentNode)) _UnparsedProperties = ""; } // Read the expanded flag // string expanded; // Expanded = true; // if (CIXml::getPropertyString (expanded, xmlNode, "EXPANDED")) // Expanded = (expanded != "false"); // Read the properties xmlNodePtr propNode; propNode = CIXml::getFirstChildNode (xmlNode, "PROPERTY"); if (propNode) { do { // Read the name string name; if (GetNodeString (name, filename, propNode, "NAME")) { // Get the property type string type; if (GetPropertyString (type, filename, propNode, "TYPE")) { // The property IProperty *property = NULL; // Check the type if (type == "string") { // Create a new property CPropertyString *propertyString = new CPropertyString; property = propertyString; // Read it if (!GetNodeString (propertyString->String, filename, propNode, "STRING")) { return false; } } else if (type == "string_array") { // Create a new property CPropertyStringArray *propertyStringArray = new CPropertyStringArray; property = propertyStringArray; // Read strings xmlNodePtr stringNode; propertyStringArray->StringArray.reserve (CIXml::countChildren (propNode, "STRING")); stringNode = CIXml::getFirstChildNode (propNode, "STRING"); if (stringNode) { do { // Add the string string content; GetContentString (content, filename, stringNode); propertyStringArray->StringArray.push_back (content); stringNode = CIXml::getNextChildNode (stringNode, "STRING"); } while (stringNode); } } else if (type == "color") { // Create a new property CPropertyColor *propertyColor= new CPropertyColor; property = propertyColor; // Read strings xmlNodePtr colorNode; colorNode = CIXml::getFirstChildNode (xmlNode, "COLOR"); string R, G, B, A; if (GetPropertyString (R, filename, colorNode, "R") && GetPropertyString (G, filename, colorNode, "G") && GetPropertyString (B, filename, colorNode, "B") && GetPropertyString (A, filename, colorNode, "A")) { sint32 sR=0, sG=0, sB=0, sA=255; sR = atoi (R.c_str ()); clamp (sR, 0, 255); sG = atoi (G.c_str ()); clamp (sG, 0, 255); sB = atoi (B.c_str ()); clamp (sB, 0, 255); sA = atoi (A.c_str ()); clamp (sR, 0, 255); propertyColor->Color.R = (uint8)sR; propertyColor->Color.G = (uint8)sG; propertyColor->Color.B = (uint8)sB; propertyColor->Color.A = (uint8)sA; } else return false; } // Property found ? if (property == NULL) { XMLError (propNode, filename, "IPrimitive::read : Unknown property type (%s)", type.c_str ()); return false; } // Add it _Properties.insert (std::map::value_type (name, property)); } else { return false; } } else { return false; } propNode = CIXml::getNextChildNode (propNode, "PROPERTY"); } while (propNode); } // Initialise default value initDefaultValues (config); // Read children xmlNodePtr childNode; childNode = CIXml::getFirstChildNode (xmlNode, "CHILD"); if (childNode) { do { // Get the property class string type; if (GetPropertyString (type, filename, childNode, "TYPE")) { // Primitive if (type=="node") type="CPrimNode"; if (type=="point") type="CPrimPoint"; if (type=="path") type="CPrimPath"; if (type=="zone") type="CPrimZone"; if (type=="alias") type="CPrimAlias"; IPrimitive *primitive = static_cast (CClassRegistry::create (type)); // Primitive type not found ? if (primitive == NULL) { XMLError (childNode, filename, "IPrimitive::read : Unknown primitive type (%s)", type.c_str ()); return false; } // Read it primitive->read (childNode, filename, version, config); // Add it insertChild (primitive); } else { return false; } childNode = CIXml::getNextChildNode (childNode, "CHILD"); } while (childNode); } #ifdef NLLIGO_DEBUG // store debug data getPropertyByName("class", _DebugClassName); getPropertyByName("name", _DebugPrimitiveName); #endif // Done return true; } // *************************************************************************** void IPrimitive::initDefaultValues (CLigoConfig &config) { // Get the primitive class const CPrimitiveClass *primitiveClass = config.getPrimitiveClass (*this); if (primitiveClass) { // For each properties uint count = (uint)primitiveClass->Parameters.size (); uint i; for (i=0; iParameters[i]; // Get the property IProperty *result; if (!getPropertyByName (parameter.Name.c_str(), result)) { // Create the property if ((parameter.Type == CPrimitiveClass::CParameter::StringArray) || (parameter.Type == CPrimitiveClass::CParameter::ConstStringArray)) result = new CPropertyStringArray(); else result = new CPropertyString(); nlverify (addPropertyByName (parameter.Name.c_str(), result)); } } // Set the default values for (i=0; iParameters[i]; CPropertyString *pString = NULL; CPropertyStringArray *pStringArray = NULL; IProperty *result; nlverify (getPropertyByName (parameter.Name.c_str(), result)); pString = dynamic_cast(result); if (!pString) pStringArray = dynamic_cast(result); // Property have default values ? if (pString) { // Empty string ? if (pString->String.empty()) { // Set as default pString->Default = true; parameter.getDefaultValue (pString->String, *this, *primitiveClass); } } else if (pStringArray) { // Empty string array ? if (pStringArray->StringArray.empty()) { // Set as default pStringArray->Default = true; parameter.getDefaultValue (pStringArray->StringArray, *this, *primitiveClass); } } } } } // *************************************************************************** void IPrimitive::write (xmlNodePtr xmlNode, const char *filename) const { // Save the expanded flag // if (!Expanded) // xmlSetProp (xmlNode, (const xmlChar*)"EXPANDED", (const xmlChar*)"false"); // Set the type xmlSetProp (xmlNode, (const xmlChar*)"TYPE", (const xmlChar*)(const_cast (this)->getClassName ().c_str ())); // Save the unparsed property if (!_UnparsedProperties.empty()) { xmlNodePtr commentNode = xmlNewComment((const xmlChar*)(_UnparsedProperties.c_str())); nlverify(commentNode); xmlAddChild(xmlNode, commentNode); } // Save the properties std::map::const_iterator ite = _Properties.begin (); while (ite != _Properties.end ()) { // Not a default property ? if (!ite->second->Default) { // Create new nodes xmlNodePtr propNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"PROPERTY", NULL); xmlNodePtr nameNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"NAME", NULL); xmlNodePtr textNode = xmlNewText ((const xmlChar *)(ite->first.c_str ())); xmlAddChild (nameNode, textNode); // Type const CPropertyString *str = dynamic_cast (ite->second); if (str) { // Set the type xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string"); // Create new nodes xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL); xmlNodePtr textNode = xmlNewText ((const xmlChar *)(str->String.c_str ())); xmlAddChild (stringNode, textNode); } else { // Should be an array const CPropertyStringArray *array = dynamic_cast (ite->second); if (array) { // Set the type xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"string_array"); // For each strings in the array for (uint i=0; iStringArray.size (); i++) { // Create new nodes xmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"STRING", NULL); xmlNodePtr textNode = xmlNewText ((const xmlChar *)(array->StringArray[i].c_str ())); xmlAddChild (stringNode, textNode); } } else { // Should be a color const CPropertyColor *color = safe_cast (ite->second); // Set the type xmlSetProp (propNode, (const xmlChar*)"TYPE", (const xmlChar*)"color"); // Create new nodes xmlNodePtr colorNode = xmlNewChild ( propNode, NULL, (const xmlChar*)"COLOR", NULL); xmlSetProp (colorNode, (const xmlChar*)"R", (const xmlChar*)toString (color->Color.R).c_str ()); xmlSetProp (colorNode, (const xmlChar*)"G", (const xmlChar*)toString (color->Color.G).c_str ()); xmlSetProp (colorNode, (const xmlChar*)"B", (const xmlChar*)toString (color->Color.B).c_str ()); xmlSetProp (colorNode, (const xmlChar*)"A", (const xmlChar*)toString (color->Color.A).c_str ()); } } } ite++; } // Save the children for (uint i=0; i<_Children.size (); i++) { // New node xmlNodePtr childNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)"CHILD", NULL); // Write it _Children[i]->write (childNode, filename); } } // *************************************************************************** bool IPrimitive::getChildId (uint &childId, const IPrimitive *child) const { childId = child->_ChildId; return true; } // *************************************************************************** uint IPrimitive::getNumProperty () const { return (uint)_Properties.size (); } // *************************************************************************** std::string IPrimitive::getName() const { std::string ret; getPropertyByName("name", ret); return ret; } // *************************************************************************** const std::string &IPrimitive::getUnparsedProperties() const { return _UnparsedProperties; } // *************************************************************************** void IPrimitive::setUnparsedProperties(const std::string &unparsedProperties) const { _UnparsedProperties = unparsedProperties; } // *************************************************************************** // CPrimAlias // *************************************************************************** CPrimAlias::CPrimAlias() : _Alias(0), _Container(NULL) { } CPrimAlias::CPrimAlias(const CPrimAlias &other) : IPrimitive(other) { // clear the container reference and alias _Container = NULL; _Alias = other._Alias; } CPrimAlias::~CPrimAlias() { if (_Container) onBranchUnlink(); } void CPrimAlias::onBranchLink() { CPrimitiveContext &ctx = CPrimitiveContext::instance(); // context must be set when handling alias nlassert(ctx.CurrentPrimitive); nlassert(_Container == NULL || _Container == ctx.CurrentPrimitive); _Container = ctx.CurrentPrimitive; // generate a new alias, eventually keeping the current one if any and if still available _Alias = _Container->genAlias(this, _Alias); } void CPrimAlias::onBranchUnlink() { nlassert(_Container != NULL); _Container->releaseAlias(this, _Alias); _Container = NULL; // NB : we keep the alias value for next linkage } uint32 CPrimAlias::getAlias() const { return _Alias; } uint32 CPrimAlias::getFullAlias() const { nlassert(_Container != NULL); return _Container->buildFullAlias(_Alias); } void CPrimAlias::regenAlias() { // container must exist nlassert(_Container); // generate a new alias, eventually keeping the current one if any and if still available _Alias = _Container->genAlias(this, _Alias); } // Read the primitive bool CPrimAlias::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config) { // Read alias xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "ALIAS"); if (ptNode) { sint val = 0; if (ReadInt ("VALUE", val, filename, ptNode)) { _Alias = uint32(val); // nlassert( CPrimitiveContext::instance().CurrentPrimitive); //// nlassert(_Container); // CPrimitiveContext::instance().CurrentPrimitive->reserveAlias(_Alias); // // set to null, it will be rewrited by onBranchLink callback //// _Container = NULL; } else { // error in format ! nlwarning("CPrimAlias::read: Can't find xml property 'VALUE' in element "); return false; } } else { // error in format ! nlwarning("CPrimAlias::read: Can't find xml element "); return false; } return IPrimitive::read (xmlNode, filename, version, config); } // Write the primitive void CPrimAlias::write (xmlNodePtr xmlNode, const char *filename) const { // Write alias xmlNodePtr ptNode = xmlNewChild(xmlNode, NULL, (const xmlChar*)"ALIAS", NULL); WriteInt("VALUE", int(_Alias), ptNode); IPrimitive::write (xmlNode, filename); } // Create a copy of this primitive IPrimitive *CPrimAlias::copy () const { // NB : this will not call the reserveAlias on the container CPrimAlias *pa = new CPrimAlias(*this); // clear the alias and container reference // pa->_Alias = 0; // pa->_Container = 0; return pa; } // serial for binary save void CPrimAlias::serial (NLMISC::IStream &f) { IPrimitive::serial(f); f.serial(_Alias); // if (f.isReading()) // { // nlassert(_Container); // _Container->reserveAlias(_Alias); // } } // *************************************************************************** // CPrimitives // *************************************************************************** CPrimitives::CPrimitives () : _LigoConfig(NULL) { // init the alias generator _LastGeneratedAlias = 0; _AliasStaticPart = 0; RootNode = static_cast (CClassRegistry::create ("CPrimNode")); // get the current ligo context (if any) _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig; } // *************************************************************************** CPrimitives::CPrimitives (const CPrimitives &other) { operator =(other); // _LastGeneratedAlias = other._LastGeneratedAlias; // // get the current ligo context (if any) // _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig; // // CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive; // CPrimitiveContext::instance().CurrentPrimitive = this; // // copy the nodes // RootNode = static_cast (((IPrimitive*)other.RootNode)->copy ()); // RootNode->branchLink(); // // CPrimitiveContext::instance().CurrentPrimitive = temp; } // *************************************************************************** CPrimitives::~CPrimitives () { delete RootNode; } // *************************************************************************** uint32 CPrimitives::getAliasStaticPart() { return _AliasStaticPart; } // *************************************************************************** void CPrimitives::setAliasStaticPart(uint32 staticPart) { _AliasStaticPart = staticPart; } // *************************************************************************** uint32 CPrimitives::buildFullAlias(uint32 dynamicPart) { if (_LigoConfig) { return _LigoConfig->buildAlias(_AliasStaticPart, dynamicPart, true); } else return dynamicPart; } // *************************************************************************** uint32 CPrimitives::genAlias(IPrimitive *prim, uint32 preferedAlias) { nlassert(_LigoConfig); uint32 ret; if (preferedAlias != 0) { // only dynamic part allowed here nlassert(preferedAlias == (preferedAlias & _LigoConfig->getDynamicAliasMask())); // check is the prefered alias is not already in use map::iterator it(_AliasInUse.find(preferedAlias)); if (it == _AliasInUse.end()) { // this alias is available, just use it // nldebug("Alias: added alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1); _AliasInUse.insert(make_pair(preferedAlias, prim)); return preferedAlias; } else { // check who own the alias now if (it->second == prim) { // ok, the alias is already own by this primitive // nldebug("Alias: using alias %u, %u alias used", preferedAlias, _AliasInUse.size()+1); return preferedAlias; } } } // make sure there are some free aliases uint32 mask = _LigoConfig->getDynamicAliasMask(); nlassert(_AliasInUse.size() < mask); // increment alias counter ++_LastGeneratedAlias; // mask with the dynamic alias mask _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask(); ret = _LastGeneratedAlias; while (_AliasInUse.find(ret) != _AliasInUse.end()) { // this alias is already in use ! generate a new one // increment, mask, affect... ++_LastGeneratedAlias; _LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask(); ret = _LastGeneratedAlias; } // insert the alias // nldebug("Alias: added alias %u, %u alias in use", ret, _AliasInUse.size()+1); _AliasInUse.insert(make_pair(ret, prim)); // callback prim->onModifyPrimitive (*this); return ret; } //void CPrimitives::reserveAlias(uint32 dynamicAlias) //{ // // need ligo config // nlassert(_LigoConfig); // // only dynamic part allowed here // nlassert(dynamicAlias == (dynamicAlias & _LigoConfig->getDynamicAliasMask())); // std::set::iterator it(_AliasInUse.find(dynamicAlias)); // // warn if already found // if (it != _AliasInUse.end()) // { // const string &fileName = _LigoConfig->getFileNameForStaticAlias(_AliasStaticPart); // if (fileName.empty()) // nlwarning("Dynamic Alias %u is already in use"); // else // nlwarning("Dynamic Alias %u is already in use in file '%s'", // dynamicAlias, // fileName.c_str()); // return; // } // // // insert the alias // nldebug("Alias: added alias %u, %u alias in use", dynamicAlias, _AliasInUse.size()+1); // _AliasInUse.insert(dynamicAlias); //} // void CPrimitives::releaseAlias(IPrimitive *prim, uint32 alias) { // need ligo config nlassert(_LigoConfig); // only dynamic part allowed here nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask())); std::map::iterator it(_AliasInUse.find(alias)); // need to be found nlassert(it != _AliasInUse.end()); if (it->second != prim) { nlwarning("CPrimitives::releaseAlias: The alias %u is own by another primitive !", alias); return; } // remove this alias // nldebug("Alias: remove alias %u, %u alias left", it->first, _AliasInUse.size()-1); _AliasInUse.erase(it); } // *************************************************************************** void CPrimitives::forceAlias(CPrimAlias *prim, uint32 alias) { // need ligo config nlassert(_LigoConfig); // only dynamic part allowed here nlassert(alias == (alias & _LigoConfig->getDynamicAliasMask())); // store the alias in the primitive prim->_Alias = alias; std::map::iterator it(_AliasInUse.find(alias)); if (it != _AliasInUse.end() && it->second != prim) { // we need to alloc and set a new alias for the current alias holder CPrimAlias *pa = static_cast(const_cast(it->second)); // reserve the alias for the new primitive it->second = prim; // and regen an alias for the old pa->regenAlias(); } else { // just store the association _AliasInUse.insert(make_pair(alias, prim)); } } // *************************************************************************** uint32 CPrimitives::getLastGeneratedAlias() { return _LastGeneratedAlias; } // *************************************************************************** IPrimitive *CPrimitives::getPrimitiveByAlias(uint32 primAlias) { // check the static part of the alias uint32 staticAlias = _LigoConfig->getStaticAliasMask() & primAlias; staticAlias = staticAlias >> _LigoConfig->getDynamicAliasSize(); if (staticAlias != _AliasStaticPart) return NULL; // clear the static part before searching primAlias &= _LigoConfig->getDynamicAliasMask(); std::map::const_iterator it(_AliasInUse.find(primAlias)); if (it != _AliasInUse.end()) return it->second->getParent(); else return NULL; } // *************************************************************************** void CPrimitives::buildPrimitiveWithAliasList(std::map &result) { nlassert(_LigoConfig != NULL); std::map::iterator first(_AliasInUse.begin()), last(_AliasInUse.end()); for (; first != last; ++first) { result.insert(make_pair(_LigoConfig->buildAlias(_AliasStaticPart, first->first), first->second->getParent())); } } // *************************************************************************** CPrimitives& CPrimitives::operator= (const CPrimitives &other) { // RootNode = static_cast (((IPrimitive*)other.RootNode)->copy ()); // return *this; _AliasStaticPart = other._AliasStaticPart; _LastGeneratedAlias = other._LastGeneratedAlias; // get the current ligo context (if any) _LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig; CPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive; CPrimitiveContext::instance().CurrentPrimitive = this; // copy the nodes RootNode = static_cast (((IPrimitive*)other.RootNode)->copy ()); RootNode->branchLink(); CPrimitiveContext::instance().CurrentPrimitive = temp; return *this; } // *************************************************************************** bool CPrimitives::read (xmlNodePtr xmlNode, const char *filename, CLigoConfig &config) { nlassert (xmlNode); _Filename = CFile::getFilename(filename); if (_LigoConfig) { // try to get the static alias mapping _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(CFile::getFilename(filename)); } // Clear the primitives RootNode->removeChildren (); RootNode->removeProperties (); // Get the name if (strcmp ((const char*)xmlNode->name, "PRIMITIVES") == 0) { // Get the version string versionName = "0"; if (GetPropertyString (versionName, filename, xmlNode, "VERSION")) { // Get the version uint32 version = atoi (versionName.c_str ()); // Check the version if (version <= NLLIGO_PRIMITIVE_VERSION) { // Read the primitives xmlNode = GetFirstChildNode (xmlNode, filename, "ROOT_PRIMITIVE"); if (xmlNode) { if (version > 0) { xmlNodePtr subNode = GetFirstChildNode(xmlNode, filename, "ALIAS"); if (subNode) { uint temp; ReadUInt("LAST_GENERATED", temp, filename, subNode); _LastGeneratedAlias = temp; } else _LastGeneratedAlias = 0; } else _LastGeneratedAlias = 0; // Read the primitive tree ((IPrimitive*)RootNode)->read (xmlNode, filename, version, config); } } else { Error (filename, "CPrimitives::read : Unknown file version (%d)", version); return false; } } else { return false; } } else { XMLError (xmlNode, filename, "This XML document is not a NeL primitive file"); return false; } return true; } // *************************************************************************** void CPrimitives::write (xmlDocPtr doc, const char *filename) const { nlassert (doc); // Primitive node xmlNodePtr primNode = xmlNewDocNode (doc, NULL, (const xmlChar*)"PRIMITIVES", NULL); xmlDocSetRootElement (doc, primNode); write (primNode, filename); } // *************************************************************************** void CPrimitives::write (xmlNodePtr root, const char *filename) const { nlassert (root); // Version node xmlSetProp (root, (const xmlChar*)"VERSION", (const xmlChar*)toString (NLLIGO_PRIMITIVE_VERSION).c_str ()); // The primitive root node xmlNodePtr nameNode = xmlNewChild ( root, NULL, (const xmlChar*)"ROOT_PRIMITIVE", NULL); xmlNodePtr subNode = xmlNewChild ( nameNode, NULL, (const xmlChar*)"ALIAS", NULL); WriteUInt("LAST_GENERATED", _LastGeneratedAlias, subNode); // Write the primitive tree ((IPrimitive*)RootNode)->write (nameNode, filename); } // *************************************************************************** void CPrimitives::serial(NLMISC::IStream &f) { uint currentVersion = NLLIGO_PRIMITIVE_VERSION; f.serialVersion(currentVersion); if (currentVersion == 0) { f.serial(_LastGeneratedAlias); } if (f.isReading()) { RootNode->removeChildren (); RootNode->removeProperties (); } f.serialPolyPtr(RootNode); f.serial(_Filename); if (f.isReading() && _LigoConfig) { _AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(_Filename); } } // *************************************************************************** void CPrimitives::convertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden) { // The primitve IPrimitive *primitive = NULL; // What kind of primitive ? const CPrimPoint *oldPoint = dynamic_cast(prim); if (oldPoint) { // Create a primitive CPrimPoint *point = static_cast (CClassRegistry::create ("CPrimPoint")); primitive = point; // Copy it *point = *oldPoint; } else { // Path ? const CPrimPath *oldPath = dynamic_cast(prim); if (oldPath) { // Create a primitive CPrimPath *path = static_cast (CClassRegistry::create ("CPrimPath")); primitive = path; // Copy it *path = *oldPath; } else { const CPrimZone *oldZone = safe_cast(prim); if (oldZone) { // Create a primitive CPrimZone *zone = static_cast (CClassRegistry::create ("CPrimZone")); primitive = zone; // Copy it *zone = *oldZone; } } } // Primitive has been created ? if (primitive) { // Create a property for the name CPropertyString *nameProp = new CPropertyString; // nameProp->String = prim->Name; // Add the property primitive->addPropertyByName ("name", nameProp); // The primitive is hidden ? if (hidden) { // Create a property for hidden nameProp = new CPropertyString; // Add the property primitive->addPropertyByName ("hidden", nameProp); } // Add the child child->insertChild (primitive); } } // *************************************************************************** void CPrimitives::convertPrimitive (const IPrimitive *prim, bool hidden) { // Look for the group uint numChildren = RootNode->getNumChildren (); uint j; for (j=0; jgetChild (child, j)); const IProperty *prop; if (child->getPropertyByName ("name", prop)) { // Prop string const CPropertyString *name = dynamic_cast(prop); if (name) { // This one ? /* if (name->String == prim->Layer) { convertAddPrimitive (child, prim, hidden); break; } */ } } } // Not found ? if (j==numChildren) { // Create a node CPrimNode *primNode = static_cast (CClassRegistry::create ("CPrimNode")); // Create a property for the layer CPropertyString *nameProp = new CPropertyString; // nameProp->String = prim->Layer; // Add the property primNode->addPropertyByName ("name", nameProp); // Add the child RootNode->insertChild (primNode); // Add the primitive convertAddPrimitive (primNode, prim, hidden); } } // *************************************************************************** void CPrimitives::convert (const CPrimRegion ®ion) { // Delete RootNode->removeChildren (); RootNode->removeProperties (); // For each primitives uint i; for (i=0; i