# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

mesh.h

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #ifndef NL_MESH_H
00027 #define NL_MESH_H
00028 
00029 #include "nel/misc/types_nl.h"
00030 #include "3d/shape.h"
00031 #include "3d/driver.h"
00032 #include "nel/misc/aabbox.h"
00033 #include "nel/misc/uv.h"
00034 #include "3d/vertex_buffer.h"
00035 #include "3d/vertex_buffer_hard.h"
00036 #include "3d/material.h"
00037 #include "3d/primitive_block.h"
00038 #include "3d/animated_material.h"
00039 #include "3d/mesh_base.h"
00040 #include "3d/mesh_geom.h"
00041 #include "3d/mesh_morpher.h"
00042 #include "3d/mesh_vertex_program.h"
00043 #include <set>
00044 #include <vector>
00045 
00046 
00047 namespace NL3D 
00048 {
00049 
00050 
00051 using   NLMISC::CVector;
00052 using   NLMISC::CPlane;
00053 using   NLMISC::CMatrix;
00054 
00055 
00056 class CMeshGeom;
00057 class CSkeletonModel;
00058 class CMatrix3x4;
00059 
00060 // ***************************************************************************
00061 // Should be 4.
00062 #define         NL3D_MESH_SKINNING_MAX_MATRIX           4
00063 
00064 // Above this distance, Mesh with a bigger Radius will use BBox clipping
00065 #define         NL3D_MESH_PRECISE_CLIP_THRESHOLD        5.0f
00066 
00067 
00068 // ***************************************************************************
00076 class CMesh : public CMeshBase
00077 {
00078 public:
00079 
00081 
00082 
00084         struct  CCorner
00085         {
00086                 sint32                  Vertex;         
00087                 CVector                 Normal;
00088                 NLMISC::CUVW    Uvws[CVertexBuffer::MaxStage];
00089                 CRGBA                   Color;
00090                 CRGBA                   Specular;
00091 
00092                 // Setup all to 0, but Color (to white)... Important for good corner comparison.
00093                 // This is slow but doesn't matter since used at mesh building....
00094                 CCorner();
00095 
00096                 void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00097         };
00098 
00100         struct  CFace
00101         {
00102                 CCorner         Corner[3];
00103                 sint32          MaterialId;
00104                 sint32      SmoothGroup;
00105                 void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00106         };
00107 
00108 
00112         struct  CSkinWeight
00113         {
00115                 uint32                  MatrixId[NL3D_MESH_SKINNING_MAX_MATRIX];
00117                 float                   Weights[NL3D_MESH_SKINNING_MAX_MATRIX];
00118 
00120                 CSkinWeight()
00121                 {
00122                         for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00123                         {
00124                                 MatrixId[i]=0;
00125                                 Weights[i]=0;
00126                         }
00127                 }
00128 
00129                 void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00130         };
00131 
00132         struct CVertLink
00133         {
00134                 uint32 nFace, nCorner;
00135                 uint32 VertVB;
00136 
00137                 CVertLink (uint32 face, uint32 corner, uint32 iVB)
00138                 {
00139                         nFace = face;
00140                         nCorner = corner;
00141                         VertVB = iVB;
00142                 }
00143         };
00144 
00146         struct  CMeshBuild
00147         {
00152                 sint32                                          VertexFlags;
00153                 uint8                                           NumCoords[CVertexBuffer::MaxStage]; // tells for each uvw if is uses 2 or 3 coords
00154 
00155                 // Vertices array
00156                 std::vector<CVector>            Vertices;
00157 
00158                 // Palette Skinning Vertices array (same size as Vertices). NULL if no skinning.
00159                 std::vector<CSkinWeight>        SkinWeights;
00160 
00161                 // Bones name. Each matrix id used in SkinWeights must have a corresponding string in the bone name array.
00162                 std::vector<std::string>        BonesNames;
00163 
00164                 // Faces array
00165                 std::vector<CFace>                      Faces;
00166 
00167                 // Blend shapes if some
00168                 std::vector<CBlendShape>        BlendShapes;
00169 
00170                 // Link between VB and max vertex indices
00171                 std::vector<CVertLink>          VertLink; // Filled when called build
00172 
00173                 // MeshVertexProgram to copy to meshGeom.
00174                 NLMISC::CSmartPtr<IMeshVertexProgram>   MeshVertexProgram;
00175 
00176 
00177                 CMeshBuild();
00178 
00179                 // Serialization
00180                 //void serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00181 
00182         };
00184 
00185 
00186 public:
00188         CMesh();
00190         ~CMesh();
00191         CMesh(const CMesh &mesh);
00192         CMesh   &operator=(const CMesh &mesh);
00193 
00194 
00196         void                    build(CMeshBase::CMeshBaseBuild &mbase, CMeshBuild &mbuild);
00197 
00198 
00200         void                    build(CMeshBase::CMeshBaseBuild &mbuild, CMeshGeom &meshGeom);
00201 
00202         void                    setBlendShapes(std::vector<CBlendShape>&bs);
00203 
00205         void                    computeBonesId (CSkeletonModel *skeleton);
00206 
00208         void                    updateSkeletonUsage(CSkeletonModel *sm, bool increment);
00209 
00211         // @{
00212 
00214         virtual CTransformShape         *createInstance(CScene &scene);
00215 
00217         virtual bool    clip(const std::vector<CPlane>  &pyramid, const CMatrix &worldMatrix) ;
00218 
00220         virtual void    render(IDriver *drv, CTransformShape *trans, bool opaquePass);
00221 
00223         virtual void    serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00224         NLMISC_DECLARE_CLASS(CMesh);
00225 
00227         virtual float   getNumTriangles (float distance);
00228 
00230         virtual void    getAABBox(NLMISC::CAABBox &bbox) const {bbox= getBoundingBox().getAABBox();}
00231 
00232         // @}
00233 
00235         // @{
00236 
00238         const NLMISC::CAABBoxExt& getBoundingBox() const;
00239 
00241         const CVertexBuffer &getVertexBuffer() const;
00242 
00244         uint getNbMatrixBlock() const;
00245 
00249         uint getNbRdrPass(uint matrixBlockIndex) const;
00250 
00255         const CPrimitiveBlock &getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const;
00256 
00261         uint32 getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const;
00262 
00264         const CMeshGeom &getMeshGeom () const;
00265 
00266         // @}
00267 
00268 
00270         // @{
00271         virtual IMeshGeom       *supportMeshBlockRendering (CTransformShape *trans, float &polygonCount ) const;
00272         // @}
00273 
00274 private:
00275 
00276         // The geometry.
00277         CMeshGeom               *_MeshGeom;
00278 };
00279 
00280 
00281 
00282 
00283 // ***************************************************************************
00291 class CMeshGeom: public IMeshGeom
00292 {
00293 public:
00294 
00296         CMeshGeom();
00297         virtual ~CMeshGeom();
00298 
00300         void                    build(CMesh::CMeshBuild &mbuild, uint numMaxMaterial);
00301 
00302         void                    setBlendShapes(std::vector<CBlendShape>&bs);
00303 
00304 
00306         // @{
00307 
00309         virtual void    initInstance(CMeshBaseInstance *mbi);
00310 
00312         virtual bool    clip(const std::vector<CPlane>  &pyramid, const CMatrix &worldMatrix) ;
00313 
00315         virtual void    render(IDriver *drv, CTransformShape *trans, float polygonCount, uint32 rdrFlags, float globalAlpha);
00316 
00318         virtual void    renderSkin(CTransformShape *trans, float alphaMRM);
00319 
00320         // get an approximation of the number of triangles this instance will render for a fixed distance.
00321         virtual float   getNumTriangles (float distance);
00322 
00324         virtual void    serial(NLMISC::IStream &f) throw(NLMISC::EStream);
00325         NLMISC_DECLARE_CLASS(CMeshGeom);
00326 
00327         // @}
00328 
00329 
00331         // @{
00332 
00334         const NLMISC::CAABBoxExt& getBoundingBox() const
00335         {
00336                 return _BBox;
00337         }
00338 
00340         const CVertexBuffer &getVertexBuffer() const { return _VBuffer ; }
00341 
00343         uint getNbMatrixBlock() const { return _MatrixBlocks.size() ; }
00344 
00348         uint getNbRdrPass(uint matrixBlockIndex) const { return _MatrixBlocks[matrixBlockIndex].RdrPass.size() ; }
00349 
00354         const CPrimitiveBlock &getRdrPassPrimitiveBlock(uint matrixBlockIndex, uint renderingPassIndex) const
00355         {
00356                 return _MatrixBlocks[matrixBlockIndex].RdrPass[renderingPassIndex].PBlock ;
00357         }
00358 
00363         uint32 getRdrPassMaterial(uint matrixBlockIndex, uint renderingPassIndex) const
00364         {
00365                 return _MatrixBlocks[matrixBlockIndex].RdrPass[renderingPassIndex].MaterialId ;
00366         }
00367 
00368         // @}
00369 
00370 
00372         // @{
00373 
00375         bool isSkinned () const
00376         {
00377                 return _Skinned;
00378         }
00379 
00381         void                    computeBonesId (CSkeletonModel *skeleton);
00382 
00384         void                    updateSkeletonUsage(CSkeletonModel *sm, bool increment);
00385 
00387         const std::vector<sint32>       &getSkinBoneUsage() const {return _BonesId;}
00388 
00389         // @}
00390 
00391 
00399         void                    renderSimpleWithMaterial(IDriver *drv, const CMatrix &worldMatrix, CMaterial &mat);
00400 
00401 
00402 
00404         // @{
00405 
00409         virtual bool    supportMeshBlockRendering () const;
00410 
00411         virtual bool    sortPerMaterial() const;
00412         virtual uint    getNumRdrPasses() const ;
00413         virtual void    beginMesh(CMeshGeomRenderContext &rdrCtx) ;
00414         virtual void    activeInstance(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount) ;
00415         virtual void    renderPass(CMeshGeomRenderContext &rdrCtx, CMeshBaseInstance *inst, float polygonCount, uint rdrPass) ;
00416         virtual void    endMesh(CMeshGeomRenderContext &rdrCtx) ;
00417 
00418         virtual bool    getVBHeapInfo(uint &vertexFormat, uint &numVertices);
00419         virtual void    computeMeshVBHeap(void *dst, uint indexStart);
00420 
00421         // @}
00422 
00423 
00424 // ************************
00425 private:
00426 
00428         class   CRdrPass
00429         {
00430         public:
00431                 // The id of this material.
00432                 uint32                          MaterialId;
00433                 // The list of primitives.
00434                 CPrimitiveBlock         PBlock;
00435 
00436                 // The same, shifted for VBHeap rendering.
00437                 CPrimitiveBlock         VBHeapPBlock;
00438 
00439 
00440                 // Serialize a rdrpass.
00441                 void    serial(NLMISC::IStream &f)
00442                 {
00443                         (void)f.serialVersion(0);
00444 
00445                         f.serial(MaterialId);
00446                         f.serial(PBlock);
00447                 }
00448         };
00449 
00450 
00452         class   CMatrixBlock
00453         {
00454         public:
00456                 uint32                                  MatrixId[IDriver::MaxModelMatrix];
00458                 uint32                                  NumMatrix;
00460                 std::vector<CRdrPass>   RdrPass;
00461 
00462                 void    serial(NLMISC::IStream &f)
00463                 {
00464                         (void)f.serialVersion(0);
00465 
00466                         // Code written for IDriver::MaxModelMatrix==16 matrixs.
00467                         nlassert(IDriver::MaxModelMatrix == 16);
00468                         for(uint i=0;i<IDriver::MaxModelMatrix;i++)
00469                                 f.serial(MatrixId[i]);
00470                         f.serial(NumMatrix);
00471                         f.serialCont(RdrPass);
00472                 }
00473 
00474 
00476                 sint    getMatrixIdLocation(uint32 boneId) const;
00477         };
00478 
00479 
00480 private:
00486         struct  CCornerTmp : public CMesh::CCorner
00487         {
00488                 CPaletteSkin    Palette;
00489                 float                   Weights[NL3D_MESH_SKINNING_MAX_MATRIX];
00490 
00491                 // The comparison.
00492                 bool            operator<(const CCornerTmp &c) const;
00493                 // The result of the compression.
00494                 mutable sint    VBId;
00495                 // The flags to know what to compare.
00496                 static  sint    Flags;
00497 
00498                 // Setup all to 0, but Color (to white)... Important for good corner comparison.
00499                 // This is slow but doesn't matter since used at mesh building....
00500                 CCornerTmp()
00501                 {
00502                         VBId= 0;
00503                         for(sint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00504                         {
00505                                 Palette.MatrixId[i]=0;
00506                                 Weights[i]=0;
00507                         }
00508                 }
00509 
00510                 // copy from corner.
00511                 CCornerTmp &operator=(const CMesh::CCorner &o)
00512                 {
00513                         Vertex= o.Vertex;
00514                         Normal= o.Normal;
00515                         for(sint i=0;i<=CVertexBuffer::MaxStage;i++)
00516                         {
00517                                 Uvws[i]= o.Uvws[i];
00518                         }                       
00519                         Color= o.Color;
00520                         Specular= o.Specular;
00521 
00522                         return *this;
00523                 }
00524 
00525         };
00526 
00527 
00530         struct  CBoneTmp
00531         {
00532                 // How many ref points on it? (NB: a corner may have multiple (up to 4) on it).
00533                 uint    RefCount;
00534                 // Am i inserted into the current matrixblock?
00535                 bool    Inserted;
00536                 // If I am inserted into the current matrixblock, to which local bone (0-15) I am linked?
00537                 uint    MatrixIdInMB;
00538 
00539                 CBoneTmp()
00540                 {
00541                         RefCount= 0;
00542                         Inserted=false;
00543                 }
00544         };
00545 
00546 
00549         typedef std::map<uint, CBoneTmp>        TBoneMap;
00550         typedef TBoneMap::iterator                      ItBoneMap;
00551 
00552 
00555         struct  CFaceTmp
00556         {
00557                 CCornerTmp              Corner[3];
00558                 uint                    MaterialId;
00559                 // which matrixblock own this face. -1 <=> Not owned.
00560                 sint                    MatrixBlockId;
00561 
00562                 CFaceTmp()
00563                 {
00564                         MatrixBlockId= -1;
00565                 }
00566                 CFaceTmp        &operator=(const CMesh::CFace& o)
00567                 {
00568                         Corner[0]= o.Corner[0];
00569                         Corner[1]= o.Corner[1];
00570                         Corner[2]= o.Corner[2];
00571                         MaterialId= o.MaterialId;
00572 
00573                         return *this;
00574                 }
00575 
00576 
00577                 void    buildBoneUse(std::vector<uint>  &boneUse, std::vector<CMesh::CSkinWeight> &skinWeights);
00578 
00579         };
00580 
00581 
00584         class   CMatrixBlockRemap
00585         {
00586         public:
00587                 uint32                                  Remap[IDriver::MaxModelMatrix];
00588         };
00589 
00590 
00591 private:
00595         std::vector<CVector>            _OriginalSkinVertices;
00596         std::vector<CVector>            _OriginalSkinNormals;
00597         std::vector<CVector>            _OriginalTGSpace;
00598 
00600         CVertexBuffer                           _VBuffer;
00602         CVertexBuffer                           _VBufferOri;
00604         std::vector<CMatrixBlock>       _MatrixBlocks;
00606         NLMISC::CAABBoxExt                      _BBox;
00608         bool                                            _Skinned;
00610         bool                                            _OriginalSkinRestored;
00611 
00613         bool                                            _BoneIdComputed;
00615         bool                                            _BoneIdExtended;
00616 
00618         std::vector<std::string>        _BonesName;
00620         std::vector<sint32>                     _BonesId;
00622         std::vector<sint32>                     _BonesIdExt;
00623 
00624 
00626         // @{
00628         CRefPtr<IVertexBufferHard>              _VertexBufferHard;
00630         CRefPtr<IDriver>                                _Driver;
00632         bool                                                    _VertexBufferHardDirty;
00633 
00635         void                                                    updateVertexBufferHard(IDriver *drv);
00636         // @}
00637 
00638 
00640         // @{
00642         bool                                                    _SupportMeshBlockRendering;
00643         // @}
00644 
00646         bool                                            _PreciseClipping;
00647 
00648         // The Mesh Morpher
00649         CMeshMorpher    *_MeshMorpher; 
00650 
00651 
00652         // Possible MeshVertexProgram to apply at render()
00653         NLMISC::CSmartPtr<IMeshVertexProgram>   _MeshVertexProgram;
00654 
00655 
00656 private:
00657         // Locals, for build.
00658         class   CCornerPred
00659         {
00660         public:
00661                 bool operator()(const CCornerTmp *x, const CCornerTmp *y) const
00662                 {
00663                         return (*x<*y);
00664                 }
00665         };
00666         typedef         std::set<CCornerTmp*, CCornerPred>      TCornerSet;
00667         typedef         TCornerSet::iterator ItCornerSet;
00668 
00669         // Find and fill the VBuffer.
00670         void    findVBId(TCornerSet  &corners, const CCornerTmp *corn, sint &currentVBIndex, const CVector &vert, const CMesh::CMeshBuild &mb)
00671         {
00672                 ItCornerSet  it= corners.find(const_cast<CCornerTmp *>(corn));
00673                 if(it!=corners.end())
00674                         corn->VBId= (*it)->VBId;
00675                 else
00676                 {
00677                         // Add corner to the set to not insert same corner two times.
00678                         corners.insert (const_cast<CCornerTmp *>(corn));
00679                         sint    i;
00680                         corn->VBId= currentVBIndex++;
00681                         // Fill the VBuffer.
00682                         _VBuffer.setNumVertices(currentVBIndex);
00683                         sint    id= currentVBIndex-1;
00684                         // XYZ.
00685                         _VBuffer.setVertexCoord(id, vert);
00686                         // Normal
00687                         if(CCornerTmp::Flags & CVertexBuffer::NormalFlag)
00688                                 _VBuffer.setNormalCoord(id, corn->Normal);
00689                         // Uvws.
00690                         for(i=0;i<CVertexBuffer::MaxStage;i++)
00691                         {
00692                                 if(CCornerTmp::Flags & (CVertexBuffer::TexCoord0Flag<<i))
00693                                 {
00694                                         switch(mb.NumCoords[i])
00695                                         {
00696                                                 case 2:
00697                                                         _VBuffer.setTexCoord(id, i, corn->Uvws[i].U, corn->Uvws[i].V);
00698                                                 break;
00699                                                 case 3:
00700                                                         _VBuffer.setValueFloat3Ex((CVertexBuffer::TValue) (CVertexBuffer::TexCoord0 + i), id, corn->Uvws[i].U, corn->Uvws[i].V, corn->Uvws[i].W);
00701                                                 break;
00702                                                 default: // not supported
00703                                                         nlassert(0);
00704                                                 break;
00705                                         }                                       
00706                                 }
00707                         }
00708                         // Color.
00709                         if(CCornerTmp::Flags & CVertexBuffer::PrimaryColorFlag)
00710                                 _VBuffer.setColor(id, corn->Color);
00711                         // Specular.
00712                         if(CCornerTmp::Flags & CVertexBuffer::SecondaryColorFlag)
00713                                 _VBuffer.setSpecular(id, corn->Specular);
00714 
00715                         // setup palette skinning.
00716                         if ((CCornerTmp::Flags & CVertexBuffer::PaletteSkinFlag)==CVertexBuffer::PaletteSkinFlag)
00717                         {
00718                                 _VBuffer.setPaletteSkin(id, corn->Palette);
00719                                 for(i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00720                                         _VBuffer.setWeight(id, i, corn->Weights[i]);
00721                         }
00722                 }
00723         }
00724 
00725 
00726         // optimize triangles order of all render pass.
00727         void    optimizeTriangleOrder();
00728 
00729         // Some runtime not serialized compilation
00730         void    compileRunTime();
00731 
00732 
00734         // @{
00735 
00736         enum    TSkinType {SkinPosOnly=0, SkinWithNormal, SkinWithTgSpace};
00737         
00738         // build skinning.
00739         void    buildSkin(CMesh::CMeshBuild &m, std::vector<CFaceTmp>   &tmpFaces);
00740 
00741         // Build bone Usage information for serialized mesh <= version 3.
00742         void    buildBoneUsageVer3 ();
00743 
00744         // bkup from VBuffer into _OriginalSkin*
00745         void    bkupOriginalSkinVertices();
00746         // restore from _OriginalSkin* to VBuffer. set _OriginalSkinRestored to true
00747         void    restoreOriginalSkinVertices();
00748 
00749         // apply Skin to all vertices from _OriginalSkin* to _VBuffer.
00750         void    applySkin(CSkeletonModel *skeleton);
00751 
00752 
00753         void    flagSkinVerticesForMatrixBlock(uint8 *skinFlags, CMatrixBlock &mb);
00754         void    computeSkinMatrixes(CSkeletonModel *skeleton, CMatrix3x4 *matrixes, CMatrixBlock  *prevBlock, CMatrixBlock &curBlock);
00755         void    computeSoftwarePointSkinning(CMatrix3x4 *matrixes, CVector *srcVector, CPaletteSkin *srcPal, float *srcWgt, CVector *dstVector);
00756         void    computeSoftwareVectorSkinning(CMatrix3x4 *matrixes, CVector *srcVector, CPaletteSkin *srcPal, float *srcWgt, CVector *dstVector);
00757 
00758         // @}
00759 
00760 };
00761 
00762 
00763 
00764 
00765 } // NL3D
00766 
00767 
00768 #endif // NL_MESH_H
00769             
00770 /* End of mesh.h */