# 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_mrm_skin.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 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 #include "std3d.h"
00027 
00028 #include "nel/misc/bsphere.h"
00029 #include "nel/misc/fast_mem.h"
00030 #include "nel/misc/system_info.h"
00031 #include "3d/mesh_mrm.h"
00032 #include "3d/mrm_builder.h"
00033 #include "3d/mrm_parameters.h"
00034 #include "3d/mesh_mrm_instance.h"
00035 #include "3d/scene.h"
00036 #include "3d/skeleton_model.h"
00037 #include "3d/stripifier.h"
00038 #include "3d/matrix_3x4.h"
00039 #include "3d/raw_skin.h"
00040 
00041 
00042 using namespace NLMISC;
00043 using namespace std;
00044 
00045 
00046 namespace NL3D 
00047 {
00048 
00049 
00050 // ***************************************************************************
00051 // ***************************************************************************
00052 // CMatrix3x4SSE array correctly aligned
00053 // ***************************************************************************
00054 // ***************************************************************************
00055 
00056 
00057 
00058 // ***************************************************************************
00059 #define NL3D_SSE_ALIGNEMENT             16
00060 
00063 class   CMatrix3x4SSEArray
00064 {
00065 private:
00066         void    *_AllocData;
00067         void    *_Data;
00068         uint    _Size;
00069         uint    _Capacity;
00070 
00071 public:
00072         CMatrix3x4SSEArray()
00073         {
00074                 _AllocData= NULL;
00075                 _Data= NULL;
00076                 _Size= 0;
00077                 _Capacity= 0;
00078         }
00079         ~CMatrix3x4SSEArray()
00080         {
00081                 clear();
00082         }
00083         CMatrix3x4SSEArray(const CMatrix3x4SSEArray &other)
00084         {
00085                 _AllocData= NULL;
00086                 _Data= NULL;
00087                 _Size= 0;
00088                 _Capacity= 0;
00089                 *this= other;
00090         }
00091         CMatrix3x4SSEArray &operator=(const CMatrix3x4SSEArray &other)
00092         {
00093                 if( this == &other)
00094                         return *this;
00095                 resize(other.size());
00096                 // copy data from aligned pointers to aligned pointers.
00097                 memcpy(_Data, other._Data, size() * sizeof(CMatrix3x4SSE) );
00098 
00099                 return *this;
00100         }
00101 
00102 
00103         CMatrix3x4SSE   *getPtr()
00104         {
00105                 return (CMatrix3x4SSE*)_Data;
00106         }
00107 
00108         void    clear()
00109         {
00110                 free(_AllocData);
00111                 _AllocData= NULL;
00112                 _Data= NULL;
00113                 _Size= 0;
00114                 _Capacity= 0;
00115         }
00116 
00117         void    resize(uint n)
00118         {
00119                 // reserve ??
00120                 if(n>_Capacity)
00121                         reserve( max(2*_Capacity, n));
00122                 _Size= n;
00123         }
00124 
00125         void    reserve(uint n)
00126         {
00127                 if(n==0)
00128                         clear();
00129                 else if(n>_Capacity)
00130                 {
00131                         // Alloc new data.
00132                         void    *newAllocData;
00133                         void    *newData;
00134 
00135                         // Alloc for alignement.
00136                         newAllocData= malloc(n * sizeof(CMatrix3x4SSE) + NL3D_SSE_ALIGNEMENT-1);
00137                         if(newAllocData==NULL)
00138                                 throw Exception("SSE Allocation Failed");
00139 
00140                         // Align ptr
00141                         newData= (void*) ( ((uint32)newAllocData+NL3D_SSE_ALIGNEMENT-1) & (~(NL3D_SSE_ALIGNEMENT-1)) );
00142 
00143                         // copy valid data from old to new.
00144                         memcpy(newData, _Data, size() * sizeof(CMatrix3x4SSE) );
00145 
00146                         // change ptrs and capacity.
00147                         _Data= newData;
00148                         _AllocData= newAllocData;
00149                         _Capacity= n;
00150                 }
00151         }
00152 
00153         uint    size() const {return _Size;}
00154 
00155 
00156         CMatrix3x4SSE   &operator[](uint i) {return ((CMatrix3x4SSE*)_Data)[i];}
00157 };
00158 
00159 
00160 
00161 // ***************************************************************************
00162 // ***************************************************************************
00163 // Matrix manip
00164 // ***************************************************************************
00165 // ***************************************************************************
00166 
00167 
00168 // ***************************************************************************
00169 template <class TMatrixArray>
00170 inline void     computeBoneMatrixes3x4(TMatrixArray &boneMat3x4, const vector<uint32> &matInfs, const CSkeletonModel *skeleton)
00171 {
00172         // For all matrix this lod use.
00173         for(uint i= 0; i<matInfs.size(); i++)
00174         {
00175                 // Get Matrix info.
00176                 uint    matId= matInfs[i];
00177                 const CMatrix           &boneMat= skeleton->getActiveBoneSkinMatrix(matId);
00178 
00179                 // compute "fast" matrix 3x4.
00180                 // resize Matrix3x4.
00181                 if(matId>=boneMat3x4.size())
00182                 {
00183                         boneMat3x4.resize(matId+1);
00184                 }
00185                 boneMat3x4[matId].set(boneMat);
00186         }
00187 }
00188 
00189 
00190 // ***************************************************************************
00191 // ***************************************************************************
00192 // Simple (slow) skinning version with position only.
00193 // ***************************************************************************
00194 // ***************************************************************************
00195 
00196 
00197 // ***************************************************************************
00198 void    CMeshMRMGeom::applySkin(CLod &lod, const CSkeletonModel *skeleton)
00199 {
00200         nlassert(_Skinned);
00201         if(_SkinWeights.size()==0)
00202                 return;
00203 
00204         // get vertexPtr.
00205         //===========================
00206         uint8           *destVertexPtr= (uint8*)_VBufferFinal.getVertexCoordPointer();
00207         uint            flags= _VBufferFinal.getVertexFormat();
00208         sint32          vertexSize= _VBufferFinal.getVertexSize();
00209         // must have XYZ.
00210         nlassert(flags & CVertexBuffer::PositionFlag);
00211 
00212 
00213         // compute src array.
00214         CMesh::CSkinWeight      *srcSkinPtr;
00215         CVector                         *srcVertexPtr;
00216         srcSkinPtr= &_SkinWeights[0];
00217         srcVertexPtr= &_OriginalSkinVertices[0];
00218 
00219 
00220 
00221         // Compute usefull Matrix for this lod.
00222         //===========================
00223         // Those arrays map the array of bones in skeleton.
00224         static  vector<CMatrix3x4>                      boneMat3x4;
00225         computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton);
00226 
00227 
00228         // apply skinning.
00229         //===========================
00230         // assert, code below is written especially for 4 per vertex.
00231         nlassert(NL3D_MESH_SKINNING_MAX_MATRIX==4);
00232         for(uint i=0;i<NL3D_MESH_SKINNING_MAX_MATRIX;i++)
00233         {
00234                 uint            nInf= lod.InfluencedVertices[i].size();
00235                 if( nInf==0 )
00236                         continue;
00237                 uint32          *infPtr= &(lod.InfluencedVertices[i][0]);
00238 
00239                 // apply the skin to the vertices
00240                 switch(i)
00241                 {
00242                 //=========
00243                 case 0:
00244                         // Special case for Vertices influenced by one matrix. Just copy result of mul.
00245                         //  for all InfluencedVertices only.
00246                         for(;nInf>0;nInf--, infPtr++)
00247                         {
00248                                 uint    index= *infPtr;
00249                                 CMesh::CSkinWeight      *srcSkin= srcSkinPtr + index;
00250                                 CVector                         *srcVertex= srcVertexPtr + index;
00251                                 uint8                           *dstVertexVB= destVertexPtr + index * vertexSize;
00252                                 CVector                         *dstVertex= (CVector*)(dstVertexVB);
00253 
00254 
00255                                 // Vertex.
00256                                 boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, *dstVertex);
00257                         }
00258                         break;
00259 
00260                 //=========
00261                 case 1:
00262                         //  for all InfluencedVertices only.
00263                         for(;nInf>0;nInf--, infPtr++)
00264                         {
00265                                 uint    index= *infPtr;
00266                                 CMesh::CSkinWeight      *srcSkin= srcSkinPtr + index;
00267                                 CVector                         *srcVertex= srcVertexPtr + index;
00268                                 uint8                           *dstVertexVB= destVertexPtr + index * vertexSize;
00269                                 CVector                         *dstVertex= (CVector*)(dstVertexVB);
00270 
00271 
00272                                 // Vertex.
00273                                 boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex);
00274                                 boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex);
00275                         }
00276                         break;
00277 
00278                 //=========
00279                 case 2:
00280                         //  for all InfluencedVertices only.
00281                         for(;nInf>0;nInf--, infPtr++)
00282                         {
00283                                 uint    index= *infPtr;
00284                                 CMesh::CSkinWeight      *srcSkin= srcSkinPtr + index;
00285                                 CVector                         *srcVertex= srcVertexPtr + index;
00286                                 uint8                           *dstVertexVB= destVertexPtr + index * vertexSize;
00287                                 CVector                         *dstVertex= (CVector*)(dstVertexVB);
00288 
00289 
00290                                 // Vertex.
00291                                 boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex);
00292                                 boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex);
00293                                 boneMat3x4[ srcSkin->MatrixId[2] ].mulAddPoint( *srcVertex, srcSkin->Weights[2], *dstVertex);
00294                         }
00295                         break;
00296 
00297                 //=========
00298                 case 3:
00299                         //  for all InfluencedVertices only.
00300                         for(;nInf>0;nInf--, infPtr++)
00301                         {
00302                                 uint    index= *infPtr;
00303                                 CMesh::CSkinWeight      *srcSkin= srcSkinPtr + index;
00304                                 CVector                         *srcVertex= srcVertexPtr + index;
00305                                 uint8                           *dstVertexVB= destVertexPtr + index * vertexSize;
00306                                 CVector                         *dstVertex= (CVector*)(dstVertexVB);
00307 
00308 
00309                                 // Vertex.
00310                                 boneMat3x4[ srcSkin->MatrixId[0] ].mulSetPoint( *srcVertex, srcSkin->Weights[0], *dstVertex);
00311                                 boneMat3x4[ srcSkin->MatrixId[1] ].mulAddPoint( *srcVertex, srcSkin->Weights[1], *dstVertex);
00312                                 boneMat3x4[ srcSkin->MatrixId[2] ].mulAddPoint( *srcVertex, srcSkin->Weights[2], *dstVertex);
00313                                 boneMat3x4[ srcSkin->MatrixId[3] ].mulAddPoint( *srcVertex, srcSkin->Weights[3], *dstVertex);
00314                         }
00315                         break;
00316 
00317                 }
00318         }
00319 }
00320 
00321 
00322 // ***************************************************************************
00323 // ***************************************************************************
00324 // Old school Template skinning: SSE or not.
00325 // ***************************************************************************
00326 // ***************************************************************************
00327 
00328 
00329 // RawSkin Cache constants
00330 //===============
00331 // The number of byte to process per block
00332 const   uint    NL_BlockByteL1= 4096;
00333 
00334 // Number of vertices per block to process with 1 matrix.
00335 uint    CMeshMRMGeom::NumCacheVertexNormal1= NL_BlockByteL1 / sizeof(CRawVertexNormalSkin1);
00336 // Number of vertices per block to process with 2 matrix.
00337 uint    CMeshMRMGeom::NumCacheVertexNormal2= NL_BlockByteL1 / sizeof(CRawVertexNormalSkin2);
00338 // Number of vertices per block to process with 3/4 matrix.
00339 uint    CMeshMRMGeom::NumCacheVertexNormal4= NL_BlockByteL1 / sizeof(CRawVertexNormalSkin4);
00340 
00341 
00342 // Old School template: include the same file with define switching
00343 #undef NL_SKIN_SSE
00344 #include "mesh_mrm_skin_template.cpp"
00345 #define NL_SKIN_SSE
00346 #include "mesh_mrm_skin_template.cpp"
00347 
00348 
00349 
00350 // ***************************************************************************
00351 // ***************************************************************************
00352 // Misc.
00353 // ***************************************************************************
00354 // ***************************************************************************
00355 
00356 
00357 
00358 // ***************************************************************************
00359 void                            CMeshMRMGeom::fillAGPSkinPart(CLod &lod, IVertexBufferHard *currentVBHard)
00360 {
00361         // if VBHard OK
00362         if(currentVBHard)
00363         {
00364                 // lock buffer.
00365                 uint8           *vertexDst= (uint8*)currentVBHard->lock();
00366 
00367                 // do it.
00368                 fillAGPSkinPartWithVBHardPtr(lod, vertexDst);
00369 
00370                 // release
00371                 currentVBHard->unlock();
00372         }
00373 }
00374 
00375 
00376 // ***************************************************************************
00377 void                            CMeshMRMGeom::fillAGPSkinPartWithVBHardPtr(CLod &lod, uint8 *vertexDst)
00378 {
00379         // Fill AGP vertices used by this lod from RAM. (not geomorphed ones).
00380         if( lod.SkinVertexBlocks.size()>0 )
00381         {
00382                 // Get VB info, and lock buffers.
00383                 uint8           *vertexSrc= (uint8*)_VBufferFinal.getVertexCoordPointer();
00384                 uint32          vertexSize= _VBufferFinal.getVertexSize();
00385 
00386                 // big copy of all vertices and their data.
00387                 // NB: this not help RAM bandwidth, but this help AGP write combiners.
00388                 // For the majority of mesh (vertex/normal/uv), this is better (6/10).
00389 
00390                 // Also, this is a requirement for MeshMorpher to work, because the MehsMorpher may modify
00391                 // UV and color
00392 
00393 
00394                 // For all block of vertices.
00395                 CVertexBlock    *vBlock= &lod.SkinVertexBlocks[0];
00396                 uint    n= lod.SkinVertexBlocks.size();
00397 
00398                 /*
00399                         It appears that it is not a so good idea to use CFastMem::memcpySSE() here, maybe because
00400                         data is often already in cache (written by skinning), and maybe because movntq is not usefull here since
00401                         AGP is already a write-combining memory.
00402                 */
00403                 for(;n>0; n--, vBlock++)
00404                 {
00405                         // For all vertices of this block, copy it from RAM to VRAM.
00406                         uint8           *src= vertexSrc + vertexSize * vBlock->VertexStart;
00407                         uint8           *dst= vertexDst + vertexSize * vBlock->VertexStart;
00408 
00409                         memcpy(dst, src, vBlock->NVertices * vertexSize);
00410                 }
00411         }
00412 }
00413 
00414 
00415 
00416 } // NL3D
00417