Allow static glTF2 models to be inlined in dmap and kicked unused Collada DAE support

This commit is contained in:
Robert Beckebans 2024-06-18 20:33:11 +02:00
parent aab5a4844f
commit c035a5b867
13 changed files with 183 additions and 5054 deletions

View file

@ -37,7 +37,6 @@ If you have questions concerning this license or the applicable additional terms
#include "Model_ase.h"
#include "Model_lwo.h"
#include "Model_ma.h"
#include "Model_ColladaParser.h"
#include "Model_obj.h"
idCVar idRenderModelStatic::r_mergeModelSurfaces( "r_mergeModelSurfaces", "1", CVAR_BOOL | CVAR_RENDERER, "combine model surfaces with the same material" );
@ -266,7 +265,11 @@ void idRenderModelStatic::MakeDefaultModel()
srfTriangles_t* tri = R_AllocStaticTriSurf();
#if defined( DMAP )
surf.shader = declManager->FindMaterial( "_default", false );
#else
surf.shader = tr.defaultMaterial;
#endif
surf.geometry = tri;
R_AllocStaticTriSurfVerts( tri, 24 );
@ -323,12 +326,6 @@ void idRenderModelStatic::InitFromFile( const char* fileName, const idImportOpti
loaded = LoadASE( name, &sourceTimeStamp );
reloadable = true;
}
// RB: Collada DAE and Wavefront OBJ
else if( extension.Icmp( "dae" ) == 0 )
{
loaded = LoadDAE( name, &sourceTimeStamp );
reloadable = true;
}
else if( extension.Icmp( "obj" ) == 0 )
{
loaded = LoadOBJ( name, &sourceTimeStamp );
@ -1332,474 +1329,6 @@ typedef struct matchVert_s
idVec3 normal;
} matchVert_t;
bool idRenderModelStatic::ConvertDAEToModelSurfaces( const ColladaParser* dae )
{
Collada::Node** object;
Collada::Mesh** mesh;
Collada::MeshInstance* meshInstance;
// Collada::Material** material;
const idMaterial* im1, *im2;
srfTriangles_t* tri;
int objectNum;
int i, j, k;
int index, v, tv;
int* vRemap;
int* tvRemap;
matchVert_t* mvTable; // all of the match verts
matchVert_t** mvHash; // points inside mvTable for each xyz index
matchVert_t* lastmv;
matchVert_t* mv;
idVec3 normal;
int* mergeTo;
byte* color;
static byte identityColor[4] = { 255, 255, 255, 255 };
modelSurface_t surf, *modelSurf;
if( dae->mNodeLibrary.Num() < 1 )
{
return false;
}
timeStamp = dae->mReader->getTimestamp();
// the modeling programs can save out multiple surfaces with a common
// material, but we would like to mege them together where possible
// meaning that this->NumSurfaces() <= ase->objects.currentElements
mergeTo = ( int* )_alloca( dae->mNodeLibrary.Num() * sizeof( *mergeTo ) );
surf.geometry = NULL;
if( dae->mMaterialLibrary.Num() == 0 )
{
// if we don't have any materials, dump everything into a single surface
surf.shader = tr.defaultMaterial;
surf.id = 0;
this->AddSurface( surf );
for( i = 0 ; i < dae->mNodeLibrary.Num() ; i++ )
{
mergeTo[i] = 0;
}
}
else if( !r_mergeModelSurfaces.GetBool() )
{
// don't merge any
for( i = 0; i < dae->mNodeLibrary.Num(); i++ )
{
mergeTo[i] = i;
object = dae->mNodeLibrary.GetIndex( i ); //object = ase->objects[i];
if( ( *object )->mMeshes.Num() <= 0 )
{
continue;
}
meshInstance = &( *object )->mMeshes[0]; //mesh = &object->mesh;
idStr matName = "_default";
if( meshInstance->mMaterials.Num() > 0 )
{
matName = meshInstance->mMaterials[ 0 ]; //material = ase->materials[object->materialRef];
matName.Replace( "_", "/" );
matName.StripTrailingOnce( "-material" );
}
surf.shader = declManager->FindMaterial( matName );
surf.id = this->NumSurfaces();
this->AddSurface( surf );
}
}
else
{
// search for material matches
for( i = 0 ; i < dae->mNodeLibrary.Num() ; i++ )
{
object = dae->mNodeLibrary.GetIndex( i );
if( ( *object )->mMeshes.Num() <= 0 )
{
continue;
}
meshInstance = &( *object )->mMeshes[0]; //mesh = &object->mesh;
idStr matName = "_default";
if( meshInstance->mMaterials.Num() > 0 )
{
matName = meshInstance->mMaterials[ 0 ]; //material = ase->materials[object->materialRef];
matName.Replace( "_", "/" );
matName.StripTrailingOnce( "-material" );
}
im1 = declManager->FindMaterial( matName );
if( im1->IsDiscrete() )
{
// flares, autosprites, etc
j = this->NumSurfaces();
}
else
{
for( j = 0 ; j < this->NumSurfaces() ; j++ )
{
modelSurf = &this->surfaces[j];
im2 = modelSurf->shader;
if( im1 == im2 )
{
// merge this
mergeTo[i] = j;
break;
}
}
}
if( j == this->NumSurfaces() )
{
// didn't merge
mergeTo[i] = j;
surf.shader = im1;
surf.id = this->NumSurfaces();
this->AddSurface( surf );
}
}
}
idVectorSubset<idVec3, 3> vertexSubset;
idVectorSubset<idVec2, 2> texCoordSubset;
// build the surfaces
for( objectNum = 0; objectNum < dae->mNodeLibrary.Num(); objectNum++ )
{
object = ( dae->mNodeLibrary.GetIndex( objectNum ) ); //object = ase->objects[objectNum];
if( ( *object )->mMeshes.Num() <= 0 )
{
continue;
}
meshInstance = &( *object )->mMeshes[0]; //mesh = &object->mesh;
idStr matName = "_default";
#if 0
if( meshInstance->mMaterials.Num() )
{
const Collada::SemanticMappingTable* mappingTable = meshInstance->mMaterials.GetIndex( 0 );
idStr materialId = mappingTable->mMatName;
if( dae->mMaterialLibrary.Get( materialId, &material ) )
{
matName = ( *material )->mEffect;
}
}
#else
if( meshInstance->mMaterials.Num() > 0 )
{
matName = meshInstance->mMaterials[ 0 ]; //material = ase->materials[object->materialRef];
matName.Replace( "_", "/" );
matName.StripTrailingOnce( "-material" );
}
#endif
im1 = declManager->FindMaterial( matName );
// It seems like the tools our artists are using often generate
// verts and texcoords slightly separated that should be merged
// note that we really should combine the surfaces with common materials
// before doing this operation, because we can miss a slop combination
// if they are in different surfaces
idStr meshId = ( meshInstance )->mMeshOrController;
dae->mMeshLibrary.Get( meshId, &mesh );
bool normalsParsed = ( * mesh )->mNormals.Num() > 0; //mesh->normalsParsed;
// completely ignore any explict normals on surfaces with a renderbump command
// which will guarantee the best contours and least vertexes.
const char* rb = im1->GetRenderBump();
if( rb && rb[0] )
{
normalsParsed = false;
}
// TODO calculate nodeTransforms recursively using the scene hierarchy
// transform vertex positions and normals
idMat4 nodeTransform = dae->CalculateResultTransform( ( *object )->mTransforms );
// reset origin to zero for root node
if( objectNum == 0 )
{
nodeTransform[0][3] = 0;
nodeTransform[1][3] = 0;
nodeTransform[2][3] = 0;
}
for( j = 0; j < ( *mesh )->mPositions.Num(); j++ )
{
const idVec3& p = ( *mesh )->mPositions[j];
( *mesh )->mPositions[ j ] = nodeTransform * p;
}
for( j = 0; j < ( *mesh )->mNormals.Num(); j++ )
{
const idVec3& n = ( *mesh )->mNormals[j];
idVec4 n2( n.x, n.y, n.z, 0 );
n2 = nodeTransform * n2;
n2.Normalize();
( *mesh )->mNormals[ j ] = n2.ToVec3();
}
vRemap = ( int* )R_StaticAlloc( ( *mesh )->mPositions.Num() * sizeof( vRemap[0] ) );
#if 0
for( j = 0; j < ( *mesh )->mPositions.Num(); j++ )
{
vRemap[j] = j;
}
#else
if( fastLoad )
{
// renderbump doesn't care about vertex count
for( j = 0; j < ( *mesh )->mPositions.Num(); j++ )
{
vRemap[j] = j;
}
}
else
{
float vertexEpsilon = r_slopVertex.GetFloat();
float expand = 2 * 32 * vertexEpsilon;
idVec3 mins, maxs;
SIMDProcessor->MinMax( mins, maxs, &( *mesh )->mPositions[0], ( *mesh )->mPositions.Num() );
mins -= idVec3( expand, expand, expand );
maxs += idVec3( expand, expand, expand );
vertexSubset.Init( mins, maxs, 32, 1024 );
for( j = 0; j < ( *mesh )->mPositions.Num(); j++ )
{
vRemap[j] = vertexSubset.FindVector( &( *mesh )->mPositions[0], j, vertexEpsilon );
}
}
#endif
tvRemap = ( int* )R_StaticAlloc( ( *mesh )->mTexCoords.Num() * sizeof( tvRemap[0] ) );
#if 0
for( j = 0; j < ( *mesh )->mTexCoords.Num(); j++ )
{
tvRemap[j] = j;
}
#else
if( fastLoad )
{
// renderbump doesn't care about vertex count
for( j = 0; j < ( *mesh )->mTexCoords.Num(); j++ )
{
tvRemap[j] = j;
}
}
else
{
float texCoordEpsilon = r_slopTexCoord.GetFloat();
float expand = 2 * 32 * texCoordEpsilon;
idVec2 mins, maxs;
SIMDProcessor->MinMax( mins, maxs, &( *mesh )->mTexCoords[0], ( *mesh )->mTexCoords.Num() );
mins -= idVec2( expand, expand );
maxs += idVec2( expand, expand );
texCoordSubset.Init( mins, maxs, 32, 1024 );
for( j = 0; j < ( *mesh )->mTexCoords.Num(); j++ )
{
tvRemap[j] = texCoordSubset.FindVector( &( *mesh )->mTexCoords[0], j, texCoordEpsilon );
}
}
#endif
// we need to find out how many unique vertex / texcoord combinations
// there are, because ASE tracks them separately but we need them unified
// the maximum possible number of combined vertexes is the number of indexes
mvTable = ( matchVert_t* )R_ClearedStaticAlloc( ( *mesh )->mFacePosIndices.Num() * sizeof( mvTable[0] ) );
// we will have a hash chain based on the xyz values
mvHash = ( matchVert_t** )R_ClearedStaticAlloc( ( *mesh )->mPositions.Num() * sizeof( mvHash[0] ) );
// allocate triangle surface
tri = R_AllocStaticTriSurf();
tri->numVerts = 0;
tri->numIndexes = 0;
R_AllocStaticTriSurfIndexes( tri, ( *mesh )->mFacePosIndices.Num() ); //mesh->numFaces * 3 );
tri->generateNormals = !normalsParsed;
// init default normal, color and tex coord index
normal.Zero();
color = identityColor;
tv = 0;
// find all the unique combinations
float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
for( j = 0; j < ( ( *mesh )->mFacePosIndices.Num() / 3 ); j++ )
//for( j = 0; j < ( *mesh )->mFacePosIndices.Num(); j++ )
{
// construct triangles in reverse order
for( k = 2; k >= 0; k-- )
//for( k = 0; k < 3; k++ )
{
//v = mesh->faces[j].vertexNum[k];
//v = ( *mesh )->mFacePosIndices[j];
index = j * 3 + k;
if( index < 0 || index >= ( *mesh )->mPositions.Num() )
{
common->Error( "ConvertDAEToModelSurfaces: bad vertex index in DAE file %s", name.c_str() );
}
// collapse the position if it was slightly offset
v = vRemap[ index ];
#if 1
// we may or may not have texcoords to compare
//if( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 )
if( ( *mesh )->mTexCoords.Num() )
{
tv = index; //tv = mesh->faces[j].tVertexNum[k];
if( tv < 0 || tv >= ( *mesh )->mTexCoords.Num() )
{
common->Error( "ConvertDAEToModelSurfaces: bad tex coord index in DAE file %s", name.c_str() );
}
// collapse the tex coord if it was slightly offset
tv = tvRemap[tv];
}
// we may or may not have normals to compare
if( normalsParsed )
{
normal = ( *mesh )->mNormals[ index ]; //mesh->faces[j].vertexNormals[k];
}
// we may or may not have colors to compare
if( ( *mesh )->mColors.Num() > 0 )
{
color = ( byte* ) & ( *mesh )->mColors[ index ]; //mesh->faces[j].vertexColors[k];
}
#endif
// find a matching vert
for( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next )
{
#if 1
if( mv->tv != tv )
{
continue;
}
if( *( unsigned* )mv->color != *( unsigned* )color )
{
continue;
}
if( !normalsParsed )
{
// if we are going to create the normals, just
// matching texcoords is enough
break;
}
if( mv->normal * normal > normalEpsilon )
{
break; // we already have this one
}
#endif
}
if( !mv )
{
// allocate a new match vert and link to hash chain
mv = &mvTable[ tri->numVerts ];
mv->v = v;
mv->tv = tv;
mv->normal = normal;
*( unsigned* )mv->color = *( unsigned* )color;
mv->next = NULL;
if( lastmv )
{
lastmv->next = mv;
}
else
{
mvHash[v] = mv;
}
tri->numVerts++;
}
tri->indexes[tri->numIndexes] = mv - mvTable;
tri->numIndexes++;
}
}
// allocate space for the indexes and copy them
if( tri->numIndexes > ( *mesh )->mFacePosIndices.Num() )// mesh->numFaces * 3 )
{
common->FatalError( "ConvertDAEToModelSurfaces: index miscount in DAE file %s", name.c_str() );
}
if( tri->numVerts > ( *mesh )->mFacePosIndices.Num() ) //mesh->numFaces * 3 )
{
common->FatalError( "ConvertDAEToModelSurfaces: vertex miscount in DAE file %s", name.c_str() );
}
// now allocate and generate the combined vertexes
R_AllocStaticTriSurfVerts( tri, tri->numVerts );
for( j = 0; j < tri->numVerts; j++ )
{
mv = &mvTable[j];
tri->verts[ j ].Clear();
tri->verts[ j ].xyz = ( *mesh )->mPositions[ mv->v ];
tri->verts[ j ].SetNormal( mv->normal );
*( unsigned* )tri->verts[j].color = *( unsigned* )mv->color;
if( ( *mesh )->mTexCoords.Num() > 0 )
{
const idVec2& tv = ( *mesh )->mTexCoords[ mv->tv ];
float u = tv.x;
float v = tv.y;
tri->verts[ j ].SetTexCoord( u, v );
}
}
R_StaticFree( mvTable );
R_StaticFree( mvHash );
R_StaticFree( tvRemap );
R_StaticFree( vRemap );
// see if we need to merge with a previous surface of the same material
modelSurf = &this->surfaces[mergeTo[ objectNum ]];
srfTriangles_t* mergeTri = modelSurf->geometry;
if( !mergeTri )
{
modelSurf->geometry = tri;
}
else
{
modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
R_FreeStaticTriSurf( tri );
R_FreeStaticTriSurf( mergeTri );
}
}
return true;
}
/*
=================
idRenderModelStatic::ConvertOBJToModelSurfaces
@ -2206,7 +1735,11 @@ bool idRenderModelStatic::ConvertASEToModelSurfaces( const struct aseModel_s* as
if( ase->materials.Num() == 0 )
{
// if we don't have any materials, dump everything into a single surface
#if defined( DMAP )
surf.shader = declManager->FindMaterial( "_default", false );
#else
surf.shader = tr.defaultMaterial;
#endif
surf.id = 0;
this->AddSurface( surf );
for( i = 0; i < ase->objects.Num(); i++ )
@ -3193,7 +2726,11 @@ bool idRenderModelStatic::ConvertMAToModelSurfaces( const struct maModel_s* ma )
if( ma->materials.Num() == 0 )
{
// if we don't have any materials, dump everything into a single surface
#if defined( DMAP )
surf.shader = declManager->FindMaterial( "_default", false );
#else
surf.shader = tr.defaultMaterial;
#endif
surf.id = 0;
this->AddSurface( surf );
for( i = 0; i < ma->objects.Num(); i++ )
@ -3215,7 +2752,11 @@ bool idRenderModelStatic::ConvertMAToModelSurfaces( const struct maModel_s* ma )
}
else
{
#if defined( DMAP )
surf.shader = declManager->FindMaterial( "_default", false );
#else
surf.shader = tr.defaultMaterial;
#endif
}
surf.id = this->NumSurfaces();
this->AddSurface( surf );
@ -3234,7 +2775,11 @@ bool idRenderModelStatic::ConvertMAToModelSurfaces( const struct maModel_s* ma )
}
else
{
#if defined( DMAP )
im1 = declManager->FindMaterial( "_default", false );
#else
im1 = tr.defaultMaterial;
#endif
}
if( im1->IsDiscrete() )
{
@ -3281,7 +2826,11 @@ bool idRenderModelStatic::ConvertMAToModelSurfaces( const struct maModel_s* ma )
}
else
{
#if defined( DMAP )
im1 = declManager->FindMaterial( "_default", false );
#else
im1 = tr.defaultMaterial;
#endif
}
bool normalsParsed = mesh->normalsParsed;
@ -3608,36 +3157,6 @@ bool idRenderModelStatic::LoadMA( const char* fileName, ID_TIME_T* sourceTimeSta
return true;
}
// RB: added COLLADA support
bool idRenderModelStatic::LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp )
{
bool loaded = false;
#if defined(USE_EXCEPTIONS)
try
#endif
{
idTimer timer;
timer.Start();
ColladaParser parser( fileName, sourceTimeStamp );
loaded = ConvertDAEToModelSurfaces( &parser );
timer.Stop();
common->Printf( "...loaded '%s' in %5.2f seconds\n", fileName, timer.Milliseconds() / 1000.0 );
}
#if defined(USE_EXCEPTIONS)
catch( idException& e )
{
common->Warning( "%s", e.GetError() );
}
#endif
return loaded;
}
/*
=================
idRenderModelStatic::LoadOBJ

View file

@ -30,13 +30,16 @@ If you have questions concerning this license or the applicable additional terms
#include "precompiled.h"
#pragma hdrstop
#include "Model_gltf.h"
#include "Model_local.h"
#include "RenderCommon.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
#include <sys/DeviceManager.h>
#if !defined( DMAP )
#include <sys/DeviceManager.h>
extern DeviceManager* deviceManager;
#endif
extern DeviceManager* deviceManager;
extern idCVar r_vkUploadBufferSizeMB;
idCVar binaryLoadRenderModels( "binaryLoadRenderModels", "1", 0, "enable binary load/write of render models" );
@ -241,6 +244,7 @@ idRenderModelManagerLocal::Init
*/
void idRenderModelManagerLocal::Init()
{
#if !defined( DMAP )
if( !commandList )
{
nvrhi::CommandListParameters params = {};
@ -253,6 +257,7 @@ void idRenderModelManagerLocal::Init()
}
commandList = deviceManager->GetDevice()->createCommandList( params );
}
#endif
cmdSystem->AddCommand( "listModels", ListModels_f, CMD_FL_RENDERER, "lists all models" );
cmdSystem->AddCommand( "printModel", PrintModel_f, CMD_FL_RENDERER, "prints model info", idCmdSystem::ArgCompletion_ModelName );
@ -269,6 +274,7 @@ void idRenderModelManagerLocal::Init()
defaultModel = model;
AddModel( model );
#if !defined( DMAP )
// create the beam model
idRenderModelStatic* beam = new( TAG_MODEL ) idRenderModelBeam;
beam->InitEmpty( "_BEAM" );
@ -281,6 +287,7 @@ void idRenderModelManagerLocal::Init()
sprite->SetLevelLoadReferenced( true );
spriteModel = sprite;
AddModel( sprite );
#endif
}
/*
@ -399,13 +406,14 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
model = new( TAG_MODEL ) idRenderModelGLTF;
isGLTF = true;
}
// RB: Collada DAE and Wavefront OBJ
else if( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "obj" ) == 0 )
// RB: Wavefront OBJ
else if( ( extension.Icmp( "obj" ) == 0 )
|| ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 )
|| ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) )
{
model = new( TAG_MODEL ) idRenderModelStatic;
}
#if !defined( DMAP )
else if( extension.Icmp( MD5_MESH_EXT ) == 0 )
{
model = new( TAG_MODEL ) idRenderModelMD5;
@ -422,6 +430,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
{
model = new( TAG_MODEL ) idRenderModelLiquid;
}
#endif
idStrStatic< MAX_OSPATH > generatedFileName;
@ -477,7 +486,6 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
// Not one of the known formats
if( model == NULL )
{
if( extension.Length() )
{
common->Warning( "unknown model type '%s'", canonical.c_str() );
@ -515,6 +523,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
}
// RB begin
#if !defined( DMAP )
if( postLoadExportModels.GetBool() && ( model != defaultModel && model != beamModel && model != spriteModel ) )
{
idStrStatic< MAX_OSPATH > exportedFileName;
@ -545,6 +554,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
model->ExportOBJ( objFile, mtlFile );
}
}
#endif
// RB end
AddModel( model );
@ -661,6 +671,7 @@ idRenderModelManagerLocal::ReloadModels
*/
void idRenderModelManagerLocal::ReloadModels( bool forceAll )
{
#if !defined( DMAP )
if( forceAll )
{
common->Printf( "Reloading all model files...\n" );
@ -719,12 +730,12 @@ void idRenderModelManagerLocal::ReloadModels( bool forceAll )
{
model->LoadModel();
}
}
// we must force the world to regenerate, because models may
// have changed size, making their references invalid
R_ReCreateWorldReferences();
#endif
}
void idRenderModelManagerLocal::CreateMeshBuffers( nvrhi::ICommandList* commandList )
@ -775,7 +786,9 @@ void idRenderModelManagerLocal::BeginLevelLoad()
model->SetLevelLoadReferenced( false );
}
#if !defined( DMAP )
vertexCache.FreeStaticData();
#endif
}
/*
@ -908,6 +921,7 @@ void idRenderModelManagerLocal::EndLevelLoad()
}
}
#if !defined( DMAP )
commandList->open();
for( int i = 0; i < models.Num(); i++ )
@ -931,6 +945,7 @@ void idRenderModelManagerLocal::EndLevelLoad()
commandList->close();
deviceManager->GetDevice()->executeCommandList( commandList );
#endif
// _D3XP added this
int end = Sys_Milliseconds();

View file

@ -1,623 +0,0 @@
/** Helper structures for the Collada loader */
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2012, assimp team
Copyright (C) 2012 Robert Beckebans (id Tech 4 integration)
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#ifndef __MODEL_COLLADAHELPER_H__
#define __MODEL_COLLADAHELPER_H__
namespace Collada
{
/** Collada file versions which evolved during the years ... */
enum FormatVersion
{
FV_1_5_n,
FV_1_4_n,
FV_1_3_n
};
/** Transformation types that can be applied to a node */
enum TransformType
{
TF_LOOKAT,
TF_ROTATE,
TF_TRANSLATE,
TF_SCALE,
TF_SKEW,
TF_MATRIX
};
/** Different types of input data to a vertex or face */
enum InputType
{
IT_Invalid,
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
IT_Position,
IT_Normal,
IT_Texcoord,
IT_Color,
IT_Tangent,
IT_Bitangent
};
/** Contains all data for one of the different transformation types */
struct Transform
{
idStr mID; ///< SID of the transform step, by which anim channels address their target node
TransformType mType;
float f[16]; ///< Interpretation of data depends on the type of the transformation
};
/** A collada camera. */
struct Camera
{
Camera()
: mOrtho( false )
, mHorFov( 10e10f )
, mVerFov( 10e10f )
, mAspect( 10e10f )
, mZNear( 0.1f )
, mZFar( 1000.f )
{}
// Name of camera
idStr mName;
// True if it is an orthografic camera
bool mOrtho;
//! Horizontal field of view in degrees
float mHorFov;
//! Vertical field of view in degrees
float mVerFov;
//! Screen aspect
float mAspect;
//! Near& far z
float mZNear, mZFar;
};
#define aiLightSource_AMBIENT 0xdeaddead
/** A collada light source. */
struct Light
{
Light()
: mAttConstant( 1.f )
, mAttLinear( 0.f )
, mAttQuadratic( 0.f )
, mFalloffAngle( 180.f )
, mFalloffExponent( 0.f )
, mPenumbraAngle( 10e10f )
, mOuterAngle( 10e10f )
, mIntensity( 1.f )
{}
//! Type of the light source aiLightSourceType + ambient
unsigned int mType;
//! Color of the light
idVec3 mColor;
//! Light attenuation
float mAttConstant, mAttLinear, mAttQuadratic;
//! Spot light falloff
float mFalloffAngle;
float mFalloffExponent;
// -----------------------------------------------------
// FCOLLADA extension from here
//! ... related stuff from maja and max extensions
float mPenumbraAngle;
float mOuterAngle;
//! Common light intensity
float mIntensity;
};
/** Short vertex index description */
struct InputSemanticMapEntry
{
InputSemanticMapEntry()
: mSet( 0 )
{}
//! Index of set, optional
unsigned int mSet;
//! Name of referenced vertex input
InputType mType;
};
/** Table to map from effect to vertex input semantics */
struct SemanticMappingTable
{
//! Name of material
idStr mMatName;
//! List of semantic map commands, grouped by effect semantic name
idHashTable<InputSemanticMapEntry> mMap;
//! For std::find
bool operator == ( const idStr& s ) const
{
return s == mMatName;
}
};
/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
* The ID refers to either a mesh or a controller which specifies the mesh
*/
struct MeshInstance
{
///< ID of the mesh or controller to be instanced
idStr mMeshOrController;
///< Map of materials by the subgroup ID they're applied to
//idHashTable<SemanticMappingTable> mMaterials;
idStrList mMaterials;
};
/** A reference to a camera inside a node*/
struct CameraInstance
{
///< ID of the camera
idStr mCamera;
};
/** A reference to a light inside a node*/
struct LightInstance
{
///< ID of the camera
idStr mLight;
};
/** A reference to a node inside a node*/
struct NodeInstance
{
///< ID of the node
idStr mNode;
};
/** A node in a scene hierarchy */
struct Node
{
idStr mName;
idStr mID;
idStr mSID;
Node* mParent;
idList<Node*> mChildren;
/** Operations in order to calculate the resulting transformation to parent. */
idList<Transform> mTransforms;
/** Meshes at this node */
idList<MeshInstance> mMeshes;
/** Lights at this node */
idList<LightInstance> mLights;
/** Cameras at this node */
idList<CameraInstance> mCameras;
/** Node instances at this node */
idList<NodeInstance> mNodeInstances;
/** Rootnodes: Name of primary camera, if any */
idStr mPrimaryCamera;
//! Constructor. Begin with a zero parent
Node()
{
mParent = NULL;
}
//! Destructor: delete all children subsequently
~Node()
{
//mChildren.DeleteContents( false );
}
};
/** Data source array: either floats or strings */
struct Data
{
bool mIsStringArray;
idList<float> mValues;
idList<idStr> mStrings;
};
/** Accessor to a data array */
struct Accessor
{
size_t mCount; // in number of objects
size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
size_t mOffset; // in number of values
size_t mStride; // Stride in number of values
idList<idStr> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
idStr mSource; // URL of the source array
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
Accessor()
{
mCount = 0;
mSize = 0;
mOffset = 0;
mStride = 0;
mData = NULL;
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
}
};
/** A single face in a mesh */
struct Face
{
idList<size_t> mIndices;
};
/** An input channel for mesh data, referring to a single accessor */
struct InputChannel
{
InputType mType; // Type of the data
size_t mIndex; // Optional index, if multiple sets of the same data type are given
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
idStr mAccessor; // ID of the accessor where to read the actual values from.
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
InputChannel()
{
mType = IT_Invalid;
mIndex = 0;
mOffset = 0;
mResolved = NULL;
}
};
/** Subset of a mesh with a certain material */
struct SubMesh
{
idStr mMaterial; ///< subgroup identifier
size_t mNumFaces; ///< number of faces in this submesh
};
/** Contains data for a single mesh */
struct Mesh
{
Mesh()
{
//for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
// mNumUVComponents[i] = 2;
}
// just to check if there's some sophisticated addressing involved...
// which we don't support, and therefore should warn about.
idStr mVertexID;
// Vertex data addressed by vertex indices
idList<InputChannel> mPerVertexData;
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
idList<idVec3> mPositions;
idList<idVec3> mNormals;
idList<idVec3> mTangents;
idList<idVec3> mBitangents;
idList<idVec2> mTexCoords;
idList<dword> mColors;
//unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
// Faces. Stored are only the number of vertices for each face.
// 1 == point, 2 == line, 3 == triangle, 4+ == poly
idList<int> mFaceSize;
// Position indices for all faces in the sequence given in mFaceSize -
// necessary for bone weight assignment
idList<int> mFacePosIndices;
// Submeshes in this mesh, each with a given material
idList<SubMesh> mSubMeshes;
};
/** Which type of primitives the ReadPrimitives() function is going to read */
enum PrimitiveType
{
Prim_Invalid,
Prim_Lines,
Prim_LineStrip,
Prim_Triangles,
Prim_TriStrips,
Prim_TriFans,
Prim_Polylist,
Prim_Polygon
};
struct WeightPair
{
size_t jointIndex;
size_t weightIndex;
};
/** A skeleton controller to deform a mesh with the use of joints */
struct Controller
{
// the URL of the mesh deformed by the controller.
idStr mMeshId;
// accessor URL of the joint names
idStr mJointNameSource;
///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases
float mBindShapeMatrix[16];
// accessor URL of the joint inverse bind matrices
idStr mJointOffsetMatrixSource;
// input channel: joint names.
InputChannel mWeightInputJoints;
// input channel: joint weights
InputChannel mWeightInputWeights;
// Number of weights per vertex.
idList<size_t> mWeightCounts;
// JointIndex-WeightIndex pairs for all vertices
idList< WeightPair > mWeights;
};
/** A collada material. Pretty much the only member is a reference to an effect. */
struct Material
{
idStr mEffect;
};
/** Type of the effect param */
enum ParamType
{
Param_Sampler,
Param_Surface
};
/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
struct EffectParam
{
ParamType mType;
idStr mReference; // to which other thing the param is referring to.
};
/** Shading type supported by the standard effect spec of Collada */
enum ShadeType
{
Shade_Invalid,
Shade_Constant,
Shade_Lambert,
Shade_Phong,
Shade_Blinn
};
/** Represents a texture sampler in collada */
struct Sampler
{
Sampler()
: mWrapU( true )
, mWrapV( true )
, mMirrorU()
, mMirrorV()
//, mOp( aiTextureOp_Multiply )
//, mUVId( UINT_MAX )
, mWeighting( 1.f )
, mMixWithPrevious( 1.f )
{}
/** Name of image reference
*/
idStr mName;
/** Wrap U?
*/
bool mWrapU;
/** Wrap V?
*/
bool mWrapV;
/** Mirror U?
*/
bool mMirrorU;
/** Mirror V?
*/
bool mMirrorV;
/** Blend mode
*/
//aiTextureOp mOp;
/** UV transformation
*/
//aiUVTransform mTransform;
/** Name of source UV channel
*/
//idStr mUVChannel;
/** Resolved UV channel index or UINT_MAX if not known
*/
unsigned int mUVId;
// OKINO/MAX3D extensions from here
// -------------------------------------------------------
/** Weighting factor
*/
float mWeighting;
/** Mixing factor from OKINO
*/
float mMixWithPrevious;
};
/** A collada effect. Can contain about anything according to the Collada spec,
but we limit our version to a reasonable subset. */
struct Effect
{
// Shading mode
ShadeType mShadeType;
// Colors
idVec4 mEmissive, mAmbient, mDiffuse, mSpecular,
mTransparent, mReflective;
// Textures
Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
mTexTransparent, mTexBump, mTexReflective;
// Scalar factory
float mShininess, mRefractIndex, mReflectivity;
float mTransparency;
// local params referring to each other by their SID
typedef idHashTable<Collada::EffectParam> ParamLibrary;
ParamLibrary mParams;
// MAX3D extensions
// ---------------------------------------------------------
// Double-sided?
bool mDoubleSided, mWireframe, mFaceted;
Effect()
: mShadeType( Shade_Phong )
, mEmissive( 0, 0, 0, 1 )
, mAmbient( 0.1f, 0.1f, 0.1f, 1 )
, mDiffuse( 0.6f, 0.6f, 0.6f, 1 )
, mSpecular( 0.4f, 0.4f, 0.4f, 1 )
, mTransparent( 0, 0, 0, 1 )
, mShininess( 10.0f )
, mRefractIndex( 1.f )
, mReflectivity( 1.f )
, mTransparency( 0.f )
, mDoubleSided( false )
, mWireframe( false )
, mFaceted( false )
{
}
};
/** An image, meaning texture */
struct Image
{
idStr mFileName;
/** If image file name is zero, embedded image data
*/
idList<uint8_t> mImageData;
/** If image file name is zero, file format of
* embedded image data.
*/
idStr mEmbeddedFormat;
};
/** An animation channel. */
struct AnimationChannel
{
/** URL of the data to animate. Could be about anything, but we support only the
* "NodeID/TransformID.SubElement" notation
*/
idStr mTarget;
/** Source URL of the time values. Collada calls them "input". Meh. */
idStr mSourceTimes;
/** Source URL of the value values. Collada calls them "output". */
idStr mSourceValues;
};
/** An animation. Container for 0-x animation channels or 0-x animations */
struct Animation
{
/** Anim name */
idStr mName;
/** the animation channels, if any */
idList<AnimationChannel> mChannels;
/** the sub-animations, if any */
idList<Animation*> mSubAnims;
/** Destructor */
~Animation()
{
mSubAnims.DeleteContents( false );
}
};
/** Description of a collada animation channel which has been determined to affect the current node */
struct ChannelEntry
{
const Collada::AnimationChannel* mChannel; ///> the source channel
idStr mTransformId; // the ID of the transformation step of the node which is influenced
size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
size_t mSubElement; // starting index inside the transform data
// resolved data references
const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
const Collada::Data* mTimeData; ///> Source data array for the time values
const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
const Collada::Data* mValueData; ///> Source datat array for the key value values
ChannelEntry()
{
mChannel = NULL;
mSubElement = 0;
}
};
} // end of namespace Collada
#endif // __MODEL_COLLADAHELPER_H__

File diff suppressed because it is too large Load diff

View file

@ -1,357 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2012, assimp team
Copyright (C) 2012 Robert Beckebans (id Tech 4 integration)
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/** @file ColladaParser.h
* @brief Defines the parser helper class for the collada loader
*/
#ifndef __MODEL_COLLADAPARSER_H__
#define __MODEL_COLLADAPARSER_H__
#include "../libs/irrxml/src/irrXML.h"
#include "Model_ColladaHelper.h"
// ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader.
*
* Does all the XML reading and builds internal data structures from it,
* but leaves the resolving of all the references to the loader.
*/
class ColladaParser
{
friend class ColladaLoader;
friend class idRenderModelStatic;
protected:
/** Constructor from XML file */
ColladaParser( const char* pFile, ID_TIME_T* sourceTimeStamp );
/** Destructor */
~ColladaParser();
/** Reads the contents of the file */
void ReadContents();
/** Reads the structure of the file */
void ReadStructure();
/** Reads asset informations such as coordinate system informations and legal blah */
void ReadAssetInfo();
/** Reads the animation library */
// void ReadAnimationLibrary();
/** Reads an animation into the given parent structure */
// void ReadAnimation( Collada::Animation* pParent );
/** Reads an animation sampler into the given anim channel */
// void ReadAnimationSampler( Collada::AnimationChannel& pChannel );
/** Reads the skeleton controller library */
// void ReadControllerLibrary();
/** Reads a controller into the given mesh structure */
// void ReadController( Collada::Controller& pController );
/** Reads the joint definitions for the given controller */
// void ReadControllerJoints( Collada::Controller& pController );
/** Reads the joint weights for the given controller */
// void ReadControllerWeights( Collada::Controller& pController );
/** Reads the image library contents */
// void ReadImageLibrary();
/** Reads an image entry into the given image */
// void ReadImage( Collada::Image& pImage );
/** Reads the material library */
void ReadMaterialLibrary();
/** Reads a material entry into the given material */
void ReadMaterial( Collada::Material& pMaterial );
/** Reads the camera library */
// void ReadCameraLibrary();
/** Reads a camera entry into the given camera */
// void ReadCamera( Collada::Camera& pCamera );
/** Reads the light library */
// void ReadLightLibrary();
/** Reads a light entry into the given light */
// void ReadLight( Collada::Light& pLight );
/** Reads the effect library */
// void ReadEffectLibrary();
/** Reads an effect entry into the given effect*/
// void ReadEffect( Collada::Effect& pEffect );
/** Reads an COMMON effect profile */
// void ReadEffectProfileCommon( Collada::Effect& pEffect );
/** Read sampler properties */
// void ReadSamplerProperties( Collada::Sampler& pSampler );
/** Reads an effect entry containing a color or a texture defining that color */
// void ReadEffectColor( idVec4& pColor, Collada::Sampler& pSampler );
/** Reads an effect entry containing a float */
// void ReadEffectFloat( float& pFloat );
/** Reads an effect parameter specification of any kind */
// void ReadEffectParam( Collada::EffectParam& pParam );
/** Reads the geometry library contents */
void ReadGeometryLibrary();
/** Reads a geometry from the geometry library. */
void ReadGeometry( Collada::Mesh* pMesh );
/** Reads a mesh from the geometry library */
void ReadMesh( Collada::Mesh* pMesh );
/** Reads a source element - a combination of raw data and an accessor defining
* things that should not be redefinable. Yes, that's another rant.
*/
void ReadSource();
/** Reads a data array holding a number of elements, and stores it in the global library.
* Currently supported are array of floats and arrays of strings.
*/
void ReadDataArray();
/** Reads an accessor and stores it in the global library under the given ID -
* accessors use the ID of the parent <source> element
*/
void ReadAccessor( const idStr& pID );
/** Reads input declarations of per-vertex mesh data into the given mesh */
void ReadVertexData( Collada::Mesh* pMesh );
/** Reads input declarations of per-index mesh data into the given mesh */
void ReadIndexData( Collada::Mesh* pMesh );
/** Reads a single input channel element and stores it in the given array, if valid */
void ReadInputChannel( idList<Collada::InputChannel>& poChannels );
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
void ReadPrimitives( Collada::Mesh* pMesh, idList<Collada::InputChannel>& pPerIndexChannels,
size_t pNumPrimitives, const idList<size_t>& pVCount, Collada::PrimitiveType pPrimType );
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh );
/** Reads the library of node hierarchies and scene parts */
void ReadSceneLibrary();
/** Reads a scene node's contents including children and stores it in the given node */
void ReadSceneNode( Collada::Node* pNode );
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType );
/** Reads a mesh reference in a node and adds it to the node's mesh list */
void ReadNodeGeometry( Collada::Node* pNode );
/** Reads the collada scene */
void ReadScene();
// Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl );
protected:
/** Aborts the file reading with an exception */
void ThrowException( const idStr& pError ) const;
/** Skips all data until the end node of the current element */
void SkipElement();
/** Skips all data until the end node of the given element */
void SkipElement( const char* pElement );
bool SkipSpacesAndLineEnd( const char* in, const char** out );
/** Compares the current xml element name to the given string and returns true if equal */
bool IsElement( const char* pName ) const;
/** Tests for the opening tag of the given element, throws an exception if not found */
void TestOpening( const char* pName );
/** Tests for the closing tag of the given element, throws an exception if not found */
void TestClosing( const char* pName );
/** Checks the present element for the presence of the attribute, returns its index
or throws an exception if not found */
int GetAttribute( const char* pAttr ) const;
/** Returns the index of the named attribute or -1 if not found. Does not throw,
therefore useful for optional attributes */
int TestAttribute( const char* pAttr ) const;
/** Reads the text contents of an element, throws an exception if not given.
Skips leading whitespace. */
const char* GetTextContent();
/** Reads the text contents of an element, returns NULL if not given.
Skips leading whitespace. */
const char* TestTextContent();
/** Reads a single bool from current text content */
bool ReadBoolFromTextContent();
/** Reads a single float from current text content */
float ReadFloatFromTextContent();
/** Calculates the resulting transformation from all the given transform steps */
idMat4 CalculateResultTransform( const idList<Collada::Transform>& pTransforms ) const;
/** Determines the input data type for the given semantic string */
Collada::InputType GetTypeForSemantic( const idStr& pSemantic );
/** Finds the item in the given library by its reference, throws if not found */
template <typename Type> const Type* ResolveLibraryReference(
const idHashTable<Type>& pLibrary, const idStr& pURL ) const;
protected:
/** Filename, for a verbose error message */
idStr mFileName;
/** XML reader, member for everyday use */
irr::io::IrrXMLReader* mReader;
/** All data arrays found in the file by ID. Might be referred to by actually
everyone. Collada, you are a steaming pile of indirection. */
typedef idHashTable<Collada::Data*> DataLibrary;
DataLibrary mDataLibrary;
/** Same for accessors which define how the data in a data array is accessed. */
typedef idHashTable<Collada::Accessor*> AccessorLibrary;
AccessorLibrary mAccessorLibrary;
/** Mesh library: mesh by ID */
typedef idHashTable<Collada::Mesh*> MeshLibrary;
MeshLibrary mMeshLibrary;
/** node library: root node of the hierarchy part by ID */
typedef idHashTable<Collada::Node*> NodeLibrary;
NodeLibrary mNodeLibrary;
/** Image library: stores texture properties by ID */
typedef idHashTable<Collada::Image*> ImageLibrary;
ImageLibrary mImageLibrary;
/** Effect library: surface attributes by ID */
typedef idHashTable<Collada::Effect*> EffectLibrary;
EffectLibrary mEffectLibrary;
/** Material library: surface material by ID */
typedef idHashTable<Collada::Material*> MaterialLibrary;
MaterialLibrary mMaterialLibrary;
/** Light library: surface light by ID */
typedef idHashTable<Collada::Light*> LightLibrary;
LightLibrary mLightLibrary;
/** Camera library: surface material by ID */
typedef idHashTable<Collada::Camera*> CameraLibrary;
CameraLibrary mCameraLibrary;
/** Controller library: joint controllers by ID */
typedef idHashTable<Collada::Controller*> ControllerLibrary;
ControllerLibrary mControllerLibrary;
/** Pointer to the root node. Don't delete, it just points to one of
the nodes in the node library. */
Collada::Node* mRootNode;
/** Root animation container */
Collada::Animation mAnims;
/** Size unit: how large compared to a meter */
float mUnitSize;
/** Which is the up vector */
enum { UP_X, UP_Y, UP_Z } mUpDirection;
/** Collada file format version */
Collada::FormatVersion mFormat;
};
// ------------------------------------------------------------------------------------------------
// Check for element match
inline bool ColladaParser::IsElement( const char* pName ) const
{
assert( mReader->getNodeType() == irr::io::EXN_ELEMENT );
return idStr::Cmp( mReader->getNodeName(), pName ) == 0;
}
inline bool ColladaParser::SkipSpacesAndLineEnd( const char* in, const char** out )
{
while( *in == ' ' || *in == '\t' || *in == '\r' || *in == '\n' )
{
in++;
}
*out = in;
return *in != '\0';
}
// ------------------------------------------------------------------------------------------------
// Finds the item in the given library by its reference, throws if not found
template <typename Type>
const Type* ColladaParser::ResolveLibraryReference( const idHashTable<Type>& pLibrary, const idStr& pURL ) const
{
Type* element = NULL;
if( !pLibrary.Get( pURL, &element ) )
{
ThrowException( va( "Unable to resolve library reference \"%s\".", pURL.c_str() ) );
}
return element;
}
#endif // __MODEL_COLLADAPARSER_H__

View file

@ -36,8 +36,12 @@ If you have questions concerning this license or the applicable additional terms
#include "RenderCommon.h"
// HVG_TODO: this has to be moved out before release
#include "d3xp/anim/Anim.h"
#include "d3xp/Game_local.h"
#if !defined( DMAP )
#include "d3xp/anim/Anim.h"
#include "d3xp/Game_local.h"
#endif
idCVar r_useCachedDynamicModels( "r_useCachedDynamicModels", "1", CVAR_RENDERER | CVAR_BOOL, "cache snapshots of dynamic models" );
idCVar gltf_ForceBspMeshTexture( "gltf_ForceBspMeshTexture", "0", CVAR_SYSTEM | CVAR_BOOL, "all world geometry has the same forced texture" );
idCVar gltf_ModelSceneName( "gltf_ModelSceneName", "Scene", CVAR_SYSTEM , "Scene to use when loading specific models" );
@ -875,6 +879,7 @@ void idRenderModelGLTF::UpdateMd5Joints()
void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view )
{
#if !defined( DMAP )
int i;
int num;
idVec3 pos;
@ -918,78 +923,7 @@ void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const view
common->RW()->DrawText( md5joints[i].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
}
}
}
static bool GatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, idList<int, TAG_MODEL>& bones, idList<jointAnimInfo_t, TAG_MD5_ANIM>& jointInfo , gltfSkin* skin, const idImportOptions* options )
{
bool boneLess = false;
int targetNode = lastMeshFromFile->GetRootID();
auto targets = data->GetAnimTargets( gltfAnim );
auto& nodeList = data->NodeList();
if( skin == nullptr )
{
boneLess = true;
}
// we cant be sure channels are sorted by bone?
if( !boneLess )
{
if( skin == nullptr )
{
skin = data->GetSkin( targetNode );
}
assert( skin );
// armature node is origin/root bone
//bones.Append( skin->skeleton );
// skeleton bones
bones.Append( skin->joints );
}
else
{
bones.Append( targetNode );
}
if( options )
{
if( options->keepjoints.Num() )
{
KeepNodes( data, options->keepjoints, bones );
}
if( options->addOrigin )
{
gltfNode* armatureNode = data->NodeList()[bones[0]]->parent;
AddOriginBone( data, bones, armatureNode );
}
if( options->remapjoints.Num() )
{
RemapNodes( data, options->remapjoints, bones );
}
if( options->renamejoints.Num() )
{
RenameNodes( data, options->renamejoints, bones );
}
}
// create jointInfo
jointInfo.SetGranularity( 1 );
jointInfo.SetNum( bones.Num() );
int idx = 0;
for( auto& joint : jointInfo )
{
joint.animBits = ~63;
joint.firstComponent = -1;
const char* name = nodeList[bones[idx++]]->name.c_str();
joint.nameIndex = animationLib.JointIndex( name );
}
return boneLess;
#endif
}
static idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat, const idMat4& globalTransform )
@ -1071,6 +1005,80 @@ static int CopyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>
return out.Num();
}
#if !defined( DMAP )
static bool GatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, idList<int, TAG_MODEL>& bones, idList<jointAnimInfo_t, TAG_MD5_ANIM>& jointInfo , gltfSkin* skin, const idImportOptions* options )
{
bool boneLess = false;
int targetNode = lastMeshFromFile->GetRootID();
auto targets = data->GetAnimTargets( gltfAnim );
auto& nodeList = data->NodeList();
if( skin == nullptr )
{
boneLess = true;
}
// we cant be sure channels are sorted by bone?
if( !boneLess )
{
if( skin == nullptr )
{
skin = data->GetSkin( targetNode );
}
assert( skin );
// armature node is origin/root bone
//bones.Append( skin->skeleton );
// skeleton bones
bones.Append( skin->joints );
}
else
{
bones.Append( targetNode );
}
if( options )
{
if( options->keepjoints.Num() )
{
KeepNodes( data, options->keepjoints, bones );
}
if( options->addOrigin )
{
gltfNode* armatureNode = data->NodeList()[bones[0]]->parent;
AddOriginBone( data, bones, armatureNode );
}
if( options->remapjoints.Num() )
{
RemapNodes( data, options->remapjoints, bones );
}
if( options->renamejoints.Num() )
{
RenameNodes( data, options->renamejoints, bones );
}
}
// create jointInfo
jointInfo.SetGranularity( 1 );
jointInfo.SetNum( bones.Num() );
int idx = 0;
for( auto& joint : jointInfo )
{
joint.animBits = ~63;
joint.firstComponent = -1;
const char* name = nodeList[bones[idx++]]->name.c_str();
joint.nameIndex = animationLib.JointIndex( name );
}
return boneLess;
}
idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TIME_T sourceTimeStamp, const idImportOptions* options )
{
assert( lastMeshFromFile );
@ -1620,6 +1628,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TI
return file;
}
#endif // #if !defined( DMAP )
void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /*= NULL */ ) const
{
idRenderModelStatic::WriteBinaryModel( file , _timeStamp );
@ -1881,6 +1891,7 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i
idList<int> jointIds;
#if !defined( DMAP )
if( r_useGPUSkinning.GetBool() )
{
if( tri->verts != NULL && tri->verts != verts )
@ -1892,6 +1903,7 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i
tri->referencedVerts = true;
}
else
#endif
{
if( tri->verts == NULL || tri->verts == verts )
{
@ -2058,6 +2070,9 @@ static void TransformJointsFast( idJointMat* __restrict outJoints, const int num
idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEntity_s* ent, const viewDef_t* view, idRenderModel* cachedModel )
{
#if defined( DMAP )
return NULL;
#else
if( cachedModel != NULL && !r_useCachedDynamicModels.GetBool() )
{
delete cachedModel;
@ -2099,6 +2114,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
staticModel->bounds.Clear();
#if !defined( DMAP )
if( r_showSkel.GetInteger() )
{
if( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) )
@ -2114,6 +2130,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
return staticModel;
}
}
#endif
// update the GPU joints array
const int numInvertedJoints = SIMD_ROUND_JOINTS( md5joints.Num() );
@ -2160,6 +2177,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
}
return staticModel;
#endif
}
int idRenderModelGLTF::NumJoints() const

View file

@ -120,10 +120,8 @@ public:
bool LoadASE( const char* fileName, ID_TIME_T* sourceTimeStamp );
bool LoadLWO( const char* fileName, ID_TIME_T* sourceTimeStamp );
bool LoadMA( const char* filename, ID_TIME_T* sourceTimeStamp );
bool LoadDAE( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
bool LoadOBJ( const char* fileName, ID_TIME_T* sourceTimeStamp ); // RB
bool ConvertDAEToModelSurfaces( const ColladaParser* dae ); // RB
bool ConvertOBJToModelSurfaces( const objModel_t* obj ); // RB
bool ConvertASEToModelSurfaces( const struct aseModel_s* ase );
bool ConvertLWOToModelSurfaces( const struct st_lwObject* lwo );
@ -168,6 +166,9 @@ protected:
static idCVar r_slopNormal; // merge normals that dot less than this
};
#if !defined( DMAP )
/*
===============================================================================
@ -558,4 +559,6 @@ public:
};
};
#endif // #if !defined( DMAP )
#endif /* !__MODEL_LOCAL_H__ */

View file

@ -99,7 +99,7 @@ idCVar r_checkBounds( "r_checkBounds", "0", CVAR_RENDERER | CVAR_BOOL, "compare
idCVar r_useNodeCommonChildren( "r_useNodeCommonChildren", "1", CVAR_RENDERER | CVAR_BOOL, "stop pushing reference bounds early when possible" );
idCVar r_useShadowSurfaceScissor( "r_useShadowSurfaceScissor", "1", CVAR_RENDERER | CVAR_BOOL, "scissor shadows by the scissor rect of the interaction surfaces" );
idCVar r_useCachedDynamicModels( "r_useCachedDynamicModels", "1", CVAR_RENDERER | CVAR_BOOL, "cache snapshots of dynamic models" );
idCVar r_maxAnisotropicFiltering( "r_maxAnisotropicFiltering", "8", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "limit aniso filtering" );
idCVar r_useTrilinearFiltering( "r_useTrilinearFiltering", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Extra quality filtering" );
// RB: not used anymore

View file

@ -2604,7 +2604,6 @@ R_RemapShaderBySkin
*/
const idMaterial* R_RemapShaderBySkin( const idMaterial* shader, const idDeclSkin* skin, const idMaterial* customShader )
{
if( !shader )
{
return NULL;

View file

@ -47,7 +47,14 @@ set(BSPT_RENDERER_INCLUDES
../../renderer/Color/ColorSpace.h
../../renderer/Image.h
../../renderer/Material.h
../../renderer/VertexCache.h
#../../renderer/VertexCache.h
../../renderer/ModelManager.h
../../renderer/Model.h
../../renderer/Model_gltf.h
../../renderer/Model_ase.h
../../renderer/Model_lwo.h
../../renderer/Model_ma.h
../../renderer/Model_obj.h
)
set(BSPT_RENDERER_SOURCES
../../renderer/BinaryImage.cpp
@ -65,6 +72,14 @@ set(BSPT_RENDERER_SOURCES
../../renderer/Material.cpp
../../renderer/tr_trisurf.cpp
#../../renderer/VertexCache.cpp
../../renderer/ModelManager.cpp
../../renderer/Model.cpp
../../renderer/Model_gltf.cpp
#../../renderer/Model_md5.cpp
../../renderer/Model_ase.cpp
../../renderer/Model_lwo.cpp
../../renderer/Model_ma.cpp
../../renderer/Model_obj.cpp
)
file(GLOB MIKKTSPACE_INCLUDES ../../libs/mikktspace/*.h)

View file

@ -30,7 +30,7 @@ If you have questions concerning this license or the applicable additional terms
#include "../../../renderer/RenderCommon.h"
// DMAP TODO
#define DMAP_INLINE_MODELS 0
#define DMAP_INLINE_MODELS 1
typedef struct primitive_s
{

View file

@ -342,5 +342,15 @@ void R_FreeLightDefDerivedData( idRenderLightLocal* ldef )
ldef->references = NULL;
}
/*
===================
R_CheckForEntityDefsUsingModel
===================
*/
void R_CheckForEntityDefsUsingModel( idRenderModel* model )
{
// STUB
}
#endif

View file

@ -675,14 +675,23 @@ void FixGlobalTjunctions( uEntity_t* e )
{
continue;
}
const char* modelName = entity->mapEntity->epairs.GetString( "model" );
if( !modelName )
idStrStatic< MAX_OSPATH > modelName = entity->mapEntity->epairs.GetString( "model" );
if( modelName.IsEmpty() )
{
continue;
}
// RB: DAE and OBJ support
if( !strstr( modelName, ".lwo" ) && !strstr( modelName, ".ase" ) && !strstr( modelName, ".ma" ) && !strstr( modelName, ".dae" ) && !strstr( modelName, ".obj" ) )
idStrStatic< MAX_OSPATH > extension;
modelName.ExtractFileExtension( extension );
// RB: glTF2 and OBJ support
bool isGLTF = false;
if( ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) )
{
isGLTF = true;
}
if( !isGLTF && !strstr( modelName, ".lwo" ) && !strstr( modelName, ".ase" ) && !strstr( modelName, ".ma" ) && !strstr( modelName, ".obj" ) )
{
continue;
}