865 lines
24 KiB
C++
865 lines
24 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_H
|
|
#define NL_MESH_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/misc/bit_set.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_geom.h"
|
|
#include "nel/3d/mesh_morpher.h"
|
|
#include "nel/3d/mesh_vertex_program.h"
|
|
#include "nel/3d/shadow_skin.h"
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
|
|
using NLMISC::CVector;
|
|
using NLMISC::CPlane;
|
|
using NLMISC::CMatrix;
|
|
|
|
|
|
class CMeshGeom;
|
|
class CSkeletonModel;
|
|
class CMatrix3x4;
|
|
|
|
// ***************************************************************************
|
|
// Should be 4.
|
|
#define NL3D_MESH_SKINNING_MAX_MATRIX 4
|
|
|
|
// Above this distance, Mesh with a bigger Radius will use BBox clipping
|
|
#define NL3D_MESH_PRECISE_CLIP_THRESHOLD 5.0f
|
|
|
|
|
|
// ***************************************************************************
|
|
/**
|
|
* An instanciable mesh.
|
|
* Skinning support: support only palette skinning.
|
|
* \author Lionel Berenguier
|
|
* \author Nevrax France
|
|
* \date 2000
|
|
*/
|
|
class CMesh : public CMeshBase
|
|
{
|
|
public:
|
|
|
|
/// \name Structures for building a mesh.
|
|
//@{
|
|
|
|
/// A corner of a face.
|
|
struct CCorner
|
|
{
|
|
sint32 Vertex; /// The vertex Id.
|
|
CVector Normal;
|
|
NLMISC::CUVW Uvws[CVertexBuffer::MaxStage];
|
|
CRGBA Color;
|
|
CRGBA Specular;
|
|
|
|
// Setup all to 0, but Color (to white)... Important for good corner comparison.
|
|
// This is slow but doesn't matter since used at mesh building....
|
|
CCorner();
|
|
|
|
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
};
|
|
|
|
/// A Triangle face.
|
|
struct CFace
|
|
{
|
|
CCorner Corner[3];
|
|
sint32 MaterialId;
|
|
sint32 SmoothGroup;
|
|
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
};
|
|
|
|
|
|
/** Skinning: A skin weight for a vertex.
|
|
* NB: if you don't use all matrix for this vertex, use at least the 0th matrix, and simply set 0 on Weights you don't use.
|
|
*/
|
|
struct CSkinWeight
|
|
{
|
|
/// What matrix of the skeleton shape this vertex use.
|
|
uint32 MatrixId[NL3D_MESH_SKINNING_MAX_MATRIX];
|
|
/// weight of this matrix (sum of 4 must be 1).
|
|
float Weights[NL3D_MESH_SKINNING_MAX_MATRIX];
|
|
|
|
/// ctor.
|
|
CSkinWeight()
|
|
{
|
|
for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
|
|
{
|
|
MatrixId[i]=0;
|
|
Weights[i]=0;
|
|
}
|
|
}
|
|
|
|
void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
};
|
|
|
|
struct CVertLink
|
|
{
|
|
uint32 nFace, nCorner;
|
|
uint32 VertVB;
|
|
|
|
CVertLink (uint32 face, uint32 corner, uint32 iVB)
|
|
{
|
|
nFace = face;
|
|
nCorner = corner;
|
|
VertVB = iVB;
|
|
}
|
|
};
|
|
|
|
/** Mesh Interface System for MRM
|
|
*/
|
|
struct CInterfaceVertex
|
|
{
|
|
CVector Pos;
|
|
CVector Normal;
|
|
};
|
|
struct CInterface
|
|
{
|
|
// The polygon describing the interface between 2 meshs.
|
|
std::vector<CInterfaceVertex> Vertices;
|
|
};
|
|
/// For each vertex
|
|
struct CInterfaceLink
|
|
{
|
|
// to which interface this vertex is welded. -1 if none
|
|
sint InterfaceId;
|
|
// to which vertex of the interface this vertex is welded
|
|
uint InterfaceVertexId;
|
|
|
|
CInterfaceLink()
|
|
{
|
|
InterfaceId= -1;
|
|
}
|
|
};
|
|
|
|
/// A mesh information.
|
|
struct CMeshBuild
|
|
{
|
|
/** the IDRV_VF* flags which tells what vertices data are used. See IDriver::setVertexFormat() for
|
|
* more information. NB: IDRV_VF_XYZ is always considered to true..
|
|
* Note that is some stage use 2 textures coordinates instead of 3, then the extended vertex format must be used isntead
|
|
*/
|
|
sint32 VertexFlags;
|
|
uint8 NumCoords[CVertexBuffer::MaxStage]; // tells for each uvw if is uses 2 or 3 coords
|
|
uint8 UVRouting[CVertexBuffer::MaxStage]; // gives the uv routing table. Each final UV channel can be routed to any vertex uv
|
|
|
|
// Vertices array
|
|
std::vector<CVector> Vertices;
|
|
|
|
// Palette Skinning Vertices array (same size as Vertices). NULL if no skinning.
|
|
std::vector<CSkinWeight> SkinWeights;
|
|
|
|
// Bones name. Each matrix id used in SkinWeights must have a corresponding string in the bone name array.
|
|
std::vector<std::string> BonesNames;
|
|
|
|
// Faces array
|
|
std::vector<CFace> Faces;
|
|
|
|
// Blend shapes if some
|
|
std::vector<CBlendShape> BlendShapes;
|
|
|
|
// Link between VB and max vertex indices
|
|
std::vector<CVertLink> VertLink; // Filled when called build
|
|
|
|
// MeshVertexProgram to copy to meshGeom.
|
|
NLMISC::CSmartPtr<IMeshVertexProgram> MeshVertexProgram;
|
|
|
|
// Mesh Interface System for MRM building
|
|
std::vector<CInterface> Interfaces;
|
|
// must be same size as Vertices, else Mesh Interface system disabled
|
|
std::vector<CInterfaceLink> InterfaceLinks;
|
|
|
|
NLMISC::CBitSet InterfaceVertexFlag; // each bit indicate if the vertex belongs to an interface
|
|
|
|
|
|
CMeshBuild();
|
|
|
|
// Serialization
|
|
//void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
|
|
};
|
|
//@}
|
|
|
|
|
|
public:
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
/// Constructor
|
|
CMesh();
|
|
/// dtor
|
|
~CMesh();
|
|
CMesh(const CMesh &mesh);
|
|
CMesh &operator=(const CMesh &mesh);
|
|
|
|
|
|
/// Build a mesh, replacing old. WARNING: This has a side effect of deleting AnimatedMaterials.
|
|
void build(CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &mbuild);
|
|
|
|
/// Build a mesh from material info, and a builded MeshGeom. WARNING: This has a side effect of deleting AnimatedMaterials.
|
|
void build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom);
|
|
|
|
/** 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);
|
|
|
|
|
|
void setBlendShapes(std::vector<CBlendShape>&bs);
|
|
|
|
/// Compute skinning id
|
|
void computeBonesId (CSkeletonModel *skeleton);
|
|
|
|
/// update Skeleton Usage. increment or decrement.
|
|
void updateSkeletonUsage(CSkeletonModel *sm, bool increment);
|
|
|
|
/// \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 opaquePass);
|
|
|
|
/// serial this mesh.
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
NLMISC_DECLARE_CLASS(CMesh);
|
|
|
|
/// get trinagle count.
|
|
virtual float getNumTriangles (float distance);
|
|
|
|
/// 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;
|
|
|
|
/// get the vertex buffer used by the mesh
|
|
const CVertexBuffer &getVertexBuffer() const;
|
|
|
|
/// get the number of matrix block
|
|
uint getNbMatrixBlock() const;
|
|
|
|
/** get the number of rendering pass for a given matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the rendering passes belong to
|
|
*/
|
|
uint getNbRdrPass(uint matrixBlockIndex) const;
|
|
|
|
/** get the primitive block associated with a rendering pass of a matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the renderin pass belong to
|
|
* \param renderingPassIndex the index of the rendering pass in the matrix block
|
|
*/
|
|
const CIndexBuffer &getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const;
|
|
|
|
/** get the material ID associated with a rendering pass of a matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the renderin pass belong to
|
|
* \param renderingPassIndex the index of the rendering pass in the matrix block
|
|
*/
|
|
uint32 getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const;
|
|
|
|
/// Get the geom mesh
|
|
const CMeshGeom &getMeshGeom () const;
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Mesh Block Render Interface
|
|
// @{
|
|
virtual IMeshGeom *supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const;
|
|
// @}
|
|
|
|
private:
|
|
|
|
// The geometry.
|
|
CMeshGeom *_MeshGeom;
|
|
|
|
// Called at load or build time, all that is not serialized
|
|
void compileRunTime();
|
|
};
|
|
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
/**
|
|
* A mesh geometry.
|
|
* Skinning support: support only palette skinning.
|
|
* \author Lionel Berenguier
|
|
* \author Nevrax France
|
|
* \date 2000
|
|
*/
|
|
class CMeshGeom: public IMeshGeom
|
|
{
|
|
public:
|
|
|
|
/// Constructor
|
|
CMeshGeom();
|
|
virtual ~CMeshGeom();
|
|
|
|
/// Build a meshGeom
|
|
void build(CMesh::CMeshBuild &mbuild, uint numMaxMaterial);
|
|
|
|
void setBlendShapes(std::vector<CBlendShape>&bs);
|
|
|
|
/// change materials Ids (called from CMesh::optimizeMaterialUsage())
|
|
void applyMaterialRemap(const std::vector<sint> &remap);
|
|
|
|
|
|
/// \name From IMeshGeom
|
|
// @{
|
|
|
|
/// Init instance info.
|
|
virtual void initInstance(CMeshBaseInstance *mbi);
|
|
|
|
/// clip this mesh
|
|
virtual bool clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix) ;
|
|
|
|
/// render() this mesh in a driver.
|
|
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 mesh.
|
|
virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
|
|
NLMISC_DECLARE_CLASS(CMeshGeom);
|
|
|
|
// profile
|
|
virtual 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 mesh
|
|
const CVertexBuffer &getVertexBuffer() const { return _VBuffer ; }
|
|
|
|
/// get the number of matrix block
|
|
uint getNbMatrixBlock() const { return (uint)_MatrixBlocks.size() ; }
|
|
|
|
/** get the number of rendering pass for a given matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the rendering passes belong to
|
|
*/
|
|
uint getNbRdrPass(uint matrixBlockIndex) const { return (uint)_MatrixBlocks[matrixBlockIndex].RdrPass.size() ; }
|
|
|
|
/** get the primitive block associated with a rendering pass of a matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the renderin pass belong to
|
|
* \param renderingPassIndex the index of the rendering pass in the matrix block
|
|
*/
|
|
const CIndexBuffer &getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
|
|
{
|
|
return _MatrixBlocks[matrixBlockIndex].RdrPass[renderingPassIndex].PBlock ;
|
|
}
|
|
|
|
/** get the material ID associated with a rendering pass of a matrix block
|
|
* \param matrixBlockIndex the index of the matrix block the renderin pass belong to
|
|
* \param renderingPassIndex the index of the rendering pass in the matrix block
|
|
*/
|
|
uint32 getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
|
|
{
|
|
return _MatrixBlocks[matrixBlockIndex].RdrPass[renderingPassIndex].MaterialId ;
|
|
}
|
|
|
|
/// get the number of BlendShapes
|
|
uint getNbBlendShapes() const { if(_MeshMorpher) return (uint)_MeshMorpher->BlendShapes.size(); return 0; }
|
|
|
|
/** Tool function to retrieve vector geometry only of the mesh.
|
|
* return false if the vbuffer cannot be read (resident)
|
|
*/
|
|
bool retrieveVertices(std::vector<NLMISC::CVector> &vertices) const;
|
|
|
|
/** Tool function to retrieve triangles geometry only of the mesh (of all rdrpass).
|
|
* return false if the index buffer cannot be read (resident)
|
|
*/
|
|
bool retrieveTriangles(std::vector<uint32> &indices) 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<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;}
|
|
|
|
/// Skin intersection
|
|
bool supportIntersectSkin() const {return _Skinned;}
|
|
bool intersectSkin(CTransformShape *mi, const CMatrix &toRaySpace, float &dist2D, float &distZ, bool computeDist2D);
|
|
|
|
// @}
|
|
|
|
|
|
/** render the mesh geometry with a single material. Render is said "Simple" because no special features are used:
|
|
* - mesh is rendered without VertexProgram (if it has one).
|
|
* - mesh is rendered without Skinning.
|
|
* - mesh is rendered without use of VertexBufferHard.
|
|
* - mesh is rendered without MeshMorpher.
|
|
* - .....
|
|
*/
|
|
void renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat);
|
|
|
|
|
|
|
|
/// \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);
|
|
|
|
// @}
|
|
|
|
// Is this mesh Geom has a VertexProgram bound?
|
|
virtual bool hasMeshVertexProgram() const {return _MeshVertexProgram!=NULL;}
|
|
|
|
// get the Mesh VertexProgram
|
|
IMeshVertexProgram *getMeshVertexProgram() const {return _MeshVertexProgram;}
|
|
|
|
// ************************
|
|
private:
|
|
|
|
/// A block of primitives, sorted by material used.
|
|
class CRdrPass
|
|
{
|
|
public:
|
|
// The id of this material.
|
|
uint32 MaterialId;
|
|
// The list of primitives.
|
|
CIndexBuffer PBlock;
|
|
|
|
// The same, shifted for VBHeap rendering.
|
|
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, "CMesh::CRdrPass::PBlock");
|
|
NL_SET_IB_NAME(VBHeapPBlock, "CMesh::CRdrPass::VBHeapPBlock");
|
|
PBlock.setFormat(NL_MESH_INDEX_FORMAT);
|
|
}
|
|
};
|
|
|
|
|
|
/// A block of RdrPasses, sorted by matrix use.
|
|
class CMatrixBlock
|
|
{
|
|
public:
|
|
// ctor
|
|
CMatrixBlock() : NumMatrix(0)
|
|
{
|
|
std::fill(MatrixId, MatrixId + IDriver::MaxModelMatrix, 0);
|
|
}
|
|
/// Which matrix we use for this block.
|
|
uint32 MatrixId[IDriver::MaxModelMatrix];
|
|
/// Number of matrix actually used.
|
|
uint32 NumMatrix;
|
|
/// List of rdr pass, for this matrix block.
|
|
std::vector<CRdrPass> RdrPass;
|
|
|
|
void serial(NLMISC::IStream &f)
|
|
{
|
|
(void)f.serialVersion(0);
|
|
|
|
// Code written for IDriver::MaxModelMatrix==16 matrixs.
|
|
nlctassert(IDriver::MaxModelMatrix == 16);
|
|
for(uint i=0;i<IDriver::MaxModelMatrix;i++)
|
|
{
|
|
f.serial(MatrixId[i]);
|
|
}
|
|
f.serial(NumMatrix);
|
|
f.serialCont(RdrPass);
|
|
}
|
|
|
|
|
|
/// return the idx of this bone, in MatrixId. -1 if not found.
|
|
sint getMatrixIdLocation(uint32 boneId) const;
|
|
};
|
|
|
|
|
|
private:
|
|
/** Just for build process.
|
|
* NB: we must store palette info by corner (not by vertex) because Matrix Block grouping may insert vertex
|
|
* discontinuities. eg: a vertex use Matrix18. After Matrix grouping (16matrix max), Matrix18 could be Matrix2 for a group
|
|
* of face, but Matrix13 for another!!
|
|
*/
|
|
struct CCornerTmp : public CMesh::CCorner
|
|
{
|
|
CPaletteSkin Palette;
|
|
float Weights[NL3D_MESH_SKINNING_MAX_MATRIX];
|
|
|
|
// The comparison.
|
|
bool operator<(const CCornerTmp &c) const;
|
|
// The result of the compression.
|
|
mutable sint VBId;
|
|
// The flags to know what to compare.
|
|
static sint Flags;
|
|
|
|
// Setup all to 0, but Color (to white)... Important for good corner comparison.
|
|
// This is slow but doesn't matter since used at mesh building....
|
|
CCornerTmp()
|
|
{
|
|
VBId= 0;
|
|
for(sint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
|
|
{
|
|
Palette.MatrixId[i]=0;
|
|
Weights[i]=0;
|
|
}
|
|
}
|
|
|
|
// copy from corner.
|
|
CCornerTmp &operator=(const CMesh::CCorner &o)
|
|
{
|
|
Vertex= o.Vertex;
|
|
Normal= o.Normal;
|
|
for(sint i=0;i<CVertexBuffer::MaxStage;i++)
|
|
{
|
|
Uvws[i]= o.Uvws[i];
|
|
}
|
|
Color= o.Color;
|
|
Specular= o.Specular;
|
|
|
|
return *this;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
/** Just for build process. A Bone.
|
|
*/
|
|
struct CBoneTmp
|
|
{
|
|
// How many ref points on it? (NB: a corner may have multiple (up to 4) on it).
|
|
uint RefCount;
|
|
// Am i inserted into the current matrixblock?
|
|
bool Inserted;
|
|
// If I am inserted into the current matrixblock, to which local bone (0-15) I am linked?
|
|
uint MatrixIdInMB;
|
|
|
|
CBoneTmp()
|
|
{
|
|
RefCount= 0;
|
|
Inserted=false;
|
|
}
|
|
};
|
|
|
|
|
|
/** Just for build process. A map of Bone.
|
|
*/
|
|
typedef std::map<uint, CBoneTmp> TBoneMap;
|
|
typedef TBoneMap::iterator ItBoneMap;
|
|
|
|
|
|
/** Just for build process. A Triangle face.
|
|
*/
|
|
struct CFaceTmp
|
|
{
|
|
CCornerTmp Corner[3];
|
|
uint MaterialId;
|
|
// which matrixblock own this face. -1 <=> Not owned.
|
|
sint MatrixBlockId;
|
|
|
|
CFaceTmp()
|
|
{
|
|
MatrixBlockId= -1;
|
|
}
|
|
CFaceTmp &operator=(const CMesh::CFace& o)
|
|
{
|
|
Corner[0]= o.Corner[0];
|
|
Corner[1]= o.Corner[1];
|
|
Corner[2]= o.Corner[2];
|
|
MaterialId= o.MaterialId;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
void buildBoneUse(std::vector<uint> &boneUse, std::vector<CMesh::CSkinWeight> &skinWeights);
|
|
|
|
};
|
|
|
|
|
|
/** Just for build process. A MatrixBlock remap.
|
|
*/
|
|
class CMatrixBlockRemap
|
|
{
|
|
public:
|
|
uint32 Remap[IDriver::MaxModelMatrix];
|
|
};
|
|
|
|
|
|
private:
|
|
/** Skinning: this is the list of vertices (mirror of VBuffer), at the bind Pos.
|
|
* Potentially modified by the mesh morpher
|
|
*/
|
|
std::vector<CVector> _OriginalSkinVertices;
|
|
std::vector<CVector> _OriginalSkinNormals;
|
|
std::vector<CVector> _OriginalTGSpace;
|
|
|
|
/// VBuffer of the mesh (potentially modified by the mesh morpher and skinning)
|
|
CVertexBuffer _VBuffer;
|
|
/// The original VBuffer of the mesh used only if there are blend shapes.
|
|
CVertexBuffer _VBufferOri;
|
|
/// The matrix blocks.
|
|
std::vector<CMatrixBlock> _MatrixBlocks;
|
|
/// For clipping.
|
|
NLMISC::CAABBoxExt _BBox;
|
|
/// This tells if the mesh is correctly skinned.
|
|
bool _Skinned;
|
|
/// This tells if the mesh VBuffer has coorect BindPos vertices
|
|
bool _OriginalSkinRestored;
|
|
|
|
/// 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;
|
|
/// see CTransform::getSkinBoneSphere() doc for the meaning of this value
|
|
std::vector<NLMISC::CBSphere> _BonesSphere;
|
|
|
|
|
|
/// This array give the name of the local bones used.
|
|
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;
|
|
|
|
/// \name Mesh Block Render Implementation
|
|
// @{
|
|
/// setuped at compileRunTime.
|
|
enum TMBRSupport
|
|
{
|
|
MBROk= 1,
|
|
MBRSortPerMaterial= 2,
|
|
MBRCurrentUseVP= 4,
|
|
};
|
|
// Of if don't support MBR at all
|
|
uint8 _SupportMBRFlags;
|
|
// @}
|
|
|
|
/// 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<IMeshVertexProgram> _MeshVertexProgram;
|
|
|
|
|
|
private:
|
|
// Locals, for build.
|
|
class CCornerPred
|
|
{
|
|
public:
|
|
bool operator()(const CCornerTmp *x, const CCornerTmp *y) const
|
|
{
|
|
return (*x<*y);
|
|
}
|
|
};
|
|
typedef std::set<CCornerTmp*, CCornerPred> TCornerSet;
|
|
typedef TCornerSet::iterator ItCornerSet;
|
|
|
|
// Find and fill the VBuffer.
|
|
void findVBId(TCornerSet &corners, const CCornerTmp *corn, sint ¤tVBIndex, const CVector &vert, const CMesh::CMeshBuild &mb)
|
|
{
|
|
ItCornerSet it= corners.find(const_cast<CCornerTmp *>(corn));
|
|
if(it!=corners.end())
|
|
corn->VBId= (*it)->VBId;
|
|
else
|
|
{
|
|
// Add corner to the set to not insert same corner two times.
|
|
corners.insert (const_cast<CCornerTmp *>(corn));
|
|
sint i;
|
|
corn->VBId= currentVBIndex++;
|
|
// Fill the VBuffer.
|
|
_VBuffer.setNumVertices(currentVBIndex);
|
|
sint id= currentVBIndex-1;
|
|
|
|
CVertexBufferReadWrite vba;
|
|
_VBuffer.lock (vba);
|
|
|
|
// XYZ.
|
|
vba.setVertexCoord(id, vert);
|
|
// Normal
|
|
if(CCornerTmp::Flags & CVertexBuffer::NormalFlag)
|
|
vba.setNormalCoord(id, corn->Normal);
|
|
// Uvws.
|
|
for(i=0;i<CVertexBuffer::MaxStage;i++)
|
|
{
|
|
if(CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i))
|
|
{
|
|
switch(mb.NumCoords[i])
|
|
{
|
|
case 2:
|
|
vba.setTexCoord(id, uint8(i), corn->Uvws[i].U, corn->Uvws[i].V);
|
|
break;
|
|
case 3:
|
|
vba.setValueFloat3Ex((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + i), id, corn->Uvws[i].U, corn->Uvws[i].V, corn->Uvws[i].W);
|
|
break;
|
|
default: // not supported
|
|
nlassert(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Color.
|
|
if(CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag)
|
|
vba.setColor(id, corn->Color);
|
|
// Specular.
|
|
if(CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag)
|
|
vba.setSpecular(id, corn->Specular);
|
|
|
|
// setup palette skinning.
|
|
if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
|
|
{
|
|
vba.setPaletteSkin(id, corn->Palette);
|
|
for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
|
|
vba.setWeight(id, uint8(i), corn->Weights[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// optimize triangles order of all render pass.
|
|
void optimizeTriangleOrder();
|
|
|
|
// Some runtime not serialized compilation
|
|
void compileRunTime();
|
|
|
|
|
|
/// \name Skinning
|
|
// @{
|
|
|
|
enum TSkinType {SkinPosOnly=0, SkinWithNormal, SkinWithTgSpace};
|
|
|
|
// build skinning.
|
|
void buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp> &tmpFaces);
|
|
|
|
// Build bone Usage information for serialized mesh <= version 3.
|
|
void buildBoneUsageVer3 ();
|
|
|
|
// bkup from VBuffer into _OriginalSkin*
|
|
void bkupOriginalSkinVertices();
|
|
// restore from _OriginalSkin* to VBuffer. set _OriginalSkinRestored to true
|
|
void restoreOriginalSkinVertices();
|
|
|
|
// apply Skin to all vertices from _OriginalSkin* to _VBuffer.
|
|
void applySkin(CSkeletonModel *skeleton);
|
|
|
|
|
|
void flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb);
|
|
void computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock *prevBlock, CMatrixBlock &curBlock);
|
|
void computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVector, CPaletteSkin *srcPal, float *srcWgt, CVector *dstVector);
|
|
void computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVector, CPaletteSkin *srcPal, float *srcWgt, CVector *dstVector);
|
|
|
|
// Shadow mapping and CMesh. NB: not serialized, but created at each load
|
|
CShadowSkin _ShadowSkin;
|
|
// build the shadow skin, from the VertexBuffer/IndexBuffer
|
|
void buildShadowSkin();
|
|
|
|
// @}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
#endif // NL_MESH_H
|
|
|
|
/* End of mesh.h */
|