#include "PtexUtilizer.h"
#include <omp.h>
IMPLEMENT_SCLASS( PtexUtilizer, Utilizer, "ptexutilizer", 1 );
PtexUtilizer::PtexUtilizer( void ) : m_pWriter( NULL ), m_iComponentCount( 3 ), m_bIncludeMeshData( this, "includemeshdata" ), m_eFormat( this, "format" ), m_iPtexFaceCount( 0 )
{
m_bIncludeMeshData.SetName( QObject::tr( "Include Mesh Data:" ) );
m_bIncludeMeshData.SetToolTip( QObject::tr( "Store the mesh data with the ptex file. This is useful if you are using a ptex viewer program to preview the ptex file." ) );
m_bIncludeMeshData = true;
m_eFormat.SetName( QObject::tr( "Data Format:" ) );
m_eFormat.SetToolTip( QObject::tr( "Format of the data in the file. This affects precision and file size." ) );
m_eFormat.AddItem( QObject::tr( "8 bit integer" ) );
m_eFormat.AddItem( QObject::tr( "16 bit integer" ) );
m_eFormat.AddItem( QObject::tr( "16 bit float" ) );
m_eFormat.AddItem( QObject::tr( "32 bit float" ) );
m_eFormat = 3;
};
QStringList PtexUtilizer::SupportedExtensions( Component * ) const
{
return QStringList( QObject::tr("Ptex file ") + NTRQ("(*.ptx)") );
};
#define WRITEFACE( type, multiplier ) \
{ \
type *p = new type[d.m_aData.size()]; \
for ( int i = 0; i < d.m_aData.size() && p; i++ ) \
p[i] = (type)(multiplier*d.m_aData[i]); \
m_pWriter->writeFace( iFaceID, sInfo, p ); \
delete p; \
};
void PtexUtilizer::StoreData( const Data &cData, const TargetLocation &cTarget, bool )
{
int u = cTarget.m_aLayoutData[PtexLayout::dataURes]&0xffffff, v = cTarget.m_aLayoutData[PtexLayout::dataVRes]&0xffffff;
int ures = cTarget.m_aLayoutData[PtexLayout::dataURes]>>24, vres = cTarget.m_aLayoutData[PtexLayout::dataURes]>>24;
unsigned int iFaceID = cTarget.m_aLayoutData[PtexLayout::dataFaceID];
bool bSubface = iFaceID & 0x80000000;
iFaceID &= 0x7fffffff;
int w = 1 << ures, h = 1 << vres;
if ( m_aFaces.size() == 0 )
{
#pragma omp critical (initfaces)
{
if ( m_aFaces.size() == 0 )
{
const Mesh *pMesh = cTarget.Mesh();
if ( pMesh->Type() == Mesh::typeQuadric )
m_iPtexFaceCount = pMesh->FaceCount();
else
{
m_iPtexFaceCount = 0;
unsigned int i = 0;
while ( i < pMesh->FaceCount() )
{
int s = 3;
i++;
while ( i < pMesh->FaceCount() && pMesh->IsFakeTriangle( i ) )
{
i++; s++;
};
if ( s == 4 )
m_iPtexFaceCount++;
else
m_iPtexFaceCount += s;
};
};
m_iFacesProcessed = 0;
m_aFaces.fill( NULL, m_iPtexFaceCount );
};
};
};
if ( !m_aFaces[iFaceID] )
{
#pragma omp critical (insertface)
{
if ( !m_aFaces[iFaceID] )
m_aFaces[iFaceID] = new FaceData( w, h );
};
};
FaceData &d = *m_aFaces[iFaceID];
for ( int c = 0; c < m_iComponentCount; c++ )
d.m_aData[c+(u+v*w)*m_iComponentCount] = ((const float *)(cData.As_Color()))[c];
#pragma omp atomic
d.m_iSamplesLeft--;
if ( d.m_iSamplesLeft == 0 )
{
#pragma omp critical (flushface)
{
if ( d.m_iSamplesLeft == 0 )
{
if ( !m_pWriter )
OpenFile( cTarget.Mesh() );
MB_ASSERT( m_pMesh == cTarget.Mesh() );
Ptex::FaceInfo sInfo;
if ( bSubface )
sInfo.flags |= Ptex::FaceInfo::flag_subface;
sInfo.res = Ptex::Res( ures, vres );
unsigned int af[4], ae[4];
if ( m_pMesh->Type() == Mesh::typeQuadric )
{
for ( int c = 0; c < 4; c++ )
{
unsigned int a = cTarget.m_pMesh->QuadAdjacency( cTarget.m_iFaceIndex, c );
if ( a == 0xffffffff )
{
af[c] = 0xffffffff;
ae[c] = 0;
}
else
{
af[c] = a/4;
ae[c] = a%4;
};
};
}
else
{
for ( unsigned int c = 0; c < 4; c++ )
af[c] = m_pLayout->AdjacentFace( iFaceID, c, ae[c] );
};
sInfo.setadjfaces( af[0], af[1], af[2], af[3] );
sInfo.setadjedges( ae[0], ae[1], ae[2], ae[3] );
void *pData;
switch ( m_eFormat )
{
case eFormat8bitInteger:
WRITEFACE( unsigned char, 255 );
break;
case eFormat16bitInteger:
WRITEFACE( unsigned short, 65536 );
break;
case eFormat16bitFloat:
WRITEFACE( half_, 1 );
break;
case eFormat32bitFloat:
WRITEFACE( float, 1 );
};
delete m_aFaces[iFaceID];
m_aFaces[iFaceID] = NULL;
m_iFacesProcessed++;
};
};
};
};
void PtexUtilizer::OnPhaseEvent( PhaseEventType t )
{
if ( t == eventSectionEnd )
{
for ( int i = 0; i < m_iPtexFaceCount; i++ )
MB_ASSERT( m_aFaces[i] == 0 );
m_aFaces.clear();
if ( m_pWriter )
CloseFile();
};
};
void PtexUtilizer::OpenFile( const Mesh *pMesh )
{
MB_ASSERT( !m_pWriter );
m_pMesh = pMesh;
Ptex::String sError;
QByteArray qbaFileMask = QFile::encodeName(m_sFileMask.Value());
Ptex::DataType aFormats[4] = { Ptex::dt_uint8, Ptex::dt_uint16, Ptex::dt_half, Ptex::dt_float };
m_pWriter = PtexWriter::open( qbaFileMask.constData(), Ptex::mt_quad, aFormats[m_eFormat], m_iComponentCount, -1, m_iPtexFaceCount, sError );
if ( !m_pWriter )
MB_ERROR( sError.c_str() );
};
void PtexUtilizer::CloseFile( void )
{
MB_ONBUG( !m_pWriter )
return;
if ( m_bIncludeMeshData )
WriteMeshData( m_pWriter, m_pMesh );
Ptex::String sError;
bool bOk = m_pWriter->close( sError );
m_pWriter->release();
if ( !bOk )
MB_ERROR( sError.c_str() );
m_pWriter = NULL;
};
void PtexUtilizer::WriteMeshData( PtexWriter *pWriter, const Mesh *pMesh )
{
QVector<float> aVertexPositions( pMesh->VertexCount()*3 );
for ( unsigned int c = 0; c < pMesh->VertexCount(); c++ )
{
Vector v = pMesh->VertexPosition( c );
aVertexPositions[c*3+0] = v.x;
aVertexPositions[c*3+1] = v.y;
aVertexPositions[c*3+2] = v.z;
};
pWriter->writeMeta( "PtexVertPositions", aVertexPositions.data(), aVertexPositions.size() );
QVector<int> aFaceVertexIndices;
QVector<int> aFaceVertexCounts;
if ( pMesh->Type() == Mesh::typeQuadric )
{
aFaceVertexIndices.resize( pMesh->FaceCount()*4 );
for ( unsigned int f = 0; f < pMesh->FaceCount(); f++ )
for ( int c = 0; c < 4; c++ )
aFaceVertexIndices[f*4+c] = pMesh->QuadIndex( f, c );
aFaceVertexCounts.fill( 4, pMesh->FaceCount() );
}
else
{
unsigned int iPolygonCount = 0;
for ( unsigned int f = 0; f < pMesh->FaceCount(); f++ )
if ( !pMesh->IsFakeTriangle( f ) )
iPolygonCount++;
aFaceVertexIndices.resize( pMesh->FaceCount()+2*(iPolygonCount) );
aFaceVertexCounts.resize( iPolygonCount );
unsigned int iVertexIndex = 0, iPolygonIndex = 0;
for ( unsigned int f = 0, p = 0; f < pMesh->FaceCount(); f++ )
{
unsigned int iSideCount = 3;
aFaceVertexIndices[iVertexIndex++] = pMesh->TriangleIndex( f, 0 );
aFaceVertexIndices[iVertexIndex++] = pMesh->TriangleIndex( f, 1 );
aFaceVertexIndices[iVertexIndex++] = pMesh->TriangleIndex( f, 2 );
while ( f < pMesh->FaceCount()-1 && pMesh->IsFakeTriangle( f+1 ) )
{
f++;
iSideCount++;
aFaceVertexIndices[iVertexIndex++] = pMesh->TriangleIndex( f, 2 );
};
aFaceVertexCounts[iPolygonIndex++] = iSideCount;
};
MB_ASSERT( iVertexIndex == aFaceVertexIndices.size() );
MB_ASSERT( iPolygonIndex == aFaceVertexCounts.size() );
};
pWriter->writeMeta( "PtexFaceVertIndices", aFaceVertexIndices.data(), aFaceVertexIndices.size() );
pWriter->writeMeta( "PtexFaceVertCounts", aFaceVertexCounts.data(), aFaceVertexCounts.size() );
};
void PtexUtilizer::Serialize( Stream &s )
{
if ( s.IsNewerThan( 0, this ) )
s == m_bIncludeMeshData;
Utilizer::Serialize( s );
};
PtexUtilizer::FaceData::FaceData( unsigned int iWidth, unsigned int iHeight )
{
m_iWidth = iWidth;
m_iHeight = iHeight;
m_iSamplesLeft = m_iWidth*m_iHeight;
m_aData.resize( m_iSamplesLeft*3 );
};
void PtexUtilizer::Initialize( Layout *pLayout, Component *pComponent )
{
m_pLayout = dynamic_cast<const PtexLayout *>( pLayout );
Utilizer::Initialize( pLayout, pComponent );
};