Save rendermodels as OBJ if postLoadExportModels is set

This commit is contained in:
Robert Beckebans 2016-03-16 23:18:47 +01:00
parent 95de9c62a5
commit c664c9e940
5 changed files with 166 additions and 6 deletions

View file

@ -714,6 +714,127 @@ void idRenderModelStatic::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp
file->WriteBig( hasShadowCastingSurfaces );
}
// RB begin
void idRenderModelStatic::ExportOBJ( idFile* objFile, idFile* mtlFile, ID_TIME_T* _timeStamp ) const
{
if( objFile == NULL || mtlFile == NULL )
{
common->Printf( "Failed to ExportOBJ\n" );
return;
}
//objFile->Printf( "// generated by %s\n//\n\n", ENGINE_VERSION );
int numVerts = 0;
idList< const idMaterial* > materials;
for( int i = 0; i < surfaces.Num(); i++ )
{
// shadow models use numVerts but have no verts
if( ( surfaces[i].geometry != NULL ) && ( surfaces[i].geometry->numVerts > 0 ) && ( surfaces[i].geometry->numIndexes > 0 ) && ( surfaces[i].geometry->verts != NULL ) )
{
objFile->Printf( "o Geometry.%i\n", surfaces[i].id );
srfTriangles_t& tri = *surfaces[i].geometry;
//file->WriteVec3( tri.bounds[0] );
//file->WriteVec3( tri.bounds[1] );
// TODO print additional info ?
//file->WriteBig( tri.generateNormals );
//file->WriteBig( tri.tangentsCalculated );
//file->WriteBig( tri.perfectHull );
//file->WriteBig( tri.referencedIndexes );
if( tri.numVerts > 0 && tri.verts != NULL )
{
for( int j = 0; j < tri.numVerts; j++ )
{
objFile->Printf( "v %1.6f %1.6f %1.6f\n", tri.verts[j].xyz.x, tri.verts[j].xyz.y, tri.verts[j].xyz.z );
}
for( int j = 0; j < tri.numVerts; j++ )
{
const idVec2 vST = tri.verts[j].GetTexCoord();
objFile->Printf( "vt %1.6f %1.6f\n", vST.x, 1.0f - vST.y );
}
for( int j = 0; j < tri.numVerts; j++ )
{
const idVec3 n = tri.verts[j].GetNormalRaw();
objFile->Printf( "vn %1.6f %1.6f %1.6f\n", n.x, n.y, n.z );
}
//file->WriteBigArray( tri.verts[j].st, 2 );
//file->WriteBigArray( tri.verts[j].normal, 4 );
//file->WriteBigArray( tri.verts[j].tangent, 4 );
//file->WriteBigArray( tri.verts[j].color, sizeof( tri.verts[j].color ) / sizeof( tri.verts[j].color[0] ) );
//file->WriteBigArray( tri.verts[j].color2, sizeof( tri.verts[j].color2 ) / sizeof( tri.verts[j].color2[0] ) );
}
if( surfaces[i].shader != NULL && surfaces[i].shader->GetName() != NULL )
{
objFile->Printf( "usemtl %s\n", surfaces[i].shader->GetName() );
materials.AddUnique( surfaces[i].shader );
}
objFile->Printf( "s 1\n" );
for( int j = 0; j < tri.numIndexes; j += 3 )
{
objFile->Printf( "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
tri.indexes[j + 2] + 1 + numVerts,
tri.indexes[j + 2] + 1 + numVerts,
tri.indexes[j + 2] + 1 + numVerts,
tri.indexes[j + 1] + 1 + numVerts,
tri.indexes[j + 1] + 1 + numVerts,
tri.indexes[j + 1] + 1 + numVerts,
tri.indexes[j + 0] + 1 + numVerts,
tri.indexes[j + 0] + 1 + numVerts,
tri.indexes[j + 0] + 1 + numVerts );
}
objFile->Printf( "\n" );
numVerts += tri.numVerts;
}
}
for( int i = 0; i < materials.Num(); i++ )
{
const idMaterial* material = materials[i];
mtlFile->Printf( "newmtl %s\n", material->GetName() );
if( material->GetFastPathDiffuseImage() )
{
idStr path = material->GetFastPathDiffuseImage()->GetName();
path.SlashesToBackSlashes();
path.DefaultFileExtension( ".tga" );
mtlFile->Printf( "\tmap_Kd //..\\..\\..\\%s\n", path.c_str() );
}
else if( material->GetEditorImage() )
{
idStr path = material->GetEditorImage()->GetName();
path.SlashesToBackSlashes();
path.DefaultFileExtension( ".tga" );
mtlFile->Printf( "\tmap_Kd //..\\..\\..\\%s\n", path.c_str() );
}
mtlFile->Printf( "\n" );
}
}
// RB end
/*
================
idRenderModelStatic::LoadModel

View file

@ -172,6 +172,10 @@ public:
virtual void WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp = NULL ) const = 0;
virtual bool SupportsBinaryModel() = 0;
// RB begin
virtual void ExportOBJ( idFile* objFile, idFile* mtlFile, ID_TIME_T* _timeStamp = NULL ) const = 0;
// RB end
// renderBump uses this to load the very high poly count models, skipping the
// shadow and tangent generation, along with some surface cleanup to make it load faster
virtual void PartialInitFromFile( const char* fileName ) = 0;

View file

@ -32,9 +32,13 @@ If you have questions concerning this license or the applicable additional terms
#include "Model_local.h"
#include "tr_local.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
idCVar r_binaryLoadRenderModels( "r_binaryLoadRenderModels", "1", 0, "enable binary load/write of render models" );
idCVar binaryLoadRenderModels( "binaryLoadRenderModels", "1", 0, "enable binary load/write of render models" );
idCVar preload_MapModels( "preload_MapModels", "1", CVAR_SYSTEM | CVAR_BOOL, "preload models during begin or end levelload" );
// RB begin
idCVar postLoadExportModels( "postLoadExportModels", "0", CVAR_BOOL | CVAR_RENDERER, "export models after loading to OBJ model format" );
// RB end
class idRenderModelManagerLocal : public idRenderModelManager
{
public:
@ -305,7 +309,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
// Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical );
if( model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() )
if( model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
{
idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
model->PurgeModel();
@ -372,7 +376,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
if( !model->SupportsBinaryModel() || !r_binaryLoadRenderModels.GetBool() )
if( !model->SupportsBinaryModel() || !binaryLoadRenderModels.GetBool() )
{
model->InitFromFile( canonical );
}
@ -436,6 +440,33 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
fileSystem->AddModelPreload( model->Name() );
}
// RB begin
if( postLoadExportModels.GetBool() && ( model != defaultModel && model != beamModel && model != spriteModel ) )
{
idStrStatic< MAX_OSPATH > exportedFileName;
exportedFileName = "exported/rendermodels/";
exportedFileName.AppendPath( canonical );
exportedFileName.SetFileExtension( ".obj" );
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical );
ID_TIME_T timeStamp = fileSystem->GetTimestamp( exportedFileName );
// TODO only update if generated has changed
//if( timeStamp == FILE_NOT_FOUND_TIMESTAMP )
{
idFileLocal objFile( fileSystem->OpenFileWrite( exportedFileName, "fs_basepath" ) );
idLib::Printf( "Writing %s\n", exportedFileName.c_str() );
exportedFileName.SetFileExtension( ".mtl" );
idFileLocal mtlFile( fileSystem->OpenFileWrite( exportedFileName, "fs_basepath" ) );
model->ExportOBJ( objFile, mtlFile );
}
}
// RB end
AddModel( model );
return model;

View file

@ -57,6 +57,10 @@ public:
return true;
}
// RB begin
virtual void ExportOBJ( idFile* objFile, idFile* mtlFile, ID_TIME_T* _timeStamp = NULL ) const;
// RB end
virtual void PartialInitFromFile( const char* fileName );
virtual void PurgeModel();
virtual void Reset() {};

View file

@ -134,7 +134,7 @@ idRenderModel* idRenderWorldLocal::ReadBinaryModel( idFile* fileIn )
return NULL;
}
extern idCVar r_binaryLoadRenderModels;
extern idCVar binaryLoadRenderModels;
/*
================
@ -298,7 +298,7 @@ idRenderModel* idRenderWorldLocal::ParseModel( idLexer* src, const char* mapName
model->FinishSurfaces();
if( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() )
if( fileOut != NULL && model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
{
model->WriteBinaryModel( fileOut, &mapTimeStamp );
}
@ -398,7 +398,7 @@ idRenderModel* idRenderWorldLocal::ParseShadowModel( idLexer* src, idFile* fileO
// NOTE: we do NOT do a model->FinishSurfaceces, because we don't need sil edges, planes, tangents, etc.
if( fileOut != NULL && model->SupportsBinaryModel() && r_binaryLoadRenderModels.GetBool() )
if( fileOut != NULL && model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
{
model->WriteBinaryModel( fileOut, &mapTimeStamp );
}