1093 lines
37 KiB
C++
1093 lines
37 KiB
C++
|
// Old Lightmap process
|
||
|
|
||
|
|
||
|
void SortFaceByTextureName(vector<CMesh::CFace*> &AllFaces, CMesh::CMeshBuild *pMB)
|
||
|
{
|
||
|
int i, j;
|
||
|
int nNbFace = AllFaces.size();
|
||
|
|
||
|
for( i = 0; i < nNbFace-1; ++i )
|
||
|
for( j = i+1; j < nNbFace; ++j )
|
||
|
{
|
||
|
ITexture *pT = pMB->Materials[AllFaces[i]->MaterialId].getTexture(0);
|
||
|
CTextureFile *pTF = dynamic_cast<CTextureFile *>(pT);
|
||
|
string namei = "Default";
|
||
|
if( pTF != NULL )
|
||
|
namei = pTF->getFileName();
|
||
|
pT = pMB->Materials[AllFaces[j]->MaterialId].getTexture(0);
|
||
|
pTF = dynamic_cast<CTextureFile *>(pT);
|
||
|
string namej = "Default";
|
||
|
if( pTF != NULL )
|
||
|
namej = pTF->getFileName();
|
||
|
if( namei < namej )
|
||
|
{
|
||
|
CMesh::CFace *pFaceTemp = AllFaces[i];
|
||
|
AllFaces[i] = AllFaces[j];
|
||
|
AllFaces[j] = pFaceTemp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TextureNames is an array which indicates the number of faces that follows which have the same texture name
|
||
|
void ComputeAreaOfTextureName(vector<sint32> &TextureNames, vector<CMesh::CFace*> &AllFaces, CMesh::CMeshBuild *pMB)
|
||
|
{
|
||
|
int i, nNbFace = AllFaces.size();
|
||
|
TextureNames.resize(nNbFace);
|
||
|
ITexture *pT = pMB->Materials[AllFaces[0]->MaterialId].getTexture(0);
|
||
|
CTextureFile *pTF = dynamic_cast<CTextureFile *>(pT);
|
||
|
string CurrentName = "Default";
|
||
|
sint32 lastface = 0, nNbTexName = 0;
|
||
|
if( pTF != NULL )
|
||
|
CurrentName = pTF->getFileName();
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
{
|
||
|
ITexture *pT = pMB->Materials[AllFaces[i]->MaterialId].getTexture(0);
|
||
|
CTextureFile *pTF = dynamic_cast<CTextureFile *>(pT);
|
||
|
string namei = "Default";
|
||
|
if( pTF != NULL )
|
||
|
namei = pTF->getFileName();
|
||
|
if( ( namei != CurrentName ) || ( i == (nNbFace-1) ) )
|
||
|
{
|
||
|
CurrentName = namei;
|
||
|
TextureNames[nNbTexName] = i-lastface;
|
||
|
nNbTexName++;
|
||
|
lastface = i;
|
||
|
}
|
||
|
}
|
||
|
TextureNames[nNbTexName-1] += 1;
|
||
|
TextureNames.resize( nNbTexName );
|
||
|
}
|
||
|
|
||
|
void SortFaceByMaterialId( int offset, int nNbFace, vector<CMesh::CFace*> &AllFaces )
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
for( i = 0; i < nNbFace-1; ++i )
|
||
|
for( j = i+1; j < nNbFace; ++j )
|
||
|
if( AllFaces[offset+i]->MaterialId < AllFaces[offset+j]->MaterialId )
|
||
|
{
|
||
|
CMesh::CFace *pFaceTemp = AllFaces[offset+i];
|
||
|
AllFaces[offset+i] = AllFaces[offset+j];
|
||
|
AllFaces[offset+j] = pFaceTemp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SortFaceByTextureSurface( int offset, int nNbFace, vector<CMesh::CFace*> &AllFaces )
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
for( i = 0; i < nNbFace-1; ++i )
|
||
|
for( j = i+1; j < nNbFace; ++j )
|
||
|
if( AllFaces[i]->MaterialId == AllFaces[j]->MaterialId )
|
||
|
{
|
||
|
// Texture surface of the i face = .5*|(u1-u0)*(v2-v0)-(v1-v0)*(u2-u0)|
|
||
|
// in fact this is lightmap mapping surface
|
||
|
double surfacei = 0.5*fabs(
|
||
|
(AllFaces[i]->Corner[1].Uvws[1].U - AllFaces[i]->Corner[0].Uvws[1].U)*
|
||
|
(AllFaces[i]->Corner[2].Uvws[1].V - AllFaces[i]->Corner[0].Uvws[1].V)-
|
||
|
(AllFaces[i]->Corner[1].Uvws[1].V - AllFaces[i]->Corner[0].Uvws[1].V)*
|
||
|
(AllFaces[i]->Corner[2].Uvws[1].U - AllFaces[i]->Corner[0].Uvws[1].U) );
|
||
|
double surfacej = 0.5*fabs(
|
||
|
(AllFaces[j]->Corner[1].Uvws[1].U - AllFaces[j]->Corner[0].Uvws[1].U)*
|
||
|
(AllFaces[j]->Corner[2].Uvws[1].V - AllFaces[j]->Corner[0].Uvws[1].V)-
|
||
|
(AllFaces[j]->Corner[1].Uvws[1].V - AllFaces[j]->Corner[0].Uvws[1].V)*
|
||
|
(AllFaces[j]->Corner[2].Uvws[1].U - AllFaces[j]->Corner[0].Uvws[1].U) );
|
||
|
if( surfacei < surfacej )
|
||
|
{
|
||
|
CMesh::CFace *pFaceTemp = AllFaces[i];
|
||
|
AllFaces[i] = AllFaces[j];
|
||
|
AllFaces[j] = pFaceTemp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool isInTriangle(double x, double y, double xt1, double yt1, double xt2, double yt2, double xt3, double yt3)
|
||
|
{
|
||
|
// Test vecteur T1X avec T1T2
|
||
|
double sign1 = ((xt2-xt1)*(y-yt1) - (yt2-yt1)*(x-xt1));
|
||
|
// Test vecteur T2X avec T2T3
|
||
|
double sign2 = ((xt3-xt2)*(y-yt2) - (yt3-yt2)*(x-xt2));
|
||
|
// Test vecteur T3X avec T3T1
|
||
|
double sign3 = ((xt1-xt3)*(y-yt3) - (yt1-yt3)*(x-xt3));
|
||
|
if( (sign1 <= 0.0)&&(sign2 <= 0.0)&&(sign3 <= 0.0) )
|
||
|
return true;
|
||
|
if( (sign1 >= 0.0)&&(sign2 >= 0.0)&&(sign3 >= 0.0) )
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Segment line intersection P1P2 and P3P4
|
||
|
bool segmentIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
|
||
|
{
|
||
|
double denominator = (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1);
|
||
|
double k = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3) ) / denominator;
|
||
|
if( (k<0.0) || (k>1.0) ) return false;
|
||
|
k = ( (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3) ) / denominator;
|
||
|
if( (k<0.0) || (k>1.0) ) return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void CreatePiece( vector<uint8>& Piece, sint32& nSizeX, sint32& nSizeY, sint32 &nPosX, sint32 &nPosY,
|
||
|
float lumx1, float lumy1,
|
||
|
float lumx2, float lumy2,
|
||
|
float lumx3, float lumy3, uint8 nCol )
|
||
|
{
|
||
|
double minx, miny;
|
||
|
double maxx, maxy;
|
||
|
int j,k;
|
||
|
|
||
|
if( nCol == 0 )
|
||
|
nCol = 1;
|
||
|
minx = lumx1;
|
||
|
if( minx > lumx2 ) minx = lumx2;
|
||
|
if( minx > lumx3 ) minx = lumx3;
|
||
|
maxx = lumx1;
|
||
|
if( maxx < lumx2 ) maxx = lumx2;
|
||
|
if( maxx < lumx3 ) maxx = lumx3;
|
||
|
miny = lumy1;
|
||
|
if( miny > lumy2 ) miny = lumy2;
|
||
|
if( miny > lumy3 ) miny = lumy3;
|
||
|
maxy = lumy1;
|
||
|
if( maxy < lumy2 ) maxy = lumy2;
|
||
|
if( maxy < lumy3 ) maxy = lumy3;
|
||
|
|
||
|
// Put the piece in the new basis (nPosX,nPosY)
|
||
|
nPosX = ((sint32)floor(minx-0.5));
|
||
|
nPosY = ((sint32)floor(miny-0.5));
|
||
|
|
||
|
lumx1 -= nPosX; lumy1 -= nPosY;
|
||
|
lumx2 -= nPosX; lumy2 -= nPosY;
|
||
|
lumx3 -= nPosX; lumy3 -= nPosY;
|
||
|
|
||
|
nSizeX = 1 + ((sint32)floor(maxx+0.5)) - ((sint32)floor(minx-0.5));
|
||
|
nSizeY = 1 + ((sint32)floor(maxy+0.5)) - ((sint32)floor(miny-0.5));
|
||
|
Piece.resize( nSizeX*nSizeY );
|
||
|
for( j = 0; j < nSizeX*nSizeY; ++j )
|
||
|
Piece[j] = 0;
|
||
|
|
||
|
// The square interact with the triangle if an edge of the square is cut by an edge of the triangle
|
||
|
// Or the square is in the triangle
|
||
|
|
||
|
for( j = 0; j < nSizeY-1; ++j )
|
||
|
for( k = 0; k < nSizeX-1; ++k )
|
||
|
{
|
||
|
// Is the square (j,k) is interacting with the triangle
|
||
|
// This means : The square contains a point of the triangle (can be done for the 3 points)
|
||
|
// The triangle contains a point of the square
|
||
|
// If so then we have to turn on all the 4 pixels of the square
|
||
|
if( isInTriangle(k+0.5,j+0.5,lumx1,lumy1,lumx2,lumy2,lumx3,lumy3) ||
|
||
|
isInTriangle(k+1.5,j+0.5,lumx1,lumy1,lumx2,lumy2,lumx3,lumy3) ||
|
||
|
isInTriangle(k+0.5,j+1.5,lumx1,lumy1,lumx2,lumy2,lumx3,lumy3) ||
|
||
|
isInTriangle(k+1.5,j+1.5,lumx1,lumy1,lumx2,lumy2,lumx3,lumy3) )
|
||
|
{
|
||
|
Piece[k + j * nSizeX] = nCol;
|
||
|
Piece[1+k + j * nSizeX] = nCol;
|
||
|
Piece[k + (1+j)* nSizeX] = nCol;
|
||
|
Piece[1+k + (1+j)* nSizeX] = nCol;
|
||
|
}
|
||
|
|
||
|
if( segmentIntersection(k+0.5, j+0.5, k+1.5, j+0.5, lumx1, lumy1, lumx2, lumy2) ||
|
||
|
segmentIntersection(k+0.5, j+0.5, k+1.5, j+0.5, lumx2, lumy2, lumx3, lumy3) ||
|
||
|
segmentIntersection(k+0.5, j+0.5, k+1.5, j+0.5, lumx3, lumy3, lumx1, lumy1) ||
|
||
|
|
||
|
segmentIntersection(k+0.5, j+0.5, k+0.5, j+1.5, lumx1, lumy1, lumx2, lumy2) ||
|
||
|
segmentIntersection(k+0.5, j+0.5, k+0.5, j+1.5, lumx2, lumy2, lumx3, lumy3) ||
|
||
|
segmentIntersection(k+0.5, j+0.5, k+0.5, j+1.5, lumx3, lumy3, lumx1, lumy1) ||
|
||
|
|
||
|
segmentIntersection(k+1.5, j+1.5, k+1.5, j+0.5, lumx1, lumy1, lumx2, lumy2) ||
|
||
|
segmentIntersection(k+1.5, j+1.5, k+1.5, j+0.5, lumx2, lumy2, lumx3, lumy3) ||
|
||
|
segmentIntersection(k+1.5, j+1.5, k+1.5, j+0.5, lumx3, lumy3, lumx1, lumy1) ||
|
||
|
|
||
|
segmentIntersection(k+1.5, j+1.5, k+0.5, j+1.5, lumx1, lumy1, lumx2, lumy2) ||
|
||
|
segmentIntersection(k+1.5, j+1.5, k+0.5, j+1.5, lumx2, lumy2, lumx3, lumy3) ||
|
||
|
segmentIntersection(k+1.5, j+1.5, k+0.5, j+1.5, lumx3, lumy3, lumx1, lumy1) )
|
||
|
{
|
||
|
Piece[k + j * nSizeX] = nCol;
|
||
|
Piece[1+k + j * nSizeX] = nCol;
|
||
|
Piece[k + (1+j)* nSizeX] = nCol;
|
||
|
Piece[1+k + (1+j)* nSizeX] = nCol;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
// For all the points of the triangle update the square
|
||
|
Piece[((sint32)(lumx1-0.5)) + ((sint32)(lumy1-0.5))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx1-0.5)) + ((sint32)(lumy1-0.5))*nSizeX] = nCol;
|
||
|
Piece[((sint32)(lumx1-0.5)) + (1+((sint32)(lumy1-0.5)))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx1-0.5)) + (1+((sint32)(lumy1-0.5)))*nSizeX] = nCol;
|
||
|
|
||
|
Piece[((sint32)(lumx2-0.5)) + ((sint32)(lumy2-0.5))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx2-0.5)) + ((sint32)(lumy2-0.5))*nSizeX] = nCol;
|
||
|
Piece[((sint32)(lumx2-0.5)) + (1+((sint32)(lumy2-0.5)))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx2-0.5)) + (1+((sint32)(lumy2-0.5)))*nSizeX] = nCol;
|
||
|
|
||
|
Piece[((sint32)(lumx3-0.5)) + ((sint32)(lumy3-0.5))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx3-0.5)) + ((sint32)(lumy3-0.5))*nSizeX] = nCol;
|
||
|
Piece[((sint32)(lumx3-0.5)) + (1+((sint32)(lumy3-0.5)))*nSizeX] = nCol;
|
||
|
Piece[1+((sint32)(lumx3-0.5)) + (1+((sint32)(lumy3-0.5)))*nSizeX] = nCol;
|
||
|
}
|
||
|
|
||
|
void ResizeBitmap( vector<uint8> &vBitmap, sint32 &nSizeX, sint32 &nSizeY, sint32 nNewSizeX, sint32 nNewSizeY )
|
||
|
{
|
||
|
vector<uint8> vImgTemp;
|
||
|
int i, j;
|
||
|
|
||
|
vImgTemp.resize(nNewSizeX*nNewSizeY);
|
||
|
for( i = 0; i < nNewSizeX*nNewSizeY; ++i )
|
||
|
vImgTemp[i] = 0;
|
||
|
|
||
|
for( j = 0; j < min(nSizeY,nNewSizeY); ++j )
|
||
|
for( i = 0; i < min(nSizeX,nNewSizeX); ++i )
|
||
|
{
|
||
|
vImgTemp[i+j*nNewSizeX] = vBitmap[i+j*nSizeX];
|
||
|
}
|
||
|
|
||
|
vBitmap.resize(nNewSizeX*nNewSizeY);
|
||
|
for( i = 0; i < nNewSizeX*nNewSizeY; ++i )
|
||
|
vBitmap[i] = vImgTemp[i];
|
||
|
|
||
|
nSizeX = nNewSizeX;
|
||
|
nSizeY = nNewSizeY;
|
||
|
}
|
||
|
|
||
|
bool PutPieceInLightMap( vector<uint8>& Piece, sint32 nPieceSizeX, sint32 nPieceSizeY,
|
||
|
vector<uint8>& LightMap, sint32 nLightMapSizeX, sint32 nLightMapSizeY,
|
||
|
sint32 &nNewPosX, sint32 &nNewPosY )
|
||
|
{
|
||
|
sint32 i, j, a, b;
|
||
|
bool bGoodPosition;
|
||
|
|
||
|
if( nPieceSizeX > nLightMapSizeX ) return false;
|
||
|
if( nPieceSizeY > nLightMapSizeY ) return false;
|
||
|
|
||
|
// For all position test if the piece can get in
|
||
|
for( j = 0; j < (nLightMapSizeY-nPieceSizeY); ++j )
|
||
|
for( i = 0; i < (nLightMapSizeX-nPieceSizeX); ++i )
|
||
|
{
|
||
|
bGoodPosition = true;
|
||
|
for( b = 0; b < nPieceSizeY; ++b )
|
||
|
{
|
||
|
for( a = 0; a < nPieceSizeX; ++a )
|
||
|
{
|
||
|
if( Piece[a+b*nPieceSizeX] != 0 )
|
||
|
if( LightMap[(i+a)+(j+b)*nLightMapSizeX] != 0 )
|
||
|
{
|
||
|
bGoodPosition = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if( bGoodPosition == false )
|
||
|
break;
|
||
|
}
|
||
|
if( bGoodPosition )
|
||
|
{
|
||
|
// Write the piece in the lightmap !!!
|
||
|
for( b = 0; b < nPieceSizeY; ++b )
|
||
|
{
|
||
|
for( a = 0; a < nPieceSizeX; ++a )
|
||
|
{
|
||
|
if( Piece[a+b*nPieceSizeX] != 0 )
|
||
|
LightMap[(i+a)+(j+b)*nLightMapSizeX] = Piece[a+b*nPieceSizeX];
|
||
|
}
|
||
|
}
|
||
|
nNewPosX = i;
|
||
|
nNewPosY = j;
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void MapFace( CMesh::CFace *pFace, vector<CVector> &Vertices, double rRatio )
|
||
|
{
|
||
|
CVector V01 = Vertices[pFace->Corner[1].Vertex] - Vertices[pFace->Corner[0].Vertex];
|
||
|
CVector V02 = Vertices[pFace->Corner[2].Vertex] - Vertices[pFace->Corner[0].Vertex];
|
||
|
CVector n = V01 ^ V02;
|
||
|
n.normalize();
|
||
|
|
||
|
// Quantize the normal
|
||
|
|
||
|
// Table of unitary vector with relevant direction to map The I vector represent the plane normal
|
||
|
// and the J,K vector the U,V vector
|
||
|
CMatrix QuantizationTbl[3];
|
||
|
QuantizationTbl[0].identity();
|
||
|
QuantizationTbl[1].identity(); QuantizationTbl[1].rotateZ(Pi/2);
|
||
|
QuantizationTbl[2].identity(); QuantizationTbl[2].rotateY(Pi/2);
|
||
|
|
||
|
float fMax = 0.0f;
|
||
|
int pos = 0;
|
||
|
for( int i = 0; i < 3; ++i )
|
||
|
{
|
||
|
if( fMax < fabs(QuantizationTbl[i].getI()*n) )
|
||
|
{
|
||
|
fMax = fabs(QuantizationTbl[i].getI()*n);
|
||
|
pos = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Map with the i_th vector from the quantization table
|
||
|
// Projection of the 3 vertices of the triangle on the plane
|
||
|
// defined by the quantized vector (as the plane normal) and the origin (as a point in the plane)
|
||
|
|
||
|
// This is equivalent to a base changement with annulation of the I vector
|
||
|
CMatrix invMat = QuantizationTbl[pos].inverted();
|
||
|
CVector newPtinUVBasis = invMat.mulPoint(Vertices[pFace->Corner[0].Vertex]);
|
||
|
pFace->Corner[0].Uvws[1].U = newPtinUVBasis.y / rRatio;
|
||
|
pFace->Corner[0].Uvws[1].V = newPtinUVBasis.z / rRatio;
|
||
|
newPtinUVBasis = invMat.mulPoint(Vertices[pFace->Corner[1].Vertex]);
|
||
|
pFace->Corner[1].Uvws[1].U = newPtinUVBasis.y / rRatio;
|
||
|
pFace->Corner[1].Uvws[1].V = newPtinUVBasis.z / rRatio;
|
||
|
newPtinUVBasis = invMat.mulPoint(Vertices[pFace->Corner[2].Vertex]);
|
||
|
pFace->Corner[2].Uvws[1].U = newPtinUVBasis.y / rRatio;
|
||
|
pFace->Corner[2].Uvws[1].V = newPtinUVBasis.z / rRatio;
|
||
|
}
|
||
|
|
||
|
CMatrix getObjectToWorldMatrix( CMesh::CMeshBuild *pMB )
|
||
|
{
|
||
|
CMatrix m1, m2, m3, m4, m5;
|
||
|
m1.identity();
|
||
|
m1.setPos( pMB->DefaultPivot );
|
||
|
m1.invert();
|
||
|
|
||
|
m2.identity();
|
||
|
m2.scale( pMB->DefaultScale );
|
||
|
|
||
|
m3.identity();
|
||
|
m3.setRot( pMB->DefaultRotQuat );
|
||
|
|
||
|
m4.identity();
|
||
|
m4.setPos( pMB->DefaultPivot );
|
||
|
|
||
|
m5.identity();
|
||
|
m5.setPos( pMB->DefaultPos );
|
||
|
|
||
|
m1 = m5*m4*m3*m2*m1;
|
||
|
|
||
|
return m1;
|
||
|
}
|
||
|
|
||
|
float getUVDist( CUV& UV1, CUV& UV2 )
|
||
|
{
|
||
|
return sqrt( (UV2.U - UV1.U)*(UV2.U - UV1.U) + (UV2.V - UV1.V)*(UV2.V - UV1.V) );
|
||
|
}
|
||
|
|
||
|
struct SLightBuild
|
||
|
{
|
||
|
enum EType { LightAmbient, LightPoint, LightDir, LightSpot };
|
||
|
EType Type;
|
||
|
CVector Position; // Applicable to LightPoint and LightSpot
|
||
|
CVector Direction; // Applicable to LightSpot and LightDir
|
||
|
float rRadiusMin, rRadiusMax; // Applicable to LightPoint and LightSpot
|
||
|
CRGBA Ambient;
|
||
|
CRGBA Diffuse;
|
||
|
CRGBA Specular;
|
||
|
SLightBuild()
|
||
|
{
|
||
|
Type = LightPoint;
|
||
|
Position = CVector(0.0, 0.0, 0.0);
|
||
|
Direction = CVector(1.0, 0.0, 0.0);
|
||
|
rRadiusMin = 1.0f;
|
||
|
rRadiusMax = 2.0f;
|
||
|
Ambient = CRGBA(0, 0, 0, 0);
|
||
|
Diffuse = CRGBA(0, 0, 0, 0);
|
||
|
Specular = CRGBA(0, 0, 0, 0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void getLightBuildList(std::vector<SLightBuild>& vectLight, TimeValue tvTime, Interface& ip, INode*node=NULL )
|
||
|
{
|
||
|
if( node == NULL )
|
||
|
node = ip.GetRootNode();
|
||
|
|
||
|
// Get a pointer on the object's node
|
||
|
Object *obj = node->EvalWorldState(tvTime).obj;
|
||
|
|
||
|
// Check if there is an object
|
||
|
if (obj)
|
||
|
{
|
||
|
// Get a GenLight from the node
|
||
|
if (obj->SuperClassID()==LIGHT_CLASS_ID)
|
||
|
{
|
||
|
GenLight *maxLight = (GenLight *) obj;
|
||
|
|
||
|
bool deleteIt=false;
|
||
|
if (obj != maxLight)
|
||
|
deleteIt = true;
|
||
|
|
||
|
SLightBuild nelLight;
|
||
|
|
||
|
// Eval the light state fot this tvTime
|
||
|
Interval valid=NEVER;
|
||
|
LightState ls;
|
||
|
|
||
|
if (maxLight->EvalLightState(tvTime, valid, &ls)==REF_SUCCEED)
|
||
|
{
|
||
|
// Set the light mode
|
||
|
switch (maxLight->Type())
|
||
|
{
|
||
|
case OMNI_LIGHT:
|
||
|
nelLight.Type = SLightBuild::EType::LightPoint;
|
||
|
break;
|
||
|
case TSPOT_LIGHT:
|
||
|
case FSPOT_LIGHT:
|
||
|
nelLight.Type = SLightBuild::EType::LightSpot;
|
||
|
break;
|
||
|
case DIR_LIGHT:
|
||
|
case TDIR_LIGHT:
|
||
|
nelLight.Type = SLightBuild::EType::LightDir;
|
||
|
break;
|
||
|
default:
|
||
|
// Not initialized
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// *** Set the light color
|
||
|
|
||
|
// Get the color
|
||
|
CRGBA nelColor;
|
||
|
Point3 maxColor = maxLight->GetRGBColor(tvTime);
|
||
|
|
||
|
// Mul by multiply
|
||
|
CRGBAF nelFColor;
|
||
|
nelFColor.R = maxColor.x;
|
||
|
nelFColor.G = maxColor.y;
|
||
|
nelFColor.B = maxColor.z;
|
||
|
nelFColor.A = 1.f;
|
||
|
nelFColor *= maxLight->GetIntensity(tvTime);
|
||
|
nelColor = nelFColor;
|
||
|
|
||
|
// Affect the ambiant color ?
|
||
|
nelLight.Ambient = nelColor;
|
||
|
nelLight.Diffuse = CRGBA (0,0,0);
|
||
|
nelLight.Specular = CRGBA (0,0,0);
|
||
|
if (maxLight->GetAmbientOnly())
|
||
|
{
|
||
|
nelLight.Ambient = nelColor;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Affect the diffuse color ?
|
||
|
if( maxLight->GetAffectDiffuse() )
|
||
|
nelLight.Diffuse = nelColor;
|
||
|
// Affect the specular color ?
|
||
|
if (maxLight->GetAffectSpecular())
|
||
|
nelLight.Specular = nelColor;
|
||
|
}
|
||
|
|
||
|
// Set the light position
|
||
|
Point3 pos = node->GetNodeTM(tvTime).GetTrans ();
|
||
|
CVector position;
|
||
|
position.x=pos.x;
|
||
|
position.y=pos.y;
|
||
|
position.z=pos.z;
|
||
|
|
||
|
// Set the position
|
||
|
nelLight.Position = position;
|
||
|
|
||
|
// Set the light direction
|
||
|
CVector direction;
|
||
|
INode* target = node->GetTarget ();
|
||
|
if (target)
|
||
|
{
|
||
|
// Get the position of the target
|
||
|
Point3 posTarget=target->GetNodeTM (tvTime).GetTrans ();
|
||
|
CVector positionTarget;
|
||
|
positionTarget.x=posTarget.x;
|
||
|
positionTarget.y=posTarget.y;
|
||
|
positionTarget.z=posTarget.z;
|
||
|
|
||
|
// Direction
|
||
|
direction=positionTarget-position;
|
||
|
direction.normalize ();
|
||
|
}
|
||
|
else // No target
|
||
|
{
|
||
|
// Get orientation of the source as direction
|
||
|
CMatrix nelMatrix;
|
||
|
CExportNel::convertMatrix (nelMatrix, node->GetNodeTM(tvTime));
|
||
|
|
||
|
// Direction is -Z
|
||
|
direction=-nelMatrix.getK();
|
||
|
direction.normalize ();
|
||
|
}
|
||
|
|
||
|
// Set the direction
|
||
|
nelLight.Direction = direction;
|
||
|
/*
|
||
|
// Set spot light information
|
||
|
nelLight.setCutoff ((float)(NLMISC::Pi*maxLight.GetFallsize(tvTime)/180.f/2.f));
|
||
|
|
||
|
// Compute the exponent value
|
||
|
float angle=(float)(NLMISC::Pi*maxLight.GetHotspot(tvTime)/(2.0*180.0));
|
||
|
nelLight.setupSpotExponent (angle);
|
||
|
|
||
|
// *** Set attenuation
|
||
|
|
||
|
if (maxLight.GetUseAtten())
|
||
|
nelLight.setupAttenuation (maxLight.GetAtten (tvTime, ATTEN_START), maxLight.GetAtten (tvTime, ATTEN_END));
|
||
|
else
|
||
|
nelLight.setNoAttenuation ();
|
||
|
*/
|
||
|
if (maxLight->GetUseAtten())
|
||
|
{
|
||
|
nelLight.rRadiusMin = maxLight->GetAtten (tvTime, ATTEN_START);
|
||
|
nelLight.rRadiusMax = maxLight->GetAtten (tvTime, ATTEN_END);
|
||
|
}
|
||
|
// Add the light in the list
|
||
|
vectLight.push_back (nelLight);
|
||
|
}
|
||
|
if( deleteIt )
|
||
|
delete maxLight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Recurse sub node
|
||
|
for (int i=0; i<node->NumberOfChildren(); i++)
|
||
|
getLightBuildList(vectLight, tvTime, ip, node->GetChildNode(i));
|
||
|
}
|
||
|
|
||
|
void getLightBuilds( vector<SLightBuild> &lights, TimeValue tvTime, Interface& ip )
|
||
|
{
|
||
|
SLightBuild amb;
|
||
|
|
||
|
amb.Type = SLightBuild::EType::LightAmbient;
|
||
|
amb.Ambient.R = (uint8)(ip.GetAmbient( tvTime, FOREVER ).x*255);
|
||
|
amb.Ambient.G = (uint8)(ip.GetAmbient( tvTime, FOREVER ).y*255);
|
||
|
amb.Ambient.B = (uint8)(ip.GetAmbient( tvTime, FOREVER ).z*255);
|
||
|
amb.Ambient.A = 255;
|
||
|
amb.Specular = amb.Diffuse = CRGBA(0,0,0,0);
|
||
|
lights.push_back( amb );
|
||
|
getLightBuildList( lights, tvTime, ip );
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// -----------------------------------------------------------------------------------------------
|
||
|
// -----------------------------------------------------------------------------------------------
|
||
|
bool CNelExport::exportScene(std::vector<INode*>& vectNode)
|
||
|
{
|
||
|
// All inputs are transfered throught the global theExportSceneStruct structure
|
||
|
|
||
|
// Export the Instance Group (aka scene description)
|
||
|
// *************************
|
||
|
if( theExportSceneStruct.bExportInstanceGroup )
|
||
|
exportInstanceGroup( theExportSceneStruct.sExportInstanceGroup, vectNode );
|
||
|
|
||
|
// Export all the shapes
|
||
|
// *********************
|
||
|
// If lighting enabled we export the shape after lightmapping modification
|
||
|
if( theExportSceneStruct.bExportShapes && (!theExportSceneStruct.bExportLighting) )
|
||
|
{
|
||
|
// Get time
|
||
|
TimeValue tvTime = theCNelExport.ip->GetTime();
|
||
|
|
||
|
// Get node count
|
||
|
int nNumSelNode = vectNode.size();
|
||
|
|
||
|
// Save all selected objects
|
||
|
for (int nNode=0; nNode<nNumSelNode; nNode++)
|
||
|
{
|
||
|
// Get the node
|
||
|
INode* pNode=vectNode[nNode];
|
||
|
|
||
|
// It is a zone ?
|
||
|
if (RPO::isZone (*pNode, tvTime))
|
||
|
{
|
||
|
// Nothing to do if this is a zone
|
||
|
}
|
||
|
// Try to export a mesh
|
||
|
else if (CExportNel::isMesh (*pNode, tvTime))
|
||
|
{
|
||
|
// Build the name of the file to export
|
||
|
char sSavePath[512];
|
||
|
strcpy( sSavePath, theExportSceneStruct.sExportShapes.c_str() );
|
||
|
if(theExportSceneStruct.sExportShapes[theExportSceneStruct.sExportShapes.size()-1] != '\\' )
|
||
|
strcat( sSavePath, "\\" );
|
||
|
strcat( sSavePath, pNode->GetName() );
|
||
|
strcat( sSavePath, ".shape" );
|
||
|
|
||
|
// Export the mesh
|
||
|
if (!theCNelExport.exportMesh (sSavePath, *pNode, *theCNelExport.ip, tvTime))
|
||
|
{
|
||
|
// Error message
|
||
|
char sErrorMsg[512];
|
||
|
sprintf (sErrorMsg, "Error exporting the mesh %s in the file\n%s", pNode->GetName(), sSavePath);
|
||
|
MessageBox (theCNelExport.ip->GetMAXHWnd(), sErrorMsg, "NeL export scene", MB_OK|MB_ICONEXCLAMATION );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Export the lighting (aka compute all light maps)
|
||
|
// *******************
|
||
|
#define RATIOLIGHTMAP 0.05 // 0.5 meters in real world represent 1 Lumel in UV world
|
||
|
#define MAXLIGHTMAPSIZE 1024
|
||
|
if( theExportSceneStruct.bExportLighting )
|
||
|
{
|
||
|
// 1 -> Build all MeshBuild structure
|
||
|
// ----------------------------------
|
||
|
vector< pair < CMesh::CMeshBuild*,INode* > > AllMeshBuilds;
|
||
|
TimeValue tvTime = theCNelExport.ip->GetTime();
|
||
|
int nNumSelNode = vectNode.size();
|
||
|
int nNbMesh = 0;
|
||
|
int nNode, i, j, k;
|
||
|
// Count number of mesh in the selection
|
||
|
for( nNode = 0; nNode < nNumSelNode; ++nNode )
|
||
|
{
|
||
|
INode* pNode = vectNode[nNode];
|
||
|
if( ! RPO::isZone( *pNode, tvTime ) )
|
||
|
if( CExportNel::isMesh( *pNode, tvTime ) )
|
||
|
nNbMesh++;
|
||
|
}
|
||
|
AllMeshBuilds.resize(nNbMesh);
|
||
|
nNbMesh = 0;
|
||
|
// Create all the MeshBuild used to place lightmaps and to raytrace lightmaps
|
||
|
for( nNode=0; nNode < nNumSelNode; ++nNode )
|
||
|
{
|
||
|
INode* pNode = vectNode[nNode];
|
||
|
if( ! RPO::isZone( *pNode, tvTime ) )
|
||
|
if( CExportNel::isMesh( *pNode, tvTime ) )
|
||
|
{
|
||
|
AllMeshBuilds[nNbMesh].second = pNode;
|
||
|
AllMeshBuilds[nNbMesh].first = CExportNel::createMeshBuild( *pNode, tvTime );
|
||
|
nNbMesh++;
|
||
|
}
|
||
|
}
|
||
|
// 2 -> Place lightmap for all MeshBuild (this operation does not need interaction between MeshBuilds)
|
||
|
for( nNode=0; nNode < nNbMesh; ++nNode )
|
||
|
{
|
||
|
// First order face by Material and by texture surface
|
||
|
CMesh::CMeshBuild *pMB = AllMeshBuilds[nNode].first;
|
||
|
CMatrix MBMatrix = getObjectToWorldMatrix( pMB );
|
||
|
vector<CMesh::CFace*> AllFaces;
|
||
|
vector<CVector> AllVertices; // All vertices in world space
|
||
|
vector<sint32> AreaTextureNames; // Number of faces with the same texture name
|
||
|
sint32 nNbFace = pMB->Faces.size(), nNbVertex = pMB->Vertices.size();
|
||
|
sint32 offset, nNewPosX, nNewPosY;
|
||
|
// Make a vector of pointer to all the faces of the MeshBuild
|
||
|
AllFaces.resize(nNbFace);
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
AllFaces[i] = &pMB->Faces[i];
|
||
|
AllVertices.resize(nNbVertex);
|
||
|
for( i = 0; i < nNbVertex; ++i )
|
||
|
AllVertices[i] = MBMatrix * pMB->Vertices[i];
|
||
|
// Bubble sort pointer to the faces (Material sorting by texture name)
|
||
|
SortFaceByTextureName( AllFaces, pMB );
|
||
|
// Get the number of faces in Allfaces for each different texture name
|
||
|
ComputeAreaOfTextureName( AreaTextureNames, AllFaces, pMB );
|
||
|
|
||
|
// For all faces that has the same texture name
|
||
|
offset = 0;
|
||
|
for( int nTexName = 0; nTexName < AreaTextureNames.size(); ++nTexName )
|
||
|
{
|
||
|
nNbFace = AreaTextureNames[nTexName];
|
||
|
// Bubble sort pointer to the faces (Material sorting)
|
||
|
SortFaceByMaterialId( offset, nNbFace, AllFaces );
|
||
|
// Sort by texture surface if the faces have the same material
|
||
|
SortFaceByTextureSurface( offset, nNbFace, AllFaces );
|
||
|
offset += nNbFace;
|
||
|
}
|
||
|
|
||
|
// Here is the placement
|
||
|
// TEST 1 : One all big lightmap for this object
|
||
|
//sint32 CurrentMaterialId = AllFaces[0]->MaterialId;
|
||
|
//sint32 BeginningFace = 0;
|
||
|
vector<uint8> TheLightMap;
|
||
|
sint32 nLightMapSizeX = 1, nLightMapSizeY = 1;
|
||
|
TheLightMap.resize(1);
|
||
|
nNbFace = pMB->Faces.size();
|
||
|
// Calculation of the texture ratio
|
||
|
double SpaceDist = 0.0, TextureDist = 0.0;
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
{
|
||
|
CVector v = AllVertices[AllFaces[i]->Corner[1].Vertex] - AllVertices[AllFaces[i]->Corner[0].Vertex];
|
||
|
SpaceDist += v.norm();
|
||
|
v = AllVertices[AllFaces[i]->Corner[2].Vertex] - AllVertices[AllFaces[i]->Corner[1].Vertex];
|
||
|
SpaceDist += v.norm();
|
||
|
v = AllVertices[AllFaces[i]->Corner[0].Vertex] - AllVertices[AllFaces[i]->Corner[2].Vertex];
|
||
|
SpaceDist += v.norm();
|
||
|
TextureDist += getUVDist( AllFaces[i]->Corner[1].Uvws[1], AllFaces[i]->Corner[0].Uvws[1] );
|
||
|
TextureDist += getUVDist( AllFaces[i]->Corner[2].Uvws[1], AllFaces[i]->Corner[1].Uvws[1] );
|
||
|
TextureDist += getUVDist( AllFaces[i]->Corner[0].Uvws[1], AllFaces[i]->Corner[2].Uvws[1] );
|
||
|
}
|
||
|
double LMTextRatio = SpaceDist / TextureDist;
|
||
|
LMTextRatio = LMTextRatio / RATIOLIGHTMAP;
|
||
|
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
{
|
||
|
// Piece creation
|
||
|
vector<uint8> Piece;
|
||
|
sint32 nPieceSizeX, nPieceSizeY;
|
||
|
// Try to map this face with quantized vector and express uv in lumel
|
||
|
// MapFace( AllFaces[i], AllVertices, RATIOLIGHTMAP );
|
||
|
for( j = 0; j < 3; ++j ) // Express the UVs in lumel with a ratio
|
||
|
{ // For each corner
|
||
|
AllFaces[i]->Corner[j].Uvws[1].U *= LMTextRatio;
|
||
|
AllFaces[i]->Corner[j].Uvws[1].V *= LMTextRatio;
|
||
|
}
|
||
|
// Create the related piece
|
||
|
CreatePiece( Piece, nPieceSizeX, nPieceSizeY, nNewPosX, nNewPosY,
|
||
|
AllFaces[i]->Corner[0].Uvws[1].U, // lumx1
|
||
|
AllFaces[i]->Corner[0].Uvws[1].V, // lumy1
|
||
|
AllFaces[i]->Corner[1].Uvws[1].U, // lumx2
|
||
|
AllFaces[i]->Corner[1].Uvws[1].V, // lumy2
|
||
|
AllFaces[i]->Corner[2].Uvws[1].U, // lumx3
|
||
|
AllFaces[i]->Corner[2].Uvws[1].V, // lumy3
|
||
|
(i%254)+1 ); // color
|
||
|
// Set the UV of the face in same basis as the piece (0->nPieceSize)
|
||
|
for( j = 0; j < 3; ++j )
|
||
|
{ // For each corner
|
||
|
AllFaces[i]->Corner[j].Uvws[1].U -= nNewPosX;
|
||
|
AllFaces[i]->Corner[j].Uvws[1].V -= nNewPosY;
|
||
|
}
|
||
|
|
||
|
while( true )
|
||
|
{
|
||
|
if( !PutPieceInLightMap( Piece, nPieceSizeX, nPieceSizeY,
|
||
|
TheLightMap, nLightMapSizeX, nLightMapSizeY,
|
||
|
nNewPosX, nNewPosY ) )
|
||
|
{
|
||
|
if( ( nLightMapSizeX < MAXLIGHTMAPSIZE ) || ( nLightMapSizeY < MAXLIGHTMAPSIZE ) )
|
||
|
{
|
||
|
if( nLightMapSizeX < nLightMapSizeY )
|
||
|
ResizeBitmap( TheLightMap, nLightMapSizeX, nLightMapSizeY, nLightMapSizeX*2, nLightMapSizeY );
|
||
|
else
|
||
|
ResizeBitmap( TheLightMap, nLightMapSizeX, nLightMapSizeY, nLightMapSizeX, nLightMapSizeY*2 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ERROR: we reached the maximum texture size
|
||
|
nlstop;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We found a position for this piece, update texture coord in lumel format
|
||
|
for( j = 0; j < 3; ++j )
|
||
|
{
|
||
|
AllFaces[i]->Corner[j].Uvws[1].U += nNewPosX;
|
||
|
AllFaces[i]->Corner[j].Uvws[1].V += nNewPosY;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// All faces have been put in the lightmap so update All texture coord with the size of the lightmap
|
||
|
// Convert all faces from lumels to lumels/sizeofLightMap to get uv from 0.0 to 1.0
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
for( j = 0; j < 3; ++j )
|
||
|
{
|
||
|
AllFaces[i]->Corner[j].Uvws[1].U /= nLightMapSizeX;
|
||
|
AllFaces[i]->Corner[j].Uvws[1].V /= nLightMapSizeY;
|
||
|
}
|
||
|
// Write the new lightmap and update the buildmesh materials
|
||
|
{
|
||
|
CTextureFile *pTexture = new CTextureFile;
|
||
|
string sTemp = AllMeshBuilds[nNode].second->GetName();
|
||
|
sTemp += ".tga";
|
||
|
pTexture->setFileName( sTemp );
|
||
|
sTemp = theExportSceneStruct.sExportLighting;
|
||
|
if(sTemp[sTemp.size()-1] != '\\' ) sTemp += "\\";
|
||
|
sTemp += AllMeshBuilds[nNode].second->GetName();
|
||
|
sTemp += ".tga";
|
||
|
pTexture->resize( nLightMapSizeX, nLightMapSizeY );
|
||
|
CObjectVector<uint8> &rText = pTexture->getPixels();
|
||
|
for( j = 0; j < nLightMapSizeY; ++j )
|
||
|
for( i = 0; i < nLightMapSizeX; ++i )
|
||
|
if( TheLightMap[i+j*nLightMapSizeX] != 0 )
|
||
|
{
|
||
|
rText[(i+j*nLightMapSizeX)*4+0] = 63+((TheLightMap[i+j*nLightMapSizeX]*15)%190);
|
||
|
rText[(i+j*nLightMapSizeX)*4+1] = 63+((TheLightMap[i+j*nLightMapSizeX]*27+63)%190);
|
||
|
rText[(i+j*nLightMapSizeX)*4+2] = 63+((TheLightMap[i+j*nLightMapSizeX]*13+127)%190);
|
||
|
rText[(i+j*nLightMapSizeX)*4+3] = 255;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rText[(i+j*nLightMapSizeX)*4+0] = 0;
|
||
|
rText[(i+j*nLightMapSizeX)*4+1] = 0;
|
||
|
rText[(i+j*nLightMapSizeX)*4+2] = 0;
|
||
|
rText[(i+j*nLightMapSizeX)*4+3] = 0;
|
||
|
}
|
||
|
// Write texture to disk
|
||
|
//{
|
||
|
// COFile f;
|
||
|
// f.open( sTemp );
|
||
|
// pTexture->writeTGA( f, 32 );
|
||
|
//}
|
||
|
for( i = 0; i < AllMeshBuilds[nNode].first->Materials.size(); ++i )
|
||
|
{
|
||
|
AllMeshBuilds[nNode].first->Materials[i].setTexture( 1, pTexture );
|
||
|
//AllMeshBuilds[nNode].first->Materials[i].setLighting( false );
|
||
|
}
|
||
|
}
|
||
|
} // End for all nodes
|
||
|
// All nodes are mapped correctly with a lightmap and lightmap is created on disk
|
||
|
// --------
|
||
|
// RAYTRACE the scene
|
||
|
// --------
|
||
|
// 0 - Get Lights from 3DSMAX
|
||
|
vector<SLightBuild> vLights;
|
||
|
getLightBuilds( vLights, tvTime, *theCNelExport.ip );
|
||
|
// Old version (with lighting for the Nel Core Engine)
|
||
|
// vector<CLight> vLights;
|
||
|
// CExportNel::getLights( vLights, tvTime, *theCNelExport.ip );
|
||
|
|
||
|
// 1 - Light with the normal and the lights
|
||
|
for( nNode=0; nNode < nNbMesh; ++nNode )
|
||
|
{
|
||
|
CMesh::CMeshBuild *pMB = AllMeshBuilds[nNode].first;
|
||
|
CMatrix MBMatrix = getObjectToWorldMatrix( pMB );
|
||
|
vector<CVector> AllVertices; // All vertices in world space
|
||
|
|
||
|
AllVertices.resize(pMB->Vertices.size());
|
||
|
for( i = 0; i < pMB->Vertices.size(); ++i )
|
||
|
AllVertices[i] = MBMatrix * pMB->Vertices[i];
|
||
|
|
||
|
// Select all lights that interact with this mesh
|
||
|
|
||
|
sint32 nNbFace = pMB->Faces.size();
|
||
|
MBMatrix.invert();
|
||
|
MBMatrix.transpose();
|
||
|
for( i = 0; i < nNbFace; ++i )
|
||
|
{
|
||
|
vector<uint8> Piece;
|
||
|
sint32 nPieceSizeX, nPieceSizeY, nPiecePosX, nPiecePosY;
|
||
|
// Get the lightmap from the material of the face
|
||
|
ITexture *pText = pMB->Materials[pMB->Faces[i].MaterialId].getTexture( 1 );
|
||
|
CTextureFile *pLightMap = dynamic_cast<CTextureFile*>(pText);
|
||
|
if( pLightMap == NULL )
|
||
|
continue;
|
||
|
double u1 = pMB->Faces[i].Corner[0].Uvws[1].U * pLightMap->getWidth(),
|
||
|
v1 = pMB->Faces[i].Corner[0].Uvws[1].V * pLightMap->getHeight(),
|
||
|
u2 = pMB->Faces[i].Corner[1].Uvws[1].U * pLightMap->getWidth(),
|
||
|
v2 = pMB->Faces[i].Corner[1].Uvws[1].V * pLightMap->getHeight(),
|
||
|
u3 = pMB->Faces[i].Corner[2].Uvws[1].U * pLightMap->getWidth(),
|
||
|
v3 = pMB->Faces[i].Corner[2].Uvws[1].V * pLightMap->getHeight();
|
||
|
CVector p1 = AllVertices[pMB->Faces[i].Corner[0].Vertex],
|
||
|
p2 = AllVertices[pMB->Faces[i].Corner[1].Vertex],
|
||
|
p3 = AllVertices[pMB->Faces[i].Corner[2].Vertex];
|
||
|
CVector n1 = MBMatrix.mulVector( pMB->Faces[i].Corner[0].Normal ),
|
||
|
n2 = MBMatrix.mulVector( pMB->Faces[i].Corner[1].Normal ),
|
||
|
n3 = MBMatrix.mulVector( pMB->Faces[i].Corner[2].Normal );
|
||
|
n1.normalize(); n2.normalize(); n3.normalize();
|
||
|
// Denominator Gradient along u and v
|
||
|
double GradDen = 1.0 / ( (u3-u1)*(v2-v1) - (u2-u1)*(v3-v1) );
|
||
|
|
||
|
// Get the mask
|
||
|
CreatePiece( Piece, nPieceSizeX, nPieceSizeY, nPiecePosX, nPiecePosY,
|
||
|
u1, v1, u2, v2, u3, v3, 1 );
|
||
|
// Parse the mask
|
||
|
for( k = 0; k < nPieceSizeY; ++k )
|
||
|
for( j = 0; j < nPieceSizeX; ++j )
|
||
|
if( Piece[j+k*nPieceSizeX] != 0 ) // Must this point be lighted ?
|
||
|
{ // Yes
|
||
|
CRGBAF theColor;
|
||
|
// Convert the (u,v) to world space coord (use gradient of x along u and v) (same for y,z...)
|
||
|
double theU = nPiecePosX + j + 0.5;
|
||
|
double theV = nPiecePosY + k + 0.5;
|
||
|
CVector p, n; // p is the point in the world space
|
||
|
|
||
|
double GradU = ( (p3.x-p1.x)*(v2-v1)-(p2.x-p1.x)*(v3-v1) ) * GradDen;
|
||
|
double GradV = ( (p2.x-p1.x)*(u3-u1)-(p3.x-p1.x)*(u2-u1) ) * GradDen;
|
||
|
p.x = GradU*(theU-u1) + GradV*(theV-v1) + p1.x;
|
||
|
|
||
|
GradU = ( (p3.y-p1.y)*(v2-v1)-(p2.y-p1.y)*(v3-v1) ) * GradDen;
|
||
|
GradV = ( (p2.y-p1.y)*(u3-u1)-(p3.y-p1.y)*(u2-u1) ) * GradDen;
|
||
|
p.y = GradU*(theU-u1) + GradV*(theV-v1) + p1.y;
|
||
|
|
||
|
GradU = ( (p3.z-p1.z)*(v2-v1)-(p2.z-p1.z)*(v3-v1) ) * GradDen;
|
||
|
GradV = ( (p2.z-p1.z)*(u3-u1)-(p3.z-p1.z)*(u2-u1) ) * GradDen;
|
||
|
p.z = GradU*(theU-u1) + GradV*(theV-v1) + p1.z;
|
||
|
|
||
|
// The same for the normal
|
||
|
|
||
|
GradU = ( (n3.x-n1.x)*(v2-v1)-(n2.x-n1.x)*(v3-v1) ) * GradDen;
|
||
|
GradV = ( (n2.x-n1.x)*(u3-u1)-(n3.x-n1.x)*(u2-u1) ) * GradDen;
|
||
|
n.x = GradU*(theU-u1) + GradV*(theV-v1) + n1.x;
|
||
|
|
||
|
GradU = ( (n3.y-n1.y)*(v2-v1)-(n2.y-n1.y)*(v3-v1) ) * GradDen;
|
||
|
GradV = ( (n2.y-n1.y)*(u3-u1)-(n3.y-n1.y)*(u2-u1) ) * GradDen;
|
||
|
n.y = GradU*(theU-u1) + GradV*(theV-v1) + n1.y;
|
||
|
|
||
|
GradU = ( (n3.z-n1.z)*(v2-v1)-(n2.z-n1.z)*(v3-v1) ) * GradDen;
|
||
|
GradV = ( (n2.z-n1.z)*(u3-u1)-(n3.z-n1.z)*(u2-u1) ) * GradDen;
|
||
|
n.z = GradU*(theU-u1) + GradV*(theV-v1) + n1.z;
|
||
|
|
||
|
// --- n = n1 + n2 + n3;
|
||
|
n.normalize();
|
||
|
|
||
|
|
||
|
theColor.R = theColor.G = theColor.B = theColor.A = 0.0;
|
||
|
// Color calculation
|
||
|
for( sint32 nLight = 0; nLight < vLights.size(); ++nLight )
|
||
|
{
|
||
|
SLightBuild rLight = vLights[nLight];
|
||
|
CRGBAF lightAmbiCol = CRGBAF(0.0, 0.0, 0.0, 0.0);
|
||
|
CRGBAF lightDiffCol = CRGBAF(0.0, 0.0, 0.0, 0.0);
|
||
|
CRGBAF lightSpecCol = CRGBAF(0.0, 0.0, 0.0, 0.0);
|
||
|
|
||
|
switch( rLight.Type )
|
||
|
{
|
||
|
case SLightBuild::LightAmbient:
|
||
|
lightAmbiCol.R = rLight.Ambient.R / 255.0;
|
||
|
lightAmbiCol.G = rLight.Ambient.G / 255.0;
|
||
|
lightAmbiCol.B = rLight.Ambient.B / 255.0;
|
||
|
lightAmbiCol.A = rLight.Ambient.A / 255.0;
|
||
|
break;
|
||
|
case SLightBuild::LightPoint:
|
||
|
{
|
||
|
CVector p_light = rLight.Position - p;
|
||
|
double p_light_distance = p_light.norm();
|
||
|
double light_intensity;
|
||
|
if( p_light_distance < rLight.rRadiusMin )
|
||
|
light_intensity = 1.0;
|
||
|
else
|
||
|
if( p_light_distance > rLight.rRadiusMax )
|
||
|
light_intensity = 0.0;
|
||
|
else
|
||
|
light_intensity = 1.0 - (p_light_distance-rLight.rRadiusMin)/(rLight.rRadiusMax-rLight.rRadiusMin);
|
||
|
p_light.normalize();
|
||
|
|
||
|
// ??? light_intensity *= light_intensity * light_intensity;
|
||
|
lightDiffCol.R = light_intensity * rLight.Diffuse.R * max(0.0f, n*p_light) / 255.0;
|
||
|
lightDiffCol.G = light_intensity * rLight.Diffuse.G * max(0.0f, n*p_light) / 255.0;
|
||
|
lightDiffCol.B = light_intensity * rLight.Diffuse.B * max(0.0f, n*p_light) / 255.0;
|
||
|
lightDiffCol.A = light_intensity * rLight.Diffuse.A * max(0.0f, n*p_light) / 255.0;
|
||
|
}
|
||
|
break;
|
||
|
case SLightBuild::LightDir:
|
||
|
{
|
||
|
CVector light = - rLight.Direction;
|
||
|
light.normalize();
|
||
|
lightDiffCol.R = rLight.Diffuse.R * max(0.0f, n*light) / 255.0;
|
||
|
lightDiffCol.G = rLight.Diffuse.G * max(0.0f, n*light) / 255.0;
|
||
|
lightDiffCol.B = rLight.Diffuse.B * max(0.0f, n*light) / 255.0;
|
||
|
lightDiffCol.A = rLight.Diffuse.A * max(0.0f, n*light) / 255.0;
|
||
|
}
|
||
|
break;
|
||
|
case SLightBuild::LightSpot:
|
||
|
// TODO
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
theColor.R += lightAmbiCol.R + lightDiffCol.R;// * matDiffCol.R;
|
||
|
if( theColor.R > 1.0 ) theColor.R = 1.0;
|
||
|
theColor.G += lightAmbiCol.G + lightDiffCol.G;// * matDiffCol.G;
|
||
|
if( theColor.G > 1.0 ) theColor.G = 1.0;
|
||
|
theColor.B += lightAmbiCol.B + lightDiffCol.B;// * matDiffCol.B;
|
||
|
if( theColor.B > 1.0 ) theColor.B = 1.0;
|
||
|
theColor.A += lightAmbiCol.A + lightDiffCol.A;// * matDiffCol.A;
|
||
|
if( theColor.A > 1.0 ) theColor.A = 1.0;
|
||
|
}
|
||
|
// Affect the color
|
||
|
|
||
|
theColor.R = (1+n.x)/2;
|
||
|
theColor.G = (1+n.y)/2;
|
||
|
theColor.B = (1+n.z)/2;
|
||
|
theColor.A = 1.;
|
||
|
|
||
|
CObjectVector<uint8> &pixel = pLightMap->getPixels();
|
||
|
pixel[(j+nPiecePosX + (k+nPiecePosY)*pLightMap->getWidth())*4+0] = theColor.R*255;
|
||
|
pixel[(j+nPiecePosX + (k+nPiecePosY)*pLightMap->getWidth())*4+1] = theColor.G*255;
|
||
|
pixel[(j+nPiecePosX + (k+nPiecePosY)*pLightMap->getWidth())*4+2] = theColor.B*255;
|
||
|
pixel[(j+nPiecePosX + (k+nPiecePosY)*pLightMap->getWidth())*4+3] = theColor.A*255;
|
||
|
}
|
||
|
}
|
||
|
// Write the new LightMap
|
||
|
{
|
||
|
COFile f;
|
||
|
ITexture *pText = pMB->Materials[0].getTexture( 1 );
|
||
|
CTextureFile *pLightMap = dynamic_cast<CTextureFile*>(pText);
|
||
|
string sTemp = theExportSceneStruct.sExportLighting;
|
||
|
if(sTemp[sTemp.size()-1] != '\\' ) sTemp += "\\";
|
||
|
sTemp += pLightMap->getFileName();
|
||
|
f.open( sTemp );
|
||
|
pLightMap->writeTGA( f, 32 );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// End of the lighting process for this node we have to export the data
|
||
|
for( nNode=0; nNode < nNbMesh; ++nNode )
|
||
|
{
|
||
|
// First order face by Material and by texture surface
|
||
|
CMesh::CMeshBuild *pMB = AllMeshBuilds[nNode].first;
|
||
|
CMesh* mesh = new CMesh;
|
||
|
pMB->VertexFlags |= CVertexBuffer::TexCoord1Flag;
|
||
|
// Build the mesh with the build interface
|
||
|
|
||
|
// TEMP YOYO (DU) DE SA RACE
|
||
|
pMB->VertexFlags |= CVertexBuffer::PrimaryColorFlag;
|
||
|
CMatrix MBMatrix = getObjectToWorldMatrix( pMB );
|
||
|
for( i = 0; i < pMB->Faces.size(); ++i )
|
||
|
{
|
||
|
CVector n = MBMatrix.mulVector(pMB->Faces[i].Corner[0].Normal);
|
||
|
pMB->Faces[i].Corner[0].Color.R = 255.0 * (n.x+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[0].Color.G = 255.0 * (n.y+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[0].Color.B = 255.0 * (n.z+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[0].Color.A = 255.0;
|
||
|
n = MBMatrix.mulVector(pMB->Faces[i].Corner[1].Normal);
|
||
|
pMB->Faces[i].Corner[1].Color.R = 255.0 * (n.x+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[1].Color.G = 255.0 * (n.y+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[1].Color.B = 255.0 * (n.z+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[1].Color.A = 255.0;
|
||
|
n = MBMatrix.mulVector(pMB->Faces[i].Corner[2].Normal);
|
||
|
pMB->Faces[i].Corner[2].Color.R = 255.0 * (n.x+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[2].Color.G = 255.0 * (n.y+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[2].Color.B = 255.0 * (n.z+1.0)/2.0;
|
||
|
pMB->Faces[i].Corner[2].Color.A = 255.0;
|
||
|
}
|
||
|
// TEMP YOYO (DU) DE SA RACE end
|
||
|
|
||
|
for( i = 0; i < pMB->Materials.size(); ++i )
|
||
|
{
|
||
|
pMB->Materials[i].setLighting( false );
|
||
|
pMB->Materials[i].setColor( CRGBA(255,255,255,255) );
|
||
|
}
|
||
|
// *** TMP : force material to be animatable
|
||
|
// TODO: check if material are animated
|
||
|
//for (uint i=0; i<buildMesh.Materials.size(); i++)
|
||
|
//{
|
||
|
// mesh->setAnimatedMaterial (i, materialNames[i]);
|
||
|
//}
|
||
|
|
||
|
mesh->build( *pMB );
|
||
|
|
||
|
|
||
|
COFile file;
|
||
|
char sSavePath[512];
|
||
|
strcpy( sSavePath, theExportSceneStruct.sExportShapes.c_str() );
|
||
|
if(theExportSceneStruct.sExportShapes[theExportSceneStruct.sExportShapes.size()-1] != '\\' )
|
||
|
strcat( sSavePath, "\\" );
|
||
|
strcat( sSavePath, AllMeshBuilds[nNode].second->GetName() );
|
||
|
strcat( sSavePath, ".shape" );
|
||
|
if (file.open( sSavePath ))
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
// Create a streamable shape
|
||
|
CShapeStream shapeStream( mesh );
|
||
|
// Serial the shape
|
||
|
shapeStream.serial (file);
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Delete the pointer
|
||
|
delete mesh;
|
||
|
}
|
||
|
|
||
|
// ? -> Ending deletion des objets temporaires
|
||
|
for( nNode = 0; nNode < nNbMesh; ++nNode )
|
||
|
delete AllMeshBuilds[nNode].first;
|
||
|
} // End if lighting process asked
|
||
|
|
||
|
return true;
|
||
|
}
|