2022-06-18 09:09:09 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
|
|
Copyright (C) 2022 Harrie van Ginneken
|
|
|
|
Copyright (C) 2022 Robert Beckebans
|
|
|
|
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
|
|
|
|
===========================================================================
|
|
|
|
*/
|
2022-06-05 22:39:04 +00:00
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
|
|
|
|
|
|
#include "Model_gltf.h"
|
|
|
|
#include "Model_local.h"
|
2022-06-17 23:18:28 +00:00
|
|
|
#include "RenderCommon.h"
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
//HVG_TODO: this has to be moved out before release
|
|
|
|
#include "d3xp/anim/Anim.h"
|
|
|
|
#include "d3xp/Game_local.h"
|
|
|
|
|
2022-06-17 23:18:28 +00:00
|
|
|
idCVar gltf_ForceBspMeshTexture( "gltf_ForceBspMeshTexture", "0", CVAR_SYSTEM | CVAR_BOOL, "all world geometry has the same forced texture" );
|
2022-10-24 18:34:14 +00:00
|
|
|
idCVar gltf_ModelSceneName( "gltf_ModelSceneName", "models", CVAR_SYSTEM , "Scene to use when loading specific models" );
|
2022-06-17 23:18:28 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
idCVar gltf_AnimSampleRate( "gltf_AnimSampleRate", "24", CVAR_SYSTEM | CVAR_INTEGER , "The frame rate of the converted md5anim" );
|
|
|
|
|
2022-06-21 20:07:27 +00:00
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
static const byte GLMB_VERSION = 102;
|
2022-06-21 20:07:27 +00:00
|
|
|
static const unsigned int GLMB_MAGIC = ( 'M' << 24 ) | ( 'L' << 16 ) | ( 'G' << 8 ) | GLMB_VERSION;
|
2022-06-24 19:40:08 +00:00
|
|
|
static const char* GLTF_SnapshotName = "_GLTF_Snapshot_";
|
2022-09-25 22:31:47 +00:00
|
|
|
static const idMat4 blenderToDoomTransform( idAngles( 0.0f, 0.0f, 90 ).ToMat3(), vec3_origin );
|
|
|
|
//static const idMat4 blenderToDoomTransform = mat4_identity;
|
2022-08-01 20:05:13 +00:00
|
|
|
static idRenderModelGLTF* lastMeshFromFile = nullptr;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh )
|
|
|
|
{
|
2022-06-05 22:39:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-23 14:32:12 +00:00
|
|
|
void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, const idMat4& parentTransform, const idMat4& globalTransform, gltfData* data )
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
auto& meshList = data->MeshList();
|
|
|
|
auto& nodeList = data->NodeList();
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
gltfData::ResolveNodeMatrix( modelNode );
|
2022-06-17 23:18:28 +00:00
|
|
|
|
2022-09-25 22:31:47 +00:00
|
|
|
idMat4 nodeToWorldTransform = parentTransform * modelNode->matrix;
|
2022-06-24 19:40:08 +00:00
|
|
|
|
|
|
|
if( modelNode->mesh >= 0 )
|
|
|
|
{
|
|
|
|
gltfMesh* targetMesh = meshList[modelNode->mesh];
|
2022-06-17 23:18:28 +00:00
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
for( auto prim : targetMesh->primitives )
|
2022-06-18 08:36:48 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
//ConvertFromMeshGltf should only be used for the map, ConvertGltfMeshToModelsurfaces should be used.
|
2022-10-23 14:32:12 +00:00
|
|
|
auto* mesh = MapPolygonMesh::ConvertFromMeshGltf( prim, data, globalTransform * nodeToWorldTransform );
|
2022-06-24 19:40:08 +00:00
|
|
|
modelSurface_t surf;
|
|
|
|
|
|
|
|
gltfMaterial* mat = NULL;
|
|
|
|
if( prim->material != -1 )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
mat = data->MaterialList()[prim->material];
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
2022-08-15 10:23:38 +00:00
|
|
|
if( mat != NULL && !gltf_ForceBspMeshTexture.GetBool() )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
|
|
|
surf.shader = declManager->FindMaterial( mat->name );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
surf.shader = declManager->FindMaterial( "textures/base_wall/snpanel2rust" );
|
|
|
|
}
|
2022-08-15 10:23:38 +00:00
|
|
|
surf.id = this->NumSurfaces();
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
srfTriangles_t* tri = R_AllocStaticTriSurf();
|
|
|
|
tri->numIndexes = mesh->GetNumPolygons() * 3;
|
|
|
|
tri->numVerts = mesh->GetNumVertices();
|
2022-06-24 19:40:08 +00:00
|
|
|
|
|
|
|
R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
|
|
|
|
R_AllocStaticTriSurfVerts( tri, tri->numVerts );
|
|
|
|
|
|
|
|
int indx = 0;
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < mesh->GetNumPolygons(); i++ )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
auto& face = mesh->GetFace( i );
|
2022-08-15 10:23:38 +00:00
|
|
|
auto& faceIdxs = face.GetIndexes();
|
2022-06-24 19:40:08 +00:00
|
|
|
tri->indexes[indx] = faceIdxs[0];
|
|
|
|
tri->indexes[indx + 1] = faceIdxs[1];
|
|
|
|
tri->indexes[indx + 2] = faceIdxs[2];
|
|
|
|
indx += 3;
|
|
|
|
}
|
|
|
|
|
2022-08-16 08:41:00 +00:00
|
|
|
tri->bounds.Clear();
|
2022-06-24 19:40:08 +00:00
|
|
|
for( int i = 0; i < tri->numVerts; ++i )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
tri->verts[i] = mesh->GetDrawVerts()[i];
|
2022-06-24 19:40:08 +00:00
|
|
|
tri->bounds.AddPoint( tri->verts[i].xyz );
|
|
|
|
}
|
|
|
|
|
|
|
|
bounds.AddBounds( tri->bounds );
|
|
|
|
|
|
|
|
surf.geometry = tri;
|
|
|
|
AddSurface( surf );
|
2022-07-10 19:09:25 +00:00
|
|
|
delete mesh;
|
2022-06-17 23:18:28 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-06-18 08:36:48 +00:00
|
|
|
for( auto& child : modelNode->children )
|
|
|
|
{
|
2022-10-23 14:32:12 +00:00
|
|
|
ProcessNode_r( nodeList[child], nodeToWorldTransform, globalTransform, data );
|
2022-06-17 23:18:28 +00:00
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
2022-11-15 19:31:12 +00:00
|
|
|
static void KeepNodes( gltfData* data, const idStrList& keepList, idList<int, TAG_MODEL>& boneList )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
idStrList finalList;
|
|
|
|
idStr nodeName;
|
|
|
|
idList<int> nodesToKeep;
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
for( int i = 0 ; i < keepList.Num(); i++ )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
bool parentWildcard = false;
|
|
|
|
bool childWildcard = false;
|
2022-11-15 19:31:12 +00:00
|
|
|
if( keepList[i] == "*" )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
parentWildcard = true;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
const idStr item = keepList[i];
|
2022-11-15 19:31:12 +00:00
|
|
|
gltfNode* node = data->GetNode( item );
|
|
|
|
|
|
|
|
if( node == nullptr )
|
|
|
|
{
|
2022-11-15 19:28:06 +00:00
|
|
|
continue;
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int idx = data->GetNodeIndex( node );
|
|
|
|
if( boneList.Find( idx ) )
|
|
|
|
{
|
|
|
|
nodesToKeep.Insert( idx );
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( ( i < ( keepList.Num() - 1 ) ) && keepList[i + 1] == "*" )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
childWildcard = true;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( parentWildcard && node->parent )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
gltfNode* parent = node->parent;
|
2022-11-15 19:31:12 +00:00
|
|
|
while( parent )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
idx = data->GetNodeIndex( parent );
|
|
|
|
if( boneList.Find( idx ) )
|
|
|
|
{
|
|
|
|
nodesToKeep.Insert( idx );
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( childWildcard && node->children.Num() )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
idList<int> tmpIdx;
|
2022-11-15 19:31:12 +00:00
|
|
|
tmpIdx.Append( node->children );
|
|
|
|
for( int j = 0; j < tmpIdx.Num(); j++ )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
idx = tmpIdx[j];
|
2022-11-15 19:31:12 +00:00
|
|
|
if( boneList.Find( idx ) )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
nodesToKeep.Insert( idx );
|
2022-11-15 19:28:06 +00:00
|
|
|
gltfNode* tmpNode = data->NodeList()[idx];
|
2022-11-15 19:31:12 +00:00
|
|
|
if( tmpNode )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
for( int child : tmpNode->children )
|
|
|
|
{
|
|
|
|
tmpIdx.AddUnique( child );
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
2022-11-15 19:31:12 +00:00
|
|
|
common->SetRefreshOnPrint( true );
|
|
|
|
common->DPrintf( "=====\n" );
|
|
|
|
for( int nodeID : boneList )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
if( nodesToKeep.Find( nodeID ) )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
common->DPrintf( "^7[^2Kept^7]\t\t bone \'%s\'\n",
|
|
|
|
data->NodeList()[nodeID]->name.c_str() );
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
common->DPrintf( "^7[^1Discard^7]\t bone \'%s\'\n ",
|
|
|
|
data->NodeList()[nodeID]->name.c_str() );
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2022-11-15 19:31:12 +00:00
|
|
|
common->DPrintf( "=====\n" );
|
|
|
|
common->SetRefreshOnPrint( false );
|
2022-11-15 19:28:06 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
boneList = nodesToKeep;
|
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
static gltfNode* GetBoneNode( gltfData* data, const idList<int, TAG_MODEL>& boneList, const idStr& name )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
auto& nodelist = data->NodeList();
|
2022-11-15 19:31:12 +00:00
|
|
|
for( int boneId : boneList )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
gltfNode* boneNode = nodelist[boneId];
|
2022-11-15 19:31:12 +00:00
|
|
|
if( boneNode->name == name )
|
|
|
|
{
|
2022-11-15 19:28:06 +00:00
|
|
|
return boneNode;
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
static void RemapNodes( gltfData* data, const idList<idNamePair>& remapList, const idList<int, TAG_MODEL>& boneList )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
//we need to be _very_ careful with modifying the GLTF data since it is not saved or cached!!!
|
|
|
|
auto& nodeList = data->NodeList();
|
2022-11-15 19:31:12 +00:00
|
|
|
for( const auto& remap : remapList )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
gltfNode* from = GetBoneNode( data, boneList, remap.from );
|
|
|
|
gltfNode* to = GetBoneNode( data, boneList, remap.to );
|
|
|
|
if( !from || !to )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
common->Error( "Invalid remap name pair \'%s\'[\"%s\"] : \'%s\'[\"%s\"]",
|
|
|
|
remap.from.c_str(), from ? from->name.c_str() : "Not Found",
|
|
|
|
remap.to.c_str(), to ? to->name.c_str() : "Not Found" );
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
common->Warning( "Remapping.. setting \'%s\' as parent of \'%s\' ",
|
|
|
|
remap.to.c_str(), remap.from.c_str() );
|
2022-11-15 19:28:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
from->parent = to;
|
2022-11-15 19:31:12 +00:00
|
|
|
to->children.Alloc() = data->GetNodeIndex( from );
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:36 +00:00
|
|
|
static int AddOriginBone( gltfData* data, idList<int, TAG_MODEL>& bones, gltfNode* root )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
//we need to be _very_ careful with modifying the GLTF data since it is not saved or cached!!!
|
|
|
|
auto& nodeList = data->NodeList();
|
|
|
|
gltfNode* newNode = data->Node();
|
|
|
|
int newIdx = nodeList.Num() - 1;
|
2022-11-15 19:31:12 +00:00
|
|
|
bones.Insert( newIdx );
|
2022-11-15 19:28:06 +00:00
|
|
|
newNode->name = "origin";
|
|
|
|
|
2022-11-23 00:55:07 +00:00
|
|
|
|
2022-11-15 19:28:06 +00:00
|
|
|
//patch children
|
2022-11-15 19:31:12 +00:00
|
|
|
for( int childId : root->children )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
newNode->children.Alloc() = childId;
|
|
|
|
gltfNode* childNode = nodeList[childId];
|
|
|
|
childNode->parent = newNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
root->children.Clear();
|
|
|
|
root->children.Alloc() = nodeList.Num() - 1;
|
|
|
|
newNode->parent = root;
|
2022-11-15 19:31:12 +00:00
|
|
|
common->Warning( "Added origin bone!" );
|
2022-11-23 00:55:07 +00:00
|
|
|
return newIdx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RenameNodes( gltfData* data, const idList<idNamePair>& renameList, const idList<int, TAG_MODEL>& boneList )
|
|
|
|
{
|
|
|
|
//we need to be _very_ careful with modifying the GLTF data since it is not saved or cached!!!
|
|
|
|
auto& nodeList = data->NodeList();
|
|
|
|
for( const auto& rename : renameList )
|
|
|
|
{
|
|
|
|
gltfNode* from = GetBoneNode( data, boneList, rename.from );
|
|
|
|
if( !from )
|
|
|
|
{
|
|
|
|
common->Error( "Invalid rename name pair from \'%s\'[\"%s\"] ",
|
|
|
|
rename.from.c_str(), from ? from->name.c_str() : "Not Found" );
|
|
|
|
}
|
|
|
|
|
|
|
|
common->Warning( "Renaming.. \'%s\' to \'%s\' ",
|
|
|
|
rename.from.c_str(), rename.to.c_str() );
|
|
|
|
|
|
|
|
from->name = rename.to;
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-06-17 23:18:28 +00:00
|
|
|
//constructs a renderModel from a gltfScene node found in the "models" scene of the given gltfFile.
|
2022-06-20 20:25:52 +00:00
|
|
|
// override with gltf_ModelSceneName
|
2022-06-17 23:18:28 +00:00
|
|
|
// warning : nodeName cannot have dots!
|
|
|
|
//[fileName].[nodeName/nodeId].[gltf/glb]
|
2022-06-19 23:12:45 +00:00
|
|
|
//If no nodeName/nodeId is given, all primitives active in default scene will be added as surfaces.
|
2022-10-24 18:34:14 +00:00
|
|
|
void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOptions* options )
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
hasAnimations = false;
|
2022-06-21 20:07:27 +00:00
|
|
|
fileExclusive = false;
|
|
|
|
root = nullptr;
|
2022-07-10 19:09:25 +00:00
|
|
|
rootID = -1;
|
2022-06-17 23:18:28 +00:00
|
|
|
int meshID = -1;
|
2022-07-10 19:09:25 +00:00
|
|
|
name = fileName;
|
2022-07-31 10:13:07 +00:00
|
|
|
currentSkin = nullptr;
|
2022-11-17 21:36:12 +00:00
|
|
|
idImportOptions* localOptions = nullptr;
|
2022-11-24 22:26:36 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
PurgeModel();
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
//FIXME FIXME FIXME
|
2022-07-31 10:13:07 +00:00
|
|
|
maxJointVertDist = 10;
|
2022-11-10 21:01:48 +00:00
|
|
|
gltfFileName = idStr( fileName );
|
2022-06-24 19:40:08 +00:00
|
|
|
model_state = DM_STATIC;
|
2022-06-19 19:58:43 +00:00
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
if( options )
|
|
|
|
{
|
|
|
|
commandLine = options->commandLine;
|
|
|
|
localOptions = const_cast<idImportOptions*>( options );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( !commandLine.IsEmpty() )
|
|
|
|
{
|
|
|
|
localOptions = new idImportOptions();
|
|
|
|
localOptions->Init( commandLine, fileName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName );
|
2022-08-14 11:43:12 +00:00
|
|
|
GLTF_Parser gltf;
|
|
|
|
gltf.Load( gltfFileName );
|
2022-06-19 19:58:43 +00:00
|
|
|
|
2022-06-17 23:18:28 +00:00
|
|
|
timeStamp = fileSystem->GetTimestamp( gltfFileName );
|
2022-08-14 11:43:12 +00:00
|
|
|
data = gltf.currentAsset;
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
bounds.Clear();
|
2022-06-20 20:25:52 +00:00
|
|
|
|
2022-06-19 20:19:27 +00:00
|
|
|
int sceneId = data->DefaultScene();
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( sceneId >= 0 );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
auto scene = data->SceneList()[sceneId];
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( scene );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
auto nodes = data->NodeList();
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( nodes.Num() );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
//determine root node
|
2022-11-17 21:36:12 +00:00
|
|
|
if( !meshName[0] && data->MeshList().Num() )
|
2022-06-19 20:19:27 +00:00
|
|
|
{
|
2022-11-17 21:36:12 +00:00
|
|
|
gltfMesh* firstMesh = data->MeshList()[0];
|
|
|
|
|
2022-06-21 20:07:27 +00:00
|
|
|
fileExclusive = true;
|
2022-11-17 21:36:12 +00:00
|
|
|
root = data->GetNode( scene, firstMesh, &rootID );
|
|
|
|
if( root )
|
|
|
|
{
|
|
|
|
rootID = data->GetNodeIndex( root );
|
|
|
|
meshName = root->name;
|
|
|
|
}
|
2022-06-18 08:36:48 +00:00
|
|
|
}
|
2022-06-17 23:18:28 +00:00
|
|
|
else
|
2022-06-18 08:36:48 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
gltfNode* modelNode = data->GetNode( gltf_ModelSceneName.GetString(), meshName, &rootID );
|
2022-06-20 20:25:52 +00:00
|
|
|
if( modelNode )
|
2022-06-19 20:19:27 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
root = modelNode;
|
2022-06-19 20:19:27 +00:00
|
|
|
}
|
2022-06-18 08:36:48 +00:00
|
|
|
}
|
2022-06-17 23:18:28 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
if( !root )
|
2022-06-20 20:25:52 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
common->Warning( "Couldn't find model: '%s'", name.c_str() );
|
|
|
|
MakeDefaultModel();
|
2022-11-17 21:36:12 +00:00
|
|
|
|
|
|
|
if( localOptions && !options )
|
|
|
|
{
|
|
|
|
delete localOptions;
|
|
|
|
}
|
|
|
|
|
2022-06-19 20:19:27 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
//get allmeshes in hierachy, starting at root.
|
|
|
|
MeshNodeIds.Clear();
|
|
|
|
data->GetAllMeshes( root, MeshNodeIds );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
//find all animations and bones
|
2022-08-15 10:23:38 +00:00
|
|
|
bones.Clear();
|
2022-07-31 10:13:07 +00:00
|
|
|
int totalAnims = 0;
|
|
|
|
for( int meshID : MeshNodeIds )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
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 )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
currentSkin = data->SkinList()[tmpNode->skin];
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( currentSkin );
|
2022-07-31 10:13:07 +00:00
|
|
|
if( currentSkin->joints.Num() )
|
|
|
|
{
|
|
|
|
bones.Append( currentSkin->joints );
|
|
|
|
animCount = data->GetAnimationIds( nodes[bones[0]] , animIds );
|
|
|
|
}
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions->keepjoints.Num() )
|
2022-11-15 19:31:12 +00:00
|
|
|
{
|
2022-11-17 21:36:12 +00:00
|
|
|
KeepNodes( data, localOptions->keepjoints, bones );
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions->addOrigin )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-23 00:55:07 +00:00
|
|
|
|
2022-11-24 22:26:36 +00:00
|
|
|
AddOriginBone( data, bones, nodes[bones[0]]->parent );
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions->remapjoints.Num() )
|
2022-11-15 19:31:12 +00:00
|
|
|
{
|
2022-11-17 21:36:12 +00:00
|
|
|
RemapNodes( data, localOptions->remapjoints, bones );
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
2022-11-23 00:55:07 +00:00
|
|
|
if( localOptions->renamejoints.Num() )
|
|
|
|
{
|
|
|
|
RenameNodes( data, localOptions->renamejoints, bones );
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-08-14 11:43:12 +00:00
|
|
|
else
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
2022-11-15 19:28:06 +00:00
|
|
|
//Boneless TRS animation.
|
2022-08-14 11:43:12 +00:00
|
|
|
animCount = data->GetAnimationIds( tmpNode , animIds );
|
2022-07-31 10:13:07 +00:00
|
|
|
bones.Append( meshID );
|
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
totalAnims += animCount;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
hasAnimations = totalAnims > 0;
|
|
|
|
model_state = hasAnimations ? DM_CACHED : DM_STATIC;
|
2022-11-15 19:28:06 +00:00
|
|
|
globalTransform = blenderToDoomTransform;
|
2022-10-23 14:32:12 +00:00
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions )
|
2022-10-23 14:32:12 +00:00
|
|
|
{
|
|
|
|
const auto blenderToDoomRotation = idAngles( 0.0f, 0.0f, 90 ).ToMat3();
|
2022-11-16 19:07:47 +00:00
|
|
|
idMat3 reOrientationMat = blenderToDoomRotation;
|
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions->reOrient != ang_zero )
|
2022-11-16 19:07:47 +00:00
|
|
|
{
|
2022-11-17 21:36:12 +00:00
|
|
|
reOrientationMat = localOptions->reOrient.ToMat3();
|
2022-11-16 19:07:47 +00:00
|
|
|
}
|
2022-10-23 14:32:12 +00:00
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
float scale = localOptions->scale;
|
2022-10-23 14:32:12 +00:00
|
|
|
idMat3 scaleMat( scale, 0, 0, 0, scale, 0, 0, 0, scale );
|
|
|
|
|
2022-11-16 19:07:47 +00:00
|
|
|
globalTransform = idMat4( reOrientationMat * scaleMat, vec3_origin );
|
2022-10-23 14:32:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ProcessNode_r( root, mat4_identity, globalTransform, data );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( surfaces.Num() <= 0 )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
common->Warning( "Couldn't load model: '%s'", name.c_str() );
|
|
|
|
MakeDefaultModel();
|
2022-11-10 21:01:48 +00:00
|
|
|
data = nullptr;
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions && !options )
|
|
|
|
{
|
|
|
|
delete localOptions;
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
return;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-06-19 20:19:27 +00:00
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( options )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
if( options->addOrigin )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
//patch bone indices; all indices are offset with 1 after adding a bone
|
2022-11-15 19:31:12 +00:00
|
|
|
for( auto& surf : surfaces )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
for( int i = 0; i < surf.geometry->numVerts; i++ )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
|
|
|
idDrawVert& base = surf.geometry->verts[i];
|
|
|
|
base.color[0] += 1;
|
|
|
|
base.color[1] += 1;
|
|
|
|
base.color[2] += 1;
|
|
|
|
base.color[3] += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-20 22:20:25 +00:00
|
|
|
// derive mikktspace tangents from normals
|
|
|
|
FinishSurfaces( true );
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
LoadModel();
|
|
|
|
UpdateMd5Joints();
|
|
|
|
|
2022-06-19 20:19:27 +00:00
|
|
|
// it is now available for use
|
2022-08-01 20:05:13 +00:00
|
|
|
lastMeshFromFile = this;
|
2022-11-17 21:36:12 +00:00
|
|
|
if( localOptions && !options )
|
|
|
|
{
|
|
|
|
delete localOptions;
|
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-17 23:18:28 +00:00
|
|
|
bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp )
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
hasAnimations = false;
|
|
|
|
fileExclusive = false; // not written.
|
|
|
|
root = nullptr;
|
2022-08-07 13:56:46 +00:00
|
|
|
|
|
|
|
if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) )
|
|
|
|
{
|
2022-11-10 21:01:48 +00:00
|
|
|
data = nullptr;
|
2022-08-07 13:56:46 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
unsigned int magic = 0;
|
|
|
|
file->ReadBig( magic );
|
|
|
|
|
|
|
|
if( magic != GLMB_MAGIC )
|
|
|
|
{
|
2022-11-10 21:01:48 +00:00
|
|
|
data = nullptr;
|
2022-06-24 19:40:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-17 21:36:12 +00:00
|
|
|
file->ReadString( commandLine );
|
2022-06-24 19:40:08 +00:00
|
|
|
file->ReadBig( model_state );
|
|
|
|
file->ReadBig( rootID );
|
|
|
|
|
|
|
|
idStr dataFilename;
|
|
|
|
file->ReadString( dataFilename );
|
|
|
|
|
|
|
|
int animCnt;
|
|
|
|
file->ReadBig( animCnt );
|
|
|
|
if( animCnt > 0 )
|
|
|
|
{
|
|
|
|
animIds.Resize( animCnt, 1 );
|
2022-08-15 10:23:38 +00:00
|
|
|
file->ReadBigArray( animIds.Ptr(), animCnt );
|
2022-06-24 19:40:08 +00:00
|
|
|
animIds.SetNum( animCnt );
|
|
|
|
}
|
|
|
|
hasAnimations = animCnt > 0;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
int tempNum;
|
|
|
|
file->ReadBig( tempNum );
|
|
|
|
md5joints.SetNum( tempNum );
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < md5joints.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
file->ReadString( md5joints[i].name );
|
|
|
|
int offset;
|
|
|
|
file->ReadBig( offset );
|
|
|
|
if( offset >= 0 )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
md5joints[i].parent = md5joints.Ptr() + offset;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
md5joints[i].parent = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int boneCnt;
|
|
|
|
file->ReadBig( boneCnt );
|
|
|
|
if( boneCnt > 0 )
|
|
|
|
{
|
|
|
|
bones.Resize( boneCnt, 1 );
|
2022-08-15 10:23:38 +00:00
|
|
|
file->ReadBigArray( bones.Ptr(), boneCnt );
|
2022-07-10 19:09:25 +00:00
|
|
|
bones.SetNum( boneCnt );
|
|
|
|
}
|
|
|
|
else
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
2022-08-07 13:05:14 +00:00
|
|
|
if( hasAnimations && !bones.Num() )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
bones.Clear();
|
2022-07-10 19:09:25 +00:00
|
|
|
bones.Append( rootID );
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
file->ReadBig( tempNum );
|
|
|
|
defaultPose.SetNum( tempNum );
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < defaultPose.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
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 );
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < invertedDefaultPose.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
file->ReadBigArray( invertedDefaultPose[i].ToFloatPtr(), JOINTMAT_TYPESIZE );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-08-15 10:23:38 +00:00
|
|
|
SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), md5joints.Num() );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC;
|
|
|
|
|
2022-08-01 20:05:13 +00:00
|
|
|
lastMeshFromFile = this;
|
2022-11-10 21:01:48 +00:00
|
|
|
data = nullptr;
|
2022-06-21 20:07:27 +00:00
|
|
|
return true;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 17:29:11 +00:00
|
|
|
const idMD5Joint* idRenderModelGLTF::FindMD5Joint( const idStr& name ) const
|
|
|
|
{
|
|
|
|
for( auto& joint : md5joints )
|
|
|
|
{
|
|
|
|
if( joint.name == name )
|
|
|
|
{
|
|
|
|
return &joint;
|
|
|
|
}
|
|
|
|
}
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( 0 );
|
2022-09-05 17:29:11 +00:00
|
|
|
static idMD5Joint staticJoint;
|
|
|
|
return &staticJoint;
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
void idRenderModelGLTF::UpdateMd5Joints()
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
md5joints.Clear();
|
|
|
|
md5joints.Resize( bones.Num() );
|
|
|
|
md5joints.SetNum( bones.Num() );
|
2022-07-31 10:13:07 +00:00
|
|
|
idStr ovrBoneName;
|
2022-11-15 19:28:06 +00:00
|
|
|
int overrideIdx = -1;
|
2022-07-10 19:09:25 +00:00
|
|
|
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
|
2022-07-31 10:13:07 +00:00
|
|
|
if( i == 0 && node->name != "origin" )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
if( node->mesh == -1 )
|
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
common->Warning( "First bone of model \'%s\' is not named \"origin\"!", name.c_str() );
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
md5joints[i].name = node->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = 0 ; i < bones.Num(); i++ )
|
|
|
|
{
|
|
|
|
gltfNode* node = nodeList[bones[i]];
|
2022-07-31 10:13:07 +00:00
|
|
|
if( i && node->parent && node->parent != root )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
md5joints[i].parent = FindMD5Joint( node->parent->name );
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( bones.Num() == 1 )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
//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 ) ) );
|
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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++ )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
pos = ent->origin + joint->ToVec3() * ent->axis;
|
2022-07-10 19:09:25 +00:00
|
|
|
if( md5Joint->parent )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
parentNum = md5Joint->parent - md5joints.Ptr();
|
|
|
|
common->RW()->DebugLine( colorWhite, ent->origin + ent->joints[parentNum].ToVec3() * ent->axis, pos );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
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 );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
idBounds bounds;
|
|
|
|
|
|
|
|
bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis );
|
2022-08-15 10:23:38 +00:00
|
|
|
common->RW()->DebugBounds( colorMagenta, bounds, ent->origin );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
idVec3 offset( 0, 0, r_jointNameOffset.GetFloat() );
|
2022-07-10 19:09:25 +00:00
|
|
|
float scale;
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
scale = r_jointNameScale.GetFloat();
|
2022-07-10 19:09:25 +00:00
|
|
|
joint = ent->joints;
|
|
|
|
num = ent->numJoints;
|
|
|
|
for( i = 0; i < num; i++, joint++ )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
pos = ent->origin + joint->ToVec3() * ent->axis;
|
|
|
|
common->RW()->DrawText( md5joints[i].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-15 19:28:06 +00:00
|
|
|
static bool GatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfNode*>& nodes , idList<int, TAG_MODEL>& bones, idList<jointAnimInfo_t, TAG_MD5_ANIM>& jointInfo , const idImportOptions* options )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
//Gather Bones;
|
|
|
|
bool boneLess = false;
|
2022-08-14 11:43:12 +00:00
|
|
|
int targetNode = lastMeshFromFile->rootID;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
auto skin = data->GetSkin( gltfAnim );
|
|
|
|
auto targets = data->GetAnimTargets( gltfAnim );
|
2022-11-15 19:28:06 +00:00
|
|
|
auto& nodeList = data->NodeList();
|
2022-08-14 11:43:12 +00:00
|
|
|
if( skin == nullptr )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
boneLess = true;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//we cant be sure channels are sorted by bone?
|
|
|
|
if( !boneLess )
|
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
if( skin == nullptr )
|
|
|
|
{
|
2022-08-14 11:43:12 +00:00
|
|
|
skin = data->GetSkin( targetNode );
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( skin );
|
2022-07-31 10:13:07 +00:00
|
|
|
bones.Append( skin->joints );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
bones.Append( targetNode );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( options )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
if( options->keepjoints.Num() )
|
|
|
|
{
|
|
|
|
KeepNodes( data, options->keepjoints, bones );
|
|
|
|
}
|
|
|
|
if( options->addOrigin )
|
|
|
|
{
|
2022-11-23 00:55:07 +00:00
|
|
|
|
2022-11-24 22:26:36 +00:00
|
|
|
AddOriginBone( data, bones, data->NodeList()[bones[0]]->parent );
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
|
|
|
if( options->remapjoints.Num() )
|
|
|
|
{
|
|
|
|
RemapNodes( data, options->remapjoints, bones );
|
|
|
|
}
|
2022-11-23 00:55:07 +00:00
|
|
|
if( options->renamejoints.Num() )
|
|
|
|
{
|
|
|
|
RenameNodes( data, options->renamejoints, bones );
|
|
|
|
}
|
2022-11-15 19:31:12 +00:00
|
|
|
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
2022-11-15 19:31:12 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
//create jointInfo
|
|
|
|
jointInfo.SetGranularity( 1 );
|
2022-08-15 10:23:38 +00:00
|
|
|
jointInfo.SetNum( bones.Num() );
|
2022-11-15 19:31:12 +00:00
|
|
|
int idx = 0;
|
2022-07-10 19:09:25 +00:00
|
|
|
for( auto& joint : jointInfo )
|
|
|
|
{
|
|
|
|
joint.animBits = 0;
|
|
|
|
joint.firstComponent = -1;
|
2022-11-15 19:31:12 +00:00
|
|
|
joint.nameIndex = animationLib.JointIndex( nodeList[bones[idx++]]->name );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return boneLess;
|
|
|
|
}
|
|
|
|
|
2022-10-23 14:32:12 +00:00
|
|
|
static idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat, const idMat4& globalTransform )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
idList<idJointQuat> ret;
|
2022-08-15 10:23:38 +00:00
|
|
|
ret.AssureSize( bones.Num() );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < bones.Num(); i++ )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
auto* node = &bones[i];
|
|
|
|
|
|
|
|
idMat4 trans = mat4_identity;
|
|
|
|
gltfData::ResolveNodeMatrix( node, &trans, &bones[0] );
|
|
|
|
|
|
|
|
if( node->parent == nullptr )
|
|
|
|
{
|
2022-10-23 14:32:12 +00:00
|
|
|
node->matrix *= globalTransform;
|
2022-10-05 19:44:35 +00:00
|
|
|
trans = node->matrix;
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
idJointQuat& pose = ret[i];
|
2022-09-25 22:31:47 +00:00
|
|
|
pose.q = ( trans.ToMat3().ToQuat() );
|
2022-07-31 10:13:07 +00:00
|
|
|
pose.t = idVec3( trans[0][3], trans[1][3], trans[2][3] );
|
2022-08-15 10:23:38 +00:00
|
|
|
pose.w = pose.q.CalcW();
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < bones.Num(); i++ )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
const gltfNode* joint = &bones[i];
|
|
|
|
idJointQuat* pose = &ret[i];
|
2022-08-15 10:23:38 +00:00
|
|
|
poseMat[i].SetRotation( pose->q.ToMat3() );
|
2022-07-31 10:13:07 +00:00
|
|
|
poseMat[i].SetTranslation( pose->t );
|
|
|
|
if( joint->parent )
|
|
|
|
{
|
|
|
|
int parentNum = bones.FindIndex( *joint->parent );
|
2022-08-15 10:23:38 +00:00
|
|
|
pose->q = ( poseMat[i].ToMat3() * poseMat[parentNum].ToMat3().Transpose() ).ToQuat();
|
|
|
|
pose->t = ( poseMat[i].ToVec3() - poseMat[parentNum].ToVec3() ) * poseMat[parentNum].ToMat3().Transpose();
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2022-08-01 20:05:13 +00:00
|
|
|
|
2022-10-12 19:07:41 +00:00
|
|
|
static int CopyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>& out )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
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;
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < out.Num(); i++ )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2022-10-24 18:34:14 +00:00
|
|
|
idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TIME_T sourceTimeStamp, const idImportOptions* options )
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( lastMeshFromFile );
|
2022-10-23 14:32:12 +00:00
|
|
|
|
|
|
|
//keep in sync with game!
|
2022-07-10 19:09:25 +00:00
|
|
|
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;
|
2022-10-24 18:34:14 +00:00
|
|
|
|
|
|
|
// convert animName to original glTF2 filename and load it
|
2022-08-14 11:43:12 +00:00
|
|
|
GLTF_Parser gltf;
|
2022-11-23 00:55:07 +00:00
|
|
|
int rootMotionCopyTargetId = -1;
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
int id;
|
|
|
|
idStr gltfFileName = idStr( animName );
|
|
|
|
idStr name;
|
|
|
|
gltfManager::ExtractIdentifier( gltfFileName, id, name );
|
2022-08-14 11:43:12 +00:00
|
|
|
gltf.Load( gltfFileName );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-08-14 11:43:12 +00:00
|
|
|
gltfData* data = gltf.currentAsset;
|
2022-08-15 10:23:38 +00:00
|
|
|
auto& accessors = data->AccessorList();
|
|
|
|
auto& nodes = data->NodeList();
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-12-13 00:44:15 +00:00
|
|
|
idStr lastGltfFileName = idStr(lastMeshFromFile->name);
|
|
|
|
idStr lastName;
|
|
|
|
gltfManager::ExtractIdentifier(lastGltfFileName, id, lastName);
|
|
|
|
|
|
|
|
if (lastGltfFileName != gltfFileName)
|
|
|
|
{
|
|
|
|
common->Warning("Last loaded mesh was not the same file as the current animation");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-08-14 11:43:12 +00:00
|
|
|
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 );
|
2022-07-10 19:09:25 +00:00
|
|
|
if( !gltfAnim )
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
idList<int, TAG_MODEL> bones;
|
|
|
|
idList<jointAnimInfo_t, TAG_MD5_ANIM> jointInfo;
|
|
|
|
|
2022-11-15 19:28:06 +00:00
|
|
|
bool boneLess = GatherBoneInfo( data, gltfAnim, nodes, bones, jointInfo, options );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
idList<idList<gltfNode>> animBones;
|
2022-07-10 19:09:25 +00:00
|
|
|
idList<float, TAG_MD5_ANIM> componentFrames;
|
|
|
|
idList<idJointQuat, TAG_MD5_ANIM> baseFrame;
|
|
|
|
|
|
|
|
idList<idBounds, TAG_MD5_ANIM> bounds;
|
|
|
|
int numFrames = 0;
|
|
|
|
int frameRate = 0;
|
|
|
|
int numJoints = bones.Num();
|
|
|
|
int numAnimatedComponents = 0;
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
gameLocal.Printf( "Generating MD5Anim for GLTF anim %s from scene %s\n", name.c_str(), gltf_ModelSceneName.GetString() );
|
|
|
|
|
2022-11-15 19:28:06 +00:00
|
|
|
idMat4 globalTransform = blenderToDoomTransform;
|
2022-10-23 14:32:12 +00:00
|
|
|
|
2022-11-15 19:31:12 +00:00
|
|
|
if( options )
|
2022-11-15 19:28:06 +00:00
|
|
|
{
|
2022-11-23 00:55:07 +00:00
|
|
|
if( !options->transferRootMotion.IsEmpty() )
|
|
|
|
{
|
|
|
|
gltfNode* target = data->GetNode( options->transferRootMotion );
|
|
|
|
if( !target )
|
|
|
|
{
|
|
|
|
common->Warning( "Target bone to copy root motion from is not found" );
|
|
|
|
}
|
|
|
|
|
|
|
|
rootMotionCopyTargetId = data->GetNodeIndex( target );
|
|
|
|
}
|
2022-11-15 19:31:12 +00:00
|
|
|
const auto blenderToDoomRotation = idAngles( 0.0f, 0.0f, 90 ).ToMat3();
|
2022-11-16 19:07:47 +00:00
|
|
|
idMat3 reOrientationMat = blenderToDoomRotation;
|
|
|
|
|
|
|
|
if( options->reOrient != ang_zero )
|
|
|
|
{
|
|
|
|
reOrientationMat = options->reOrient.ToMat3();
|
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
|
|
|
|
float scale = options->scale;
|
2022-11-15 19:31:12 +00:00
|
|
|
idMat3 scaleMat( scale, 0, 0, 0, scale, 0, 0, 0, scale );
|
2022-10-23 14:32:12 +00:00
|
|
|
|
2022-11-16 19:07:47 +00:00
|
|
|
globalTransform = idMat4( reOrientationMat * scaleMat, vec3_origin );
|
2022-11-15 19:28:06 +00:00
|
|
|
}
|
2022-11-16 19:07:47 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
gltfNode* root = nullptr;
|
|
|
|
int channelCount = 0;
|
|
|
|
for( auto channel : gltfAnim->channels )
|
|
|
|
{
|
2022-08-14 11:43:12 +00:00
|
|
|
if( !bones.Find( channel->target.node ) )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
auto* sampler = gltfAnim->samplers[channel->sampler];
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
auto* input = accessors[sampler->input];
|
|
|
|
auto* output = accessors[sampler->output];
|
2022-07-10 19:09:25 +00:00
|
|
|
auto* target = nodes[channel->target.node];
|
|
|
|
jointAnimInfo_t* newJoint = &( jointInfo[ bones.FindIndex( channel->target.node ) ] );
|
|
|
|
|
|
|
|
idList<float>& timeStamps = data->GetAccessorView( input );
|
|
|
|
root = target;
|
|
|
|
int frames = timeStamps.Num();
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
2022-11-16 19:07:47 +00:00
|
|
|
//assert( newJoint->parentNum >= 0 );
|
2022-11-15 19:28:06 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
if( newJoint->firstComponent == -1 )
|
|
|
|
{
|
|
|
|
newJoint->firstComponent = numAnimatedComponents;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( channel->target.TRS )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
case gltfAnimation_Channel_Target::none:
|
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
case gltfAnimation_Channel_Target::rotation:
|
|
|
|
newJoint->animBits |= ANIM_QX | ANIM_QY | ANIM_QZ;
|
2022-08-01 20:05:13 +00:00
|
|
|
numAnimatedComponents += 3;
|
2022-07-10 19:09:25 +00:00
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
case gltfAnimation_Channel_Target::translation:
|
|
|
|
newJoint->animBits |= ANIM_TX | ANIM_TY | ANIM_TZ;
|
2022-08-01 20:05:13 +00:00
|
|
|
numAnimatedComponents += 3;
|
2022-07-10 19:09:25 +00:00
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
channelCount++;
|
|
|
|
}
|
2022-11-23 00:55:07 +00:00
|
|
|
|
|
|
|
if( options && !options->transferRootMotion.IsEmpty() )
|
|
|
|
{
|
|
|
|
jointAnimInfo_t* newJoint = &( jointInfo[0] );
|
2022-11-24 22:26:36 +00:00
|
|
|
newJoint->animBits = ANIM_TX | ANIM_TY | ANIM_TZ;
|
|
|
|
numAnimatedComponents += 3;
|
|
|
|
newJoint->firstComponent = -3;
|
2022-11-23 00:55:07 +00:00
|
|
|
for( auto& joint : jointInfo )
|
|
|
|
{
|
2022-11-24 22:26:36 +00:00
|
|
|
joint.firstComponent += 3;
|
2022-11-23 00:55:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
animBones.AssureSize( numFrames );
|
|
|
|
animBones.SetNum( numFrames );
|
|
|
|
for( int i = 0; i < numFrames; i++ )
|
|
|
|
{
|
2022-10-12 19:07:41 +00:00
|
|
|
int totalCopied = CopyBones( data, bones, animBones[i] );
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( totalCopied );
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gameLocal.Printf( "Total bones %i \n", bones.Num() );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
//we can calculate frame rate by:
|
|
|
|
// max_timestamp_value / totalFrames
|
|
|
|
// but keeping it fixed for now.
|
2022-07-10 19:09:25 +00:00
|
|
|
frameRate = gltf_AnimSampleRate.GetInteger();
|
2022-09-05 17:29:11 +00:00
|
|
|
int animLength = ( ( numFrames - 1 ) * 1000 + frameRate - 1 ) / frameRate;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < jointInfo.Num(); i++ )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
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 );
|
2022-08-15 10:23:38 +00:00
|
|
|
baseFrame.SetNum( bones.Num() );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) );
|
2022-11-15 19:28:06 +00:00
|
|
|
baseFrame = GetPose( animBones[0], poseMat, globalTransform );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
componentFrames.SetGranularity( 1 );
|
|
|
|
componentFrames.SetNum( ( ( numAnimatedComponents * numFrames ) ) + 1 );
|
|
|
|
int componentFrameIndex = 0;
|
|
|
|
for( int i = 0; i < numFrames; i++ )
|
|
|
|
{
|
|
|
|
for( auto channel : gltfAnim->channels )
|
|
|
|
{
|
2022-08-14 11:43:12 +00:00
|
|
|
if( !bones.Find( channel->target.node ) )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
auto sampler = gltfAnim->samplers[channel->sampler];
|
|
|
|
|
|
|
|
auto* input = accessors[sampler->input];
|
|
|
|
auto* output = accessors[sampler->output];
|
|
|
|
auto* target = nodes[channel->target.node];
|
|
|
|
idList<float>& timeStamps = data->GetAccessorView( input );
|
|
|
|
int boneIndex = bones.FindIndex( channel->target.node );
|
|
|
|
|
|
|
|
switch( channel->target.TRS )
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
case gltfAnimation_Channel_Target::none:
|
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
case gltfAnimation_Channel_Target::rotation:
|
|
|
|
{
|
|
|
|
idList<idQuat*>& values = data->GetAccessorView<idQuat>( output );
|
2022-08-15 10:23:38 +00:00
|
|
|
if( values.Num() > i )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
animBones[i][boneIndex].rotation = *values[i];
|
|
|
|
}
|
2022-10-12 19:07:41 +00:00
|
|
|
break;
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
case gltfAnimation_Channel_Target::translation:
|
|
|
|
{
|
|
|
|
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
2022-08-15 10:23:38 +00:00
|
|
|
if( values.Num() > i )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
2022-11-23 00:55:07 +00:00
|
|
|
if( channel->target.node == rootMotionCopyTargetId )
|
|
|
|
{
|
|
|
|
animBones[i][boneIndex].translation.y = values[i]->y;
|
|
|
|
animBones[i][0].translation = *values[i];
|
|
|
|
animBones[i][0].translation.y = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
animBones[i][boneIndex].translation = *values[i];
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-10-12 19:07:41 +00:00
|
|
|
break;
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
case gltfAnimation_Channel_Target::scale:
|
2022-10-12 19:07:41 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
2022-08-15 10:23:38 +00:00
|
|
|
if( values.Num() > i )
|
2022-08-14 11:43:12 +00:00
|
|
|
{
|
|
|
|
animBones[i][boneIndex].scale = *values[i] ;
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
break;
|
2022-10-12 19:07:41 +00:00
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-12 19:07:41 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int b = 0; b < bones.Num(); b++ )
|
2022-07-31 10:13:07 +00:00
|
|
|
{
|
|
|
|
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 ) )
|
|
|
|
{
|
2022-08-03 19:44:42 +00:00
|
|
|
if( node->parent == nullptr )
|
|
|
|
{
|
2022-11-16 19:07:47 +00:00
|
|
|
t = globalTransform * t;
|
2022-08-03 19:44:42 +00:00
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
componentFrames[componentFrameIndex++] = t.x;
|
|
|
|
componentFrames[componentFrameIndex++] = t.y;
|
|
|
|
componentFrames[componentFrameIndex++] = t.z;
|
|
|
|
}
|
2022-09-25 12:16:29 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
if( joint->animBits & ( ANIM_QX | ANIM_QY | ANIM_QZ ) )
|
|
|
|
{
|
|
|
|
if( node->parent == nullptr )
|
|
|
|
{
|
2022-11-16 19:07:47 +00:00
|
|
|
q = globalTransform.ToMat3().ToQuat() * animBones[i][b].rotation;
|
2022-07-31 10:13:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
q = -animBones[i][b].rotation;
|
|
|
|
}
|
|
|
|
|
|
|
|
componentFrames[componentFrameIndex++] = q.x;
|
|
|
|
componentFrames[componentFrameIndex++] = q.y;
|
|
|
|
componentFrames[componentFrameIndex++] = q.z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( componentFrames.Num() == ( componentFrameIndex + 1 ) );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
2022-08-01 20:05:13 +00:00
|
|
|
bounds.SetGranularity( 1 );
|
|
|
|
bounds.AssureSize( numFrames );
|
|
|
|
bounds.SetNum( numFrames );
|
2022-08-03 19:44:42 +00:00
|
|
|
|
2022-08-01 20:05:13 +00:00
|
|
|
//do software skinning to determine bounds.
|
2022-08-15 10:23:38 +00:00
|
|
|
idJointMat* currJoints = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) );
|
2022-08-01 20:05:13 +00:00
|
|
|
for( int i = 0; i < numFrames; i++ )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
bounds[i].Clear();
|
2022-08-01 20:05:13 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int b = 0; b < animBones[i].Num(); b++ )
|
2022-08-03 19:44:42 +00:00
|
|
|
{
|
|
|
|
if( animBones[i][b].parent == nullptr )
|
|
|
|
{
|
2022-11-23 00:55:07 +00:00
|
|
|
animBones[i][b].translation = globalTransform * animBones[i][b].translation;
|
2022-08-03 19:44:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 20:05:13 +00:00
|
|
|
idList<idJointMat> joints;
|
2022-11-16 19:07:47 +00:00
|
|
|
GetPose( animBones[i], currJoints, globalTransform );
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int b = 0; b < animBones[i].Num(); b++ )
|
2022-08-01 20:05:13 +00:00
|
|
|
{
|
|
|
|
idJointMat mat = poseMat[b];
|
2022-08-15 10:23:38 +00:00
|
|
|
mat.Invert();
|
|
|
|
idJointMat::Multiply( joints.Alloc(), currJoints[b], mat );
|
2022-08-01 20:05:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/// Start writing ////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
2022-07-10 19:09:25 +00:00
|
|
|
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 );
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( bounds.Num() );
|
|
|
|
for( int i = 0; i < bounds.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
idBounds& b = bounds[i];
|
|
|
|
file->WriteBig( b[0] );
|
|
|
|
file->WriteBig( b[1] );
|
|
|
|
}
|
|
|
|
|
|
|
|
//namestr list
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( jointInfo.Num() );
|
|
|
|
for( int i = 0; i < jointInfo.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
jointAnimInfo_t& j = jointInfo[i];
|
|
|
|
idStr jointName = animationLib.JointName( j.nameIndex );
|
2022-07-31 10:13:07 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
file->WriteString( jointName );
|
|
|
|
file->WriteBig( j.parentNum );
|
|
|
|
file->WriteBig( j.animBits );
|
|
|
|
file->WriteBig( j.firstComponent );
|
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
//base frame
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( baseFrame.Num() );
|
|
|
|
for( int i = 0; i < baseFrame.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//per joint timestamp values, T R
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( componentFrames.Num() - 1 );
|
|
|
|
for( int i = 0; i < componentFrames.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
file->WriteFloat( componentFrames[i] );
|
|
|
|
}
|
|
|
|
|
|
|
|
float* componentPtr = componentFrames.Ptr();
|
|
|
|
idVec3 totaldelta;
|
|
|
|
// get total move delta
|
|
|
|
if( !numAnimatedComponents )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
totaldelta.Zero();
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
if( jointInfo[0].animBits )
|
|
|
|
{
|
2022-11-15 19:28:06 +00:00
|
|
|
componentPtr = &componentFrames[jointInfo[0].firstComponent];
|
2022-11-15 19:31:12 +00:00
|
|
|
}
|
2022-11-15 19:28:06 +00:00
|
|
|
//of there is root movement on a different bone , for example when adding a root bone, this wil fail.
|
2022-07-10 19:09:25 +00:00
|
|
|
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
|
|
|
|
{
|
2022-06-21 20:07:27 +00:00
|
|
|
idRenderModelStatic::WriteBinaryModel( file );
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
if( file == NULL )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-06-21 20:07:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
file->WriteBig( GLMB_MAGIC );
|
2022-11-17 21:36:12 +00:00
|
|
|
file->WriteString( commandLine );
|
2022-06-24 19:40:08 +00:00
|
|
|
file->WriteBig( model_state );
|
|
|
|
file->WriteBig( rootID );
|
2022-08-14 11:43:12 +00:00
|
|
|
file->WriteString( file->GetName() );
|
2022-06-21 20:07:27 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( animIds.Num() );
|
|
|
|
if( animIds.Num() )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
file->WriteBigArray( animIds.Ptr(), animIds.Num() );
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( md5joints.Num() );
|
|
|
|
for( int i = 0; i < md5joints.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
file->WriteString( md5joints[i].name );
|
|
|
|
int offset = -1;
|
|
|
|
if( md5joints[i].parent != NULL )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
offset = md5joints[i].parent - md5joints.Ptr();
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
file->WriteBig( offset );
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( bones.Num() );
|
|
|
|
if( bones.Num() )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBigArray( bones.Ptr(), bones.Num() );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( defaultPose.Num() );
|
|
|
|
for( int i = 0; i < defaultPose.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBig( invertedDefaultPose.Num() );
|
|
|
|
for( int i = 0; i < invertedDefaultPose.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
file->WriteBigArray( invertedDefaultPose[i].ToFloatPtr(), JOINTMAT_TYPESIZE );
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
void idRenderModelGLTF::PurgeModel()
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-11-10 21:01:48 +00:00
|
|
|
idRenderModelStatic::PurgeModel();
|
2022-07-10 19:09:25 +00:00
|
|
|
purged = true;
|
2022-08-15 10:23:38 +00:00
|
|
|
md5joints.Clear();
|
|
|
|
defaultPose.Clear();
|
2022-07-31 10:13:07 +00:00
|
|
|
invertedDefaultPose.Clear();
|
2022-06-05 22:39:04 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
animIds.Clear();
|
|
|
|
bones.Clear();
|
|
|
|
MeshNodeIds.Clear();
|
2022-11-10 21:01:48 +00:00
|
|
|
gltfFileName.Clear();
|
2022-11-17 21:36:12 +00:00
|
|
|
meshName.Clear();
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
//if no root id was set, it is a generated one.
|
|
|
|
if( rootID == -1 && root )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
delete root;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-11-10 21:01:48 +00:00
|
|
|
data = nullptr;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
void idRenderModelGLTF::LoadModel()
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( data );
|
2022-11-10 21:01:48 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
int num;
|
2022-08-15 10:23:38 +00:00
|
|
|
auto& accessors = data->AccessorList();
|
|
|
|
auto& nodes = data->NodeList();
|
2022-08-15 14:13:04 +00:00
|
|
|
gltfNode* meshRoot = root;
|
2022-08-16 08:41:00 +00:00
|
|
|
if( !fileExclusive )
|
2022-08-15 14:13:04 +00:00
|
|
|
{
|
|
|
|
meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName );
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( meshRoot );
|
2022-08-15 14:13:04 +00:00
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
gltfSkin* skin = nullptr;
|
|
|
|
gltfAccessor* acc = nullptr;
|
2022-07-31 10:13:07 +00:00
|
|
|
if( currentSkin != nullptr )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
skin = currentSkin;
|
2022-08-15 10:23:38 +00:00
|
|
|
acc = data->AccessorList()[skin->inverseBindMatrices];
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
skin = new gltfSkin;
|
|
|
|
skin->joints.AssureSize( 1, rootID );
|
|
|
|
idMat4 trans = mat4_identity;
|
|
|
|
data->ResolveNodeMatrix( meshRoot, &trans );
|
|
|
|
acc = new gltfAccessor();
|
|
|
|
acc->matView = new idList<idMat4>( 1 );
|
|
|
|
acc->matView->AssureSize( 1, trans.Inverse() );
|
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
if( skin && skin->skeleton == -1 )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
skin->skeleton = skin->joints[0];
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
num = bones.Num();
|
|
|
|
md5joints.SetGranularity( 1 );
|
|
|
|
md5joints.SetNum( num );
|
|
|
|
defaultPose.SetGranularity( 1 );
|
|
|
|
defaultPose.SetNum( num );
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < bones.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
gltfNode* node = nodes[bones[i]];
|
|
|
|
|
|
|
|
//check for TRS anim and its artficial root bone
|
2022-08-15 10:23:38 +00:00
|
|
|
if( bones.Num() == 0 && node->mesh != -1 )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-11-15 19:31:12 +00:00
|
|
|
assert( 0 );
|
2022-11-15 19:28:06 +00:00
|
|
|
//md5joints[i].name = "origin";
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
md5joints[i].name = node->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < bones.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
auto* node = nodes[bones[i]];
|
|
|
|
|
|
|
|
if( i && node->parent && node->parent != root )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-09-05 17:29:11 +00:00
|
|
|
md5joints[i].parent = FindMD5Joint( node->parent->name );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) );
|
2022-07-31 10:13:07 +00:00
|
|
|
idList<gltfNode> animBones;
|
2022-10-12 19:07:41 +00:00
|
|
|
int totalCopied = CopyBones( data, bones, animBones );
|
2022-10-23 14:32:12 +00:00
|
|
|
defaultPose = GetPose( animBones, poseMat, globalTransform );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
if( !currentSkin )
|
|
|
|
{
|
|
|
|
delete skin;
|
|
|
|
delete acc;
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------
|
|
|
|
// 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
|
|
|
|
//-----------------------------------------
|
2022-08-15 10:23:38 +00:00
|
|
|
invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( md5joints.Num() ) );
|
|
|
|
for( int i = 0; i < md5joints.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
invertedDefaultPose[i] = poseMat[i];
|
2022-08-15 10:23:38 +00:00
|
|
|
invertedDefaultPose[i].Invert();
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-08-15 10:23:38 +00:00
|
|
|
SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), md5joints.Num() );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
//auto deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(),
|
|
|
|
// shader->UseUnsmoothedTangents() );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
model_state = hasAnimations ? DM_CACHED : DM_STATIC;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
// set the timestamp for reloadmodels
|
|
|
|
fileSystem->ReadFile( name, NULL, &timeStamp );
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
purged = false;
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
common->UpdateLevelLoadPacifier();
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
void idRenderModelGLTF::TouchData()
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0; i < surfaces.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
declManager->FindMaterial( surfaces[i].shader->GetName() );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
void idRenderModelGLTF::Print() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
idRenderModelStatic::Print();
|
|
|
|
// TODO
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
void idRenderModelGLTF::List() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
idRenderModelStatic::List();
|
|
|
|
// TODO
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
int idRenderModelGLTF::Memory() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
return idRenderModelStatic::Memory();
|
|
|
|
// TODO
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
dynamicModel_t idRenderModelGLTF::IsDynamicModel() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
return model_state;
|
|
|
|
}
|
|
|
|
|
2022-07-31 19:37:42 +00:00
|
|
|
idList<int> TransformVertsAndTangents_GLTF( idDrawVert* targetVerts, const int numVerts, const idDrawVert* baseVerts, const idJointMat* joints )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-07-31 19:37:42 +00:00
|
|
|
idList<int> jointIds;
|
2022-06-24 19:40:08 +00:00
|
|
|
for( int i = 0; i < numVerts; i++ )
|
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
const idDrawVert& base = baseVerts[i];
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
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]];
|
|
|
|
|
2022-08-01 20:05:13 +00:00
|
|
|
for( int j = 0; j < 4; j++ )
|
2022-07-31 19:37:42 +00:00
|
|
|
{
|
2022-08-16 18:35:52 +00:00
|
|
|
jointIds.AddUnique( base.color[j] );
|
2022-07-31 19:37:42 +00:00
|
|
|
}
|
|
|
|
|
2022-07-31 10:13:07 +00:00
|
|
|
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 );
|
2022-08-15 10:23:38 +00:00
|
|
|
targetVerts[i].SetNormal( accum * base.GetNormal() );
|
|
|
|
targetVerts[i].SetTangent( accum * base.GetTangent() );
|
2022-07-31 10:13:07 +00:00
|
|
|
targetVerts[i].tangent[3] = base.tangent[3];
|
2022-07-31 19:37:42 +00:00
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
2022-07-31 19:37:42 +00:00
|
|
|
return jointIds;
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
void idRenderModelGLTF::UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf, const modelSurface_t& sourceSurf )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
#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
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
//add skinning
|
2022-06-24 19:40:08 +00:00
|
|
|
if( surf->geometry != NULL )
|
|
|
|
{
|
|
|
|
R_FreeStaticTriSurfVertexCaches( surf->geometry );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
surf->geometry = R_AllocStaticTriSurf();
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
srfTriangles_t* tri = surf->geometry;
|
2022-07-10 19:09:25 +00:00
|
|
|
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;
|
|
|
|
|
2022-07-31 19:37:42 +00:00
|
|
|
idList<int> jointIds;
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( r_useGPUSkinning.GetBool() && glConfig.gpuSkinningAvailable )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
if( tri->verts != NULL && tri->verts != verts )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
R_FreeStaticTriSurfVerts( tri );
|
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
tri->verts = verts;
|
2022-07-10 19:09:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-31 19:37:42 +00:00
|
|
|
jointIds = TransformVertsAndTangents_GLTF( tri->verts, numVerts, verts, entJointsInverted );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
2022-07-31 10:13:07 +00:00
|
|
|
tri->tangentsCalculated = true;
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
#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;
|
2022-08-16 18:35:52 +00:00
|
|
|
for( int i = 0; i < md5joints.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-07-31 19:37:42 +00:00
|
|
|
const idJointMat& joint = entJoints[i];
|
2022-08-15 10:23:38 +00:00
|
|
|
__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 );
|
2022-07-10 19:09:25 +00:00
|
|
|
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 );
|
2022-08-15 10:23:38 +00:00
|
|
|
_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 ) );
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
#else
|
2022-08-15 10:23:38 +00:00
|
|
|
bounds.Clear();
|
|
|
|
for( int i = 0; i < jointIds.Num(); i++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-06 18:43:25 +00:00
|
|
|
const idJointMat& joint = entJoints[i];
|
2022-08-15 10:23:38 +00:00
|
|
|
bounds.AddPoint( joint.GetTranslation() );
|
2022-07-10 19:09:25 +00:00
|
|
|
}
|
|
|
|
bounds.ExpandSelf( maxJointVertDist );
|
|
|
|
|
|
|
|
#endif
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
/*
|
|
|
|
====================
|
|
|
|
TransformJoints
|
|
|
|
====================
|
|
|
|
*/
|
|
|
|
static void TransformJointsFast( idJointMat* __restrict outJoints, const int numJoints, const idJointMat* __restrict inJoints1, const idJointMat* __restrict inJoints2 )
|
|
|
|
{
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
float* outFloats = outJoints->ToFloatPtr();
|
|
|
|
const float* inFloats1 = inJoints1->ToFloatPtr();
|
|
|
|
const float* inFloats2 = inJoints2->ToFloatPtr();
|
2022-07-10 19:09:25 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEntity_s* ent, const viewDef_t* view, idRenderModel* cachedModel )
|
|
|
|
{
|
2022-06-24 19:40:08 +00:00
|
|
|
if( cachedModel != NULL && !r_useCachedDynamicModels.GetBool() )
|
|
|
|
{
|
|
|
|
delete cachedModel;
|
|
|
|
cachedModel = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( purged )
|
|
|
|
{
|
|
|
|
common->DWarning( "model %s instantiated while purged", Name() );
|
|
|
|
LoadModel();
|
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
if( !ent->joints )
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() );
|
2022-07-10 19:09:25 +00:00
|
|
|
delete cachedModel;
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-08-15 10:23:38 +00:00
|
|
|
else if( ent->numJoints != md5joints.Num() )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
common->Printf( "idRenderModelGLTF::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() );
|
2022-07-10 19:09:25 +00:00
|
|
|
delete cachedModel;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-24 19:40:08 +00:00
|
|
|
idRenderModelStatic* staticModel;
|
|
|
|
if( cachedModel != NULL )
|
|
|
|
{
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( dynamic_cast< idRenderModelStatic* >( cachedModel ) != NULL );
|
|
|
|
assert( idStr::Icmp( cachedModel->Name(), GLTF_SnapshotName ) == 0 );
|
2022-06-24 19:40:08 +00:00
|
|
|
staticModel = static_cast< idRenderModelStatic* >( cachedModel );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
staticModel = new( TAG_MODEL ) idRenderModelStatic;
|
|
|
|
staticModel->InitEmpty( GLTF_SnapshotName );
|
2022-07-10 19:09:25 +00:00
|
|
|
staticModel->jointsInverted = NULL;;
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
staticModel->bounds.Clear();
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( r_showSkel.GetInteger() )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
if( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
// only draw the skeleton
|
|
|
|
DrawJoints( ent, view );
|
|
|
|
}
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( r_showSkel.GetInteger() > 1 )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
// turn off the model when showing the skeleton
|
|
|
|
staticModel->InitEmpty( GLTF_SnapshotName );
|
|
|
|
return staticModel;
|
|
|
|
}
|
|
|
|
}
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
// update the GPU joints array
|
|
|
|
const int numInvertedJoints = SIMD_ROUND_JOINTS( md5joints.Num() );
|
|
|
|
if( staticModel->jointsInverted == NULL )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
staticModel->numInvertedJoints = numInvertedJoints;
|
|
|
|
staticModel->jointsInverted = ( idJointMat* ) Mem_ClearedAlloc( numInvertedJoints * sizeof( idJointMat ), TAG_JOINTMAT );
|
|
|
|
staticModel->jointsInvertedBuffer = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( staticModel->numInvertedJoints == numInvertedJoints );
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
TransformJointsFast( staticModel->jointsInverted, md5joints.Num(), ent->joints, invertedDefaultPose.Ptr() );
|
|
|
|
|
2022-08-14 18:02:06 +00:00
|
|
|
if( !staticModel->surfaces.Num() )
|
2022-06-24 19:40:08 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
for( int i = 0 ; i < surfaces.Num(); i++ )
|
2022-08-14 18:02:06 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
modelSurface_t* newSurf = &staticModel->surfaces.Alloc();
|
2022-08-14 18:02:06 +00:00
|
|
|
newSurf->geometry = NULL;
|
|
|
|
newSurf->shader = surfaces[i].shader;
|
|
|
|
}
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
int surfIdx = 0;
|
|
|
|
for( modelSurface_t& surf : staticModel->surfaces )
|
|
|
|
{
|
2022-08-14 18:02:06 +00:00
|
|
|
|
|
|
|
const idMaterial* shader = surf.shader;
|
2022-07-10 19:09:25 +00:00
|
|
|
shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader );
|
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
if( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
staticModel->DeleteSurfaceWithId( surfIdx++ );
|
|
|
|
continue;
|
|
|
|
}
|
2022-06-24 19:40:08 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
UpdateSurface( ent, ent->joints, staticModel->jointsInverted, &surf, surfaces[surfIdx++] );
|
2022-11-11 16:34:38 +00:00
|
|
|
assert( surf.geometry != NULL );
|
2022-07-10 19:09:25 +00:00
|
|
|
surf.geometry->staticModelWithJoints = staticModel;
|
|
|
|
staticModel->bounds.AddBounds( surf.geometry->bounds );
|
|
|
|
}
|
2022-06-24 19:40:08 +00:00
|
|
|
|
|
|
|
return staticModel;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
int idRenderModelGLTF::NumJoints() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-06-25 13:05:59 +00:00
|
|
|
|
2022-07-10 19:09:25 +00:00
|
|
|
return bones.Num();
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
const idMD5Joint* idRenderModelGLTF::GetJoints() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
idMD5Joint* result = nullptr;
|
|
|
|
if( md5joints.Num() )
|
|
|
|
{
|
|
|
|
return &md5joints[0];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
common->Warning( "GltfModel has no Joints" );
|
|
|
|
return nullptr;
|
|
|
|
}
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
jointHandle_t idRenderModelGLTF::GetJointHandle( const char* name ) const
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
const idMD5Joint* joint = md5joints.Ptr();
|
|
|
|
for( int i = 0; i < md5joints.Num(); i++, joint++ )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
if( idStr::Icmp( joint->name.c_str(), name ) == 0 )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
return ( jointHandle_t ) i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return INVALID_JOINT;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
const char* idRenderModelGLTF::GetJointName( jointHandle_t handle ) const
|
|
|
|
{
|
2022-08-15 10:23:38 +00:00
|
|
|
if( ( handle < 0 ) || ( handle >= md5joints.Num() ) )
|
2022-07-10 19:09:25 +00:00
|
|
|
{
|
|
|
|
return "<invalid joint>";
|
|
|
|
}
|
|
|
|
|
|
|
|
return md5joints[handle].name;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 08:43:30 +00:00
|
|
|
const idJointQuat* idRenderModelGLTF::GetDefaultPose() const
|
2022-06-06 14:13:32 +00:00
|
|
|
{
|
2022-07-10 19:09:25 +00:00
|
|
|
return defaultPose.Ptr();
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
int idRenderModelGLTF::NearestJoint( int surfaceNum, int a, int b, int c ) const
|
|
|
|
{
|
2022-09-05 17:29:11 +00:00
|
|
|
for( const modelSurface_t& surf : surfaces )
|
2022-08-03 23:40:59 +00:00
|
|
|
{
|
|
|
|
idDrawVert* verts = surf.geometry->verts;
|
|
|
|
int numVerts = surf.geometry->numVerts;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2022-07-10 19:09:25 +00:00
|
|
|
|
2022-08-15 10:23:38 +00:00
|
|
|
common->Warning( "Couldn't find NearestJoint for : '%s'", name.c_str() );
|
2022-08-03 23:40:59 +00:00
|
|
|
return 0;
|
2022-06-05 22:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-06 14:13:32 +00:00
|
|
|
idBounds idRenderModelGLTF::Bounds( const struct renderEntity_s* ent ) const
|
|
|
|
{
|
2022-07-31 10:13:07 +00:00
|
|
|
if( ent == NULL )
|
|
|
|
{
|
|
|
|
// this is the bounds for the reference pose
|
|
|
|
return bounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ent->bounds;
|
2022-06-24 19:40:08 +00:00
|
|
|
}
|