mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 22:50:45 +00:00
Merge branch 'master' into 635-nvrhi4
This commit is contained in:
commit
37127cde0e
27 changed files with 40925 additions and 196 deletions
23483
base/_tb/fgd/DOOM-3-all.fgd
Normal file
23483
base/_tb/fgd/DOOM-3-all.fgd
Normal file
File diff suppressed because it is too large
Load diff
5523
base/_tb/fgd/DOOM-3-models.fgd
Normal file
5523
base/_tb/fgd/DOOM-3-models.fgd
Normal file
File diff suppressed because it is too large
Load diff
224
base/_tb/fgd/DOOM-3-multiplayer.fgd
Normal file
224
base/_tb/fgd/DOOM-3-multiplayer.fgd
Normal file
|
@ -0,0 +1,224 @@
|
|||
// DOOM 3 BFG game definition file (.fgd) generated by RBDOOM 3 BFG 1.4.0
|
||||
|
||||
@PointClass base(ammo_belt_small) = ammo_belt_small_mp : "No description"
|
||||
[
|
||||
inv_ammo_belt(string) : "" : "120"
|
||||
]
|
||||
|
||||
@PointClass base(ammo_bullets_large) = ammo_bullets_large_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_bullets_small) = ammo_bullets_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_cells_large) = ammo_cells_large_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_cells_small) = ammo_cells_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_clip_large) = ammo_clip_large_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_clip_small) = ammo_clip_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_grenade_small) = ammo_grenade_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_rockets_large) = ammo_rockets_large_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_rockets_small) = ammo_rockets_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_shells_large) = ammo_shells_large_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(ammo_shells_small) = ammo_shells_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(item_armor_security) = item_armor_security_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(item_armor_shard) = item_armor_shard_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(item_medkit) = item_medkit_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(item_medkit_small) = item_medkit_small_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_bfg) = moveable_item_bfg_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_chaingun) = moveable_item_chaingun_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_chainsaw) = moveable_item_chainsaw_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_grenades) = moveable_item_grenades_mp : "No description"
|
||||
[
|
||||
damage(string) : "" : "80"
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_machinegun) = moveable_item_machinegun_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_pistol) = moveable_item_pistol_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_plasmagun) = moveable_item_plasmagun_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_rocketlauncher) = moveable_item_rocketlauncher_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_shotgun) = moveable_item_shotgun_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(item_team_default) model({ "path": "_tb/models/ctf/ctf_flag.obj" }) = team_ctf_blueflag : "CTF: the blue flag
|
||||
"
|
||||
[
|
||||
model(string) : "" : "models/ctf/ctf_flag.ase"
|
||||
team(string) : "" : "1"
|
||||
spin(string) : "" : "0"
|
||||
skin(string) : "" : "skins/ctf/blue_flag"
|
||||
skin_carried(string) : "" : "skins/ctf/blue_flag_not_idle"
|
||||
inv_name(string) : "" : "blueflag"
|
||||
script_taken(string) : "" : "blue_flag_taken"
|
||||
script_dropped(string) : "" : ""
|
||||
script_returned(string) : "" : "blue_flag_returned"
|
||||
script_captured(string) : "" : "blue_flag_captured"
|
||||
bouncyness(string) : "" : "0"
|
||||
friction(string) : "" : "0.8"
|
||||
density(string) : "" : "500"
|
||||
gravity(string) : "" : "-35"
|
||||
pickupDelay(string) : "" : "500"
|
||||
net_dynamic(string) : "" : "1"
|
||||
noshadows(string) : "" : "1"
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_default) model({ "path": "_tb/models/ctf/flagfx/blue_ember.obj" }) = team_ctf_blueflag_nugget : "No description"
|
||||
[
|
||||
model(string) : "" : "models/ctf/flagfx/blue_ember.ase"
|
||||
clipmodel(string) : "" : "models/ctf/flagfx/blue_ember.ase"
|
||||
density(string) : "" : "0.5"
|
||||
friction(string) : "" : "0.5"
|
||||
bouncyness(string) : "" : "0.3"
|
||||
smoke_trail(string) : "" : "blue_flag_smoke_fx.prt"
|
||||
nopulse(string) : "" : "1"
|
||||
repeatSmoke(string) : "" : "1"
|
||||
networkSync(string) : "" : "1"
|
||||
]
|
||||
|
||||
@PointClass base(item_team_default) model({ "path": "_tb/models/ctf/ctf_flag.obj" }) = team_ctf_redflag : "CTF: the red flag
|
||||
"
|
||||
[
|
||||
model(string) : "" : "models/ctf/ctf_flag.ase"
|
||||
team(string) : "" : "0"
|
||||
spin(string) : "" : "0"
|
||||
skin(string) : "" : "skins/ctf/red_flag"
|
||||
skin_carried(string) : "" : "skins/ctf/red_flag_not_idle"
|
||||
inv_name(string) : "" : "redflag"
|
||||
script_taken(string) : "" : "red_flag_taken"
|
||||
script_dropped(string) : "" : ""
|
||||
script_returned(string) : "" : "red_flag_returned"
|
||||
script_captured(string) : "" : "red_flag_captured"
|
||||
bouncyness(string) : "" : "0"
|
||||
friction(string) : "" : "0.8"
|
||||
density(string) : "" : "500"
|
||||
gravity(string) : "" : "-35"
|
||||
pickupDelay(string) : "" : "500"
|
||||
net_dynamic(string) : "" : "1"
|
||||
noshadows(string) : "" : "1"
|
||||
]
|
||||
|
||||
@PointClass base(moveable_item_default) model({ "path": "_tb/models/ctf/flagfx/red_ember.obj" }) = team_ctf_redflag_nugget : "No description"
|
||||
[
|
||||
model(string) : "" : "models/ctf/flagfx/red_ember.ase"
|
||||
clipmodel(string) : "" : "models/ctf/flagfx/red_ember.ase"
|
||||
density(string) : "" : "0.5"
|
||||
friction(string) : "" : "0.5"
|
||||
bouncyness(string) : "" : "0.3"
|
||||
smoke_trail(string) : "" : "red_flag_smoke_fx.prt"
|
||||
nopulse(string) : "" : "1"
|
||||
repeatSmoke(string) : "" : "1"
|
||||
networkSync(string) : "" : "1"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_bfg) = weapon_bfg_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(weapon_chaingun) = weapon_chaingun_mp : "No description"
|
||||
[
|
||||
spread(string) : "" : "1"
|
||||
inv_ammo_belt(string) : "" : "60"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_chainsaw) = weapon_chainsaw_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(weapon_handgrenade) = weapon_handgrenade_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(weapon_machinegun) = weapon_machinegun_mp : "No description"
|
||||
[
|
||||
spread(string) : "" : "1"
|
||||
inv_ammo_clip(string) : "" : "60"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_pistol) = weapon_pistol_mp : "No description"
|
||||
[
|
||||
]
|
||||
|
||||
@PointClass base(weapon_plasmagun) = weapon_plasmagun_mp : "No description"
|
||||
[
|
||||
inv_ammo_cells(string) : "" : "30"
|
||||
clipSize(string) : "" : "30"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_rocketlauncher) model({ "path": "_tb/models/weapons/rocketlauncher/mp_rocketlauncher.obj" }) = weapon_rocketlauncher_mp : "No description"
|
||||
[
|
||||
model(string) : "" : "models/weapons/rocketlauncher/mp_rocketlauncher.lwo"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_shotgun_double) model({ "path": "_tb/models/weapons/doublebarrel/doublebarrel_w.obj" }) = weapon_shotgun_double_mp : "No description"
|
||||
[
|
||||
model(string) : "" : "models/weapons/doublebarrel/doublebarrel_w.lwo"
|
||||
]
|
||||
|
||||
@PointClass base(weapon_shotgun) = weapon_shotgun_mp : "No description"
|
||||
[
|
||||
inv_ammo_shells(string) : "" : "8"
|
||||
spread(string) : "" : "11"
|
||||
]
|
||||
|
10523
base/_tb/fgd/DOOM-3-slim.fgd
Normal file
10523
base/_tb/fgd/DOOM-3-slim.fgd
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2,8 +2,8 @@ entityDef misc_model
|
|||
{
|
||||
"inherit" "func_static"
|
||||
"editor_color" "0 .5 .8"
|
||||
"editor_mins" "?"
|
||||
"editor_maxs" "?"
|
||||
"editor_mins" "-8 -8 0"
|
||||
"editor_maxs" "8 8 16"
|
||||
"editor_rotatable" "1"
|
||||
|
||||
"editor_usage" "Inherits from a func_static but uses a model and is a FGD PointClass so it displays correctly in TrenchBroom."
|
||||
|
@ -13,32 +13,24 @@ entityDef misc_model
|
|||
entityDef func_door_model
|
||||
{
|
||||
"inherit" "func_door"
|
||||
|
||||
"editor_mins" "-8 -8 0"
|
||||
"editor_maxs" "8 8 16"
|
||||
"editor_usage" "Inherits from a func_door but uses a model and is a FGD PointClass so it displays correctly in TrenchBroom."
|
||||
"editor_usage1" "Use it to place all kinds of models"
|
||||
}
|
||||
|
||||
/*
|
||||
already exists and is called func_mover_amodel ...
|
||||
|
||||
entityDef func_mover_model
|
||||
{
|
||||
"inherit" "func_mover"
|
||||
|
||||
"editor_usage" "Inherits from a func_mover but uses a model and is a FGD PointClass so it displays correctly in TrenchBroom."
|
||||
}
|
||||
*/
|
||||
|
||||
entityDef func_rotating_model
|
||||
{
|
||||
"inherit" "func_rotating"
|
||||
|
||||
"editor_mins" "-8 -8 0"
|
||||
"editor_maxs" "8 8 16"
|
||||
"editor_usage" "Inherits from a func_rotating but uses a model and is a FGD PointClass so it displays correctly in TrenchBroom."
|
||||
}
|
||||
|
||||
entityDef func_plat_model
|
||||
{
|
||||
"inherit" "func_plat"
|
||||
|
||||
"editor_mins" "-8 -8 0"
|
||||
"editor_maxs" "8 8 16"
|
||||
"editor_usage" "Inherits from a func_plat but uses a model and is a FGD PointClass so it displays correctly in TrenchBroom."
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Harrie van Ginneken
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -30,7 +31,10 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#pragma hdrstop
|
||||
|
||||
#include "Game_local.h"
|
||||
#include "gltfParser.h"
|
||||
|
||||
|
||||
static const idMat4 blenderToDoomTransform( idAngles( 0.0f, 0.0f, 90 ).ToMat3(), vec3_origin );
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
|
@ -363,6 +367,10 @@ void idCameraAnim::LoadAnim()
|
|||
int i;
|
||||
idStr filename;
|
||||
const char* key;
|
||||
idStr gltfFileName;
|
||||
int animID = -1;
|
||||
idStr animName;
|
||||
bool isGLTF = false;
|
||||
|
||||
key = spawnArgs.GetString( "anim" );
|
||||
if( !key )
|
||||
|
@ -373,86 +381,102 @@ void idCameraAnim::LoadAnim()
|
|||
filename = spawnArgs.GetString( va( "anim %s", key ) );
|
||||
if( !filename.Length() )
|
||||
{
|
||||
// RB: TrenchBroom interop use anim.<name> instead so we can build this up using the FGD files
|
||||
filename = spawnArgs.GetString( va( "anim.%s", key ) );
|
||||
if( !filename.Length() )
|
||||
gltfFileName = key;
|
||||
gltfManager::ExtractIdentifier( gltfFileName, animID, animName );
|
||||
if( animName.Length() )
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim.%s' key on '%s'", key, name.c_str() );
|
||||
isGLTF = true;
|
||||
}
|
||||
// RB end
|
||||
}
|
||||
|
||||
filename.SetFileExtension( MD5_CAMERA_EXT );
|
||||
if( !parser.LoadFile( filename ) )
|
||||
{
|
||||
gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
|
||||
}
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
|
||||
parser.ExpectTokenString( MD5_VERSION_STRING );
|
||||
version = parser.ParseInt();
|
||||
if( version != MD5_VERSION )
|
||||
{
|
||||
parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
|
||||
}
|
||||
|
||||
// skip the commandline
|
||||
parser.ExpectTokenString( "commandline" );
|
||||
parser.ReadToken( &token );
|
||||
|
||||
// parse num frames
|
||||
parser.ExpectTokenString( "numFrames" );
|
||||
numFrames = parser.ParseInt();
|
||||
if( numFrames <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid number of frames: %d", numFrames );
|
||||
}
|
||||
|
||||
// parse framerate
|
||||
parser.ExpectTokenString( "frameRate" );
|
||||
frameRate = parser.ParseInt();
|
||||
if( frameRate <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid framerate: %d", frameRate );
|
||||
}
|
||||
|
||||
// parse num cuts
|
||||
parser.ExpectTokenString( "numCuts" );
|
||||
numCuts = parser.ParseInt();
|
||||
if( ( numCuts < 0 ) || ( numCuts > numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid number of camera cuts: %d", numCuts );
|
||||
}
|
||||
|
||||
// parse the camera cuts
|
||||
parser.ExpectTokenString( "cuts" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
cameraCuts.SetNum( numCuts );
|
||||
for( i = 0; i < numCuts; i++ )
|
||||
{
|
||||
cameraCuts[ i ] = parser.ParseInt();
|
||||
if( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) )
|
||||
else
|
||||
{
|
||||
parser.Error( "Invalid camera cut" );
|
||||
// RB: TrenchBroom interop use anim.<name> instead so we can build this up using the FGD files
|
||||
filename = spawnArgs.GetString( va( "anim.%s", key ) );
|
||||
if( !filename.Length() )
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim.%s' key on '%s'", key, name.c_str() );
|
||||
}
|
||||
// RB end
|
||||
}
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
|
||||
// parse the camera frames
|
||||
parser.ExpectTokenString( "camera" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
camera.SetNum( numFrames );
|
||||
for( i = 0; i < numFrames; i++ )
|
||||
if( isGLTF )
|
||||
{
|
||||
parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() );
|
||||
parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() );
|
||||
camera[ i ].fov = parser.ParseFloat();
|
||||
gltfLoadAnim( gltfFileName, animName );
|
||||
}
|
||||
else
|
||||
{
|
||||
filename.SetFileExtension( MD5_CAMERA_EXT );
|
||||
if( !parser.LoadFile( filename ) )
|
||||
{
|
||||
gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
|
||||
}
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
|
||||
parser.ExpectTokenString( MD5_VERSION_STRING );
|
||||
version = parser.ParseInt();
|
||||
if( version != MD5_VERSION )
|
||||
{
|
||||
parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
|
||||
}
|
||||
|
||||
// skip the commandline
|
||||
parser.ExpectTokenString( "commandline" );
|
||||
parser.ReadToken( &token );
|
||||
|
||||
// parse num frames
|
||||
parser.ExpectTokenString( "numFrames" );
|
||||
numFrames = parser.ParseInt();
|
||||
if( numFrames <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid number of frames: %d", numFrames );
|
||||
}
|
||||
|
||||
// parse framerate
|
||||
parser.ExpectTokenString( "frameRate" );
|
||||
frameRate = parser.ParseInt();
|
||||
if( frameRate <= 0 )
|
||||
{
|
||||
parser.Error( "Invalid framerate: %d", frameRate );
|
||||
}
|
||||
|
||||
// parse num cuts
|
||||
parser.ExpectTokenString( "numCuts" );
|
||||
numCuts = parser.ParseInt();
|
||||
if( ( numCuts < 0 ) || ( numCuts > numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid number of camera cuts: %d", numCuts );
|
||||
}
|
||||
|
||||
// parse the camera cuts
|
||||
parser.ExpectTokenString( "cuts" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
cameraCuts.SetNum( numCuts );
|
||||
for( i = 0; i < numCuts; i++ )
|
||||
{
|
||||
cameraCuts[i] = parser.ParseInt();
|
||||
if( ( cameraCuts[i] < 1 ) || ( cameraCuts[i] >= numFrames ) )
|
||||
{
|
||||
parser.Error( "Invalid camera cut" );
|
||||
}
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
|
||||
// parse the camera frames
|
||||
parser.ExpectTokenString( "camera" );
|
||||
parser.ExpectTokenString( "{" );
|
||||
camera.SetNum( numFrames );
|
||||
for( i = 0; i < numFrames; i++ )
|
||||
{
|
||||
parser.Parse1DMatrix( 3, camera[i].t.ToFloatPtr() );
|
||||
parser.Parse1DMatrix( 3, camera[i].q.ToFloatPtr() );
|
||||
camera[i].fov = parser.ParseFloat();
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
}
|
||||
parser.ExpectTokenString( "}" );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -692,6 +716,123 @@ void idCameraAnim::Event_Activate( idEntity* _activator )
|
|||
}
|
||||
}
|
||||
|
||||
void idCameraAnim::gltfLoadAnim( idStr gltfFileName, idStr animName )
|
||||
{
|
||||
//we dont wat to load the gltb all the time. write custom binary format !
|
||||
GLTF_Parser gltf;
|
||||
if( gltf.Load( gltfFileName ) )
|
||||
{
|
||||
ID_TIME_T timeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
gltfData* data = gltf.currentAsset;
|
||||
auto& accessors = data->AccessorList();
|
||||
auto& nodes = data->NodeList();
|
||||
|
||||
gltfNode* cameraNode = data->GetNode( name );
|
||||
assert( cameraNode );
|
||||
|
||||
gltfAnimation* anim = data->GetAnimation( animName, data->GetNodeIndex( cameraNode ) );
|
||||
assert( anim );
|
||||
|
||||
cameraCuts.Clear();
|
||||
cameraCuts.SetGranularity( 1 );
|
||||
camera.Clear();
|
||||
camera.SetGranularity( 1 );
|
||||
frameRate = 24;
|
||||
for( auto channel : anim->channels )
|
||||
{
|
||||
auto* sampler = anim->samplers[channel->sampler];
|
||||
auto* input = accessors[sampler->input];
|
||||
auto* output = accessors[sampler->output];
|
||||
auto* target = nodes[channel->target.node];
|
||||
|
||||
idList<float>& timeStamps = data->GetAccessorView( input );
|
||||
int frames = timeStamps.Num();
|
||||
if( !camera.Num() )
|
||||
{
|
||||
cameraFrame_t t;
|
||||
t.fov = 90;
|
||||
t.q = mat3_identity.ToCQuat();
|
||||
t.t = vec3_origin;
|
||||
for( int i = 0; i < frames; i++ )
|
||||
{
|
||||
camera.Alloc() = t;
|
||||
}
|
||||
}
|
||||
//This has to be replaced for correct interpolation between frames
|
||||
for( int i = 0; i < frames; i++ )
|
||||
{
|
||||
cameraFrame_t& cameraFrame = camera[i];
|
||||
|
||||
cameraFrame.fov = 90.0f;
|
||||
switch( channel->target.TRS )
|
||||
{
|
||||
default:
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::none:
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::rotation:
|
||||
{
|
||||
idList<idQuat*>& values = data->GetAccessorView<idQuat>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
|
||||
idQuat q = ( *values[i] );
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat()
|
||||
* q.Inverse()
|
||||
* blenderToDoomTransform.ToMat3().ToQuat();
|
||||
cameraFrame.q = q.ToCQuat();
|
||||
|
||||
//This has to be replaced with correct interpolation between frames.
|
||||
if( ( ( i + 1 ) == frames ) && ( frames < camera.Num() ) )
|
||||
{
|
||||
while( i++ < camera.Num() - 1 )
|
||||
{
|
||||
camera[i].q = cameraFrame.q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::translation:
|
||||
{
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
idVec3 val = *values[i];
|
||||
cameraFrame.t = blenderToDoomTransform * val;
|
||||
|
||||
//This has to be replaced with correct interpolation between frames.
|
||||
if( ( ( i + 1 ) == frames ) && ( frames < camera.Num() ) )
|
||||
{
|
||||
while( i++ < camera.Num() - 1 )
|
||||
{
|
||||
camera[i].t = cameraFrame.t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case gltfAnimation_Channel_Target::scale:
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
gameLocal.Printf( "^5Frame: ^7%i ignored scale on /%s \n\n\n", i, anim->name.c_str() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idCameraAnim::Event_Start
|
||||
|
|
|
@ -131,6 +131,8 @@ private:
|
|||
void Event_Stop();
|
||||
void Event_SetCallback();
|
||||
void Event_Activate( idEntity* activator );
|
||||
|
||||
void gltfLoadAnim( idStr gltfFileName, idStr animName );
|
||||
};
|
||||
|
||||
#endif /* !__GAME_CAMERA_H__ */
|
||||
|
|
|
@ -31,7 +31,6 @@ 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" );
|
||||
|
@ -158,7 +157,7 @@ bool idMD5Anim::Reload()
|
|||
filename = name;
|
||||
Free();
|
||||
|
||||
return LoadAnim( filename );
|
||||
return LoadAnim( filename, &importOptions );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -177,7 +176,7 @@ size_t idMD5Anim::Allocated() const
|
|||
idMD5Anim::LoadAnim
|
||||
====================
|
||||
*/
|
||||
bool idMD5Anim::LoadAnim( const char* filename )
|
||||
bool idMD5Anim::LoadAnim( const char* filename, const idImportOptions* options )
|
||||
{
|
||||
idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
|
||||
idToken token;
|
||||
|
@ -189,38 +188,39 @@ bool idMD5Anim::LoadAnim( const char* filename )
|
|||
generatedFileName.AppendPath( filename );
|
||||
generatedFileName.SetFileExtension( ".bMD5anim" );
|
||||
|
||||
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 ) ;
|
||||
|
||||
bool isGLTF = ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 );
|
||||
if( isGLTF )
|
||||
{
|
||||
idStr gltfFileName = idStr( filename );
|
||||
int gltfAnimId = -1;
|
||||
idStr gltfAnimName;
|
||||
|
||||
gltfManager::ExtractIdentifier( gltfFileName, gltfAnimId, gltfAnimName );
|
||||
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
|
||||
importOptions = *options;
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( filename );
|
||||
}
|
||||
|
||||
// glTF2 animations will be saved straight to .bMD5anim files instead of the old ASCII format
|
||||
idFile* fileptr = fileSystem->OpenFileReadMemory( generatedFileName );
|
||||
bool doWrite = false;
|
||||
if( fileptr == nullptr && isGLTF )
|
||||
{
|
||||
fileptr = idRenderModelGLTF::GetAnimBin( filenameStr , sourceTimeStamp );
|
||||
fileptr = idRenderModelGLTF::GetAnimBin( filenameStr, sourceTimeStamp, options );
|
||||
doWrite = fileptr != nullptr;
|
||||
}
|
||||
|
||||
idFileLocal file( fileptr );
|
||||
|
||||
if( binaryLoadAnim.GetBool() && LoadBinary( file, sourceTimeStamp ) )
|
||||
if( ( binaryLoadAnim.GetBool() || isGLTF ) && LoadBinary( file, sourceTimeStamp ) )
|
||||
{
|
||||
name = filename;
|
||||
if( cvarSystem->GetCVarBool( "fs_buildresources" ) )
|
||||
|
@ -228,6 +228,7 @@ 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() );
|
||||
|
@ -1197,7 +1198,7 @@ void idAnimManager::Shutdown()
|
|||
idAnimManager::GetAnim
|
||||
====================
|
||||
*/
|
||||
idMD5Anim* idAnimManager::GetAnim( const char* name )
|
||||
idMD5Anim* idAnimManager::GetAnim( const char* name, const idImportOptions* options )
|
||||
{
|
||||
idMD5Anim** animptrptr;
|
||||
idMD5Anim* anim;
|
||||
|
@ -1220,7 +1221,7 @@ idMD5Anim* idAnimManager::GetAnim( const char* name )
|
|||
}
|
||||
|
||||
anim = new( TAG_ANIM ) idMD5Anim();
|
||||
if( !anim->LoadAnim( filename ) )
|
||||
if( !anim->LoadAnim( filename, options ) )
|
||||
{
|
||||
gameLocal.Warning( "Couldn't load anim: '%s'", filename.c_str() );
|
||||
delete anim;
|
||||
|
@ -1249,7 +1250,7 @@ void idAnimManager::Preload( const idPreloadManifest& manifest )
|
|||
const preloadEntry_s& p = manifest.GetPreloadByIndex( i );
|
||||
if( p.resType == PRELOAD_ANIM )
|
||||
{
|
||||
GetAnim( p.resourceName );
|
||||
GetAnim( p.resourceName, NULL );
|
||||
numLoaded++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -217,6 +217,8 @@ private:
|
|||
idStr name;
|
||||
idVec3 totaldelta;
|
||||
mutable int ref_count;
|
||||
// RB
|
||||
idImportOptions importOptions;
|
||||
|
||||
public:
|
||||
idMD5Anim();
|
||||
|
@ -229,7 +231,7 @@ public:
|
|||
{
|
||||
return sizeof( *this ) + Allocated();
|
||||
};
|
||||
bool LoadAnim( const char* filename );
|
||||
bool LoadAnim( const char* filename, const idImportOptions* options );
|
||||
bool LoadBinary( idFile* file, ID_TIME_T sourceTimeStamp );
|
||||
void WriteBinary( idFile* file, ID_TIME_T sourceTimeStamp );
|
||||
|
||||
|
@ -348,7 +350,7 @@ public:
|
|||
|
||||
private:
|
||||
void CopyDecl( const idDeclModelDef* decl );
|
||||
bool ParseAnim( idLexer& src, int numDefaultAnims );
|
||||
bool ParseAnim( idLexer& src, int numDefaultAnims, const idStr& defaultCommands );
|
||||
|
||||
private:
|
||||
idVec3 offset;
|
||||
|
@ -602,7 +604,7 @@ public:
|
|||
static bool forceExport;
|
||||
|
||||
void Shutdown();
|
||||
idMD5Anim* GetAnim( const char* name );
|
||||
idMD5Anim* GetAnim( const char* name, const idImportOptions* options ); // RB: added import options
|
||||
void Preload( const idPreloadManifest& manifest );
|
||||
void ReloadAnims();
|
||||
void ListAnims() const;
|
||||
|
|
|
@ -3038,7 +3038,7 @@ void idDeclModelDef::SetupJoints( int* numJoints, idJointMat** jointList, idBoun
|
|||
idDeclModelDef::ParseAnim
|
||||
=====================
|
||||
*/
|
||||
bool idDeclModelDef::ParseAnim( idLexer& src, int numDefaultAnims )
|
||||
bool idDeclModelDef::ParseAnim( idLexer& src, int numDefaultAnims, const idStr& defaultCommands )
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
|
@ -3112,6 +3112,40 @@ bool idDeclModelDef::ParseAnim( idLexer& src, int numDefaultAnims )
|
|||
// parse the anims from the string
|
||||
do
|
||||
{
|
||||
// RB: check if there are any options within [ ]
|
||||
idStr optionsStr = defaultCommands;
|
||||
idStr parms;
|
||||
idImportOptions options;
|
||||
|
||||
if( src.PeekTokenString( "[" ) )
|
||||
{
|
||||
while( src.ReadToken( &token ) )
|
||||
{
|
||||
if( token == "]" )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( token == "[" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( parms.Length() )
|
||||
{
|
||||
parms += " ";
|
||||
}
|
||||
|
||||
parms += token;
|
||||
}
|
||||
|
||||
if( parms.Length() )
|
||||
{
|
||||
optionsStr = " ";
|
||||
optionsStr += parms;
|
||||
}
|
||||
}
|
||||
|
||||
if( !src.ReadToken( &token ) )
|
||||
{
|
||||
src.Warning( "Unexpected end of file" );
|
||||
|
@ -3119,8 +3153,20 @@ bool idDeclModelDef::ParseAnim( idLexer& src, int numDefaultAnims )
|
|||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
options.Init( optionsStr.c_str(), token.c_str() );
|
||||
}
|
||||
catch( idException& ex )
|
||||
{
|
||||
src.Warning( "Model '%s': Failed to parse import options'%s'", token.c_str(), ex.GetError() );
|
||||
MakeDefault();
|
||||
return false;
|
||||
}
|
||||
// RB end
|
||||
|
||||
// lookup the animation
|
||||
md5anim = animationLib.GetAnim( token );
|
||||
md5anim = animationLib.GetAnim( token, &options );
|
||||
if( !md5anim )
|
||||
{
|
||||
src.Warning( "Couldn't load anim '%s'", token.c_str() );
|
||||
|
@ -3266,6 +3312,9 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
|
|||
jointHandle_t jointnum;
|
||||
idList<jointHandle_t> jointList;
|
||||
int numDefaultAnims;
|
||||
// RB: import options
|
||||
idStr defaultCommands;
|
||||
idStr temp;
|
||||
|
||||
src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
|
||||
src.SetFlags( DECL_LEXER_FLAGS );
|
||||
|
@ -3284,7 +3333,19 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
|
|||
break;
|
||||
}
|
||||
|
||||
if( token == "inherit" )
|
||||
// RB: add import options
|
||||
if( token == "options" )
|
||||
{
|
||||
src.ParseRestOfLine( defaultCommands );
|
||||
}
|
||||
else if( token == "addoptions" )
|
||||
{
|
||||
src.ParseRestOfLine( temp );
|
||||
defaultCommands += " ";
|
||||
defaultCommands += temp;
|
||||
}
|
||||
// RB end
|
||||
else if( token == "inherit" )
|
||||
{
|
||||
if( !src.ReadToken( &token2 ) )
|
||||
{
|
||||
|
@ -3328,6 +3389,39 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
|
|||
}
|
||||
else if( token == "mesh" )
|
||||
{
|
||||
// RB: parse import options right before filename
|
||||
idStr optionsStr = defaultCommands;
|
||||
idStr parms;
|
||||
|
||||
if( src.PeekTokenString( "[" ) )
|
||||
{
|
||||
while( src.ReadToken( &token2 ) )
|
||||
{
|
||||
if( token2 == "]" )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( token2 == "[" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( parms.Length() )
|
||||
{
|
||||
parms += " ";
|
||||
}
|
||||
|
||||
parms += token2;
|
||||
}
|
||||
|
||||
if( parms.Length() )
|
||||
{
|
||||
optionsStr = " ";
|
||||
optionsStr += parms;
|
||||
}
|
||||
}
|
||||
|
||||
if( !src.ReadToken( &token2 ) )
|
||||
{
|
||||
src.Warning( "Unexpected end of file" );
|
||||
|
@ -3344,7 +3438,29 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
|
|||
MakeDefault();
|
||||
return false;
|
||||
}
|
||||
modelHandle = renderModelManager->FindModel( filename );
|
||||
|
||||
idImportOptions options;
|
||||
if( isGltf )
|
||||
{
|
||||
try
|
||||
{
|
||||
options.Init( optionsStr.c_str(), filename.c_str() );
|
||||
}
|
||||
catch( idException& ex )
|
||||
{
|
||||
src.Warning( "Model '%s': Failed to parse import options'%s'", filename.c_str(), ex.GetError() );
|
||||
MakeDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
modelHandle = renderModelManager->FindModel( filename, &options );
|
||||
}
|
||||
else
|
||||
{
|
||||
modelHandle = renderModelManager->FindModel( filename );
|
||||
}
|
||||
// RB end
|
||||
|
||||
if( !modelHandle )
|
||||
{
|
||||
src.Warning( "Model '%s' not found", filename.c_str() );
|
||||
|
@ -3435,7 +3551,7 @@ bool idDeclModelDef::Parse( const char* text, const int textLength, bool allowBi
|
|||
MakeDefault();
|
||||
return false;
|
||||
}
|
||||
if( !ParseAnim( src, numDefaultAnims ) )
|
||||
if( !ParseAnim( src, numDefaultAnims, defaultCommands ) )
|
||||
{
|
||||
MakeDefault();
|
||||
return false;
|
||||
|
@ -5960,7 +6076,7 @@ idGameEdit::ANIM_GetAnim
|
|||
*/
|
||||
const idMD5Anim* idGameEdit::ANIM_GetAnim( const char* fileName )
|
||||
{
|
||||
return animationLib.GetAnim( fileName );
|
||||
return animationLib.GetAnim( fileName, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6129,7 +6245,8 @@ idRenderModel* idGameEdit::ANIM_CreateMeshForAnim( idRenderModel* model, const c
|
|||
animname = args->GetString( va( "anim %s", animname ) );
|
||||
}
|
||||
|
||||
md5anim = animationLib.GetAnim( animname );
|
||||
// no modelDef no options!
|
||||
md5anim = animationLib.GetAnim( animname, NULL );
|
||||
offset.Zero();
|
||||
}
|
||||
|
||||
|
|
|
@ -2164,6 +2164,8 @@ void idDeclManagerLocal::ExportDeclsToTrenchBroom_f( const idCmdArgs& args )
|
|||
ignoreList.AddUnique( "blooper" );
|
||||
ignoreList.AddUnique( "npc" );
|
||||
ignoreList.AddUnique( "zombie" );
|
||||
ignoreList.AddUnique( "space" );
|
||||
ignoreList.AddUnique( "static" );
|
||||
|
||||
idStrList solidClassNames;
|
||||
solidClassNames.AddUnique( "worldspawn" );
|
||||
|
@ -2178,6 +2180,7 @@ void idDeclManagerLocal::ExportDeclsToTrenchBroom_f( const idCmdArgs& args )
|
|||
solidClassNames.AddUnique( "func_splinemover" );
|
||||
solidClassNames.AddUnique( "func_static" );
|
||||
solidClassNames.AddUnique( "func_mover" );
|
||||
solidClassNames.AddUnique( "func_door" );
|
||||
solidClassNames.AddUnique( "moveable_base" );
|
||||
solidClassNames.AddUnique( "trigger_" );
|
||||
|
||||
|
@ -2263,13 +2266,21 @@ void idDeclManagerLocal::ExportDeclsToTrenchBroom_f( const idCmdArgs& args )
|
|||
}
|
||||
}
|
||||
|
||||
// ignore autogenerated model definitions for slim FGD
|
||||
bool genmodel = false;
|
||||
if( idStr::Icmpn( decl->GetName(), "genmodel_", 9 ) == 0 )
|
||||
{
|
||||
genmodel = true;
|
||||
}
|
||||
|
||||
// filter multiplayer entities
|
||||
bool multiplayer = ( idStr::FindText( decl->GetName(), "_mp", false ) != -1 ||
|
||||
idStr::FindText( decl->GetName(), "team_ctf", false ) != -1 ||
|
||||
idStr::FindText( decl->GetName(), "_coop", false ) != -1 );
|
||||
|
||||
if( f == 2 )
|
||||
{
|
||||
if( !multiplayer )
|
||||
if( !multiplayer || genmodel )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -2280,6 +2291,11 @@ void idDeclManagerLocal::ExportDeclsToTrenchBroom_f( const idCmdArgs& args )
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( f == 1 && genmodel )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool solidClass = false;
|
||||
|
@ -2583,7 +2599,7 @@ void idDeclManagerLocal::ExportDeclsToTrenchBroom_f( const idCmdArgs& args )
|
|||
idStr::Icmp( decl->GetName(), "func_rotating_model" ) == 0 )
|
||||
{
|
||||
// dynamic model that prefers a TB specific proxymodel
|
||||
file->Printf( "model({{\n\tproxymodel != null -> { \"path\": proxymodel },\n\t{ \"path\": model }\n}})" );
|
||||
file->Printf( "model({{\n\tproxymodel -> { \"path\": proxymodel },\n\t{ \"path\": model }\n}})" );
|
||||
}
|
||||
else if( idStr::Icmp( decl->GetName(), "light" ) == 0 )
|
||||
{
|
||||
|
@ -3140,13 +3156,15 @@ void idDeclManagerLocal::ExportModelsToTrenchBroom_f( const idCmdArgs& args )
|
|||
|
||||
fgdFile->Printf( "@PointClass " );
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
if( bounds.GetVolume() > 0 )
|
||||
{
|
||||
fgdFile->Printf( "size(%i %i %i, %i %i %i) ",
|
||||
int( bounds[0].x ), int( bounds[0].y ), int( bounds[0].z ),
|
||||
int( bounds[1].x ), int( bounds[1].y ), int( bounds[1].z ) );
|
||||
}
|
||||
//#else
|
||||
//fgdFile->Printf( "size(-8 -8 0, 8 8 16) " );
|
||||
#endif
|
||||
|
||||
fgdFile->Printf( "base(auto_generated_model) model({ \"path\": \"%s\" }) = %s : \"Display entity\"\n[\n", exportedModelFileName.c_str(), entityName.c_str() );
|
||||
|
@ -3163,6 +3181,13 @@ void idDeclManagerLocal::ExportModelsToTrenchBroom_f( const idCmdArgs& args )
|
|||
defFile->Printf( "\t \"inherit\" \"misc_model\"\n" );
|
||||
defFile->Printf( "\t \"proxymodel\" \"%s\"\n", exportedModelFileName.c_str() );
|
||||
defFile->Printf( "\t \"model\" \"%s\"\n", originalModelFileName.c_str() );
|
||||
#if 0
|
||||
if( bounds.GetVolume() > 0 )
|
||||
{
|
||||
defFile->Printf( "\t \"editor_mins\" \"%i %i %i\"\n", int( bounds[0].x ), int( bounds[0].y ), int( bounds[0].z ) );
|
||||
defFile->Printf( "\t \"editor_maxs\" \"%i %i %i\"\n", int( bounds[1].x ), int( bounds[1].y ), int( bounds[1].z ) );
|
||||
}
|
||||
#endif
|
||||
defFile->Printf( "}\n\n", exportedModelFileName.c_str() );
|
||||
|
||||
totalEntitiesCount++;
|
||||
|
|
|
@ -3059,6 +3059,17 @@ bool idMapFile::ConvertToValve220Format()
|
|||
ent->epairs.SetAngles( "angles", angles );
|
||||
}
|
||||
|
||||
// TODO use angles instead of angle
|
||||
#if 0
|
||||
if( ent->epairs.FindKey( "angle" ) )
|
||||
{
|
||||
ent->epairs.Delete( "angle" );
|
||||
|
||||
idAngles angles = rot.ToAngles();
|
||||
ent->epairs.SetAngles( "angles", angles );
|
||||
}
|
||||
#endif
|
||||
|
||||
const idKeyValue* kv = classTypeOverview.FindKey( classname );
|
||||
if( kv && kv->GetValue().Length() )
|
||||
{
|
||||
|
|
|
@ -457,13 +457,15 @@ void ResolveLight( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
|
||||
case gltfExt_KHR_lights_punctual::Spot:
|
||||
{
|
||||
// RB: this code is based on Cmd_TestLight_f which sets the light properties in world space
|
||||
idMat4 entityToWorldTransform = mat4_identity;
|
||||
gltfData::ResolveNodeMatrix( node, &entityToWorldTransform );
|
||||
idMat4 worldToEntityTransform = entityToWorldTransform.Inverse();
|
||||
|
||||
float fov = tan( light->spot.outerConeAngle ) / 2 ;
|
||||
idMat3 axis = idAngles( 0.0f, 90.0f, 90.0f ).ToMat3() * entityToWorldTransform.ToMat3();
|
||||
|
||||
// HarrievG: TODO cleanup this was done by try & error until it worked
|
||||
idQuat q = ( entityToWorldTransform ).ToMat3().ToQuat();
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * idAngles( 180.0f, 180.0f, -90.0f ).ToQuat();
|
||||
idMat3 axis = q.ToMat3();
|
||||
newEntity->epairs.SetVector( "light_target", axis[0] );
|
||||
newEntity->epairs.SetVector( "light_right", axis[1] * -fov );
|
||||
newEntity->epairs.SetVector( "light_up", axis[2] * fov );
|
||||
|
@ -507,10 +509,13 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
newEntity->epairs = newPairs;
|
||||
|
||||
// gather entity transform and bring it into id Tech 4 space
|
||||
gltfData::ResolveNodeMatrix( node );
|
||||
idMat4 entityToWorldTransform = mat4_identity;
|
||||
gltfData::ResolveNodeMatrix( node, &entityToWorldTransform );
|
||||
|
||||
// set entity transform in a way the game and physics code understand it
|
||||
idVec3 origin = blenderToDoomTransform * node->translation;
|
||||
// RB: should be idVec3 origin = ( blenderToDoomTransform * entityToWorldTransform ).GetTranslation();
|
||||
|
||||
newEntity->epairs.SetVector( "origin", origin );
|
||||
|
||||
if( node->extensions.KHR_lights_punctual != nullptr )
|
||||
|
@ -518,12 +523,32 @@ void ResolveEntity( gltfData* data, idMapEntity* newEntity, gltfNode* node )
|
|||
ResolveLight( data, newEntity, node );
|
||||
}
|
||||
|
||||
// TODO set rotation key to store rotation and scaling
|
||||
//if (idStr::Icmp(classname, "info_player_start") == 0)
|
||||
// if( !node->matrix.IsIdentity() )
|
||||
//{
|
||||
// newEntity->epairs.SetMatrix("rotation", axis );
|
||||
//}
|
||||
// HarrievG: TODO cleanup this was done by try & error until it worked
|
||||
if( node->camera >= 0 && !newEntity->epairs.FindKey( "rotation" ) )
|
||||
{
|
||||
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
|
||||
q = idAngles( 90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
|
||||
}
|
||||
else if( idStr::Icmp( classname, "info_player_start" ) == 0 && !newEntity->epairs.FindKey( "rotation" ) )
|
||||
{
|
||||
idQuat q = entityToWorldTransform.ToMat3().ToQuat();
|
||||
q = idAngles( -90.0f, 0.0, -90.0f ).ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
newEntity->epairs.SetMatrix( "rotation", q.ToMat3() );
|
||||
}
|
||||
else if( node->extras.strPairs.GetBool( "useNodeOrientation", false ) )
|
||||
{
|
||||
//Nodes that are an instance of an collection containing a mesh that is not inline, ea; a gltfModel; static _or_ dynamic,
|
||||
//which has its transformations applied on vertex level so we do not apply it here.
|
||||
origin = blenderToDoomTransform * ( node->translation * ( entityToWorldTransform * node->matrix.Inverse() ) );
|
||||
newEntity->epairs.SetVector( "origin", origin );
|
||||
|
||||
idQuat q = ( entityToWorldTransform * node->matrix.Inverse() ).ToMat3().ToQuat();
|
||||
q = blenderToDoomTransform.Inverse().ToMat3().ToQuat() * q * blenderToDoomTransform.ToMat3().ToQuat();
|
||||
idMat3 rot = q.ToMat3();
|
||||
//idMat3 rot = ( blenderToDoomTransform * entityToWorldTransform ).ToMat3();
|
||||
newEntity->epairs.SetMatrix( "rotation", rot );
|
||||
}
|
||||
|
||||
#if 0
|
||||
for( int i = 0; i < newEntity->epairs.GetNumKeyVals(); i++ )
|
||||
|
|
|
@ -1150,7 +1150,7 @@ void GLTF_Parser::Shutdown()
|
|||
bufferViewsDone = false;
|
||||
}
|
||||
GLTF_Parser::GLTF_Parser()
|
||||
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ) { }
|
||||
: parser( LEXFL_ALLOWPATHNAMES | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES ) , buffersDone( false ), bufferViewsDone( false ), currentAsset( nullptr ) { }
|
||||
|
||||
void GLTF_Parser::Parse_ASSET( idToken& token )
|
||||
{
|
||||
|
|
|
@ -401,11 +401,6 @@ public:
|
|||
{
|
||||
return false;
|
||||
}
|
||||
const idVec3& TotalMovementDelta() const
|
||||
{
|
||||
static idVec3 temp;
|
||||
return temp;
|
||||
}
|
||||
int NumFrames() const
|
||||
{
|
||||
return numFrames;
|
||||
|
|
|
@ -963,6 +963,7 @@ public:
|
|||
// jmarshall
|
||||
idMat3 ToMat3() const;
|
||||
// jmarshall end
|
||||
idVec3 GetTranslation() const;
|
||||
private:
|
||||
idVec4 mat[ 4 ];
|
||||
};
|
||||
|
@ -991,6 +992,19 @@ ID_INLINE idMat3 idMat4::ToMat3() const
|
|||
}
|
||||
// jmarshall end
|
||||
|
||||
// RB begin
|
||||
ID_INLINE idVec3 idMat4::GetTranslation() const
|
||||
{
|
||||
idVec3 pos;
|
||||
|
||||
pos.x = mat[ 0 ][ 3 ];
|
||||
pos.y = mat[ 1 ][ 3 ];
|
||||
pos.z = mat[ 2 ][ 3 ];
|
||||
|
||||
return pos;
|
||||
}
|
||||
// RB end
|
||||
|
||||
ID_INLINE idMat4::idMat4()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -295,7 +295,7 @@ idRenderModelStatic::PartialInitFromFile
|
|||
void idRenderModelStatic::PartialInitFromFile( const char* fileName )
|
||||
{
|
||||
fastLoad = true;
|
||||
InitFromFile( fileName );
|
||||
InitFromFile( fileName, nullptr );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -303,20 +303,22 @@ void idRenderModelStatic::PartialInitFromFile( const char* fileName )
|
|||
idRenderModelStatic::InitFromFile
|
||||
================
|
||||
*/
|
||||
void idRenderModelStatic::InitFromFile( const char* fileName )
|
||||
void idRenderModelStatic::InitFromFile( const char* fileName, const idImportOptions* options )
|
||||
{
|
||||
bool loaded;
|
||||
idStr extension;
|
||||
|
||||
InitEmpty( fileName );
|
||||
|
||||
// FIXME: load new .proc map format
|
||||
|
||||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
name.ExtractFileExtension( extension );
|
||||
|
||||
if( extension.Icmp( "ase" ) == 0 )
|
||||
if( extension.Icmp( "glb" ) == 0 || extension.Icmp( "gltf" ) == 0 )
|
||||
{
|
||||
loaded = false;
|
||||
reloadable = true;
|
||||
}
|
||||
else if( extension.Icmp( "ase" ) == 0 )
|
||||
{
|
||||
loaded = LoadASE( name, &sourceTimeStamp );
|
||||
reloadable = true;
|
||||
|
@ -872,7 +874,7 @@ idRenderModelStatic::LoadModel
|
|||
void idRenderModelStatic::LoadModel()
|
||||
{
|
||||
PurgeModel();
|
||||
InitFromFile( name );
|
||||
InitFromFile( name, nullptr );
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -62,6 +62,7 @@ struct dominantTri_t
|
|||
const int SHADOW_CAP_INFINITE = 64;
|
||||
|
||||
class idRenderModelStatic;
|
||||
class idImportOptions;
|
||||
struct viewDef_t;
|
||||
|
||||
// our only drawing geometry type
|
||||
|
@ -168,7 +169,7 @@ public:
|
|||
virtual ~idRenderModel() {};
|
||||
|
||||
// Loads static models only, dynamic models must be loaded by the modelManager
|
||||
virtual void InitFromFile( const char* fileName ) = 0;
|
||||
virtual void InitFromFile( const char* fileName, const idImportOptions* options ) = 0;
|
||||
|
||||
// Supports reading/writing binary file formats
|
||||
virtual bool LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp ) = 0;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
Copyright (C) 2022 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -56,7 +57,7 @@ public:
|
|||
virtual void Shutdown();
|
||||
virtual idRenderModel* AllocModel();
|
||||
virtual void FreeModel( idRenderModel* model );
|
||||
virtual idRenderModel* FindModel( const char* modelName );
|
||||
virtual idRenderModel* FindModel( const char* modelName, const idImportOptions* options = NULL );
|
||||
virtual idRenderModel* CheckModel( const char* modelName );
|
||||
virtual idRenderModel* DefaultModel();
|
||||
virtual void AddModel( idRenderModel* model );
|
||||
|
@ -80,7 +81,7 @@ private:
|
|||
bool insideLevelLoad; // don't actually load now
|
||||
nvrhi::CommandListHandle commandList;
|
||||
|
||||
idRenderModel* GetModel( const char* modelName, bool createIfNotFound );
|
||||
idRenderModel* GetModel( const char* modelName, bool createIfNotFound, const idImportOptions* options );
|
||||
|
||||
static void PrintModel_f( const idCmdArgs& args );
|
||||
static void ListModels_f( const idCmdArgs& args );
|
||||
|
@ -296,7 +297,7 @@ void idRenderModelManagerLocal::Shutdown()
|
|||
idRenderModelManagerLocal::GetModel
|
||||
=================
|
||||
*/
|
||||
idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool createIfNotFound )
|
||||
idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool createIfNotFound, const idImportOptions* options )
|
||||
{
|
||||
if( !_modelName || !_modelName[0] )
|
||||
{
|
||||
|
@ -309,6 +310,13 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
idStrStatic< MAX_OSPATH > extension;
|
||||
canonical.ExtractFileExtension( extension );
|
||||
|
||||
bool isGLTF = false;
|
||||
// HvG: GLTF 2 support
|
||||
if( ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) )
|
||||
{
|
||||
isGLTF = true;
|
||||
}
|
||||
|
||||
// see if it is already present
|
||||
int key = hash.GenerateKey( canonical, false );
|
||||
for( int i = hash.First( key ); i != -1; i = hash.Next( i ) )
|
||||
|
@ -325,7 +333,22 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) );
|
||||
|
||||
// Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
|
||||
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical );
|
||||
|
||||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
if( isGLTF )
|
||||
{
|
||||
idStr gltfFileName = idStr( canonical );
|
||||
int gltfMeshId = -1;
|
||||
idStr gltfMeshName;
|
||||
gltfManager::ExtractIdentifier( gltfFileName, gltfMeshId, gltfMeshName );
|
||||
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( canonical );
|
||||
}
|
||||
|
||||
if( model->SupportsBinaryModel() && binaryLoadRenderModels.GetBool() )
|
||||
{
|
||||
|
@ -333,7 +356,14 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
model->PurgeModel();
|
||||
if( !model->LoadBinaryModel( file, sourceTimeStamp ) )
|
||||
{
|
||||
model->LoadModel();
|
||||
if( isGLTF )
|
||||
{
|
||||
model->InitFromFile( canonical, options );
|
||||
}
|
||||
else
|
||||
{
|
||||
model->LoadModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -359,10 +389,12 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
// determine which subclass of idRenderModel to initialize
|
||||
|
||||
idRenderModel* model = NULL;
|
||||
|
||||
// HvG: GLTF 2 support
|
||||
if( ( extension.Icmp( GLTF_GLB_EXT ) == 0 ) || ( extension.Icmp( GLTF_EXT ) == 0 ) )
|
||||
if( isGLTF )
|
||||
{
|
||||
model = new( TAG_MODEL ) idRenderModelGLTF;
|
||||
isGLTF = true;
|
||||
}
|
||||
// RB: Collada DAE and Wavefront OBJ
|
||||
else if( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "obj" ) == 0 )
|
||||
|
@ -397,19 +429,33 @@ idRenderModel* idRenderModelManagerLocal::GetModel( const char* _modelName, bool
|
|||
generatedFileName.SetFileExtension( va( "b%s", extension.c_str() ) );
|
||||
|
||||
// Get the timestamp on the original file, if it's newer than what is stored in binary model, regenerate it
|
||||
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( canonical );
|
||||
ID_TIME_T sourceTimeStamp;
|
||||
|
||||
if( isGLTF )
|
||||
{
|
||||
idStr gltfFileName = idStr( canonical );
|
||||
int gltfMeshId = -1;
|
||||
idStr gltfMeshName;
|
||||
gltfManager::ExtractIdentifier( gltfFileName, gltfMeshId, gltfMeshName );
|
||||
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( gltfFileName );
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceTimeStamp = fileSystem->GetTimestamp( canonical );
|
||||
}
|
||||
|
||||
idFileLocal file( fileSystem->OpenFileReadMemory( generatedFileName ) );
|
||||
|
||||
if( !model->SupportsBinaryModel() || !binaryLoadRenderModels.GetBool() )
|
||||
{
|
||||
model->InitFromFile( canonical );
|
||||
model->InitFromFile( canonical, options );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !model->LoadBinaryModel( file, sourceTimeStamp ) )
|
||||
{
|
||||
model->InitFromFile( canonical );
|
||||
model->InitFromFile( canonical, options );
|
||||
|
||||
// RB: default models shouldn't be cached as binary models
|
||||
if( !model->IsDefaultModel() )
|
||||
|
@ -555,9 +601,9 @@ void idRenderModelManagerLocal::FreeModel( idRenderModel* model )
|
|||
idRenderModelManagerLocal::FindModel
|
||||
=================
|
||||
*/
|
||||
idRenderModel* idRenderModelManagerLocal::FindModel( const char* modelName )
|
||||
idRenderModel* idRenderModelManagerLocal::FindModel( const char* modelName, const idImportOptions* options )
|
||||
{
|
||||
return GetModel( modelName, true );
|
||||
return GetModel( modelName, true, options );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -567,7 +613,7 @@ idRenderModelManagerLocal::CheckModel
|
|||
*/
|
||||
idRenderModel* idRenderModelManagerLocal::CheckModel( const char* modelName )
|
||||
{
|
||||
return GetModel( modelName, false );
|
||||
return GetModel( modelName, false, nullptr );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -633,22 +679,44 @@ void idRenderModelManagerLocal::ReloadModels( bool forceAll )
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
bool isGLTF = false;
|
||||
idStr filename = model->Name();
|
||||
idStr extension;
|
||||
idStr assetName = filename;
|
||||
assetName.ExtractFileExtension( extension );
|
||||
isGLTF = extension.Icmp( "glb" ) == 0 || extension.Icmp( "gltf" ) == 0;
|
||||
if( !forceAll )
|
||||
{
|
||||
// check timestamp
|
||||
ID_TIME_T current;
|
||||
|
||||
fileSystem->ReadFile( model->Name(), NULL, ¤t );
|
||||
if( isGLTF )
|
||||
{
|
||||
idStr meshName;
|
||||
int meshID = -1;
|
||||
gltfManager::ExtractIdentifier( filename, meshID, meshName );
|
||||
}
|
||||
|
||||
fileSystem->ReadFile( filename, NULL, ¤t );
|
||||
if( current <= model->Timestamp() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
common->DPrintf( "reloading %s.\n", model->Name() );
|
||||
common->DPrintf( "^1Reloading %s.\n", model->Name() );
|
||||
|
||||
if( isGLTF )
|
||||
{
|
||||
// RB: we don't have the options here so make sure this only applies to static models
|
||||
model->InitFromFile( model->Name(), NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
model->LoadModel();
|
||||
}
|
||||
|
||||
model->LoadModel();
|
||||
}
|
||||
|
||||
// we must force the world to regenerate, because models may
|
||||
|
@ -932,3 +1000,483 @@ void idRenderModelManagerLocal::PrintMemInfo( MemInfo_t* mi )
|
|||
f->Printf( "\nTotal model bytes allocated: %s\n", idStr::FormatNumber( totalMem ).c_str() );
|
||||
fileSystem->CloseFile( f );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// RB: added Maya exporter options
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idTokenizer
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=================
|
||||
MayaError
|
||||
=================
|
||||
*/
|
||||
void MayaError( const char* fmt, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
char text[ 8192 ];
|
||||
|
||||
va_start( argptr, fmt );
|
||||
idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
throw idException( text );
|
||||
}
|
||||
|
||||
|
||||
class idTokenizer
|
||||
{
|
||||
private:
|
||||
int currentToken;
|
||||
idStrList tokens;
|
||||
|
||||
public:
|
||||
idTokenizer()
|
||||
{
|
||||
Clear();
|
||||
};
|
||||
void Clear()
|
||||
{
|
||||
currentToken = 0;
|
||||
tokens.Clear();
|
||||
};
|
||||
|
||||
int SetTokens( const char* buffer );
|
||||
const char* NextToken( const char* errorstring = NULL );
|
||||
|
||||
bool TokenAvailable()
|
||||
{
|
||||
return currentToken < tokens.Num();
|
||||
};
|
||||
int Num()
|
||||
{
|
||||
return tokens.Num();
|
||||
};
|
||||
void UnGetToken()
|
||||
{
|
||||
if( currentToken > 0 )
|
||||
{
|
||||
currentToken--;
|
||||
}
|
||||
};
|
||||
const char* GetToken( int index )
|
||||
{
|
||||
if( ( index >= 0 ) && ( index < tokens.Num() ) )
|
||||
{
|
||||
return tokens[ index ];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
const char* CurrentToken()
|
||||
{
|
||||
return GetToken( currentToken );
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
====================
|
||||
idTokenizer::SetTokens
|
||||
====================
|
||||
*/
|
||||
int idTokenizer::SetTokens( const char* buffer )
|
||||
{
|
||||
const char* cmd;
|
||||
|
||||
Clear();
|
||||
|
||||
// tokenize commandline
|
||||
cmd = buffer;
|
||||
while( *cmd )
|
||||
{
|
||||
// skip whitespace
|
||||
while( *cmd && isspace( *cmd ) )
|
||||
{
|
||||
cmd++;
|
||||
}
|
||||
|
||||
if( !*cmd )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
idStr& current = tokens.Alloc();
|
||||
while( *cmd && !isspace( *cmd ) )
|
||||
{
|
||||
current += *cmd;
|
||||
cmd++;
|
||||
}
|
||||
}
|
||||
|
||||
return tokens.Num();
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
idTokenizer::NextToken
|
||||
====================
|
||||
*/
|
||||
const char* idTokenizer::NextToken( const char* errorstring )
|
||||
{
|
||||
if( currentToken < tokens.Num() )
|
||||
{
|
||||
return tokens[ currentToken++ ];
|
||||
}
|
||||
|
||||
if( errorstring )
|
||||
{
|
||||
MayaError( "Error: %s", errorstring );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idImportOptions
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
#define DEFAULT_ANIM_EPSILON 0.125f
|
||||
#define DEFAULT_QUAT_EPSILON ( 1.0f / 8192.0f )
|
||||
|
||||
void idImportOptions::Init( const char* commandline, const char* ospath )
|
||||
{
|
||||
idStr token;
|
||||
idNamePair joints;
|
||||
int i;
|
||||
idAnimGroup* group;
|
||||
idStr sourceDir;
|
||||
idStr destDir;
|
||||
|
||||
//Reset( commandline );
|
||||
scale = 1.0f;
|
||||
//type = WRITE_MESH;
|
||||
startframe = -1;
|
||||
endframe = -1;
|
||||
ignoreMeshes = false;
|
||||
clearOrigin = false;
|
||||
clearOriginAxis = false;
|
||||
framerate = 24;
|
||||
align = "";
|
||||
rotate = 0.0f;
|
||||
commandLine = commandline;
|
||||
prefix = "";
|
||||
jointThreshold = 0.05f;
|
||||
ignoreScale = false;
|
||||
xyzPrecision = DEFAULT_ANIM_EPSILON;
|
||||
quatPrecision = DEFAULT_QUAT_EPSILON;
|
||||
cycleStart = -1;
|
||||
|
||||
src.Clear();
|
||||
dest.Clear();
|
||||
|
||||
idTokenizer tokens;
|
||||
tokens.SetTokens( commandline );
|
||||
|
||||
keepjoints.Clear();
|
||||
renamejoints.Clear();
|
||||
remapjoints.Clear();
|
||||
exportgroups.Clear();
|
||||
skipmeshes.Clear();
|
||||
keepmeshes.Clear();
|
||||
groups.Clear();
|
||||
|
||||
/*
|
||||
token = tokens.NextToken( "Missing export command" );
|
||||
if( token == "mesh" )
|
||||
{
|
||||
type = WRITE_MESH;
|
||||
}
|
||||
else if( token == "anim" )
|
||||
{
|
||||
type = WRITE_ANIM;
|
||||
}
|
||||
else if( token == "camera" )
|
||||
{
|
||||
type = WRITE_CAMERA;
|
||||
}
|
||||
else
|
||||
{
|
||||
MayaError( "Unknown export command '%s'", token.c_str() );
|
||||
}
|
||||
*/
|
||||
|
||||
//src = tokens.NextToken( "Missing source filename" );
|
||||
//dest = src;
|
||||
|
||||
for( token = tokens.NextToken(); token != ""; token = tokens.NextToken() )
|
||||
{
|
||||
if( token == "-" )
|
||||
{
|
||||
token = tokens.NextToken( "Missing import parameter" );
|
||||
|
||||
if( token == "force" )
|
||||
{
|
||||
// skip
|
||||
}
|
||||
else if( token == "game" )
|
||||
{
|
||||
// parse game name
|
||||
game = tokens.NextToken( "Expecting game name after -game" );
|
||||
|
||||
}
|
||||
else if( token == "rename" )
|
||||
{
|
||||
// parse joint to rename
|
||||
joints.from = tokens.NextToken( "Missing joint name for -rename. Usage: -rename [joint name] [new name]" );
|
||||
joints.to = tokens.NextToken( "Missing new name for -rename. Usage: -rename [joint name] [new name]" );
|
||||
renamejoints.Append( joints );
|
||||
|
||||
}
|
||||
else if( token == "prefix" )
|
||||
{
|
||||
prefix = tokens.NextToken( "Missing name for -prefix. Usage: -prefix [joint prefix]" );
|
||||
|
||||
}
|
||||
else if( token == "parent" )
|
||||
{
|
||||
// parse joint to reparent
|
||||
joints.from = tokens.NextToken( "Missing joint name for -parent. Usage: -parent [joint name] [new parent]" );
|
||||
joints.to = tokens.NextToken( "Missing new parent for -parent. Usage: -parent [joint name] [new parent]" );
|
||||
remapjoints.Append( joints );
|
||||
|
||||
}
|
||||
else if( !token.Icmp( "sourcedir" ) )
|
||||
{
|
||||
// parse source directory
|
||||
sourceDir = tokens.NextToken( "Missing filename for -sourcedir. Usage: -sourcedir [directory]" );
|
||||
|
||||
}
|
||||
else if( !token.Icmp( "destdir" ) )
|
||||
{
|
||||
// parse destination directory
|
||||
destDir = tokens.NextToken( "Missing filename for -destdir. Usage: -destdir [directory]" );
|
||||
|
||||
}
|
||||
else if( token == "dest" )
|
||||
{
|
||||
// parse destination filename
|
||||
dest = tokens.NextToken( "Missing filename for -dest. Usage: -dest [filename]" );
|
||||
|
||||
}
|
||||
else if( token == "range" )
|
||||
{
|
||||
// parse frame range to export
|
||||
token = tokens.NextToken( "Missing start frame for -range. Usage: -range [start frame] [end frame]" );
|
||||
startframe = atoi( token );
|
||||
token = tokens.NextToken( "Missing end frame for -range. Usage: -range [start frame] [end frame]" );
|
||||
endframe = atoi( token );
|
||||
|
||||
if( startframe > endframe )
|
||||
{
|
||||
MayaError( "Start frame is greater than end frame." );
|
||||
}
|
||||
|
||||
}
|
||||
else if( !token.Icmp( "cycleStart" ) )
|
||||
{
|
||||
// parse start frame of cycle
|
||||
token = tokens.NextToken( "Missing cycle start frame for -cycleStart. Usage: -cycleStart [first frame of cycle]" );
|
||||
cycleStart = atoi( token );
|
||||
|
||||
}
|
||||
else if( token == "scale" )
|
||||
{
|
||||
// parse scale
|
||||
token = tokens.NextToken( "Missing scale amount for -scale. Usage: -scale [scale amount]" );
|
||||
scale = atof( token );
|
||||
|
||||
}
|
||||
else if( token == "align" )
|
||||
{
|
||||
// parse align joint
|
||||
align = tokens.NextToken( "Missing joint name for -align. Usage: -align [joint name]" );
|
||||
|
||||
}
|
||||
else if( token == "rotate" )
|
||||
{
|
||||
// parse angle rotation
|
||||
token = tokens.NextToken( "Missing value for -rotate. Usage: -rotate [yaw]" );
|
||||
rotate = -atof( token );
|
||||
|
||||
}
|
||||
else if( token == "nomesh" )
|
||||
{
|
||||
ignoreMeshes = true;
|
||||
|
||||
}
|
||||
else if( token == "clearorigin" )
|
||||
{
|
||||
clearOrigin = true;
|
||||
clearOriginAxis = true;
|
||||
|
||||
}
|
||||
else if( token == "clearoriginaxis" )
|
||||
{
|
||||
clearOriginAxis = true;
|
||||
|
||||
}
|
||||
else if( token == "ignorescale" )
|
||||
{
|
||||
ignoreScale = true;
|
||||
|
||||
}
|
||||
else if( token == "xyzprecision" )
|
||||
{
|
||||
// parse quaternion precision
|
||||
token = tokens.NextToken( "Missing value for -xyzprecision. Usage: -xyzprecision [precision]" );
|
||||
xyzPrecision = atof( token );
|
||||
if( xyzPrecision < 0.0f )
|
||||
{
|
||||
MayaError( "Invalid value for -xyzprecision. Must be >= 0" );
|
||||
}
|
||||
|
||||
}
|
||||
else if( token == "quatprecision" )
|
||||
{
|
||||
// parse quaternion precision
|
||||
token = tokens.NextToken( "Missing value for -quatprecision. Usage: -quatprecision [precision]" );
|
||||
quatPrecision = atof( token );
|
||||
if( quatPrecision < 0.0f )
|
||||
{
|
||||
MayaError( "Invalid value for -quatprecision. Must be >= 0" );
|
||||
}
|
||||
|
||||
}
|
||||
else if( token == "jointthreshold" )
|
||||
{
|
||||
// parse joint threshold
|
||||
token = tokens.NextToken( "Missing weight for -jointthreshold. Usage: -jointthreshold [minimum joint weight]" );
|
||||
jointThreshold = atof( token );
|
||||
|
||||
}
|
||||
else if( token == "skipmesh" )
|
||||
{
|
||||
token = tokens.NextToken( "Missing name for -skipmesh. Usage: -skipmesh [name of mesh to skip]" );
|
||||
skipmeshes.AddUnique( token );
|
||||
|
||||
}
|
||||
else if( token == "keepmesh" )
|
||||
{
|
||||
token = tokens.NextToken( "Missing name for -keepmesh. Usage: -keepmesh [name of mesh to keep]" );
|
||||
keepmeshes.AddUnique( token );
|
||||
|
||||
}
|
||||
else if( token == "jointgroup" )
|
||||
{
|
||||
token = tokens.NextToken( "Missing name for -jointgroup. Usage: -jointgroup [group name] [joint1] [joint2]...[joint n]" );
|
||||
group = groups.Ptr();
|
||||
for( i = 0; i < groups.Num(); i++, group++ )
|
||||
{
|
||||
if( group->name == token )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i >= groups.Num() )
|
||||
{
|
||||
// create a new group
|
||||
group = &groups.Alloc();
|
||||
group->name = token;
|
||||
}
|
||||
|
||||
while( tokens.TokenAvailable() )
|
||||
{
|
||||
token = tokens.NextToken();
|
||||
if( token[ 0 ] == '-' )
|
||||
{
|
||||
tokens.UnGetToken();
|
||||
break;
|
||||
}
|
||||
|
||||
group->joints.AddUnique( token );
|
||||
}
|
||||
}
|
||||
else if( token == "group" )
|
||||
{
|
||||
// add the list of groups to export (these don't affect the hierarchy)
|
||||
while( tokens.TokenAvailable() )
|
||||
{
|
||||
token = tokens.NextToken();
|
||||
if( token[ 0 ] == '-' )
|
||||
{
|
||||
tokens.UnGetToken();
|
||||
break;
|
||||
}
|
||||
|
||||
group = groups.Ptr();
|
||||
for( i = 0; i < groups.Num(); i++, group++ )
|
||||
{
|
||||
if( group->name == token )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i >= groups.Num() )
|
||||
{
|
||||
MayaError( "Unknown group '%s'", token.c_str() );
|
||||
}
|
||||
|
||||
exportgroups.AddUnique( group );
|
||||
}
|
||||
}
|
||||
else if( token == "keep" )
|
||||
{
|
||||
// add joints that are kept whether they're used by a mesh or not
|
||||
while( tokens.TokenAvailable() )
|
||||
{
|
||||
token = tokens.NextToken();
|
||||
if( token[ 0 ] == '-' )
|
||||
{
|
||||
tokens.UnGetToken();
|
||||
break;
|
||||
}
|
||||
keepjoints.AddUnique( token );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MayaError( "Unknown option '%s'", token.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token = src;
|
||||
src = ospath;
|
||||
src.BackSlashesToSlashes();
|
||||
src.AppendPath( sourceDir );
|
||||
src.AppendPath( token );
|
||||
|
||||
token = dest;
|
||||
dest = ospath;
|
||||
dest.BackSlashesToSlashes();
|
||||
dest.AppendPath( destDir );
|
||||
dest.AppendPath( token );
|
||||
|
||||
// Maya only accepts unix style path separators
|
||||
src.BackSlashesToSlashes();
|
||||
dest.BackSlashesToSlashes();
|
||||
|
||||
if( skipmeshes.Num() && keepmeshes.Num() )
|
||||
{
|
||||
MayaError( "Can't use -keepmesh and -skipmesh together." );
|
||||
}
|
||||
}
|
||||
|
||||
// RB end
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -29,6 +30,68 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#ifndef __MODELMANAGER_H__
|
||||
#define __MODELMANAGER_H__
|
||||
|
||||
/*
|
||||
==============================================================================================
|
||||
|
||||
idImportOptions
|
||||
|
||||
==============================================================================================
|
||||
*/
|
||||
|
||||
class idNamePair
|
||||
{
|
||||
public:
|
||||
idStr from;
|
||||
idStr to;
|
||||
};
|
||||
|
||||
class idAnimGroup
|
||||
{
|
||||
public:
|
||||
idStr name;
|
||||
idStrList joints;
|
||||
};
|
||||
|
||||
class idImportOptions
|
||||
{
|
||||
private:
|
||||
//idTokenizer tokens;
|
||||
//void Reset( const char* commandline );
|
||||
|
||||
public:
|
||||
idStr commandLine;
|
||||
idStr src;
|
||||
idStr dest;
|
||||
idStr game;
|
||||
idStr prefix;
|
||||
float scale;
|
||||
//exportType_t type;
|
||||
bool ignoreMeshes;
|
||||
bool clearOrigin;
|
||||
bool clearOriginAxis;
|
||||
bool ignoreScale;
|
||||
int startframe;
|
||||
int endframe;
|
||||
int framerate;
|
||||
float xyzPrecision;
|
||||
float quatPrecision;
|
||||
idStr align;
|
||||
idList<idNamePair> renamejoints;
|
||||
idList<idNamePair> remapjoints;
|
||||
idStrList keepjoints;
|
||||
idStrList skipmeshes;
|
||||
idStrList keepmeshes;
|
||||
idList<idAnimGroup*> exportgroups;
|
||||
idList<idAnimGroup> groups;
|
||||
float rotate;
|
||||
float jointThreshold;
|
||||
int cycleStart;
|
||||
|
||||
void Init( const char* commandline, const char* ospath );
|
||||
|
||||
//bool JointInExportGroup( const char* jointname );
|
||||
};
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
|
@ -67,7 +130,7 @@ public:
|
|||
|
||||
// returns NULL if modelName is NULL or an empty string, otherwise
|
||||
// it will create a default model if not loadable
|
||||
virtual idRenderModel* FindModel( const char* modelName ) = 0;
|
||||
virtual idRenderModel* FindModel( const char* modelName, const idImportOptions* options = NULL ) = 0;
|
||||
|
||||
// returns NULL if not loadable
|
||||
virtual idRenderModel* CheckModel( const char* modelName ) = 0;
|
||||
|
|
|
@ -57,7 +57,7 @@ bool idRenderModelStatic::ConvertGltfMeshToModelsurfaces( const gltfMesh* mesh )
|
|||
return false;
|
||||
}
|
||||
|
||||
void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, idMat4 parentTransform, gltfData* data )
|
||||
void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, const idMat4& parentTransform, const idMat4& globalTransform, gltfData* data )
|
||||
{
|
||||
auto& meshList = data->MeshList();
|
||||
auto& nodeList = data->NodeList();
|
||||
|
@ -73,7 +73,7 @@ void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, idMat4 parentTransfo
|
|||
for( auto prim : targetMesh->primitives )
|
||||
{
|
||||
//ConvertFromMeshGltf should only be used for the map, ConvertGltfMeshToModelsurfaces should be used.
|
||||
auto* mesh = MapPolygonMesh::ConvertFromMeshGltf( prim, data, blenderToDoomTransform * nodeToWorldTransform );
|
||||
auto* mesh = MapPolygonMesh::ConvertFromMeshGltf( prim, data, globalTransform * nodeToWorldTransform );
|
||||
modelSurface_t surf;
|
||||
|
||||
gltfMaterial* mat = NULL;
|
||||
|
@ -126,7 +126,7 @@ void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, idMat4 parentTransfo
|
|||
|
||||
for( auto& child : modelNode->children )
|
||||
{
|
||||
ProcessNode_r( nodeList[child], nodeToWorldTransform, data );
|
||||
ProcessNode_r( nodeList[child], nodeToWorldTransform, globalTransform, data );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ void idRenderModelGLTF::ProcessNode_r( gltfNode* modelNode, idMat4 parentTransfo
|
|||
// warning : nodeName cannot have dots!
|
||||
//[fileName].[nodeName/nodeId].[gltf/glb]
|
||||
//If no nodeName/nodeId is given, all primitives active in default scene will be added as surfaces.
|
||||
void idRenderModelGLTF::InitFromFile( const char* fileName )
|
||||
void idRenderModelGLTF::InitFromFile( const char* fileName, const idImportOptions* options )
|
||||
{
|
||||
hasAnimations = false;
|
||||
fileExclusive = false;
|
||||
|
@ -144,12 +144,13 @@ void idRenderModelGLTF::InitFromFile( const char* fileName )
|
|||
int meshID = -1;
|
||||
name = fileName;
|
||||
currentSkin = nullptr;
|
||||
globalTransform = blenderToDoomTransform;
|
||||
|
||||
PurgeModel();
|
||||
|
||||
//FIXME FIXME FIXME
|
||||
maxJointVertDist = 10;
|
||||
idStr gltfFileName = idStr( fileName );
|
||||
gltfFileName = idStr( fileName );
|
||||
model_state = DM_STATIC;
|
||||
|
||||
gltfManager::ExtractIdentifier( gltfFileName, meshID, meshName );
|
||||
|
@ -231,12 +232,25 @@ void idRenderModelGLTF::InitFromFile( const char* fileName )
|
|||
hasAnimations = totalAnims > 0;
|
||||
model_state = hasAnimations ? DM_CACHED : DM_STATIC;
|
||||
|
||||
ProcessNode_r( root, mat4_identity, data );
|
||||
//idMat4 globalTransform = blenderToDoomTransform;
|
||||
|
||||
if( options )
|
||||
{
|
||||
const auto blenderToDoomRotation = idAngles( 0.0f, 0.0f, 90 ).ToMat3();
|
||||
|
||||
float scale = options->scale;
|
||||
idMat3 scaleMat( scale, 0, 0, 0, scale, 0, 0, 0, scale );
|
||||
|
||||
globalTransform = idMat4( scaleMat * blenderToDoomRotation, vec3_origin );
|
||||
}
|
||||
|
||||
ProcessNode_r( root, mat4_identity, globalTransform, data );
|
||||
|
||||
if( surfaces.Num() <= 0 )
|
||||
{
|
||||
common->Warning( "Couldn't load model: '%s'", name.c_str() );
|
||||
MakeDefaultModel();
|
||||
data = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -259,6 +273,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
|
||||
if( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) )
|
||||
{
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -267,6 +282,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
|
||||
if( magic != GLMB_MAGIC )
|
||||
{
|
||||
data = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -343,6 +359,7 @@ bool idRenderModelGLTF::LoadBinaryModel( idFile* file, const ID_TIME_T sourceTim
|
|||
model_state = hasAnimations ? DM_CONTINUOUS : DM_STATIC;
|
||||
|
||||
lastMeshFromFile = this;
|
||||
data = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -467,7 +484,7 @@ void idRenderModelGLTF::DrawJoints( const struct renderEntity_s* ent, const view
|
|||
}
|
||||
}
|
||||
|
||||
bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfNode*>& nodes , idList<int, TAG_MODEL>& bones, idList<jointAnimInfo_t, TAG_MD5_ANIM>& jointInfo )
|
||||
static bool GatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfNode*>& nodes , idList<int, TAG_MODEL>& bones, idList<jointAnimInfo_t, TAG_MD5_ANIM>& jointInfo )
|
||||
{
|
||||
//Gather Bones;
|
||||
bool boneLess = false;
|
||||
|
@ -508,7 +525,7 @@ bool gatherBoneInfo( gltfData* data, gltfAnimation* gltfAnim, const idList<gltfN
|
|||
return boneLess;
|
||||
}
|
||||
|
||||
idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat )
|
||||
static idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat, const idMat4& globalTransform )
|
||||
{
|
||||
idList<idJointQuat> ret;
|
||||
ret.AssureSize( bones.Num() );
|
||||
|
@ -522,7 +539,7 @@ idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat )
|
|||
|
||||
if( node->parent == nullptr )
|
||||
{
|
||||
node->matrix *= blenderToDoomTransform;
|
||||
node->matrix *= globalTransform;
|
||||
trans = node->matrix;
|
||||
}
|
||||
|
||||
|
@ -549,7 +566,7 @@ idList<idJointQuat> GetPose( idList<gltfNode>& bones, idJointMat* poseMat )
|
|||
return ret;
|
||||
}
|
||||
|
||||
int copyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>& out )
|
||||
static int CopyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>& out )
|
||||
{
|
||||
out.Clear();
|
||||
|
||||
|
@ -584,12 +601,15 @@ int copyBones( gltfData* data, const idList<int>& bones, idList<gltfNode>& out )
|
|||
return out.Num();
|
||||
}
|
||||
|
||||
idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T sourceTimeStamp )
|
||||
idFile_Memory* idRenderModelGLTF::GetAnimBin( const idStr& animName, const ID_TIME_T sourceTimeStamp, const idImportOptions* options )
|
||||
{
|
||||
assert( lastMeshFromFile );
|
||||
///keep in sync with game!
|
||||
|
||||
//keep in sync with game!
|
||||
static const byte B_ANIM_MD5_VERSION = 101;
|
||||
static const unsigned int B_ANIM_MD5_MAGIC = ( 'B' << 24 ) | ( 'M' << 16 ) | ( 'D' << 8 ) | B_ANIM_MD5_VERSION;
|
||||
|
||||
// convert animName to original glTF2 filename and load it
|
||||
GLTF_Parser gltf;
|
||||
int id;
|
||||
idStr gltfFileName = idStr( animName );
|
||||
|
@ -617,8 +637,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
idList<int, TAG_MODEL> bones;
|
||||
idList<jointAnimInfo_t, TAG_MD5_ANIM> jointInfo;
|
||||
|
||||
|
||||
bool boneLess = gatherBoneInfo( data, gltfAnim, nodes, bones, jointInfo );
|
||||
bool boneLess = GatherBoneInfo( data, gltfAnim, nodes, bones, jointInfo );
|
||||
|
||||
idList<idList<gltfNode>> animBones;
|
||||
idList<float, TAG_MD5_ANIM> componentFrames;
|
||||
|
@ -632,6 +651,9 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
|
||||
gameLocal.Printf( "Generating MD5Anim for GLTF anim %s from scene %s\n", name.c_str(), gltf_ModelSceneName.GetString() );
|
||||
|
||||
// TODO use idImportOptions to build globalTransform
|
||||
|
||||
|
||||
gltfNode* root = nullptr;
|
||||
int channelCount = 0;
|
||||
for( auto channel : gltfAnim->channels )
|
||||
|
@ -675,16 +697,20 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::none:
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::rotation:
|
||||
newJoint->animBits |= ANIM_QX | ANIM_QY | ANIM_QZ;
|
||||
numAnimatedComponents += 3;
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::translation:
|
||||
newJoint->animBits |= ANIM_TX | ANIM_TY | ANIM_TZ;
|
||||
numAnimatedComponents += 3;
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::scale: // this is not supported by engine, but it should be for gltf
|
||||
break;
|
||||
}
|
||||
|
@ -695,7 +721,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
animBones.SetNum( numFrames );
|
||||
for( int i = 0; i < numFrames; i++ )
|
||||
{
|
||||
int totalCopied = copyBones( data, bones, animBones[i] );
|
||||
int totalCopied = CopyBones( data, bones, animBones[i] );
|
||||
assert( totalCopied );
|
||||
}
|
||||
|
||||
|
@ -722,7 +748,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
baseFrame.SetNum( bones.Num() );
|
||||
|
||||
idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) );
|
||||
baseFrame = GetPose( animBones[0], poseMat );
|
||||
baseFrame = GetPose( animBones[0], poseMat, blenderToDoomTransform );
|
||||
|
||||
componentFrames.SetGranularity( 1 );
|
||||
componentFrames.SetNum( ( ( numAnimatedComponents * numFrames ) ) + 1 );
|
||||
|
@ -748,8 +774,10 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::none:
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::rotation:
|
||||
{
|
||||
idList<idQuat*>& values = data->GetAccessorView<idQuat>( output );
|
||||
|
@ -757,8 +785,9 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
{
|
||||
animBones[i][boneIndex].rotation = *values[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::translation:
|
||||
{
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
|
@ -766,17 +795,21 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
{
|
||||
animBones[i][boneIndex].translation = *values[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case gltfAnimation_Channel_Target::scale:
|
||||
{
|
||||
idList<idVec3*>& values = data->GetAccessorView<idVec3>( output );
|
||||
if( values.Num() > i )
|
||||
{
|
||||
animBones[i][boneIndex].scale = *values[i] ;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( int b = 0; b < bones.Num(); b++ )
|
||||
{
|
||||
auto* node = &animBones[i][b];
|
||||
|
@ -836,7 +869,7 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
}
|
||||
|
||||
idList<idJointMat> joints;
|
||||
GetPose( animBones[i], currJoints );
|
||||
GetPose( animBones[i], currJoints, blenderToDoomTransform );
|
||||
for( int b = 0; b < animBones[i].Num(); b++ )
|
||||
{
|
||||
idJointMat mat = poseMat[b];
|
||||
|
@ -893,9 +926,6 @@ idFile_Memory* idRenderModelGLTF::GetAnimBin( idStr animName , const ID_TIME_T
|
|||
file->WriteBig( numJoints );
|
||||
file->WriteBig( numAnimatedComponents );
|
||||
|
||||
|
||||
|
||||
|
||||
file->WriteBig( bounds.Num() );
|
||||
for( int i = 0; i < bounds.Num(); i++ )
|
||||
{
|
||||
|
@ -1049,6 +1079,7 @@ void idRenderModelGLTF::WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp /*
|
|||
|
||||
void idRenderModelGLTF::PurgeModel()
|
||||
{
|
||||
idRenderModelStatic::PurgeModel();
|
||||
purged = true;
|
||||
md5joints.Clear();
|
||||
defaultPose.Clear();
|
||||
|
@ -1057,16 +1088,20 @@ void idRenderModelGLTF::PurgeModel()
|
|||
animIds.Clear();
|
||||
bones.Clear();
|
||||
MeshNodeIds.Clear();
|
||||
gltfFileName.Clear();
|
||||
|
||||
//if no root id was set, it is a generated one.
|
||||
if( rootID == -1 && root )
|
||||
{
|
||||
delete root;
|
||||
}
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
void idRenderModelGLTF::LoadModel()
|
||||
{
|
||||
assert( data );
|
||||
|
||||
int num;
|
||||
auto& accessors = data->AccessorList();
|
||||
auto& nodes = data->NodeList();
|
||||
|
@ -1074,6 +1109,7 @@ void idRenderModelGLTF::LoadModel()
|
|||
if( !fileExclusive )
|
||||
{
|
||||
meshRoot = data->GetNode( gltf_ModelSceneName.GetString(), meshName );
|
||||
assert( meshRoot );
|
||||
}
|
||||
|
||||
gltfSkin* skin = nullptr;
|
||||
|
@ -1132,8 +1168,8 @@ void idRenderModelGLTF::LoadModel()
|
|||
|
||||
idJointMat* poseMat = ( idJointMat* ) _alloca16( bones.Num() * sizeof( poseMat[0] ) );
|
||||
idList<gltfNode> animBones;
|
||||
int totalCopied = copyBones( data, bones, animBones );
|
||||
defaultPose = GetPose( animBones, poseMat );
|
||||
int totalCopied = CopyBones( data, bones, animBones );
|
||||
defaultPose = GetPose( animBones, poseMat, globalTransform );
|
||||
|
||||
if( !currentSkin )
|
||||
{
|
||||
|
@ -1462,9 +1498,6 @@ idRenderModel* idRenderModelGLTF::InstantiateDynamicModel( const struct renderEn
|
|||
if( purged )
|
||||
{
|
||||
common->DWarning( "model %s instantiated while purged", Name() );
|
||||
GLTF_Parser gltf;
|
||||
gltf.Load( name );
|
||||
data = gltf.currentAsset;
|
||||
LoadModel();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
class idRenderModelGLTF : public idRenderModelStatic
|
||||
{
|
||||
public:
|
||||
virtual void InitFromFile( const char* fileName ) override;
|
||||
virtual void InitFromFile( const char* fileName, const idImportOptions* options ) override;
|
||||
virtual bool LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp ) override;
|
||||
virtual void WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp = NULL ) const override;
|
||||
virtual dynamicModel_t IsDynamicModel() const override;
|
||||
|
@ -54,10 +54,10 @@ public:
|
|||
{
|
||||
return true;
|
||||
}
|
||||
static idFile_Memory* GetAnimBin( idStr animName, const ID_TIME_T sourceTimeStamp );
|
||||
static idFile_Memory* GetAnimBin( const idStr& animName, const ID_TIME_T sourceTimeStamp, const idImportOptions* options );
|
||||
int rootID;
|
||||
private:
|
||||
void ProcessNode_r( gltfNode* modelNode, idMat4 trans, gltfData* data );
|
||||
void ProcessNode_r( gltfNode* modelNode, const idMat4& parentTransform, const idMat4& globalTransform, gltfData* data );
|
||||
void UpdateSurface( const struct renderEntity_s* ent, const idJointMat* entJoints, const idJointMat* entJointsInverted, modelSurface_t* surf, const modelSurface_t& sourceSurf );
|
||||
void UpdateMd5Joints();
|
||||
|
||||
|
@ -73,11 +73,15 @@ private:
|
|||
idList<int, TAG_MODEL> MeshNodeIds;
|
||||
dynamicModel_t model_state;
|
||||
idStr meshName;
|
||||
idStr gltfFileName;
|
||||
|
||||
idList<idMD5Joint, TAG_MODEL> md5joints;
|
||||
idList<idJointQuat, TAG_MODEL> defaultPose;
|
||||
idList<idJointMat, TAG_MODEL> invertedDefaultPose;
|
||||
gltfSkin* currentSkin;
|
||||
|
||||
// derived reimport options
|
||||
idMat4 globalTransform; // Blender to Doom + exta scaling, rotation
|
||||
private:
|
||||
void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view );
|
||||
};
|
|
@ -373,7 +373,7 @@ void idRenderModelLiquid::Reset()
|
|||
idRenderModelLiquid::InitFromFile
|
||||
====================
|
||||
*/
|
||||
void idRenderModelLiquid::InitFromFile( const char* fileName, nvrhi::ICommandList* commandList )
|
||||
void idRenderModelLiquid::InitFromFile( const char* fileName, nvrhi::ICommandList* commandList, const idImportOptions* options )
|
||||
{
|
||||
int i, x, y;
|
||||
idToken token;
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
idRenderModelStatic();
|
||||
virtual ~idRenderModelStatic();
|
||||
|
||||
virtual void InitFromFile( const char* fileName );
|
||||
virtual void InitFromFile( const char* fileName, const idImportOptions* options );
|
||||
virtual bool LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp );
|
||||
virtual void WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp = NULL ) const;
|
||||
virtual bool SupportsBinaryModel()
|
||||
|
@ -218,7 +218,7 @@ class idRenderModelMD5 : public idRenderModelStatic
|
|||
{
|
||||
friend class idRenderModelGLTF;
|
||||
public:
|
||||
void InitFromFile( const char* fileName ) override;
|
||||
void InitFromFile( const char* fileName, const idImportOptions* options );
|
||||
bool LoadBinaryModel( idFile* file, const ID_TIME_T sourceTimeStamp ) override;
|
||||
void WriteBinaryModel( idFile* file, ID_TIME_T* _timeStamp = NULL ) const override;
|
||||
dynamicModel_t IsDynamicModel() const override;
|
||||
|
@ -271,7 +271,7 @@ struct md3Surface_s;
|
|||
class idRenderModelMD3 : public idRenderModelStatic
|
||||
{
|
||||
public:
|
||||
virtual void InitFromFile( const char* fileName );
|
||||
virtual void InitFromFile( const char* fileName, const idImportOptions* options );
|
||||
virtual bool SupportsBinaryModel()
|
||||
{
|
||||
return false;
|
||||
|
@ -302,7 +302,7 @@ class idRenderModelLiquid : public idRenderModelStatic
|
|||
public:
|
||||
idRenderModelLiquid();
|
||||
|
||||
virtual void InitFromFile( const char* fileName, nvrhi::ICommandList* commandList );
|
||||
virtual void InitFromFile( const char* fileName, nvrhi::ICommandList* commandList, const idImportOptions* options );
|
||||
virtual bool SupportsBinaryModel()
|
||||
{
|
||||
return false;
|
||||
|
@ -363,7 +363,7 @@ class idRenderModelPrt : public idRenderModelStatic
|
|||
public:
|
||||
idRenderModelPrt();
|
||||
|
||||
virtual void InitFromFile( const char* fileName );
|
||||
virtual void InitFromFile( const char* fileName, const idImportOptions* options );
|
||||
virtual bool SupportsBinaryModel()
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -46,7 +46,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
idRenderModelMD3::InitFromFile
|
||||
=================
|
||||
*/
|
||||
void idRenderModelMD3::InitFromFile( const char* fileName )
|
||||
void idRenderModelMD3::InitFromFile( const char* fileName, const idImportOptions* options )
|
||||
{
|
||||
int i, j;
|
||||
md3Header_t* pinmodel;
|
||||
|
|
|
@ -706,7 +706,7 @@ void idRenderModelMD5::ParseJoint( idLexer& parser, idMD5Joint* joint, idJointQu
|
|||
idRenderModelMD5::InitFromFile
|
||||
====================
|
||||
*/
|
||||
void idRenderModelMD5::InitFromFile( const char* fileName )
|
||||
void idRenderModelMD5::InitFromFile( const char* fileName, const idImportOptions* options )
|
||||
{
|
||||
name = fileName;
|
||||
LoadModel();
|
||||
|
|
|
@ -49,7 +49,7 @@ idRenderModelPrt::idRenderModelPrt()
|
|||
idRenderModelPrt::InitFromFile
|
||||
====================
|
||||
*/
|
||||
void idRenderModelPrt::InitFromFile( const char* fileName )
|
||||
void idRenderModelPrt::InitFromFile( const char* fileName, const idImportOptions* options )
|
||||
{
|
||||
name = fileName;
|
||||
particleSystem = static_cast<const idDeclParticle*>( declManager->FindType( DECL_PARTICLE, fileName ) );
|
||||
|
|
Loading…
Reference in a new issue