1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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
;
39 // 0.5 cm of precision
40 #define PORTALPRECISION 0.005
42 // ***************************************************************************
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
;
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)
87 // Clip portal with pyramid
90 p
.clip( &pyramid
[1], (uint
)pyramid
.size()-1 );
92 // Construct pyramid with clipped portal
93 if( p
.Vertices
.size() > 2 )
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
)
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()] );
120 // ***************************************************************************
121 bool CPortal::isInFront (CVector
&v
)
125 CVector v1
= _Poly
[1] - _Poly
[0];
126 CVector v2
= _Poly
[2] - _Poly
[0];
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
;
147 if( _Clusters
[1] == NULL
)
149 _Clusters
[1] = cluster
;
155 // ***************************************************************************
156 uint8
CPortal::getNbCluster()
159 if( _Clusters
[0] != NULL
)
161 if( _Clusters
[1] != NULL
)
166 // ***************************************************************************
167 bool CPortal::setPoly(const std::vector
<CVector
> &poly
)
171 if( poly
.size() < 3 )
174 // Check if the polygon is a plane
176 p
.make( poly
[0], poly
[1], poly
[2] );
179 for( i
= 0; i
< (poly
.size()-3); ++i
)
181 dist
= fabsf(p
*poly
[i
+3]);
182 if( dist
> PORTALPRECISION
)
186 // Check if the polygon is convex
187 /// \todo check if the polygon has the good orientation
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 )
208 // ***************************************************************************
209 void CPortal::getPoly(std::vector
<NLMISC::CVector
> &dest
) const
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
);
237 occName
= "no occlusion";
238 _OcclusionModelId
= CStringMapper::map(occName
);
242 occName
= "no occlusion";
243 _OpenOcclusionModelId
= CStringMapper::map(occName
);
247 std::string occName
= CStringMapper::unmap(_OcclusionModelId
);
248 if (occName
== "no occlusion")
251 occName
= CStringMapper::unmap(_OpenOcclusionModelId
);
252 if (occName
== "no occlusion")
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
)
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
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
;
288 float lambda
= (plane
.d
+np1
)/np2
;
290 // Checks the intersection belongs to the segment
291 if (lambda
< 0 || lambda
> 1.0f
)
294 // The intersection on the plane
295 CVector hit
= start
*lambda
+end
*(1.0f
-lambda
);
297 // Do convex test on each border
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
);
323 // all on same side, ok!