From edf657f50d6be5adcd7fc5719969e01950c872b1 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 10 Jul 2022 21:09:25 +0200 Subject: [PATCH 01/16] - Initial GLTF Animation Implementation. For now only supports boneless TRS animations without scale. ![only works with r_UseGpuSkinning 0]! - Writes bmd5anim for each animation. its not perfect yet but, rot + trans looks good. - Model tag supports gltf Animations. Indexed the same way as meshes. - Enabled weights and bone index in ConvertFromMeshGltf --- neo/cm/CollisionModel_files.cpp | 2 +- neo/cm/CollisionModel_load.cpp | 2 +- neo/d3xp/anim/Anim.cpp | 47 +- neo/d3xp/anim/Anim_Blend.cpp | 2 +- neo/idlib/MapFile_gltf.cpp | 68 +- neo/idlib/gltfParser.cpp | 18 +- neo/idlib/gltfParser.h | 2 +- neo/idlib/gltfProperties.h | 61 ++ neo/renderer/Model_gltf.cpp | 1312 ++++++++++++++++++++++++++----- neo/renderer/Model_gltf.h | 37 +- 10 files changed, 1314 insertions(+), 237 deletions(-) diff --git a/neo/cm/CollisionModel_files.cpp b/neo/cm/CollisionModel_files.cpp index e3418945..636f5376 100644 --- a/neo/cm/CollisionModel_files.cpp +++ b/neo/cm/CollisionModel_files.cpp @@ -633,7 +633,7 @@ bool idCollisionModelManagerLocal::LoadCollisionModelFile( const char* name, uns int id; idStr tmp; idStr file = fileName; - gltfManager::ExtractMeshIdentifier( file, id, tmp ); + gltfManager::ExtractIdentifier( file, id, tmp ); currentTimeStamp = fileSystem->GetTimestamp( file ); } diff --git a/neo/cm/CollisionModel_load.cpp b/neo/cm/CollisionModel_load.cpp index 26f86ee1..a8930ff9 100644 --- a/neo/cm/CollisionModel_load.cpp +++ b/neo/cm/CollisionModel_load.cpp @@ -4574,7 +4574,7 @@ cmHandle_t idCollisionModelManagerLocal::LoadModel( const char* modelName, const int id; idStr tmp; idStr file = modelName; - gltfManager::ExtractMeshIdentifier( file, id, tmp ); + gltfManager::ExtractIdentifier( file, id, tmp ); sourceTimeStamp = fileSystem->GetTimestamp( file ); } diff --git a/neo/d3xp/anim/Anim.cpp b/neo/d3xp/anim/Anim.cpp index e116d0d1..031d3204 100644 --- a/neo/d3xp/anim/Anim.cpp +++ b/neo/d3xp/anim/Anim.cpp @@ -31,6 +31,8 @@ If you have questions concerning this license or the applicable additional terms #include "../Game_local.h" +//should go before release? +#include "renderer/Model_gltf.h" idCVar binaryLoadAnim( "binaryLoadAnim", "1", 0, "enable binary load/write of idMD5Anim" ); @@ -177,18 +179,47 @@ idMD5Anim::LoadAnim */ bool idMD5Anim::LoadAnim( const char* filename ) { - idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT ); idToken token; + idStr extension; + idStr filenameStr = idStr( filename ); + filenameStr.ExtractFileExtension( extension ); idStr generatedFileName = "generated/anim/"; generatedFileName.AppendPath( filename ); generatedFileName.SetFileExtension( ".bMD5anim" ); - // 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( filename ); + idStr gltfFileName = idStr( filename ); + int gltfAnimId = -1; + idStr gltfAnimName; + + + // Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it + ID_TIME_T sourceTimeStamp; + + bool isGLTF = ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) ; + + if( isGLTF ) + { + gltfManager::ExtractIdentifier( gltfFileName, gltfAnimId, gltfAnimName ); + + sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName ); + } + else + { + sourceTimeStamp = fileSystem->GetTimestamp( filename ); + } + + idFile* fileptr = fileSystem->OpenFileReadMemory( generatedFileName ); + bool doWrite = false; + if( fileptr == nullptr && isGLTF ) + { + fileptr = idRenderModelGLTF::GetAnimBin( filenameStr , sourceTimeStamp ); + doWrite = fileptr != nullptr; + } + + idFileLocal file( fileptr ); - idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) ); if( binaryLoadAnim.GetBool() && LoadBinary( file, sourceTimeStamp ) ) { name = filename; @@ -197,6 +228,14 @@ bool idMD5Anim::LoadAnim( const char* filename ) // for resource gathering write this anim to the preload file for this map fileSystem->AddAnimPreload( name ); } + if( doWrite && binaryLoadAnim.GetBool( ) ) + { + idLib::Printf( "Writing %s\n", generatedFileName.c_str( ) ); + fileptr->Seek( 0, FS_SEEK_SET ); + idFile_Memory* memFile = static_cast( fileptr ); + fileSystem->WriteFile( generatedFileName, memFile->GetDataPtr(), memFile->GetAllocated(), "fs_basepath" ); + } + return true; } diff --git a/neo/d3xp/anim/Anim_Blend.cpp b/neo/d3xp/anim/Anim_Blend.cpp index ac0798f2..6d1d7c24 100644 --- a/neo/d3xp/anim/Anim_Blend.cpp +++ b/neo/d3xp/anim/Anim_Blend.cpp @@ -3361,7 +3361,7 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi // get the number of joints num = modelHandle->NumJoints(); - if( !num ) + if( !num && !isGltf ) { src.Warning( "Model '%s' has no joints", filename.c_str() ); } diff --git a/neo/idlib/MapFile_gltf.cpp b/neo/idlib/MapFile_gltf.cpp index 8f1960c5..46d48157 100644 --- a/neo/idlib/MapFile_gltf.cpp +++ b/neo/idlib/MapFile_gltf.cpp @@ -204,30 +204,50 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p } break; } - //case gltfMesh_Primitive_Attribute::Type::Weight: - //{ - // for ( int i = 0; i < attrAcc->count; i++ ) { - // bin.Read( ( void * ) ( &vtxData[i].weight.x ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].weight.y ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].weight.z ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].weight.w ), attrAcc->typeSize ); - // if ( attrBv->byteStride ) - // bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); - // } - // break; - //} - //case gltfMesh_Primitive_Attribute::Type::Indices: - //{ - // for ( int i = 0; i < attrAcc->count; i++ ) { - // bin.Read( ( void * ) ( &vtxData[i].boneIndex.x ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].boneIndex.y ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].boneIndex.z ), attrAcc->typeSize ); - // bin.Read( ( void * ) ( &vtxData[i].boneIndex.w ), attrAcc->typeSize ); - // if ( attrBv->byteStride ) - // bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); - // } - // break; - //} + case gltfMesh_Primitive_Attribute::Type::Weight: + { + idVec4 vec; + for( int i = 0; i < attrAcc->count; i++ ) + { + bin.Read( ( void* )( &vec.x ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.y ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.z ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.w ), attrAcc->typeSize ); + if( attrBv->byteStride ) + { + bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); + } + + mesh->verts[i].color2[0] = vec.x; + mesh->verts[i].color2[1] = vec.y; + mesh->verts[i].color2[2] = vec.z; + mesh->verts[i].color2[3] = vec.w; + + } + break; + } + case gltfMesh_Primitive_Attribute::Type::Indices: + { + idVec4 vec; + for( int i = 0; i < attrAcc->count; i++ ) + { + bin.Read( ( void* )( &vec.x ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.y ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.z ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec.w ), attrAcc->typeSize ); + if( attrBv->byteStride ) + { + bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); + } + + mesh->verts[i].color[0] = vec.x; + mesh->verts[i].color[1] = vec.y; + mesh->verts[i].color[2] = vec.z; + mesh->verts[i].color[3] = vec.w; + } + break; + + } } } diff --git a/neo/idlib/gltfParser.cpp b/neo/idlib/gltfParser.cpp index d80dd118..41f582c8 100644 --- a/neo/idlib/gltfParser.cpp +++ b/neo/idlib/gltfParser.cpp @@ -2319,38 +2319,38 @@ CONSOLE_COMMAND_COMPILE( LoadGLTF, "Loads an .gltf or .glb file", idCmdSystem::A // not dots allowed in [%s]! // [filename].[%i|%s].[gltf/glb] -bool gltfManager::ExtractMeshIdentifier( idStr& filename, int& meshId, idStr& meshName ) +bool gltfManager::ExtractIdentifier( idStr& filename, int& id, idStr& name ) { idStr extension; - idStr meshStr; + idStr targetStr; filename.ExtractFileExtension( extension ); idStr file = filename; file = file.StripFileExtension(); - file.ExtractFileExtension( meshStr ); + file.ExtractFileExtension( targetStr ); if( !extension.Length() ) { - idLib::Warning( "no gltf mesh identifier" ); + idLib::Warning( "no gltf identifier" ); return false; } - if( meshStr.Length() ) + if( targetStr.Length() ) { - filename = file.Left( file.Length() - meshStr.Length() - 1 ) + "." + extension; + filename = file.Left( file.Length() - targetStr.Length() - 1 ) + "." + extension; idParser parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS ); - parser.LoadMemory( meshStr.c_str(), meshStr.Size(), "model:GltfmeshID" ); + parser.LoadMemory( targetStr.c_str(), targetStr.Size(), "model:GltfID" ); idToken token; if( parser.ExpectAnyToken( &token ) ) { if( ( token.type == TT_NUMBER ) && ( token.subtype & TT_INTEGER ) ) { - meshId = token.GetIntValue(); + id = token.GetIntValue(); } else if( token.type == TT_NAME ) { - meshName = token; + name = token; } else { diff --git a/neo/idlib/gltfParser.h b/neo/idlib/gltfParser.h index 1d7e25a3..690b6a56 100644 --- a/neo/idlib/gltfParser.h +++ b/neo/idlib/gltfParser.h @@ -349,7 +349,7 @@ private: class gltfManager { public: - static bool ExtractMeshIdentifier( idStr& filename , int& meshId, idStr& meshName ); + static bool ExtractIdentifier( idStr& filename , int& id, idStr& name ); }; extern GLTF_Parser* gltfParser; \ No newline at end of file diff --git a/neo/idlib/gltfProperties.h b/neo/idlib/gltfProperties.h index 3eff84c3..fa01d141 100644 --- a/neo/idlib/gltfProperties.h +++ b/neo/idlib/gltfProperties.h @@ -943,6 +943,20 @@ public: return nullptr; } + int GetNodeIndex( gltfNode* node ) + { + int index = -1; + for( auto* node : nodes ) + { + index++; + if( node == node ) + { + return index; + } + } + return -1; + } + bool HasAnimation( int nodeID ) { for( auto anim : animations ) @@ -958,6 +972,18 @@ public: return false; } + gltfAnimation* GetAnimation( idStr animName ) + { + for( auto anim : animations ) + { + if( anim->name == animName ) + { + return anim; + } + } + return nullptr; + } + int GetSceneId( idStr sceneName ) const { for( int i = 0; i < scenes.Num(); i++ ) @@ -970,6 +996,41 @@ public: return -1; } + idList GetChannelIds( gltfAnimation* anim , gltfNode* node ) + { + idList result; + int channelIdx = 0; + for( auto channel : anim->channels ) + { + if( channel->target.node >= 0 && nodes[channel->target.node] == node ) + { + result.Append( channelIdx ); + break; + } + channelIdx++; + } + return result; + } + + idList GetAnimationIds( gltfNode* node ) + { + idList result; + int animIdx = 0; + for( auto anim : animations ) + { + for( auto channel : anim->channels ) + { + if( channel->target.node >= 0 && nodes[channel->target.node] == node ) + { + result.Append( animIdx ); + break; + } + } + animIdx++; + } + return result; + } + idMat4 GetViewMatrix( int camId ) const { //if (cameraManager->HasOverideID(camId) ) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 95322a85..7041edd9 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -35,14 +35,21 @@ If you have questions concerning this license or the applicable additional terms #include "Model_local.h" #include "RenderCommon.h" +//HVG_TODO: this has to be moved out before release +#include "d3xp/anim/Anim.h" +#include "d3xp/Game_local.h" + idCVar gltf_ForceBspMeshTexture( "gltf_ForceBspMeshTexture", "0", CVAR_SYSTEM | CVAR_BOOL, "all world geometry has the same forced texture" ); idCVar gltf_ModelSceneName( "gltf_ModelSceneName", "models", CVAR_SYSTEM , "Scene to use when loading specific models" ); +idCVar gltf_AnimSampleRate( "gltf_AnimSampleRate", "24", CVAR_SYSTEM | CVAR_INTEGER , "The frame rate of the converted md5anim" ); + static const byte GLMB_VERSION = 100; static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << 8 ) | GLMB_VERSION; static const char* GLTF_SnapshotName = "_GLTF_Snapshot_"; + bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh ) { return false; @@ -53,18 +60,6 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData auto& meshList = data->MeshList( ); auto& nodeList = data->NodeList( ); - //find all animations - for( auto anim : data->AnimationList( ) ) - { - for( auto channel : anim->channels ) - { - if( channel->target.node >= 0 && nodeList[channel->target.node] == modelNode ) - { - animIds.Alloc( ) = channel->target.node; - } - } - } - gltfData::ResolveNodeMatrix( modelNode ); idMat4 curTrans = trans * modelNode->matrix; @@ -73,17 +68,21 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData { gltfMesh* targetMesh = meshList[modelNode->mesh]; - idMat4 newTrans = mat4_identity; + idMat4 newTrans; if( !animIds.Num() ) { newTrans = curTrans; } + else + { + newTrans = modelNode->matrix; + } for( auto prim : targetMesh->primitives ) { //ConvertFromMeshGltf should only be used for the map, ConvertGltfMeshToModelsurfaces should be used. - auto* newMesh = MapPolygonMesh::ConvertFromMeshGltf( prim, data, newTrans ); + auto* mesh = MapPolygonMesh::ConvertFromMeshGltf( prim, data, newTrans ); modelSurface_t surf; gltfMaterial* mat = NULL; @@ -102,16 +101,16 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData surf.id = this->NumSurfaces( ); srfTriangles_t* tri = R_AllocStaticTriSurf( ); - tri->numIndexes = newMesh->GetNumPolygons( ) * 3; - tri->numVerts = newMesh->GetNumVertices( ); + tri->numIndexes = mesh->GetNumPolygons( ) * 3; + tri->numVerts = mesh->GetNumVertices( ); R_AllocStaticTriSurfIndexes( tri, tri->numIndexes ); R_AllocStaticTriSurfVerts( tri, tri->numVerts ); int indx = 0; - for( int i = 0; i < newMesh->GetNumPolygons( ); i++ ) + for( int i = 0; i < mesh->GetNumPolygons( ); i++ ) { - auto& face = newMesh->GetFace( i ); + auto& face = mesh->GetFace( i ); auto& faceIdxs = face.GetIndexes( ); tri->indexes[indx] = faceIdxs[0]; tri->indexes[indx + 1] = faceIdxs[1]; @@ -121,7 +120,7 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData for( int i = 0; i < tri->numVerts; ++i ) { - tri->verts[i] = newMesh->GetDrawVerts( )[i]; + tri->verts[i] = mesh->GetDrawVerts( )[i]; tri->bounds.AddPoint( tri->verts[i].xyz ); } @@ -129,6 +128,7 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData surf.geometry = tri; AddSurface( surf ); + delete mesh; } } @@ -138,13 +138,6 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData } } -void idRenderModelGLTF::MakeMD5Mesh( ) -{ - - meshes.SetGranularity( 1 ); - //meshes.SetNum( num ); -} - //constructs a renderModel from a gltfScene node found in the "models" scene of the given gltfFile. // override with gltf_ModelSceneName // warning : nodeName cannot have dots! @@ -155,12 +148,17 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) hasAnimations = false; fileExclusive = false; root = nullptr; + rootID = -1; int meshID = -1; + name = fileName; + + //FIXME FIXME FIXME + maxJointVertDist = 60; idStr meshName; idStr gltfFileName = idStr( fileName ); model_state = DM_STATIC; - gltfManager::ExtractMeshIdentifier( gltfFileName, meshID, meshName ); + gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName ); if( gltfParser->currentFile.Length() ) { @@ -182,7 +180,6 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) int sceneId = data->DefaultScene(); assert( sceneId >= 0 ); - if( !meshName[0] ) { //this needs to be fixed to correctly support multiple meshes. @@ -215,17 +212,34 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) MakeDefaultModel( ); return; } - model_state = animIds.Num() ? DM_CONTINUOUS : DM_STATIC; + + //find all animations + animIds = data->GetAnimationIds( root ); + + hasAnimations = animIds.Num() > 0; + model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; + + //check if this model has a skeleton + if( root->skin >= 0 ) + { + + gltfSkin* skin = data->SkinList( )[root->skin]; + bones = skin->joints; + } + else if( animIds.Num( ) ) + { + bones.Clear( ); + bones.Append( rootID ); + } // derive mikktspace tangents from normals FinishSurfaces( true ); - // it is now available for use - purged = false; + LoadModel(); + UpdateMd5Joints(); + + // it is now available for use - //skin - //gltfNode * modelNode = data->GetNode(data->SceneList()[data->GetSceneId("models")],targetMesh); - //__debugbreak(); } bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp ) @@ -233,7 +247,6 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim hasAnimations = false; fileExclusive = false; // not written. root = nullptr; - prevTrans = mat4_identity; //we should still load the scene information ? if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) @@ -280,12 +293,561 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim animIds.SetNum( animCnt ); } hasAnimations = animCnt > 0; + + int tempNum; + file->ReadBig( tempNum ); + md5joints.SetNum( tempNum ); + for( int i = 0; i < md5joints.Num( ); i++ ) + { + file->ReadString( md5joints[i].name ); + int offset; + file->ReadBig( offset ); + if( offset >= 0 ) + { + md5joints[i].parent = md5joints.Ptr( ) + offset; + } + else + { + md5joints[i].parent = NULL; + } + } + + int boneCnt; + file->ReadBig( boneCnt ); + if( boneCnt > 0 ) + { + bones.Resize( boneCnt, 1 ); + file->ReadBigArray( bones.Ptr( ), boneCnt ); + bones.SetNum( boneCnt ); + } + else + + + if( root->skin == -1 && hasAnimations && !bones.Num() ) + { + bones.Clear( ); + bones.Append( rootID ); + } + + file->ReadBig( tempNum ); + defaultPose.SetNum( tempNum ); + for( int i = 0; i < defaultPose.Num( ); i++ ) + { + file->ReadBig( defaultPose[i].q.x ); + file->ReadBig( defaultPose[i].q.y ); + file->ReadBig( defaultPose[i].q.z ); + file->ReadBig( defaultPose[i].q.w ); + file->ReadVec3( defaultPose[i].t ); + } + + file->ReadBig( tempNum ); + invertedDefaultPose.SetNum( tempNum ); + for( int i = 0; i < invertedDefaultPose.Num( ); i++ ) + { + file->ReadBigArray( invertedDefaultPose[i].ToFloatPtr( ), JOINTMAT_TYPESIZE ); + } + SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); + + model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; + + //HVG_TODO: replace bonedata with md5jointData + //UpdateMd5Joints(); + return true; } +void idRenderModelGLTF::UpdateMd5Joints( ) +{ + md5joints.Clear(); + md5joints.Resize( bones.Num() ); + md5joints.SetNum( bones.Num() ); + auto& nodeList = data->NodeList(); + + for( int i = 0 ; i < bones.Num(); i++ ) + { + gltfNode* node = nodeList[bones[i]]; + + //check for TRS anim and its artificial root bone + if( bones.Num() == 1 && node->mesh != -1 ) + { + md5joints[i].name = "origin"; + } + else + { + md5joints[i].name = node->name; + } + } + + auto findMd5Joint = [&]( idStr & name ) -> auto + { + for( auto& joint : md5joints ) + { + if( joint.name == name ) + { + return &joint; + } + } + assert( 0 ); + static idMD5Joint staticJoint; + return &staticJoint; + }; + + for( int i = 0 ; i < bones.Num(); i++ ) + { + gltfNode* node = nodeList[bones[i]]; + if( node->parent ) + { + md5joints[i].parent = findMd5Joint( node->parent->name ); + } + } +} + +void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view ) +{ + int i; + int num; + idVec3 pos; + const idJointMat* joint; + const idMD5Joint* md5Joint; + int parentNum; + + num = ent->numJoints; + joint = ent->joints; + md5Joint = md5joints.Ptr(); + for( i = 0; i < num; i++, joint++, md5Joint++ ) + { + pos = ent->origin + joint->ToVec3( ) * ent->axis; + if( md5Joint->parent ) + { + parentNum = md5Joint->parent - md5joints.Ptr( ); + common->RW( )->DebugLine( colorWhite, ent->origin + ent->joints[parentNum].ToVec3( ) * ent->axis, pos ); + } + + common->RW( )->DebugLine( colorRed, pos, pos + joint->ToMat3( )[0] * 2.0f * ent->axis ); + common->RW( )->DebugLine( colorGreen, pos, pos + joint->ToMat3( )[1] * 2.0f * ent->axis ); + common->RW( )->DebugLine( colorBlue, pos, pos + joint->ToMat3( )[2] * 2.0f * ent->axis ); + } + + idBounds bounds; + + bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis ); + common->RW( )->DebugBounds( colorMagenta, bounds, ent->origin ); + + if( ( r_jointNameScale.GetFloat( ) != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) + { + idVec3 offset( 0, 0, r_jointNameOffset.GetFloat( ) ); + float scale; + + scale = r_jointNameScale.GetFloat( ); + joint = ent->joints; + num = ent->numJoints; + for( i = 0; i < num; i++, joint++ ) + { + pos = ent->origin + joint->ToVec3( ) * ent->axis; + common->RW( )->DrawText( md5joints[i].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 ); + } + } +} + +bool gatherBoneInfo( gltfAnimation* gltfAnim, const idList& nodes , idList& bones, idList& jointInfo ) +{ + //Gather Bones; + bool boneLess = false; + int boneLessTarget = -1; + for( auto channel : gltfAnim->channels ) + { + auto* target = nodes[channel->target.node]; + if( target->mesh != 0 ) + { + + if( boneLessTarget == -1 || boneLessTarget != channel->target.node ) + { + assert( !boneLess ); + } + + boneLess = true; + boneLessTarget = channel->target.node; + } + else + { + bones.Append( channel->target.node ); + } + } + + if( !bones.Num( ) ) + { + assert( boneLess ); + } + else + { + assert( bones.Num( ) && !boneLess ); + } + + //we cant be sure channels are sorted by bone? + if( !boneLess ) + { + assert( 0 ); // implement me + } + else + { + bones.Append( boneLessTarget ); + } + + //create jointInfo + jointInfo.SetGranularity( 1 ); + jointInfo.SetNum( bones.Num( ) ); + for( auto& joint : jointInfo ) + { + joint.animBits = 0; + joint.firstComponent = -1; + } + + return boneLess; +} + +idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T sourceTimeStamp ) +{ + ///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; + + idMat4 axisTransform( idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ), vec3_origin ); + + int id; + idStr gltfFileName = idStr( animName ); + idStr name; + gltfManager::ExtractIdentifier( gltfFileName, id, name ); + + if( gltfParser->currentFile.Length( ) ) + { + if( gltfParser->currentAsset && gltfParser->currentFile != gltfFileName ) + { + common->FatalError( "multiple GLTF file loading not supported" ); + } + } + else + { + gltfParser->Load( gltfFileName ); + } + + gltfData* data = gltfParser->currentAsset; + + auto gltfAnim = data->GetAnimation( name ); + if( !gltfAnim ) + { + return nullptr; + } + + auto& accessors = data->AccessorList( ); + auto& nodes = data->NodeList( ); + + idList bones; + idList jointInfo; + + bool boneLess = gatherBoneInfo( gltfAnim, nodes, bones, jointInfo ); + + + idList frameCounts; + idList componentFrames; + idList baseFrame; + + idList bounds; + int numFrames = 0; + int frameRate = 0; + int numJoints = bones.Num(); + int numAnimatedComponents = 0; + + gltfNode* root = nullptr; + int channelCount = 0; + for( auto channel : gltfAnim->channels ) + { + auto& sampler = *gltfAnim->samplers[channel->sampler]; + + auto* input = accessors[sampler.input]; + auto* output = accessors[sampler.output]; + auto* target = nodes[channel->target.node]; + jointAnimInfo_t* newJoint = &( jointInfo[ bones.FindIndex( channel->target.node ) ] ); + + idList& timeStamps = data->GetAccessorView( input ); + root = target; + int frames = timeStamps.Num(); + frameCounts.Append( frames ); + + if( numFrames != 0 && numFrames != frames ) + { + common->Warning( "Not all channel animations have the same amount of frames" ); + } + + if( frames > numFrames ) + { + numFrames = frames; + } + + int parentIndex = data->GetNodeIndex( target->parent ); + newJoint->nameIndex = animationLib.JointIndex( boneLess ? "origin" : target->name ); + newJoint->parentNum = bones.FindIndex( parentIndex ); + + if( newJoint->firstComponent == -1 ) + { + newJoint->firstComponent = numAnimatedComponents; + } + + switch( channel->target.TRS ) + { + default: + break; + case gltfAnimation_Channel_Target::none: + break; + case gltfAnimation_Channel_Target::rotation: + newJoint->animBits |= ANIM_QX | ANIM_QY | ANIM_QZ; + numAnimatedComponents += 3;// * frames; + break; + case gltfAnimation_Channel_Target::translation: + newJoint->animBits |= ANIM_TX | ANIM_TY | ANIM_TZ; + numAnimatedComponents += 3;// * frames; + break; + case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf + break; + } + + channelCount++; + } + + frameRate = gltf_AnimSampleRate.GetInteger(); + INT animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate; + + idFile_Memory* file = new idFile_Memory(); + file->WriteBig( B_ANIM_MD5_MAGIC ); + file->WriteBig( sourceTimeStamp ); + + file->WriteBig( numFrames ); + file->WriteBig( frameRate ); + file->WriteBig( animLength ); + file->WriteBig( numJoints ); + file->WriteBig( numAnimatedComponents ); + + bounds.SetGranularity( 1 ); + bounds.SetNum( numFrames ); + for( int i = 0 ; i < numFrames; i++ ) + { + for( int boneId : bones ) + { + gltfNode* boneNode = nodes[boneId]; + idMat4 trans = mat4_identity; + gltfData::ResolveNodeMatrix( boneNode, &trans ); + trans *= axisTransform; + + bounds[i].AddPoint( idVec3( trans[0][3], trans[1][3], trans[2][3] ) ); + } + } + + file->WriteBig( bounds.Num( ) ); + for( int i = 0; i < bounds.Num( ); i++ ) + { + idBounds& b = bounds[i]; + file->WriteBig( b[0] ); + file->WriteBig( b[1] ); + } + + //namestr list + file->WriteBig( jointInfo.Num( ) ); + for( int i = 0; i < jointInfo.Num( ); i++ ) + { + jointAnimInfo_t& j = jointInfo[i]; + idStr jointName = animationLib.JointName( j.nameIndex ); + file->WriteString( jointName ); + file->WriteBig( j.parentNum ); + file->WriteBig( j.animBits ); + file->WriteBig( j.firstComponent ); + } + + baseFrame.SetGranularity( 1 ); + baseFrame.SetNum( bones.Num() ); + + + for( int i = 0 ; i < bones.Num(); i++ ) + { + gltfNode* boneNode = nodes[bones[i]]; + + baseFrame[i].q = boneNode->rotation * idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ).Transpose().ToQuat( ); + baseFrame[i].t = boneNode->translation * axisTransform; + baseFrame[i].w = baseFrame[i].q.CalcW(); + } + + //raw node / skeleton + file->WriteBig( baseFrame.Num( ) ); + for( int i = 0; i < baseFrame.Num( ); i++ ) + { + idJointQuat& j = baseFrame[i]; + file->WriteBig( j.q.x ); + file->WriteBig( j.q.y ); + file->WriteBig( j.q.z ); + file->WriteBig( j.q.w ); + file->WriteVec3( j.t ); + } + + componentFrames.SetGranularity( 1 ); + componentFrames.SetNum( numAnimatedComponents * numFrames * numJoints + 1 ); + componentFrames[numAnimatedComponents * numFrames * numJoints ] = 0.0f; + int componentFrameIndex = 0; + + for( int i = 0 ; i < numFrames; i++ ) + { + + bool hasTranslation = false; + bool hasRotation = false; + bool transDone = false; + bool rotDone = false; + //add weight + scale + + while( !transDone && !rotDone ) + { + idVec3 t = vec3_zero; + idQuat q; + q.w = 1.0f; + + for( auto channel : gltfAnim->channels ) + { + auto& sampler = *gltfAnim->samplers[channel->sampler]; + + auto* input = accessors[sampler.input]; + auto* output = accessors[sampler.output]; + auto* target = nodes[channel->target.node]; + idList& timeStamps = data->GetAccessorView( input ); + jointAnimInfo_t* joint = &( jointInfo[ bones.FindIndex( channel->target.node ) ] ); + hasTranslation |= ( joint->animBits & ANIM_TX || joint->animBits & ANIM_TY || joint->animBits & ANIM_TZ ); + hasRotation |= ( joint->animBits & ANIM_QX || joint->animBits & ANIM_QY || joint->animBits & ANIM_QZ ); + + int targetID = nodes.FindIndex( target ); + + switch( channel->target.TRS ) + { + default: + break; + case gltfAnimation_Channel_Target::none: + break; + case gltfAnimation_Channel_Target::rotation: + { + idList& values = data->GetAccessorView( output ); + if( values.Num() > i ) + { + q = *values[i]; + } + rotDone = true; + } + break; + case gltfAnimation_Channel_Target::translation: + { + idList& values = data->GetAccessorView( output ); + if( values.Num() > i ) + { + t = *values[i]; + } + transDone = true; + } + break; + case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf + break; + } + + if( !transDone ) + { + transDone = !hasTranslation; + } + if( !rotDone ) + { + rotDone = !hasRotation; + } + } + + if( rotDone && transDone ) + { + if( hasTranslation ) + { + t *= axisTransform; + componentFrames[componentFrameIndex++] = t.x; + componentFrames[componentFrameIndex++] = t.y; + componentFrames[componentFrameIndex++] = t.z; + } + if( hasRotation ) + { + q *= idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ).Transpose().ToQuat( ); + idVec3 rot = q.ToRotation().GetVec(); + componentFrames[componentFrameIndex++] = q.x; + componentFrames[componentFrameIndex++] = q.y; + componentFrames[componentFrameIndex++] = q.z; + } + break; + } + } + } + + assert( componentFrames.Num() == ( componentFrameIndex + 1 ) ); + //per joint timestamp values, T R + file->WriteBig( componentFrames.Num( ) - 1 ); + for( int i = 0; i < componentFrames.Num( ); i++ ) + { + file->WriteFloat( componentFrames[i] ); + } + + float* componentPtr = componentFrames.Ptr(); + idVec3 totaldelta; + // get total move delta + if( !numAnimatedComponents ) + { + totaldelta.Zero( ); + } + else + { + componentPtr = &componentFrames[jointInfo[0].firstComponent]; + if( jointInfo[0].animBits & ANIM_TX ) + { + for( int i = 0; i < numFrames; i++ ) + { + componentPtr[numAnimatedComponents * i] -= baseFrame[0].t.x; + } + totaldelta.x = componentPtr[numAnimatedComponents * ( numFrames - 1 )]; + componentPtr++; + } + else + { + totaldelta.x = 0.0f; + } + if( jointInfo[0].animBits & ANIM_TY ) + { + for( int i = 0; i < numFrames; i++ ) + { + componentPtr[numAnimatedComponents * i] -= baseFrame[0].t.y; + } + totaldelta.y = componentPtr[numAnimatedComponents * ( numFrames - 1 )]; + componentPtr++; + } + else + { + totaldelta.y = 0.0f; + } + if( jointInfo[0].animBits & ANIM_TZ ) + { + for( int i = 0; i < numFrames; i++ ) + { + componentPtr[numAnimatedComponents * i] -= baseFrame[0].t.z; + } + totaldelta.z = componentPtr[numAnimatedComponents * ( numFrames - 1 )]; + } + else + { + totaldelta.z = 0.0f; + } + } + + file->WriteVec3( totaldelta ); + file->Seek( 0, FS_SEEK_SET ); + file->TakeDataOwnership(); + return file; +} + void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /*= NULL */ ) const { - idRenderModelStatic::WriteBinaryModel( file ); if( file == NULL || root == nullptr ) @@ -301,120 +863,249 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /* file->WriteBig( animIds.Num( ) ); if( animIds.Num( ) ) { - file->WriteBigArray( animIds.Ptr(), animIds.Size() ); + file->WriteBigArray( animIds.Ptr(), animIds.Num() ); } - //check if this model has a skeleton - //if ( root->skin >= 0 ) - //{ - // gltfSkin *skin = data->SkinList( )[root->skin]; - // auto &nodeList = data->NodeList( ); - // file->WriteBig( skin->joints.Num( ) ); - // for ( int i = 0; i < skin->joints.Num( ); i++ ) { + file->WriteBig( md5joints.Num( ) ); + for( int i = 0; i < md5joints.Num( ); i++ ) + { + file->WriteString( md5joints[i].name ); + int offset = -1; + if( md5joints[i].parent != NULL ) + { + offset = md5joints[i].parent - md5joints.Ptr( ); + } + file->WriteBig( offset ); + } - // gltfNode &target = *nodeList[skin->joints[i]]; - // file->WriteString( target.name ); - // int offset = -1; - // if ( target.parent != NULL ) { - // offset = target.parent - skin->joints.Ptr( ); - // } - // file->WriteBig( offset ); - // } - //} - // file->WriteBig( defaultPose.Num( ) ); - // for ( int i = 0; i < defaultPose.Num( ); i++ ) { - // file->WriteBig( defaultPose[i].q.x ); - // file->WriteBig( defaultPose[i].q.y ); - // file->WriteBig( defaultPose[i].q.z ); - // file->WriteBig( defaultPose[i].q.w ); - // file->WriteVec3( defaultPose[i].t ); - // } + file->WriteBig( bones.Num( ) ); + if( bones.Num( ) ) + { + file->WriteBigArray( bones.Ptr( ), bones.Num( ) ); + } - // file->WriteBig( invertedDefaultPose.Num( ) ); - // for ( int i = 0; i < invertedDefaultPose.Num( ); i++ ) { - // file->WriteBigArray( invertedDefaultPose[i].ToFloatPtr( ), JOINTMAT_TYPESIZE ); - // } - //} + file->WriteBig( defaultPose.Num( ) ); + for( int i = 0; i < defaultPose.Num( ); i++ ) + { + file->WriteBig( defaultPose[i].q.x ); + file->WriteBig( defaultPose[i].q.y ); + file->WriteBig( defaultPose[i].q.z ); + file->WriteBig( defaultPose[i].q.w ); + file->WriteVec3( defaultPose[i].t ); + } - - - //file->WriteBig( meshes.Num( ) ); - //for ( int i = 0; i < meshes.Num( ); i++ ) { - - // if ( meshes[i].shader != NULL && meshes[i].shader->GetName( ) != NULL ) { - // file->WriteString( meshes[i].shader->GetName( ) ); - // } else { - // file->WriteString( "" ); - // } - - // file->WriteBig( meshes[i].numVerts ); - // file->WriteBig( meshes[i].numTris ); - - // file->WriteBig( meshes[i].numMeshJoints ); - // file->WriteBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints ); - // file->WriteBig( meshes[i].maxJointVertDist ); - - // deformInfo_t &deform = *meshes[i].deformInfo; - - // file->WriteBig( deform.numSourceVerts ); - // file->WriteBig( deform.numOutputVerts ); - // file->WriteBig( deform.numIndexes ); - // file->WriteBig( deform.numMirroredVerts ); - // file->WriteBig( deform.numDupVerts ); - // file->WriteBig( deform.numSilEdges ); - - // if ( deform.numOutputVerts > 0 ) { - // file->WriteBigArray( deform.verts, deform.numOutputVerts ); - // } - - // if ( deform.numIndexes > 0 ) { - // file->WriteBigArray( deform.indexes, deform.numIndexes ); - // file->WriteBigArray( deform.silIndexes, deform.numIndexes ); - // } - - // if ( deform.numMirroredVerts > 0 ) { - // file->WriteBigArray( deform.mirroredVerts, deform.numMirroredVerts ); - // } - - // if ( deform.numDupVerts > 0 ) { - // file->WriteBigArray( deform.dupVerts, deform.numDupVerts * 2 ); - // } - - // if ( deform.numSilEdges > 0 ) { - // for ( int j = 0; j < deform.numSilEdges; j++ ) { - // file->WriteBig( deform.silEdges[j].p1 ); - // file->WriteBig( deform.silEdges[j].p2 ); - // file->WriteBig( deform.silEdges[j].v1 ); - // file->WriteBig( deform.silEdges[j].v2 ); - // } - // } - - // file->WriteBig( meshes[i].surfaceNum ); - //} + file->WriteBig( invertedDefaultPose.Num( ) ); + for( int i = 0; i < invertedDefaultPose.Num( ); i++ ) + { + file->WriteBigArray( invertedDefaultPose[i].ToFloatPtr( ), JOINTMAT_TYPESIZE ); + } } void idRenderModelGLTF::PurgeModel() { - common->Warning( "idRenderModelGLTF::PurgeModel is not implemented." ); + purged = true; + md5joints.Clear( ); + defaultPose.Clear( ); + meshes.Clear( ); +} + +idList getSkinningMatrix( gltfData* data, gltfSkin* skin, gltfAccessor* acc ) +{ + idMat4 world = mat4_identity; + idList values = data->GetAccessorViewMat( acc ); + + auto& nodeList = data->NodeList( ); + int count = 0; + + if( skin->skeleton == -1 ) + { + skin->skeleton = skin->joints[0]; + } + + for( int joint : skin->joints ) + { + world = mat4_identity; + auto* node = nodeList[joint]; + idMat4* bindMat = &values[count]; + bindMat->TransposeSelf( ); + data->ResolveNodeMatrix( node, &world ); + *bindMat = world * *bindMat; + bindMat->TransposeSelf( ); + count++; + } + return values; } void idRenderModelGLTF::LoadModel() { - common->Warning( "The method or operation is not implemented." ); + int meshID; + idStr meshName; + idStr gltfFileName = idStr( name ); + + gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName ); + + if( gltfParser->currentFile.Length( ) ) + { + if( gltfParser->currentAsset && gltfParser->currentFile != gltfFileName ) + { + common->FatalError( "multiple GLTF file loading not supported" ); + } + } + else + { + if( !gltfParser->Load( gltfFileName ) ) + { + MakeDefaultModel( ); + return; + } + } + + timeStamp = fileSystem->GetTimestamp( gltfFileName ); + + int num; + int parentNum; + + if( !purged ) + { + PurgeModel( ); + } + + purged = false; + + gltfData* data = gltfParser->currentAsset; + auto& accessors = data->AccessorList( ); + auto& nodes = data->NodeList( ); + gltfNode* meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); + auto animList = data->GetAnimationIds( meshRoot ); + + gltfSkin* skin = nullptr; + gltfAccessor* acc = nullptr; + if( meshRoot->skin != -1 ) + { + skin = data->SkinList( )[meshRoot->skin]; + acc = data->AccessorList( )[skin->inverseBindMatrices]; + } + else + { + skin = new gltfSkin; + skin->joints.AssureSize( 1, rootID ); + idMat4 trans = mat4_identity; + data->ResolveNodeMatrix( meshRoot, &trans ); + acc = new gltfAccessor(); + acc->matView = new idList( 1 ); + acc->matView->AssureSize( 1, trans.Inverse() ); + } + + auto basepose = getSkinningMatrix( data, skin, acc ); + + if( meshRoot->skin == -1 ) + { + delete skin; + delete acc; + } + + num = bones.Num(); + md5joints.SetGranularity( 1 ); + md5joints.SetNum( num ); + defaultPose.SetGranularity( 1 ); + defaultPose.SetNum( num ); + + for( int i = 0; i < bones.Num( ); i++ ) + { + gltfNode* node = nodes[bones[i]]; + + //check for TRS anim and its artficial root bone + if( bones.Num( ) == 1 && node->mesh != -1 ) + { + md5joints[i].name = "origin"; + } + else + { + md5joints[i].name = node->name; + } + } + + auto findMd5Joint = [&]( idStr & name ) -> auto + { + for( auto& joint : md5joints ) + { + if( joint.name == name ) + { + return &joint; + } + } + assert( 0 ); + static idMD5Joint staticJoint; + return &staticJoint; + }; + + idAngles axisTransformAngels = idAngles( 0.0f, 0.0f, 90.0f ); + idMat4 axisTransform( axisTransformAngels.ToMat3( ), vec3_origin ); + + for( int i = 0; i < bones.Num( ); i++ ) + { + gltfNode* node = nodes[bones[i]]; + if( node->parent ) + { + md5joints[i].parent = findMd5Joint( node->parent->name ); + } + idJointQuat& pose = defaultPose[i]; + pose.q = node->rotation; + pose.t = node->translation; + } + + idJointMat* poseMat = ( idJointMat* ) _alloca16( md5joints.Num( ) * sizeof( poseMat[0] ) ); + for( int i = 0; i < md5joints.Num( ); i++ ) + { + idMD5Joint* joint = &md5joints[i]; + idJointQuat* pose = &defaultPose[i]; + + poseMat[i].SetRotation( pose->q.ToMat3() * axisTransformAngels.ToMat3( ).Transpose() ); + poseMat[i].SetTranslation( pose->t * axisTransform ); + if( joint->parent ) + { + parentNum = joint->parent - md5joints.Ptr( ); + pose->q = ( poseMat[i].ToMat3( ) * poseMat[parentNum].ToMat3( ).Transpose( ) ).ToQuat( ); + pose->t = ( poseMat[i].ToVec3( ) - poseMat[parentNum].ToVec3( ) ) * poseMat[parentNum].ToMat3( ).Transpose( ); + } + } + + + //----------------------------------------- + // create the inverse of the base pose joints to support tech6 style deformation + // of base pose vertexes, normals, and tangents. + // + // vertex * joints * inverseJoints == vertex when joints is the base pose + // When the joints are in another pose, it gives the animated vertex position + //----------------------------------------- + invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( md5joints.Num( ) ) ); + for( int i = 0; i < md5joints.Num( ); i++ ) + { + invertedDefaultPose[i] = poseMat[i]; + invertedDefaultPose[i].Invert( ); + } + SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); + + + //deformInfo = R_BuildDeformInfo( texCoords.Num( ), basePose, tris.Num( ), tris.Ptr( ), + // shader->UseUnsmoothedTangents( ) ); + + model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; + + // set the timestamp for reloadmodels + fileSystem->ReadFile( name, NULL, &timeStamp ); + + common->UpdateLevelLoadPacifier( ); } void idRenderModelGLTF::TouchData() { - common->Warning( "The method or operation is not implemented." ); + for( int i = 0; i < surfaces.Num( ); i++ ) + { + declManager->FindMaterial( surfaces[i].shader->GetName( ) ); + } } -/* -void idRenderModelGLTF::CreateBuffers() -{ - common->Warning( "The method or operation is not implemented." ); -} -*/ - void idRenderModelGLTF::Print() const { common->Warning( "The method or operation is not implemented." ); @@ -436,20 +1127,30 @@ dynamicModel_t idRenderModelGLTF::IsDynamicModel() const return model_state; } -void TransformVertsAndTangents( idDrawVert* targetVerts, const int numVerts, idMat4 trans ) +void TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts, const idDrawVert* baseVerts, const idJointMat* joints ) { + idJointMat trans = joints[0]; + //add skinning for( int i = 0; i < numVerts; i++ ) { + const idDrawVert& base = baseVerts[i]; - targetVerts[i].xyz *= trans;// * idVec3( base.xyz.x, base.xyz.y, base.xyz.z); - targetVerts[i].SetNormal( trans.ToMat3() * targetVerts[i].GetNormal( ) ); - targetVerts[i].SetTangent( trans.ToMat3() * targetVerts[i].GetTangent( ) ); + targetVerts[i].xyz = trans * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); + targetVerts[i].SetNormal( trans * baseVerts[i].GetNormal( ) ); + float t3 = base.tangent[3]; + targetVerts[i].SetTangent( trans * base.GetTangent( ) ); + targetVerts[i].tangent[3] = t3; } } -void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, idMat4 trans, modelSurface_t* surf ) +void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf ) { +#if defined(USE_INTRINSICS_SSE) + static const __m128 vector_float_posInfinity = { idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM }; + static const __m128 vector_float_negInfinity = { -idMath::INFINITUM, -idMath::INFINITUM, -idMath::INFINITUM, -idMath::INFINITUM }; +#endif + //add skinning if( surf->geometry != NULL ) { R_FreeStaticTriSurfVertexCaches( surf->geometry ); @@ -460,8 +1161,201 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, idMat4 } srfTriangles_t* tri = surf->geometry; - TransformVertsAndTangents( tri->verts, tri->numVerts, trans ); + modelSurface_t& sourceSurf = surfaces[0]; + int numVerts = sourceSurf.geometry->numVerts; + idDrawVert* verts = sourceSurf.geometry->verts; + tri->referencedIndexes = true; + tri->numIndexes = sourceSurf.geometry->numIndexes; + tri->indexes = sourceSurf.geometry->indexes; + tri->silIndexes = sourceSurf.geometry->silIndexes; + tri->numMirroredVerts = sourceSurf.geometry->numMirroredVerts; + tri->mirroredVerts = sourceSurf.geometry->mirroredVerts; + tri->numDupVerts = sourceSurf.geometry->numDupVerts; + tri->dupVerts = sourceSurf.geometry->dupVerts; + tri->numSilEdges = sourceSurf.geometry->numSilEdges; + tri->silEdges = sourceSurf.geometry->silEdges; + + tri->indexCache = sourceSurf.geometry->indexCache; + + tri->numVerts = numVerts; + + if( r_useGPUSkinning.GetBool( ) && glConfig.gpuSkinningAvailable ) + { + if( tri->verts != NULL && tri->verts != sourceSurf.geometry->verts ) + { + R_FreeStaticTriSurfVerts( tri ); + } + tri->verts = sourceSurf.geometry->verts; + tri->ambientCache = sourceSurf.geometry->ambientCache; + tri->shadowCache = sourceSurf.geometry->shadowCache; + tri->referencedVerts = true; + } + else + { + if( tri->verts == NULL || tri->verts == verts ) + { + tri->verts = NULL; + R_AllocStaticTriSurfVerts( tri, numVerts ); + assert( tri->verts != NULL ); // quiet analyze warning + memcpy( tri->verts, verts, numVerts * sizeof( verts[0] ) ); // copy over the texture coordinates + tri->referencedVerts = false; + } + + TransformVertsAndTangents_GLTF( tri->verts, numVerts, verts, entJointsInverted ); + tri->tangentsCalculated = true; + } + +#if defined(USE_INTRINSICS_SSE) + + __m128 minX = vector_float_posInfinity; + __m128 minY = vector_float_posInfinity; + __m128 minZ = vector_float_posInfinity; + __m128 maxX = vector_float_negInfinity; + __m128 maxY = vector_float_negInfinity; + __m128 maxZ = vector_float_negInfinity; + for( int i = 0; i < numVerts; i++ ) + { + const idJointMat& joint = entJoints[0]; + __m128 x = _mm_load_ps( joint.ToFloatPtr( ) + 0 * 4 ); + __m128 y = _mm_load_ps( joint.ToFloatPtr( ) + 1 * 4 ); + __m128 z = _mm_load_ps( joint.ToFloatPtr( ) + 2 * 4 ); + minX = _mm_min_ps( minX, x ); + minY = _mm_min_ps( minY, y ); + minZ = _mm_min_ps( minZ, z ); + maxX = _mm_max_ps( maxX, x ); + maxY = _mm_max_ps( maxY, y ); + maxZ = _mm_max_ps( maxZ, z ); + } + __m128 expand = _mm_splat_ps( _mm_load_ss( &maxJointVertDist ), 0 ); + minX = _mm_sub_ps( minX, expand ); + minY = _mm_sub_ps( minY, expand ); + minZ = _mm_sub_ps( minZ, expand ); + maxX = _mm_add_ps( maxX, expand ); + maxY = _mm_add_ps( maxY, expand ); + maxZ = _mm_add_ps( maxZ, expand ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 0, _mm_splat_ps( minX, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 1, _mm_splat_ps( minY, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 2, _mm_splat_ps( minZ, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 3, _mm_splat_ps( maxX, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 4, _mm_splat_ps( maxY, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr( ) + 5, _mm_splat_ps( maxZ, 3 ) ); + +#else + + bounds.Clear( ); + for( int i = 0; i < numMeshJoints; i++ ) + { + const idJointMat& joint = entJoints[meshJoints[i]]; + bounds.AddPoint( joint.GetTranslation( ) ); + } + bounds.ExpandSelf( maxJointVertDist ); + +#endif + +} + +/* +==================== +TransformJoints +==================== +*/ +static void TransformJointsFast( idJointMat* __restrict outJoints, const int numJoints, const idJointMat* __restrict inJoints1, const idJointMat* __restrict inJoints2 ) +{ + + float* outFloats = outJoints->ToFloatPtr( ); + const float* inFloats1 = inJoints1->ToFloatPtr( ); + const float* inFloats2 = inJoints2->ToFloatPtr( ); + + assert_16_byte_aligned( outFloats ); + assert_16_byte_aligned( inFloats1 ); + assert_16_byte_aligned( inFloats2 ); + +#if defined(USE_INTRINSICS_SSE) + + const __m128 mask_keep_last = __m128c( _mm_set_epi32( 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 ) ); + + for( int i = 0; i < numJoints; i += 2, inFloats1 += 2 * 12, inFloats2 += 2 * 12, outFloats += 2 * 12 ) + { + __m128 m1a0 = _mm_load_ps( inFloats1 + 0 * 12 + 0 ); + __m128 m1b0 = _mm_load_ps( inFloats1 + 0 * 12 + 4 ); + __m128 m1c0 = _mm_load_ps( inFloats1 + 0 * 12 + 8 ); + __m128 m1a1 = _mm_load_ps( inFloats1 + 1 * 12 + 0 ); + __m128 m1b1 = _mm_load_ps( inFloats1 + 1 * 12 + 4 ); + __m128 m1c1 = _mm_load_ps( inFloats1 + 1 * 12 + 8 ); + + __m128 m2a0 = _mm_load_ps( inFloats2 + 0 * 12 + 0 ); + __m128 m2b0 = _mm_load_ps( inFloats2 + 0 * 12 + 4 ); + __m128 m2c0 = _mm_load_ps( inFloats2 + 0 * 12 + 8 ); + __m128 m2a1 = _mm_load_ps( inFloats2 + 1 * 12 + 0 ); + __m128 m2b1 = _mm_load_ps( inFloats2 + 1 * 12 + 4 ); + __m128 m2c1 = _mm_load_ps( inFloats2 + 1 * 12 + 8 ); + + __m128 tj0 = _mm_and_ps( m1a0, mask_keep_last ); + __m128 tk0 = _mm_and_ps( m1b0, mask_keep_last ); + __m128 tl0 = _mm_and_ps( m1c0, mask_keep_last ); + __m128 tj1 = _mm_and_ps( m1a1, mask_keep_last ); + __m128 tk1 = _mm_and_ps( m1b1, mask_keep_last ); + __m128 tl1 = _mm_and_ps( m1c1, mask_keep_last ); + + __m128 ta0 = _mm_splat_ps( m1a0, 0 ); + __m128 td0 = _mm_splat_ps( m1b0, 0 ); + __m128 tg0 = _mm_splat_ps( m1c0, 0 ); + __m128 ta1 = _mm_splat_ps( m1a1, 0 ); + __m128 td1 = _mm_splat_ps( m1b1, 0 ); + __m128 tg1 = _mm_splat_ps( m1c1, 0 ); + + __m128 ra0 = _mm_add_ps( tj0, _mm_mul_ps( ta0, m2a0 ) ); + __m128 rd0 = _mm_add_ps( tk0, _mm_mul_ps( td0, m2a0 ) ); + __m128 rg0 = _mm_add_ps( tl0, _mm_mul_ps( tg0, m2a0 ) ); + __m128 ra1 = _mm_add_ps( tj1, _mm_mul_ps( ta1, m2a1 ) ); + __m128 rd1 = _mm_add_ps( tk1, _mm_mul_ps( td1, m2a1 ) ); + __m128 rg1 = _mm_add_ps( tl1, _mm_mul_ps( tg1, m2a1 ) ); + + __m128 tb0 = _mm_splat_ps( m1a0, 1 ); + __m128 te0 = _mm_splat_ps( m1b0, 1 ); + __m128 th0 = _mm_splat_ps( m1c0, 1 ); + __m128 tb1 = _mm_splat_ps( m1a1, 1 ); + __m128 te1 = _mm_splat_ps( m1b1, 1 ); + __m128 th1 = _mm_splat_ps( m1c1, 1 ); + + __m128 rb0 = _mm_add_ps( ra0, _mm_mul_ps( tb0, m2b0 ) ); + __m128 re0 = _mm_add_ps( rd0, _mm_mul_ps( te0, m2b0 ) ); + __m128 rh0 = _mm_add_ps( rg0, _mm_mul_ps( th0, m2b0 ) ); + __m128 rb1 = _mm_add_ps( ra1, _mm_mul_ps( tb1, m2b1 ) ); + __m128 re1 = _mm_add_ps( rd1, _mm_mul_ps( te1, m2b1 ) ); + __m128 rh1 = _mm_add_ps( rg1, _mm_mul_ps( th1, m2b1 ) ); + + __m128 tc0 = _mm_splat_ps( m1a0, 2 ); + __m128 tf0 = _mm_splat_ps( m1b0, 2 ); + __m128 ti0 = _mm_splat_ps( m1c0, 2 ); + __m128 tf1 = _mm_splat_ps( m1b1, 2 ); + __m128 ti1 = _mm_splat_ps( m1c1, 2 ); + __m128 tc1 = _mm_splat_ps( m1a1, 2 ); + + __m128 rc0 = _mm_add_ps( rb0, _mm_mul_ps( tc0, m2c0 ) ); + __m128 rf0 = _mm_add_ps( re0, _mm_mul_ps( tf0, m2c0 ) ); + __m128 ri0 = _mm_add_ps( rh0, _mm_mul_ps( ti0, m2c0 ) ); + __m128 rc1 = _mm_add_ps( rb1, _mm_mul_ps( tc1, m2c1 ) ); + __m128 rf1 = _mm_add_ps( re1, _mm_mul_ps( tf1, m2c1 ) ); + __m128 ri1 = _mm_add_ps( rh1, _mm_mul_ps( ti1, m2c1 ) ); + + _mm_store_ps( outFloats + 0 * 12 + 0, rc0 ); + _mm_store_ps( outFloats + 0 * 12 + 4, rf0 ); + _mm_store_ps( outFloats + 0 * 12 + 8, ri0 ); + _mm_store_ps( outFloats + 1 * 12 + 0, rc1 ); + _mm_store_ps( outFloats + 1 * 12 + 4, rf1 ); + _mm_store_ps( outFloats + 1 * 12 + 8, ri1 ); + } + +#else + + for( int i = 0; i < numJoints; i++ ) + { + idJointMat::Multiply( outJoints[i], inJoints1[i], inJoints2[i] ); + } + +#endif } idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEntity_s* ent, const viewDef_t* view, idRenderModel* cachedModel ) @@ -478,6 +1372,19 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn LoadModel(); } + if( !ent->joints ) + { + common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name( ) ); + delete cachedModel; + return NULL; + } + else if( ent->numJoints != md5joints.Num( ) ) + { + common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name( ) ); + delete cachedModel; + return NULL; + } + idRenderModelStatic* staticModel; if( cachedModel != NULL ) { @@ -489,35 +1396,78 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn { staticModel = new( TAG_MODEL ) idRenderModelStatic; staticModel->InitEmpty( GLTF_SnapshotName ); + + //idStr prevName = name; + //name = GLTF_SnapshotName; + ////surfaces = surfaces; + //*staticModel = *this; + //name = prevName; + staticModel->jointsInverted = NULL;; } - idStr prevName = name; - name = GLTF_SnapshotName; - *staticModel = *this; - name = prevName; + staticModel->bounds.Clear(); - idMat3 rotation = idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ); - idMat4 axisTransform( rotation, vec3_origin ); - idMat4 trans = prevTrans; - bool wasDirty = root->dirty; - - gltfData::ResolveNodeMatrix( root, &trans ); - - if( wasDirty ) + if( r_showSkel.GetInteger( ) ) { - trans *= axisTransform; + if( ( view != NULL ) && ( !r_skipSuppress.GetBool( ) || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) + { + // only draw the skeleton + DrawJoints( ent, view ); + } + + if( r_showSkel.GetInteger( ) > 1 ) + { + // turn off the model when showing the skeleton + staticModel->InitEmpty( GLTF_SnapshotName ); + return staticModel; + } } + // update the GPU joints array + const int numInvertedJoints = SIMD_ROUND_JOINTS( md5joints.Num() ); + if( staticModel->jointsInverted == NULL ) + { + staticModel->numInvertedJoints = numInvertedJoints; + staticModel->jointsInverted = ( idJointMat* ) Mem_ClearedAlloc( numInvertedJoints * sizeof( idJointMat ), TAG_JOINTMAT ); + staticModel->jointsInvertedBuffer = 0; + } + else + { + assert( staticModel->numInvertedJoints == numInvertedJoints ); + } + + TransformJointsFast( staticModel->jointsInverted, md5joints.Num(), ent->joints, invertedDefaultPose.Ptr() ); + + modelSurface_t* newSurf; + if( staticModel->surfaces.Num() ) + { + newSurf = &staticModel->surfaces[0]; + } + else + { + newSurf = &staticModel->surfaces.Alloc( ); + newSurf->geometry = NULL; + newSurf->shader = surfaces[0].shader; + } + + int surfIdx = 0; for( modelSurface_t& surf : staticModel->surfaces ) { - UpdateSurface( ent, trans, &surf ); + const idMaterial* shader = newSurf->shader; + shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader ); + + if( !shader || ( !shader->IsDrawn( ) && !shader->SurfaceCastsShadow( ) ) ) + { + staticModel->DeleteSurfaceWithId( surfIdx++ ); + continue; + } + + UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf ); + assert( surf.geometry != NULL ); + surf.geometry->staticModelWithJoints = staticModel; + staticModel->bounds.AddBounds( surf.geometry->bounds ); } - prevTrans = root->matrix.Inverse(); - - //staticModel->bounds *= trans.ToMat3( ); - //bounds.Translate( idVec3( trans[0][3], trans[1][3], trans[2][3] ) ); - return staticModel; } @@ -528,41 +1478,56 @@ int idRenderModelGLTF::NumJoints() const common->FatalError( "Trying to determine Joint count without a model node loaded" ); } - if( root->skin >= 0 ) - { - gltfSkin* skin = data->SkinList( )[root->skin]; - return skin->joints.Num(); - } - - return 0; + return bones.Num(); } const idMD5Joint* idRenderModelGLTF::GetJoints() const { - common->Warning( "The method or operation is not implemented." ); - return nullptr; + idMD5Joint* result = nullptr; + if( md5joints.Num() ) + { + return &md5joints[0]; + } + else + { + common->Warning( "GltfModel has no Joints" ); + return nullptr; + } } jointHandle_t idRenderModelGLTF::GetJointHandle( const char* name ) const { - common->Warning( "The method or operation is not implemented." ); - return jointHandle_t(); + const idMD5Joint* joint = md5joints.Ptr( ); + for( int i = 0; i < md5joints.Num( ); i++, joint++ ) + { + if( idStr::Icmp( joint->name.c_str( ), name ) == 0 ) + { + return ( jointHandle_t ) i; + } + } + + return INVALID_JOINT; } const char* idRenderModelGLTF::GetJointName( jointHandle_t handle ) const { - common->Warning( "The method or operation is not implemented." ); - return ""; + if( ( handle < 0 ) || ( handle >= md5joints.Num( ) ) ) + { + return ""; + } + + return md5joints[handle].name; } const idJointQuat* idRenderModelGLTF::GetDefaultPose() const { - common->Warning( "The method or operation is not implemented." ); - return nullptr; + return defaultPose.Ptr(); } int idRenderModelGLTF::NearestJoint( int surfaceNum, int a, int b, int c ) const { + + ///this needs to be implemented for correct traces common->Warning( "The method or operation is not implemented." ); return -1; } @@ -571,8 +1536,3 @@ idBounds idRenderModelGLTF::Bounds( const struct renderEntity_s* ent ) const { return bounds; } - -idGltfMesh::idGltfMesh( gltfMesh* _mesh, gltfData* _data ) : mesh( _mesh ), data( _data ) -{ - -} diff --git a/neo/renderer/Model_gltf.h b/neo/renderer/Model_gltf.h index 5a4f6cdc..16dabd6f 100644 --- a/neo/renderer/Model_gltf.h +++ b/neo/renderer/Model_gltf.h @@ -29,19 +29,6 @@ If you have questions concerning this license or the applicable additional terms #pragma once #include "Model_local.h" - - -class idGltfMesh -{ -public: - idGltfMesh( ) {}; - idGltfMesh( gltfMesh* _mesh, gltfData* _data ); -private: - gltfMesh* mesh; - gltfData* data; - idMD5Mesh md5Mesh; -}; - class idRenderModelGLTF : public idRenderModelStatic { public: @@ -67,20 +54,30 @@ public: { return true; } - - void MakeMD5Mesh() ; + static idFile_Memory* GetAnimBin( idStr animName, const ID_TIME_T sourceTimeStamp ); private: void ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData* data ); - void UpdateSurface( const struct renderEntity_s* ent, idMat4 trans, modelSurface_t* surf ); + 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; bool hasAnimations; - idList animIds; - idList meshes; + + float maxJointVertDist; // maximum distance a vertex is separated from a joint + idList animIds; + idList bones; dynamicModel_t model_state; - idMat4 prevTrans; idList SkeletonNodes; + + idList md5joints; + idList defaultPose; + idList invertedDefaultPose; + idList meshes; + deformInfo_t* deformInfo; + + MapPolygonMesh* mesh; +private: + void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view ); }; \ No newline at end of file From e56f696c9c96a9ba7105d4367b1cc0e9a62139f3 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 31 Jul 2022 12:13:07 +0200 Subject: [PATCH 02/16] - Skinned / animated GLTF models --- neo/CMakeLists.txt | 3 + neo/idStuff.natvis | 63 ++++ neo/idlib/MapFile_gltf.cpp | 7 +- neo/idlib/gltfParser.cpp | 2 +- neo/idlib/gltfProperties.h | 111 ++++-- neo/idlib/math/Math.h | 17 + neo/idlib/math/VectorI.h | 254 +++++++++++++ neo/renderer/Model_gltf.cpp | 728 +++++++++++++++++++++--------------- neo/renderer/Model_gltf.h | 8 +- 9 files changed, 848 insertions(+), 345 deletions(-) create mode 100644 neo/idStuff.natvis diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index 33cd0bd2..46483660 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -484,6 +484,8 @@ endif (RAPIDJSON_FOUND) add_subdirectory(idlib) +file(GLOB NATVIS_SOURCES .natvis) + file(GLOB AAS_INCLUDES aas/*.h) file(GLOB AAS_SOURCES aas/*.cpp) @@ -1389,6 +1391,7 @@ set(RBDOOM3_INCLUDES ) set(RBDOOM3_SOURCES + ${NATVIS_SOURCES} ${AAS_SOURCES} ${CM_SOURCES} ${FRAMEWORK_SOURCES} diff --git a/neo/idStuff.natvis b/neo/idStuff.natvis new file mode 100644 index 00000000..5b4ab57d --- /dev/null +++ b/neo/idStuff.natvis @@ -0,0 +1,63 @@ + + + + + + + + {{Size={num} Capacity={size}}} + + num + size + + num + list + + + + + + {{{x,g},{y,g},{z,g},{w,g}}} + + + + {{{x},{y}}} + + + + {data,s} + + + + {name} + + sprite + edittext + font + text + imageSize + name + + + + + + value.object + value.function + value.string + value.f + value + value.b + value.i + value.i + + + + + [{name}]{value} + + + + [{name}] + + \ No newline at end of file diff --git a/neo/idlib/MapFile_gltf.cpp b/neo/idlib/MapFile_gltf.cpp index 46d48157..93910a94 100644 --- a/neo/idlib/MapFile_gltf.cpp +++ b/neo/idlib/MapFile_gltf.cpp @@ -218,17 +218,14 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); } - mesh->verts[i].color2[0] = vec.x; - mesh->verts[i].color2[1] = vec.y; - mesh->verts[i].color2[2] = vec.z; - mesh->verts[i].color2[3] = vec.w; + mesh->verts[i].SetColor2( PackColor( vec ) ); } break; } case gltfMesh_Primitive_Attribute::Type::Indices: { - idVec4 vec; + idVec4i vec; for( int i = 0; i < attrAcc->count; i++ ) { bin.Read( ( void* )( &vec.x ), attrAcc->typeSize ); diff --git a/neo/idlib/gltfParser.cpp b/neo/idlib/gltfParser.cpp index 41f582c8..0bc5ef6f 100644 --- a/neo/idlib/gltfParser.cpp +++ b/neo/idlib/gltfParser.cpp @@ -2318,7 +2318,7 @@ CONSOLE_COMMAND_COMPILE( LoadGLTF, "Loads an .gltf or .glb file", idCmdSystem::A // not dots allowed in [%s]! -// [filename].[%i|%s].[gltf/glb] +// [filename].[%i|%s].[gltf|glb] bool gltfManager::ExtractIdentifier( idStr& filename, int& id, idStr& name ) { idStr extension; diff --git a/neo/idlib/gltfProperties.h b/neo/idlib/gltfProperties.h index fa01d141..ca2c67c2 100644 --- a/neo/idlib/gltfProperties.h +++ b/neo/idlib/gltfProperties.h @@ -134,6 +134,11 @@ public: gltfNode() : camera( -1 ), skin( -1 ), matrix( mat4_zero ), mesh( -1 ), rotation( 0.f, 0.f, 0.f, 1.f ), scale( 1.f, 1.f, 1.f ), translation( vec3_zero ), parent( nullptr ), dirty( true ) { } + //Only checks name! + bool operator == ( const gltfNode& rhs ) + { + return name == rhs.name; + } int camera; idList children; int skin; @@ -866,23 +871,6 @@ public: return nullptr; } - gltfNode* GetNode( gltfScene* scene, idStr name ) - { - assert( scene ); - assert( name[0] ); - - auto& nodeList = scene->nodes; - for( auto& nodeId : nodeList ) - { - if( nodes[nodeId]->name == name ) - { - return nodes[nodeId]; - } - } - - return nullptr; - } - gltfNode* GetNode( idStr sceneName, int id, idStr* name = nullptr ) { int sceneId = GetSceneId( sceneName ); @@ -913,7 +901,7 @@ public: return nullptr; } - gltfNode* GetNode( idStr sceneName, idStr name , int* id = nullptr ) + gltfNode* GetNode( idStr sceneName, idStr name , int* id = nullptr , bool caseSensitive = false ) { int sceneId = GetSceneId( sceneName ); if( sceneId < 0 || sceneId > scenes.Num() ) @@ -927,9 +915,9 @@ public: assert( name[0] ); auto& nodeList = scene->nodes; - for( auto& nodeId : nodeList ) + for( auto nodeId : nodeList ) { - if( nodes[nodeId]->name.Icmp( name ) == 0 ) + if( caseSensitive ? nodes[nodeId]->name.Cmp( name ) : nodes[nodeId]->name.Icmp( name ) == 0 ) { if( id != nullptr ) { @@ -946,10 +934,10 @@ public: int GetNodeIndex( gltfNode* node ) { int index = -1; - for( auto* node : nodes ) + for( auto& it : nodes ) { index++; - if( node == node ) + if( it == node ) { return index; } @@ -984,19 +972,81 @@ public: return nullptr; } - int GetSceneId( idStr sceneName ) const + int GetSceneId( idStr sceneName , gltfScene* result = nullptr ) const { for( int i = 0; i < scenes.Num(); i++ ) { if( scenes[i]->name == sceneName ) { + if( result != nullptr ) + { + result = scenes[i]; + } + return i; } } return -1; } - idList GetChannelIds( gltfAnimation* anim , gltfNode* node ) + void GetAllMeshes( gltfNode* node, idList& meshIds ) + { + if( node->mesh != -1 ) + { + meshIds.Append( GetNodeIndex( node ) ); + } + + for( auto child : node->children ) + { + GetAllMeshes( nodes[child], meshIds ); + } + } + + gltfSkin* GetSkin( int boneNodeId ) + { + for( auto skin : skins ) + { + if( skin->joints.Find( boneNodeId ) ) + { + return skin; + } + } + + return nullptr; + } + + gltfSkin* GetSkin( gltfAnimation* anim ) + { + auto animTargets = GetAnimTargets( anim ); + + if( !animTargets.Num() ) + { + return nullptr; + } + + for( int nodeID : animTargets ) + { + gltfSkin* foundSkin = GetSkin( nodeID ); + if( foundSkin != nullptr ) + { + return foundSkin; + } + } + + return nullptr; + } + + idList GetAnimTargets( gltfAnimation* anim ) const + { + idList result; + for( auto channel : anim->channels ) + { + result.AddUnique( channel->target.node ); + } + return result; + } + + idList GetChannelIds( gltfAnimation* anim , gltfNode* node ) const { idList result; int channelIdx = 0; @@ -1012,9 +1062,9 @@ public: return result; } - idList GetAnimationIds( gltfNode* node ) + int GetAnimationIds( gltfNode* node , idList& result ) { - idList result; + int animIdx = 0; for( auto anim : animations ) { @@ -1022,13 +1072,16 @@ public: { if( channel->target.node >= 0 && nodes[channel->target.node] == node ) { - result.Append( animIdx ); - break; + result.AddUnique( animIdx ); } } animIdx++; } - return result; + for( int nodeId : node->children ) + { + GetAnimationIds( nodes[nodeId], result ); + } + return result.Num(); } idMat4 GetViewMatrix( int camId ) const diff --git a/neo/idlib/math/Math.h b/neo/idlib/math/Math.h index 2031ac91..50e0b7cc 100644 --- a/neo/idlib/math/Math.h +++ b/neo/idlib/math/Math.h @@ -360,6 +360,8 @@ public: static void Init(); + static float RSqrt( float x ); // reciprocal square root, returns huge number when x == 0.0 + static float InvSqrt( float x ); // inverse square root with 32 bits precision, returns huge number when x == 0.0 static float InvSqrt16( float x ); // inverse square root with 16 bits precision, returns huge number when x == 0.0 @@ -502,6 +504,21 @@ ID_INLINE byte CLAMP_BYTE( int x ) return ( ( x ) < 0 ? ( 0 ) : ( ( x ) > 255 ? 255 : ( byte )( x ) ) ); } + +ID_INLINE float idMath::RSqrt( float x ) +{ + int i; + float y, r; + + y = x * 0.5f; + i = *reinterpret_cast< int* >( &x ); + i = 0x5f3759df - ( i >> 1 ); + r = *reinterpret_cast< float* >( &i ); + r = r * ( 1.5f - r * r * y ); + return r; +} + + /* ======================== idMath::InvSqrt diff --git a/neo/idlib/math/VectorI.h b/neo/idlib/math/VectorI.h index 05f938dc..1b4b9a89 100644 --- a/neo/idlib/math/VectorI.h +++ b/neo/idlib/math/VectorI.h @@ -280,4 +280,258 @@ public: } }; + +//=============================================================== +// +// idVec4i - 4D vector +// +//=============================================================== + +class idVec4i +{ +public: + uint8 x; + uint8 y; + uint8 z; + uint8 w; + + idVec4i( void ); + explicit idVec4i( const uint8 x ) + { + Set( x, x, x, x ); + } + explicit idVec4i( const uint8 x, const uint8 y, const uint8 z, const uint8 w ); + + void Set( const uint8 x, const uint8 y, const uint8 z, const uint8 w ); + void Zero( void ); + + int operator[]( const int index ) const; + uint8& operator[]( const int index ); + idVec4i operator-( ) const; + uint8 operator*( const idVec4i& a ) const; + idVec4i operator*( const uint8 a ) const; + idVec4i operator/( const uint8 a ) const; + idVec4i operator+( const idVec4i& a ) const; + idVec4i operator-( const idVec4i& a ) const; + idVec4i& operator+=( const idVec4i& a ); + idVec4i& operator-=( const idVec4i& a ); + idVec4i& operator/=( const idVec4i& a ); + idVec4i& operator/=( const uint8 a ); + idVec4i& operator*=( const uint8 a ); + + friend idVec4i operator*( const uint8 a, const idVec4i b ); + + idVec4i Multiply( const idVec4i& a ) const; + bool Compare( const idVec4i& a ) const; // exact compare, no epsilon + + bool operator==( const idVec4i& a ) const; // exact compare, no epsilon + bool operator!=( const idVec4i& a ) const; // exact compare, no epsilon + + float Length( void ) const; + float LengthSqr( void ) const; + float Normalize( void ); // returns length + float NormalizeFast( void ); // returns length + + int GetDimension( void ) const; + + const uint8* ToIntPtr( void ) const; + uint8* ToIntPtr( void ); + const char* ToString( int precision = 2 ) const; + + void Lerp( const idVec4i& v1, const idVec4i& v2, const float l ); +}; + + +ID_INLINE idVec4i::idVec4i( void ) { } + +ID_INLINE idVec4i::idVec4i( const uint8 x, const uint8 y, const uint8 z, const uint8 w ) +{ + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +ID_INLINE void idVec4i::Set( const uint8 x, const uint8 y, const uint8 z, const uint8 w ) +{ + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +ID_INLINE void idVec4i::Zero( void ) +{ + x = y = z = w = 0.0f; +} + +ID_INLINE int idVec4i::operator[]( int index ) const +{ + return ( &x )[index]; +} + +ID_INLINE uint8& idVec4i::operator[]( int index ) +{ + return ( &x )[index]; +} + +ID_INLINE idVec4i idVec4i::operator-( ) const +{ + return idVec4i( -x, -y, -z, -w ); +} + +ID_INLINE idVec4i idVec4i::operator-( const idVec4i& a ) const +{ + return idVec4i( x - a.x, y - a.y, z - a.z, w - a.w ); +} + +ID_INLINE uint8 idVec4i::operator*( const idVec4i& a ) const +{ + return x * a.x + y * a.y + z * a.z + w * a.w; +} + +ID_INLINE idVec4i idVec4i::operator*( const uint8 a ) const +{ + return idVec4i( x * a, y * a, z * a, w * a ); +} + +ID_INLINE idVec4i idVec4i::operator/( const uint8 a ) const +{ + float inva = 1.0f / a; + return idVec4i( x * inva, y * inva, z * inva, w * inva ); +} + +ID_INLINE idVec4i operator*( const int a, const idVec4i b ) +{ + return idVec4i( b.x * a, b.y * a, b.z * a, b.w * a ); +} + +ID_INLINE idVec4i idVec4i::operator+( const idVec4i& a ) const +{ + return idVec4i( x + a.x, y + a.y, z + a.z, w + a.w ); +} + +ID_INLINE idVec4i& idVec4i::operator+=( const idVec4i& a ) +{ + x += a.x; + y += a.y; + z += a.z; + w += a.w; + + return *this; +} + +ID_INLINE idVec4i& idVec4i::operator/=( const idVec4i& a ) +{ + x /= a.x; + y /= a.y; + z /= a.z; + w /= a.w; + + return *this; +} + +ID_INLINE idVec4i& idVec4i::operator/=( const uint8 a ) +{ + float inva = 1.0f / a; + x *= inva; + y *= inva; + z *= inva; + w *= inva; + + return *this; +} + +ID_INLINE idVec4i& idVec4i::operator-=( const idVec4i& a ) +{ + x -= a.x; + y -= a.y; + z -= a.z; + w -= a.w; + + return *this; +} + +ID_INLINE idVec4i& idVec4i::operator*=( const uint8 a ) +{ + x *= a; + y *= a; + z *= a; + w *= a; + + return *this; +} + +ID_INLINE idVec4i idVec4i::Multiply( const idVec4i& a ) const +{ + return idVec4i( x * a.x, y * a.y, z * a.z, w * a.w ); +} + +ID_INLINE bool idVec4i::Compare( const idVec4i& a ) const +{ + return ( ( x == a.x ) && ( y == a.y ) && ( z == a.z ) && w == a.w ); +} + +ID_INLINE bool idVec4i::operator==( const idVec4i& a ) const +{ + return Compare( a ); +} + +ID_INLINE bool idVec4i::operator!=( const idVec4i& a ) const +{ + return !Compare( a ); +} + +ID_INLINE float idVec4i::Length( void ) const +{ + return ( float ) idMath::Sqrt( x * x + y * y + z * z + w * w ); +} + +ID_INLINE float idVec4i::LengthSqr( void ) const +{ + return ( x * x + y * y + z * z + w * w ); +} + +ID_INLINE float idVec4i::Normalize( void ) +{ + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z + w * w; + invLength = idMath::InvSqrt( sqrLength ); + x *= invLength; + y *= invLength; + z *= invLength; + w *= invLength; + return invLength * sqrLength; +} + +ID_INLINE float idVec4i::NormalizeFast( void ) +{ + float sqrLength, invLength; + + sqrLength = x * x + y * y + z * z + w * w; + invLength = idMath::RSqrt( sqrLength ); + x *= invLength; + y *= invLength; + z *= invLength; + w *= invLength; + return invLength * sqrLength; +} + +ID_INLINE int idVec4i::GetDimension( void ) const +{ + return 4; +} + +ID_INLINE const uint8* idVec4i::ToIntPtr( void ) const +{ + return &x; +} + +ID_INLINE uint8* idVec4i::ToIntPtr( void ) +{ + return &x; +} + + #endif diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 7041edd9..6fd2c450 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -48,6 +48,8 @@ idCVar gltf_AnimSampleRate( "gltf_AnimSampleRate", "24", CVAR_SYSTEM | CVAR_INTE static const byte GLMB_VERSION = 100; static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << 8 ) | GLMB_VERSION; static const char* GLTF_SnapshotName = "_GLTF_Snapshot_"; +static const idAngles axisTransformAngels = idAngles( 0.0f, 0.0f, 90 ); +static const idMat4 axisTransform( axisTransformAngels.ToMat3( ), vec3_origin ); bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh ) @@ -76,7 +78,7 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData } else { - newTrans = modelNode->matrix; + newTrans = mat4_identity; } for( auto prim : targetMesh->primitives ) @@ -151,10 +153,12 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) rootID = -1; int meshID = -1; name = fileName; + currentSkin = nullptr; + + PurgeModel( ); //FIXME FIXME FIXME - maxJointVertDist = 60; - idStr meshName; + maxJointVertDist = 10; idStr gltfFileName = idStr( fileName ); model_state = DM_STATIC; @@ -178,21 +182,21 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) bounds.Clear(); int sceneId = data->DefaultScene(); - assert( sceneId >= 0 ); + + auto scene = data->SceneList()[sceneId]; + assert( scene ); + + auto nodes = data->NodeList(); + assert( nodes.Num() ); + + //determine root node if( !meshName[0] ) { - //this needs to be fixed to correctly support multiple meshes. - // atm this will only correctlty with static models. - // we could do gltfMeshes a la md5 - // or re-use this class - auto& nodeList = data->NodeList(); - for( auto& nodeID : data->SceneList()[sceneId]->nodes ) - { - gltfNode* modelNode = nodeList[nodeID]; - assert( modelNode ); - ProcessNode( modelNode, mat4_identity, data ); - } + root = new gltfNode(); + root->name = scene->name; + root->children.Append( scene->nodes ); + rootID = -1; fileExclusive = true; } else @@ -201,37 +205,61 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) if( modelNode ) { root = modelNode; - ProcessNode( modelNode, mat4_identity, data ); } - } - if( surfaces.Num( ) <= 0 ) + if( !root ) + { + common->Warning( "Couldn't find model: '%s'", name.c_str( ) ); + MakeDefaultModel( ); + return; + } + + //get allmeshes in hierachy, starting at root. + MeshNodeIds.Clear(); + data->GetAllMeshes( root, MeshNodeIds ); + + //find all animations and bones + bones.Clear( ); + int totalAnims = 0; + for( int meshID : MeshNodeIds ) + { + gltfNode* tmpNode = nodes[meshID]; + int animCount = data->GetAnimationIds( tmpNode , animIds ); + + //check if this model has a skeleton/bones + //if not but it has an anim, create a bone from the target mesh-node as origin. + if( tmpNode->skin >= 0 ) + { + currentSkin = data->SkinList( )[tmpNode->skin]; + assert( currentSkin ); + if( currentSkin->joints.Num() ) + { + bones.Append( currentSkin->joints ); + animCount = data->GetAnimationIds( nodes[bones[0]] , animIds ); + } + } + else if( animCount ) + { + bones.Append( meshID ); + } + + totalAnims += animCount; + } + + hasAnimations = totalAnims > 0; + model_state = hasAnimations ? DM_CACHED : DM_STATIC; + + ProcessNode( root, mat4_identity, data ); + + if( surfaces.Num( ) <= 0 || surfaces.Num( ) != MeshNodeIds.Num( ) ) { common->Warning( "Couldn't load model: '%s'", name.c_str( ) ); MakeDefaultModel( ); return; } - //find all animations - animIds = data->GetAnimationIds( root ); - - hasAnimations = animIds.Num() > 0; - model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; - - //check if this model has a skeleton - if( root->skin >= 0 ) - { - - gltfSkin* skin = data->SkinList( )[root->skin]; - bones = skin->joints; - } - else if( animIds.Num( ) ) - { - bones.Clear( ); - bones.Append( rootID ); - } - + // derive mikktspace tangents from normals FinishSurfaces( true ); @@ -281,7 +309,19 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim } data = gltfParser->currentAsset; - root = data->GetNode( gltf_ModelSceneName.GetString(), rootID ); + if( rootID != -1 ) + { + root = data->GetNode( gltf_ModelSceneName.GetString(), rootID ); + } + else + { + root = new gltfNode(); + root->name = gltf_ModelSceneName.GetString(); + gltfScene scene; + data->GetSceneId( root->name, &scene ); + root->children.Append( scene.nodes ); + } + assert( root ); int animCnt; @@ -321,13 +361,13 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim bones.SetNum( boneCnt ); } else - - + { if( root->skin == -1 && hasAnimations && !bones.Num() ) { bones.Clear( ); bones.Append( rootID ); } + } file->ReadBig( tempNum ); defaultPose.SetNum( tempNum ); @@ -350,9 +390,6 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; - //HVG_TODO: replace bonedata with md5jointData - //UpdateMd5Joints(); - return true; } @@ -361,6 +398,7 @@ void idRenderModelGLTF::UpdateMd5Joints( ) md5joints.Clear(); md5joints.Resize( bones.Num() ); md5joints.SetNum( bones.Num() ); + idStr ovrBoneName; auto& nodeList = data->NodeList(); for( int i = 0 ; i < bones.Num(); i++ ) @@ -368,8 +406,14 @@ void idRenderModelGLTF::UpdateMd5Joints( ) gltfNode* node = nodeList[bones[i]]; //check for TRS anim and its artificial root bone - if( bones.Num() == 1 && node->mesh != -1 ) + if( i == 0 && node->name != "origin" ) { + if( node->mesh == -1 ) + { + common->Warning( "First bone of model is not named \"origin\", name forced!" ); + } + + ovrBoneName = node->name; md5joints[i].name = "origin"; } else @@ -395,9 +439,30 @@ void idRenderModelGLTF::UpdateMd5Joints( ) for( int i = 0 ; i < bones.Num(); i++ ) { gltfNode* node = nodeList[bones[i]]; - if( node->parent ) + if( i && node->parent && node->parent != root ) { - md5joints[i].parent = findMd5Joint( node->parent->name ); + if( node->parent->name == ovrBoneName ) + { + md5joints[i].parent = findMd5Joint( idStr( "origin" ) ); + } + else + { + md5joints[i].parent = findMd5Joint( node->parent->name ); + } + } + } + + if( bones.Num( ) == 1 ) + { + //patch bone indices + for( auto& surf : surfaces ) + { + for( int i = 0; i < surf.geometry->numVerts; i++ ) + { + idDrawVert& base = surf.geometry->verts[i]; + base.SetColor( PackColor( ( vec4_zero ) ) ); + base.SetColor2( PackColor( ( vec4_one / 4 ) ) ); + } } } } @@ -449,48 +514,34 @@ void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const view } } -bool gatherBoneInfo( gltfAnimation* gltfAnim, const idList& nodes , idList& bones, idList& jointInfo ) +bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList& nodes , idList& bones, idList& jointInfo ) { //Gather Bones; bool boneLess = false; - int boneLessTarget = -1; - for( auto channel : gltfAnim->channels ) - { - auto* target = nodes[channel->target.node]; - if( target->mesh != 0 ) - { + int targetNode = -1; - if( boneLessTarget == -1 || boneLessTarget != channel->target.node ) - { - assert( !boneLess ); - } + auto skin = data->GetSkin( gltfAnim ); + auto targets = data->GetAnimTargets( gltfAnim ); - boneLess = true; - boneLessTarget = channel->target.node; - } - else - { - bones.Append( channel->target.node ); - } - } - - if( !bones.Num( ) ) + if( targets.Num( ) == 1 ) { - assert( boneLess ); - } - else - { - assert( bones.Num( ) && !boneLess ); + boneLess = true; + targetNode = targets[0]; } //we cant be sure channels are sorted by bone? if( !boneLess ) { - assert( 0 ); // implement me + if( skin == nullptr ) + { + skin = data->GetSkin( targets[0] ); + } + assert( skin ); + bones.Append( skin->joints ); } else { - bones.Append( boneLessTarget ); + bones.Append( targetNode ); } //create jointInfo @@ -505,14 +556,87 @@ bool gatherBoneInfo( gltfAnimation* gltfAnim, const idList& nodes , i return boneLess; } + +idList GetPose( idList& bones, idJointMat* poseMat ) +{ + idList ret; + ret.AssureSize( bones.Num( ) ); + + for( int i = 0; i < bones.Num( ); i++ ) + { + auto* node = &bones[i]; + + idMat4 trans = mat4_identity; + gltfData::ResolveNodeMatrix( node, &trans, &bones[0] ); + + if( node->parent == nullptr ) + { + node->matrix *= axisTransform; + } + + idJointQuat& pose = ret[i]; + pose.q = ( trans.ToMat3( ).Transpose().ToQuat( ) ); + pose.t = idVec3( trans[0][3], trans[1][3], trans[2][3] ); + pose.w = pose.q.CalcW( ); + } + + for( int i = 0; i < bones.Num( ); i++ ) + { + const gltfNode* joint = &bones[i]; + idJointQuat* pose = &ret[i]; + poseMat[i].SetRotation( pose->q.ToMat3( ) ); + poseMat[i].SetTranslation( pose->t ); + if( joint->parent ) + { + int parentNum = bones.FindIndex( *joint->parent ); + pose->q = ( poseMat[i].ToMat3( ) * poseMat[parentNum].ToMat3( ).Transpose( ) ).ToQuat( ); + pose->t = ( poseMat[i].ToVec3( ) - poseMat[parentNum].ToVec3( ) ) * poseMat[parentNum].ToMat3( ).Transpose( ); + } + } + + return ret; +} +int copyBones( gltfData* data, const idList& bones, idList& out ) +{ + out.Clear(); + + auto nodes = data->NodeList(); + for( auto jointId : bones ) + { + auto* newNode = &out.Alloc(); + *newNode = *nodes[jointId]; + } + + //patch parents + for( auto& bone : out ) + { + bool found = false; + for( int i = 0; i < out.Num( ); i++ ) + { + if( bone.parent && bone.parent->name == out[i].name ) + { + bone.parent = &out[i]; + found = true; + break; + } + } + + if( !found ) + { + bone.parent = nullptr; + } + } + //patch childs! + // -> skipping because not used. + return out.Num(); +} + idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T sourceTimeStamp ) { - ///keep in sync with game. + ///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; - idMat4 axisTransform( idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ), vec3_origin ); - int id; idStr gltfFileName = idStr( animName ); idStr name; @@ -544,10 +668,10 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T idList bones; idList jointInfo; - bool boneLess = gatherBoneInfo( gltfAnim, nodes, bones, jointInfo ); + bool boneLess = gatherBoneInfo( data, gltfAnim, nodes, bones, jointInfo ); - idList frameCounts; + idList> animBones; idList componentFrames; idList baseFrame; @@ -557,21 +681,22 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T int numJoints = bones.Num(); int numAnimatedComponents = 0; + gameLocal.Printf( "Generating MD5Anim for GLTF anim %s from scene %s\n", name.c_str(), gltf_ModelSceneName.GetString() ); + gltfNode* root = nullptr; int channelCount = 0; for( auto channel : gltfAnim->channels ) { - auto& sampler = *gltfAnim->samplers[channel->sampler]; + auto* sampler = gltfAnim->samplers[channel->sampler]; - auto* input = accessors[sampler.input]; - auto* output = accessors[sampler.output]; + auto* input = accessors[sampler->input]; + auto* output = accessors[sampler->output]; auto* target = nodes[channel->target.node]; jointAnimInfo_t* newJoint = &( jointInfo[ bones.FindIndex( channel->target.node ) ] ); idList& timeStamps = data->GetAccessorView( input ); root = target; int frames = timeStamps.Num(); - frameCounts.Append( frames ); if( numFrames != 0 && numFrames != frames ) { @@ -612,10 +737,140 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T channelCount++; } + animBones.AssureSize( numFrames ); + animBones.SetNum( numFrames ); + for( int i = 0; i < numFrames; i++ ) + { + int totalCopied = copyBones( data, bones, animBones[i] ); + assert( totalCopied ); + } + gameLocal.Printf( "Total bones %i \n", bones.Num() ); + + //we can calculate frame rate by: + // max_timestamp_value / totalFrames + // but keeping it fixed for now. frameRate = gltf_AnimSampleRate.GetInteger(); INT animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate; + for( int i = 0; i < jointInfo.Num( ); i++ ) + { + jointAnimInfo_t& j = jointInfo[i]; + idStr jointName = animationLib.JointName( j.nameIndex ); + if( i == 0 && ( jointName != "origin" ) ) + { + gameLocal.Warning( "Renaming bone 0 from %s to %s \n", jointName.c_str(), "origin" ); + jointName = "origin"; + } + } + + baseFrame.SetGranularity( 1 ); + baseFrame.SetNum( bones.Num( ) ); + + gltfSkin* skin = data->GetSkin( gltfAnim );; + gltfAccessor* acc = nullptr; + if( skin != nullptr ) + { + acc = data->AccessorList( )[skin->inverseBindMatrices]; + } + else + { + skin = new gltfSkin; + skin->joints.AssureSize( 1, data->GetNodeIndex( root ) ); + idMat4 trans = mat4_identity; + data->ResolveNodeMatrix( root, &trans ); + acc = new gltfAccessor( ); + acc->matView = new idList( 1 ); + acc->matView->AssureSize( 1, trans.Inverse( ).Transpose( ) ); + } + + idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + baseFrame = GetPose( animBones[0], poseMat ); + + componentFrames.SetGranularity( 1 ); + componentFrames.SetNum( ( ( numAnimatedComponents * numFrames ) ) + 1 ); + int componentFrameIndex = 0; + for( int i = 0; i < numFrames; i++ ) + { + for( auto channel : gltfAnim->channels ) + { + auto sampler = gltfAnim->samplers[channel->sampler]; + + auto* input = accessors[sampler->input]; + auto* output = accessors[sampler->output]; + auto* target = nodes[channel->target.node]; + idList& timeStamps = data->GetAccessorView( input ); + int boneIndex = bones.FindIndex( channel->target.node ); + + switch( channel->target.TRS ) + { + default: + break; + case gltfAnimation_Channel_Target::none: + break; + case gltfAnimation_Channel_Target::rotation: + { + idList& values = data->GetAccessorView( output ); + if( values.Num( ) > i ) + { + animBones[i][boneIndex].rotation = *values[i]; + } + } + break; + case gltfAnimation_Channel_Target::translation: + { + idList& values = data->GetAccessorView( output ); + if( values.Num( ) > i ) + { + animBones[i][boneIndex].translation = *values[i]; + } + } + break; + case gltfAnimation_Channel_Target::scale: + idList& values = data->GetAccessorView( output ); + //animBones[boneIndex].scale = *values[i] ; + break; + } + } + for( int b = 0; b < bones.Num( ); b++ ) + { + auto* node = &animBones[i][b]; + jointAnimInfo_t* joint = &( jointInfo[b] ); + + idQuat q = node->rotation; + idVec3 t = node->translation; + + if( joint->animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) + { + componentFrames[componentFrameIndex++] = t.x; + componentFrames[componentFrameIndex++] = t.y; + componentFrames[componentFrameIndex++] = t.z; + } + if( joint->animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) ) + { + + if( node->parent == nullptr ) + { + q = axisTransformAngels.ToQuat( ) * animBones[i][b].rotation; + } + else + { + q = -animBones[i][b].rotation; + } + + componentFrames[componentFrameIndex++] = q.x; + componentFrames[componentFrameIndex++] = q.y; + componentFrames[componentFrameIndex++] = q.z; + } + } + } + + assert( componentFrames.Num( ) == ( componentFrameIndex + 1 ) ); + + + ////////////////////////////////////////////////////////////////////////// + /// Start writing //////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////// idFile_Memory* file = new idFile_Memory(); file->WriteBig( B_ANIM_MD5_MAGIC ); file->WriteBig( sourceTimeStamp ); @@ -627,18 +882,27 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T file->WriteBig( numAnimatedComponents ); bounds.SetGranularity( 1 ); + bounds.AssureSize( numFrames ); bounds.SetNum( numFrames ); + + idList boundBones; + int totalCopied = copyBones( data, bones, boundBones ); + assert( totalCopied ); + for( int i = 0 ; i < numFrames; i++ ) { - for( int boneId : bones ) + bounds[i].Clear(); + for( int b = 0; b < animBones[i].Num(); b++ ) { - gltfNode* boneNode = nodes[boneId]; - idMat4 trans = mat4_identity; - gltfData::ResolveNodeMatrix( boneNode, &trans ); - trans *= axisTransform; + auto* node = &animBones[i][b]; - bounds[i].AddPoint( idVec3( trans[0][3], trans[1][3], trans[2][3] ) ); + idMat4 trans = mat4_identity; + gltfData::ResolveNodeMatrix( node, &trans, &animBones[i][0] ); + bounds[i].AddPoint( idVec3( trans[0][3], trans[1][3], trans[2][3] ) * axisTransform ); } + //the only way to do this right, is or to calculate the maxVertBoneDist on runtime , + //or pass the mesh entry for the current model decl + bounds[i].ExpandSelf( 10 ); } file->WriteBig( bounds.Num( ) ); @@ -655,26 +919,14 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T { jointAnimInfo_t& j = jointInfo[i]; idStr jointName = animationLib.JointName( j.nameIndex ); + file->WriteString( jointName ); file->WriteBig( j.parentNum ); file->WriteBig( j.animBits ); file->WriteBig( j.firstComponent ); } - baseFrame.SetGranularity( 1 ); - baseFrame.SetNum( bones.Num() ); - - - for( int i = 0 ; i < bones.Num(); i++ ) - { - gltfNode* boneNode = nodes[bones[i]]; - - baseFrame[i].q = boneNode->rotation * idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ).Transpose().ToQuat( ); - baseFrame[i].t = boneNode->translation * axisTransform; - baseFrame[i].w = baseFrame[i].q.CalcW(); - } - - //raw node / skeleton + //base frame file->WriteBig( baseFrame.Num( ) ); for( int i = 0; i < baseFrame.Num( ); i++ ) { @@ -686,103 +938,6 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T file->WriteVec3( j.t ); } - componentFrames.SetGranularity( 1 ); - componentFrames.SetNum( numAnimatedComponents * numFrames * numJoints + 1 ); - componentFrames[numAnimatedComponents * numFrames * numJoints ] = 0.0f; - int componentFrameIndex = 0; - - for( int i = 0 ; i < numFrames; i++ ) - { - - bool hasTranslation = false; - bool hasRotation = false; - bool transDone = false; - bool rotDone = false; - //add weight + scale - - while( !transDone && !rotDone ) - { - idVec3 t = vec3_zero; - idQuat q; - q.w = 1.0f; - - for( auto channel : gltfAnim->channels ) - { - auto& sampler = *gltfAnim->samplers[channel->sampler]; - - auto* input = accessors[sampler.input]; - auto* output = accessors[sampler.output]; - auto* target = nodes[channel->target.node]; - idList& timeStamps = data->GetAccessorView( input ); - jointAnimInfo_t* joint = &( jointInfo[ bones.FindIndex( channel->target.node ) ] ); - hasTranslation |= ( joint->animBits & ANIM_TX || joint->animBits & ANIM_TY || joint->animBits & ANIM_TZ ); - hasRotation |= ( joint->animBits & ANIM_QX || joint->animBits & ANIM_QY || joint->animBits & ANIM_QZ ); - - int targetID = nodes.FindIndex( target ); - - switch( channel->target.TRS ) - { - default: - break; - case gltfAnimation_Channel_Target::none: - break; - case gltfAnimation_Channel_Target::rotation: - { - idList& values = data->GetAccessorView( output ); - if( values.Num() > i ) - { - q = *values[i]; - } - rotDone = true; - } - break; - case gltfAnimation_Channel_Target::translation: - { - idList& values = data->GetAccessorView( output ); - if( values.Num() > i ) - { - t = *values[i]; - } - transDone = true; - } - break; - case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf - break; - } - - if( !transDone ) - { - transDone = !hasTranslation; - } - if( !rotDone ) - { - rotDone = !hasRotation; - } - } - - if( rotDone && transDone ) - { - if( hasTranslation ) - { - t *= axisTransform; - componentFrames[componentFrameIndex++] = t.x; - componentFrames[componentFrameIndex++] = t.y; - componentFrames[componentFrameIndex++] = t.z; - } - if( hasRotation ) - { - q *= idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ).Transpose().ToQuat( ); - idVec3 rot = q.ToRotation().GetVec(); - componentFrames[componentFrameIndex++] = q.x; - componentFrames[componentFrameIndex++] = q.y; - componentFrames[componentFrameIndex++] = q.z; - } - break; - } - } - } - - assert( componentFrames.Num() == ( componentFrameIndex + 1 ) ); //per joint timestamp values, T R file->WriteBig( componentFrames.Num( ) - 1 ); for( int i = 0; i < componentFrames.Num( ); i++ ) @@ -850,7 +1005,7 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /* { idRenderModelStatic::WriteBinaryModel( file ); - if( file == NULL || root == nullptr ) + if( file == NULL ) { return; } @@ -906,83 +1061,33 @@ void idRenderModelGLTF::PurgeModel() purged = true; md5joints.Clear( ); defaultPose.Clear( ); - meshes.Clear( ); -} + invertedDefaultPose.Clear(); -idList getSkinningMatrix( gltfData* data, gltfSkin* skin, gltfAccessor* acc ) -{ - idMat4 world = mat4_identity; - idList values = data->GetAccessorViewMat( acc ); + animIds.Clear(); + bones.Clear(); + MeshNodeIds.Clear(); - auto& nodeList = data->NodeList( ); - int count = 0; - - if( skin->skeleton == -1 ) + //if no root id was set, it is a generated one. + if( rootID == -1 && root ) { - skin->skeleton = skin->joints[0]; + delete root; } - - for( int joint : skin->joints ) - { - world = mat4_identity; - auto* node = nodeList[joint]; - idMat4* bindMat = &values[count]; - bindMat->TransposeSelf( ); - data->ResolveNodeMatrix( node, &world ); - *bindMat = world * *bindMat; - bindMat->TransposeSelf( ); - count++; - } - return values; } void idRenderModelGLTF::LoadModel() { - int meshID; - idStr meshName; - idStr gltfFileName = idStr( name ); - - gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName ); - - if( gltfParser->currentFile.Length( ) ) - { - if( gltfParser->currentAsset && gltfParser->currentFile != gltfFileName ) - { - common->FatalError( "multiple GLTF file loading not supported" ); - } - } - else - { - if( !gltfParser->Load( gltfFileName ) ) - { - MakeDefaultModel( ); - return; - } - } - - timeStamp = fileSystem->GetTimestamp( gltfFileName ); - int num; - int parentNum; - - if( !purged ) - { - PurgeModel( ); - } - - purged = false; gltfData* data = gltfParser->currentAsset; auto& accessors = data->AccessorList( ); auto& nodes = data->NodeList( ); gltfNode* meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); - auto animList = data->GetAnimationIds( meshRoot ); gltfSkin* skin = nullptr; gltfAccessor* acc = nullptr; - if( meshRoot->skin != -1 ) + if( currentSkin != nullptr ) { - skin = data->SkinList( )[meshRoot->skin]; + skin = currentSkin; acc = data->AccessorList( )[skin->inverseBindMatrices]; } else @@ -996,12 +1101,9 @@ void idRenderModelGLTF::LoadModel() acc->matView->AssureSize( 1, trans.Inverse() ); } - auto basepose = getSkinningMatrix( data, skin, acc ); - - if( meshRoot->skin == -1 ) + if( skin && skin->skeleton == -1 ) { - delete skin; - delete acc; + skin->skeleton = skin->joints[0]; } num = bones.Num(); @@ -1015,7 +1117,7 @@ void idRenderModelGLTF::LoadModel() gltfNode* node = nodes[bones[i]]; //check for TRS anim and its artficial root bone - if( bones.Num( ) == 1 && node->mesh != -1 ) + if( bones.Num( ) == 0 && node->mesh != -1 ) { md5joints[i].name = "origin"; } @@ -1039,38 +1141,28 @@ void idRenderModelGLTF::LoadModel() return &staticJoint; }; - idAngles axisTransformAngels = idAngles( 0.0f, 0.0f, 90.0f ); - idMat4 axisTransform( axisTransformAngels.ToMat3( ), vec3_origin ); for( int i = 0; i < bones.Num( ); i++ ) { - gltfNode* node = nodes[bones[i]]; - if( node->parent ) + auto* node = nodes[bones[i]]; + + if( i && node->parent && node->parent != root ) { md5joints[i].parent = findMd5Joint( node->parent->name ); } - idJointQuat& pose = defaultPose[i]; - pose.q = node->rotation; - pose.t = node->translation; } - idJointMat* poseMat = ( idJointMat* ) _alloca16( md5joints.Num( ) * sizeof( poseMat[0] ) ); - for( int i = 0; i < md5joints.Num( ); i++ ) + idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + idList animBones; + int totalCopied = copyBones( data, bones, animBones ); + defaultPose = GetPose( animBones, poseMat ); + + if( !currentSkin ) { - idMD5Joint* joint = &md5joints[i]; - idJointQuat* pose = &defaultPose[i]; - - poseMat[i].SetRotation( pose->q.ToMat3() * axisTransformAngels.ToMat3( ).Transpose() ); - poseMat[i].SetTranslation( pose->t * axisTransform ); - if( joint->parent ) - { - parentNum = joint->parent - md5joints.Ptr( ); - pose->q = ( poseMat[i].ToMat3( ) * poseMat[parentNum].ToMat3( ).Transpose( ) ).ToQuat( ); - pose->t = ( poseMat[i].ToVec3( ) - poseMat[parentNum].ToVec3( ) ) * poseMat[parentNum].ToMat3( ).Transpose( ); - } + delete skin; + delete acc; } - //----------------------------------------- // create the inverse of the base pose joints to support tech6 style deformation // of base pose vertexes, normals, and tangents. @@ -1087,14 +1179,16 @@ void idRenderModelGLTF::LoadModel() SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); - //deformInfo = R_BuildDeformInfo( texCoords.Num( ), basePose, tris.Num( ), tris.Ptr( ), + //auto deformInfo = R_BuildDeformInfo( texCoords.Num( ), basePose, tris.Num( ), tris.Ptr( ), // shader->UseUnsmoothedTangents( ) ); - model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; + model_state = hasAnimations ? DM_CACHED : DM_STATIC; // set the timestamp for reloadmodels fileSystem->ReadFile( name, NULL, &timeStamp ); + purged = false; + common->UpdateLevelLoadPacifier( ); } @@ -1108,18 +1202,20 @@ void idRenderModelGLTF::TouchData() void idRenderModelGLTF::Print() const { - common->Warning( "The method or operation is not implemented." ); + idRenderModelStatic::Print(); + // TODO } void idRenderModelGLTF::List() const { - common->Warning( "The method or operation is not implemented." ); + idRenderModelStatic::List(); + // TODO } int idRenderModelGLTF::Memory() const { - common->Warning( "The method or operation is not implemented." ); - return -1; + return idRenderModelStatic::Memory(); + // TODO } dynamicModel_t idRenderModelGLTF::IsDynamicModel() const @@ -1129,17 +1225,30 @@ dynamicModel_t idRenderModelGLTF::IsDynamicModel() const void TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts, const idDrawVert* baseVerts, const idJointMat* joints ) { - idJointMat trans = joints[0]; - //add skinning for( int i = 0; i < numVerts; i++ ) { const idDrawVert& base = baseVerts[i]; - targetVerts[i].xyz = trans * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); - targetVerts[i].SetNormal( trans * baseVerts[i].GetNormal( ) ); - float t3 = base.tangent[3]; - targetVerts[i].SetTangent( trans * base.GetTangent( ) ); - targetVerts[i].tangent[3] = t3; + const idJointMat& j0 = joints[base.color[0]]; + const idJointMat& j1 = joints[base.color[1]]; + const idJointMat& j2 = joints[base.color[2]]; + const idJointMat& j3 = joints[base.color[3]]; + + const float w0 = base.color2[0] * ( 1.0f / 255.0f ); + const float w1 = base.color2[1] * ( 1.0f / 255.0f ); + const float w2 = base.color2[2] * ( 1.0f / 255.0f ); + const float w3 = base.color2[3] * ( 1.0f / 255.0f ); + + idJointMat accum; + idJointMat::Mul( accum, j0, w0 ); + idJointMat::Mad( accum, j1, w1 ); + idJointMat::Mad( accum, j2, w2 ); + idJointMat::Mad( accum, j3, w3 ); + + targetVerts[i].xyz = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); + targetVerts[i].SetNormal( accum * base.GetNormal( ) ); + targetVerts[i].SetTangent( accum * base.GetTangent( ) ); + targetVerts[i].tangent[3] = base.tangent[3]; } } @@ -1182,11 +1291,11 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i if( r_useGPUSkinning.GetBool( ) && glConfig.gpuSkinningAvailable ) { - if( tri->verts != NULL && tri->verts != sourceSurf.geometry->verts ) + if( tri->verts != NULL && tri->verts != verts ) { R_FreeStaticTriSurfVerts( tri ); } - tri->verts = sourceSurf.geometry->verts; + tri->verts = verts; tri->ambientCache = sourceSurf.geometry->ambientCache; tri->shadowCache = sourceSurf.geometry->shadowCache; tri->referencedVerts = true; @@ -1203,11 +1312,14 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i } TransformVertsAndTangents_GLTF( tri->verts, numVerts, verts, entJointsInverted ); - tri->tangentsCalculated = true; } + tri->tangentsCalculated = true; + //fix this. + //only vs root bone is checked. + //now, this is not the biggest issue, there is something wrong with the bounds for the gltfmodel in general. + // it did work for non skinned models, it broke somewhere down the line. #if defined(USE_INTRINSICS_SSE) - __m128 minX = vector_float_posInfinity; __m128 minY = vector_float_posInfinity; __m128 minZ = vector_float_posInfinity; @@ -1534,5 +1646,11 @@ int idRenderModelGLTF::NearestJoint( int surfaceNum, int a, int b, int c ) const idBounds idRenderModelGLTF::Bounds( const struct renderEntity_s* ent ) const { - return bounds; + if( ent == NULL ) + { + // this is the bounds for the reference pose + return bounds; + } + + return ent->bounds; } diff --git a/neo/renderer/Model_gltf.h b/neo/renderer/Model_gltf.h index 16dabd6f..b1025eb2 100644 --- a/neo/renderer/Model_gltf.h +++ b/neo/renderer/Model_gltf.h @@ -68,16 +68,14 @@ private: float maxJointVertDist; // maximum distance a vertex is separated from a joint idList animIds; idList bones; + idList MeshNodeIds; dynamicModel_t model_state; - idList SkeletonNodes; + idStr meshName; idList md5joints; idList defaultPose; idList invertedDefaultPose; - idList meshes; - deformInfo_t* deformInfo; - - MapPolygonMesh* mesh; + gltfSkin* currentSkin; private: void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view ); }; \ No newline at end of file From c5f8af3b6615369935c764e4e97553c010df08dc Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 31 Jul 2022 21:37:42 +0200 Subject: [PATCH 03/16] corrected sw skinning bounds --- neo/renderer/Model_gltf.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 6fd2c450..e92fa220 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -1223,8 +1223,9 @@ dynamicModel_t idRenderModelGLTF::IsDynamicModel() const return model_state; } -void TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts, const idDrawVert* baseVerts, const idJointMat* joints ) +idList TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts, const idDrawVert* baseVerts, const idJointMat* joints ) { + idList jointIds; for( int i = 0; i < numVerts; i++ ) { const idDrawVert& base = baseVerts[i]; @@ -1234,6 +1235,11 @@ void TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts const idJointMat& j2 = joints[base.color[2]]; const idJointMat& j3 = joints[base.color[3]]; + for (int j = 0; j < 4; j++ ) + { + jointIds.AddUnique(base.color[0]); + } + const float w0 = base.color2[0] * ( 1.0f / 255.0f ); const float w1 = base.color2[1] * ( 1.0f / 255.0f ); const float w2 = base.color2[2] * ( 1.0f / 255.0f ); @@ -1249,7 +1255,9 @@ void TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts targetVerts[i].SetNormal( accum * base.GetNormal( ) ); targetVerts[i].SetTangent( accum * base.GetTangent( ) ); targetVerts[i].tangent[3] = base.tangent[3]; + } + return jointIds; } void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf ) @@ -1289,6 +1297,8 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i tri->numVerts = numVerts; + idList jointIds; + if( r_useGPUSkinning.GetBool( ) && glConfig.gpuSkinningAvailable ) { if( tri->verts != NULL && tri->verts != verts ) @@ -1311,14 +1321,10 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i tri->referencedVerts = false; } - TransformVertsAndTangents_GLTF( tri->verts, numVerts, verts, entJointsInverted ); + jointIds = TransformVertsAndTangents_GLTF( tri->verts, numVerts, verts, entJointsInverted ); } tri->tangentsCalculated = true; - //fix this. - //only vs root bone is checked. - //now, this is not the biggest issue, there is something wrong with the bounds for the gltfmodel in general. - // it did work for non skinned models, it broke somewhere down the line. #if defined(USE_INTRINSICS_SSE) __m128 minX = vector_float_posInfinity; __m128 minY = vector_float_posInfinity; @@ -1326,9 +1332,9 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i __m128 maxX = vector_float_negInfinity; __m128 maxY = vector_float_negInfinity; __m128 maxZ = vector_float_negInfinity; - for( int i = 0; i < numVerts; i++ ) + for( int i = 0; i < jointIds.Num(); i++ ) { - const idJointMat& joint = entJoints[0]; + const idJointMat& joint = entJoints[i]; __m128 x = _mm_load_ps( joint.ToFloatPtr( ) + 0 * 4 ); __m128 y = _mm_load_ps( joint.ToFloatPtr( ) + 1 * 4 ); __m128 z = _mm_load_ps( joint.ToFloatPtr( ) + 2 * 4 ); From b6bccf19d085a9fbbbc52bae509eb4ac6d9366f3 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Mon, 1 Aug 2022 22:05:13 +0200 Subject: [PATCH 04/16] Fixed gltf animation bounds. --- neo/renderer/Model_gltf.cpp | 92 +++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index e92fa220..2b2db00f 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -50,7 +50,7 @@ static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << static const char* GLTF_SnapshotName = "_GLTF_Snapshot_"; static const idAngles axisTransformAngels = idAngles( 0.0f, 0.0f, 90 ); static const idMat4 axisTransform( axisTransformAngels.ToMat3( ), vec3_origin ); - +static idRenderModelGLTF* lastMeshFromFile = nullptr; bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh ) { @@ -259,7 +259,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) return; } - + // derive mikktspace tangents from normals FinishSurfaces( true ); @@ -267,7 +267,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) UpdateMd5Joints(); // it is now available for use - + lastMeshFromFile = this; } bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp ) @@ -390,6 +390,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; + lastMeshFromFile = this; return true; } @@ -556,7 +557,6 @@ bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList GetPose( idList& bones, idJointMat* poseMat ) { idList ret; @@ -596,6 +596,7 @@ idList GetPose( idList& bones, idJointMat* poseMat ) return ret; } + int copyBones( gltfData* data, const idList& bones, idList& out ) { out.Clear(); @@ -725,11 +726,11 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T break; case gltfAnimation_Channel_Target::rotation: newJoint->animBits |= ANIM_QX | ANIM_QY | ANIM_QZ; - numAnimatedComponents += 3;// * frames; + numAnimatedComponents += 3; break; case gltfAnimation_Channel_Target::translation: newJoint->animBits |= ANIM_TX | ANIM_TY | ANIM_TZ; - numAnimatedComponents += 3;// * frames; + numAnimatedComponents += 3; break; case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf break; @@ -867,6 +868,59 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T assert( componentFrames.Num( ) == ( componentFrameIndex + 1 ) ); + bounds.SetGranularity( 1 ); + bounds.AssureSize( numFrames ); + bounds.SetNum( numFrames ); + //do software skinning to determine bounds. + idJointMat* currJoints = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + for( int i = 0; i < numFrames; i++ ) + { + bounds[i].Clear( ); + + idList joints; + GetPose( animBones[i], currJoints ); + for( int b = 0; b < animBones[i].Num( ); b++ ) + { + idJointMat mat = poseMat[b]; + mat.Invert( ); + idJointMat::Multiply( joints.Alloc( ), currJoints[b], mat ); + } + + // an mesh entry _should_ always be before an anim entry! + // use those verts as base. + if( lastMeshFromFile != nullptr ) + { + for( modelSurface_t& surf : lastMeshFromFile->surfaces ) + { + idDrawVert* verts = surf.geometry->verts; + int numVerts = surf.geometry->numVerts; + + for( int v = 0; v < numVerts; v++ ) + { + const idDrawVert& base = verts[v]; + + const idJointMat& j0 = joints[base.color[0]]; + const idJointMat& j1 = joints[base.color[1]]; + const idJointMat& j2 = joints[base.color[2]]; + const idJointMat& j3 = joints[base.color[3]]; + + const float w0 = base.color2[0] * ( 1.0f / 255.0f ); + const float w1 = base.color2[1] * ( 1.0f / 255.0f ); + const float w2 = base.color2[2] * ( 1.0f / 255.0f ); + const float w3 = base.color2[3] * ( 1.0f / 255.0f ); + + idJointMat accum; + idJointMat::Mul( accum, j0, w0 ); + idJointMat::Mad( accum, j1, w1 ); + idJointMat::Mad( accum, j2, w2 ); + idJointMat::Mad( accum, j3, w3 ); + + idVec3 pos = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); + bounds[i].AddPoint( pos ); + } + } + } + } ////////////////////////////////////////////////////////////////////////// /// Start writing //////////////////////////////////////////////////////// @@ -881,29 +935,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T file->WriteBig( numJoints ); file->WriteBig( numAnimatedComponents ); - bounds.SetGranularity( 1 ); - bounds.AssureSize( numFrames ); - bounds.SetNum( numFrames ); - idList boundBones; - int totalCopied = copyBones( data, bones, boundBones ); - assert( totalCopied ); - for( int i = 0 ; i < numFrames; i++ ) - { - bounds[i].Clear(); - for( int b = 0; b < animBones[i].Num(); b++ ) - { - auto* node = &animBones[i][b]; - - idMat4 trans = mat4_identity; - gltfData::ResolveNodeMatrix( node, &trans, &animBones[i][0] ); - bounds[i].AddPoint( idVec3( trans[0][3], trans[1][3], trans[2][3] ) * axisTransform ); - } - //the only way to do this right, is or to calculate the maxVertBoneDist on runtime , - //or pass the mesh entry for the current model decl - bounds[i].ExpandSelf( 10 ); - } file->WriteBig( bounds.Num( ) ); for( int i = 0; i < bounds.Num( ); i++ ) @@ -1178,7 +1211,6 @@ void idRenderModelGLTF::LoadModel() } SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); - //auto deformInfo = R_BuildDeformInfo( texCoords.Num( ), basePose, tris.Num( ), tris.Ptr( ), // shader->UseUnsmoothedTangents( ) ); @@ -1235,9 +1267,9 @@ idList TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int n const idJointMat& j2 = joints[base.color[2]]; const idJointMat& j3 = joints[base.color[3]]; - for (int j = 0; j < 4; j++ ) + for( int j = 0; j < 4; j++ ) { - jointIds.AddUnique(base.color[0]); + jointIds.AddUnique( base.color[0] ); } const float w0 = base.color2[0] * ( 1.0f / 255.0f ); From 7e7ee22f3baaca2f4c80de387b2b352046b1486c Mon Sep 17 00:00:00 2001 From: HarrievG Date: Wed, 3 Aug 2022 02:14:06 +0200 Subject: [PATCH 05/16] AAS support for MapPolygonMehses --- neo/idlib/MapFile.cpp | 1 + neo/tools/compilers/aas/AASBuild.cpp | 116 +++++++++++++++++++++++ neo/tools/compilers/aas/AASBuild_local.h | 3 + 3 files changed, 120 insertions(+) diff --git a/neo/idlib/MapFile.cpp b/neo/idlib/MapFile.cpp index f7ef3189..95b85b26 100644 --- a/neo/idlib/MapFile.cpp +++ b/neo/idlib/MapFile.cpp @@ -5,6 +5,7 @@ Doom 3 BFG Edition GPL Source Code Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. Copyright (C) 2015-2022 Robert Beckebans Copyright (C) 2020 Admer (id Tech Fox) +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"). diff --git a/neo/tools/compilers/aas/AASBuild.cpp b/neo/tools/compilers/aas/AASBuild.cpp index d294145b..528d407a 100644 --- a/neo/tools/compilers/aas/AASBuild.cpp +++ b/neo/tools/compilers/aas/AASBuild.cpp @@ -3,6 +3,8 @@ Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. +Copyright (C) 2022 Harrie van Ginneken +Copyright (C) 2022 Robert Beckebans This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). @@ -417,6 +419,115 @@ idBrushList idAASBuild::AddBrushesForMapBrush( const idMapBrush* mapBrush, const return brushList; } +/* +============ +idAASBuild::AddBrushesForMapPolygonMesh +============ +*/ + +idBrushList idAASBuild::AddBrushesForMapPolygonMesh( const MapPolygonMesh* mapMesh, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ) +{ + int contents = 0; + int validBrushes = 0; + + idFixedWinding w; + idPlane plane; + idVec3 d1, d2; + idBrush* brush; + const idMaterial* mat; + + //per map polygon + for( int p = 0 ; p < mapMesh->GetNumPolygons(); p++ ) + { + const MapPolygon& face = mapMesh->GetFace( p ); + + mat = declManager->FindMaterial( face.GetMaterial() ); + contents = ContentsForAAS( mat->GetContentFlags( ) ); + + if( !contents ) + { + return brushList; + } + + const idList& verts = mapMesh->GetDrawVerts( ); + const idList& indices = face.GetIndexes( ); + + idVec3 triNormal; + int v1 = 0; + int v2 = 1; + int v3 = 2; + + //create brush with 2 triangles + // 1 frontface from the mappoly verts + // 1 backface, offset in direction off frontface normal at unit distance + + //Front face + d1 = verts[indices[1]].xyz - verts[indices[0]].xyz; + d2 = verts[indices[2]].xyz - verts[indices[0]].xyz; + plane.SetNormal( d1.Cross( d2 ) ); + if( plane.Normalize( ) != 0.0f ) + { + plane.FitThroughPoint( verts[indices[2]].xyz ); + + w.Clear( ); + w += verts[indices[0]].xyz; + w += verts[indices[1]].xyz; + w += verts[indices[2]].xyz; + + brush = new idBrush( ); + brush->SetContents( contents ); + if( brush->FromWinding( w, plane ) ) + { + brush->SetEntityNum( entityNum ); + brush->SetPrimitiveNum( primitiveNum ); + brush->SetFlag( BFL_PATCH ); + brush->Transform( origin, axis ); + brushList.AddToTail( brush ); + validBrushes++; + } + else + { + delete brush; + } + } + + //Back face + triNormal = plane.Normal(); + plane.SetNormal( d2.Cross( d1 ) ); + if( plane.Normalize( ) != 0.0f ) + { + plane.FitThroughPoint( verts[indices[0]].xyz ); + + w.Clear( ); + w += verts[indices[2]].xyz + triNormal; + w += verts[indices[1]].xyz + triNormal; + w += verts[indices[0]].xyz + triNormal; + + brush = new idBrush( ); + brush->SetContents( contents ); + if( brush->FromWinding( w, plane ) ) + { + brush->SetEntityNum( entityNum ); + brush->SetPrimitiveNum( primitiveNum ); + brush->SetFlag( BFL_PATCH ); + brush->Transform( origin, axis ); + brushList.AddToTail( brush ); + validBrushes++; + } + else + { + delete brush; + } + } + } + + if( !validBrushes ) + { + common->Warning( "map polygon primitive %d on entity %d is completely degenerate", primitiveNum, entityNum ); + } + + return brushList; +} /* ============ @@ -613,6 +724,11 @@ idBrushList idAASBuild::AddBrushesForMapEntity( const idMapEntity* mapEnt, int e } continue; } + //HVG: Map polygon mesh support + if( mapPrim->GetType( ) == idMapPrimitive::TYPE_MESH ) + { + brushList = AddBrushesForMapPolygonMesh( static_cast< MapPolygonMesh* >( mapPrim ), origin, axis, entityNum, i, brushList ); + } } return brushList; diff --git a/neo/tools/compilers/aas/AASBuild_local.h b/neo/tools/compilers/aas/AASBuild_local.h index dd1b42e3..d0907d63 100644 --- a/neo/tools/compilers/aas/AASBuild_local.h +++ b/neo/tools/compilers/aas/AASBuild_local.h @@ -3,6 +3,8 @@ Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. +Copyright (C) 2022 Harrie van Ginneken +Copyright (C) 2022 Robert Beckebans This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?). @@ -104,6 +106,7 @@ private: // map loading int ContentsForAAS( int contents ); idBrushList AddBrushesForMapBrush( const idMapBrush* mapBrush, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ); idBrushList AddBrushesForMapPatch( const idMapPatch* mapPatch, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ); + idBrushList AddBrushesForMapPolygonMesh( const MapPolygonMesh* mapMesh, const idVec3& origin, const idMat3& axis, int entityNum, int primitiveNum, idBrushList brushList ); idBrushList AddBrushesForMapEntity( const idMapEntity* mapEnt, int entityNum, idBrushList brushList ); idBrushList AddBrushesForMapFile( const idMapFile* mapFile, idBrushList brushList ); bool CheckForEntities( const idMapFile* mapFile, idStrList& entityClassNames ) const; From b41411f8d0ba4c73da01c2dc429da276d7005aea Mon Sep 17 00:00:00 2001 From: HarrievG Date: Wed, 3 Aug 2022 21:44:42 +0200 Subject: [PATCH 06/16] Fixed axis conversion for gltfModels with animated translations --- neo/renderer/Model_gltf.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 2b2db00f..7f6978e6 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -829,7 +829,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T break; case gltfAnimation_Channel_Target::scale: idList& values = data->GetAccessorView( output ); - //animBones[boneIndex].scale = *values[i] ; + animBones[i][boneIndex].scale = *values[i] ; break; } } @@ -843,6 +843,11 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T if( joint->animBits & ( ANIM_TX | ANIM_TY | ANIM_TZ ) ) { + if( node->parent == nullptr ) + { + t = axisTransform * t; + } + componentFrames[componentFrameIndex++] = t.x; componentFrames[componentFrameIndex++] = t.y; componentFrames[componentFrameIndex++] = t.z; @@ -871,12 +876,21 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T bounds.SetGranularity( 1 ); bounds.AssureSize( numFrames ); bounds.SetNum( numFrames ); + //do software skinning to determine bounds. idJointMat* currJoints = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); for( int i = 0; i < numFrames; i++ ) { bounds[i].Clear( ); + for( int b = 0; b < animBones[i].Num( ); b++ ) + { + if( animBones[i][b].parent == nullptr ) + { + animBones[i][b].translation = axisTransform * animBones[i][b].translation; + } + } + idList joints; GetPose( animBones[i], currJoints ); for( int b = 0; b < animBones[i].Num( ); b++ ) From 2ef1fe3ce2e37c3a1da2e8b7e1d0fbccbee9b19e Mon Sep 17 00:00:00 2001 From: HarrievG Date: Thu, 4 Aug 2022 01:40:59 +0200 Subject: [PATCH 07/16] idRenderModelGLTF::NearestJoint --- neo/renderer/Model_gltf.cpp | 58 ++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 7f6978e6..6acd6afa 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -1560,12 +1560,6 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn { staticModel = new( TAG_MODEL ) idRenderModelStatic; staticModel->InitEmpty( GLTF_SnapshotName ); - - //idStr prevName = name; - //name = GLTF_SnapshotName; - ////surfaces = surfaces; - //*staticModel = *this; - //name = prevName; staticModel->jointsInverted = NULL;; } @@ -1637,10 +1631,6 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn int idRenderModelGLTF::NumJoints() const { - if( !root ) - { - common->FatalError( "Trying to determine Joint count without a model node loaded" ); - } return bones.Num(); } @@ -1690,10 +1680,52 @@ const idJointQuat* idRenderModelGLTF::GetDefaultPose() const int idRenderModelGLTF::NearestJoint( int surfaceNum, int a, int b, int c ) const { + for( modelSurface_t& surf : surfaces ) + { + idDrawVert* verts = surf.geometry->verts; + int numVerts = surf.geometry->numVerts; - ///this needs to be implemented for correct traces - common->Warning( "The method or operation is not implemented." ); - return -1; + for( int v = 0; v < numVerts; v++ ) + { + // duplicated vertices might not have weights + int vertNum; + if( a >= 0 && a < numVerts ) + { + vertNum = a; + } + else if( b >= 0 && b < numVerts ) + { + vertNum = b; + } + else if( c >= 0 && c < numVerts ) + { + vertNum = c; + } + else + { + // all vertices are duplicates which shouldn't happen + return 0; + } + + const idDrawVert& vert = verts[vertNum]; + + int bestWeight = 0; + int bestJoint = 0; + for( int i = 0; i < 4; i++ ) + { + if( vert.color2[i] > bestWeight ) + { + bestWeight = vert.color2[i]; + bestJoint = vert.color[i]; + } + } + + return bestJoint; + } + } + + common->Warning( "Couldn't find NearestJoint for : '%s'", name.c_str( ) ); + return 0; } idBounds idRenderModelGLTF::Bounds( const struct renderEntity_s* ent ) const From 8e889c180431ba36fc601fff227d5125ec1d7d05 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sat, 6 Aug 2022 20:43:25 +0200 Subject: [PATCH 08/16] Fixed non Simdpath for idRenderModelGLTF::UpdateSurface --- neo/renderer/Model_gltf.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 6acd6afa..c85a052f 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -1406,11 +1406,10 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i _mm_store_ss( tri->bounds.ToFloatPtr( ) + 5, _mm_splat_ps( maxZ, 3 ) ); #else - bounds.Clear( ); - for( int i = 0; i < numMeshJoints; i++ ) + for( int i = 0; i < jointIds.Num( ); i++ ) { - const idJointMat& joint = entJoints[meshJoints[i]]; + const idJointMat& joint = entJoints[i]; bounds.AddPoint( joint.GetTranslation( ) ); } bounds.ExpandSelf( maxJointVertDist ); From d0ff0a7f64f7e3628f39fefdfa088c9a466f58b3 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 7 Aug 2022 15:05:14 +0200 Subject: [PATCH 09/16] Dont load GLTF data when loading bglb/bgltf --- neo/renderer/Model_gltf.cpp | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index c85a052f..578b3698 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -275,13 +275,6 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim hasAnimations = false; fileExclusive = false; // not written. root = nullptr; - - //we should still load the scene information ? - if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) - { - return false; - } - unsigned int magic = 0; file->ReadBig( magic ); @@ -296,34 +289,6 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim idStr dataFilename; file->ReadString( dataFilename ); - if( gltfParser->currentFile.Length( ) ) - { - if( gltfParser->currentAsset && gltfParser->currentFile != dataFilename ) - { - common->FatalError( "multiple GLTF file loading not supported" ); - } - } - else - { - gltfParser->Load( dataFilename ); - } - - data = gltfParser->currentAsset; - if( rootID != -1 ) - { - root = data->GetNode( gltf_ModelSceneName.GetString(), rootID ); - } - else - { - root = new gltfNode(); - root->name = gltf_ModelSceneName.GetString(); - gltfScene scene; - data->GetSceneId( root->name, &scene ); - root->children.Append( scene.nodes ); - } - - assert( root ); - int animCnt; file->ReadBig( animCnt ); if( animCnt > 0 ) @@ -362,7 +327,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim } else { - if( root->skin == -1 && hasAnimations && !bones.Num() ) + if( hasAnimations && !bones.Num() ) { bones.Clear( ); bones.Append( rootID ); From ecaf297ef6e940557b88dfaf6117990f9b4c9437 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 7 Aug 2022 15:56:46 +0200 Subject: [PATCH 10/16] Allow for multple GLTF/GLB to be loaded at the same time. --- neo/idlib/gltfParser.cpp | 21 +++++++++------------ neo/idlib/gltfProperties.h | 30 +++++++++++++++++++----------- neo/renderer/Model_gltf.cpp | 32 ++++++++------------------------ 3 files changed, 36 insertions(+), 47 deletions(-) diff --git a/neo/idlib/gltfParser.cpp b/neo/idlib/gltfParser.cpp index 0bc5ef6f..0c218b5a 100644 --- a/neo/idlib/gltfParser.cpp +++ b/neo/idlib/gltfParser.cpp @@ -1948,7 +1948,7 @@ bool GLTF_Parser::loadGLB( idStr filename ) unsigned int chunk_type = 0; // 4 bytes unsigned int chunk_length = 0; // 4 bytes byte* data = nullptr; - gltfData* dataCache = gltfData::Data( filename ); + gltfData* dataCache = gltfData::Data( filename, true ); currentAsset = dataCache; int chunkCount = 0; @@ -2074,21 +2074,18 @@ bool GLTF_Parser::Parse() bool GLTF_Parser::Load( idStr filename ) { - //seriously fix this; proper gltf data cache. - //.. and destroy it properly too!! - static idStr lastFile = ""; - //next line still has to be fixed. - //gfx is not updated on command - common->SetRefreshOnPrint( true ); + //.. and destroy data !! - if( lastFile == filename ) + gltfData* data = gltfData::Data( filename ); + currentFile = filename; + if( data != nullptr ) { - common->Warning( "Did not parse %s again", filename.c_str() ); + currentAsset = data; return true; } - lastFile = filename; - currentFile = filename; + + common->SetRefreshOnPrint( true ); if( filename.CheckExtension( ".glb" ) ) { if( !loadGLB( filename ) ) @@ -2104,7 +2101,7 @@ bool GLTF_Parser::Load( idStr filename ) common->FatalError( "Failed to read file" ); } - gltfData* data = gltfData::Data( filename ); + data = gltfData::Data( filename , true ); data->FileName( filename ); byte* dataBuff = data->AddData( length ); currentAsset = data; diff --git a/neo/idlib/gltfProperties.h b/neo/idlib/gltfProperties.h index ca2c67c2..c8293dc2 100644 --- a/neo/idlib/gltfProperties.h +++ b/neo/idlib/gltfProperties.h @@ -793,18 +793,26 @@ public: static idHashIndex fileDataHash; static idList dataList; - //add data from filename - static gltfData* Data( idStr& fileName ) + //add data for filename + static gltfData* Data( idStr& fileName, bool create = false ) { - dataList.AssureSizeAlloc( dataList.Num() + 1, idListNewElement ); - dataList[dataList.Num() - 1]->FileName( fileName ); - fileDataHash.Add( fileDataHash.GenerateKey( fileName ), dataList.Num() - 1 ); - return dataList[dataList.Num() - 1]; - } - //find data; - static gltfData* Data( const char* filename ) - { - return dataList[fileDataHash.First( fileDataHash.GenerateKey( filename ) )]; + int key = fileDataHash.GenerateKey( fileName ); + int index = fileDataHash.GetFirst( key ); + + if( create && index == -1 ) + { + index = dataList.Num( ); + dataList.AssureSizeAlloc( index + 1, idListNewElement ); + dataList[index]->FileName( fileName ); + fileDataHash.Add( fileDataHash.GenerateKey( fileName ), index ); + } + + if( !create && index < 0 ) + { + return nullptr; + } + + return dataList[index]; } static const idList& DataList() { diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 578b3698..e3302223 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -163,18 +163,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) model_state = DM_STATIC; gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName ); - - if( gltfParser->currentFile.Length() ) - { - if( gltfParser->currentAsset && gltfParser->currentFile != gltfFileName ) - { - common->FatalError( "multiple GLTF file loading not supported" ); - } - } - else - { - gltfParser->Load( gltfFileName ); - } + gltfParser->Load( gltfFileName ); timeStamp = fileSystem->GetTimestamp( gltfFileName ); data = gltfParser->currentAsset; @@ -275,6 +264,12 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim hasAnimations = false; fileExclusive = false; // not written. root = nullptr; + + if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) + { + return false; + } + unsigned int magic = 0; file->ReadBig( magic ); @@ -607,18 +602,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T idStr gltfFileName = idStr( animName ); idStr name; gltfManager::ExtractIdentifier( gltfFileName, id, name ); - - if( gltfParser->currentFile.Length( ) ) - { - if( gltfParser->currentAsset && gltfParser->currentFile != gltfFileName ) - { - common->FatalError( "multiple GLTF file loading not supported" ); - } - } - else - { - gltfParser->Load( gltfFileName ); - } + gltfParser->Load( gltfFileName ); gltfData* data = gltfParser->currentAsset; From 486315c7e769e9bdd845f5d6be5da9298daef2a5 Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 14 Aug 2022 13:43:12 +0200 Subject: [PATCH 11/16] - 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. --- neo/idlib/MapFile.cpp | 5 ++- neo/idlib/MapFile_gltf.cpp | 16 ++++++-- neo/idlib/gltfParser.cpp | 73 ++++++++++++++++++++++++++++++------- neo/idlib/gltfParser.h | 8 ++-- neo/idlib/gltfProperties.h | 63 ++++++++++++++++++++++++++------ neo/renderer/Model_gltf.cpp | 65 +++++++++++++++++++++++---------- neo/renderer/Model_gltf.h | 2 +- 7 files changed, 179 insertions(+), 53 deletions(-) diff --git a/neo/idlib/MapFile.cpp b/neo/idlib/MapFile.cpp index 95b85b26..94ca74c6 100644 --- a/neo/idlib/MapFile.cpp +++ b/neo/idlib/MapFile.cpp @@ -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 { diff --git a/neo/idlib/MapFile_gltf.cpp b/neo/idlib/MapFile_gltf.cpp index 93910a94..7c18efc8 100644 --- a/neo/idlib/MapFile_gltf.cpp +++ b/neo/idlib/MapFile_gltf.cpp @@ -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 ) ); } diff --git a/neo/idlib/gltfParser.cpp b/neo/idlib/gltfParser.cpp index 0c218b5a..5008528e 100644 --- a/neo/idlib/gltfParser.cpp +++ b/neo/idlib/gltfParser.cpp @@ -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& 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 ) ); } } diff --git a/neo/idlib/gltfParser.h b/neo/idlib/gltfParser.h index 690b6a56..7eb9a048 100644 --- a/neo/idlib/gltfParser.h +++ b/neo/idlib/gltfParser.h @@ -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; \ No newline at end of file +}; \ No newline at end of file diff --git a/neo/idlib/gltfProperties.h b/neo/idlib/gltfProperties.h index c8293dc2..fff75eed 100644 --- a/neo/idlib/gltfProperties.h +++ b/neo/idlib/gltfProperties.h @@ -765,7 +765,7 @@ const inline idList & ##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 ); - 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; diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index e3302223..e324f106 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -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 idListrootID; 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 idListGetSkin( targets[0] ); + skin = data->GetSkin( targetNode ); } assert( skin ); bones.Append( skin->joints ); @@ -594,27 +595,34 @@ int copyBones( gltfData* data, const idList& bones, idList& 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 bones; idList 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( 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& values = data->GetAccessorView( 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(); } diff --git a/neo/renderer/Model_gltf.h b/neo/renderer/Model_gltf.h index b1025eb2..c1d95a9f 100644 --- a/neo/renderer/Model_gltf.h +++ b/neo/renderer/Model_gltf.h @@ -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; From 457e0e143b9f46581c8fe070c7ccc3576b86ff9d Mon Sep 17 00:00:00 2001 From: HarrievG Date: Sun, 14 Aug 2022 20:02:06 +0200 Subject: [PATCH 12/16] - Fixed missing surfaces in multi surface/texture gltf models. --- neo/renderer/Model_gltf.cpp | 24 +++++++++++------------- neo/renderer/Model_gltf.h | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index e324f106..02070e06 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -1279,7 +1279,7 @@ idList TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int n return jointIds; } -void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf ) +void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf,const modelSurface_t & sourceSurf ) { #if defined(USE_INTRINSICS_SSE) static const __m128 vector_float_posInfinity = { idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM }; @@ -1297,7 +1297,6 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i } srfTriangles_t* tri = surf->geometry; - modelSurface_t& sourceSurf = surfaces[0]; int numVerts = sourceSurf.geometry->numVerts; idDrawVert* verts = sourceSurf.geometry->verts; @@ -1571,22 +1570,21 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn TransformJointsFast( staticModel->jointsInverted, md5joints.Num(), ent->joints, invertedDefaultPose.Ptr() ); - modelSurface_t* newSurf; - if( staticModel->surfaces.Num() ) + if( !staticModel->surfaces.Num() ) { - newSurf = &staticModel->surfaces[0]; - } - else - { - newSurf = &staticModel->surfaces.Alloc( ); - newSurf->geometry = NULL; - newSurf->shader = surfaces[0].shader; + for (int i =0 ; isurfaces.Alloc( ); + newSurf->geometry = NULL; + newSurf->shader = surfaces[i].shader; + } } int surfIdx = 0; for( modelSurface_t& surf : staticModel->surfaces ) { - const idMaterial* shader = newSurf->shader; + + const idMaterial* shader = surf.shader; shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader ); if( !shader || ( !shader->IsDrawn( ) && !shader->SurfaceCastsShadow( ) ) ) @@ -1595,7 +1593,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn continue; } - UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf ); + UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf,surfaces[surfIdx++] ); assert( surf.geometry != NULL ); surf.geometry->staticModelWithJoints = staticModel; staticModel->bounds.AddBounds( surf.geometry->bounds ); diff --git a/neo/renderer/Model_gltf.h b/neo/renderer/Model_gltf.h index c1d95a9f..a82423a6 100644 --- a/neo/renderer/Model_gltf.h +++ b/neo/renderer/Model_gltf.h @@ -58,7 +58,7 @@ public: 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 UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf,const modelSurface_t& sourceSurf ); void UpdateMd5Joints(); gltfData* data; gltfNode* root; From c52e4c345d7582f51c2b3fae99e509f3f9ea386e Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Mon, 15 Aug 2022 12:23:38 +0200 Subject: [PATCH 13/16] ( ) -> () --- neo/d3xp/anim/Anim.cpp | 4 +- neo/d3xp/anim/Anim_Blend.cpp | 2 +- neo/idlib/MapFile_gltf.cpp | 14 +- neo/idlib/gltfParser.cpp | 2 +- neo/idlib/gltfProperties.h | 4 +- neo/idlib/math/VectorI.h | 4 +- neo/renderer/Model_gltf.cpp | 298 +++++++++++++-------------- neo/renderer/Model_gltf.h | 2 +- neo/tools/compilers/aas/AASBuild.cpp | 20 +- 9 files changed, 175 insertions(+), 175 deletions(-) diff --git a/neo/d3xp/anim/Anim.cpp b/neo/d3xp/anim/Anim.cpp index 031d3204..f002b7fe 100644 --- a/neo/d3xp/anim/Anim.cpp +++ b/neo/d3xp/anim/Anim.cpp @@ -228,9 +228,9 @@ bool idMD5Anim::LoadAnim( const char* filename ) // for resource gathering write this anim to the preload file for this map fileSystem->AddAnimPreload( name ); } - if( doWrite && binaryLoadAnim.GetBool( ) ) + if( doWrite && binaryLoadAnim.GetBool() ) { - idLib::Printf( "Writing %s\n", generatedFileName.c_str( ) ); + idLib::Printf( "Writing %s\n", generatedFileName.c_str() ); fileptr->Seek( 0, FS_SEEK_SET ); idFile_Memory* memFile = static_cast( fileptr ); fileSystem->WriteFile( generatedFileName, memFile->GetDataPtr(), memFile->GetAllocated(), "fs_basepath" ); diff --git a/neo/d3xp/anim/Anim_Blend.cpp b/neo/d3xp/anim/Anim_Blend.cpp index 6d1d7c24..e66c1d1a 100644 --- a/neo/d3xp/anim/Anim_Blend.cpp +++ b/neo/d3xp/anim/Anim_Blend.cpp @@ -3373,7 +3373,7 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi joints.SetNum( num ); jointParents.SetNum( num ); channelJoints[0].SetNum( num ); - md5joints = modelHandle->GetJoints( ); + md5joints = modelHandle->GetJoints(); md5joint = md5joints; for( i = 0; i < num; i++, md5joint++ ) { diff --git a/neo/idlib/MapFile_gltf.cpp b/neo/idlib/MapFile_gltf.cpp index 7c18efc8..e8606bd9 100644 --- a/neo/idlib/MapFile_gltf.cpp +++ b/neo/idlib/MapFile_gltf.cpp @@ -39,7 +39,7 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p gltfData* data = bv->parent; // files import as y-up. Use this transform to change the model to z-up. - idMat3 rotation = idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ); + idMat3 rotation = idAngles( 0.0f, 0.0f, 90.0f ).ToMat3(); idMat4 axisTransform( rotation, vec3_origin ); gltfMaterial* mat = NULL; @@ -66,9 +66,9 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p } } - int polyCount = accessor->count /3; + int polyCount = accessor->count / 3; - mesh->polygons.AssureSize(polyCount ); + mesh->polygons.AssureSize( polyCount ); mesh->polygons.SetNum( polyCount ); int cnt = 0; @@ -90,7 +90,7 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p polygon.AddIndex( indices[i + 0] ); } - assert(cnt == polyCount ); + assert( cnt == polyCount ); Mem_Free( indices ); bool sizeSet = false; @@ -311,7 +311,7 @@ void ProcessSceneNode( idMapEntity* newEntity, gltfNode* node, idMat4 trans, glt origin.z = node->translation.z; // files import as y-up. Use this transform to change the model to z-up. - idMat3 rotation = idAngles( 0.0f, 0.0f, 90.0f ).ToMat3( ); + idMat3 rotation = idAngles( 0.0f, 0.0f, 90.0f ).ToMat3(); idMat4 axisTransform( rotation, vec3_origin ); origin *= axisTransform; @@ -326,7 +326,7 @@ void Map_AddMeshes( idMapEntity* _Entity, gltfNode* _Node, idMat4& _Trans, gltfD if( _Node->mesh != -1 ) { - for( auto prim : _Data->MeshList( )[_Node->mesh]->primitives ) + for( auto prim : _Data->MeshList()[_Node->mesh]->primitives ) { _Entity->AddPrimitive( MapPolygonMesh::ConvertFromMeshGltf( prim, _Data, curTrans ) ); } @@ -334,7 +334,7 @@ void Map_AddMeshes( idMapEntity* _Entity, gltfNode* _Node, idMat4& _Trans, gltfD for( auto& child : _Node->children ) { - Map_AddMeshes( _Entity, _Data->NodeList( )[child], curTrans, _Data ); + Map_AddMeshes( _Entity, _Data->NodeList()[child], curTrans, _Data ); } }; diff --git a/neo/idlib/gltfParser.cpp b/neo/idlib/gltfParser.cpp index 5008528e..50ae2953 100644 --- a/neo/idlib/gltfParser.cpp +++ b/neo/idlib/gltfParser.cpp @@ -2339,7 +2339,7 @@ void gltfData::ClearData( idStr& fileName ) } else { - common->DWarning( " tried to clear GLTF data while no data was loaded for %s", fileName.c_str( ) ); + common->DWarning( " tried to clear GLTF data while no data was loaded for %s", fileName.c_str() ); } } diff --git a/neo/idlib/gltfProperties.h b/neo/idlib/gltfProperties.h index fff75eed..4102c123 100644 --- a/neo/idlib/gltfProperties.h +++ b/neo/idlib/gltfProperties.h @@ -807,7 +807,7 @@ public: if( create && index == -1 ) { - index = dataList.Num( ); + index = dataList.Num(); dataList.AssureSizeAlloc( index + 1, idListNewElement ); dataList[index]->FileName( fileName, key ); fileDataHash.Add( key , index ); @@ -886,7 +886,7 @@ public: gltfNode* GetNode( idStr sceneName, int id, idStr* name = nullptr ) { int sceneId = GetSceneId( sceneName ); - if( sceneId < 0 || sceneId > scenes.Num( ) ) + if( sceneId < 0 || sceneId > scenes.Num() ) { return nullptr; } diff --git a/neo/idlib/math/VectorI.h b/neo/idlib/math/VectorI.h index 1b4b9a89..95a9595b 100644 --- a/neo/idlib/math/VectorI.h +++ b/neo/idlib/math/VectorI.h @@ -307,7 +307,7 @@ public: int operator[]( const int index ) const; uint8& operator[]( const int index ); - idVec4i operator-( ) const; + idVec4i operator-() const; uint8 operator*( const idVec4i& a ) const; idVec4i operator*( const uint8 a ) const; idVec4i operator/( const uint8 a ) const; @@ -375,7 +375,7 @@ ID_INLINE uint8& idVec4i::operator[]( int index ) return ( &x )[index]; } -ID_INLINE idVec4i idVec4i::operator-( ) const +ID_INLINE idVec4i idVec4i::operator-() const { return idVec4i( -x, -y, -z, -w ); } diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 02070e06..505f9931 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -49,7 +49,7 @@ static const byte GLMB_VERSION = 100; static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << 8 ) | GLMB_VERSION; static const char* GLTF_SnapshotName = "_GLTF_Snapshot_"; static const idAngles axisTransformAngels = idAngles( 0.0f, 0.0f, 90 ); -static const idMat4 axisTransform( axisTransformAngels.ToMat3( ), vec3_origin ); +static const idMat4 axisTransform( axisTransformAngels.ToMat3(), vec3_origin ); static idRenderModelGLTF* lastMeshFromFile = nullptr; bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh ) @@ -59,8 +59,8 @@ bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh ) void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData* data ) { - auto& meshList = data->MeshList( ); - auto& nodeList = data->NodeList( ); + auto& meshList = data->MeshList(); + auto& nodeList = data->NodeList(); gltfData::ResolveNodeMatrix( modelNode ); @@ -90,9 +90,9 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData gltfMaterial* mat = NULL; if( prim->material != -1 ) { - mat = data->MaterialList( )[prim->material]; + mat = data->MaterialList()[prim->material]; } - if( mat != NULL && !gltf_ForceBspMeshTexture.GetBool( ) ) + if( mat != NULL && !gltf_ForceBspMeshTexture.GetBool() ) { surf.shader = declManager->FindMaterial( mat->name ); } @@ -100,20 +100,20 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData { surf.shader = declManager->FindMaterial( "textures/base_wall/snpanel2rust" ); } - surf.id = this->NumSurfaces( ); + surf.id = this->NumSurfaces(); - srfTriangles_t* tri = R_AllocStaticTriSurf( ); - tri->numIndexes = mesh->GetNumPolygons( ) * 3; - tri->numVerts = mesh->GetNumVertices( ); + srfTriangles_t* tri = R_AllocStaticTriSurf(); + tri->numIndexes = mesh->GetNumPolygons() * 3; + tri->numVerts = mesh->GetNumVertices(); R_AllocStaticTriSurfIndexes( tri, tri->numIndexes ); R_AllocStaticTriSurfVerts( tri, tri->numVerts ); int indx = 0; - for( int i = 0; i < mesh->GetNumPolygons( ); i++ ) + for( int i = 0; i < mesh->GetNumPolygons(); i++ ) { auto& face = mesh->GetFace( i ); - auto& faceIdxs = face.GetIndexes( ); + auto& faceIdxs = face.GetIndexes(); tri->indexes[indx] = faceIdxs[0]; tri->indexes[indx + 1] = faceIdxs[1]; tri->indexes[indx + 2] = faceIdxs[2]; @@ -122,7 +122,7 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData for( int i = 0; i < tri->numVerts; ++i ) { - tri->verts[i] = mesh->GetDrawVerts( )[i]; + tri->verts[i] = mesh->GetDrawVerts()[i]; tri->bounds.AddPoint( tri->verts[i].xyz ); } @@ -155,7 +155,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) name = fileName; currentSkin = nullptr; - PurgeModel( ); + PurgeModel(); //FIXME FIXME FIXME maxJointVertDist = 10; @@ -200,8 +200,8 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) if( !root ) { - common->Warning( "Couldn't find model: '%s'", name.c_str( ) ); - MakeDefaultModel( ); + common->Warning( "Couldn't find model: '%s'", name.c_str() ); + MakeDefaultModel(); return; } @@ -210,7 +210,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) data->GetAllMeshes( root, MeshNodeIds ); //find all animations and bones - bones.Clear( ); + bones.Clear(); int totalAnims = 0; for( int meshID : MeshNodeIds ) { @@ -221,7 +221,7 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) //if not but it has an anim, create a bone from the target mesh-node as origin. if( tmpNode->skin >= 0 ) { - currentSkin = data->SkinList( )[tmpNode->skin]; + currentSkin = data->SkinList()[tmpNode->skin]; assert( currentSkin ); if( currentSkin->joints.Num() ) { @@ -243,10 +243,10 @@ void idRenderModelGLTF::InitFromFile( const char* fileName ) ProcessNode( root, mat4_identity, data ); - if( surfaces.Num( ) <= 0 ) + if( surfaces.Num() <= 0 ) { - common->Warning( "Couldn't load model: '%s'", name.c_str( ) ); - MakeDefaultModel( ); + common->Warning( "Couldn't load model: '%s'", name.c_str() ); + MakeDefaultModel(); return; } @@ -291,7 +291,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim if( animCnt > 0 ) { animIds.Resize( animCnt, 1 ); - file->ReadBigArray( animIds.Ptr( ), animCnt ); + file->ReadBigArray( animIds.Ptr(), animCnt ); animIds.SetNum( animCnt ); } hasAnimations = animCnt > 0; @@ -299,14 +299,14 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim int tempNum; file->ReadBig( tempNum ); md5joints.SetNum( tempNum ); - for( int i = 0; i < md5joints.Num( ); i++ ) + for( int i = 0; i < md5joints.Num(); i++ ) { file->ReadString( md5joints[i].name ); int offset; file->ReadBig( offset ); if( offset >= 0 ) { - md5joints[i].parent = md5joints.Ptr( ) + offset; + md5joints[i].parent = md5joints.Ptr() + offset; } else { @@ -319,21 +319,21 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim if( boneCnt > 0 ) { bones.Resize( boneCnt, 1 ); - file->ReadBigArray( bones.Ptr( ), boneCnt ); + file->ReadBigArray( bones.Ptr(), boneCnt ); bones.SetNum( boneCnt ); } else { if( hasAnimations && !bones.Num() ) { - bones.Clear( ); + bones.Clear(); bones.Append( rootID ); } } file->ReadBig( tempNum ); defaultPose.SetNum( tempNum ); - for( int i = 0; i < defaultPose.Num( ); i++ ) + for( int i = 0; i < defaultPose.Num(); i++ ) { file->ReadBig( defaultPose[i].q.x ); file->ReadBig( defaultPose[i].q.y ); @@ -344,11 +344,11 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim file->ReadBig( tempNum ); invertedDefaultPose.SetNum( tempNum ); - for( int i = 0; i < invertedDefaultPose.Num( ); i++ ) + for( int i = 0; i < invertedDefaultPose.Num(); i++ ) { - file->ReadBigArray( invertedDefaultPose[i].ToFloatPtr( ), JOINTMAT_TYPESIZE ); + file->ReadBigArray( invertedDefaultPose[i].ToFloatPtr(), JOINTMAT_TYPESIZE ); } - SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); + SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), md5joints.Num() ); model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC; @@ -356,7 +356,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim return true; } -void idRenderModelGLTF::UpdateMd5Joints( ) +void idRenderModelGLTF::UpdateMd5Joints() { md5joints.Clear(); md5joints.Resize( bones.Num() ); @@ -415,7 +415,7 @@ void idRenderModelGLTF::UpdateMd5Joints( ) } } - if( bones.Num( ) == 1 ) + if( bones.Num() == 1 ) { //patch bone indices for( auto& surf : surfaces ) @@ -444,35 +444,35 @@ void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const view md5Joint = md5joints.Ptr(); for( i = 0; i < num; i++, joint++, md5Joint++ ) { - pos = ent->origin + joint->ToVec3( ) * ent->axis; + pos = ent->origin + joint->ToVec3() * ent->axis; if( md5Joint->parent ) { - parentNum = md5Joint->parent - md5joints.Ptr( ); - common->RW( )->DebugLine( colorWhite, ent->origin + ent->joints[parentNum].ToVec3( ) * ent->axis, pos ); + parentNum = md5Joint->parent - md5joints.Ptr(); + common->RW()->DebugLine( colorWhite, ent->origin + ent->joints[parentNum].ToVec3() * ent->axis, pos ); } - common->RW( )->DebugLine( colorRed, pos, pos + joint->ToMat3( )[0] * 2.0f * ent->axis ); - common->RW( )->DebugLine( colorGreen, pos, pos + joint->ToMat3( )[1] * 2.0f * ent->axis ); - common->RW( )->DebugLine( colorBlue, pos, pos + joint->ToMat3( )[2] * 2.0f * ent->axis ); + common->RW()->DebugLine( colorRed, pos, pos + joint->ToMat3()[0] * 2.0f * ent->axis ); + common->RW()->DebugLine( colorGreen, pos, pos + joint->ToMat3()[1] * 2.0f * ent->axis ); + common->RW()->DebugLine( colorBlue, pos, pos + joint->ToMat3()[2] * 2.0f * ent->axis ); } idBounds bounds; bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis ); - common->RW( )->DebugBounds( colorMagenta, bounds, ent->origin ); + common->RW()->DebugBounds( colorMagenta, bounds, ent->origin ); - if( ( r_jointNameScale.GetFloat( ) != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) + if( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) { - idVec3 offset( 0, 0, r_jointNameOffset.GetFloat( ) ); + idVec3 offset( 0, 0, r_jointNameOffset.GetFloat() ); float scale; - scale = r_jointNameScale.GetFloat( ); + scale = r_jointNameScale.GetFloat(); joint = ent->joints; num = ent->numJoints; for( i = 0; i < num; i++, joint++ ) { - pos = ent->origin + joint->ToVec3( ) * ent->axis; - common->RW( )->DrawText( md5joints[i].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 ); + pos = ent->origin + joint->ToVec3() * ent->axis; + common->RW()->DrawText( md5joints[i].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 ); } } } @@ -508,7 +508,7 @@ bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList GetPose( idList& bones, idJointMat* poseMat ) { idList ret; - ret.AssureSize( bones.Num( ) ); + ret.AssureSize( bones.Num() ); - for( int i = 0; i < bones.Num( ); i++ ) + for( int i = 0; i < bones.Num(); i++ ) { auto* node = &bones[i]; @@ -536,22 +536,22 @@ idList GetPose( idList& bones, idJointMat* poseMat ) } idJointQuat& pose = ret[i]; - pose.q = ( trans.ToMat3( ).Transpose().ToQuat( ) ); + pose.q = ( trans.ToMat3().Transpose().ToQuat() ); pose.t = idVec3( trans[0][3], trans[1][3], trans[2][3] ); - pose.w = pose.q.CalcW( ); + pose.w = pose.q.CalcW(); } - for( int i = 0; i < bones.Num( ); i++ ) + for( int i = 0; i < bones.Num(); i++ ) { const gltfNode* joint = &bones[i]; idJointQuat* pose = &ret[i]; - poseMat[i].SetRotation( pose->q.ToMat3( ) ); + poseMat[i].SetRotation( pose->q.ToMat3() ); poseMat[i].SetTranslation( pose->t ); if( joint->parent ) { int parentNum = bones.FindIndex( *joint->parent ); - pose->q = ( poseMat[i].ToMat3( ) * poseMat[parentNum].ToMat3( ).Transpose( ) ).ToQuat( ); - pose->t = ( poseMat[i].ToVec3( ) - poseMat[parentNum].ToVec3( ) ) * poseMat[parentNum].ToMat3( ).Transpose( ); + pose->q = ( poseMat[i].ToMat3() * poseMat[parentNum].ToMat3().Transpose() ).ToQuat(); + pose->t = ( poseMat[i].ToVec3() - poseMat[parentNum].ToVec3() ) * poseMat[parentNum].ToMat3().Transpose(); } } @@ -573,7 +573,7 @@ int copyBones( gltfData* data, const idList& bones, idList& out ) for( auto& bone : out ) { bool found = false; - for( int i = 0; i < out.Num( ); i++ ) + for( int i = 0; i < out.Num(); i++ ) { if( bone.parent && bone.parent->name == out[i].name ) { @@ -607,8 +607,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T gltf.Load( gltfFileName ); gltfData* data = gltf.currentAsset; - auto& accessors = data->AccessorList( ); - auto& nodes = data->NodeList( ); + auto& accessors = data->AccessorList(); + auto& nodes = data->NodeList(); gltfNode* nodeRoot = nodes[lastMeshFromFile->rootID]; int boneRootNode = lastMeshFromFile->rootID; @@ -716,7 +716,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T frameRate = gltf_AnimSampleRate.GetInteger(); INT animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate; - for( int i = 0; i < jointInfo.Num( ); i++ ) + for( int i = 0; i < jointInfo.Num(); i++ ) { jointAnimInfo_t& j = jointInfo[i]; idStr jointName = animationLib.JointName( j.nameIndex ); @@ -728,13 +728,13 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T } baseFrame.SetGranularity( 1 ); - baseFrame.SetNum( bones.Num( ) ); + baseFrame.SetNum( bones.Num() ); gltfSkin* skin = data->GetSkin( gltfAnim );; gltfAccessor* acc = nullptr; if( skin != nullptr ) { - acc = data->AccessorList( )[skin->inverseBindMatrices]; + acc = data->AccessorList()[skin->inverseBindMatrices]; } else { @@ -743,12 +743,12 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T idMat4 trans = mat4_identity; data->ResolveNodeMatrix( root, &trans ); trans *= axisTransform.Inverse(); - acc = new gltfAccessor( ); + acc = new gltfAccessor(); acc->matView = new idList( 1 ); - acc->matView->AssureSize( 1, trans.Inverse( ).Transpose( ) ); + acc->matView->AssureSize( 1, trans.Inverse().Transpose() ); } - idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) ); baseFrame = GetPose( animBones[0], poseMat ); componentFrames.SetGranularity( 1 ); @@ -780,7 +780,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T case gltfAnimation_Channel_Target::rotation: { idList& values = data->GetAccessorView( output ); - if( values.Num( ) > i ) + if( values.Num() > i ) { animBones[i][boneIndex].rotation = *values[i]; } @@ -789,7 +789,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T case gltfAnimation_Channel_Target::translation: { idList& values = data->GetAccessorView( output ); - if( values.Num( ) > i ) + if( values.Num() > i ) { animBones[i][boneIndex].translation = *values[i]; } @@ -797,14 +797,14 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T break; case gltfAnimation_Channel_Target::scale: idList& values = data->GetAccessorView( output ); - if( values.Num( ) > i ) + if( values.Num() > i ) { animBones[i][boneIndex].scale = *values[i] ; } break; } } - for( int b = 0; b < bones.Num( ); b++ ) + for( int b = 0; b < bones.Num(); b++ ) { auto* node = &animBones[i][b]; jointAnimInfo_t* joint = &( jointInfo[b] ); @@ -828,7 +828,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T if( node->parent == nullptr ) { - q = axisTransformAngels.ToQuat( ) * animBones[i][b].rotation; + q = axisTransformAngels.ToQuat() * animBones[i][b].rotation; if( animBones[i].Num() == 1 ) { q = -animBones[i][b].rotation; @@ -846,19 +846,19 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T } } - assert( componentFrames.Num( ) == ( componentFrameIndex + 1 ) ); + assert( componentFrames.Num() == ( componentFrameIndex + 1 ) ); bounds.SetGranularity( 1 ); bounds.AssureSize( numFrames ); bounds.SetNum( numFrames ); //do software skinning to determine bounds. - idJointMat* currJoints = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + idJointMat* currJoints = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) ); for( int i = 0; i < numFrames; i++ ) { - bounds[i].Clear( ); + bounds[i].Clear(); - for( int b = 0; b < animBones[i].Num( ); b++ ) + for( int b = 0; b < animBones[i].Num(); b++ ) { if( animBones[i][b].parent == nullptr ) { @@ -868,11 +868,11 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T idList joints; GetPose( animBones[i], currJoints ); - for( int b = 0; b < animBones[i].Num( ); b++ ) + for( int b = 0; b < animBones[i].Num(); b++ ) { idJointMat mat = poseMat[b]; - mat.Invert( ); - idJointMat::Multiply( joints.Alloc( ), currJoints[b], mat ); + mat.Invert(); + idJointMat::Multiply( joints.Alloc(), currJoints[b], mat ); } // an mesh entry _should_ always be before an anim entry! @@ -927,8 +927,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T - file->WriteBig( bounds.Num( ) ); - for( int i = 0; i < bounds.Num( ); i++ ) + file->WriteBig( bounds.Num() ); + for( int i = 0; i < bounds.Num(); i++ ) { idBounds& b = bounds[i]; file->WriteBig( b[0] ); @@ -936,8 +936,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T } //namestr list - file->WriteBig( jointInfo.Num( ) ); - for( int i = 0; i < jointInfo.Num( ); i++ ) + file->WriteBig( jointInfo.Num() ); + for( int i = 0; i < jointInfo.Num(); i++ ) { jointAnimInfo_t& j = jointInfo[i]; idStr jointName = animationLib.JointName( j.nameIndex ); @@ -949,8 +949,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T } //base frame - file->WriteBig( baseFrame.Num( ) ); - for( int i = 0; i < baseFrame.Num( ); i++ ) + file->WriteBig( baseFrame.Num() ); + for( int i = 0; i < baseFrame.Num(); i++ ) { idJointQuat& j = baseFrame[i]; file->WriteBig( j.q.x ); @@ -961,8 +961,8 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T } //per joint timestamp values, T R - file->WriteBig( componentFrames.Num( ) - 1 ); - for( int i = 0; i < componentFrames.Num( ); i++ ) + file->WriteBig( componentFrames.Num() - 1 ); + for( int i = 0; i < componentFrames.Num(); i++ ) { file->WriteFloat( componentFrames[i] ); } @@ -972,7 +972,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T // get total move delta if( !numAnimatedComponents ) { - totaldelta.Zero( ); + totaldelta.Zero(); } else { @@ -1037,32 +1037,32 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /* file->WriteBig( rootID ); file->WriteString( file->GetName() ); - file->WriteBig( animIds.Num( ) ); - if( animIds.Num( ) ) + file->WriteBig( animIds.Num() ); + if( animIds.Num() ) { file->WriteBigArray( animIds.Ptr(), animIds.Num() ); } - file->WriteBig( md5joints.Num( ) ); - for( int i = 0; i < md5joints.Num( ); i++ ) + file->WriteBig( md5joints.Num() ); + for( int i = 0; i < md5joints.Num(); i++ ) { file->WriteString( md5joints[i].name ); int offset = -1; if( md5joints[i].parent != NULL ) { - offset = md5joints[i].parent - md5joints.Ptr( ); + offset = md5joints[i].parent - md5joints.Ptr(); } file->WriteBig( offset ); } - file->WriteBig( bones.Num( ) ); - if( bones.Num( ) ) + file->WriteBig( bones.Num() ); + if( bones.Num() ) { - file->WriteBigArray( bones.Ptr( ), bones.Num( ) ); + file->WriteBigArray( bones.Ptr(), bones.Num() ); } - file->WriteBig( defaultPose.Num( ) ); - for( int i = 0; i < defaultPose.Num( ); i++ ) + file->WriteBig( defaultPose.Num() ); + for( int i = 0; i < defaultPose.Num(); i++ ) { file->WriteBig( defaultPose[i].q.x ); file->WriteBig( defaultPose[i].q.y ); @@ -1071,18 +1071,18 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /* file->WriteVec3( defaultPose[i].t ); } - file->WriteBig( invertedDefaultPose.Num( ) ); - for( int i = 0; i < invertedDefaultPose.Num( ); i++ ) + file->WriteBig( invertedDefaultPose.Num() ); + for( int i = 0; i < invertedDefaultPose.Num(); i++ ) { - file->WriteBigArray( invertedDefaultPose[i].ToFloatPtr( ), JOINTMAT_TYPESIZE ); + file->WriteBigArray( invertedDefaultPose[i].ToFloatPtr(), JOINTMAT_TYPESIZE ); } } void idRenderModelGLTF::PurgeModel() { purged = true; - md5joints.Clear( ); - defaultPose.Clear( ); + md5joints.Clear(); + defaultPose.Clear(); invertedDefaultPose.Clear(); animIds.Clear(); @@ -1099,8 +1099,8 @@ void idRenderModelGLTF::PurgeModel() void idRenderModelGLTF::LoadModel() { int num; - auto& accessors = data->AccessorList( ); - auto& nodes = data->NodeList( ); + auto& accessors = data->AccessorList(); + auto& nodes = data->NodeList(); gltfNode* meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); gltfSkin* skin = nullptr; @@ -1108,7 +1108,7 @@ void idRenderModelGLTF::LoadModel() if( currentSkin != nullptr ) { skin = currentSkin; - acc = data->AccessorList( )[skin->inverseBindMatrices]; + acc = data->AccessorList()[skin->inverseBindMatrices]; } else { @@ -1132,12 +1132,12 @@ void idRenderModelGLTF::LoadModel() defaultPose.SetGranularity( 1 ); defaultPose.SetNum( num ); - for( int i = 0; i < bones.Num( ); i++ ) + for( int i = 0; i < bones.Num(); i++ ) { gltfNode* node = nodes[bones[i]]; //check for TRS anim and its artficial root bone - if( bones.Num( ) == 0 && node->mesh != -1 ) + if( bones.Num() == 0 && node->mesh != -1 ) { md5joints[i].name = "origin"; } @@ -1162,7 +1162,7 @@ void idRenderModelGLTF::LoadModel() }; - for( int i = 0; i < bones.Num( ); i++ ) + for( int i = 0; i < bones.Num(); i++ ) { auto* node = nodes[bones[i]]; @@ -1172,7 +1172,7 @@ void idRenderModelGLTF::LoadModel() } } - idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num( ) * sizeof( poseMat[0] ) ); + idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) ); idList animBones; int totalCopied = copyBones( data, bones, animBones ); defaultPose = GetPose( animBones, poseMat ); @@ -1190,16 +1190,16 @@ void idRenderModelGLTF::LoadModel() // vertex * joints * inverseJoints == vertex when joints is the base pose // When the joints are in another pose, it gives the animated vertex position //----------------------------------------- - invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( md5joints.Num( ) ) ); - for( int i = 0; i < md5joints.Num( ); i++ ) + invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( md5joints.Num() ) ); + for( int i = 0; i < md5joints.Num(); i++ ) { invertedDefaultPose[i] = poseMat[i]; - invertedDefaultPose[i].Invert( ); + invertedDefaultPose[i].Invert(); } - SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr( ), md5joints.Num( ) ); + SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), md5joints.Num() ); - //auto deformInfo = R_BuildDeformInfo( texCoords.Num( ), basePose, tris.Num( ), tris.Ptr( ), - // shader->UseUnsmoothedTangents( ) ); + //auto deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(), + // shader->UseUnsmoothedTangents() ); model_state = hasAnimations ? DM_CACHED : DM_STATIC; @@ -1208,14 +1208,14 @@ void idRenderModelGLTF::LoadModel() purged = false; - common->UpdateLevelLoadPacifier( ); + common->UpdateLevelLoadPacifier(); } void idRenderModelGLTF::TouchData() { - for( int i = 0; i < surfaces.Num( ); i++ ) + for( int i = 0; i < surfaces.Num(); i++ ) { - declManager->FindMaterial( surfaces[i].shader->GetName( ) ); + declManager->FindMaterial( surfaces[i].shader->GetName() ); } } @@ -1271,15 +1271,15 @@ idList TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int n idJointMat::Mad( accum, j3, w3 ); targetVerts[i].xyz = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f ); - targetVerts[i].SetNormal( accum * base.GetNormal( ) ); - targetVerts[i].SetTangent( accum * base.GetTangent( ) ); + targetVerts[i].SetNormal( accum * base.GetNormal() ); + targetVerts[i].SetTangent( accum * base.GetTangent() ); targetVerts[i].tangent[3] = base.tangent[3]; } return jointIds; } -void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf,const modelSurface_t & sourceSurf ) +void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf, const modelSurface_t& sourceSurf ) { #if defined(USE_INTRINSICS_SSE) static const __m128 vector_float_posInfinity = { idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM, idMath::INFINITUM }; @@ -1293,7 +1293,7 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i } else { - surf->geometry = R_AllocStaticTriSurf( ); + surf->geometry = R_AllocStaticTriSurf(); } srfTriangles_t* tri = surf->geometry; @@ -1317,7 +1317,7 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i idList jointIds; - if( r_useGPUSkinning.GetBool( ) && glConfig.gpuSkinningAvailable ) + if( r_useGPUSkinning.GetBool() && glConfig.gpuSkinningAvailable ) { if( tri->verts != NULL && tri->verts != verts ) { @@ -1353,9 +1353,9 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i for( int i = 0; i < jointIds.Num(); i++ ) { const idJointMat& joint = entJoints[i]; - __m128 x = _mm_load_ps( joint.ToFloatPtr( ) + 0 * 4 ); - __m128 y = _mm_load_ps( joint.ToFloatPtr( ) + 1 * 4 ); - __m128 z = _mm_load_ps( joint.ToFloatPtr( ) + 2 * 4 ); + __m128 x = _mm_load_ps( joint.ToFloatPtr() + 0 * 4 ); + __m128 y = _mm_load_ps( joint.ToFloatPtr() + 1 * 4 ); + __m128 z = _mm_load_ps( joint.ToFloatPtr() + 2 * 4 ); minX = _mm_min_ps( minX, x ); minY = _mm_min_ps( minY, y ); minZ = _mm_min_ps( minZ, z ); @@ -1370,19 +1370,19 @@ void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const i maxX = _mm_add_ps( maxX, expand ); maxY = _mm_add_ps( maxY, expand ); maxZ = _mm_add_ps( maxZ, expand ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 0, _mm_splat_ps( minX, 3 ) ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 1, _mm_splat_ps( minY, 3 ) ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 2, _mm_splat_ps( minZ, 3 ) ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 3, _mm_splat_ps( maxX, 3 ) ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 4, _mm_splat_ps( maxY, 3 ) ); - _mm_store_ss( tri->bounds.ToFloatPtr( ) + 5, _mm_splat_ps( maxZ, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 0, _mm_splat_ps( minX, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 1, _mm_splat_ps( minY, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 2, _mm_splat_ps( minZ, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 3, _mm_splat_ps( maxX, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 4, _mm_splat_ps( maxY, 3 ) ); + _mm_store_ss( tri->bounds.ToFloatPtr() + 5, _mm_splat_ps( maxZ, 3 ) ); #else - bounds.Clear( ); - for( int i = 0; i < jointIds.Num( ); i++ ) + bounds.Clear(); + for( int i = 0; i < jointIds.Num(); i++ ) { const idJointMat& joint = entJoints[i]; - bounds.AddPoint( joint.GetTranslation( ) ); + bounds.AddPoint( joint.GetTranslation() ); } bounds.ExpandSelf( maxJointVertDist ); @@ -1398,9 +1398,9 @@ TransformJoints static void TransformJointsFast( idJointMat* __restrict outJoints, const int numJoints, const idJointMat* __restrict inJoints1, const idJointMat* __restrict inJoints2 ) { - float* outFloats = outJoints->ToFloatPtr( ); - const float* inFloats1 = inJoints1->ToFloatPtr( ); - const float* inFloats2 = inJoints2->ToFloatPtr( ); + float* outFloats = outJoints->ToFloatPtr(); + const float* inFloats1 = inJoints1->ToFloatPtr(); + const float* inFloats2 = inJoints2->ToFloatPtr(); assert_16_byte_aligned( outFloats ); assert_16_byte_aligned( inFloats1 ); @@ -1512,13 +1512,13 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn if( !ent->joints ) { - common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name( ) ); + common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() ); delete cachedModel; return NULL; } - else if( ent->numJoints != md5joints.Num( ) ) + else if( ent->numJoints != md5joints.Num() ) { - common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name( ) ); + common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() ); delete cachedModel; return NULL; } @@ -1527,7 +1527,7 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn if( cachedModel != NULL ) { assert( dynamic_cast< idRenderModelStatic* >( cachedModel ) != NULL ); - assert( idStr::Icmp( cachedModel->Name( ), GLTF_SnapshotName ) == 0 ); + assert( idStr::Icmp( cachedModel->Name(), GLTF_SnapshotName ) == 0 ); staticModel = static_cast< idRenderModelStatic* >( cachedModel ); } else @@ -1539,15 +1539,15 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn staticModel->bounds.Clear(); - if( r_showSkel.GetInteger( ) ) + if( r_showSkel.GetInteger() ) { - if( ( view != NULL ) && ( !r_skipSuppress.GetBool( ) || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) + if( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) { // only draw the skeleton DrawJoints( ent, view ); } - if( r_showSkel.GetInteger( ) > 1 ) + if( r_showSkel.GetInteger() > 1 ) { // turn off the model when showing the skeleton staticModel->InitEmpty( GLTF_SnapshotName ); @@ -1572,9 +1572,9 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn if( !staticModel->surfaces.Num() ) { - for (int i =0 ; isurfaces.Alloc( ); + modelSurface_t* newSurf = &staticModel->surfaces.Alloc(); newSurf->geometry = NULL; newSurf->shader = surfaces[i].shader; } @@ -1587,13 +1587,13 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn const idMaterial* shader = surf.shader; shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader ); - if( !shader || ( !shader->IsDrawn( ) && !shader->SurfaceCastsShadow( ) ) ) + if( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) { staticModel->DeleteSurfaceWithId( surfIdx++ ); continue; } - UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf,surfaces[surfIdx++] ); + UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf, surfaces[surfIdx++] ); assert( surf.geometry != NULL ); surf.geometry->staticModelWithJoints = staticModel; staticModel->bounds.AddBounds( surf.geometry->bounds ); @@ -1624,10 +1624,10 @@ const idMD5Joint* idRenderModelGLTF::GetJoints() const jointHandle_t idRenderModelGLTF::GetJointHandle( const char* name ) const { - const idMD5Joint* joint = md5joints.Ptr( ); - for( int i = 0; i < md5joints.Num( ); i++, joint++ ) + const idMD5Joint* joint = md5joints.Ptr(); + for( int i = 0; i < md5joints.Num(); i++, joint++ ) { - if( idStr::Icmp( joint->name.c_str( ), name ) == 0 ) + if( idStr::Icmp( joint->name.c_str(), name ) == 0 ) { return ( jointHandle_t ) i; } @@ -1638,7 +1638,7 @@ jointHandle_t idRenderModelGLTF::GetJointHandle( const char* name ) const const char* idRenderModelGLTF::GetJointName( jointHandle_t handle ) const { - if( ( handle < 0 ) || ( handle >= md5joints.Num( ) ) ) + if( ( handle < 0 ) || ( handle >= md5joints.Num() ) ) { return ""; } @@ -1697,7 +1697,7 @@ int idRenderModelGLTF::NearestJoint( int surfaceNum, int a, int b, int c ) const } } - common->Warning( "Couldn't find NearestJoint for : '%s'", name.c_str( ) ); + common->Warning( "Couldn't find NearestJoint for : '%s'", name.c_str() ); return 0; } diff --git a/neo/renderer/Model_gltf.h b/neo/renderer/Model_gltf.h index a82423a6..83b79ccc 100644 --- a/neo/renderer/Model_gltf.h +++ b/neo/renderer/Model_gltf.h @@ -58,7 +58,7 @@ public: 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,const modelSurface_t& sourceSurf ); + void UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf, const modelSurface_t& sourceSurf ); void UpdateMd5Joints(); gltfData* data; gltfNode* root; diff --git a/neo/tools/compilers/aas/AASBuild.cpp b/neo/tools/compilers/aas/AASBuild.cpp index 528d407a..0d4b8fdd 100644 --- a/neo/tools/compilers/aas/AASBuild.cpp +++ b/neo/tools/compilers/aas/AASBuild.cpp @@ -442,15 +442,15 @@ idBrushList idAASBuild::AddBrushesForMapPolygonMesh( const MapPolygonMesh* mapMe const MapPolygon& face = mapMesh->GetFace( p ); mat = declManager->FindMaterial( face.GetMaterial() ); - contents = ContentsForAAS( mat->GetContentFlags( ) ); + contents = ContentsForAAS( mat->GetContentFlags() ); if( !contents ) { return brushList; } - const idList& verts = mapMesh->GetDrawVerts( ); - const idList& indices = face.GetIndexes( ); + const idList& verts = mapMesh->GetDrawVerts(); + const idList& indices = face.GetIndexes(); idVec3 triNormal; int v1 = 0; @@ -465,16 +465,16 @@ idBrushList idAASBuild::AddBrushesForMapPolygonMesh( const MapPolygonMesh* mapMe d1 = verts[indices[1]].xyz - verts[indices[0]].xyz; d2 = verts[indices[2]].xyz - verts[indices[0]].xyz; plane.SetNormal( d1.Cross( d2 ) ); - if( plane.Normalize( ) != 0.0f ) + if( plane.Normalize() != 0.0f ) { plane.FitThroughPoint( verts[indices[2]].xyz ); - w.Clear( ); + w.Clear(); w += verts[indices[0]].xyz; w += verts[indices[1]].xyz; w += verts[indices[2]].xyz; - brush = new idBrush( ); + brush = new idBrush(); brush->SetContents( contents ); if( brush->FromWinding( w, plane ) ) { @@ -494,16 +494,16 @@ idBrushList idAASBuild::AddBrushesForMapPolygonMesh( const MapPolygonMesh* mapMe //Back face triNormal = plane.Normal(); plane.SetNormal( d2.Cross( d1 ) ); - if( plane.Normalize( ) != 0.0f ) + if( plane.Normalize() != 0.0f ) { plane.FitThroughPoint( verts[indices[0]].xyz ); - w.Clear( ); + w.Clear(); w += verts[indices[2]].xyz + triNormal; w += verts[indices[1]].xyz + triNormal; w += verts[indices[0]].xyz + triNormal; - brush = new idBrush( ); + brush = new idBrush(); brush->SetContents( contents ); if( brush->FromWinding( w, plane ) ) { @@ -725,7 +725,7 @@ idBrushList idAASBuild::AddBrushesForMapEntity( const idMapEntity* mapEnt, int e continue; } //HVG: Map polygon mesh support - if( mapPrim->GetType( ) == idMapPrimitive::TYPE_MESH ) + if( mapPrim->GetType() == idMapPrimitive::TYPE_MESH ) { brushList = AddBrushesForMapPolygonMesh( static_cast< MapPolygonMesh* >( mapPrim ), origin, axis, entityNum, i, brushList ); } From 1d354e995f7bc42858e4b62a2ec019f14b8e036f Mon Sep 17 00:00:00 2001 From: HarrievG Date: Mon, 15 Aug 2022 16:13:04 +0200 Subject: [PATCH 14/16] - fix for file exclusive gltf models --- neo/renderer/Model_gltf.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 02070e06..b95bf28e 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -1101,7 +1101,11 @@ void idRenderModelGLTF::LoadModel() int num; auto& accessors = data->AccessorList( ); auto& nodes = data->NodeList( ); - gltfNode* meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); + gltfNode* meshRoot = root; + if ( !fileExclusive ) + { + meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); + } gltfSkin* skin = nullptr; gltfAccessor* acc = nullptr; From 88b02efd6d56132c3b43ce8a59f2db59e15bf62b Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Tue, 16 Aug 2022 10:41:00 +0200 Subject: [PATCH 15/16] Fixed camera clipping with static glTF2 models --- neo/d3xp/Entity.cpp | 10 +++++++++- neo/renderer/Model_gltf.cpp | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/neo/d3xp/Entity.cpp b/neo/d3xp/Entity.cpp index cd8ea2a8..233c0bc8 100644 --- a/neo/d3xp/Entity.cpp +++ b/neo/d3xp/Entity.cpp @@ -283,7 +283,15 @@ void idGameEdit::ParseSpawnArgsToRenderEntity( const idDict* args, renderEntity_ if( renderEntity->hModel ) { - renderEntity->bounds = renderEntity->hModel->Bounds( renderEntity ); + // RB: glTF2 models can be static and cached + if( renderEntity->hModel->IsDynamicModel() == DM_STATIC ) + { + renderEntity->bounds = renderEntity->hModel->Bounds( NULL ); + } + else + { + renderEntity->bounds = renderEntity->hModel->Bounds( renderEntity ); + } } else { diff --git a/neo/renderer/Model_gltf.cpp b/neo/renderer/Model_gltf.cpp index 78d599e5..e45df578 100644 --- a/neo/renderer/Model_gltf.cpp +++ b/neo/renderer/Model_gltf.cpp @@ -120,6 +120,7 @@ void idRenderModelGLTF::ProcessNode( gltfNode* modelNode, idMat4 trans, gltfData indx += 3; } + tri->bounds.Clear(); for( int i = 0; i < tri->numVerts; ++i ) { tri->verts[i] = mesh->GetDrawVerts()[i]; @@ -1102,7 +1103,7 @@ void idRenderModelGLTF::LoadModel() auto& accessors = data->AccessorList(); auto& nodes = data->NodeList(); gltfNode* meshRoot = root; - if ( !fileExclusive ) + if( !fileExclusive ) { meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName ); } From 3ea4ac29fe87418c7b885a0a657cf753e06589b0 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Tue, 16 Aug 2022 13:00:52 +0200 Subject: [PATCH 16/16] Fixed support for glTF2 uint16 weight indices --- neo/idlib/MapFile_gltf.cpp | 51 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/neo/idlib/MapFile_gltf.cpp b/neo/idlib/MapFile_gltf.cpp index e8606bd9..0afa42d0 100644 --- a/neo/idlib/MapFile_gltf.cpp +++ b/neo/idlib/MapFile_gltf.cpp @@ -235,22 +235,47 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p } case gltfMesh_Primitive_Attribute::Type::Indices: { - idVec4i vec; - for( int i = 0; i < attrAcc->count; i++ ) + if( attrAcc->typeSize == 2 ) { - bin.Read( ( void* )( &vec.x ), attrAcc->typeSize ); - bin.Read( ( void* )( &vec.y ), attrAcc->typeSize ); - bin.Read( ( void* )( &vec.z ), attrAcc->typeSize ); - bin.Read( ( void* )( &vec.w ), attrAcc->typeSize ); - if( attrBv->byteStride ) + uint16_t vec[4]; + for( int i = 0; i < attrAcc->count; i++ ) { - bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); - } + bin.Read( ( void* )( &vec[0] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[1] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[2] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[3] ), attrAcc->typeSize ); + if( attrBv->byteStride ) + { + bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); + } - mesh->verts[i].color[0] = vec.x; - mesh->verts[i].color[1] = vec.y; - mesh->verts[i].color[2] = vec.z; - mesh->verts[i].color[3] = vec.w; + mesh->verts[i].color[0] = vec[0]; + mesh->verts[i].color[1] = vec[1]; + mesh->verts[i].color[2] = vec[2]; + mesh->verts[i].color[3] = vec[3]; + } + } + else + { + uint8_t vec[4]; + for( int i = 0; i < attrAcc->count; i++ ) + { + assert( sizeof( vec ) == attrAcc->typeSize ); + + bin.Read( ( void* )( &vec[0] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[1] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[2] ), attrAcc->typeSize ); + bin.Read( ( void* )( &vec[3] ), attrAcc->typeSize ); + if( attrBv->byteStride ) + { + bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR ); + } + + mesh->verts[i].color[0] = vec[0]; + mesh->verts[i].color[1] = vec[1]; + mesh->verts[i].color[2] = vec[2]; + mesh->verts[i].color[3] = vec[3]; + } } break;