# 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_shape.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 "3d/lod_character_shape.h"
00029 #include "nel/misc/vectord.h"
00030 #include "3d/fast_floor.h"
00031 #include "3d/lod_character_texture.h"
00032 #include "nel/misc/triangle.h"
00033 #include "nel/misc/polygon.h"
00034 
00035 
00036 using namespace std;
00037 using namespace NLMISC;
00038 
00039 
00040 namespace NL3D 
00041 {
00042 
00043 
00044 // ***************************************************************************
00045 // ***************************************************************************
00046 // CLodCharacterShape
00047 // ***************************************************************************
00048 // ***************************************************************************
00049 
00050 
00051 // ***************************************************************************
00052 const CLodCharacterShapeBuild::CPixelInfo               CLodCharacterShapeBuild::CPixelInfo::EmptyPixel(
00053                 CVector::Null, CVector(1000,0,0));
00054 
00055 
00056 // ***************************************************************************
00057 CLodCharacterShapeBuild::CLodCharacterShapeBuild()
00058 {
00059         _Width= 0;
00060         _Height= 0;
00061 }
00062 
00063 
00064 // ***************************************************************************
00065 void    CLodCharacterShapeBuild::compile(const std::vector<bool> &triangleSelection, uint textureOverSample)
00066 {
00067         nlassert(UVs.size()==Vertices.size());
00068         nlassert(Normals.size()==Vertices.size());
00069 
00070         // take the sqrtf.
00071         textureOverSample= (uint)sqrtf((float)textureOverSample);
00072         textureOverSample= max(textureOverSample, 1U);
00073 
00074         _Width= NL3D_CLOD_TEXT_WIDTH;
00075         _Height= NL3D_CLOD_TEXT_HEIGHT;
00076 
00077         uint    wOver= _Width*textureOverSample;
00078         uint    hOver= _Height*textureOverSample;
00079         std::vector<CPixelInfo>         overTextureInfo;
00080 
00081         // do some tri selection?
00082         bool    triSelectOk= triangleSelection.size()==TriangleIndices.size()/3;
00083 
00084 
00085         // **** reset the texture and init with "empty" pixel (ie normal.x==1000, which is not possible because normal.norm()==1)
00086         _TextureInfo.resize(_Width*_Height);
00087         fill(_TextureInfo.begin(), _TextureInfo.end(), CPixelInfo::EmptyPixel);
00088         // do it to the oversampled texture
00089         overTextureInfo.resize(wOver*hOver, CPixelInfo::EmptyPixel);
00090 
00091 
00092         // **** For each triangle in the shape, polyfill this triangle from a texture view, in the overSampledTexture
00093         CPolygon2D      poly;
00094         poly.Vertices.resize(3);
00095         for(uint i=0; i<TriangleIndices.size();i+=3)
00096         {
00097                 // if selection OK, and the tri is not selected, skip
00098                 if(triSelectOk && !triangleSelection[i/3])
00099                         continue;
00100 
00101                 // Setup triangle.
00102                 // -----------
00103                 uint    idx[3];
00104                 idx[0]= TriangleIndices[i+0];
00105                 idx[1]= TriangleIndices[i+1];
00106                 idx[2]= TriangleIndices[i+2];
00107                 // compute corners UVs, in texel size
00108                 CTriangle               triangleUV;
00109                 triangleUV.V0= CVector(UVs[idx[0]].U*wOver, UVs[idx[0]].V*hOver, 0);
00110                 triangleUV.V1= CVector(UVs[idx[1]].U*wOver, UVs[idx[1]].V*hOver, 0);
00111                 triangleUV.V2= CVector(UVs[idx[2]].U*wOver, UVs[idx[2]].V*hOver, 0);
00112                 // compute corners pixelInfos 
00113                 CPixelInfo              pInf[3];
00114                 for(uint corner=0; corner<3; corner++)
00115                 {
00116                         pInf[corner].Pos= Vertices[idx[corner]];
00117                         pInf[corner].Normal= Normals[idx[corner]];
00118                 }
00119                 // Compute Gradients
00120                 CVector         GradPosX, GradPosY, GradPosZ;
00121                 CVector         GradNormalX, GradNormalY, GradNormalZ;
00122                 triangleUV.computeGradient(pInf[0].Pos.x, pInf[1].Pos.x, pInf[2].Pos.x, GradPosX);
00123                 triangleUV.computeGradient(pInf[0].Pos.y, pInf[1].Pos.y, pInf[2].Pos.y, GradPosY);
00124                 triangleUV.computeGradient(pInf[0].Pos.z, pInf[1].Pos.z, pInf[2].Pos.z, GradPosZ);
00125                 triangleUV.computeGradient(pInf[0].Normal.x, pInf[1].Normal.x, pInf[2].Normal.x, GradNormalX);
00126                 triangleUV.computeGradient(pInf[0].Normal.y, pInf[1].Normal.y, pInf[2].Normal.y, GradNormalY);
00127                 triangleUV.computeGradient(pInf[0].Normal.z, pInf[1].Normal.z, pInf[2].Normal.z, GradNormalZ);
00128                 // Compute Gradients offset
00129                 float           OffPosX, OffPosY, OffPosZ;
00130                 float           OffNormalX, OffNormalY, OffNormalZ;
00131                 OffPosX= pInf[0].Pos.x - GradPosX*triangleUV.V0;
00132                 OffPosY= pInf[0].Pos.y - GradPosY*triangleUV.V0;
00133                 OffPosZ= pInf[0].Pos.z - GradPosZ*triangleUV.V0;
00134                 OffNormalX= pInf[0].Normal.x - GradNormalX*triangleUV.V0;
00135                 OffNormalY= pInf[0].Normal.y - GradNormalY*triangleUV.V0;
00136                 OffNormalZ= pInf[0].Normal.z - GradNormalZ*triangleUV.V0;
00137 
00138 
00139                 // PolyFiller
00140                 // -----------
00141                 CVector2f       dCenter(0.5f, 0.5f);
00142                 // select texels if their centers is in the triangle
00143                 poly.Vertices[0]= triangleUV.V0-dCenter;
00144                 poly.Vertices[1]= triangleUV.V1-dCenter;
00145                 poly.Vertices[2]= triangleUV.V2-dCenter;
00146                 // polyFiller
00147                 CPolygon2D::TRasterVect rasters;
00148                 sint    minY;
00149                 poly.computeBorders(rasters, minY);
00150                 for(sint y=0;y<(sint)rasters.size();y++)
00151                 {
00152                         sint x0= rasters[y].first;
00153                         sint x1= rasters[y].second;
00154                         CVector v;
00155                         // get the center coord of this texel
00156                         v.y= y+minY+0.5f;
00157                         v.z= 0;
00158                         for(sint x=x0;x<=x1;x++)
00159                         {
00160                                 // get the center coord of this texel
00161                                 v.x= x+0.5f;
00162                                 // Compute Pos/Normal on this texel.
00163                                 CPixelInfo      texelInf;
00164                                 texelInf.Pos.x= OffPosX + GradPosX * v;
00165                                 texelInf.Pos.y= OffPosY + GradPosY * v;
00166                                 texelInf.Pos.z= OffPosZ + GradPosZ * v;
00167                                 texelInf.Normal.x= OffNormalX + GradNormalX * v;
00168                                 texelInf.Normal.y= OffNormalY + GradNormalY * v;
00169                                 texelInf.Normal.z= OffNormalZ + GradNormalZ * v;
00170                                 // normalize.
00171                                 texelInf.Normal.normalize();
00172                                 // Store (NB: overwrite any pixel)
00173                                 sint    texX= ((uint)x)%wOver;
00174                                 sint    texY= ((uint)y+minY)%hOver;
00175                                 overTextureInfo[texY*wOver+texX]= texelInf;
00176                         }
00177                 }
00178 
00179         }
00180 
00181 
00182         // **** Down sample the overSampled texture.
00183         sint    x,y;
00184         if(textureOverSample==1)
00185         {
00186                 _TextureInfo= overTextureInfo;
00187         }
00188         else
00189         {
00190                 // eg: 3 gives 1. delta ranges from -1 to 1.
00191                 float   middle= (textureOverSample-1)/2.f;
00192 
00193                 // for all pixels.
00194                 for(y=0;y<(sint)_Height;y++)
00195                 {
00196                         for(x=0;x<(sint)_Width;x++)
00197                         {
00198                                 // for all samples, take the best one.
00199                                 sint            xo, yo;
00200                                 float           bestDist= FLT_MAX;
00201                                 CPixelInfo      bestPixel= CPixelInfo::EmptyPixel;
00202                                 for(yo=0;yo<(sint)textureOverSample;yo++)
00203                                 {
00204                                         for(xo=0;xo<(sint)textureOverSample;xo++)
00205                                         {
00206                                                 // compute distance to the pixel center.
00207                                                 float   dist= sqr(yo-middle)+sqr(xo-middle);
00208                                                 const CPixelInfo        &overPixel= overTextureInfo[(y*textureOverSample+yo)*wOver+(x*textureOverSample+xo)];
00209                                                 // if the overPixel is not empty.
00210                                                 if( !(overPixel==CPixelInfo::EmptyPixel) )
00211                                                 {
00212                                                         // take it if the best: nearest to the pixel center.
00213                                                         if(dist<bestDist)
00214                                                         {
00215                                                                 bestDist= dist;
00216                                                                 bestPixel= overPixel;
00217                                                         }
00218                                                 }
00219                                         }
00220                                 }
00221 
00222                                 // fill textureInfo
00223                                 _TextureInfo[y*_Width+x]= bestPixel;
00224                         }
00225                 }
00226         }
00227 
00228 
00229         // **** Dilate texture 1 time: each empty pixel info get neighbor full pixel (8box)
00230         // copy the non dilated texture
00231         std::vector<CPixelInfo>         tmpTextureInfo= _TextureInfo;
00232         // process all pixels
00233         for(y=0;y<(sint)_Height;y++)
00234         {
00235                 sint    y0=y-1, y1=y+1;
00236                 y0= max(y0, 0);
00237                 y1= min(y1, (sint)_Height-1);
00238                 for(x=0;x<(sint)_Width;x++)
00239                 {
00240                         CPixelInfo      &texelInf= _TextureInfo[y*_Width+x];
00241                         // if an empty pixel.
00242                         if(texelInf==CPixelInfo::EmptyPixel)
00243                         {
00244                                 // dilate: look around for non empty pixel.
00245                                 sint    x0=x-1, x1=x+1;
00246                                 x0= max(x0, 0);
00247                                 x1= min(x1, (sint)_Width-1);
00248                                 // For the 8 possible pixels (nb: look us too, but doesn't matter since we are an empty pixel)
00249                                 for(sint yb= y0; yb<=y1;yb++)
00250                                 {
00251                                         for(sint xb= x0; xb<=x1;xb++)
00252                                         {
00253                                                 // if the neighbor is not an empty pixel. NB: avoid override problems using not Dilated texture
00254                                                 CPixelInfo      &nbTexelInf= tmpTextureInfo[yb*_Width+xb];
00255                                                 if( !(nbTexelInf==CPixelInfo::EmptyPixel) )
00256                                                 {
00257                                                         // write it in the center pixel, and skip the search
00258                                                         texelInf= nbTexelInf;
00259                                                         yb= y1+1;
00260                                                         break;
00261                                                 }
00262                                         }
00263                                 }
00264                         }
00265                 }
00266         }
00267 
00268 }
00269 
00270 
00271 // ***************************************************************************
00272 void    CLodCharacterShapeBuild::serial(NLMISC::IStream &f)
00273 {
00274         // NEL_CLODBULD
00275         f.serialCheck((uint32)'_LEN');
00276         f.serialCheck((uint32)'DOLC');
00277         f.serialCheck((uint32)'DLUB');
00278 
00279         /*
00280         Version 1:
00281                 - UVs and Normals + texture info
00282         */
00283         sint    ver= f.serialVersion(1);
00284 
00285         f.serialCont(Vertices);
00286         f.serialCont(SkinWeights);
00287         f.serialCont(BonesNames);
00288         f.serialCont(TriangleIndices);
00289 
00290         if(ver>=1)
00291         {
00292                 f.serialCont(UVs);
00293                 f.serialCont(Normals);
00294                 f.serial(_Width, _Height);
00295                 f.serialCont(_TextureInfo);
00296         }
00297         else
00298         {
00299                 // Must init dummy UVs/normals
00300                 UVs.resize(Vertices.size(), CUV(0,0));
00301                 Normals.resize(Vertices.size(), CVector::K);
00302                 // Must init dummy texture
00303                 _Width= NL3D_CLOD_TEXT_WIDTH;
00304                 _Height= NL3D_CLOD_TEXT_HEIGHT;
00305                 _TextureInfo.resize(_Width*_Height, CPixelInfo::EmptyPixel);
00306         }
00307 
00308 }
00309 
00310 
00311 // ***************************************************************************
00312 const CLodCharacterShapeBuild::CPixelInfo       *CLodCharacterShapeBuild::getTextureInfoPtr()
00313 {
00314         if(_TextureInfo.empty())
00315                 return NULL;
00316         else
00317                 return &_TextureInfo[0];
00318 }
00319 
00320 
00321 // ***************************************************************************
00322 // ***************************************************************************
00323 // CLodCharacterShape
00324 // ***************************************************************************
00325 // ***************************************************************************
00326 
00327 
00328 // ***************************************************************************
00329 CLodCharacterShape::CLodCharacterShape()
00330 {
00331         _NumVertices= 0;
00332         _NumTriangles= 0;
00333 }
00334 
00335 // ***************************************************************************
00336 void                    CLodCharacterShape::buildMesh(const std::string &name, const CLodCharacterShapeBuild &lodBuild)
00337 {
00338         uint    numVertices= lodBuild.Vertices.size();
00339         const vector<uint32>                            &triangleIndices= lodBuild.TriangleIndices;
00340         const vector<CMesh::CSkinWeight>        &skinWeights= lodBuild.SkinWeights;
00341         const vector<CUV>                                       &uvs= lodBuild.UVs;
00342         const vector<CVector>                           &normals= lodBuild.Normals;
00343 
00344         nlassert(numVertices>0);
00345         nlassert(triangleIndices.size()>0);
00346         nlassert((triangleIndices.size()%3)==0);
00347         nlassert(skinWeights.size() == numVertices);
00348         nlassert(uvs.size() == numVertices);
00349         nlassert(normals.size() == numVertices);
00350 
00351         // reset data
00352         contReset(_Anims);
00353         contReset(_AnimMap);
00354         contReset(_Bones);
00355         contReset(_BoneMap);
00356         contReset(_TriangleIndices);
00357         contReset(_UVs);
00358         contReset(_Normals);
00359 
00360         // Copy data.
00361         _Name= name;
00362         _NumVertices= numVertices;
00363         _NumTriangles= triangleIndices.size()/3;
00364         _TriangleIndices= triangleIndices;
00365         _UVs= uvs;
00366         _Normals= normals;
00367 
00368         // check indices.
00369         uint    i;
00370         for(i=0;i<triangleIndices.size();i++)
00371         {
00372                 nlassert(triangleIndices[i]<_NumVertices);
00373         }
00374 
00375         // Copy bone names, and compute bone Map
00376         _Bones.resize(lodBuild.BonesNames.size());
00377         for(i=0; i<_Bones.size(); i++)
00378         {
00379                 _Bones[i].Name= lodBuild.BonesNames[i];
00380                 _BoneMap.insert( make_pair(_Bones[i].Name, i) );
00381         }
00382 
00383         // "Normalize" SkinWeights for CLodCharacterShape
00384         for(i=0;i<skinWeights.size();i++)
00385         {
00386                 nlassert(skinWeights[i].Weights[0]>0);
00387                 // for all slots not 0
00388                 for(uint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
00389                 {
00390                         // if this this slot is used.
00391                         if(skinWeights[i].Weights[j]>0)
00392                         {
00393                                 uint boneId= skinWeights[i].MatrixId[j];
00394                                 nlassert(boneId < _Bones.size());
00395                                 // init the vInf data
00396                                 CVertexInf      vInf;
00397                                 vInf.VertexId= i;
00398                                 vInf.Influence= skinWeights[i].Weights[j];
00399                                 // Insert this vertex influence in the bone.
00400                                 _Bones[boneId].InfVertices.push_back(vInf);
00401                         }
00402                         else
00403                                 // stop for this vertex.
00404                                 break;
00405                 }
00406         }
00407 }
00408 
00409 // ***************************************************************************
00410 bool                    CLodCharacterShape::addAnim(const CAnimBuild &animBuild)
00411 {
00412         // first, verify don't exist.
00413         if(getAnimIdByName(animBuild.Name)!=-1)
00414                 return false;
00415 
00416         // build basics of the animation
00417         CAnim   dstAnim;
00418         dstAnim.Name= animBuild.Name;
00419         dstAnim.AnimLength= animBuild.AnimLength;
00420         // Possible to have an Anim with just one key. setup an epsilon for animLength if 0.
00421         if(dstAnim.AnimLength<=0)
00422                 dstAnim.AnimLength= 0.001f;
00423         dstAnim.OOAnimLength= 1.0f / animBuild.AnimLength;
00424         dstAnim.NumKeys= animBuild.NumKeys;
00425         // verify size of the array
00426         nlassert(dstAnim.NumKeys>0);
00427         nlassert(dstAnim.NumKeys * _NumVertices == animBuild.Keys.size());
00428         // resize dest array
00429         dstAnim.Keys.resize(animBuild.Keys.size());
00430 
00431 
00432         // Pack animation. 1st pass: compute max size over the animation vertices
00433         uint    i;
00434         // minimum shape size is , say, 1 cm :)
00435         CVector         maxSize(0.01f, 0.01f, 0.01f);
00436         for(i=0;i<animBuild.Keys.size();i++)
00437         {
00438                 // take the maxSize of the abs values
00439                 maxSize.maxof(maxSize, -animBuild.Keys[i]);
00440                 maxSize.maxof(maxSize, animBuild.Keys[i]);
00441         }
00442 
00443         // compute the UnPackScaleFactor ie maxSize, to be multiplied by max Abs value of a sint16
00444         dstAnim.UnPackScaleFactor= maxSize * (1.0f/32767);
00445 
00446         // Pack animation. 2st pass: pack.
00447         CVectorD                packScaleFactor;
00448         packScaleFactor.x= 1.0 / dstAnim.UnPackScaleFactor.x;
00449         packScaleFactor.y= 1.0 / dstAnim.UnPackScaleFactor.y;
00450         packScaleFactor.z= 1.0 / dstAnim.UnPackScaleFactor.z;
00451         // For all key vertices
00452         for(i=0;i<animBuild.Keys.size();i++)
00453         {
00454                 CVector         v= animBuild.Keys[i];
00455                 CVector3s       &dstV= dstAnim.Keys[i];
00456 
00457                 // compress
00458                 v.x= float(v.x*packScaleFactor.x);
00459                 v.y= float(v.y*packScaleFactor.y);
00460                 v.z= float(v.z*packScaleFactor.z);
00461                 // clamp to sint16 limits (for float precision problems).
00462                 clamp(v.x, -32767, 32767);
00463                 clamp(v.y, -32767, 32767);
00464                 clamp(v.z, -32767, 32767);
00465                 // get into the vector3s
00466                 dstV.x= (sint16)floor(v.x);
00467                 dstV.y= (sint16)floor(v.y);
00468                 dstV.z= (sint16)floor(v.z);
00469         }
00470 
00471 
00472         // Add the anim to the array, and add an entry to the map
00473         _Anims.push_back(dstAnim);
00474         _AnimMap.insert(make_pair(dstAnim.Name, _Anims.size()-1));
00475 
00476         return true;
00477 }
00478 
00479 // ***************************************************************************
00480 void                    CLodCharacterShape::CAnim::serial(NLMISC::IStream &f)
00481 {
00482         (void)f.serialVersion(0);
00483 
00484         f.serial(Name);
00485         f.serial(NumKeys);
00486         f.serial(AnimLength);
00487         f.serial(OOAnimLength);
00488         f.serial(UnPackScaleFactor);
00489         f.serialCont(Keys);
00490 }
00491 
00492 
00493 // ***************************************************************************
00494 void                    CLodCharacterShape::CBoneInfluence::serial(NLMISC::IStream &f)
00495 {
00496         (void)f.serialVersion(0);
00497 
00498         f.serial(Name);
00499         f.serialCont(InfVertices);
00500 }
00501 
00502 
00503 // ***************************************************************************
00504 void                    CLodCharacterShape::serial(NLMISC::IStream &f)
00505 {
00506         // NEL_CLODSHAP
00507         f.serialCheck((uint32)'_LEN');
00508         f.serialCheck((uint32)'DOLC');
00509         f.serialCheck((uint32)'PAHS');
00510 
00511         /*
00512         Version 1:
00513                 - UVs and Normals.
00514         */
00515         sint ver= f.serialVersion(1);
00516 
00517         f.serial(_Name);
00518         f.serial(_NumVertices);
00519         f.serial(_NumTriangles);
00520         f.serialCont(_Bones);
00521         f.serialCont(_BoneMap);
00522         f.serialCont(_TriangleIndices);
00523         f.serialCont(_Anims);
00524         f.serialCont(_AnimMap);
00525 
00526         if(ver>=1)
00527         {
00528                 f.serialCont(_UVs);
00529                 f.serialCont(_Normals);
00530         }
00531         else
00532         {
00533                 // Must init dummy UVs/normals
00534                 _UVs.resize(_NumVertices, CUV(0,0));
00535                 _Normals.resize(_NumVertices, CVector::K);
00536         }
00537 }
00538 
00539 // ***************************************************************************
00540 sint                    CLodCharacterShape::getAnimIdByName(const std::string &name) const
00541 {
00542         CstItStrIdMap   it= _AnimMap.find(name);
00543         if(it == _AnimMap.end())
00544                 return -1;
00545         else
00546                 return it->second;
00547 }
00548 
00549 
00550 // ***************************************************************************
00551 sint                    CLodCharacterShape::getBoneIdByName(const std::string &name) const
00552 {
00553         CstItStrIdMap   it= _BoneMap.find(name);
00554         if(it == _BoneMap.end())
00555                 return -1;
00556         else
00557                 return it->second;
00558 }
00559 
00560 
00561 // ***************************************************************************
00562 const uint32    *CLodCharacterShape::getTriangleArray() const
00563 {
00564         if(_NumTriangles)
00565                 return &_TriangleIndices[0];
00566         else
00567                 return NULL;
00568 }
00569 
00570 // ***************************************************************************
00571 const CLodCharacterShape::CVector3s     *CLodCharacterShape::getAnimKey(uint animId, TGlobalAnimationTime time, bool wrapMode, CVector &unPackScaleFactor) const
00572 {
00573         float   localTime;
00574 
00575         if(animId>=_Anims.size())
00576                 return NULL;
00577 
00578         // get the anim.
00579         const CAnim &anim= _Anims[animId];
00580 
00581         // scale info
00582         unPackScaleFactor= anim.UnPackScaleFactor;
00583 
00584         // Loop mgt.
00585         if(wrapMode)
00586                 localTime= (float)fmod(time, anim.AnimLength);
00587         else
00588                 localTime= (float)time;
00589 
00590         // Clamp to the range.
00591         clamp(localTime, 0, anim.AnimLength);
00592 
00593         // get the key.
00594         sint    keyId= (sint)floor( (localTime*anim.OOAnimLength) * anim.NumKeys );
00595         clamp(keyId, 0, sint(anim.NumKeys-1));
00596 
00597         // return the key.
00598         return &anim.Keys[keyId * _NumVertices];
00599 }
00600 
00601 // ***************************************************************************
00602 const CUV               *CLodCharacterShape::getUVs() const
00603 {
00604         if(_NumVertices==0)
00605                 return NULL;
00606 
00607         return &_UVs[0];
00608 }
00609 
00610 // ***************************************************************************
00611 const CVector   *CLodCharacterShape::getNormals() const
00612 {
00613         if(_NumVertices==0)
00614                 return NULL;
00615 
00616         return &_Normals[0];
00617 }
00618 
00619 
00620 
00621 // ***************************************************************************
00622 // ***************************************************************************
00623 // Bone coloring
00624 // ***************************************************************************
00625 // ***************************************************************************
00626 
00627 
00628 // ***************************************************************************
00629 void                    CLodCharacterShape::startBoneColor(std::vector<NLMISC::CRGBAF>  &tmpColors) const
00630 {
00631         // alocate
00632         tmpColors.resize(getNumVertices());
00633         // fill with black (in Alpha too)
00634         CRGBAF  black(0,0,0,0);
00635         fill(tmpColors.begin(), tmpColors.end(), black);
00636 }
00637 
00638 // ***************************************************************************
00639 void                    CLodCharacterShape::addBoneColor(uint boneId, CRGBA     color, std::vector<NLMISC::CRGBAF> &tmpColors) const
00640 {
00641         // Yoyo: This is an error to not have the same skeleton that the one stored in the lod shape. But must not crash
00642         if(boneId>=_Bones.size())
00643                 return;
00644         const CBoneInfluence    &bone= _Bones[boneId];
00645 
00646         // for all vertices influenced by this bone, must influence the color
00647         for(uint i=0; i<bone.InfVertices.size(); i++)
00648         {
00649                 const CVertexInf        &vInf= bone.InfVertices[i];
00650                 // Add the color, modulated by the vertex weight
00651                 tmpColors[vInf.VertexId].R+= color.R * vInf.Influence;
00652                 tmpColors[vInf.VertexId].G+= color.G * vInf.Influence;
00653                 tmpColors[vInf.VertexId].B+= color.B * vInf.Influence;
00654                 // Add the weight in alpha channel
00655                 tmpColors[vInf.VertexId].A+= vInf.Influence;
00656         }
00657 }
00658 
00659 // ***************************************************************************
00660 void                    CLodCharacterShape::endBoneColor(const std::vector<NLMISC::CRGBAF> &tmpColors, std::vector<NLMISC::CRGBA>       &dstColors) const
00661 {
00662         // The default value if vertex is not influenced at all
00663         CRGBA   defaultColor(128,128,128,0);
00664 
00665         // resize dstColors
00666         nlassert(tmpColors.size() == getNumVertices());
00667         dstColors.resize(getNumVertices());
00668 
00669         // For all vertices
00670         for(uint i=0; i<dstColors.size(); i++)
00671         {
00672                 // If the vertex is not influenced, set transparent
00673                 if(tmpColors[i].A==0)
00674                         dstColors[i]= defaultColor;
00675                 else
00676                 {
00677                         // Average the color.
00678                         float   R= tmpColors[i].R / tmpColors[i].A;
00679                         float   G= tmpColors[i].G / tmpColors[i].A;
00680                         float   B= tmpColors[i].B / tmpColors[i].A;
00681                         // store.
00682                         dstColors[i].R= (uint8)OptFastFloor(R);
00683                         dstColors[i].G= (uint8)OptFastFloor(G);
00684                         dstColors[i].B= (uint8)OptFastFloor(B);
00685                         dstColors[i].A= 255;
00686                 }
00687         }
00688 }
00689 
00690 
00691 
00692 } // NL3D