Merge branch '679-gltf-map-support2' into 679-gltf-map-support-nvrhi

This commit is contained in:
Robert Beckebans 2022-08-16 13:45:58 +02:00
commit f22d7f511b
18 changed files with 2281 additions and 406 deletions

View file

@ -554,6 +554,8 @@ endif (RAPIDJSON_FOUND)
add_subdirectory(idlib)
file(GLOB NATVIS_SOURCES .natvis)
file(GLOB AAS_INCLUDES aas/*.h)
file(GLOB AAS_SOURCES aas/*.cpp)
@ -1473,6 +1475,7 @@ set(RBDOOM3_INCLUDES
)
set(RBDOOM3_SOURCES
${NATVIS_SOURCES}
${AAS_SOURCES}
${CM_SOURCES}
${FRAMEWORK_SOURCES}

View file

@ -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 );
}

View file

@ -4573,7 +4573,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 );
}

View file

@ -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
{

View file

@ -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<idFile_Memory*>( fileptr );
fileSystem->WriteFile( generatedFileName, memFile->GetDataPtr(), memFile->GetAllocated(), "fs_basepath" );
}
return true;
}

View file

@ -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() );
}
@ -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++ )
{

63
neo/idStuff.natvis Normal file
View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- natvis file for Visual Studio debugger (you can include this in a project file, or install in visual studio folder) -->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="idList&lt;*&gt;">
<DisplayString>{{Size={num} Capacity={size}}}</DisplayString>
<Expand>
<Item Name="[size]">num</Item>
<Item Name="[capacity]">size</Item>
<ArrayItems>
<Size>num</Size>
<ValuePointer>list</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="idVec4">
<DisplayString>{{{x,g},{y,g},{z,g},{w,g}}}</DisplayString>
</Type>
<Type Name="idVec2">
<DisplayString>{{{x},{y}}}</DisplayString>
</Type>
<Type Name="idStr">
<DisplayString>{data,s}</DisplayString>
</Type>
<Type Name="idSWFDictionaryEntry">
<DisplayString Condition="name != 0">{name}</DisplayString>
<Expand>
<Item Condition="type == SWF_DICT_SPRITE" Name=" [ Sprite ]">sprite</Item>
<Item Condition="type == SWF_DICT_EDITTEXT" Name=" [ EditText ]">edittext</Item>
<Item Condition="type == SWF_DICT_FONT" Name=" [ Font ] ">font</Item>
<Item Condition="type == SWF_DICT_TEXT" Name=" [ Text ] ">text</Item>
<Item Condition="type == SWF_DICT_IMAGE" Name=" [ Image ]">imageSize</Item>
<Item Condition="type == SWF_DICT_NULL" Name=" [ Empty ] ">name</Item>
</Expand>
</Type>
<Type Name="idSWFScriptVar">
<Expand>
<Item Condition="type == SWF_VAR_OBJECT" Name=" [ Object ]">value.object</Item>
<Item Condition="type == SWF_VAR_FUNCTION" Name=" [ Function ]">value.function</Item>
<Item Condition="type == SWF_VAR_STRING" Name=" [ String ]">value.string</Item>
<Item Condition="type == SWF_VAR_FLOAT" Name=" [ Float ]">value.f</Item>
<Item Condition="type == SWF_VAR_UNDEF" Name=" [ UNDEFINED ]">value</Item>
<Item Condition="type == SWF_VAR_BOOL" Name=" [ Bool ]">value.b</Item>
<Item Condition="type == SWF_VAR_INTEGER" Name=" [ Int ]">value.i</Item>
<Item Condition="type == SWF_VAR_STRINGID" Name=" [ StrID ]">value.i</Item>
</Expand>
</Type>
<Type Name="idSWFScriptObject::swfNamedVar_t">
<DisplayString >[{name}]{value}</DisplayString>
</Type>
<Type Name="swfMethod_info">
<DisplayString >[{name}]</DisplayString>
</Type>
</AutoVisualizer>

View file

@ -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").
@ -1673,13 +1674,9 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
}
else if( isGTLF )
{
gltfParser->Load( fullName );
idMapEntity::GetEntities( gltfParser->currentAsset, entities, 0 );
}
else if( isGTLF )
{
gltfParser->Load( fullName );
idMapEntity::GetEntities( gltfParser->currentAsset, entities, gltfParser->currentAsset->GetSceneId( gltf_MapSceneName.GetString() ) );
GLTF_Parser gltf;
gltf.Load( fullName );
idMapEntity::GetEntities( gltf.currentAsset, entities, gltf.currentAsset->GetSceneId( gltf_MapSceneName.GetString() ) );
}
else
{

View file

@ -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;
@ -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;
@ -204,30 +214,72 @@ 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].SetColor2( PackColor( vec ) );
}
break;
}
case gltfMesh_Primitive_Attribute::Type::Indices:
{
if( attrAcc->typeSize == 2 )
{
uint16_t vec[4];
for( int i = 0; i < attrAcc->count; i++ )
{
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];
}
}
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;
}
}
}
@ -256,9 +308,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 ) );
}
@ -284,7 +336,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;
@ -299,7 +351,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 ) );
}
@ -307,7 +359,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 );
}
};

View file

@ -1135,8 +1135,14 @@ void gltfItem_texture_info_extensions::parse( idToken& token )
void GLTF_Parser::Shutdown()
{
parser.FreeSource();
currentFile.FreeData();
if( currentAsset )
{
delete currentAsset;
}
currentAsset = nullptr;
buffersDone = false;
bufferViewsDone = false;
}
GLTF_Parser::GLTF_Parser()
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ) { }
@ -1914,6 +1920,12 @@ gltfProperty GLTF_Parser::ResolveProp( idToken& token )
bool GLTF_Parser::loadGLB( idStr filename )
{
if( fileSystem->GetFileLength( filename ) <= 0 )
{
common->Warning( " %s does not exist!", filename.c_str() );
return false;
}
idFile* file = fileSystem->OpenFileRead( filename );
if( file->Length() < 20 )
@ -1948,7 +1960,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;
@ -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 )
@ -2074,21 +2085,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 );
if( lastFile == filename )
//.. and destroy data !!
gltfData* data = gltfData::Data( filename );
currentFile = filename;
if( data != nullptr )
{
common->Warning( "Did not parse %s again", filename.c_str() );
currentAsset = data;
parser.FreeSource();
return true;
}
lastFile = filename;
currentFile = filename;
common->SetRefreshOnPrint( true );
if( filename.CheckExtension( ".glb" ) )
{
if( !loadGLB( filename ) )
@ -2104,8 +2112,7 @@ bool GLTF_Parser::Load( idStr filename )
common->FatalError( "Failed to read file" );
}
gltfData* data = gltfData::Data( filename );
data->FileName( filename );
data = gltfData::Data( filename , true );
byte* dataBuff = data->AddData( length );
currentAsset = data;
@ -2137,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;
}
@ -2287,20 +2305,45 @@ idList<idQuat*>& gltfData::GetAccessorView( gltfAccessor* accessor )
gltfData::~gltfData()
{
//hvg_todo
//delete data, not only pointer
common->Warning( "GLTF DATA NOT FREED" );
if( data )
{
delete[] data;
while( totalChunks )
{
Mem_Free( data[--totalChunks] );
}
Mem_Free( data );
}
//delete cameraManager;
if( json )
{
Mem_Free( json );
}
data = nullptr;
json = nullptr;
ClearData( fileName );
}
void gltfData::ClearData( idStr& fileName )
{
int key = fileDataHash.GenerateKey( fileName );
int index = fileDataHash.GetFirst( key );
if( index != -1 )
{
dataList.RemoveIndex( index );
dataList.Condense();
fileDataHash.RemoveIndex( key, index );
}
else
{
common->DWarning( " tried to clear GLTF data while no data was loaded for %s", fileName.c_str() );
}
}
GLTF_Parser localGltfParser;
GLTF_Parser* gltfParser = &localGltfParser;
#undef GLTFARRAYITEM
#undef GLTFARRAYITEMREF
@ -2310,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 ) );
}
}
@ -2318,39 +2362,39 @@ 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 )
// [filename].[%i|%s].[gltf|glb]
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
{

View file

@ -303,6 +303,10 @@ private:
class GLTF_Parser
{
public:
~GLTF_Parser()
{
Shutdown();
}
GLTF_Parser();
void Shutdown();
bool Parse();
@ -349,7 +353,5 @@ private:
class gltfManager
{
public:
static bool ExtractMeshIdentifier( idStr& filename , int& meshId, idStr& meshName );
};
extern GLTF_Parser* gltfParser;
static bool ExtractIdentifier( idStr& filename , int& id, idStr& name );
};

View file

@ -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<int> children;
int skin;
@ -760,7 +765,7 @@ const inline idList<gltf##name*> & ##name##List() { return target; }
class gltfData
{
public:
gltfData() : fileNameHash( 0 ), json( nullptr ), data( nullptr ), totalChunks( -1 ) { };
gltfData() : fileName( "" ), fileNameHash( 0 ), json( nullptr ), data( nullptr ), totalChunks( -1 ) { };
~gltfData();
byte* AddData( int size, int* bufferID = nullptr );
byte* GetJsonData( int& size )
@ -772,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()
{
@ -788,27 +793,39 @@ public:
static idHashIndex fileDataHash;
static idList<gltfData*> 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<gltfData> );
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 ) )];
static bool intialized = false;
if( ! intialized )
{
dataList.SetGranularity( 1 );
intialized = true;
}
int key = fileDataHash.GenerateKey( fileName );
int index = fileDataHash.GetFirst( key );
if( create && index == -1 )
{
index = dataList.Num();
dataList.AssureSizeAlloc( index + 1, idListNewElement<gltfData> );
dataList[index]->FileName( fileName, key );
fileDataHash.Add( key , index );
}
if( !create && index < 0 )
{
return nullptr;
}
return dataList[index];
}
static const idList<gltfData*>& DataList()
{
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..)
@ -866,27 +883,10 @@ 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 );
if( sceneId < 0 || sceneId > scenes.Num( ) )
if( sceneId < 0 || sceneId > scenes.Num() )
{
return nullptr;
}
@ -913,7 +913,30 @@ public:
return nullptr;
}
gltfNode* GetNode( idStr sceneName, idStr name , int* id = 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 );
if( sceneId < 0 || sceneId > scenes.Num() )
@ -927,9 +950,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 )
{
@ -943,6 +966,20 @@ public:
return nullptr;
}
int GetNodeIndex( gltfNode* node )
{
int index = -1;
for( auto& it : nodes )
{
index++;
if( it == node )
{
return index;
}
}
return -1;
}
bool HasAnimation( int nodeID )
{
for( auto anim : animations )
@ -958,18 +995,142 @@ public:
return false;
}
int GetSceneId( idStr sceneName ) const
gltfAnimation* GetAnimation( idStr animName, int target )
{
for( auto* anim : animations )
{
if( anim->name == animName )
{
bool hasTarget = false;
for( auto* channel : anim->channels )
{
if( channel->target.node == target )
{
hasTarget = true;
break;
}
}
if( hasTarget )
{
return anim;
}
}
}
return nullptr;
}
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;
}
void GetAllMeshes( gltfNode* node, idList<int>& 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<int> GetAnimTargets( gltfAnimation* anim ) const
{
idList<int> result;
for( auto channel : anim->channels )
{
result.AddUnique( channel->target.node );
}
return result;
}
idList<int> GetChannelIds( gltfAnimation* anim , gltfNode* node ) const
{
idList<int> 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;
}
int GetAnimationIds( gltfNode* node , idList<int>& result )
{
int animIdx = 0;
for( auto anim : animations )
{
for( auto channel : anim->channels )
{
if( channel->target.node >= 0 && nodes[channel->target.node] == node )
{
result.AddUnique( animIdx );
}
}
animIdx++;
}
for( int nodeId : node->children )
{
GetAnimationIds( nodes[nodeId], result );
}
return result.Num();
}
idMat4 GetViewMatrix( int camId ) const
{
//if (cameraManager->HasOverideID(camId) )

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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,28 @@ public:
{
return true;
}
void MakeMD5Mesh() ;
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, idMat4 trans, modelSurface_t* surf );
int rootID;
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;
bool fileExclusive;
bool hasAnimations;
idList<int> animIds;
idList<idGltfMesh, TAG_MODEL> meshes;
float maxJointVertDist; // maximum distance a vertex is separated from a joint
idList<int, TAG_MODEL> animIds;
idList<int, TAG_MODEL> bones;
idList<int, TAG_MODEL> MeshNodeIds;
dynamicModel_t model_state;
idMat4 prevTrans;
idList<gltfNode*, TAG_MODEL> SkeletonNodes;
idStr meshName;
idList<idMD5Joint, TAG_MODEL> md5joints;
idList<idJointQuat, TAG_MODEL> defaultPose;
idList<idJointMat, TAG_MODEL> invertedDefaultPose;
gltfSkin* currentSkin;
private:
void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view );
};

View file

@ -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<idDrawVert>& verts = mapMesh->GetDrawVerts();
const idList<int>& 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;

View file

@ -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;