// NeL - MMORPG Framework // 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 . #ifndef NL_MESH_MRM_H #define NL_MESH_MRM_H #include "nel/misc/types_nl.h" #include "nel/3d/shape.h" #include "nel/3d/driver.h" #include "nel/misc/aabbox.h" #include "nel/misc/uv.h" #include "nel/3d/vertex_buffer.h" #include "nel/3d/material.h" #include "nel/3d/index_buffer.h" #include "nel/3d/animated_material.h" #include "nel/3d/mesh_base.h" #include "nel/3d/mesh.h" #include "nel/3d/mrm_mesh.h" #include "nel/3d/mrm_parameters.h" #include "nel/3d/bone.h" #include "nel/3d/mesh_geom.h" #include "nel/3d/mrm_level_detail.h" #include "nel/3d/shadow_skin.h" #include #include namespace NL3D { using NLMISC::CVector; using NLMISC::CPlane; using NLMISC::CMatrix; class CMRMBuilder; // Fast matrix in mesh_mrm_skin.cpp class CMatrix3x4; class CRawVertexNormalSkin1; class CRawVertexNormalSkin2; class CRawVertexNormalSkin3; class CRawVertexNormalSkin4; class CRawSkinNormalCache; class CMeshMRMInstance; class CSkinSpecularRdrPass; // *************************************************************************** /** * An MRM mesh geometry, with no materials information. * * To build a CMeshMRMGeom, you should: * - build a CMesh::CMeshBuild meshBuild (see CMesh) * - call MeshMRMGeom.build(MeshBuild); * * NB: internally, build() use CMRMBuilder, a builder of MRM. * * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CMeshMRMGeom : public IMeshGeom { public: /// Constructor CMeshMRMGeom(); ~CMeshMRMGeom(); /** Build a mesh, replacing old. * this is much slower than CMeshGeom::build(), because it computes the MRM. * \param params parameters of the MRM build process. */ void build(CMesh::CMeshBuild &m, std::vector &bsList, uint numMaxMaterial, const CMRMParameters ¶ms= CMRMParameters()); /// change materials Ids (called from CMesh::optimizeMaterialUsage()) void applyMaterialRemap(const std::vector &remap); /** Change MRM Distance setup. * NB: no-op if distanceFinest<0, distanceMiddle<=distanceFinest or if distanceCoarsest<=distanceMiddle. * \param distanceFinest The MRM has its max faces when dist<=distanceFinest. * \param distanceMiddle The MRM has 50% of its faces at dist==distanceMiddle. * \param distanceCoarsest The MRM has faces/Divisor (ie near 0) when dist>=distanceCoarsest. */ void changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest); /// \name From IMeshGeom // @{ /// Init instance info. virtual void initInstance(CMeshBaseInstance *mbi); /// clip this mesh in a driver. true if visible. virtual bool clip(const std::vector &pyramid, const CMatrix &worldMatrix) ; /// render() this mesh in a driver, given an instance and his materials. virtual void render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha); /// render() this mesh as a skin virtual void renderSkin(CTransformShape *trans, float alphaMRM); /// get an approximation of the number of triangles this instance will render for a fixed distance. virtual float getNumTriangles (float distance); /// serial this meshGeom. virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream); NLMISC_DECLARE_CLASS(CMeshMRMGeom); /// Scene profile void profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags); // @} /// \name Lod management. // @{ /** get the number of LOD currently loaded. */ uint getNbLodLoaded() const { return _NbLodLoaded ; } /** Load the header and the first lod of a MRM in a stream. * \param f the input stream to read. NB: after load, f.getPos() return the position of the second lod in the stream. */ void loadFirstLod(NLMISC::IStream &f); /** Load next lod of a stream. use getNbLodLoaded() to know what Lod will be loaded. * NB: if getNbLodLoaded() == getNbLod(), no op. * \param f the same input stream passed to loadFirstLod(). NB: after load, f.getPos() is "unedfined" * (actually return the position of the next lod in the stream). */ void loadNextLod(NLMISC::IStream &f); /** UnLoad Lod getNbLodLoaded()-1 from memory. use getNbLodLoaded()-1 to know what Lod will be unloaded. * NB: if getNbLodLoaded() <= 1, no op. */ void unloadNextLod(NLMISC::IStream &f); // @} /// \name Geometry accessors // @{ /// get the extended axis aligned bounding box of the mesh const NLMISC::CAABBoxExt& getBoundingBox() const { return _BBox; } /// get the vertex buffer used by the mrm mesh. NB: this VB store all Vertices used by All LODs. const CVertexBuffer &getVertexBuffer() const { return _VBufferFinal ; } /// get the skinWeights used by the mrm mesh. NB: same size of the vertexBuffer. empty if !isSkinned() const std::vector &getSkinWeights() const {return _SkinWeights;} /// get the bone names of the meshMRM. const std::vector &getBonesName() const {return _BonesName;} /** get the number of LOD. */ uint getNbLod() const { return (uint)_Lods.size() ; } /** get the number of rendering pass of a LOD. * \param lodId the id of the LOD. */ uint getNbRdrPass(uint lodId) const { return (uint)_Lods[lodId].RdrPass.size() ; } /** get the primitive block associated with a rendering pass of a LOD. * \param lodId the id of the LOD. * \param renderingPassIndex the index of the rendering pass */ const CIndexBuffer &getRdrPassPrimitiveBlock(uint lodId, uint renderingPassIndex) const { return _Lods[lodId].RdrPass[renderingPassIndex].PBlock ; } /** get the material ID associated with a rendering pass of a LOD. * \param lodId the id of the LOD. * \param renderingPassIndex the index of the rendering pass in the matrix block */ uint32 getRdrPassMaterial(uint lodId, uint renderingPassIndex) const { return _Lods[lodId].RdrPass[renderingPassIndex].MaterialId ; } /// Advanced. get the geomorphs for a special lod. const std::vector &getGeomorphs(uint lodId) const { return _Lods[lodId].Geomorphs; } /// get the number of BlendShapes uint getNbBlendShapes() const { return (uint)_MeshMorpher.BlendShapes.size(); } /** Build a geometry copy for the given Lod. The VBuffer/IndexBuffer must not be resident. false if bad lodId * The process ensure there is no hole in the resulting vertices array. Hence VB num Verts != vertices.size(). */ bool buildGeometryForLod(uint lodId, std::vector &vertices, std::vector &triangles) const; // @} /// \name Skinning Behavior // @{ /// Return true if the mesh is skinned, else return false. bool isSkinned () const { return _Skinned; } /// Compute skinning id void computeBonesId (CSkeletonModel *skeleton); /// update Skeleton Usage. increment or decrement. computeBonesId must has been called before. void updateSkeletonUsage(CSkeletonModel *sm, bool increment); /// return array of bones used by the skin. computeBonesId must has been called before. const std::vector &getSkinBoneUsage() const {return _BonesId;} /// see CTransform::getSkinBoneSphere() doc for the meaning of this value. computeBonesId must has been called before. const std::vector &getSkinBoneSphere() const {return _BonesSphere;} /// Called for edition purpose (slow O(NVertex) ). computeBonesId must has been called before. bool getSkinBoneBBox(CSkeletonModel *skeleton, NLMISC::CAABBox &bbox, uint boneId) const; // @} /// \name Mesh Block Render Implementation // @{ /** true if this meshGeom support meshBlock rendering. * return false if skinned/meshMorphed. */ virtual bool supportMeshBlockRendering () const; virtual bool sortPerMaterial() const; virtual uint getNumRdrPassesForMesh() const ; virtual uint getNumRdrPassesForInstance(CMeshBaseInstance *inst) const ; virtual void beginMesh(CMeshGeomRenderContext &rdrCtx) ; virtual void activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, void *vbDst) ; virtual void renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, uint rdrPass) ; virtual void endMesh(CMeshGeomRenderContext &rdrCtx) ; virtual bool getVBHeapInfo(uint &vertexFormat, uint &numVertices); virtual void computeMeshVBHeap(void *dst, uint indexStart); virtual bool isActiveInstanceNeedVBFill() const; // @} /// get the MRM level detail information const CMRMLevelDetail &getLevelDetail() const {return _LevelDetail;} /// \name Special SkinGrouping Rendering // @{ bool supportSkinGrouping() const; sint renderSkinGroupGeom(CMeshMRMInstance *mi, float alphaMRM, uint remainingVertices, uint8 *vbDest); void renderSkinGroupPrimitives(CMeshMRMInstance *mi, uint baseVertex, std::vector &specularRdrPasses, uint skinIndex); void renderSkinGroupSpecularRdrPass(CMeshMRMInstance *mi, uint rdrPassId); // @} // Is this mesh Geom has a VertexProgram bound? virtual bool hasMeshVertexProgram() const {return _MeshVertexProgram!=NULL;} /// \name ShadowMap Skin rendering // @{ /// Setup the ShadowMesh void setShadowMesh(const std::vector &shadowVertices, const std::vector &triangles); /// Get the num of shadow skin vertices uint getNumShadowSkinVertices() const; /// Render the ShadowSkin (SkinGroup like) bool supportShadowSkinGrouping() const {return _SupportShadowSkinGrouping;} sint renderShadowSkinGeom(CMeshMRMInstance *mi, uint remainingVertices, uint8 *vbDest); void renderShadowSkinPrimitives(CMeshMRMInstance *mi, CMaterial &castMat, IDriver *drv, uint baseVertex); /** Special use of skinning to compute intersection of a ray with it. * Internaly Use same system than ShadowSkinning, see CShadowSkin::getRayIntersection() */ bool supportIntersectSkin() const {return supportShadowSkinGrouping();} bool intersectSkin(CMeshMRMInstance *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D); // @} // ************************ private: friend class CMRMBuilder; /// \name Structures for building a MRM mesh. //@{ /// A block of primitives, sorted by material use. class CRdrPass { public: // The id of this material. uint32 MaterialId; // The list of primitives. CIndexBuffer PBlock; // The same, precomputed for VBHeap Index Shifting CIndexBuffer VBHeapPBlock; // Serialize a rdrpass. void serial(NLMISC::IStream &f) { (void)f.serialVersion(0); f.serial(MaterialId); f.serial(PBlock); } CRdrPass() { NL_SET_IB_NAME(PBlock, "CMeshMRM::CRdrPass::PBlock"); NL_SET_IB_NAME(VBHeapPBlock, "CMeshMRM::CRdrPass::VBHeapPBlock"); PBlock.setFormat(NL_MESH_MRM_INDEX_FORMAT); } }; /// A block of vertices descriptor. struct CVertexBlock { // The index of the start vertex. uint32 VertexStart; // Number of vertices. uint32 NVertices; void serial(NLMISC::IStream &f) { f.serial(VertexStart, NVertices); } }; /// A LOD of the MRM. class CLod { public: /// The number of vertex in The VB this Lod needs. uint32 NWedges; /// List of geomorph, for this LOD. std::vector Geomorphs; /// List of rdr pass, for this LOD. std::vector RdrPass; /** Skinning: list of influenced vertices to compute, for this lod only. There is 4 array, 0th * is for vertices which have only one matrix. 1st if for vertices which have only 2 matrix .... */ std::vector InfluencedVertices[NL3D_MESH_SKINNING_MAX_MATRIX]; /// Skinning: list of Matrix which influence this Lod. So we know what matrix to compute. std::vector MatrixInfluences; /// Skinning: does the VBuffer part of this Lod contains original skin vertices. bool OriginalSkinRestored; /** Skinning: list of vertex blocks to copy from RAM to AGP, for this Lod only. * NB: it is constructed from InfluencedVertices. Only useful if skinned. */ std::vector SkinVertexBlocks; CLod() { // By default, this is supposed false. OriginalSkinRestored= false; } // Serialize a Lod. void serial(NLMISC::IStream &f); // Used in CMeshMRMGeom::build(). void buildSkinVertexBlocks(); void optimizeTriangleOrder(); }; friend class CLod; /** A mesh information. NB: private. unlike CMesh::CMeshBuild, do not herit from CMeshBase::CMeshBuild, because * computed internally with CMRMBuilder, and only geometry is of interest. */ struct CMeshBuildMRM { // This tells if the mesh is correctly skinned. bool Skinned; // This is the array of SkinWeights, same size as the VB. std::vector SkinWeights; // This VB is computed with CMRMBuilder and is ready to used CVertexBuffer VBuffer; // Lod array, computed with CMRMBuilder and ready to used std::vector Lods; // The blend shapes std::vector BlendShapes; /// \Degradation control. // @{ /// The MRM has its max faces when dist<=DistanceFinest. float DistanceFinest; /// The MRM has 50% of its faces at dist==DistanceMiddle. float DistanceMiddle; /// The MRM has faces/Divisor when dist>=DistanceCoarsest. float DistanceCoarsest; // @} }; //@} /// A LOD of the MRM. class CLodInfo { public: /// The frist new wedge this lod use. uint32 StartAddWedge; /// The last+1 new wedge this lod use. NB: Lod.NWedges== LodInfo.EndAddWedges. uint32 EndAddWedges; /// the absolute Lod offset in the last Stream which has been used to read this MRM. sint32 LodOffset; void serial(NLMISC::IStream &f) { (void)f.serialVersion(0); f.serial(StartAddWedge); f.serial(EndAddWedges); // do not serial LodOffset here. } }; private: /// Skinning: This tells if the mesh is correctly skinned (suuport skinning). bool _Skinned; /// Skinning: this is the list of vertices (mirror of VBuffer), at the bind Pos. std::vector _OriginalSkinVertices; std::vector _OriginalSkinNormals; std::vector _OriginalTGSpace; /// The Original VBuffer CVertexBuffer _VBufferOriginal; /// The Final VBuffer CVertexBuffer _VBufferFinal; /// This is the array of SkinWeights, same size as the VB. std::vector _SkinWeights; /// This boolean is true if the bones id have been passed in the skeleton bool _BoneIdComputed; /// true if the _BonesIdExt have been computed (for bone Usage). bool _BoneIdExtended; /// if true, then maybe use faster render bool _SupportSkinGrouping; /// Last lod rendered. used with renderSkinGroup*() only uint8 _LastLodComputed; /// This array give the name of the local bones std::vector _BonesName; /// This array give the index in the skeleton of the local bones used. computed at first computeBoneId() std::vector _BonesId; /// Same as _BonesId but with parent of bones added. (used for bone usage) std::vector _BonesIdExt; /// see CTransform::getSkinBoneSphere() doc for the meaning of this value std::vector _BonesSphere; /// List of Lods. std::vector _Lods; /// For clipping. this is the BB of all vertices of all Lods. NLMISC::CAABBoxExt _BBox; /// Info for pre-loading Lods. std::vector _LodInfos; uint _NbLodLoaded; /// \Degradation control. // @{ CMRMLevelDetail _LevelDetail; // @} /// NB: HERE FOR PACKING ONLY. For clipping. Estimate if we must do a Precise clipping (ie with bboxes) bool _PreciseClipping; // The Mesh Morpher CMeshMorpher _MeshMorpher; // Possible MeshVertexProgram to apply at render() NLMISC::CSmartPtr _MeshVertexProgram; /// \name Mesh Block Render Implementation // @{ /// setuped at compileRunTime. bool _SupportMeshBlockRendering; /// BeginMesh setup bool _MBRBkupNormalize; /// global setup at activateInstance() sint _MBRCurrentLodId; // @} /// \name ShadowMap Skin rendering // @{ CShadowSkin _ShadowSkin; bool _SupportShadowSkinGrouping; // @} private: /// serial a subset of the vertices. void serialLodVertexData(NLMISC::IStream &f, uint startWedge, uint endWedge); /// choose the lod according to the alphaMRM [0,1] given. sint chooseLod(float alphaMRM, float &alphaLod); /// Apply the geomorph to the _VBuffer, or the VBhard, if exist/used void applyGeomorph(std::vector &geoms, float alphaLod); /// Apply the geomorph to the VBhard ptr, if not NULL void applyGeomorphWithVBHardPtr(std::vector &geoms, float alphaLod, uint8 *vertexDestPtr); /// Faster, but common geomorph apply void applyGeomorphPosNormalUV0(std::vector &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, float a, float a1); /// Skinning: bkup Vertex/Normal into _OriginalSkin* from VBuffer. void bkupOriginalSkinVertices(); void bkupOriginalSkinVerticesSubset(uint wedgeStart, uint wedgeEnd); /// Skinning: restore Vertex/Normal from _OriginalSkin* to VBuffer. void restoreOriginalSkinVertices(); /// Skinning: Apply skinning to the _VBuffer (before geomorph). void applySkin(CLod &lod, const CSkeletonModel *skeleton); /** The same as apply skin, but with normal modified. Normal is not normalized. * 4 versions from slower to faster. */ void applySkinWithNormal(CLod &lod, const CSkeletonModel *skeleton); void applyRawSkinWithNormal(CLod &lod, CRawSkinNormalCache &rawSkinLod, const CSkeletonModel *skeleton, uint8 *vbHard, float alphaLod); /** The same as apply skin with normal, but with a tangent space added (encoded in a texture coordinate). * The tangent space is modified, but not normalized (must be done in a vertex program). * 4 versions from slower to faster. */ void applySkinWithTangentSpace(CLod &lod, const CSkeletonModel *skeleton, uint tangentSpaceTexCoord); /// Skinning: same as restoreOriginalSkinVertices(), but for one Lod only. void restoreOriginalSkinPart(CLod &lod); /// load the header of this mesh. return the version of the header. sint loadHeader(NLMISC::IStream &f) throw(NLMISC::EStream); /// load this mesh. void load(NLMISC::IStream &f) throw(NLMISC::EStream); /// save the entire mesh. void save(NLMISC::IStream &f) throw(NLMISC::EStream); // Build bone Usage information for serialized mesh <= version 2. void buildBoneUsageVer2 (); // Some runtime not serialized compilation void compileRunTime(); // SkinGroup void updateShiftedTriangleCache(CMeshMRMInstance *mi, sint curLodId, uint baseVertex); private: /// \name RawSkin optimisation. // @{ /// Each time the mesh is loaded/built, this increment uint _MeshDataId; /// compute RawSkin info in the MRMInstance according to current skin setup. void updateRawSkinNormal(bool enabled, CMeshMRMInstance *mi, sint curLodId); /// Increment the refCount, so instances RawSkins are no longer valid void dirtMeshDataId(); // ApplySkin method void applyArrayRawSkinNormal1(CRawVertexNormalSkin1 *src, uint8 *destVertexPtr, CMatrix3x4 *boneMat3x4, uint nInf); void applyArrayRawSkinNormal2(CRawVertexNormalSkin2 *src, uint8 *destVertexPtr, CMatrix3x4 *boneMat3x4, uint nInf); void applyArrayRawSkinNormal3(CRawVertexNormalSkin3 *src, uint8 *destVertexPtr, CMatrix3x4 *boneMat3x4, uint nInf); void applyArrayRawSkinNormal4(CRawVertexNormalSkin4 *src, uint8 *destVertexPtr, CMatrix3x4 *boneMat3x4, uint nInf); public: static uint NumCacheVertexNormal1; static uint NumCacheVertexNormal2; static uint NumCacheVertexNormal3; static uint NumCacheVertexNormal4; // @} }; // *************************************************************************** /** * An instanciable MRM mesh. * * To build a CMeshMRM, you should: * - build a CMesh::CMeshBuild meshBuild (see CMesh) * - call MeshMRM.build(MeshBuild); * - call if you want setAnimatedMaterial() etc... * * NB: internally, build() use CMRMBuilder, a builder of MRM. * * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CMeshMRM : public CMeshBase { public: /// Constructor CMeshMRM(); /** Build a mesh, replacing old. WARNING: This has a side effect of deleting AnimatedMaterials. * this is much slower than CMesh::build(), because it computes the MRM. * \param params parameters of the MRM build process. */ void build ( CMeshBase::CMeshBaseBuild &mBase, CMesh::CMeshBuild &m, std::vector &listBS, const CMRMParameters ¶ms= CMRMParameters() ); /** Build a mesh, replacing old. build from a CMeshBaseBuild (materials info) and a previously builded CMeshMRMGeom. * WARNING: This has a side effect of deleting AnimatedMaterials. * this is much slower than CMesh::build(), because it computes the MRM. * \param params parameters of the MRM build process. */ void build (CMeshBase::CMeshBaseBuild &m, const CMeshMRMGeom &mgeom); /** Optimize material use. If a material in CMeshBase is not used by any renderPasses, it is removed, and ids are updated. * WARNING: This has a side effect of deleting AnimatedMaterials. * \param remap a remap material Id: newId= remap[oldId]. -1 means "no more used" */ void optimizeMaterialUsage(std::vector &remap); /// Compute skinning id void computeBonesId (CSkeletonModel *skeleton); /// update Skeleton Usage. increment or decrement. void updateSkeletonUsage(CSkeletonModel *sm, bool increment); /** Change MRM Distance setup. * NB: no-op if distanceFinest<0, distanceMiddle<=distanceFinest or if distanceCoarsest<=distanceMiddle. * \param distanceFinest The MRM has its max faces when dist<=distanceFinest. * \param distanceMiddle The MRM has 50% of its faces at dist==distanceMiddle. * \param distanceCoarsest The MRM has faces/Divisor (ie near 0) when dist>=distanceCoarsest. */ void changeMRMDistanceSetup(float distanceFinest, float distanceMiddle, float distanceCoarsest); /// \name From IShape // @{ /// Create a CMeshInstance, which contains materials. virtual CTransformShape *createInstance(CScene &scene); /// clip this mesh in a driver. virtual bool clip(const std::vector &pyramid, const CMatrix &worldMatrix) ; /// render() this mesh in a driver. virtual void render(IDriver *drv, CTransformShape *trans, bool passOpaque); /// get an approximation of the number of triangles this instance will render for a fixed distance. virtual float getNumTriangles (float distance); /// serial this mesh. virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream); NLMISC_DECLARE_CLASS(CMeshMRM); /// Get bbox. virtual void getAABBox(NLMISC::CAABBox &bbox) const {bbox= getBoundingBox().getAABBox();} /// profiling virtual void profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool opaquePass); /// System Mem Geometry Copy, built at load time virtual void buildSystemGeometry(); // @} /// \name Geometry accessors // @{ /// get the extended axis aligned bounding box of the mesh const NLMISC::CAABBoxExt& getBoundingBox() const { return _MeshMRMGeom.getBoundingBox(); } /// get the vertex buffer used by the mrm mesh. NB: this VB store all Vertices used by All LODs. const CVertexBuffer &getVertexBuffer() const { return _MeshMRMGeom.getVertexBuffer(); } /** get the number of LOD. */ uint getNbLod() const { return _MeshMRMGeom.getNbLod() ; } /** get the number of rendering pass of a LOD. * \param lodId the id of the LOD. */ uint getNbRdrPass(uint lodId) const { return _MeshMRMGeom.getNbRdrPass(lodId) ; } /** get the primitive block associated with a rendering pass of a LOD. * \param lodId the id of the LOD. * \param renderingPassIndex the index of the rendering pass */ const CIndexBuffer &getRdrPassPrimitiveBlock(uint lodId, uint renderingPassIndex) const { return _MeshMRMGeom.getRdrPassPrimitiveBlock(lodId, renderingPassIndex) ; } /** get the material ID associated with a rendering pass of a LOD. * \param lodId the id of the LOD. * \param renderingPassIndex the index of the rendering pass in the matrix block */ uint32 getRdrPassMaterial(uint lodId, uint renderingPassIndex) const { return _MeshMRMGeom.getRdrPassMaterial(lodId, renderingPassIndex) ; } /// Get the mesh geom const CMeshMRMGeom& getMeshGeom () const; // @} /// \name Mesh Block Render Interface // @{ virtual IMeshGeom *supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const; // @} // ************************ private: CMeshMRMGeom _MeshMRMGeom; }; } // NL3D #endif // NL_MESH_MRM_H /* End of mesh_mrm.h */