mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-04-19 08:12:14 +00:00
- Skinned / animated GLTF models
This commit is contained in:
parent
edf657f50d
commit
e56f696c9c
9 changed files with 848 additions and 345 deletions
|
@ -484,6 +484,8 @@ endif (RAPIDJSON_FOUND)
|
|||
|
||||
add_subdirectory(idlib)
|
||||
|
||||
file(GLOB NATVIS_SOURCES .natvis)
|
||||
|
||||
file(GLOB AAS_INCLUDES aas/*.h)
|
||||
file(GLOB AAS_SOURCES aas/*.cpp)
|
||||
|
||||
|
@ -1389,6 +1391,7 @@ set(RBDOOM3_INCLUDES
|
|||
)
|
||||
|
||||
set(RBDOOM3_SOURCES
|
||||
${NATVIS_SOURCES}
|
||||
${AAS_SOURCES}
|
||||
${CM_SOURCES}
|
||||
${FRAMEWORK_SOURCES}
|
||||
|
|
63
neo/idStuff.natvis
Normal file
63
neo/idStuff.natvis
Normal 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<*>">
|
||||
<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>
|
|
@ -218,17 +218,14 @@ MapPolygonMesh* MapPolygonMesh::ConvertFromMeshGltf( const gltfMesh_Primitive* p
|
|||
bin.Seek( attrBv->byteStride - ( attrib->elementSize * attrAcc->typeSize ), FS_SEEK_CUR );
|
||||
}
|
||||
|
||||
mesh->verts[i].color2[0] = vec.x;
|
||||
mesh->verts[i].color2[1] = vec.y;
|
||||
mesh->verts[i].color2[2] = vec.z;
|
||||
mesh->verts[i].color2[3] = vec.w;
|
||||
mesh->verts[i].SetColor2( PackColor( vec ) );
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gltfMesh_Primitive_Attribute::Type::Indices:
|
||||
{
|
||||
idVec4 vec;
|
||||
idVec4i vec;
|
||||
for( int i = 0; i < attrAcc->count; i++ )
|
||||
{
|
||||
bin.Read( ( void* )( &vec.x ), attrAcc->typeSize );
|
||||
|
|
|
@ -2318,7 +2318,7 @@ CONSOLE_COMMAND_COMPILE( LoadGLTF, "Loads an .gltf or .glb file", idCmdSystem::A
|
|||
|
||||
|
||||
// not dots allowed in [%s]!
|
||||
// [filename].[%i|%s].[gltf/glb]
|
||||
// [filename].[%i|%s].[gltf|glb]
|
||||
bool gltfManager::ExtractIdentifier( idStr& filename, int& id, idStr& name )
|
||||
{
|
||||
idStr extension;
|
||||
|
|
|
@ -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;
|
||||
|
@ -866,23 +871,6 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
gltfNode* GetNode( gltfScene* scene, idStr name )
|
||||
{
|
||||
assert( scene );
|
||||
assert( name[0] );
|
||||
|
||||
auto& nodeList = scene->nodes;
|
||||
for( auto& nodeId : nodeList )
|
||||
{
|
||||
if( nodes[nodeId]->name == name )
|
||||
{
|
||||
return nodes[nodeId];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
gltfNode* GetNode( idStr sceneName, int id, idStr* name = nullptr )
|
||||
{
|
||||
int sceneId = GetSceneId( sceneName );
|
||||
|
@ -913,7 +901,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
gltfNode* GetNode( idStr sceneName, idStr name , int* id = nullptr )
|
||||
gltfNode* GetNode( idStr sceneName, idStr name , int* id = nullptr , bool caseSensitive = false )
|
||||
{
|
||||
int sceneId = GetSceneId( sceneName );
|
||||
if( sceneId < 0 || sceneId > scenes.Num() )
|
||||
|
@ -927,9 +915,9 @@ public:
|
|||
assert( name[0] );
|
||||
|
||||
auto& nodeList = scene->nodes;
|
||||
for( auto& nodeId : nodeList )
|
||||
for( auto nodeId : nodeList )
|
||||
{
|
||||
if( nodes[nodeId]->name.Icmp( name ) == 0 )
|
||||
if( caseSensitive ? nodes[nodeId]->name.Cmp( name ) : nodes[nodeId]->name.Icmp( name ) == 0 )
|
||||
{
|
||||
if( id != nullptr )
|
||||
{
|
||||
|
@ -946,10 +934,10 @@ public:
|
|||
int GetNodeIndex( gltfNode* node )
|
||||
{
|
||||
int index = -1;
|
||||
for( auto* node : nodes )
|
||||
for( auto& it : nodes )
|
||||
{
|
||||
index++;
|
||||
if( node == node )
|
||||
if( it == node )
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
@ -984,19 +972,81 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int GetSceneId( idStr sceneName ) const
|
||||
int GetSceneId( idStr sceneName , gltfScene* result = nullptr ) const
|
||||
{
|
||||
for( int i = 0; i < scenes.Num(); i++ )
|
||||
{
|
||||
if( scenes[i]->name == sceneName )
|
||||
{
|
||||
if( result != nullptr )
|
||||
{
|
||||
result = scenes[i];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
idList<int> GetChannelIds( gltfAnimation* anim , gltfNode* node )
|
||||
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;
|
||||
|
@ -1012,9 +1062,9 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
idList<int> GetAnimationIds( gltfNode* node )
|
||||
int GetAnimationIds( gltfNode* node , idList<int>& result )
|
||||
{
|
||||
idList<int> result;
|
||||
|
||||
int animIdx = 0;
|
||||
for( auto anim : animations )
|
||||
{
|
||||
|
@ -1022,13 +1072,16 @@ public:
|
|||
{
|
||||
if( channel->target.node >= 0 && nodes[channel->target.node] == node )
|
||||
{
|
||||
result.Append( animIdx );
|
||||
break;
|
||||
result.AddUnique( animIdx );
|
||||
}
|
||||
}
|
||||
animIdx++;
|
||||
}
|
||||
return result;
|
||||
for( int nodeId : node->children )
|
||||
{
|
||||
GetAnimationIds( nodes[nodeId], result );
|
||||
}
|
||||
return result.Num();
|
||||
}
|
||||
|
||||
idMat4 GetViewMatrix( int camId ) const
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -68,16 +68,14 @@ private:
|
|||
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;
|
||||
idList<gltfNode*, TAG_MODEL> SkeletonNodes;
|
||||
idStr meshName;
|
||||
|
||||
idList<idMD5Joint, TAG_MODEL> md5joints;
|
||||
idList<idJointQuat, TAG_MODEL> defaultPose;
|
||||
idList<idJointMat, TAG_MODEL> invertedDefaultPose;
|
||||
idList<idMD5Mesh, TAG_MODEL> meshes;
|
||||
deformInfo_t* deformInfo;
|
||||
|
||||
MapPolygonMesh* mesh;
|
||||
gltfSkin* currentSkin;
|
||||
private:
|
||||
void DrawJoints( const struct renderEntity_s* ent, const viewDef_t* view );
|
||||
};
|
Loading…
Reference in a new issue