# 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  

lod_character_builder.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 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/debug.h"
00029 #include "3d/lod_character_builder.h"
00030 #include "3d/scene.h"
00031 #include "3d/skeleton_shape.h"
00032 #include "3d/mesh.h"
00033 #include "3d/skeleton_model.h"
00034 
00035 
00036 using namespace std;
00037 using namespace NLMISC;
00038 
00039 
00040 namespace NL3D 
00041 {
00042 
00043 
00044 // ***************************************************************************
00045 CLodCharacterBuilder::CLodCharacterBuilder()
00046 {
00047         _SkeletonShape= NULL;
00048         _LodBuild= NULL;
00049         _TmpScene= NULL;
00050 }
00051 // ***************************************************************************
00052 CLodCharacterBuilder::~CLodCharacterBuilder()
00053 {
00054         // release the scene
00055         if(_TmpScene)
00056         {
00057                 _TmpScene->release();
00058                 delete _TmpScene;
00059                 _TmpScene= NULL;
00060         }
00061 }
00062 
00063 // ***************************************************************************
00064 void                    CLodCharacterBuilder::setShape(const std::string &name, CSkeletonShape *skeletonShape, CLodCharacterShapeBuild *lodBuild)
00065 {
00066         nlassert(skeletonShape);
00067         nlassert(lodBuild);
00068 
00069         // SmartPtr the skeleton Shape (NB: important because skeletonModel use it)
00070         _SkeletonShape= skeletonShape;
00071         // a std ptr.
00072         _LodBuild= lodBuild;
00073 
00074         // Remap bone, with help of lodBuild and skeleton names.
00075         _BoneRemap.resize(lodBuild->BonesNames.size());
00076         for(uint i=0; i<_BoneRemap.size(); i++)
00077         {
00078                 const std::string       &boneName= lodBuild->BonesNames[i];
00079                 sint32  boneId= _SkeletonShape->getBoneIdByName(boneName);
00080                 // If not found
00081                 if(boneId<0)
00082                 {
00083                         nlwarning("Not found a bone in the skeleton Shape: %s", boneName.c_str());
00084                         // use root bone.
00085                         _BoneRemap[i]= 0;
00086                 }
00087                 else
00088                         // remap
00089                         _BoneRemap[i]= boneId;
00090         }
00091 
00092         // build basics
00093         _LodCharacterShape.buildMesh(name, *_LodBuild);
00094 
00095         // Build a scene, for addAnim purpose
00096         if(!_TmpScene)
00097         {
00098                 _TmpScene= new CScene;
00099                 // Must init Statics for scene (because use it in addAnim). NB: never mind if done twice.
00100                 CScene::registerBasics();
00101                 // init scene travs
00102                 _TmpScene->initDefaultTravs();
00103                 // Don't add any user trav.
00104                 // init default Roots.
00105                 _TmpScene->initDefaultRoots();
00106                 // Don't Set driver/viewport
00107                 // Init the world instance group
00108                 _TmpScene->initGlobalnstanceGroup();
00109                 // Init coarse mesh manager
00110                 _TmpScene->initCoarseMeshManager ();
00111                 // init QuadGridClipManager
00112                 _TmpScene->initQuadGridClipManager ();
00113         }
00114 }
00115 
00116 
00117 // ***************************************************************************
00118 void                    CLodCharacterBuilder::addAnim(const char *animName, CAnimation *animation, float frameRate)
00119 {
00120         nlassert(frameRate>0);
00121         nlassert(animation);
00122 
00123         /*      Create a Scene, a skeletonModel, an animation set, and a channel mixer to play the animation
00124                 NB: no render is made and no driver is created. The scene is just here for correct creation of the skeleton
00125                 Yoyo: This is a tricky way, but I found it the easier one...
00126         */
00127 
00128         // Create Components necesssary to play the animation
00129         //==========================
00130 
00131         // create an animationSet, and a channelMixer.
00132         //--------------
00133         // build an animation set with the only one animation. This animation will be deleted with the animationSet
00134         CAnimationSet   *tmpAnimationSet= new CAnimationSet;
00135         tmpAnimationSet->addAnimation(animName, animation);
00136         tmpAnimationSet->build();
00137         // Build a channelMixer.
00138         CChannelMixer   *tmpChannelMixer= new CChannelMixer;
00139         tmpChannelMixer->setAnimationSet(tmpAnimationSet);
00140 
00141 
00142         // create a skeleton Model for animation
00143         //---------------
00144         CSkeletonModel  *skeleton= (CSkeletonModel*)_SkeletonShape->createInstance(*_TmpScene);
00145         // and skeleton it with animation
00146         skeleton->registerToChannelMixer(tmpChannelMixer, "");
00147         // activate the anim
00148         uint animID = tmpAnimationSet->getAnimationIdByName(animName);
00149         nlassert(animID != CAnimationSet::NotFound);
00150         tmpChannelMixer->setSlotAnimation(0, animID);
00151 
00152 
00153         // Build Dst Animation basics.
00154         //--------------
00155         CLodCharacterShape::CAnimBuild  dstAnim;
00156         dstAnim.Name= animName;
00157         dstAnim.AnimLength= animation->getEndTime();
00158         dstAnim.NumKeys= (uint)ceil(dstAnim.AnimLength * frameRate);
00159         dstAnim.NumKeys= max(1U, dstAnim.NumKeys);
00160         // resize array.
00161         dstAnim.Keys.resize(_LodCharacterShape.getNumVertices() * dstAnim.NumKeys);
00162 
00163 
00164         // Bake the animation
00165         //==========================
00166         double  time=0;
00167         double  dt= 1.0/(double)frameRate;
00168         uint64  evalDetaiDate= 0;
00169         for(uint i=0; i<dstAnim.NumKeys; i++, time+= dt)
00170         {
00171                 // clamp the time
00172                 time= min(time, (double)dstAnim.AnimLength);
00173 
00174                 // setup the channelMixer time
00175                 tmpChannelMixer->setSlotTime(0, (float)time);
00176 
00177                 // Eval the channelMixer, both global and detail
00178                 tmpChannelMixer->eval(false);
00179                 tmpChannelMixer->eval(true, evalDetaiDate++);
00180 
00181                 // Use the skeleton model to compute bone skin matrix, supposing an identity skeleton worldMatrix
00182                 skeleton->computeAllBones(CMatrix::Identity);
00183 
00184                 // apply the skinning from the current skeleton state
00185                 applySkin(skeleton, &dstAnim.Keys[i*_LodCharacterShape.getNumVertices()]);
00186         }
00187 
00188 
00189         // Add the animation to the lod
00190         //==========================
00191         _LodCharacterShape.addAnim(dstAnim);
00192 
00193 
00194         // Delete
00195         //==========================
00196         // release the skeleton
00197         _TmpScene->deleteModel(skeleton);
00198         // delete the channelMixer
00199         delete tmpChannelMixer;
00200         // delete the animationSet
00201         delete tmpAnimationSet;
00202 }
00203 
00204 
00205 // ***************************************************************************
00206 void                    CLodCharacterBuilder::applySkin(CSkeletonModel *skeleton, CVector       *dstVertices)
00207 {
00208         uint    numVerts= _LodBuild->Vertices.size();
00209 
00210         // for all vertices.
00211         for(uint i=0; i<numVerts; i++)
00212         {
00213                 CMesh::CSkinWeight      &skinWgt= _LodBuild->SkinWeights[i];
00214                 CVector                         &srcVert= _LodBuild->Vertices[i];
00215                 CVector                         &dstVert= dstVertices[i];
00216                 dstVert= CVector::Null;
00217                 // parse all Weights, and add influence.
00218                 for(uint j=0; j<NL3D_MESH_SKINNING_MAX_MATRIX; j++)
00219                 {
00220                         float   wgt= skinWgt.Weights[j];
00221 
00222                         if(wgt==0)
00223                         {
00224                                 // this should not happen, at least weight 0 should have an influence.
00225                                 if(j==0)
00226                                         dstVert= srcVert;
00227                                 // no more influence for this vertex.
00228                                 break;
00229                         }
00230                         else
00231                         {
00232                                 // Get the skeleton bone to read.
00233                                 uint    boneId= _BoneRemap[skinWgt.MatrixId[j]];
00234                                 // Get the computed matrix from the skeleton.
00235                                 const   CMatrix &boneMat= skeleton->Bones[boneId].getBoneSkinMatrix();
00236                                 // Add the influence of this bone.
00237                                 dstVert+= (boneMat * srcVert) * wgt;
00238                         }
00239                 }
00240         }
00241 }
00242 
00243 
00244 } // NL3D