- removed global gltfParser so it cannot be used as an singleton anymore.

- fixed destruction and cleanup of gltfData and gltfParser
- gltfParser always fixes up skeletonID's for skins that do not have it set.
- fixed gltfData::GetAnimation to also check for duplicates taking multple targets for the same animation into account.
- several boneless animation fixes
[!] [ BUG WARNING ] Be aware -> for some reason models/meshes that use multple textures are not drawn correctly; ATM onlt single texure users are correct.
This commit is contained in:
HarrievG 2022-08-14 13:43:12 +02:00
parent ecaf297ef6
commit 486315c7e7
7 changed files with 179 additions and 53 deletions

View file

@ -1674,8 +1674,9 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
}
else if( isGTLF )
{
gltfParser->Load( fullName );
idMapEntity::GetEntities( gltfParser->currentAsset, entities, gltfParser->currentAsset->GetSceneId( gltf_MapSceneName.GetString() ) );
GLTF_Parser gltf;
gltf.Load( fullName );
idMapEntity::GetEntities( gltf.currentAsset, entities, gltf.currentAsset->GetSceneId( gltf_MapSceneName.GetString() ) );
}
else
{

View file

@ -55,6 +55,8 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p
idFile_Memory idxBin = idFile_Memory( "gltfChunkIndices",
( const char* )( ( data->GetData( bv->buffer ) + bv->byteOffset + accessor->byteOffset ) ), bv->byteLength );
for( int i = 0; i < accessor->count; i++ )
{
idxBin.Read( ( void* )( &indices[i] ), accessor->typeSize );
@ -64,9 +66,15 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p
}
}
int polyCount = accessor->count /3;
mesh->polygons.AssureSize(polyCount );
mesh->polygons.SetNum( polyCount );
int cnt = 0;
for( int i = 0; i < accessor->count; i += 3 )
{
MapPolygon& polygon = mesh->polygons.Alloc();
MapPolygon& polygon = mesh->polygons[cnt++];
if( mat != NULL )
{
@ -82,6 +90,8 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p
polygon.AddIndex( indices[i + 0] );
}
assert(cnt == polyCount );
Mem_Free( indices );
bool sizeSet = false;
@ -273,9 +283,9 @@ void ProcessSceneNode( idMapEntity* newEntity, gltfNode* node, idMat4 trans, glt
ProcessSceneNode( newEntity, nodeList[child], curTrans, data, isFuncStaticMesh );
}
if( isFuncStaticMesh && node->mesh != -1 )
if( node->mesh != -1 )
{
for( auto prim : data->MeshList()[node->mesh]->primitives )
for( auto* prim : data->MeshList()[node->mesh]->primitives )
{
newEntity->AddPrimitive( MapPolygonMesh::ConvertFromMeshGltf( prim, data , curTrans ) );
}

View file

@ -1135,8 +1135,14 @@ void gltfItem_texture_info_extensions::parse( idToken& token )
void GLTF_Parser::Shutdown()
{
parser.FreeSource();
currentFile.FreeData();
if( currentAsset )
{
delete currentAsset;
}
currentAsset = nullptr;
buffersDone = false;
bufferViewsDone = false;
}
GLTF_Parser::GLTF_Parser()
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ) { }
@ -1914,6 +1920,12 @@ gltfProperty GLTF_Parser::ResolveProp( idToken& token )
bool GLTF_Parser::loadGLB( idStr filename )
{
if( fileSystem->GetFileLength( filename ) <= 0 )
{
common->Warning( " %s does not exist!", filename.c_str() );
return false;
}
idFile* file = fileSystem->OpenFileRead( filename );
if( file->Length() < 20 )
@ -1959,7 +1971,6 @@ bool GLTF_Parser::loadGLB( idStr filename )
length -= file->ReadUnsignedInt( chunk_type );
data = dataCache->AddData( chunk_length );
dataCache->FileName( filename );
int read = file->Read( ( void* )data, chunk_length );
if( read != chunk_length )
@ -2076,12 +2087,12 @@ bool GLTF_Parser::Load( idStr filename )
{
//.. and destroy data !!
gltfData* data = gltfData::Data( filename );
currentFile = filename;
if( data != nullptr )
{
currentAsset = data;
parser.FreeSource();
return true;
}
@ -2102,7 +2113,6 @@ bool GLTF_Parser::Load( idStr filename )
}
data = gltfData::Data( filename , true );
data->FileName( filename );
byte* dataBuff = data->AddData( length );
currentAsset = data;
@ -2134,18 +2144,29 @@ bool GLTF_Parser::Load( idStr filename )
//fix up node hierarchy
auto& nodeList = currentAsset->NodeList();
for( auto& scene : currentAsset->SceneList() )
{
for( auto& node : scene->nodes )
{
SetNodeParent( nodeList[node] );
}
}
//set skeleton ID's
for( auto* skin : currentAsset->SkinList() )
{
if( skin->skeleton == -1 )
{
skin->skeleton = currentAsset->GetNodeIndex( currentAsset->GetNode( skin->name ) );
}
}
//prefix with id
if( gltfParser_PrefixNodeWithID.GetBool() )
{
for( int i = 0; i < nodeList.Num(); i++ )
{
nodeList[i]->name = "[" + idStr( i ) + "]" + nodeList[i]->name;
}
}
//CreateBgfxData();
return true;
}
@ -2284,20 +2305,45 @@ idList<idQuat*>& gltfData::GetAccessorView( gltfAccessor* accessor )
gltfData::~gltfData()
{
//hvg_todo
//delete data, not only pointer
common->Warning( "GLTF DATA NOT FREED" );
if( data )
{
delete[] data;
while( totalChunks )
{
Mem_Free( data[--totalChunks] );
}
Mem_Free( data );
}
//delete cameraManager;
if( json )
{
Mem_Free( json );
}
data = nullptr;
json = nullptr;
ClearData( fileName );
}
void gltfData::ClearData( idStr& fileName )
{
int key = fileDataHash.GenerateKey( fileName );
int index = fileDataHash.GetFirst( key );
if( index != -1 )
{
dataList.RemoveIndex( index );
dataList.Condense();
fileDataHash.RemoveIndex( key, index );
}
else
{
common->DWarning( " tried to clear GLTF data while no data was loaded for %s", fileName.c_str( ) );
}
}
GLTF_Parser localGltfParser;
GLTF_Parser* gltfParser = &localGltfParser;
#undef GLTFARRAYITEM
#undef GLTFARRAYITEMREF
@ -2307,7 +2353,8 @@ CONSOLE_COMMAND_COMPILE( LoadGLTF, "Loads an .gltf or .glb file", idCmdSystem::A
if( args.Argc() > 1 )
{
gltfParser->Load( args.Argv( 1 ) );
GLTF_Parser gltf;
gltf.Load( args.Argv( 1 ) );
}
}

View file

@ -303,6 +303,10 @@ private:
class GLTF_Parser
{
public:
~GLTF_Parser()
{
Shutdown();
}
GLTF_Parser();
void Shutdown();
bool Parse();
@ -350,6 +354,4 @@ class gltfManager
{
public:
static bool ExtractIdentifier( idStr& filename , int& id, idStr& name );
};
extern GLTF_Parser* gltfParser;
};

View file

@ -765,7 +765,7 @@ const inline idList<gltf##name*> & ##name##List() { return target; }
class gltfData
{
public:
gltfData() : fileNameHash( 0 ), json( nullptr ), data( nullptr ), totalChunks( -1 ) { };
gltfData() : fileName( "" ), fileNameHash( 0 ), json( nullptr ), data( nullptr ), totalChunks( -1 ) { };
~gltfData();
byte* AddData( int size, int* bufferID = nullptr );
byte* GetJsonData( int& size )
@ -777,10 +777,10 @@ public:
{
return data[index];
}
void FileName( const idStr& file )
void FileName( const idStr& file, int hash )
{
fileName = file;
fileNameHash = fileDataHash.GenerateKey( file.c_str() );
fileNameHash = hash;
}
int FileNameHash()
{
@ -796,6 +796,12 @@ public:
//add data for filename
static gltfData* Data( idStr& fileName, bool create = false )
{
static bool intialized = false;
if( ! intialized )
{
dataList.SetGranularity( 1 );
intialized = true;
}
int key = fileDataHash.GenerateKey( fileName );
int index = fileDataHash.GetFirst( key );
@ -803,8 +809,8 @@ public:
{
index = dataList.Num( );
dataList.AssureSizeAlloc( index + 1, idListNewElement<gltfData> );
dataList[index]->FileName( fileName );
fileDataHash.Add( fileDataHash.GenerateKey( fileName ), index );
dataList[index]->FileName( fileName, key );
fileDataHash.Add( key , index );
}
if( !create && index < 0 )
@ -818,10 +824,8 @@ public:
{
return dataList;
}
static void ClearData()
{
idLib::Warning( "TODO! DATA NOT FREED" );
}
static void ClearData( idStr& fileName );
//return the GLTF nodes that control the given camera
//return TRUE if the camera uses 2 nodes (like when blender exports gltfs with +Y..)
@ -909,6 +913,29 @@ public:
return nullptr;
}
gltfNode* GetNode( idStr name, int* id = nullptr, bool caseSensitive = false )
{
assert( name[0] );
auto& nodeList = NodeList();
for( auto* node : nodes )
{
int nodeId = GetNodeIndex( node );
if( caseSensitive ? nodes[nodeId]->name.Cmp( name ) : nodes[nodeId]->name.Icmp( name ) == 0 )
{
if( id != nullptr )
{
*id = nodeId;
}
return nodes[nodeId];
}
}
return nullptr;
}
gltfNode* GetNode( idStr sceneName, idStr name , int* id = nullptr , bool caseSensitive = false )
{
int sceneId = GetSceneId( sceneName );
@ -968,13 +995,25 @@ public:
return false;
}
gltfAnimation* GetAnimation( idStr animName )
gltfAnimation* GetAnimation( idStr animName, int target )
{
for( auto anim : animations )
for( auto* anim : animations )
{
if( anim->name == animName )
{
return anim;
bool hasTarget = false;
for( auto* channel : anim->channels )
{
if( channel->target.node == target )
{
hasTarget = true;
break;
}
}
if( hasTarget )
{
return anim;
}
}
}
return nullptr;

View file

@ -163,10 +163,11 @@ void idRenderModelGLTF::InitFromFile( const char* fileName )
model_state = DM_STATIC;
gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName );
gltfParser->Load( gltfFileName );
GLTF_Parser gltf;
gltf.Load( gltfFileName );
timeStamp = fileSystem->GetTimestamp( gltfFileName );
data = gltfParser->currentAsset;
data = gltf.currentAsset;
bounds.Clear();
@ -228,8 +229,9 @@ void idRenderModelGLTF::InitFromFile( const char* fileName )
animCount = data->GetAnimationIds( nodes[bones[0]] , animIds );
}
}
else if( animCount )
else
{
animCount = data->GetAnimationIds( tmpNode , animIds );
bones.Append( meshID );
}
@ -241,7 +243,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName )
ProcessNode( root, mat4_identity, data );
if( surfaces.Num( ) <= 0 || surfaces.Num( ) != MeshNodeIds.Num( ) )
if( surfaces.Num( ) <= 0 )
{
common->Warning( "Couldn't load model: '%s'", name.c_str( ) );
MakeDefaultModel( );
@ -479,15 +481,14 @@ bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfN
{
//Gather Bones;
bool boneLess = false;
int targetNode = -1;
int targetNode = lastMeshFromFile->rootID;
auto skin = data->GetSkin( gltfAnim );
auto targets = data->GetAnimTargets( gltfAnim );
if( targets.Num( ) == 1 )
if( skin == nullptr )
{
boneLess = true;
targetNode = targets[0];
}
//we cant be sure channels are sorted by bone?
@ -495,7 +496,7 @@ bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfN
{
if( skin == nullptr )
{
skin = data->GetSkin( targets[0] );
skin = data->GetSkin( targetNode );
}
assert( skin );
bones.Append( skin->joints );
@ -594,27 +595,34 @@ int copyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>& out )
idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T sourceTimeStamp )
{
assert( lastMeshFromFile );
///keep in sync with game!
static const byte B_ANIM_MD5_VERSION = 101;
static const unsigned int B_ANIM_MD5_MAGIC = ( 'B' << 24 ) | ( 'M' << 16 ) | ( 'D' << 8 ) | B_ANIM_MD5_VERSION;
GLTF_Parser gltf;
int id;
idStr gltfFileName = idStr( animName );
idStr name;
gltfManager::ExtractIdentifier( gltfFileName, id, name );
gltfParser->Load( gltfFileName );
gltf.Load( gltfFileName );
gltfData* data = gltfParser->currentAsset;
gltfData* data = gltf.currentAsset;
auto& accessors = data->AccessorList( );
auto& nodes = data->NodeList( );
auto gltfAnim = data->GetAnimation( name );
gltfNode* nodeRoot = nodes[lastMeshFromFile->rootID];
int boneRootNode = lastMeshFromFile->rootID;
if( nodeRoot->skin > -1 )
{
boneRootNode = nodes[data->SkinList()[nodeRoot->skin]->skeleton]->children[0];
}
auto gltfAnim = data->GetAnimation( name, boneRootNode );
if( !gltfAnim )
{
return nullptr;
}
auto& accessors = data->AccessorList( );
auto& nodes = data->NodeList( );
idList<int, TAG_MODEL> bones;
idList<jointAnimInfo_t, TAG_MD5_ANIM> jointInfo;
@ -637,6 +645,11 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
int channelCount = 0;
for( auto channel : gltfAnim->channels )
{
if( !bones.Find( channel->target.node ) )
{
continue;
}
auto* sampler = gltfAnim->samplers[channel->sampler];
auto* input = accessors[sampler->input];
@ -729,6 +742,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
skin->joints.AssureSize( 1, data->GetNodeIndex( root ) );
idMat4 trans = mat4_identity;
data->ResolveNodeMatrix( root, &trans );
trans *= axisTransform.Inverse();
acc = new gltfAccessor( );
acc->matView = new idList<idMat4>( 1 );
acc->matView->AssureSize( 1, trans.Inverse( ).Transpose( ) );
@ -744,6 +758,11 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
{
for( auto channel : gltfAnim->channels )
{
if( !bones.Find( channel->target.node ) )
{
continue;
}
auto sampler = gltfAnim->samplers[channel->sampler];
auto* input = accessors[sampler->input];
@ -778,7 +797,10 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
break;
case gltfAnimation_Channel_Target::scale:
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
animBones[i][boneIndex].scale = *values[i] ;
if( values.Num( ) > i )
{
animBones[i][boneIndex].scale = *values[i] ;
}
break;
}
}
@ -807,6 +829,10 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
if( node->parent == nullptr )
{
q = axisTransformAngels.ToQuat( ) * animBones[i][b].rotation;
if( animBones[i].Num() == 1 )
{
q = -animBones[i][b].rotation;
}
}
else
{
@ -1009,7 +1035,7 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /*
file->WriteBig( GLMB_MAGIC );
file->WriteBig( model_state );
file->WriteBig( rootID );
file->WriteString( data->FileName() );
file->WriteString( file->GetName() );
file->WriteBig( animIds.Num( ) );
if( animIds.Num( ) )
@ -1073,8 +1099,6 @@ void idRenderModelGLTF::PurgeModel()
void idRenderModelGLTF::LoadModel()
{
int num;
gltfData* data = gltfParser->currentAsset;
auto& accessors = data->AccessorList( );
auto& nodes = data->NodeList( );
gltfNode* meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName );
@ -1481,6 +1505,9 @@ 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();
}

View file

@ -55,11 +55,11 @@ public:
return true;
}
static idFile_Memory* GetAnimBin( idStr animName, const ID_TIME_T sourceTimeStamp );
int rootID;
private:
void ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData* data );
void UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf );
void UpdateMd5Joints();
int rootID;
gltfData* data;
gltfNode* root;
bool fileExclusive;