Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / portal.cpp
blob096dcd1293be9e15569c4a5828d50d352e52d623
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/portal.h"
20 #include "nel/misc/string_mapper.h"
21 #include "nel/misc/matrix.h"
22 #include "nel/misc/stream.h"
23 #include "nel/misc/polygon.h"
24 #include "nel/misc/triangle.h"
25 #include "nel/3d/scene.h"
26 #include "nel/3d/transform_shape.h"
27 #include "nel/3d/mesh_instance.h"
29 using namespace NLMISC;
30 using namespace std;
32 #ifdef DEBUG_NEW
33 #define new DEBUG_NEW
34 #endif
36 namespace NL3D
39 // 0.5 cm of precision
40 #define PORTALPRECISION 0.005
42 // ***************************************************************************
43 CPortal::CPortal()
45 /* ***********************************************
46 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
47 * It can be loaded/called through CAsyncFileManager for instance
48 * ***********************************************/
50 _Clusters[0] = _Clusters[1] = NULL;
51 _Opened = true;
52 _OcclusionModelId = CStringMapper::map("no occlusion");
53 _OpenOcclusionModelId = CStringMapper::map("no occlusion");
56 void CPortal::setOcclusionModel(const std::string &occlusionModel)
58 _OcclusionModelId = CStringMapper::map(occlusionModel);
60 const std::string &CPortal::getOcclusionModel()
62 return CStringMapper::unmap(_OcclusionModelId);
64 NLMISC::TStringId CPortal::getOcclusionModelId()
66 return _OcclusionModelId;
68 void CPortal::setOpenOcclusionModel(const std::string &occlusionModel)
70 _OpenOcclusionModelId = CStringMapper::map(occlusionModel);
72 const std::string &CPortal::getOpenOcclusionModel()
74 return CStringMapper::unmap(_OpenOcclusionModelId);
76 NLMISC::TStringId CPortal::getOpenOcclusionModelId()
78 return _OpenOcclusionModelId;
82 // ***************************************************************************
83 bool CPortal::clipPyramid (CVector &observer, std::vector<CPlane> &pyramid)
85 if (!_Opened || _Poly.size()<3)
86 return false;
87 // Clip portal with pyramid
88 CPolygon p;
89 p.Vertices = _Poly;
90 p.clip( &pyramid[1], (uint)pyramid.size()-1 );
92 // Construct pyramid with clipped portal
93 if( p.Vertices.size() > 2 )
95 uint i;
96 // Found the right orientation
97 CVector n = (p.Vertices[1]-p.Vertices[0])^(p.Vertices[2]-p.Vertices[0]);
98 if( ((observer-p.Vertices[0])*n) < 0.0f )
100 // Invert vertices
101 for( i = 0; i < (p.Vertices.size()/2); ++i )
103 CVector tmp = p.Vertices[i];
104 p.Vertices[i] = p.Vertices[p.Vertices.size()-1-i];
105 p.Vertices[p.Vertices.size()-1-i] = tmp;
108 // Make pyramid : preserve 0 and 1 plane which are near and far plane
109 pyramid.resize (p.Vertices.size()+2);
110 for( i = 0; i < (p.Vertices.size()); ++i )
112 pyramid[i+2].make( observer, p.Vertices[i], p.Vertices[(i+1)%p.Vertices.size()] );
114 return true;
117 return false;
120 // ***************************************************************************
121 bool CPortal::isInFront (CVector &v)
123 if( _Poly.size()<3 )
124 return false;
125 CVector v1 = _Poly[1] - _Poly[0];
126 CVector v2 = _Poly[2] - _Poly[0];
127 CVector n = v1^v2;
128 CVector pv = v - _Poly[0];
129 return ((n*pv) > 0.0f);
133 // ***************************************************************************
134 void CPortal::resetClusterLinks()
136 _Clusters[0] = _Clusters[1] = NULL;
139 // ***************************************************************************
140 bool CPortal::setCluster(CCluster *cluster)
142 if( _Clusters[0] == NULL )
144 _Clusters[0] = cluster;
145 return true;
147 if( _Clusters[1] == NULL )
149 _Clusters[1] = cluster;
150 return true;
152 return false;
155 // ***************************************************************************
156 uint8 CPortal::getNbCluster()
158 uint8 nRet = 0;
159 if( _Clusters[0] != NULL )
160 nRet++;
161 if( _Clusters[1] != NULL )
162 nRet++;
163 return nRet;
166 // ***************************************************************************
167 bool CPortal::setPoly(const std::vector<CVector> &poly)
169 uint i;
171 if( poly.size() < 3 )
172 return false;
174 // Check if the polygon is a plane
175 CPlane p;
176 p.make( poly[0], poly[1], poly[2] );
177 p.normalize();
178 float dist;
179 for( i = 0; i < (poly.size()-3); ++i )
181 dist = fabsf(p*poly[i+3]);
182 if( dist > PORTALPRECISION )
183 return false;
186 // Check if the polygon is convex
187 /// \todo check if the polygon has the good orientation
189 CPlane p2;
190 for( i = 0; i < (poly.size()-1); ++i )
192 p2.make( poly[i], poly[i+1], poly[i]+p.getNormal() );
193 for( j = 0; j < poly.size(); ++j )
194 if( (j != i) && (j != i+1) )
196 if( p2*poly[j] < 0.0f )
197 return false;
201 // Set the value
202 _LocalPoly = poly;
203 _Poly = poly;
205 return true;
208 // ***************************************************************************
209 void CPortal::getPoly(std::vector<NLMISC::CVector> &dest) const
211 dest = _LocalPoly;
215 // ***************************************************************************
216 void CPortal::serial (NLMISC::IStream& f)
218 /* ***********************************************
219 * WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
220 * It can be loaded/called through CAsyncFileManager for instance
221 * ***********************************************/
223 int version = f.serialVersion (1);
225 f.serialCont (_LocalPoly);
226 if (f.isReading())
227 _Poly = _LocalPoly;
228 f.serial (_Name);
230 if (version >= 1)
232 if (f.isReading())
234 std::string occName;
235 f.serial(occName);
236 if (occName.empty())
237 occName = "no occlusion";
238 _OcclusionModelId = CStringMapper::map(occName);
240 f.serial(occName);
241 if (occName.empty())
242 occName = "no occlusion";
243 _OpenOcclusionModelId = CStringMapper::map(occName);
245 else
247 std::string occName = CStringMapper::unmap(_OcclusionModelId);
248 if (occName == "no occlusion")
249 occName.clear();
250 f.serial(occName);
251 occName = CStringMapper::unmap(_OpenOcclusionModelId);
252 if (occName == "no occlusion")
253 occName.clear();
254 f.serial(occName);
259 // ***************************************************************************
260 void CPortal::setWorldMatrix (const CMatrix &WM)
262 for (uint32 i = 0; i < _LocalPoly.size(); ++i)
263 _Poly[i] = WM.mulPoint(_LocalPoly[i]);
266 // ***************************************************************************
267 bool CPortal::clipRay(const NLMISC::CVector &startWorld, const NLMISC::CVector &endWorld)
269 if(_Poly.size()<3)
270 return false;
272 // Avoid precision problem, make local to poly
273 const CVector &refVert= _Poly[0];
274 CVector start= startWorld - refVert;
275 CVector end= endWorld - refVert;
277 // compute the plane of this poly, local to polygon
278 CPlane plane;
279 plane.make(CVector::Null, _Poly[1] - refVert, _Poly[2] - refVert);
280 CVector normal = plane.getNormal();
282 float np1 = normal*end;
283 float np2 = np1-normal*start;
285 if (np2 == 0.0f)
286 return false;
288 float lambda = (plane.d+np1)/np2;
290 // Checks the intersection belongs to the segment
291 if (lambda < 0 || lambda > 1.0f)
292 return false;
294 // The intersection on the plane
295 CVector hit = start*lambda+end*(1.0f-lambda);
297 // Do convex test on each border
298 sint sign= 0;
299 uint polySize= (uint)_Poly.size();
300 for(uint i=0;i<polySize;i++)
302 const CVector v0= _Poly[i] - refVert;
303 const CVector v1= _Poly[(i+1)%polySize] - refVert;
304 float d = ((v1-v0)^normal)*(hit-v0);
305 if(d<0)
307 if(sign==1)
308 return false;
309 else
310 sign=-1;
312 else if(d>0)
314 if(sign==-1)
315 return false;
316 else
317 sign=1;
319 else
320 return false;
323 // all on same side, ok!
324 return true;
328 } // NL3D