00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
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
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
00082 bool triSelectOk= triangleSelection.size()==TriangleIndices.size()/3;
00083
00084
00085
00086 _TextureInfo.resize(_Width*_Height);
00087 fill(_TextureInfo.begin(), _TextureInfo.end(), CPixelInfo::EmptyPixel);
00088
00089 overTextureInfo.resize(wOver*hOver, CPixelInfo::EmptyPixel);
00090
00091
00092
00093 CPolygon2D poly;
00094 poly.Vertices.resize(3);
00095 for(uint i=0; i<TriangleIndices.size();i+=3)
00096 {
00097
00098 if(triSelectOk && !triangleSelection[i/3])
00099 continue;
00100
00101
00102
00103 uint idx[3];
00104 idx[0]= TriangleIndices[i+0];
00105 idx[1]= TriangleIndices[i+1];
00106 idx[2]= TriangleIndices[i+2];
00107
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
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
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
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
00140
00141 CVector2f dCenter(0.5f, 0.5f);
00142
00143 poly.Vertices[0]= triangleUV.V0-dCenter;
00144 poly.Vertices[1]= triangleUV.V1-dCenter;
00145 poly.Vertices[2]= triangleUV.V2-dCenter;
00146
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
00156 v.y= y+minY+0.5f;
00157 v.z= 0;
00158 for(sint x=x0;x<=x1;x++)
00159 {
00160
00161 v.x= x+0.5f;
00162
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
00171 texelInf.Normal.normalize();
00172
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
00183 sint x,y;
00184 if(textureOverSample==1)
00185 {
00186 _TextureInfo= overTextureInfo;
00187 }
00188 else
00189 {
00190
00191 float middle= (textureOverSample-1)/2.f;
00192
00193
00194 for(y=0;y<(sint)_Height;y++)
00195 {
00196 for(x=0;x<(sint)_Width;x++)
00197 {
00198
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
00207 float dist= sqr(yo-middle)+sqr(xo-middle);
00208 const CPixelInfo &overPixel= overTextureInfo[(y*textureOverSample+yo)*wOver+(x*textureOverSample+xo)];
00209
00210 if( !(overPixel==CPixelInfo::EmptyPixel) )
00211 {
00212
00213 if(dist<bestDist)
00214 {
00215 bestDist= dist;
00216 bestPixel= overPixel;
00217 }
00218 }
00219 }
00220 }
00221
00222
00223 _TextureInfo[y*_Width+x]= bestPixel;
00224 }
00225 }
00226 }
00227
00228
00229
00230
00231 std::vector<CPixelInfo> tmpTextureInfo= _TextureInfo;
00232
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
00242 if(texelInf==CPixelInfo::EmptyPixel)
00243 {
00244
00245 sint x0=x-1, x1=x+1;
00246 x0= max(x0, 0);
00247 x1= min(x1, (sint)_Width-1);
00248
00249 for(sint yb= y0; yb<=y1;yb++)
00250 {
00251 for(sint xb= x0; xb<=x1;xb++)
00252 {
00253
00254 CPixelInfo &nbTexelInf= tmpTextureInfo[yb*_Width+xb];
00255 if( !(nbTexelInf==CPixelInfo::EmptyPixel) )
00256 {
00257
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
00275 f.serialCheck((uint32)'_LEN');
00276 f.serialCheck((uint32)'DOLC');
00277 f.serialCheck((uint32)'DLUB');
00278
00279
00280
00281
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
00300 UVs.resize(Vertices.size(), CUV(0,0));
00301 Normals.resize(Vertices.size(), CVector::K);
00302
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
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
00352 contReset(_Anims);
00353 contReset(_AnimMap);
00354 contReset(_Bones);
00355 contReset(_BoneMap);
00356 contReset(_TriangleIndices);
00357 contReset(_UVs);
00358 contReset(_Normals);
00359
00360
00361 _Name= name;
00362 _NumVertices= numVertices;
00363 _NumTriangles= triangleIndices.size()/3;
00364 _TriangleIndices= triangleIndices;
00365 _UVs= uvs;
00366 _Normals= normals;
00367
00368
00369 uint i;
00370 for(i=0;i<triangleIndices.size();i++)
00371 {
00372 nlassert(triangleIndices[i]<_NumVertices);
00373 }
00374
00375
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
00384 for(i=0;i<skinWeights.size();i++)
00385 {
00386 nlassert(skinWeights[i].Weights[0]>0);
00387
00388 for(uint j=0;j<NL3D_MESH_SKINNING_MAX_MATRIX;j++)
00389 {
00390
00391 if(skinWeights[i].Weights[j]>0)
00392 {
00393 uint boneId= skinWeights[i].MatrixId[j];
00394 nlassert(boneId < _Bones.size());
00395
00396 CVertexInf vInf;
00397 vInf.VertexId= i;
00398 vInf.Influence= skinWeights[i].Weights[j];
00399
00400 _Bones[boneId].InfVertices.push_back(vInf);
00401 }
00402 else
00403
00404 break;
00405 }
00406 }
00407 }
00408
00409
00410 bool CLodCharacterShape::addAnim(const CAnimBuild &animBuild)
00411 {
00412
00413 if(getAnimIdByName(animBuild.Name)!=-1)
00414 return false;
00415
00416
00417 CAnim dstAnim;
00418 dstAnim.Name= animBuild.Name;
00419 dstAnim.AnimLength= animBuild.AnimLength;
00420
00421 if(dstAnim.AnimLength<=0)
00422 dstAnim.AnimLength= 0.001f;
00423 dstAnim.OOAnimLength= 1.0f / animBuild.AnimLength;
00424 dstAnim.NumKeys= animBuild.NumKeys;
00425
00426 nlassert(dstAnim.NumKeys>0);
00427 nlassert(dstAnim.NumKeys * _NumVertices == animBuild.Keys.size());
00428
00429 dstAnim.Keys.resize(animBuild.Keys.size());
00430
00431
00432
00433 uint i;
00434
00435 CVector maxSize(0.01f, 0.01f, 0.01f);
00436 for(i=0;i<animBuild.Keys.size();i++)
00437 {
00438
00439 maxSize.maxof(maxSize, -animBuild.Keys[i]);
00440 maxSize.maxof(maxSize, animBuild.Keys[i]);
00441 }
00442
00443
00444 dstAnim.UnPackScaleFactor= maxSize * (1.0f/32767);
00445
00446
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
00452 for(i=0;i<animBuild.Keys.size();i++)
00453 {
00454 CVector v= animBuild.Keys[i];
00455 CVector3s &dstV= dstAnim.Keys[i];
00456
00457
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
00462 clamp(v.x, -32767, 32767);
00463 clamp(v.y, -32767, 32767);
00464 clamp(v.z, -32767, 32767);
00465
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
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
00507 f.serialCheck((uint32)'_LEN');
00508 f.serialCheck((uint32)'DOLC');
00509 f.serialCheck((uint32)'PAHS');
00510
00511
00512
00513
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
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
00579 const CAnim &anim= _Anims[animId];
00580
00581
00582 unPackScaleFactor= anim.UnPackScaleFactor;
00583
00584
00585 if(wrapMode)
00586 localTime= (float)fmod(time, anim.AnimLength);
00587 else
00588 localTime= (float)time;
00589
00590
00591 clamp(localTime, 0, anim.AnimLength);
00592
00593
00594 sint keyId= (sint)floor( (localTime*anim.OOAnimLength) * anim.NumKeys );
00595 clamp(keyId, 0, sint(anim.NumKeys-1));
00596
00597
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
00624
00625
00626
00627
00628
00629 void CLodCharacterShape::startBoneColor(std::vector<NLMISC::CRGBAF> &tmpColors) const
00630 {
00631
00632 tmpColors.resize(getNumVertices());
00633
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
00642 if(boneId>=_Bones.size())
00643 return;
00644 const CBoneInfluence &bone= _Bones[boneId];
00645
00646
00647 for(uint i=0; i<bone.InfVertices.size(); i++)
00648 {
00649 const CVertexInf &vInf= bone.InfVertices[i];
00650
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
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
00663 CRGBA defaultColor(128,128,128,0);
00664
00665
00666 nlassert(tmpColors.size() == getNumVertices());
00667 dstColors.resize(getNumVertices());
00668
00669
00670 for(uint i=0; i<dstColors.size(); i++)
00671 {
00672
00673 if(tmpColors[i].A==0)
00674 dstColors[i]= defaultColor;
00675 else
00676 {
00677
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
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 }