#include "PtexUtilizer.h"
#include <omp.h>
Preferences::String g_sPtexPath(
NTR(
"Map Extraction Ptex Folder"),
QObject::tr("Map Extraction Ptex Folder"),
QObject::tr("Paths"),
Kernel()->Preferences()->m_sTexturePath.Value(),
false );
PtexUtilizer::PtexUtilizer( void ) :
m_pWriter( NULL ),
m_iChannelCount( 3 ),
m_bIncludeMeshData( this, "includemeshdata" ),
m_eFormat( this, "format" ),
m_iPtexFaceCount( 0 ),
m_sFileName( this,
NTRQ(
"filename"), false ),
m_sFilePath( this, "filepath" )
{
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;
m_sFileName.m_sFilter = QObject::tr( "Ptex files (*.ptx)" );
m_sFileName.SetInstantEdit( true );
m_sFileName.SetName( QObject::tr( "File Name:" ) );
m_sFilePath.Connect( *g_sPtexPath.m_pAttribute );
m_sFilePath.SetVisible( false );
};
{
m_sFileName.m_sPath = m_sFilePath;
Extractor()->ValidityChanged();
g_sPtexPath.m_pAttribute->SetValue( m_sFileName.m_sPath );
};
#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, const SurfacePoint & )
{
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::dataVRes]>>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() )
{
i++;
while ( i < pMesh->FaceCount() && pMesh->IsFakeTriangle( i ) )
{
i++; s++;
};
if ( s == 4 )
m_iPtexFaceCount++;
else
};
};
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, m_iChannelCount );
};
};
FaceData &d = *m_aFaces[iFaceID];
for (
int c = 0;
c < m_iChannelCount;
c++ )
d.m_aData[
c+(u+
v*w)*m_iChannelCount] = ((
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() );
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 )
{
}
else
{
};
};
}
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] );
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++;
};
};
};
};
{
{
for ( unsigned int i = 0; i < m_iPtexFaceCount; i++ )
m_aFaces.clear();
if ( m_pWriter )
CloseFile();
};
};
void PtexUtilizer::OpenFile( const Mesh *pMesh )
{
m_pMesh = pMesh;
Ptex::String sError;
MapExtractor *pM = Extractor();
if ( pM && pM->TargetMesh(pM->CurrentTarget()) && pM->TargetMesh(pM->CurrentTarget())->Geometry() )
{
QString sTargetID = pM->TargetMesh( pM->CurrentTarget() )->Geometry()->Name();
sFileName.
replace(
"%s", sTargetID );
}
sFileName =
QDir(
Kernel()->Preferences()->m_sDataPath.Value()).absoluteFilePath(sFileName);
Ptex::DataType aFormats[4] = { Ptex::dt_uint8, Ptex::dt_uint16, Ptex::dt_half, Ptex::dt_float };
PtexWriter::setTempFolder(
Kernel()->Preferences()->m_sTempPath.Value().toStdString() );
m_pWriter = PtexWriter::open( qbaFileMask.
constData(), Ptex::mt_quad, aFormats[m_eFormat], m_iChannelCount, -1, m_iPtexFaceCount, sError );
if ( !m_pWriter )
};
void PtexUtilizer::CloseFile( void )
{
return;
if ( m_bIncludeMeshData )
WriteMeshData( m_pWriter, m_pMesh );
Ptex::String sError;
bool bOk = m_pWriter->close( sError );
m_pWriter->release();
m_pWriter = NULL;
if ( !bOk )
};
void PtexUtilizer::WriteMeshData( PtexWriter *pWriter, const Mesh *pMesh )
{
for (
unsigned int c = 0;
c < pMesh->VertexCount();
c++ )
{
Vector
v = pMesh->Geometry()->Transformation()->TransformToWorld( 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() );
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 ) )
{
iSideCount++;
aFaceVertexIndices[iVertexIndex++] = pMesh->TriangleIndex(
f, 2 );
};
aFaceVertexCounts[iPolygonIndex++] = iSideCount;
};
};
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;
if ( s.IsNewerThan( 1, this ) )
s == m_sFileName == m_eFormat;
Utilizer::Serialize( s );
};
PtexUtilizer::FaceData::FaceData( unsigned int iWidth, unsigned int iHeight, unsigned int iChannelCount )
{
m_iWidth = iWidth;
m_iHeight = iHeight;
m_iSamplesLeft = m_iWidth*m_iHeight;
m_aData.resize( m_iSamplesLeft*iChannelCount );
};
void PtexUtilizer::Prepare( Layout *pLayout, class Sampler *pSampler )
{
struct Sampler::DataInfo i = Sampler()->DataInfo();
if ( i.m_ePrecision == Sampler::ePrecFloatOnly )
m_eFormat = m_eFormat+2;
m_iChannelCount = pSampler->DataInfo().m_iChannelCount;
m_pLayout = dynamic_cast<const PtexLayout *>( pLayout );
Utilizer::Prepare( pLayout, pSampler );
};
QWidget *PtexUtilizer::UserInterface(
void )
{
struct Sampler::DataInfo i = Sampler()->DataInfo();
if ( i.m_ePrecision == Sampler::ePrecFloatOnly )
{
m_eFormat.Clear();
m_eFormat.AddItem( QObject::tr( "16 bit float" ) );
m_eFormat.AddItem( QObject::tr( "32 bit float" ) );
m_eFormat = 1;
};
return Utilizer::UserInterface();
};