769 lines
23 KiB
C++
769 lines
23 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef NL_MESH_MRM_SKINNED_H
|
|
#define NL_MESH_MRM_SKINNED_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 <set>
|
|
#include <vector>
|
|
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
|
|
using NLMISC::CVector;
|
|
using NLMISC::CPlane;
|
|
using NLMISC::CMatrix;
|
|
class CMRMBuilder;
|
|
// Fast matrix in mesh_mrm_skin.cpp
|
|
class CMatrix3x4;
|
|
class CRawVertexNormalSkinned1;
|
|
class CRawVertexNormalSkinned2;
|
|
class CRawVertexNormalSkinned3;
|
|
class CRawVertexNormalSkinned4;
|
|
class CRawSkinnedNormalCache;
|
|
class CMeshMRMSkinnedInstance;
|
|
class CSkinSpecularRdrPass;
|
|
|
|
#define NL3D_MESH_MRM_SKINNED_WEIGHT_FACTOR (255.f)
|
|
#define NL3D_MESH_MRM_SKINNED_UV_FACTOR (8192.f)
|
|
#define NL3D_MESH_MRM_SKINNED_NORMAL_FACTOR (32767.f)
|
|
#define NL3D_MESH_MRM_SKINNED_DEFAULT_POS_SCALE (8.f/32767.f)
|
|
#define NL3D_MESH_MRM_SKINNED_MAX_MATRIX 4
|
|
#define NL3D_MESH_MRM_SKINNED_VERTEX_FORMAT (CVertexBuffer::PositionFlag|CVertexBuffer::NormalFlag|CVertexBuffer::TexCoord0Flag|CVertexBuffer::PaletteSkinFlag)
|
|
|
|
// ***************************************************************************
|
|
/**
|
|
* An MRM mesh geometry, with no materials information.
|
|
*
|
|
* To build a CMeshMRMSkinnedGeom, 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 CMeshMRMSkinnedGeom : public IMeshGeom
|
|
{
|
|
public:
|
|
/// Constructor
|
|
CMeshMRMSkinnedGeom();
|
|
~CMeshMRMSkinnedGeom();
|
|
|
|
/** 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, uint numMaxMaterial, const CMRMParameters ¶ms= CMRMParameters());
|
|
|
|
/// change materials Ids (called from CMesh::optimizeMaterialUsage())
|
|
void applyMaterialRemap(const std::vector<sint> &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<CPlane> &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);
|
|
NLMISC_DECLARE_CLASS(CMeshMRMSkinnedGeom);
|
|
|
|
/// Scene profile
|
|
void profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, float polygonCount, uint32 rdrFlags);
|
|
|
|
// @}
|
|
|
|
|
|
/// \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.
|
|
void getVertexBuffer(CVertexBuffer &output) const;
|
|
|
|
/// get the skin weight buffer
|
|
void getSkinWeights (std::vector<CMesh::CSkinWeight> &skinWeights) const;
|
|
|
|
|
|
/// get the bone names of the meshMRM.
|
|
const std::vector<std::string> &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
|
|
*/
|
|
void getRdrPassPrimitiveBlock(uint lodId, uint renderingPassIndex, CIndexBuffer &block) const
|
|
{
|
|
_Lods[lodId].getRdrPassPrimitiveBlock(renderingPassIndex, block);
|
|
}
|
|
|
|
|
|
/** 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<CMRMWedgeGeom> &getGeomorphs(uint lodId) const
|
|
{
|
|
return _Lods[lodId].Geomorphs;
|
|
}
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Skinning Behavior
|
|
// @{
|
|
|
|
/// 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<sint32> &getSkinBoneUsage() const {return _BonesId;}
|
|
|
|
/// see CTransform::getSkinBoneSphere() doc for the meaning of this value. computeBonesId must has been called before.
|
|
const std::vector<NLMISC::CBSphere> &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 { return false; }
|
|
virtual uint getNumRdrPassesForMesh() const { return 0; }
|
|
virtual uint getNumRdrPassesForInstance(CMeshBaseInstance * /* inst */) const { return 0; }
|
|
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 */) {}
|
|
|
|
// @}
|
|
|
|
|
|
/// get the MRM level detail information
|
|
const CMRMLevelDetail &getLevelDetail() const {return _LevelDetail;}
|
|
|
|
|
|
/// \name Special SkinGrouping Rendering
|
|
// @{
|
|
bool supportSkinGrouping() const;
|
|
sint renderSkinGroupGeom(CMeshMRMSkinnedInstance *mi, float alphaMRM, uint remainingVertices, uint8 *vbDest);
|
|
void renderSkinGroupPrimitives(CMeshMRMSkinnedInstance *mi, uint baseVertex, std::vector<CSkinSpecularRdrPass> &specularRdrPasses, uint skinIndex);
|
|
void renderSkinGroupSpecularRdrPass(CMeshMRMSkinnedInstance *mi, uint rdrPassId);
|
|
// @}
|
|
|
|
// Is this mesh Geom has a VertexProgram bound?
|
|
virtual bool hasMeshVertexProgram() const {return false;}
|
|
|
|
/// \name ShadowMap Skin rendering
|
|
// @{
|
|
/// Setup the ShadowMesh
|
|
void setShadowMesh(const std::vector<CShadowVertex> &shadowVertices, const std::vector<uint32> &triangles);
|
|
|
|
/// Get the num of shadow skin vertices
|
|
uint getNumShadowSkinVertices() const;
|
|
|
|
/// Render the ShadowSkin (SkinGroup like)
|
|
bool supportShadowSkinGrouping() const {return _SupportShadowSkinGrouping;}
|
|
sint renderShadowSkinGeom(CMeshMRMSkinnedInstance *mi, uint remainingVertices, uint8 *vbDest);
|
|
void renderShadowSkinPrimitives(CMeshMRMSkinnedInstance *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(CMeshMRMSkinnedInstance *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.
|
|
std::vector<uint16> PBlock;
|
|
|
|
// Serialize a rdrpass.
|
|
void serial(NLMISC::IStream &f)
|
|
{
|
|
(void)f.serialVersion(0);
|
|
|
|
f.serial(MaterialId);
|
|
f.serialCont(PBlock);
|
|
}
|
|
|
|
// Get num triangle
|
|
uint getNumTriangle () const
|
|
{
|
|
return (uint)PBlock.size()/3;
|
|
}
|
|
};
|
|
|
|
|
|
/// 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<CMRMWedgeGeom> Geomorphs;
|
|
/// List of rdr pass, for this LOD.
|
|
std::vector<CRdrPass> 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<uint32> InfluencedVertices[NL3D_MESH_SKINNING_MAX_MATRIX];
|
|
/// Skinning: list of Matrix which influence this Lod. So we know what matrix to compute.
|
|
std::vector<uint32> MatrixInfluences;
|
|
|
|
|
|
|
|
CLod()
|
|
{
|
|
}
|
|
|
|
// Serialize a Lod.
|
|
void serial(NLMISC::IStream &f);
|
|
|
|
// Used in CMeshMRMSkinnedGeom::build().
|
|
void optimizeTriangleOrder();
|
|
|
|
// Get the primitive block
|
|
void getRdrPassPrimitiveBlock (uint renderPass, CIndexBuffer &block) const;
|
|
|
|
// Build the primitive block
|
|
void buildPrimitiveBlock(uint renderPass, const CIndexBuffer &block);
|
|
};
|
|
|
|
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<CMesh::CSkinWeight> 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<CLod> Lods;
|
|
|
|
// The blend shapes
|
|
std::vector<CBlendShape> 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;
|
|
// @}
|
|
|
|
};
|
|
//@}
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// The packed vertex buffer
|
|
class CPackedVertexBuffer
|
|
{
|
|
public:
|
|
/// The Final VBuffer
|
|
struct CPackedVertex
|
|
{
|
|
sint16 X, Y, Z;
|
|
sint16 Nx, Ny, Nz;
|
|
sint16 U, V;
|
|
uint8 Matrices[NL3D_MESH_MRM_SKINNED_MAX_MATRIX];
|
|
uint8 Weights[NL3D_MESH_MRM_SKINNED_MAX_MATRIX];
|
|
|
|
// Decompact it
|
|
inline void getPos (CVector &dest, float factor) const
|
|
{
|
|
dest.x = (float)X * factor;
|
|
dest.y = (float)Y * factor;
|
|
dest.z = (float)Z * factor;
|
|
}
|
|
inline void getNormal (CVector &dest) const
|
|
{
|
|
dest.x = (float)Nx * (1.f/NL3D_MESH_MRM_SKINNED_NORMAL_FACTOR);
|
|
dest.y = (float)Ny * (1.f/NL3D_MESH_MRM_SKINNED_NORMAL_FACTOR);
|
|
dest.z = (float)Nz * (1.f/NL3D_MESH_MRM_SKINNED_NORMAL_FACTOR);
|
|
}
|
|
inline void getU (float &_u) const
|
|
{
|
|
_u = (float)U * (1.f/NL3D_MESH_MRM_SKINNED_UV_FACTOR);
|
|
}
|
|
inline void getV (float &_v) const
|
|
{
|
|
_v = (float)V * (1.f/NL3D_MESH_MRM_SKINNED_UV_FACTOR);
|
|
}
|
|
inline void getWeight (float &dest, uint index) const
|
|
{
|
|
dest = (float)Weights[index] * (1.f/NL3D_MESH_MRM_SKINNED_WEIGHT_FACTOR);
|
|
}
|
|
|
|
// Compact it
|
|
void setNormal (const CVector &pos);
|
|
void setUV (float _u, float _v);
|
|
void setWeight (uint weightId, float weight);
|
|
void setPos (const CVector &pos, float scaleFactor);
|
|
|
|
// Serial it
|
|
void serial(NLMISC::IStream &f);
|
|
};
|
|
|
|
// Build it
|
|
void build (const CVertexBuffer &buffer, const std::vector<CMesh::CSkinWeight> &skinWeight);
|
|
|
|
// Clear it
|
|
void clear ()
|
|
{
|
|
_PackedBuffer.clear();
|
|
}
|
|
|
|
// Reset
|
|
void contReset()
|
|
{
|
|
NLMISC::contReset (_PackedBuffer);
|
|
}
|
|
|
|
// Access it
|
|
const CPackedVertex *getPackedVertices() const
|
|
{
|
|
if (_PackedBuffer.empty())
|
|
return NULL;
|
|
else
|
|
return &(_PackedBuffer[0]);
|
|
}
|
|
|
|
// Access it
|
|
CPackedVertex *getPackedVertices()
|
|
{
|
|
if (_PackedBuffer.empty())
|
|
return NULL;
|
|
else
|
|
return &(_PackedBuffer[0]);
|
|
}
|
|
|
|
// Acces it
|
|
uint getNumVertices() const
|
|
{
|
|
return (uint)_PackedBuffer.size();
|
|
}
|
|
|
|
// Decompact position
|
|
inline void getPos (CVector &dest, const CPackedVertex &src) const
|
|
{
|
|
src.getPos (dest, _DecompactScale);
|
|
}
|
|
|
|
// Serialize it
|
|
void serial(NLMISC::IStream &f);
|
|
|
|
private:
|
|
/// Decompact position values
|
|
float _DecompactScale;
|
|
|
|
//
|
|
std::vector<CPackedVertex> _PackedBuffer;
|
|
};
|
|
|
|
private:
|
|
|
|
// The packed vertex buffer
|
|
CPackedVertexBuffer _VBufferFinal;
|
|
|
|
/// 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;
|
|
|
|
/// Last lod rendered. used with renderSkinGroup*() only
|
|
uint8 _LastLodComputed;
|
|
|
|
/// This array give the name of the local bones
|
|
std::vector<std::string> _BonesName;
|
|
/// This array give the index in the skeleton of the local bones used. computed at first computeBoneId()
|
|
std::vector<sint32> _BonesId;
|
|
/// Same as _BonesId but with parent of bones added. (used for bone usage)
|
|
std::vector<sint32> _BonesIdExt;
|
|
/// see CTransform::getSkinBoneSphere() doc for the meaning of this value
|
|
std::vector<NLMISC::CBSphere> _BonesSphere;
|
|
|
|
/// List of Lods.
|
|
std::vector<CLod> _Lods;
|
|
/// For clipping. this is the BB of all vertices of all Lods.
|
|
NLMISC::CAABBoxExt _BBox;
|
|
|
|
|
|
/// \Degradation control.
|
|
// @{
|
|
CMRMLevelDetail _LevelDetail;
|
|
// @}
|
|
|
|
|
|
/// \name Hard VB
|
|
// @{
|
|
|
|
/// NB: HERE FOR PACKING ONLY. For clipping. Estimate if we must do a Precise clipping (ie with bboxes)
|
|
bool _PreciseClipping;
|
|
|
|
// @}
|
|
|
|
/// \name ShadowMap Skin rendering
|
|
// @{
|
|
CShadowSkin _ShadowSkin;
|
|
bool _SupportShadowSkinGrouping;
|
|
// @}
|
|
|
|
private:
|
|
|
|
/// 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<CMRMWedgeGeom> &geoms, float alphaLod);
|
|
|
|
/// Apply the geomorph to the VBhard ptr, if not NULL
|
|
void applyGeomorphWithVBHardPtr(std::vector<CMRMWedgeGeom> &geoms, float alphaLod);
|
|
|
|
/// Faster, but common geomorph apply
|
|
void applyGeomorphPosNormalUV0Int(std::vector<CMRMWedgeGeom> &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, sint a, sint a1);
|
|
|
|
/// Faster, but common geomorph apply
|
|
void applyGeomorphPosNormalUV0(std::vector<CMRMWedgeGeom> &geoms, uint8 *vertexPtr, uint8 *vertexDestPtr, sint32 vertexSize, float a, float a1);
|
|
|
|
/** The same as apply skin, but with normal modified. Normal is not normalized.
|
|
* 4 versions from slower to faster.
|
|
*/
|
|
void applyRawSkinWithNormal(CLod &lod, CRawSkinnedNormalCache &rawSkinLod, const CSkeletonModel *skeleton, uint8 *vbHard, float alphaLod);
|
|
|
|
// Some runtime not serialized compilation
|
|
void compileRunTime();
|
|
|
|
// SkinGroup
|
|
void updateShiftedTriangleCache(CMeshMRMSkinnedInstance *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, CMeshMRMSkinnedInstance *mi, sint curLodId);
|
|
/// Increment the refCount, so instances RawSkins are no longer valid
|
|
void dirtMeshDataId();
|
|
|
|
// ApplySkin method
|
|
void applyArrayRawSkinNormal1(CRawVertexNormalSkinned1 *src, uint8 *destVertexPtr,
|
|
CMatrix3x4 *boneMat3x4, uint nInf);
|
|
void applyArrayRawSkinNormal2(CRawVertexNormalSkinned2 *src, uint8 *destVertexPtr,
|
|
CMatrix3x4 *boneMat3x4, uint nInf);
|
|
void applyArrayRawSkinNormal3(CRawVertexNormalSkinned3 *src, uint8 *destVertexPtr,
|
|
CMatrix3x4 *boneMat3x4, uint nInf);
|
|
void applyArrayRawSkinNormal4(CRawVertexNormalSkinned4 *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 CMeshMRMSkinned, 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 CMeshMRMSkinned : public CMeshBase
|
|
{
|
|
public:
|
|
/// Constructor
|
|
CMeshMRMSkinned();
|
|
|
|
/** Return true if the CMesh::CMeshBuild is compatible with the CMeshMRMSkinned.
|
|
* If not, build a CMeshMRM. You must test this before call build().
|
|
*/
|
|
static bool isCompatible(const CMesh::CMeshBuild &m);
|
|
|
|
/** Build a mesh, replacing old. WARNING: This has a side effect of deleting AnimatedMaterials.
|
|
* Call isCompatible() before this method.
|
|
* 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,
|
|
const CMRMParameters ¶ms= CMRMParameters() );
|
|
|
|
/** Build a mesh, replacing old. build from a CMeshBaseBuild (materials info) and a previously builded CMeshMRMSkinnedGeom.
|
|
* 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 CMeshMRMSkinnedGeom &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<sint> &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<CPlane> &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);
|
|
NLMISC_DECLARE_CLASS(CMeshMRMSkinned);
|
|
|
|
/// Get bbox.
|
|
virtual void getAABBox(NLMISC::CAABBox &bbox) const {bbox= getBoundingBox().getAABBox();}
|
|
|
|
/// profiling
|
|
virtual void profileSceneRender(CRenderTrav *rdrTrav, CTransformShape *trans, bool opaquePass);
|
|
|
|
// @}
|
|
|
|
|
|
/// \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.
|
|
void getVertexBuffer(CVertexBuffer &output) const { _MeshMRMGeom.getVertexBuffer(output); }
|
|
|
|
|
|
/** 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
|
|
*/
|
|
void getRdrPassPrimitiveBlock(uint lodId, uint renderingPassIndex, CIndexBuffer &block) const
|
|
{
|
|
_MeshMRMGeom.getRdrPassPrimitiveBlock(lodId, renderingPassIndex, block);
|
|
}
|
|
|
|
|
|
/** 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 CMeshMRMSkinnedGeom& getMeshGeom () const;
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Mesh Block Render Interface
|
|
// @{
|
|
virtual IMeshGeom *supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const;
|
|
// @}
|
|
|
|
|
|
// ************************
|
|
private:
|
|
|
|
CMeshMRMSkinnedGeom _MeshMRMGeom;
|
|
|
|
|
|
};
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
#endif // NL_MESH_MRM_SKINNED_H
|
|
|
|
/* End of mesh_mrm_skinned.h */
|