#include "PtexImporter.h"
IMPLEMENT_CLASS( PtexImporter, Importer, "pteximporter" );
void PtexImporter::Import( const QString &sFileName, Scene::LoadData & )
{
QByteArray a = QFile::encodeName( sFileName );
Ptex::String s;
PtexTexture *pT = PtexTexture::open( a.constData(), s );
PtexMetaData *pM = pT->getMetaData();
if ( !pM )
{
Kernel()->HUDMessageShow( tr("This PTEX file does not contain mesh information. Mudbox cannot import it."), Kernel::HUDmsgFade );
return;
};
Mesh *pMesh = CreateMeshFromMetaData( pM );
if ( pMesh == NULL )
return;
pMesh->RecalculateAdjacency();
AddMesh( pMesh );
UVGeneratorNode *pG = pMesh->ChildByClass<UVGeneratorNode>( true );
for ( unsigned int f = 0; f < pMesh->FaceCount(); f++ )
{
const Ptex::FaceInfo &i = pT->getFaceInfo( f );
pG->SetFaceSize( f, 1<<i.res.ulog2, 1<<i.res.vlog2 );
};
pG->GenerateUVs( false );
Material *pMat = CreateInstance<Material>();
pMesh->Geometry()->SetMaterial( pMat );
Kernel()->ProgressStart( tr("Reading Ptex Texture..."), pMesh->FaceCount() );
for ( unsigned int j = 0; j < pMat->TextureCount(); j++ )
{
TexturePool *pTP = pMat->Texture( j );
if ( pTP->Name() == NTR("Diffuse") )
{
LayerContainer *pC = dynamic_cast<LayerContainer *>( pTP );
if ( pC )
{
Layer *pL = pC->CreateLayer();
TexturePool *pTP = dynamic_cast<TexturePool *>( pL );
MB_SAFELY( pTP )
{
QFileInfo i( sFileName );
pTP->Node::SetName( i.baseName() );
LoadPtexTexture( pT, pTP, pMesh, pG );
EdgeBleeding::FillBleedingAreas( pMesh, pTP );
};
};
pTP->SetRenderMode( TexturePool::renderModeTexture );
};
};
Kernel()->ProgressEnd();
};
Mesh *PtexImporter::CreateMeshFromMetaData( PtexMetaData *pM ) const
{
int iFaceCount = 0;
const int *aFaceSizes = NULL;
pM->getValue( NTR("PtexFaceVertCounts"), aFaceSizes, iFaceCount );
if ( aFaceSizes == NULL )
return NULL;
for ( int i = 0; i < iFaceCount; i++ )
if ( aFaceSizes[i] != 4 )
{
Kernel()->HUDMessageShow( tr("Mudbox can only import PTEX files that contain quad-only meshes."), Kernel::HUDmsgFade );
return NULL;
};
int iVertexDataSize = 0;
const float *aVertexPositions = NULL;
pM->getValue( NTR("PtexVertPositions"), aVertexPositions, iVertexDataSize );
if ( iVertexDataSize%3 || aVertexPositions == NULL )
return NULL;
int iFaceDataSize = 0;
const int *aFaceData = NULL;
pM->getValue( NTR("PtexFaceVertIndices"), aFaceData, iFaceDataSize );
if ( iFaceDataSize != iFaceCount*4 || aFaceData == NULL )
return NULL;
Mesh *pMesh = Kernel()->CreateMesh( Topology::typeQuadric );
pMesh->SetVertexCount( iVertexDataSize/3 );
for ( int i = 0; i < iVertexDataSize/3; i++ )
pMesh->SetVertexPosition( i, Vector( aVertexPositions[i*3+0], aVertexPositions[i*3+1], aVertexPositions[i*3+2] ) );
pMesh->SetFaceCount( iFaceCount );
for ( int i = 0; i < iFaceCount; i++ )
{
pMesh->SetQuadIndex( i, 0, aFaceData[i*4+0] );
pMesh->SetQuadIndex( i, 1, aFaceData[i*4+1] );
pMesh->SetQuadIndex( i, 2, aFaceData[i*4+2] );
pMesh->SetQuadIndex( i, 3, aFaceData[i*4+3] );
};
return pMesh;
};
void PtexImporter::LoadPtexTexture( PtexTexture *pT, TexturePool *pTP, Mesh *pMesh, UVGeneratorNode *pG )
{
const unsigned int iTileSize = pG->UVTileSize();
unsigned int iUS = 0, iUE = 0, iVS = 0, iVE = 0;
for ( unsigned int f = 0; f < pMesh->FaceCount(); f++ )
{
UVGeneratorNode::DimData2 d = pG->FaceUVArea( f );
iUS = Min( iUS, d[0] );
iUE = Max( iUE, d[0]+1 );
iVS = Min( iVS, d[1] );
iVE = Max( iVE, d[1]+1 );
};
for ( unsigned int u = iUS; u < iUE; u++ )
for ( unsigned int v = iVS; v < iVE; v++ )
{
Instance<Image> i;
enum Image::Format aPtexFormats[4] = { Image::e8integer, Image::e16integer, Image::e16float, Image::e32float };
i->Create( iTileSize, iTileSize, 4, aPtexFormats[pT->dataType()] );
for ( unsigned int f = 0; f < pMesh->FaceCount(); f++ )
{
MB_ASSERT( pG->FaceSizeExponent( f )[0] == pT->getFaceInfo( f ).res.ulog2 );
MB_ASSERT( pG->FaceSizeExponent( f )[1] == pT->getFaceInfo( f ).res.vlog2 );
UVGeneratorNode::DimData2 d = pG->FaceUVPosition( f );
if ( pG->FaceUVArea( f )[0] != u || pG->FaceUVArea( f )[1] != v )
continue;
char iOrientation = pG->FaceOrientation( f );
void *p = NULL;
switch ( pT->dataType() )
{
case Ptex::dt_uint8:
p = PrepareFaceBuffer<unsigned char,255>( pT, f, iOrientation );
break;
case Ptex::dt_uint16:
p = PrepareFaceBuffer<unsigned short,65535>( pT, f, iOrientation );
break;
case Ptex::dt_half:
p = PrepareFaceBuffer<half_,1>( pT, f, iOrientation );
break;
case Ptex::dt_float:
p = PrepareFaceBuffer<float,1>( pT, f, iOrientation );
break;
};
i->setTile( d[0]%iTileSize, d[1]%iTileSize, pG->FaceUVSize( f )[0], pG->FaceUVSize( f )[1], p );
delete p;
Kernel()->ProgressAdd();
};
Texture *pO = pTP->Tile( AxisAlignedBoundingBox( Vector( u, v, 0.5 ), Vector( u+1, v+1, 0.5 ) ) );
pO->CopyFrom( i );
};
};
template <typename eFormat, int iMax>
void *PtexImporter::PrepareFaceBuffer( PtexTexture *pTexture, unsigned int iFaceIndex, char iDirection )
{
int iChannelCount = pTexture->numChannels();
int iU = 1<<pTexture->getFaceInfo( iFaceIndex ).res.ulog2, iV = 1<<pTexture->getFaceInfo( iFaceIndex ).res.vlog2;
eFormat *pTmp = new eFormat[iU*iV*iChannelCount];
pTexture->getData( iFaceIndex, pTmp, iU*iChannelCount*sizeof(eFormat) );
eFormat *pBuffer = new eFormat[4*iU*iV];
for ( int y = 0; y < iV; y++ )
for ( int x = 0; x < iU; x++ )
{
unsigned int d = 0;
switch ( iDirection )
{
case 0:
d = 4*(x+y*iU);
break;
case 1:
d = 4*(y+(iU-x-1)*iV);
break;
case 2:
d = 4*((iU-x-1)+(iV-y-1)*iU);
break;
case 3:
d = 4*((iV-y-1)+x*iV);
break;
};
int c = 0;
while ( c < iChannelCount )
{
pBuffer[d+c] = pTmp[iChannelCount*(x+y*iU)+c];
c++;
};
while ( c < 4 )
{
if ( c == 3 )
pBuffer[d+c] = iMax;
else
pBuffer[d+c] = 0;
c++;
};
};
return pBuffer;
};