mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 22:50:45 +00:00
Merge branch '721-gltf2-cameras' into 705-gltf2-import-options
This commit is contained in:
commit
ad78435446
10 changed files with 353 additions and 114 deletions
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Harrie van Ginneken
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -30,7 +31,10 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#pragma hdrstop
|
||||
|
||||
#include "Game_local.h"
|
||||
#include "gltfParser.h"
|
||||
|
||||
|
||||
static const idMat4 blenderToDoomTransform( idAngles( 0.0f, 0.0f, 90 ).ToMat3(), vec3_origin );
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
|
@ -363,6 +367,10 @@ void idCameraAnim::LoadAnim()
|
|||
int i;
|
||||
idStr filename;
|
||||
const char* key;
|
||||
idStr gltfFileName;
|
||||
int animID = -1;
|
||||
idStr animName;
|
||||
bool isGLTF = false;
|
||||
|
||||
key = spawnArgs.GetString( "anim" );
|
||||
if( !key )
|
||||
|
@ -373,86 +381,102 @@ void idCameraAnim::LoadAnim()
|
|||
filename = spawnArgs.GetString( va( "anim %s", key ) );
|
||||
if( !filename.Length() )
|
||||
{
|
||||
// RB: TrenchBroom interop use anim.<name> instead so we can build this up using the FGD files
|
||||
filename = spawnArgs.GetString( va( "anim.%s", key ) );
|
||||
if( !filename.Length() )
|
||||
gltfFileName = key;
|
||||
gltfManager::ExtractIdentifier( gltfFileName, animID, animName );
|
||||
if( animName.Length() )
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim.%s' key on '%s'", key, name.c_str() );
|
||||
isGLTF = true;
|
||||
}
|
||||
// RB end
|
||||
}
|
||||
|
||||
filename.SetFileExtension( MD5_CAMERA_EXT );
|
||||
if( !parser.LoadFile( filename ) )
|
||||
{
|
||||
gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
|
||||
}
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
|
||||
parser.ExpectTokenString( MD5_VERSION_STRING );
|
||||
version = parser.ParseInt();
|
||||
if( version != MD5_VERSION )
|
||||
{
|
||||
parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
|
||||
}
|
||||
|
||||
// skip the commandline
|
||||
parser.ExpectTokenString( "commandline" );
|
||||
parser.ReadToken( &token );
|
||||
|
||||
// parse num frames
|
||||
parser.ExpectTokenString( "numFrames" );
|
||||
numFrames = parser.ParseInt();
|
||||
if( numFrames <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid number of frames: %d", numFrames );
|
||||
}
|
||||
|
||||
// parse framerate
|
||||
parser.ExpectTokenString( "frameRate" );
|
||||
frameRate = parser.ParseInt();
|
||||
if( frameRate <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid framerate: %d", frameRate );
|
||||
}
|
||||
|
||||
// parse num cuts
|
||||
parser.ExpectTokenString( "numCuts" );
|
||||
numCuts = parser.ParseInt();
|
||||
if( ( numCuts < 0 ) || ( numCuts > numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid number of camera cuts: %d", numCuts );
|
||||
}
|
||||
|
||||
// parse the camera cuts
|
||||
parser.ExpectTokenString( "cuts" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
cameraCuts.SetNum( numCuts );
|
||||
for( i = 0; i < numCuts; i++ )
|
||||
{
|
||||
cameraCuts[ i ] = parser.ParseInt();
|
||||
if( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) )
|
||||
else
|
||||
{
|
||||
parser.Error( "Invalid camera cut" );
|
||||
// RB: TrenchBroom interop use anim.<name> instead so we can build this up using the FGD files
|
||||
filename = spawnArgs.GetString( va( "anim.%s", key ) );
|
||||
if( !filename.Length() )
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim.%s' key on '%s'", key, name.c_str() );
|
||||
}
|
||||
// RB end
|
||||
}
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
|
||||
// parse the camera frames
|
||||
parser.ExpectTokenString( "camera" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
camera.SetNum( numFrames );
|
||||
for( i = 0; i < numFrames; i++ )
|
||||
if( isGLTF )
|
||||
{
|
||||
parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() );
|
||||
parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() );
|
||||
camera[ i ].fov = parser.ParseFloat();
|
||||
gltfLoadAnim( gltfFileName, animName );
|
||||
}
|
||||
else
|
||||
{
|
||||
filename.SetFileExtension( MD5_CAMERA_EXT );
|
||||
if( !parser.LoadFile( filename ) )
|
||||
{
|
||||
gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
|
||||
}
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
|
||||
parser.ExpectTokenString( MD5_VERSION_STRING );
|
||||
version = parser.ParseInt();
|
||||
if( version != MD5_VERSION )
|
||||
{
|
||||
parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
|
||||
}
|
||||
|
||||
// skip the commandline
|
||||
parser.ExpectTokenString( "commandline" );
|
||||
parser.ReadToken( &token );
|
||||
|
||||
// parse num frames
|
||||
parser.ExpectTokenString( "numFrames" );
|
||||
numFrames = parser.ParseInt();
|
||||
if( numFrames <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid number of frames: %d", numFrames );
|
||||
}
|
||||
|
||||
// parse framerate
|
||||
parser.ExpectTokenString( "frameRate" );
|
||||
frameRate = parser.ParseInt();
|
||||
if( frameRate <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid framerate: %d", frameRate );
|
||||
}
|
||||
|
||||
// parse num cuts
|
||||
parser.ExpectTokenString( "numCuts" );
|
||||
numCuts = parser.ParseInt();
|
||||
if( ( numCuts < 0 ) || ( numCuts > numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid number of camera cuts: %d", numCuts );
|
||||
}
|
||||
|
||||
// parse the camera cuts
|
||||
parser.ExpectTokenString( "cuts" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
cameraCuts.SetNum( numCuts );
|
||||
for( i = 0; i < numCuts; i++ )
|
||||
{
|
||||
cameraCuts[i] = parser.ParseInt();
|
||||
if( ( cameraCuts[i] < 1 ) || ( cameraCuts[i] >= numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid camera cut" );
|
||||
}
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
|
||||
// parse the camera frames
|
||||
parser.ExpectTokenString( "camera" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
camera.SetNum( numFrames );
|
||||
for( i = 0; i < numFrames; i++ )
|
||||
{
|
||||
parser.Parse1DMatrix( 3, camera[i].t.ToFloatPtr() );
|
||||
parser.Parse1DMatrix( 3, camera[i].q.ToFloatPtr() );
|
||||
camera[i].fov = parser.ParseFloat();
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -692,6 +716,123 @@ void idCameraAnim::Event_Activate( idEntity* _activator )
|
|||
}
|
||||
}
|
||||
|
||||
void idCameraAnim::gltfLoadAnim( idStr gltfFileName, idStr animName )
|
||||
{
|
||||
//we dont wat to load the gltb all the time. write custom binary format !
|
||||
GLTF_Parser gltf;
|
||||
if( gltf.Load( gltfFileName ) )
|
||||
{
|
||||
ID_TIME_T timeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
gltfData* data = gltf.currentAsset;
|
||||
auto& accessors = data->AccessorList();
|
||||
auto& nodes = data->NodeList();
|
||||
|
||||
gltfNode* cameraNode = data->GetNode( name );
|
||||
assert( cameraNode );
|
||||
|
||||
gltfAnimation* anim = data->GetAnimation( animName, data->GetNodeIndex( cameraNode ) );
|
||||
assert( anim );
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
frameRate = 24;
|
||||
for( auto channel : anim->channels )
|
||||
{
|
||||
auto* sampler = anim->samplers[channel->sampler];
|
||||
auto* input = accessors[sampler->input];
|
||||
auto* output = accessors[sampler->output];
|
||||
auto* target = nodes[channel->target.node];
|
||||
|
||||
idList<float>& timeStamps = data->GetAccessorView( input );
|
||||
int frames = timeStamps.Num();
|
||||
if( !camera.Num() )
|
||||
{
|
||||
cameraFrame_t t;
|
||||
t.fov = 90;
|
||||
t.q = mat3_identity.ToCQuat();
|
||||
t.t = vec3_origin;
|
||||
for( int i = 0; i < frames; i++ )
|
||||
{
|
||||
camera.Alloc() = t;
|
||||
}
|
||||
}
|
||||
//This has to be replaced for correct interpolation between frames
|
||||
for( int i = 0; i < frames; i++ )
|
||||
{
|
||||
cameraFrame_t& cameraFrame = camera[i];
|
||||
|
||||
cameraFrame.fov = 90.0f;
|
||||
switch( channel->target.TRS )
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::none:
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::rotation:
|
||||
{
|
||||
idList<idQuat*>& values = data->GetAccessorView<idQuat>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
|
||||
idQuat q = ( *values[i] );
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat()
|
||||
* q.Inverse()
|
||||
* blenderToDoomTransform.ToMat3().ToQuat();
|
||||
cameraFrame.q = q.ToCQuat();
|
||||
|
||||
//This has to be replaced with correct interpolation between frames.
|
||||
if( ( ( i + 1 ) == frames ) && ( frames < camera.Num() ) )
|
||||
{
|
||||
while( i++ < camera.Num() - 1 )
|
||||
{
|
||||
camera[i].q = cameraFrame.q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::translation:
|
||||
{
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
idVec3 val = *values[i];
|
||||
cameraFrame.t = blenderToDoomTransform * val;
|
||||
|
||||
//This has to be replaced with correct interpolation between frames.
|
||||
if( ( ( i + 1 ) == frames ) && ( frames < camera.Num() ) )
|
||||
{
|
||||
while( i++ < camera.Num() - 1 )
|
||||
{
|
||||
camera[i].t = cameraFrame.t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::scale:
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
gameLocal.Printf( "^5Frame: ^7%i ignored scale on /%s \n\n\n", i, anim->name.c_str() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idCameraAnim::Event_Start
|
||||
|
|
|
@ -131,6 +131,8 @@ private:
|
|||
void Event_Stop();
|
||||
void Event_SetCallback();
|
||||
void Event_Activate( idEntity* activator );
|
||||
|
||||
void gltfLoadAnim( idStr gltfFileName, idStr animName );
|
||||
};
|
||||
|
||||
#endif /* !__GAME_CAMERA_H__ */
|
||||
|
|
|
@ -457,13 +457,15 @@ void ResolveLight( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
|
||||
case gltfExt_KHR_lights_punctual::Spot:
|
||||
{
|
||||
// RB: this code is based on Cmd_TestLight_f which sets the light properties in world space
|
||||
idMat4 entityToWorldTransform = mat4_identity;
|
||||
gltfData::ResolveNodeMatrix( node, &entityToWorldTransform );
|
||||
idMat4 worldToEntityTransform = entityToWorldTransform.Inverse();
|
||||
|
||||
float fov = tan( light->spot.outerConeAngle ) / 2 ;
|
||||
idMat3 axis = idAngles( 0.0f, 90.0f, 90.0f ).ToMat3() * entityToWorldTransform.ToMat3();
|
||||
|
||||
// HarrievG: TODO cleanup this was done by try & error until it worked
|
||||
idQuat q = ( entityToWorldTransform ).ToMat3().ToQuat();
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * idAngles( 180.0f, 180.0f, -90.0f ).ToQuat();
|
||||
idMat3 axis = q.ToMat3();
|
||||
newEntity->epairs.SetVector( "light_target", axis[0] );
|
||||
newEntity->epairs.SetVector( "light_right", axis[1] * -fov );
|
||||
newEntity->epairs.SetVector( "light_up", axis[2] * fov );
|
||||
|
@ -507,10 +509,13 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
newEntity->epairs = newPairs;
|
||||
|
||||
// gather entity transform and bring it into id Tech 4 space
|
||||
gltfData::ResolveNodeMatrix( node );
|
||||
idMat4 entityToWorldTransform = mat4_identity;
|
||||
gltfData::ResolveNodeMatrix( node, &entityToWorldTransform );
|
||||
|
||||
// set entity transform in a way the game and physics code understand it
|
||||
idVec3 origin = blenderToDoomTransform * node->translation;
|
||||
// RB: should be idVec3 origin = ( blenderToDoomTransform * entityToWorldTransform ).GetTranslation();
|
||||
|
||||
newEntity->epairs.SetVector( "origin", origin );
|
||||
|
||||
if( node->extensions.KHR_lights_punctual != nullptr )
|
||||
|
@ -518,12 +523,32 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
ResolveLight( data, newEntity, node );
|
||||
}
|
||||
|
||||
// TODO set rotation key to store rotation and scaling
|
||||
//if (idStr::Icmp(classname, "info_player_start") == 0)
|
||||
// if( !node->matrix.IsIdentity() )
|
||||
//{
|
||||
// newEntity->epairs.SetMatrix("rotation", axis );
|
||||
//}
|
||||
// HarrievG: TODO cleanup this was done by try & error until it worked
|
||||
if( node->camera >= 0 && !newEntity->epairs.FindKey( "rotation" ) )
|
||||
{
|
||||
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
|
||||
}
|
||||
else if( idStr::Icmp( classname, "info_player_start" ) == 0 && !newEntity->epairs.FindKey( "rotation" ) )
|
||||
{
|
||||
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
|
||||
q = idAngles( -90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
|
||||
}
|
||||
else if( node->extras.strPairs.GetBool( "useNodeOrientation", false ) )
|
||||
{
|
||||
//Nodes that are an instance of an collection containing a mesh that is not inline, ea; a gltfModel; static _or_ dynamic,
|
||||
//which has its transformations applied on vertex level so we do not apply it here.
|
||||
origin = blenderToDoomTransform * ( node->translation * ( entityToWorldTransform * node->matrix.Inverse() ) );
|
||||
newEntity->epairs.SetVector( "origin", origin );
|
||||
|
||||
idQuat q = ( entityToWorldTransform * node->matrix.Inverse() ).ToMat3().ToQuat();
|
||||
q = blenderToDoomTransform.Inverse().ToMat3().ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
idMat3 rot = q.ToMat3();
|
||||
//idMat3 rot = ( blenderToDoomTransform * entityToWorldTransform ).ToMat3();
|
||||
newEntity->epairs.SetMatrix( "rotation", rot );
|
||||
}
|
||||
|
||||
#if 0
|
||||
for( int i = 0; i < newEntity->epairs.GetNumKeyVals(); i++ )
|
||||
|
|
|
@ -1150,7 +1150,7 @@ void GLTF_Parser::Shutdown()
|
|||
bufferViewsDone = false;
|
||||
}
|
||||
GLTF_Parser::GLTF_Parser()
|
||||
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ) { }
|
||||
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ), currentAsset( nullptr ) { }
|
||||
|
||||
void GLTF_Parser::Parse_ASSET( idToken& token )
|
||||
{
|
||||
|
|
|
@ -401,11 +401,6 @@ public:
|
|||
{
|
||||
return false;
|
||||
}
|
||||
const idVec3& TotalMovementDelta() const
|
||||
{
|
||||
static idVec3 temp;
|
||||
return temp;
|
||||
}
|
||||
int NumFrames() const
|
||||
{
|
||||
return numFrames;
|
||||
|
|
|
@ -963,6 +963,7 @@ public:
|
|||
// jmarshall
|
||||
idMat3 ToMat3() const;
|
||||
// jmarshall end
|
||||
idVec3 GetTranslation() const;
|
||||
private:
|
||||
idVec4 mat[ 4 ];
|
||||
};
|
||||
|
@ -991,6 +992,19 @@ ID_INLINE idMat3 idMat4::ToMat3() const
|
|||
}
|
||||
// jmarshall end
|
||||
|
||||
// RB begin
|
||||
ID_INLINE idVec3 idMat4::GetTranslation() const
|
||||
{
|
||||
idVec3 pos;
|
||||
|
||||
pos.x = mat[ 0 ][ 3 ];
|
||||
pos.y = mat[ 1 ][ 3 ];
|
||||
pos.z = mat[ 2 ][ 3 ];
|
||||
|
||||
return pos;
|
||||
}
|
||||
// RB end
|
||||
|
||||
ID_INLINE idMat4::idMat4()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -313,8 +313,12 @@ void idRenderModelStatic::InitFromFile( const char* fileName, const idImportOpti
|
|||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
name.ExtractFileExtension( extension );
|
||||
|
||||
if( extension.Icmp( "ase" ) == 0 )
|
||||
if( extension.Icmp( "glb" ) == 0 || extension.Icmp( "gltf" ) == 0 )
|
||||
{
|
||||
loaded = false;
|
||||
reloadable = true;
|
||||
}
|
||||
else if( extension.Icmp( "ase" ) == 0 )
|
||||
{
|
||||
loaded = LoadASE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
|
|
|
@ -292,6 +292,13 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
idStrStatic< MAX_OSPATH > extension;
|
||||
canonical.ExtractFileExtension( extension );
|
||||
|
||||
bool isGLTF = false;
|
||||
// HvG: GLTF 2 support
|
||||
if( ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) )
|
||||
{
|
||||
isGLTF = true;
|
||||
}
|
||||
|
||||
// see if it is already present
|
||||
int key = hash.GenerateKey( canonical, false );
|
||||
for( int i = hash.First( key ); i != -1; i = hash.Next( i ) )
|
||||
|
@ -308,7 +315,22 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) );
|
||||
|
||||
// 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 );
|
||||
|
||||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
if( isGLTF )
|
||||
{
|
||||
idStr gltfFileName = idStr( canonical );
|
||||
int gltfMeshId = -1;
|
||||
idStr gltfMeshName;
|
||||
gltfManager::ExtractIdentifier( gltfFileName, gltfMeshId, gltfMeshName );
|
||||
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( canonical );
|
||||
}
|
||||
|
||||
if( model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
|
||||
{
|
||||
|
@ -316,7 +338,14 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
model->PurgeModel();
|
||||
if( !model->LoadBinaryModel( file, sourceTimeStamp ) )
|
||||
{
|
||||
model->LoadModel();
|
||||
if( isGLTF )
|
||||
{
|
||||
model->InitFromFile( canonical );
|
||||
}
|
||||
else
|
||||
{
|
||||
model->LoadModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -344,7 +373,7 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
idRenderModel* model = NULL;
|
||||
bool isGLTF = false;
|
||||
// HvG: GLTF 2 support
|
||||
if( ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) )
|
||||
if( isGLTF )
|
||||
{
|
||||
model = new( TAG_MODEL ) idRenderModelGLTF;
|
||||
isGLTF = true;
|
||||
|
@ -632,22 +661,42 @@ void idRenderModelManagerLocal::ReloadModels( bool forceAll )
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isGltf = false;
|
||||
idStr name = model->Name();
|
||||
idStr extension;
|
||||
idStr assetName = name;
|
||||
assetName.ExtractFileExtension( extension );
|
||||
isGltf = extension.Icmp( "glb" ) == 0 || extension.Icmp( "gltf" ) == 0;
|
||||
if( !forceAll )
|
||||
{
|
||||
// check timestamp
|
||||
ID_TIME_T current;
|
||||
|
||||
fileSystem->ReadFile( model->Name(), NULL, ¤t );
|
||||
if( isGltf )
|
||||
{
|
||||
idStr meshName;
|
||||
int meshID = -1;
|
||||
gltfManager::ExtractIdentifier( name, meshID, meshName );
|
||||
}
|
||||
|
||||
fileSystem->ReadFile( name, NULL, ¤t );
|
||||
if( current <= model->Timestamp() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
common->DPrintf( "reloading %s.\n", model->Name() );
|
||||
common->DPrintf( "^1Reloading %s.\n", model->Name() );
|
||||
|
||||
if( isGltf )
|
||||
{
|
||||
model->InitFromFile( model->Name() );
|
||||
}
|
||||
else
|
||||
{
|
||||
model->LoadModel();
|
||||
}
|
||||
|
||||
model->LoadModel();
|
||||
}
|
||||
|
||||
// we must force the world to regenerate, because models may
|
||||
|
|
|
@ -150,7 +150,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOption
|
|||
|
||||
//FIXME FIXME FIXME
|
||||
maxJointVertDist = 10;
|
||||
idStr gltfFileName = idStr( fileName );
|
||||
gltfFileName = idStr( fileName );
|
||||
model_state = DM_STATIC;
|
||||
|
||||
gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName );
|
||||
|
@ -163,13 +163,13 @@ void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOption
|
|||
bounds.Clear();
|
||||
|
||||
int sceneId = data->DefaultScene();
|
||||
assert( sceneId >= 0 );
|
||||
idassert( sceneId >= 0 );
|
||||
|
||||
auto scene = data->SceneList()[sceneId];
|
||||
assert( scene );
|
||||
idassert( scene );
|
||||
|
||||
auto nodes = data->NodeList();
|
||||
assert( nodes.Num() );
|
||||
idassert( nodes.Num() );
|
||||
|
||||
//determine root node
|
||||
if( !meshName[0] )
|
||||
|
@ -213,7 +213,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOption
|
|||
if( tmpNode->skin >= 0 )
|
||||
{
|
||||
currentSkin = data->SkinList()[tmpNode->skin];
|
||||
assert( currentSkin );
|
||||
idassert( currentSkin );
|
||||
if( currentSkin->joints.Num() )
|
||||
{
|
||||
bones.Append( currentSkin->joints );
|
||||
|
@ -250,6 +250,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOption
|
|||
{
|
||||
common->Warning( "Couldn't load model: '%s'", name.c_str() );
|
||||
MakeDefaultModel();
|
||||
data = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -257,6 +258,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOption
|
|||
// derive mikktspace tangents from normals
|
||||
FinishSurfaces( true );
|
||||
|
||||
|
||||
LoadModel();
|
||||
UpdateMd5Joints();
|
||||
|
||||
|
@ -272,6 +274,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
|
||||
if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) )
|
||||
{
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -280,6 +283,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
|
||||
if( magic != GLMB_MAGIC )
|
||||
{
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -356,6 +360,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC;
|
||||
|
||||
lastMeshFromFile = this;
|
||||
data = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -368,7 +373,7 @@ const idMD5Joint* idRenderModelGLTF::FindMD5Joint( const idStr& name ) const
|
|||
return &joint;
|
||||
}
|
||||
}
|
||||
assert( 0 );
|
||||
idassert( 0 );
|
||||
static idMD5Joint staticJoint;
|
||||
return &staticJoint;
|
||||
}
|
||||
|
@ -501,7 +506,7 @@ static bool GatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idLis
|
|||
{
|
||||
skin = data->GetSkin( targetNode );
|
||||
}
|
||||
assert( skin );
|
||||
idassert( skin );
|
||||
bones.Append( skin->joints );
|
||||
}
|
||||
else
|
||||
|
@ -599,7 +604,7 @@ static int CopyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>
|
|||
|
||||
idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TIME_T sourceTimeStamp, const idImportOptions* options )
|
||||
{
|
||||
assert( lastMeshFromFile );
|
||||
idassert( lastMeshFromFile );
|
||||
|
||||
//keep in sync with game!
|
||||
static const byte B_ANIM_MD5_VERSION = 101;
|
||||
|
@ -718,7 +723,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TI
|
|||
for( int i = 0; i < numFrames; i++ )
|
||||
{
|
||||
int totalCopied = CopyBones( data, bones, animBones[i] );
|
||||
assert( totalCopied );
|
||||
idassert( totalCopied );
|
||||
}
|
||||
|
||||
gameLocal.Printf( "Total bones %i \n", bones.Num() );
|
||||
|
@ -844,7 +849,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TI
|
|||
}
|
||||
}
|
||||
|
||||
assert( componentFrames.Num() == ( componentFrameIndex + 1 ) );
|
||||
idassert( componentFrames.Num() == ( componentFrameIndex + 1 ) );
|
||||
|
||||
bounds.SetGranularity( 1 );
|
||||
bounds.AssureSize( numFrames );
|
||||
|
@ -1075,6 +1080,7 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /*
|
|||
|
||||
void idRenderModelGLTF::PurgeModel()
|
||||
{
|
||||
idRenderModelStatic::PurgeModel();
|
||||
purged = true;
|
||||
md5joints.Clear();
|
||||
defaultPose.Clear();
|
||||
|
@ -1083,16 +1089,20 @@ void idRenderModelGLTF::PurgeModel()
|
|||
animIds.Clear();
|
||||
bones.Clear();
|
||||
MeshNodeIds.Clear();
|
||||
gltfFileName.Clear();
|
||||
|
||||
//if no root id was set, it is a generated one.
|
||||
if( rootID == -1 && root )
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
void idRenderModelGLTF::LoadModel()
|
||||
{
|
||||
idassert( data );
|
||||
|
||||
int num;
|
||||
auto& accessors = data->AccessorList();
|
||||
auto& nodes = data->NodeList();
|
||||
|
@ -1100,6 +1110,7 @@ void idRenderModelGLTF::LoadModel()
|
|||
if( !fileExclusive )
|
||||
{
|
||||
meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName );
|
||||
idassert( meshRoot );
|
||||
}
|
||||
|
||||
gltfSkin* skin = nullptr;
|
||||
|
@ -1488,9 +1499,6 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
|
|||
if( purged )
|
||||
{
|
||||
common->DWarning( "model %s instantiated while purged", Name() );
|
||||
GLTF_Parser gltf;
|
||||
gltf.Load( name );
|
||||
data = gltf.currentAsset;
|
||||
LoadModel();
|
||||
}
|
||||
|
||||
|
@ -1510,8 +1518,8 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
|
|||
idRenderModelStatic* staticModel;
|
||||
if( cachedModel != NULL )
|
||||
{
|
||||
assert( dynamic_cast< idRenderModelStatic* >( cachedModel ) != NULL );
|
||||
assert( idStr::Icmp( cachedModel->Name(), GLTF_SnapshotName ) == 0 );
|
||||
idassert( dynamic_cast< idRenderModelStatic* >( cachedModel ) != NULL );
|
||||
idassert( idStr::Icmp( cachedModel->Name(), GLTF_SnapshotName ) == 0 );
|
||||
staticModel = static_cast< idRenderModelStatic* >( cachedModel );
|
||||
}
|
||||
else
|
||||
|
@ -1549,7 +1557,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
|
|||
}
|
||||
else
|
||||
{
|
||||
assert( staticModel->numInvertedJoints == numInvertedJoints );
|
||||
idassert( staticModel->numInvertedJoints == numInvertedJoints );
|
||||
}
|
||||
|
||||
TransformJointsFast( staticModel->jointsInverted, md5joints.Num(), ent->joints, invertedDefaultPose.Ptr() );
|
||||
|
@ -1578,7 +1586,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
|
|||
}
|
||||
|
||||
UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf, surfaces[surfIdx++] );
|
||||
assert( surf.geometry != NULL );
|
||||
idassert( surf.geometry != NULL );
|
||||
surf.geometry->staticModelWithJoints = staticModel;
|
||||
staticModel->bounds.AddBounds( surf.geometry->bounds );
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ private:
|
|||
idList<int, TAG_MODEL> MeshNodeIds;
|
||||
dynamicModel_t model_state;
|
||||
idStr meshName;
|
||||
idStr gltfFileName;
|
||||
|
||||
idList<idMD5Joint, TAG_MODEL> md5joints;
|
||||
idList<idJointQuat, TAG_MODEL> defaultPose;
|
||||
|
|
Loading…
Reference in a new issue