+ id style gltf2 parser

+ initial attempt to dmap glb/gltf
[!] added blend file and glb for debugging purposes
This commit is contained in:
HarrievG 2022-06-06 00:39:04 +02:00
parent e6caee4cae
commit 0518644103
18 changed files with 3355 additions and 54 deletions

BIN
base/physics_test.blend Normal file

Binary file not shown.

BIN
base/physics_test.glb Normal file

Binary file not shown.

View file

@ -243,7 +243,7 @@ ID_INLINE void idCmdSystem::ArgCompletion_FileName( const idCmdArgs& args, void(
ID_INLINE void idCmdSystem::ArgCompletion_MapName( const idCmdArgs& args, void( *callback )( const char* s ) )
{
cmdSystem->ArgCompletion_FolderExtension( args, callback, "maps/", true, ".map", ".json", NULL );
cmdSystem->ArgCompletion_FolderExtension( args, callback, "maps/", true, ".map", ".json",".gltf",".glb", NULL );
}
ID_INLINE void idCmdSystem::ArgCompletion_MapNameNoJson( const idCmdArgs& args, void( *callback )( const char* s ) )

View file

@ -1507,31 +1507,31 @@ Skips until a matching close brace is found.
Internal brace depths are properly skipped.
=================
*/
int idLexer::SkipBracedSection( bool parseFirstBrace )
{
int idLexer::SkipBracedSection( bool parseFirstBrace, braceSkipMode_t skipMode/* = BRSKIP_BRACE */, int * skipped /*= nullptr*/) {
idToken token;
int depth;
idStr openTokens[2] = { "{" , "[" };
idStr closeTokens[2] = { "}" , "]" };
if ( skipped != nullptr )
*skipped = 0;
int scopeCount = 0;
depth = parseFirstBrace ? 0 : 1;
do
{
if( !ReadToken( &token ) )
{
do {
if ( !ReadToken( &token ) ) {
return false;
}
if( token.type == TT_PUNCTUATION )
{
if( token == "{" )
{
if ( token.type == TT_PUNCTUATION ) {
if ( token == openTokens[skipMode] ) {
depth++;
}
else if( token == "}" )
{
if ( skipped != nullptr )
(*skipped)++;
} else if ( token == closeTokens[skipMode] ) {
depth--;
}
}
}
while( depth );
} while( depth );
return true;
}
@ -2083,8 +2083,9 @@ void idLexer::Reset()
// set if there's a token available in idLexer::token
idLexer::tokenavailable = 0;
idLexer::line = 1;
idLexer::lastline = 1;
idLexer::line = intialLine;
idLexer::lastline = intialLine;
// clear the saved token
idLexer::token = "";
}
@ -2166,6 +2167,7 @@ int idLexer::LoadFile( const char* filename, bool OSPath )
idLexer::tokenavailable = 0;
idLexer::line = 1;
idLexer::line = 1;
idLexer::lastline = 1;
idLexer::allocated = true;
idLexer::loaded = true;
@ -2199,6 +2201,7 @@ int idLexer::LoadMemory( const char* ptr, int length, const char* name, int star
idLexer::tokenavailable = 0;
idLexer::line = startLine;
idLexer::lastline = startLine;
idLexer::intialLine = startLine;
idLexer::allocated = false;
idLexer::loaded = true;

View file

@ -64,6 +64,12 @@ typedef enum
LEXFL_ONLYSTRINGS = BIT( 13 ) // parse as whitespace deliminated strings (quoted strings keep quotes)
} lexerFlags_t;
typedef enum {
BRSKIP_BRACES,
BRSKIP_BRACKET
} braceSkipMode_t;
// punctuation ids
#define P_RSHIFT_ASSIGN 1
#define P_LSHIFT_ASSIGN 2
@ -182,7 +188,7 @@ public:
// skip the rest of the current line
int SkipRestOfLine();
// skip the braced section
int SkipBracedSection( bool parseFirstBrace = true );
int SkipBracedSection( bool parseFirstBrace = true , braceSkipMode_t skipMode = BRSKIP_BRACES,int * skipped = nullptr);
// skips spaces, tabs, C-like comments etc. Returns false if there is no token left to read.
bool SkipWhiteSpace( bool currentLine );
// unread the given token
@ -267,6 +273,7 @@ private:
int length; // length of the script in bytes
int line; // current line in script
int lastline; // line before reading token
int intialLine; // line that was set on load as starting line
int tokenavailable; // set by unreadToken
int flags; // several script flags
const punctuation_t* punctuations; // the punctuations used in the script

View file

@ -1553,6 +1553,7 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
idMapEntity* mapEnt;
int i, j, k;
idStr extension;
name = filename;
name.StripFileExtension();
name.StripFileExtension(); // RB: there might be .map.map
@ -1572,6 +1573,18 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
}
}
bool isGTLF = false;
if ( !src.IsLoaded( ) ) {
// HVG: try loading a .gltf/glb second
fullName.SetFileExtension( "glb" );
isGTLF = src.LoadFile( fullName, osPath );
if ( !isGTLF )
{
fullName.SetFileExtension( "gltf" );
isGTLF = src.LoadFile( fullName, osPath );
}
}
if( !src.IsLoaded() )
{
// now try a .map file
@ -1588,17 +1601,11 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
fileTime = src.GetFileTime();
entities.DeleteContents( true );
if( !src.ReadToken( &token ) )
if(!isGTLF && !src.ReadToken( &token ) )
{
return false;
}
// RB: TODO check for JSON in another way
//if( token == "{" )
//{
// isJSON = true;
//}
if( isJSON )
{
while( true )
@ -1661,7 +1668,11 @@ bool idMapFile::Parse( const char* filename, bool ignoreRegion, bool osPath )
}
}
}
else
else if ( isGTLF )
{
gltfParser->Load( fullName );
idMapEntity::GetEntities(gltfParser->currentAsset,entities,0);
}else
{
if( token == "Version" )
{

View file

@ -29,6 +29,7 @@ If you have questions concerning this license or the applicable additional terms
#ifndef __MAPFILE_H__
#define __MAPFILE_H__
#include "gltfProperties.h"
/*
===============================================================================
@ -348,7 +349,7 @@ public:
void ConvertFromBrush( const idMapBrush* brush, int entityNum, int primitiveNum );
void ConvertFromPatch( const idMapPatch* patch, int entityNum, int primitiveNum );
void ConvertFromMeshGltf( const gltfMesh * mesh , gltfData * data );
static MapPolygonMesh* Parse( idLexer& src, const idVec3& origin, float version = CURRENT_MAP_VERSION );
bool Write( idFile* fp, int primitiveNum, const idVec3& origin ) const;
@ -367,6 +368,9 @@ public:
return verts.Append( v );
}
int AddVertices( const idList<idDrawVert> &v ) {
return verts.Append( v );
}
int GetNumPolygons() const
{
@ -422,6 +426,10 @@ protected:
class idMapEntity
{
typedef idList<idMapEntity *, TAG_IDLIB_LIST_MAP> EntityList;
typedef idList<idMapEntity *, TAG_IDLIB_LIST_MAP> &EntityListRef;
typedef idList<idMapEntity *, TAG_IDLIB_LIST_MAP> *EntityListPtr;
friend class idMapFile;
public:
@ -437,8 +445,12 @@ public:
{
primitives.DeleteContents( true );
}
// HVG check gltf scene for entities
static int GetEntities( gltfData * data, EntityListRef entities, int scene = 0 );
static idMapEntity* Parse( idLexer& src, bool worldSpawn = false, float version = CURRENT_MAP_VERSION );
bool Write( idFile* fp, int entityNum, bool valve220 ) const;
// HVG NOTE: this is not compatible with gltf (extra) json!
// RB begin
static idMapEntity* ParseJSON( idLexer& src );
bool WriteJSON( idFile* fp, int entityNum, int numEntities ) const;
@ -538,7 +550,7 @@ protected:
float version;
ID_TIME_T fileTime;
unsigned int geometryCRC;
idList<idMapEntity*, TAG_IDLIB_LIST_MAP> entities;
idMapEntity::EntityList entities;
idStr name;
bool hasPrimitiveData;
bool valve220Format; // RB: for TrenchBroom support

View file

@ -203,29 +203,21 @@ public:
memTag = ( byte )tag_;
};
// Begin/End methods for range-based for loops.
_type_* begin()
{
if( num > 0 )
{
return &list[0];
struct Iterator {
_type_ *p;
_type_ &operator*( ) { return *p; }
bool operator != ( const Iterator &rhs ) {
return p != rhs.p;
}
else
{
return nullptr;
}
}
_type_* end()
{
if( num > 0 )
{
return &list[num - 1];
}
else
{
return nullptr;
}
}
void operator ++( ) { ++p; }
};
auto begin( ) const { // const version
return Iterator{list};
};
auto end( ) const { // const version
return Iterator{list + Num( )};
};
private:
int num;

35
neo/idlib/gltfExtras.cpp Normal file
View file

@ -0,0 +1,35 @@
#include "precompiled.h"
#pragma hdrstop
#include "gltfExtras.h"
extern idCVar gltf_parseVerbose;
void gltfExtra_Scatter::parse( idToken &token, idLexer * parser ) {
parser->UnreadToken( &token );
gltfItemArray scatterInfo;
GLTFARRAYITEM( scatterInfo, emitter, gltfObject );
scatterInfo.Parse( parser,true );
}
void gltfExtra_cvar::parse( idToken &token, idLexer *parser ) {
parser->UnreadToken( &token );
gltfItemArray cvarInfo;
idStr n,t,v,d;
GLTFARRAYITEMREF( cvarInfo, name, gltfItem , n);
GLTFARRAYITEMREF( cvarInfo, type, gltfItem , t);
GLTFARRAYITEMREF( cvarInfo, value, gltfItem, v );
GLTFARRAYITEMREF( cvarInfo, desc, gltfItem , d);
int total = cvarInfo.Parse( parser );
assert( total == 3 );
idCVar * gltExtra_cvar = new idCVar(
n.c_str(),
v.c_str(),
CVAR_SYSTEM | CVAR_BOOL,
d.c_str()
);
cvarSystem->Register(gltExtra_cvar);
}

35
neo/idlib/gltfExtras.h Normal file
View file

@ -0,0 +1,35 @@
#include "gltfParser.h"
#ifndef gltfExtraParser
#define gltfExtraParser(className,ptype) \
class gltfExtra_##className : public parsable, public parseType<ptype> \
{public: \
gltfExtra_##className( idStr Name ) : name( Name ){ item = nullptr; } \
virtual void parse( idToken &token ){parse(token,nullptr);} \
virtual void parse( idToken &token , idLexer * parser ); \
virtual idStr &Name( ) { return name; } \
private: \
idStr name;}
#pragma endregion
#endif
//Helper macros for gltf data deserialize
#define GLTFARRAYITEM(target,name,type) auto * name = new type (#name); target.AddItemDef((parsable*)name)
#define GLTFARRAYITEMREF(target,name,type,ref) auto * name = new type (#name); target.AddItemDef((parsable*)name); name->Set(&ref)
#ifndef GLTF_EXTRAS_H
#define GLTF_EXTRAS_H
class test {
public:
test(){ }
};
gltfExtraParser( Scatter, test );
gltfExtraParser( cvar, idCVar );
#endif // GLTF_EXTRAS_H
#ifndef gltfExternalParser
#undef gltfExtraParser
#endif

2111
neo/idlib/gltfParser.cpp Normal file

File diff suppressed because it is too large Load diff

240
neo/idlib/gltfParser.h Normal file
View file

@ -0,0 +1,240 @@
#pragma once
#include "containers/StrList.h"
#include <functional>
#include "gltfProperties.h"
#pragma region GLTF Types parsing
#pragma region Parser interfaces
struct parsable {
public:
virtual void parse(idToken & token )=0;
virtual void parse(idToken & token , idLexer * parser){};
virtual idStr &Name( ) = 0;
};
template<class T>
class parseType {
public:
void Set(T * type ) { item = type; }
virtual ~parseType() { delete item; }
T* item;
};
class gltfItem : public parsable, public parseType<idStr>
{
public:
gltfItem( idStr Name) : name( Name ) { item = nullptr; }
virtual void parse( idToken &token ) { *item = token; };
virtual idStr &Name( ) {return name;}
~gltfItem(){}
private:
idStr name;
};
class gltfObject : public parsable, public parseType<idStr> {
public:
gltfObject( idStr Name ) : name( Name ), object("null"){}
virtual void parse( idToken &token ) {}
virtual void parse(idToken & token , idLexer * parser){
parser->UnreadToken( &token );parser->ParseBracedSection( object );
}
virtual idStr &Name( ) { return name; }
private:
idStr name;
idStr object;
};
class gltfItemArray;
class gltfItem_Extra : public parsable, public parseType<gltfExtra> {
public:
gltfItem_Extra( idStr Name ) : name( Name ), data(nullptr),parser(nullptr) { item = nullptr; }
virtual void parse( idToken &token ) ;
virtual idStr &Name( ) { return name; }
void Set( gltfExtra *type, idLexer *lexer ) { parseType::Set( type ); parser = lexer; }
static void Register(parsable * extra);
private:
idStr name;
gltfData *data;
idLexer* parser;
static gltfItemArray*items;
};
class gltfItem_uri : public parsable, public parseType<idStr> {
public:
gltfItem_uri( idStr Name ) : name( Name ) { item = nullptr; }
virtual void parse( idToken &token ) { *item = token; Convert(); };
virtual idStr &Name( ) { return name; }
void Set( idStr *type,int * targetBufferview,gltfData* dataDestination ) { parseType::Set(type); bufferView = targetBufferview; data = dataDestination; }
// read data from uri file, and push it at end of current data buffer for this GLTF File
// bufferView will be set accordingly to the generated buffer.
bool Convert( );
private:
idStr name;
int * bufferView;
gltfData * data;
};
#pragma endregion
#pragma region helper macro to define gltf data types with extra parsing context forced to be implemented externally
#define gltfItemClassParser(className,ptype) \
class gltfItem_##className : public parsable, public parseType<ptype> \
{public: \
gltfItem_##className( idStr Name ) : name( Name ){ item = nullptr; } \
virtual void parse( idToken &token ); \
virtual idStr &Name( ) { return name; } \
void Set( ptype *type, idLexer *lexer ) { parseType::Set( type ); parser = lexer; } \
private: \
idStr name; \
idLexer *parser;}
#pragma endregion
gltfItemClassParser( animation_sampler, idList<gltfAnimation_Sampler*> );
gltfItemClassParser( animation_channel_target, gltfAnimation_Channel_Target );
gltfItemClassParser( animation_channel, idList<gltfAnimation_Channel*>);
gltfItemClassParser( mesh_primitive, idList<gltfMesh_Primitive *>);
gltfItemClassParser( mesh_primitive_attribute, idList<gltfMesh_Primitive_Attribute *> );
gltfItemClassParser( integer_array, idList<int>);
gltfItemClassParser( number_array, idList<double>);//does float suffice?
gltfItemClassParser( mat4, idMat4 );
gltfItemClassParser( vec4, idVec4 );
gltfItemClassParser( vec3, idVec3 );
gltfItemClassParser( vec2, idVec2 );
gltfItemClassParser( quat, idQuat );
gltfItemClassParser( accessor_sparse, gltfAccessor_Sparse );
gltfItemClassParser( accessor_sparse_indices, gltfAccessor_Sparse_Indices );
gltfItemClassParser( accessor_sparse_values, gltfAccessor_Sparse_Values );
gltfItemClassParser( camera_perspective, gltfCamera_Perspective );
gltfItemClassParser( camera_orthographic, gltfCamera_Orthographic );
gltfItemClassParser( pbrMetallicRoughness, gltfMaterial_pbrMetallicRoughness );
gltfItemClassParser( texture_info, gltfTexture_Info);
gltfItemClassParser( normal_texture, gltfNormalTexture_Info);
gltfItemClassParser( occlusion_texture, gltfOcclusionTexture_Info );
gltfItemClassParser( node_extensions, gltfNode_Extensions );
gltfItemClassParser( material_extensions, gltfMaterial_Extensions );
gltfItemClassParser( texture_info_extensions, gltfTexture_Info_Extensions );
//extensions
gltfItemClassParser( KHR_lights_punctual, gltfExtensions );
gltfItemClassParser( Node_KHR_lights_punctual, gltfNode_Extensions );
gltfItemClassParser( Material_KHR_materials_pbrSpecularGlossiness, gltfMaterial_Extensions );
gltfItemClassParser( TextureInfo_KHR_texture_transform, gltfTexture_Info_Extensions );
#undef gltfItemClassParser
#pragma region helper macro to define more gltf data types that only rely on token
#define gltfItemClass(className,type,function) \
class gltfItem_##className : public parsable, public parseType<type> \
{public: \
gltfItem_##className( idStr Name ) : name( Name ){ item = nullptr; } \
virtual void parse( idToken &token ) { function } \
virtual idStr &Name( ) { return name; } \
private: \
idStr name;}
#pragma endregion
gltfItemClass(integer, int, *item = token.GetIntValue( ); );
gltfItemClass(number, float, *item = token.GetFloatValue( ); );
gltfItemClass(boolean, bool, if (token.Icmp("true") == 0 ) *item=true; else{ if(token.Icmp("false") == 0)*item=false; else idLib::FatalError("parse error");});
#undef gltfItemClass
class gltfItemArray
{
public:
~gltfItemArray( ) { items.DeleteContents(true); }
gltfItemArray( ) { };
int Num() { return items.Num(); }
void AddItemDef( parsable *item ) { items.Alloc( ) = item;}
int Fill(idLexer * lexer , idDict * strPairs );
int Parse(idLexer * lexer , bool forwardLexer = false );
template<class T>
T* Get(idStr name ){ for ( auto * item : items) if (item->Name() == name) return static_cast<T*>(item); return nullptr; }
private:
idList<parsable*> items;
};
#pragma endregion
#pragma region GLTF Object parsing
class gltfPropertyArray;
class gltfPropertyItem
{
public:
gltfPropertyItem( ) : array(nullptr){ }
gltfPropertyArray * array;
idToken item;
};
class gltfPropertyArray
{
public:
gltfPropertyArray( idLexer *Parser,bool AoS = true );
~gltfPropertyArray( );
struct Iterator {
gltfPropertyArray * array;
gltfPropertyItem *p;
gltfPropertyItem &operator*( ) {return *p;}
bool operator != ( Iterator &rhs ) {
return p != rhs.p;
}
void operator ++( );
};
gltfPropertyArray::Iterator begin( );
gltfPropertyArray::Iterator end( );
private:
bool iterating;
bool dirty;
int index;
idLexer * parser;
idList<gltfPropertyItem*> properties;
gltfPropertyItem * endPtr;
bool isArrayOfStructs;
};
#pragma endregion
class GLTF_Parser
{
public:
GLTF_Parser();
void Shutdown();
bool Parse();
bool Load(idStr filename );
bool loadGLB(idStr filename );
//current/last loaded gltf asset and index offsets
gltfData *currentAsset;
private:
void SetNodeParent( gltfNode *node, gltfNode *parent = nullptr );
//void CreateBgfxData( );
void Parse_ASSET( idToken &token );
void Parse_CAMERAS( idToken &token );
void Parse_SCENE( idToken &token );
void Parse_SCENES( idToken &token );
void Parse_NODES( idToken &token );
void Parse_MATERIALS( idToken &token );
void Parse_MESHES( idToken &token );
void Parse_TEXTURES( idToken &token );
void Parse_IMAGES( idToken &token );
void Parse_ACCESSORS( idToken &token );
void Parse_BUFFERVIEWS( idToken &token );
void Parse_SAMPLERS( idToken &token );
void Parse_BUFFERS( idToken &token );
void Parse_ANIMATIONS( idToken &token );
void Parse_SKINS( idToken &token );
void Parse_EXTENSIONS( idToken &token );
void Parse_EXTENSIONS_USED( idToken &token );
void Parse_EXTENSIONS_REQUIRED( idToken &token );
gltfProperty ParseProp( idToken &token );
gltfProperty ResolveProp( idToken &token );
idLexer parser;
idToken token;
idStr currentFile;
bool buffersDone;
bool bufferViewsDone;
};
extern GLTF_Parser * gltfParser;

838
neo/idlib/gltfProperties.h Normal file
View file

@ -0,0 +1,838 @@
#pragma once
#include "containers/StrList.h"
#include <functional>
#include "math/Quat.h"
#include "Lib.h"
#include "containers/List.h"
enum gltfProperty {
INVALID,
ASSET,
ACCESSOR,
CAMERAS,
SCENE,
SCENES,
NODES,
MATERIALS,
MESHES,
TEXTURES,
IMAGES,
ACCESSORS,
BUFFERVIEWS,
SAMPLERS,
BUFFERS,
ANIMATIONS,
SKINS,
EXTENSIONS,
EXTENSIONS_USED,
EXTENSIONS_REQUIRED
};
class gltfData;
struct gltf_accessor_component
{
enum Type {
_byte,
_uByte,
_short,
_uShort,
_uInt,
_float,
_double,
Count
};
};
template< class T >
struct gltf_accessor_component_type_map {
idStr stringID;
int id;
T type;
uint sizeInBytes;//single element
};
class gltfExtra
{
public:
gltfExtra( ) { }
//entire extra json scope
idStr json;
//str:str pairs of each item
idDict strPairs;
//specialized parsers
idList<gltfExtra *> extras;
};
class gltfExt_KHR_lights_punctual;
class gltfExtensions {
public:
gltfExtensions( ) { }
idList<gltfExt_KHR_lights_punctual *> KHR_lights_punctual;
};
class gltfNode_KHR_lights_punctual {
public:
int light;
};
class gltfNode_Extensions {
public:
gltfNode_Extensions( ) :
KHR_lights_punctual( nullptr) { }
gltfNode_KHR_lights_punctual* KHR_lights_punctual;
};
class gltfExt_KHR_materials_pbrSpecularGlossiness;
class gltfMaterial_Extensions {
public:
gltfMaterial_Extensions( ) :
KHR_materials_pbrSpecularGlossiness( nullptr ) { }
gltfExt_KHR_materials_pbrSpecularGlossiness *KHR_materials_pbrSpecularGlossiness;
};
class gltfNode {
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 ) { }
int camera;
idList<int> children;
int skin;
idMat4 matrix;
int mesh;
idQuat rotation;
idVec3 scale;
idVec3 translation;
idList<double> weights;
idStr name;
gltfNode_Extensions extensions;
gltfExtra extras;
//
gltfNode * parent;
bool dirty;
};
struct gltfCameraNodePtrs {
gltfNode *translationNode = nullptr;
gltfNode *orientationNode = nullptr;
};
class gltfScene {
public:
gltfScene( ) { }
idList<int> nodes;
idStr name;
idStr extensions;
gltfExtra extras;
};
class gltfMesh_Primitive_Attribute {
public:
enum Type {
Position,
Normal,
Tangent,
TexCoord0,
TexCoord1,
TexCoord2,
TexCoord3,
TexCoord4,
TexCoord5,
TexCoord6,
TexCoord7,
Color0,
Color1,
Color2,
Color3,
Weight,
Indices,
Count
};
gltfMesh_Primitive_Attribute( ) : accessorIndex( -1 ), elementSize( 0 ), type( gltfMesh_Primitive_Attribute::Type::Count ){ }
idStr attributeSemantic;
int accessorIndex;
uint elementSize;
Type type;
};
struct gltf_mesh_attribute_map {
idStr stringID;
gltfMesh_Primitive_Attribute::Type attib;
uint elementSize;
};
class gltfMesh_Primitive {
public:
gltfMesh_Primitive( ) : indices( -1 ), material( -1 ), mode( -1 ) { }
idList<gltfMesh_Primitive_Attribute *> attributes;
int indices;
int material;
int mode;
idStr target;
idStr extensions;
gltfExtra extras;
};
class gltfMesh {
public:
gltfMesh( ) { };
idList<gltfMesh_Primitive *> primitives; // gltfMesh_Primitive[1,*]
idList<double> weights; // number[1,*]
idStr name;
idStr extensions;
gltfExtra extras;
};
class gltfCamera_Orthographic {
public:
gltfCamera_Orthographic( ) : xmag( 0.0f ), ymag( 0.0f ), zfar( 0.0f ), znear( 0.0f ) { };
float xmag;
float ymag;
float zfar;
float znear;
idStr extensions;
gltfExtra extras;
};
class gltfCamera_Perspective {
public:
gltfCamera_Perspective( ) : aspectRatio( 0.0f ), yfov( 0.0f ), zfar( 0.0f ), znear( 0.0f ) { };
float aspectRatio;
float yfov;
float zfar;
float znear;
idStr extensions;
gltfExtra extras;
};
class gltfCamera {
public:
gltfCamera( ) { };
gltfCamera_Orthographic orthographic;
gltfCamera_Perspective perspective;
idStr type;
idStr name;
idStr extensions;
gltfExtra extras;
};
class gltfAnimation_Channel_Target {
public:
gltfAnimation_Channel_Target( ) : node( -1 ), TRS( gltfTRS::count ) { };
int node;
idStr path;
idStr extensions;
gltfExtra extras;
enum gltfTRS {
none,
rotation,
translation,
scale,
weights,
count
};
gltfTRS TRS;
static gltfTRS resolveType( idStr type ) {
if ( type == "translation" )
return gltfTRS::translation;
else if ( type == "rotation" )
return gltfTRS::rotation;
else if ( type == "scale" )
return gltfTRS::scale;
else if ( type == "weights" )
return gltfTRS::weights;
return gltfTRS::count;
}
};
class gltfAnimation_Channel {
public:
gltfAnimation_Channel( ) : sampler( -1 ) { };
int sampler;
gltfAnimation_Channel_Target target;
idStr extensions;
gltfExtra extras;
};
class gltfAnimation_Sampler {
public:
gltfAnimation_Sampler( ) : input( -1 ), interpolation("LINEAR"),output( -1 ), intType(gltfInterpType::count) { };
int input;
idStr interpolation;
int output;
idStr extensions;
gltfExtra extras;
enum gltfInterpType {
linear,
step,
cubicSpline,
count
};
gltfInterpType intType;
static gltfInterpType resolveType( idStr type ) {
if ( type == "LINEAR" )
return gltfInterpType::linear;
else if ( type == "STEP" )
return gltfInterpType::step;
else if ( type == "CUBICSPLINE" )
return gltfInterpType::cubicSpline;
return gltfInterpType::count;
}
};
class gltfAnimation {
public:
gltfAnimation( ) : maxTime (0.0f),numFrames(0) { };
idList<gltfAnimation_Channel *> channels;
idList<gltfAnimation_Sampler *> samplers;
idStr name;
idStr extensions;
gltfExtra extras;
float maxTime;
//id specific
mutable int ref_count;
int numFrames;
void DecreaseRefs() const {ref_count--;};
void IncreaseRefs() const {ref_count++;};
bool GetBounds( idBounds &bnds, int time, int cyclecount ) const { return false;}
bool GetOriginRotation( idQuat &rotation, int time, int cyclecount ) const { return false;}
bool GetOrigin( idVec3 &offset, int time, int cyclecount ) const { return false;}
const idVec3 &TotalMovementDelta( void ) const {static idVec3 temp; return temp; }
int NumFrames() const {return numFrames;}
};
class gltfAccessor_Sparse_Values {
public:
gltfAccessor_Sparse_Values( ) : bufferView( -1 ), byteOffset( -1 ) { };
int bufferView;
int byteOffset;
idStr extensions;
gltfExtra extras;
};
class gltfAccessor_Sparse_Indices {
public:
gltfAccessor_Sparse_Indices( ) : bufferView( -1 ), byteOffset( -1 ), componentType( -1 ) { };
int bufferView;
int byteOffset;
int componentType;
idStr extensions;
gltfExtra extras;
};
class gltfAccessor_Sparse {
public:
gltfAccessor_Sparse( ) : count( -1 ) { };
int count;
gltfAccessor_Sparse_Indices indices;
gltfAccessor_Sparse_Values values;
idStr extensions;
gltfExtra extras;
};
class gltfAccessor {
public:
gltfAccessor( ) : bufferView( -1 ), byteOffset( 0 ), componentType( -1 ), normalized( false ), count( -1 ) ,
floatView(nullptr),vecView(nullptr),quatView(nullptr),matView(nullptr){ }
int bufferView;
int byteOffset;
int componentType;
bool normalized;
int count;
idStr type;
idList<double> max;
idList<double> min;
gltfAccessor_Sparse sparse;
idStr name;
idStr extensions;
gltfExtra extras;
uint typeSize;
idList<float> * floatView;
idList<idVec3*> * vecView;
idList<idQuat*> * quatView;
idList<idMat4> * matView;
};
class gltfBufferView {
public:
gltfBufferView( ) : buffer( -1 ), byteLength( -1 ), byteStride( 0 ), byteOffset( 0 ), target( -1 ) { };
int buffer;
int byteLength;
int byteStride;
int byteOffset;
int target;
idStr name;
idStr extensions;
gltfExtra extras;
//
gltfData *parent;
};
class gltfBuffer {
public:
gltfBuffer( ) : byteLength( -1 ), parent( nullptr ) { };
idStr uri;
int byteLength;
idStr name;
idStr extensions;
gltfExtra extras;
//
gltfData * parent;
};
class gltfSampler {
public:
gltfSampler( ) : magFilter( 0 ), minFilter( 0 ), wrapS( 10497 ), wrapT( 10497 ) { };
int magFilter;
int minFilter;
int wrapS;
int wrapT;
idStr name;
idStr extensions;
gltfExtra extras;
//
uint bgfxSamplerFlags;
};
class gltfImage {
public:
gltfImage( ) : bufferView( -1 ) { }
idStr uri;
idStr mimeType;
int bufferView;
idStr name;
idStr extensions;
gltfExtra extras;
};
class gltfSkin {
public:
gltfSkin( ) : inverseBindMatrices(-1),skeleton(-1),name("unnamedSkin"){ };
int inverseBindMatrices;
int skeleton;
idList<int> joints; // integer[1,*]
idStr name;
idStr extensions;
gltfExtra extras;
};
class gltfExt_KHR_texture_transform;
class gltfTexture_Info_Extensions {
public:
gltfTexture_Info_Extensions( ) :
KHR_texture_transform( nullptr ) { }
gltfExt_KHR_texture_transform *KHR_texture_transform;
};
class gltfOcclusionTexture_Info {
public:
gltfOcclusionTexture_Info( ) : index( -1 ), texCoord( 0 ), strength( 1.0f ) { }
int index;
int texCoord;
float strength;
gltfTexture_Info_Extensions extensions;
gltfExtra extras;
};
class gltfNormalTexture_Info {
public:
gltfNormalTexture_Info( ) : index( -1 ), texCoord( 0 ), scale( 1.0f ) { }
int index;
int texCoord;
float scale;
gltfTexture_Info_Extensions extensions;
gltfExtra extras;
};
class gltfTexture_Info {
public:
gltfTexture_Info( ) : index( -1 ), texCoord( 0 ) { }
int index;
int texCoord;
gltfTexture_Info_Extensions extensions;
gltfExtra extras;
};
class gltfTexture {
public:
gltfTexture( ) : sampler( -1 ), source( -1 ) { }
int sampler;
int source;
idStr name;
gltfTexture_Info_Extensions extensions;
gltfExtra extras;
};
class gltfMaterial_pbrMetallicRoughness {
public:
gltfMaterial_pbrMetallicRoughness( ) : baseColorFactor( vec4_one ), metallicFactor( 1.0f ), roughnessFactor( 1.0f ) { }
idVec4 baseColorFactor;
gltfTexture_Info baseColorTexture;
float metallicFactor;
float roughnessFactor;
gltfTexture_Info metallicRoughnessTexture;
idStr extensions;
gltfExtra extras;
};
class gltfMaterial {
public:
enum gltfAlphaMode {
gltfOPAQUE,
gltfMASK,
gltfBLEND,
count
};
gltfMaterial( ) : emissiveFactor( vec3_zero ), alphaMode( "OPAQUE" ), alphaCutoff( 0.5f ), doubleSided( false ) { }
gltfMaterial_pbrMetallicRoughness pbrMetallicRoughness;
gltfNormalTexture_Info normalTexture;
gltfOcclusionTexture_Info occlusionTexture;
gltfTexture_Info emissiveTexture;
idVec3 emissiveFactor;
idStr alphaMode;
float alphaCutoff;
bool doubleSided;
idStr name;
gltfMaterial_Extensions extensions;
gltfExtra extras;
gltfAlphaMode intType;
static gltfAlphaMode resolveAlphaMode( idStr type ) {
if ( type == "OPAQUE" )
return gltfAlphaMode::gltfOPAQUE;
else if ( type == "MASK" )
return gltfAlphaMode::gltfMASK;
else if ( type == "BLEND" )
return gltfAlphaMode::gltfBLEND;
return gltfAlphaMode::count;
}
};
class gltfAsset {
public:
gltfAsset( ) { }
idStr copyright;
idStr generator;
idStr version;
idStr minVersion;
idStr extensions;
gltfExtra extras;
};
//this is not used.
//if an extension is found, it _will_ be used. (if implemented)
class gltfExtensionsUsed {
public:
gltfExtensionsUsed( ) { }
idStr extension;
};
//ARCHIVED?
//https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness
class gltfExt_KHR_materials_pbrSpecularGlossiness
{
public:
gltfExt_KHR_materials_pbrSpecularGlossiness( ) { }
idVec4 diffuseFactor;
gltfTexture_Info diffuseTexture;
idVec3 specularFactor;
float glossinessFactor;
gltfTexture_Info specularGlossinessTexture;
idStr extensions;
gltfExtra extras;
};
//KHR_lights_punctual_spot
//https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/schema/light.spot.schema.json
class gltfExt_KHR_lights_punctual_spot {
public:
gltfExt_KHR_lights_punctual_spot( ) : innerConeAngle(0.0f), outerConeAngle( idMath::ONEFOURTH_PI ){ }
float innerConeAngle;
float outerConeAngle;
idStr extensions;
gltfExtra extras;
};
typedef gltfExt_KHR_lights_punctual_spot spot;
//KHR_lights_punctual
//https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/schema/light.schema.json
class gltfExt_KHR_lights_punctual {
public:
gltfExt_KHR_lights_punctual( ) : color(vec3_one),intensity(1.0f),range(-1.0f),intType(-1) { }
idVec3 color;
float intensity;
spot spot;
idStr type; //directional=0,point=1,spot=2
float range;
idStr name;
idStr extensions;
gltfExtra extras;
int intType;
static int resolveType( idStr type ) {
if (type == "directional" )
return 0;
else if (type == "point" )
return 1;
else if (type == "spot" )
return 2;
return -1;
}
};
//KHR_texture_transform
//https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_transform/schema/KHR_texture_transform.textureInfo.schema.json
class gltfExt_KHR_texture_transform {
public:
gltfExt_KHR_texture_transform( ) : offset( vec2_zero ), rotation( 0.0f ), scale( vec2_one ), texCoord( -1 ),index(0),resolved(false) { }
idVec2 offset;
float rotation;
idVec2 scale;
int texCoord;
idStr extensions;
gltfExtra extras;
//for shader
uint index;
bool resolved;
};
/////////////////////////////////////////////////////////////////////////////
//// For these to function you need to add an private idList<gltf{name}*> {target}
#define GLTFCACHEITEM(name,target) \
gltf##name * name ( ) { target.AssureSizeAlloc( target.Num()+1,idListNewElement<gltf##name>); return target[target.Num()-1];} \
const inline idList<gltf##name*> & ##name##List() { return target; }
// URI's are resolved during parsing so that
// all data should be layed out like an GLB with multiple bin chunks
// EACH URI will have an unique chunk
// JSON chunk MUST be the first one to be allocated/added
class gltfData {
public:
gltfData( ) : fileNameHash( 0 ), json( nullptr ), data( nullptr ), totalChunks( -1 ) { };
~gltfData( );
byte *AddData( int size, int *bufferID = nullptr );
byte *GetJsonData( int &size ) { size = jsonDataLength; return json; }
byte *GetData( int index ) { return data[index]; }
void FileName( const idStr &file ) { fileName = file; fileNameHash = fileDataHash.GenerateKey( file.c_str( ) ); }
int FileNameHash( ) { return fileNameHash; }
idStr &FileName( ) { return fileName; }
static idHashIndex fileDataHash;
static idList<gltfData *> dataList;
//add data from filename
static gltfData *Data( idStr &fileName ) {
dataList.AssureSizeAlloc( dataList.Num( ) + 1, idListNewElement<gltfData> );
dataList[dataList.Num( ) - 1]->FileName( fileName );
fileDataHash.Add( fileDataHash.GenerateKey( fileName ), dataList.Num( ) - 1 );
return dataList[dataList.Num( ) - 1];
}
//find data;
static gltfData *Data( const char *filename ) { return dataList[fileDataHash.First( fileDataHash.GenerateKey( filename ) )]; }
static const idList<gltfData *> &DataList( ) { return dataList; }
static void ClearData( ) { idLib::Warning( "TODO! DATA NOT FREED" ); }
//return the GLTF nodes that control the given camera
//return TRUE if the camera uses 2 nodes (like when blender exports gltfs with +Y..)
//This is determined by checking for an "_Orientation" suffix to the camera name of the node that has the target camera assigned.
// if so, translate node will be set to the parent node of the orientation node.
//Note: does not take overides into account!
gltfNode* GetCameraNodes( gltfCamera *camera )
{
gltfCameraNodePtrs result;
assert( camera );
int camId = -1;
for ( auto *cam : cameras )
{
camId++;
if ( cam == camera )
break;
}
for ( int i = 0; i < nodes.Num( ); i++ )
{
if ( nodes[i]->camera != -1 && nodes[i]->camera == camId )
return nodes[i];
}
return nullptr;
}
idMat4 GetViewMatrix( int camId ) const
{
//if (cameraManager->HasOverideID(camId) )
//{
// auto overrideCam = cameraManager->GetOverride( camId );
// camId = overrideCam.newCameraID;
//}
idMat4 result = mat4_identity;
idList<gltfNode*> hierachy(2);
gltfNode* parent = nullptr;
for ( int i = 0; i < nodes.Num( ); i++ )
{
if ( nodes[i]->camera != -1 && nodes[i]->camera == camId )
{
parent = nodes[i];
while ( parent ) {
hierachy.Append( parent );
parent = parent->parent;
}
break;
}
}
for ( int i = hierachy.Num( ) - 1; i >= 0; i-- )
{
ResolveNodeMatrix(hierachy[i]);
result *= hierachy[i]->matrix;
}
return result;
}
//Please note : assumes all nodes are _not_ dirty!
idMat4 GetLightMatrix( int lightId ) const
{
idMat4 result = mat4_identity;
idList<gltfNode *> hierachy;
gltfNode *parent = nullptr;
hierachy.SetGranularity( 2 );
for ( int i = 0; i < nodes.Num( ); i++ ) {
if ( nodes[i]->extensions.KHR_lights_punctual && nodes[i]->extensions.KHR_lights_punctual->light == lightId ) {
parent = nodes[i];
while ( parent ) {
hierachy.Append( parent );
parent = parent->parent;
}
break;
}
}
for ( int i = hierachy.Num( ) - 1; i >= 0; i-- )
result *= hierachy[i]->matrix;
return result;
}
// v * T * R * S. ->row major
// v' = S * R * T * v -> column major;
//bgfx = column-major
//idmath = row major, except mat3
//gltf matrices : column-major.
//if mat* is valid , it will be multplied by this node's matrix that is resolved in its full hiararchy and stops at root.
static void ResolveNodeMatrix( gltfNode *node, idMat4 *mat = nullptr ,gltfNode *root = nullptr )
{
if ( node->dirty )
{
idMat4 scaleMat = idMat4(
node->scale.x, 0, 0, 0,
0, node->scale.y, 0, 0,
0, 0, node->scale.z, 0,
0, 0, 0, 1
);
node->matrix = idMat4( mat3_identity, node->translation ) * node->rotation.ToMat4( ).Transpose( ) * scaleMat;
node->dirty = false;
}
//resolve full hierarchy
if ( mat != nullptr ) {
idList<gltfNode *> hierachy(2);
gltfNode *parent = node;
while ( parent ) {
ResolveNodeMatrix(parent);
hierachy.Append( parent );
if ( parent == root )
break;
parent = parent->parent;
}
for ( int i = hierachy.Num( ) - 1; i >= 0; i-- )
*mat *= hierachy[i]->matrix;
}
}
void Advance( gltfAnimation *anim = nullptr );
//this copies the data and view cached on the accessor
template <class T>
idList<T*> &GetAccessorView( gltfAccessor *accessor );
idList<float> &GetAccessorView( gltfAccessor *accessor );
idList<idMat4> &GetAccessorViewMat( gltfAccessor *accessor );
int &DefaultScene( ) { return scene; }
GLTFCACHEITEM( Buffer, buffers )
GLTFCACHEITEM( Sampler, samplers )
GLTFCACHEITEM( BufferView, bufferViews )
GLTFCACHEITEM( Image, images )
GLTFCACHEITEM( Texture, textures )
GLTFCACHEITEM( Accessor, accessors )
GLTFCACHEITEM( ExtensionsUsed, extensionsUsed )
GLTFCACHEITEM( Mesh, meshes )
GLTFCACHEITEM( Scene, scenes )
GLTFCACHEITEM( Node, nodes )
GLTFCACHEITEM( Camera, cameras )
GLTFCACHEITEM( Material, materials )
GLTFCACHEITEM( Extensions, extensions )
GLTFCACHEITEM( Animation, animations )
GLTFCACHEITEM( Skin, skins )
//gltfCameraManager * cameraManager;
private:
idStr fileName;
int fileNameHash;
byte *json;
byte **data;
int jsonDataLength;
int totalChunks;
idList<gltfBuffer *> buffers;
idList<gltfImage *> images;
idList<gltfData *> assetData;
idList<gltfSampler *> samplers;
idList<gltfBufferView *> bufferViews;
idList<gltfTexture *> textures;
idList<gltfAccessor *> accessors;
idList<gltfExtensionsUsed *> extensionsUsed;
idList<gltfMesh *> meshes;
int scene;
idList<gltfScene *> scenes;
idList<gltfNode *> nodes;
idList<gltfCamera *> cameras;
idList<gltfMaterial *> materials;
idList<gltfExtensions *> extensions;
idList<gltfAnimation *> animations;
idList<gltfSkin *> skins;
};
#undef GLTFCACHEITEM

View file

@ -30,6 +30,10 @@ If you have questions concerning this license or the applicable additional terms
#include "precompiled.h"
#pragma hdrstop
idVec2 vec2_one( 1.0f, 1.0f );
idVec3 vec3_one( 1.0f, 1.0f, 1.0f );
idVec4 vec4_one( 1.0f, 1.0f, 1.0f, 1.0f );
idVec2 vec2_origin( 0.0f, 0.0f );
idVec3 vec3_origin( 0.0f, 0.0f, 0.0f );
idVec4 vec4_origin( 0.0f, 0.0f, 0.0f, 0.0f );

View file

@ -109,6 +109,7 @@ public:
extern idVec2 vec2_origin;
#define vec2_zero vec2_origin
extern idVec2 vec2_one;
ID_INLINE idVec2::idVec2()
{
@ -463,6 +464,7 @@ public:
extern idVec3 vec3_origin;
#define vec3_zero vec3_origin
extern idVec3 vec3_one;
ID_INLINE idVec3::idVec3()
{
@ -1066,6 +1068,7 @@ public:
extern idVec4 vec4_origin;
#define vec4_zero vec4_origin
extern idVec4 vec4_one;
ID_INLINE void idVec4::Set( const float x, const float y, const float z, const float w )
{

View file

@ -46,6 +46,9 @@ If you have questions concerning this license or the applicable additional terms
// id lib
#include "../idlib/Lib.h"
#include "../idlib/gltfProperties.h"
#include "../idlib/gltfParser.h"
#include "sys/sys_filesystem.h"

View file

@ -85,6 +85,7 @@ MEM_TAG( IDLIB_SURFACE )
MEM_TAG( IDLIB_WINDING )
MEM_TAG( IDLIB_LEXER )
MEM_TAG( IDLIB_PARSER )
MEM_TAG( IDLIB_GLTF )
MEM_TAG( AF )
MEM_TAG( COLLISION )
MEM_TAG( COLLISION_QUERY )

View file

@ -29,7 +29,7 @@ If you have questions concerning this license or the applicable additional terms
#include "precompiled.h"
#pragma hdrstop
#include "Model_gltf.h"
#include "Model_local.h"
#include "RenderCommon.h" // just for R_FreeWorldInteractions and R_CreateWorldInteractions
@ -356,9 +356,15 @@ 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 ))
{
model = new( TAG_MODEL ) idRenderModelGLTF;
// RB: Collada DAE and Wavefront OBJ
if( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "obj" ) == 0 ) || ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 ) || ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) )
}else if ( ( extension.Icmp( "dae" ) == 0 ) || ( extension.Icmp( "obj" ) == 0 ) // RB: Collada DAE and Wavefront OBJ
|| ( extension.Icmp( "ase" ) == 0 ) || ( extension.Icmp( "lwo" ) == 0 )
|| ( extension.Icmp( "flt" ) == 0 ) || ( extension.Icmp( "ma" ) == 0 ) )
{
model = new( TAG_MODEL ) idRenderModelStatic;
}