Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / mesh_instance.cpp
blobeef6e92a5bbdf2c2e824106183f7c5236ac7fefd
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/mesh_instance.h"
20 #include "nel/3d/mesh.h"
21 #include "nel/3d/skeleton_model.h"
22 #include "nel/3d/u_scene.h"
23 #include "nel/3d/scene.h"
24 #include <list>
26 using namespace std;
27 using namespace NLMISC;
29 #ifdef DEBUG_NEW
30 #define new DEBUG_NEW
31 #endif
33 namespace NL3D
36 // ***************************************************************************
37 CMeshInstance::CMeshInstance()
39 _ShadowMap= NULL;
41 // LoadBalancing is not useful for Mesh, because meshs cannot be reduced in faces.
42 // Override CTransformShape state.
43 CTransform::setIsLoadbalancable(false);
45 // Mesh support shadow map casting only
46 CTransform::setIsShadowMapCaster(true);
49 // ***************************************************************************
50 CMeshInstance::~CMeshInstance()
52 // Auto detach me from skeleton. Must do it here, not in ~CTransform().
53 if(_FatherSkeletonModel)
55 // detach me from the skeleton.
56 // hrc and clip hierarchy is modified.
57 _FatherSkeletonModel->detachSkeletonSon(this);
58 nlassert(_FatherSkeletonModel==NULL);
61 // delete the shadowMap
62 deleteShadowMap();
66 // ***************************************************************************
67 void CMeshInstance::registerBasic()
69 CScene::registerModel(MeshInstanceId, MeshBaseInstanceId, CMeshInstance::creator);
72 // ***************************************************************************
73 void CMeshInstance::setApplySkin(bool state)
75 // Call parents method
76 CMeshBaseInstance::setApplySkin (state);
78 // Get a pointer on the shape
79 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
81 // Recompute the id
82 if (state)
84 pMesh->computeBonesId (_FatherSkeletonModel);
87 // update the skeleton usage according to the mesh.
88 pMesh->updateSkeletonUsage(_FatherSkeletonModel, state);
92 // ***************************************************************************
93 const std::vector<sint32> *CMeshInstance::getSkinBoneUsage() const
95 // Get a pointer on the shape
96 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
98 // Recompute the id
99 pMesh->computeBonesId (_FatherSkeletonModel);
101 // get ids.
102 return &pMesh->getMeshGeom().getSkinBoneUsage();
106 // ***************************************************************************
107 const std::vector<NLMISC::CBSphere> *CMeshInstance::getSkinBoneSphere() const
109 // Get a pointer on the shape
110 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
112 // Recompute the id, and skin spheres, if needed
113 pMesh->computeBonesId (_FatherSkeletonModel);
115 // get it.
116 return &pMesh->getMeshGeom().getSkinBoneSphere();
120 // ***************************************************************************
121 bool CMeshInstance::isSkinnable() const
123 if(Shape==NULL)
124 return false;
126 // Get a pointer on the shape
127 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
129 // true if the mesh is skinned
130 return pMesh->getMeshGeom().isSkinned();
134 // ***************************************************************************
135 void CMeshInstance::renderSkin(float alphaMRM)
137 // Don't setup lighting or matrix in Skin. Done by the skeleton
139 if(Shape && getVisibility() != CHrcTrav::Hide)
141 // Get a pointer on the shape
142 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
144 // render the meshGeom
145 CMeshGeom &meshGeom= const_cast<CMeshGeom&>(pMesh->getMeshGeom ());
146 meshGeom.renderSkin( this, alphaMRM );
151 // ***************************************************************************
152 void CMeshInstance::initRenderFilterType()
154 if(Shape)
156 // If the Shape has a VP or not...
157 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
159 if( pMesh->getMeshGeom().hasMeshVertexProgram() )
160 _RenderFilterType= UScene::FilterMeshVP;
161 else
162 _RenderFilterType= UScene::FilterMeshNoVP;
166 // ***************************************************************************
167 bool CMeshInstance::supportIntersectSkin() const
169 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
170 CMeshGeom &meshGeom= const_cast<CMeshGeom&>(pMesh->getMeshGeom ());
171 return meshGeom.supportIntersectSkin();
174 // ***************************************************************************
175 bool CMeshInstance::intersectSkin(const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D)
177 // Get a pointer on the shape
178 CMesh *pMesh = NLMISC::safe_cast<CMesh *>((IShape*)Shape);
179 // render the meshGeom
180 CMeshGeom &meshGeom= const_cast<CMeshGeom&>(pMesh->getMeshGeom ());
181 return meshGeom.intersectSkin(this, toRaySpace, dist2D, distZ, computeDist2D);
184 // ***************************************************************************
185 // ***************************************************************************
186 // ShadowMapping
187 // ***************************************************************************
188 // ***************************************************************************
191 // ***************************************************************************
192 void CMeshInstance::generateShadowMap(const CVector &lightDir)
194 // get the driver for Texture Render
195 CScene *scene= getOwnerScene();
196 CRenderTrav &renderTrav= scene->getRenderTrav();
197 IDriver *driver= renderTrav.getAuxDriver();
199 if(!Shape)
200 return;
202 // update ShadowMap data if needed.
203 // ****
204 updateShadowMap(driver);
206 if(!_ShadowMap)
207 return;
209 // compute the ProjectionMatrix.
210 // ****
212 // get the BBox and localPosMatrix
213 CAABBox bbShape;
214 Shape->getAABBox(bbShape);
215 CMatrix localPosMatrix= getWorldMatrix();
216 localPosMatrix.setPos(CVector::Null);
218 // setup cameraMatrix with BBox and Enlarge For 1 pixel
219 CMatrix cameraMatrix;
220 _ShadowMap->buildCasterCameraMatrix(lightDir, localPosMatrix, bbShape, cameraMatrix);
223 // Render.
224 // ****
225 // setup the orhtogonal frustum and viewMatrix to include all the object.
226 driver->setFrustum(0,1,0,1,0,1,false);
227 driver->setupViewMatrix(cameraMatrix.inverted());
228 driver->setupModelMatrix(localPosMatrix);
230 // render the Mesh
231 CMaterial &castMat= renderTrav.getShadowMapManager().getCasterShadowMaterial();
232 CMesh *mesh= (CMesh*)(IShape*)Shape;
233 driver->activeVertexBuffer( const_cast<CVertexBuffer&>(mesh->getVertexBuffer()) );
234 for(uint mb=0;mb<mesh->getNbMatrixBlock();mb++)
236 for(uint rp=0;rp<mesh->getNbRdrPass(mb);rp++)
238 const CIndexBuffer &pb= mesh->getRdrPassPrimitiveBlock(mb, rp);
239 driver->activeIndexBuffer(const_cast<CIndexBuffer&>(pb));
240 driver->renderTriangles(castMat, 0, pb.getNumIndexes()/3);
244 // Infos.
245 // ****
247 // Compute the BackPoint: the first point to be shadowed.
248 CVector backPoint= bbShape.getCenter();
249 // get the 3/4 bottom of the shape
250 backPoint.z-= bbShape.getHalfSize().z/2;
251 backPoint= localPosMatrix * backPoint;
252 // Use the 3/4 bottom of the BBox minus the light direction in XY. NB: little hack:
253 // suppose no Rotate (but Z) and no scale
254 CVector ldir= lightDir;
255 ldir.z= 0;
256 ldir.normalize();
257 float lenXY= (CVector(bbShape.getHalfSize().x, bbShape.getHalfSize().y, 0)).norm();
258 backPoint-= ldir*lenXY;
260 // Compute LocalProjectionMatrix and other infos from cameraMatrix and backPoint?
261 _ShadowMap->buildProjectionInfos(cameraMatrix, backPoint, getShadowMapMaxDepth());
264 // ***************************************************************************
265 CShadowMap *CMeshInstance::getShadowMap()
267 return _ShadowMap;
270 // ***************************************************************************
271 void CMeshInstance::createShadowMap()
273 // create the shadowMap
274 if(!_ShadowMap)
276 _ShadowMap= new CShadowMap(&getOwnerScene()->getRenderTrav().getShadowMapManager());
277 getOwnerScene()->registerShadowCasterToList(this);
281 // ***************************************************************************
282 void CMeshInstance::deleteShadowMap()
284 if(_ShadowMap)
286 delete _ShadowMap;
287 _ShadowMap= NULL;
288 getOwnerScene()->unregisterShadowCasterToList(this);
292 // ***************************************************************************
293 void CMeshInstance::updateShadowMap(IDriver * /* driver */)
295 nlassert(_ShadowMap);
297 // create/update texture
298 if(_ShadowMap->getTextureSize()!=getOwnerScene()->getShadowMapTextureSize())
300 _ShadowMap->initTexture(getOwnerScene()->getShadowMapTextureSize());
305 // ***************************************************************************
306 bool CMeshInstance::computeWorldBBoxForShadow(NLMISC::CAABBox &worldBB)
308 // If even not visible or empty, no-op
309 if(!isHrcVisible() || !Shape)
310 return false;
312 // get the shape bbox
313 Shape->getAABBox(worldBB);
314 // transform into world
315 worldBB= CAABBox::transformAABBox(getWorldMatrix(), worldBB);
317 return true;
320 // ***************************************************************************
321 void CMeshInstance::renderIntoSkeletonShadowMap(CSkeletonModel *rootSkeleton, CMaterial &castMat)
324 Yoyo: Not Very Robuts here:
325 - suppose the MeshInstance don't have sons.
326 - suppose that the VertexBuffer doesn't have VertexColor (else castMat.color unused).
329 // If even not visible or empty, no-op
330 if(!isHrcVisible() || !Shape)
331 return;
333 // render into aux Driver
334 IDriver *driver= getOwnerScene()->getRenderTrav().getAuxDriver();
336 // **** Render the Skeleton Skins
337 // The model Matrix is special here. It must be the Skeleton World Matrix, minus The Root Skeleton pos.
338 CMatrix localPosMatrix;
339 localPosMatrix.setRot( getWorldMatrix() );
340 // NB: if this==rootSkeleton, then the final pos will be CVector::Null
341 localPosMatrix.setPos( getWorldMatrix().getPos() - rootSkeleton->getWorldMatrix().getPos() );
342 driver->setupModelMatrix(localPosMatrix);
344 // render the Mesh
345 CMesh *mesh= (CMesh*)(IShape*)Shape;
346 driver->activeVertexBuffer( const_cast<CVertexBuffer&>(mesh->getVertexBuffer()) );
347 for(uint mb=0;mb<mesh->getNbMatrixBlock();mb++)
349 for(uint rp=0;rp<mesh->getNbRdrPass(mb);rp++)
351 const CIndexBuffer &pb= mesh->getRdrPassPrimitiveBlock(mb, rp);
352 driver->activeIndexBuffer(const_cast<CIndexBuffer&>(pb));
353 driver->renderTriangles(castMat, 0, pb.getNumIndexes()/3);
360 } // NL3D