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/misc/hierarchical_timer.h"
20 #include "nel/misc/debug.h"
21 #include "nel/3d/driver.h"
22 #include "nel/3d/transform_shape.h"
23 #include "nel/3d/skeleton_model.h"
24 #include "nel/3d/mesh_base_instance.h"
25 #include "nel/3d/clip_trav.h"
26 #include "nel/3d/render_trav.h"
27 #include "nel/3d/load_balancing_trav.h"
28 #include "nel/3d/quad_grid_clip_cluster.h"
29 #include "nel/3d/scene.h"
32 using namespace NLMISC
;
42 // ***************************************************************************
43 void CTransformShape::registerBasic()
45 CScene::registerModel(TransformShapeId
, TransformId
, CTransformShape::creator
);
49 // ***************************************************************************
50 CTransformShape::CTransformShape()
52 _NumTrianglesAfterLoadBalancing
= 100;
53 _CurrentLightContribution
= NULL
;
54 _CurrentUseLocalAttenuation
= false;
56 // By default all transformShape are LoadBalancable
57 CTransform::setIsLoadbalancable(true);
59 // The model is renderable
60 CTransform::setIsRenderable(true);
62 // I am a CTransformShape
63 CTransform::setIsTransformShape(true);
67 // ***************************************************************************
68 float CTransformShape::getNumTriangles (float distance
)
71 return Shape
->getNumTriangles (distance
);
75 // ***************************************************************************
76 void CTransformShape::getAABBox(NLMISC::CAABBox
&bbox
) const
80 Shape
->getAABBox(bbox
);
84 bbox
.setCenter(CVector::Null
);
85 bbox
.setHalfSize(CVector::Null
);
90 // ***************************************************************************
91 void CTransformShape::setupCurrentLightContribution(CLightContribution
*lightContrib
, bool useLocalAtt
)
93 _CurrentLightContribution
= lightContrib
;
94 _CurrentUseLocalAttenuation
= useLocalAtt
;
97 // ***************************************************************************
98 void CTransformShape::changeLightSetup(CRenderTrav
*rdrTrav
)
100 // setup the instance lighting.
101 rdrTrav
->changeLightSetup(_CurrentLightContribution
, _CurrentUseLocalAttenuation
);
105 // ***************************************************************************
106 uint
CTransformShape::getNumMaterial () const
112 // ***************************************************************************
113 const CMaterial
*CTransformShape::getMaterial (uint
/* materialId */) const
119 // ***************************************************************************
120 CMaterial
*CTransformShape::getMaterial (uint
/* materialId */)
125 // ***************************************************************************
126 void CTransformShape::unlinkFromQuadCluster()
128 // if linked to a quadGridClipCluster, unlink it
129 _QuadClusterListNode
.unlink();
133 // ***************************************************************************
134 bool CTransformShape::clip()
136 H_AUTO( NL3D_TrShape_Clip
);
138 CClipTrav
&clipTrav
= getOwnerScene()->getClipTrav();
142 // first test DistMax (faster).
143 float maxDist
= getDistMax();
144 // if DistMax test enabled
148 float sqrDist
= (clipTrav
.CamPos
- getWorldMatrix().getPos()).sqrnorm ();
151 // if dist > maxDist, skip
152 if (sqrDist
> maxDist
)
159 // Else finer clip with pyramid, only if needed
160 if(clipTrav
.ForceNoFrustumClip
)
163 return Shape
->clip(clipTrav
.WorldPyramid
, getWorldMatrix());
170 // ***************************************************************************
171 void CTransformShape::traverseRender()
173 H_AUTO( NL3D_TrShape_Render
);
176 // Compute the current lighting setup for this instance
177 //===================
180 // if the transform is lightable (ie not a fully lightmaped model), setup lighting
183 // useLocalAttenuation for this shape ??
185 _CurrentUseLocalAttenuation
= Shape
->useLightingLocalAttenuation ();
187 _CurrentUseLocalAttenuation
= false;
189 // the std case is to take my model lightContribution
190 if(_AncestorSkeletonModel
==NULL
)
191 _CurrentLightContribution
= &getLightContribution();
192 // but if skinned/sticked (directly or not) to a skeleton, take its.
194 _CurrentLightContribution
= &((CTransformShape
*)_AncestorSkeletonModel
)->getLightContribution();
196 // else must disable the lightSetup
199 // setting NULL will disable all lights
200 _CurrentLightContribution
= NULL
;
201 _CurrentUseLocalAttenuation
= false;
209 CRenderTrav
&rdrTrav
= getOwnerScene()->getRenderTrav();
210 bool currentPassOpaque
= rdrTrav
.isCurrentPassOpaque();
212 // shape must be rendered in a CMeshBlockManager ??
213 float polygonCount
= 0.f
;
214 IMeshGeom
*meshGeom
= NULL
;
215 // true only if in pass opaque
216 if( currentPassOpaque
)
217 meshGeom
= Shape
->supportMeshBlockRendering(this, polygonCount
);
219 // if ok, add the meshgeom to the block manager.
222 CMeshBaseInstance
*inst
= safe_cast
<CMeshBaseInstance
*>(this);
223 rdrTrav
.MeshBlockManager
.addInstance(meshGeom
, inst
, polygonCount
);
228 // setup the lighting
229 changeLightSetup( &rdrTrav
);
232 IDriver
*drv
= rdrTrav
.getDriver();
233 Shape
->render( drv
, this, currentPassOpaque
);
239 // ***************************************************************************
240 void CTransformShape::profileRender()
242 // profile the shape.
245 CRenderTrav
&rdrTrav
= getOwnerScene()->getRenderTrav();
246 bool currentPassOpaque
= rdrTrav
.isCurrentPassOpaque();
248 Shape
->profileSceneRender( &rdrTrav
, this, currentPassOpaque
);
253 // ***************************************************************************
254 void CTransformShape::traverseLoadBalancing()
256 CLoadBalancingTrav
&loadTrav
= getOwnerScene()->getLoadBalancingTrav();
257 if(loadTrav
.getLoadPass()==0)
258 traverseLoadBalancingPass0();
260 traverseLoadBalancingPass1();
265 // ***************************************************************************
266 void CTransformShape::traverseLoadBalancingPass0()
268 CLoadBalancingTrav
&loadTrav
= getOwnerScene()->getLoadBalancingTrav();
269 CSkeletonModel
*skeleton
= getSkeletonModel();
271 // World Model position
272 const CVector
*modelPos
;
274 // If this isntance is binded or skinned to a skeleton, take the world matrix of this one as
275 // center for LoadBalancing Resolution.
278 // Take the root bone of the skeleton as reference (bone 0)
279 // And so get our position.
280 modelPos
= &skeleton
->Bones
[0].getWorldMatrix().getPos();
284 // get our position from
285 modelPos
= &getWorldMatrix().getPos();
289 // Then compute distance from camera.
290 float modelDist
= ( loadTrav
.CamPos
- *modelPos
).norm();
293 // Get the number of triangles this model use now.
294 _FaceCount
= getNumTriangles(modelDist
);
295 _LoadBalancingGroup
->addNbFacesPass0(_FaceCount
);
299 // ***************************************************************************
300 void CTransformShape::traverseLoadBalancingPass1()
302 // Show more polygons for upscaled shapes to preserve visual quality
304 if (getTransformMode() == RotEuler
|| getTransformMode() == RotQuat
)
306 factor
= std::max(1.0f
, std::max(getScale().x
, std::max(getScale().y
, getScale().z
)));
309 _FaceCount
= factor
* std::max(_FaceCount
, factor
* 200.0f
);
313 // Set the result into the instance.
314 _NumTrianglesAfterLoadBalancing
= _LoadBalancingGroup
->computeModelNbFace(_FaceCount
);
318 // ***************************************************************************
319 void CTransformShape::getLightHotSpotInWorld(CVector
&modelPos
, float &modelRadius
) const
322 // get the untransformed bbox from the model.
325 // get transformed center pos of bbox
326 modelPos= getWorldMatrix() * bbox.getCenter();
327 // If the model is a big lightable, must take radius from aabbox, else suppose 0 radius.
330 // get size of the bbox (bounding sphere)
331 modelRadius= bbox.getRadius();
335 // Assume 0 radius => faster computeLinearAttenuation()
340 // This method works well for Big Trees.
341 // TODO: generalize, saving a LightHotSpot per shape.
343 // get pos of object. Ie the hotSpot is the pivot.
344 modelPos
= getWorldMatrix().getPos();
345 // If the model is a big lightable, must take radius from aabbox, else suppose 0 radius.
348 // get the untransformed bbox from the model.
351 // get size of the bbox (bounding sphere)
352 modelRadius
= bbox
.getRadius();
356 // Assume 0 radius => faster computeLinearAttenuation()