// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/> // 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 <http://www.gnu.org/licenses/>. #ifndef NL_SURFACE_SPLITTER_H #define NL_SURFACE_SPLITTER_H #include "nel/misc/types_nl.h" #include "nel/pacs/local_retriever.h" #include "nel/pacs/quad_grid.h" #include <map> /** * TODO Class description * \author Benjamin Legros * \author Nevrax France * \date 2002 */ class CSurfaceSplitter { public: /// class CVector2s64; class CSurfaceId; class CChain; class CLoop; class CSurface; /// class CFixed64 { protected: sint64 _Value; public: CFixed64() : _Value(0) {} CFixed64(const sint64 &v) : _Value(v) {} CFixed64(const double &v) : _Value((sint64)(v*4294967296.0)) {} CFixed64(const CFixed64 &v) : _Value(v._Value) {} operator double(void) const { return ((double)_Value) / 4294967296.0; } operator float(void) const { return ((float)_Value) / 4294967296.0f; } operator sint64(void) const { return _Value; } CFixed64 operator + (const CFixed64 &f) const { return CFixed64(_Value + f._Value); } CFixed64 operator - (const CFixed64 &f) const { return CFixed64(_Value - f._Value); } CFixed64 operator - () const { return CFixed64(-_Value); } CFixed64 operator * (const CFixed64 &f) const { sint64 vh = _Value>>32; sint64 vl = _Value&0xffffffff; sint64 uh = f._Value>>32; sint64 ul = f._Value&0xffffffff; sint64 res = ((vh*uh)<<32)+(vh*ul+uh*vl)+((uint64)(vl*ul)>>32); double fres = ((double)res) / 4294967296.0; double cfres = (double)(*this) * (double)f; return CFixed64(res); } CFixed64 operator / (const CFixed64 &f) const { if (f._Value == 0) return CFixed64(); sint sign = 0; uint64 a = _Value; uint64 b = f._Value; if ((sint64)a < 0) a = -(sint64)a, sign ^= 1; if ((sint64)b < 0) b = -(sint64)b, sign ^= 1; uint64 lb = INT64_CONSTANT (0x8000000000000000); uint64 q = 0; uint64 nh = a>>32; uint64 nl = a<<32; while (lb != 0) { if (nh >= b) { q |= (lb+lb); nh -= b; } nh = (nh+nh) + (nl&lb ? 1 : 0); lb >>= 1; } // round final bit if (nh >= b) ++q; CFixed64 result(sign ? -(sint64)q : +(sint64)q ); return result; } CFixed64 &operator += (const CFixed64 &f) { _Value+=f._Value; return *this; } CFixed64 &operator -= (const CFixed64 &f) { _Value-=f._Value; return *this; } CFixed64 &operator *= (const CFixed64 &f) { *this = *this*f; return *this; } CFixed64 &operator /= (const CFixed64 &f) { *this = *this/f; return *this; } bool operator == (const CFixed64 &f) const { return _Value == f._Value; } bool operator != (const CFixed64 &f) const { return _Value != f._Value; } bool operator < (const CFixed64 &f) const { return _Value < f._Value; } bool operator <= (const CFixed64 &f) const { return _Value <= f._Value; } bool operator >= (const CFixed64 &f) const { return _Value >= f._Value; } bool operator > (const CFixed64 &f) const { return _Value > f._Value; } double sqnorm() const { return (double)(*this * *this); } double norm() const { return sqrt(sqnorm()); } }; /// class CVector2s64 { public: CFixed64 x; CFixed64 y; CVector2s64() : x(), y() {} CVector2s64(const sint64 &X, const sint64 &Y) : x(X), y(Y) {} CVector2s64(const CFixed64 &X, const CFixed64 &Y) : x(X), y(Y) {} CVector2s64(const NLMISC::CVector &v) : x(v.x), y(v.y) {} CVector2s64(const NLMISC::CVectorD &v) : x(v.x), y(v.y) {} CVector2s64(const NLPACS::CVector2s &v) : x(((sint64)v.x) << 25), y(((sint64)v.y) << 25) {} CVector2s64 operator + (const CVector2s64 &v) const { return CVector2s64(x+v.x, y+v.y); } CVector2s64 operator - (const CVector2s64 &v) const { return CVector2s64(x-v.x, y-v.y); } CVector2s64 operator * (sint64 s) const { return CVector2s64(x*CFixed64(s), y*CFixed64(s)); } CVector2s64 operator * (CFixed64 s) const { return CVector2s64(x*s, y*s); } CVector2s64 operator * (double s) const { return CVector2s64(x*CFixed64(s), y*CFixed64(s)); } CVector2s64 operator / (sint64 s) const { return CVector2s64(x*CFixed64(s), y*CFixed64(s)); } CVector2s64 operator / (CFixed64 s) const { return CVector2s64(x*s, y*s); } CVector2s64 operator / (double s) const { return CVector2s64(x*CFixed64(s), y*CFixed64(s)); } CFixed64 operator * (const CVector2s64 &v) const { return x*v.x + y*v.y; } CFixed64 operator ^ (const CVector2s64 &v) const { return x*v.y - y*v.x; } bool operator == (const CVector2s64 &v) const { return x == v.x && y == v.y; } bool operator != (const CVector2s64 &v) const { return x != v.x || y != v.y; } CVector2s64 &operator += (const CVector2s64 &v) { x += v.x; y += v.y; return *this; } CVector2s64 &operator -= (const CVector2s64 &v) { x -= v.x; y -= v.y; return *this; } CVector2s64 &operator *= (sint64 s) { CFixed64 ss(s); x *= ss; y *= ss; return *this; } CVector2s64 &operator *= (double s) { CFixed64 ss(s); x *= ss; y *= ss; return *this; } NLMISC::CVector asVector() const { return NLMISC::CVector((float)x, (float)y, 0.0f); } NLMISC::CVectorD asVectorD() const { return NLMISC::CVectorD((double)x, (double)y, 0.0); } }; /// class CSurfaceId { public: uint16 Instance; uint16 Surface; uint16 SubSurface; CSurfaceId(uint16 instance=65535, uint16 surface=65535, uint16 subsurface=0) : Instance(instance), Surface(surface), SubSurface(subsurface) {} bool operator == (const CSurfaceId &id) const { return Instance == id.Instance && Surface == id.Surface && SubSurface == id.SubSurface; } bool operator != (const CSurfaceId &id) const { return !(*this == id); } bool operator < (const CSurfaceId &id) const { if (Instance < id.Instance) return true; else if (Instance > id.Instance) return false; else if (Surface < id.Surface) return true; else if (Surface > id.Surface) return false; else return SubSurface < id.SubSurface; } bool operator > (const CSurfaceId &id) const { return id < *this; } bool operator <= (const CSurfaceId &id) const { return *this == id || *this < id; } bool operator >= (const CSurfaceId &id) const { return *this == id || id < *this; } }; /// class CChainId { public: CChainId(uint32 id=0) : Id(id) {} uint32 Id; bool operator == (const CChainId &id) const { return Id == id.Id; } bool operator != (const CChainId &id) const { return !(*this == id); } bool operator < (const CChainId &id) const { return Id < id.Id; } bool operator > (const CChainId &id) const { return id < *this; } bool operator <= (const CChainId &id) const { return *this == id || *this < id; } bool operator >= (const CChainId &id) const { return *this == id || id < *this; } }; /// class CEdgeId { public: CEdgeId(const CChainId &chain=CChainId(), uint edge=0) : Chain(chain), Edge(edge) {} CChainId Chain; uint Edge; }; typedef NLPACS::CQuadGrid<CEdgeId> TEdgeGrid; /// class CTipId { public: CTipId(uint32 id=0) : Id(id) {} uint32 Id; bool operator == (const CTipId &id) const { return Id == id.Id; } bool operator != (const CTipId &id) const { return !(*this == id); } bool operator < (const CTipId &id) const { return Id < id.Id; } bool operator > (const CTipId &id) const { return id < *this; } bool operator <= (const CTipId &id) const { return *this == id || *this < id; } bool operator >= (const CTipId &id) const { return *this == id || id < *this; } }; /// class CChain { public: CChainId Id; CSurfaceId Left; CSurfaceId Right; CTipId Start; CTipId Stop; std::vector<CVector2s64> Vertices; std::vector<TEdgeGrid::CIterator> Iterators; bool DontSplit; /// CChain() : DontSplit(false) {} /// void dump(bool forward) const { NLMISC::InfoLog->displayRawNL("Chain:%d[Left=%d:%d:%d,Right=%d:%d:%d]", Id.Id, Left.Instance, Left.Surface, Left.SubSurface, Right.Instance, Right.Surface, Right.SubSurface); sint i, j=0; if (forward) { for (i=0; i<(sint)Vertices.size(); ++i, ++j) NLMISC::InfoLog->displayRawNL("%d;%.3f;%.3f", j, (double)Vertices[i].x, (double)Vertices[i].y); } else { for (i=(sint)Vertices.size()-1; i>=0; --i, ++j) NLMISC::InfoLog->displayRawNL("%d;%.3f;%.3f", j, (double)Vertices[i].x, (double)Vertices[i].y); } } }; /// class CTip { public: CTipId Id; CVector2s64 Tip; std::vector<CChainId> Chains; }; /// class CLoop { public: CSurfaceId Surface; std::vector<CChainId> Chains; /// void dump(const CSurfaceSplitter &splitter) const { uint i; for (i=0; i<Chains.size(); ++i) { const CChain *chain = splitter.getChain(Chains[i]); if (chain != NULL) chain->dump(Surface == chain->Left); } } /// void removeChain(CChainId chain) { std::vector<CChainId>::iterator it; for (it=Chains.begin(); it!=Chains.end(); ) { if (*it == chain) it = Chains.erase(it); else ++it; } } /// class iterator { public: CSurfaceSplitter *pSplitter; CLoop *pLoop; sint Chain; CChain *pChain; sint ChainVertex; sint8 Direction; sint8 ChainDirection; iterator(CSurfaceSplitter *splitter=NULL, CLoop *loop=NULL, bool forward=true) : pSplitter(splitter), pLoop(loop), Chain(0), pChain(NULL), ChainVertex(0), Direction(0), ChainDirection(0) { Direction = forward ? +1 : -1; if (splitter == NULL || pLoop == NULL) return; Chain = (Direction>0 ? 0 : (sint)pLoop->Chains.size()-1); resetChain(); } iterator(const iterator &it) { *this = it; } iterator &operator = (const iterator &it) { pSplitter = it.pSplitter; pLoop = it.pLoop; Chain = it.Chain; pChain = it.pChain; ChainVertex = it.ChainVertex; Direction = it.Direction; return *this; } bool operator == (const iterator &it) { return pSplitter == it.pSplitter && pLoop == it.pLoop && Chain == it.Chain && ChainVertex == it.ChainVertex; } bool operator != (const iterator &it) { return !(*this == it); } // ++it iterator &operator ++ () { ChainVertex += ChainDirection; if (ChainVertex == 0 || ChainVertex == (sint)pChain->Vertices.size()-1) { Chain += Direction; resetChain(); } return *this; } // it++ iterator operator ++ (int) { iterator tmp(*this); ChainVertex += ChainDirection; if (ChainVertex == 0 || ChainVertex == (sint)pChain->Vertices.size()-1) { Chain += Direction; resetChain(); } return tmp; } void resetChain() { if (Chain < 0 || Chain == (sint)pLoop->Chains.size()) { pSplitter = NULL; pLoop = NULL; Chain = 0; pChain = NULL; ChainVertex = 0; Direction = 0; ChainDirection = 0; return; } pChain = pSplitter->getChain(pLoop->Chains[Chain]); ChainDirection = (pChain->Left == pLoop->Surface ? Direction : -Direction); ChainVertex = (ChainDirection>0 ? 0 : (sint)pChain->Vertices.size()-1); } CVector2s64 operator * () const { return pChain->Vertices[ChainVertex]; } }; }; /// class CSurface { public: CSurfaceId Id; std::vector<CLoop> Loops; /// void dump(const CSurfaceSplitter &splitter) const { NLMISC::InfoLog->displayRawNL("---Surface:%d:%d:%d", Id.Instance, Id.Surface, Id.SubSurface); uint i; for (i=0; i<Loops.size(); ++i) { NLMISC::InfoLog->displayRawNL("Loop:%d", i); Loops[i].dump(splitter); } } /// void removeChain(CChainId chain) { uint i; for (i=0; i<Loops.size(); ++i) Loops[i].removeChain(chain); } }; protected: typedef std::map<CSurfaceId, CSurface> TSurfaceMap; typedef std::map<CChainId, CChain> TChainMap; typedef std::map<CTipId, CTip> TTipMap; TSurfaceMap _Surfaces; uint _NumSurfaces; TChainMap _Chains; uint _NumChains; TTipMap _Tips; uint _NumTips; TEdgeGrid _Edges; public: /// Constructor CSurfaceSplitter(); /// void build(NLPACS::CLocalRetriever &lr); /// CSurface *getSurface(const CSurfaceId &id) { TSurfaceMap::iterator it = _Surfaces.find(id); return (it == _Surfaces.end() ? NULL : &((*it).second)); } /// CChain *getChain(const CChainId &id) { TChainMap::iterator it = _Chains.find(id); return (it == _Chains.end() ? NULL : &((*it).second)); } /// const CSurface *getSurface(const CSurfaceId &id) const { TSurfaceMap::const_iterator it = _Surfaces.find(id); return (it == _Surfaces.end() ? NULL : &((*it).second)); } /// const CChain *getChain(const CChainId &id) const { TChainMap::const_iterator it = _Chains.find(id); return (it == _Chains.end() ? NULL : &((*it).second)); } protected: /// void buildChain(NLPACS::CLocalRetriever &lr, uint chain); /// void buildSurface(NLPACS::CLocalRetriever &lr, uint surface); /// void initEdgeGrid(); /// void splitChains(); /// void splitChain(TChainMap::iterator it, uint &numInters); /// void dump() const { TSurfaceMap::const_iterator it; for (it=_Surfaces.begin(); it!=_Surfaces.end(); ++it) (*it).second.dump(*this); } /// void dumpChain(CChainId chain) const { TChainMap::const_iterator it = _Chains.find(chain); if (it == _Chains.end()) return; (*it).second.dump(true); } /// bool intersect(const CVector2s64 &v0, const CVector2s64 &v1, const CVector2s64 &c0, const CVector2s64 &c1, CVector2s64 &intersect, CFixed64 &ndist); /// CChainId addChain(const CSurfaceId &left, const CSurfaceId &right, const std::vector<CVector2s64> &points, bool dontSplit=false); /// void removeChain(CChainId chain); /// void replaceChain(CChainId chain, const std::vector<CChainId> &chains); }; #endif // NL_SURFACE_SPLITTER_H /* End of surface_splitter.h */