mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-24 12:51:46 +00:00
Potentially support a highly-compressed variety of gltf2 files... but needs third party library so will probably remain permanently disabled at compiletime.
This commit is contained in:
parent
8066f712e0
commit
a7a620f690
3 changed files with 421 additions and 41 deletions
|
@ -845,6 +845,27 @@ SET(FTE_Q3_FILES
|
||||||
plugins/quake3/q3g_public.h
|
plugins/quake3/q3g_public.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#For annoying compressed gltf2 files.
|
||||||
|
SET(FTE_DEP_DRACO false CACHE BOOL "Link against libdraco.")
|
||||||
|
IF(FTE_DEP_DRACO)
|
||||||
|
FIND_LIBRARY(
|
||||||
|
DRACO_LIBRARY
|
||||||
|
NAMES draco
|
||||||
|
)
|
||||||
|
IF(DRACO_LIBRARY)
|
||||||
|
SET(DRACO_FILES plugins/models/draco.cpp)
|
||||||
|
SET(DRACO_CFLAGS HAVE_DRACO)
|
||||||
|
|
||||||
|
SET(FTE_COMMON_FILES ${FTE_COMMON_FILES} ${DRACO_FILES})
|
||||||
|
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};${DRACO_CFLAGS})
|
||||||
|
SET(FTE_LIBS ${FTE_LIBS} ${DRACO_LIBRARY})
|
||||||
|
SET(FTESV_LIBS ${FTESV_LIBS} ${DRACO_LIBRARY})
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(WARNING "draco library not found, needed for GLTF's KHR_draco_mesh_compression to be usable.")
|
||||||
|
ENDIF()
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
|
||||||
SET(FTE_PLUG_QUAKE3 true CACHE BOOL "Compile Quake3 plugin.")
|
SET(FTE_PLUG_QUAKE3 true CACHE BOOL "Compile Quake3 plugin.")
|
||||||
IF(FTE_PLUG_QUAKE3)
|
IF(FTE_PLUG_QUAKE3)
|
||||||
IF (0)
|
IF (0)
|
||||||
|
@ -912,7 +933,7 @@ IF(FTE_PLUG_ODE)
|
||||||
#SET (FTE_COMMON_FILES ${FTE_COMMON_FILES} engine/common/com_phys_ode.c)
|
#SET (FTE_COMMON_FILES ${FTE_COMMON_FILES} engine/common/com_phys_ode.c)
|
||||||
SET(FTE_LIB_DEFINES "${FTE_LIB_DEFINES};USE_INTERNAL_ODE;ODE_STATIC")
|
SET(FTE_LIB_DEFINES "${FTE_LIB_DEFINES};USE_INTERNAL_ODE;ODE_STATIC")
|
||||||
SET(FTE_LIBS ${FTE_LIBS} ${LIBODE_LIBRARY})
|
SET(FTE_LIBS ${FTE_LIBS} ${LIBODE_LIBRARY})
|
||||||
SET(FTESV_LIBS ${FTE_LIBS} ${LIBODE_LIBRARY})
|
SET(FTESV_LIBS ${FTESV_LIBS} ${LIBODE_LIBRARY})
|
||||||
SET(FTE_INCLUDES ${FTE_INCLUDES} ${ODE_INCLUDE_DIRS})
|
SET(FTE_INCLUDES ${FTE_INCLUDES} ${ODE_INCLUDE_DIRS})
|
||||||
ELSE()
|
ELSE()
|
||||||
ADD_LIBRARY(plug_ode MODULE
|
ADD_LIBRARY(plug_ode MODULE
|
||||||
|
@ -1009,13 +1030,14 @@ ELSE()
|
||||||
ADD_EXECUTABLE(iqmtool
|
ADD_EXECUTABLE(iqmtool
|
||||||
iqm/iqm.cpp
|
iqm/iqm.cpp
|
||||||
plugins/models/gltf.c
|
plugins/models/gltf.c
|
||||||
|
${DRACO_FILES}
|
||||||
engine/common/json.c
|
engine/common/json.c
|
||||||
engine/client/image.c
|
engine/client/image.c
|
||||||
imgtool.c
|
imgtool.c
|
||||||
iqm/iqm.h
|
iqm/iqm.h
|
||||||
)
|
)
|
||||||
SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${FTE_REVISON}")
|
SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${DRACO_CFLAGS};${FTE_REVISON}")
|
||||||
TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS})
|
TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS} ${DRACO_LIBRARY})
|
||||||
SET(INSTALLTARGS ${INSTALLTARGS} iqmtool)
|
SET(INSTALLTARGS ${INSTALLTARGS} iqmtool)
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
@ -1362,11 +1384,12 @@ IF(FTE_PLUG_MODELS)
|
||||||
plugins/plugin.c
|
plugins/plugin.c
|
||||||
plugins/models/models.c
|
plugins/models/models.c
|
||||||
plugins/models/gltf.c
|
plugins/models/gltf.c
|
||||||
|
${DRACO_FILES}
|
||||||
engine/common/json.c
|
engine/common/json.c
|
||||||
plugins/models/exportiqm.c
|
plugins/models/exportiqm.c
|
||||||
)
|
)
|
||||||
SET_TARGET_PROPERTIES(plug_models PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
|
SET_TARGET_PROPERTIES(plug_models PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${DRACO_CFLAGS};${FTE_LIB_DEFINES}")
|
||||||
TARGET_LINK_LIBRARIES(plug_models ${SYS_LIBS})
|
TARGET_LINK_LIBRARIES(plug_models ${SYS_LIBS} ${DRACO_LIBRARY})
|
||||||
|
|
||||||
EMBED_PLUGIN_META(models "Models Plugin" "Kinda redundant now that the engine has gltf2 loading.")
|
EMBED_PLUGIN_META(models "Models Plugin" "Kinda redundant now that the engine has gltf2 loading.")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
137
plugins/models/draco.cpp
Normal file
137
plugins/models/draco.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//I fucking hate c++
|
||||||
|
typedef struct ftedracofuncs_s
|
||||||
|
{
|
||||||
|
void (*Release)(struct ftedracofuncs_s *ctx); //frees all memory
|
||||||
|
|
||||||
|
struct ftedracoattr_s
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
int isnormalised;
|
||||||
|
unsigned int type; //gl constants, because why not
|
||||||
|
unsigned int components; //1-4
|
||||||
|
unsigned int bytestride;
|
||||||
|
unsigned int usage; //typical usage type.
|
||||||
|
unsigned int uniqueid; //annoying extra lookup.
|
||||||
|
} *attrib;
|
||||||
|
unsigned int num_attribs;
|
||||||
|
|
||||||
|
//mesh data
|
||||||
|
char triangleloop;
|
||||||
|
unsigned int num_indexes;
|
||||||
|
unsigned int *ptr_indexes, num_vertexes;
|
||||||
|
} ftedracofuncs_t;
|
||||||
|
|
||||||
|
ftedracofuncs_t *Draco_Decode(void *ptr, size_t size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DRACO_API_ONLY) && defined(HAVE_DRACO)
|
||||||
|
#include <draco/compression/decode.h>
|
||||||
|
|
||||||
|
struct dracofuncs_t : public ftedracofuncs_s
|
||||||
|
{
|
||||||
|
draco::Decoder decoder;
|
||||||
|
draco::DecoderBuffer buffer;
|
||||||
|
draco::Mesh mesh;
|
||||||
|
|
||||||
|
static void DoRelease(ftedracofuncs_s *ctx)
|
||||||
|
{
|
||||||
|
auto d = reinterpret_cast<dracofuncs_t*>(ctx);
|
||||||
|
delete[] d->ptr_indexes;
|
||||||
|
for (auto i = d->num_attribs; i --> 0; )
|
||||||
|
delete[] (char*)d->attrib[i].ptr;
|
||||||
|
delete[] d->attrib;
|
||||||
|
delete d; //do all the third-party destructor stuff too.
|
||||||
|
}
|
||||||
|
dracofuncs_t()
|
||||||
|
{
|
||||||
|
Release = DoRelease;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <class attrtype, int gltype>
|
||||||
|
static void CopyAttribute(unsigned int numpoints, draco::PointAttribute *attr, ftedracofuncs_s::ftedracoattr_s *oattr)
|
||||||
|
{
|
||||||
|
auto nc = oattr->components;
|
||||||
|
auto *out = new attrtype[numpoints*nc];
|
||||||
|
for (size_t i = 0; i < numpoints; i++)
|
||||||
|
attr->GetMappedValue(draco::PointIndex(i), &out[i*nc]);
|
||||||
|
|
||||||
|
oattr->bytestride = sizeof(attrtype)*nc; //the output data is tightly packed.
|
||||||
|
oattr->ptr = out;
|
||||||
|
oattr->type = gltype;
|
||||||
|
};
|
||||||
|
ftedracofuncs_t *Draco_Decode(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
size_t tris;
|
||||||
|
dracofuncs_t *d = new dracofuncs_t();
|
||||||
|
|
||||||
|
d->buffer.Init((const char *)ptr, size);
|
||||||
|
if (!d->decoder.DecodeBufferToGeometry(&d->buffer, &d->mesh).ok())
|
||||||
|
{ //check for corruption...
|
||||||
|
delete d;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tris = d->mesh.num_faces();
|
||||||
|
d->num_indexes = tris*3;
|
||||||
|
d->ptr_indexes = new unsigned int[d->num_indexes];
|
||||||
|
while (tris --> 0)
|
||||||
|
{
|
||||||
|
auto &tri = d->mesh.face(draco::FaceIndex(tris));
|
||||||
|
d->ptr_indexes[tris*3+0] = tri[0].value();
|
||||||
|
d->ptr_indexes[tris*3+1] = tri[1].value();
|
||||||
|
d->ptr_indexes[tris*3+2] = tri[2].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
d->num_vertexes = d->mesh.num_points();
|
||||||
|
d->num_attribs = d->mesh.num_attributes();
|
||||||
|
d->attrib = new struct ftedracofuncs_s::ftedracoattr_s[d->num_attribs];
|
||||||
|
for (unsigned int i = 0; i < d->num_attribs; i++)
|
||||||
|
{
|
||||||
|
draco::PointAttribute *attr = d->mesh.attribute(i);
|
||||||
|
auto oattr = &d->attrib[i];
|
||||||
|
oattr->isnormalised = attr->normalized();
|
||||||
|
oattr->bytestride = attr->byte_stride();
|
||||||
|
oattr->components = attr->num_components();
|
||||||
|
oattr->usage = attr->attribute_type();
|
||||||
|
oattr->uniqueid = attr->unique_id();
|
||||||
|
#define GL_BYTE 0x1400
|
||||||
|
#define GL_UNSIGNED_BYTE 0x1401
|
||||||
|
#define GL_SHORT 0x1402
|
||||||
|
#define GL_UNSIGNED_SHORT 0x1403
|
||||||
|
#define GL_INT 0x1404
|
||||||
|
#define GL_UNSIGNED_INT 0x1405
|
||||||
|
#define GL_FLOAT 0x1406
|
||||||
|
#define GL_DOUBLE 0x140A
|
||||||
|
#define GL_INT64_ARB 0x140E
|
||||||
|
#define GL_UNSIGNED_INT64_ARB 0x140F
|
||||||
|
|
||||||
|
switch(attr->data_type())
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
memset(oattr, 0, sizeof(*oattr));
|
||||||
|
break;
|
||||||
|
case draco::DataType::DT_INT8: CopyAttribute< int8_t, GL_BYTE >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_UINT8: CopyAttribute<uint8_t, GL_UNSIGNED_BYTE >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_INT16: CopyAttribute< int16_t, GL_SHORT >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_UINT16: CopyAttribute<uint16_t, GL_UNSIGNED_SHORT >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_INT32: CopyAttribute< int32_t, GL_INT >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_UINT32: CopyAttribute<uint32_t, GL_UNSIGNED_INT >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_INT64: CopyAttribute< int64_t, GL_INT64_ARB >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_UINT64: CopyAttribute<uint64_t, GL_UNSIGNED_INT64_ARB >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_FLOAT32: CopyAttribute<float, GL_FLOAT >(d->num_vertexes, attr, oattr); break;
|
||||||
|
case draco::DataType::DT_FLOAT64: CopyAttribute<double, GL_DOUBLE >(d->num_vertexes, attr, oattr); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -518,6 +518,13 @@ static qboolean GLTF_GetAccessor(gltf_t *gltf, json_t *accessorid, struct gltf_a
|
||||||
offset = JSON_GetUInteger(a, "byteOffset", 0);
|
offset = JSON_GetUInteger(a, "byteOffset", 0);
|
||||||
if (offset > bv.length)
|
if (offset > bv.length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (JSON_FindChild(a, "sparse"))
|
||||||
|
{ //0-initialised, with separate index+values tables for ones that need an actual value.
|
||||||
|
if (gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING"%s: sparse accessors are not supported\n", gltf->mod->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
out->length = bv.length - offset;
|
out->length = bv.length - offset;
|
||||||
if (gltf->ver <= 1)
|
if (gltf->ver <= 1)
|
||||||
out->bytestride = JSON_GetInteger(a, "byteStride", 0);
|
out->bytestride = JSON_GetInteger(a, "byteStride", 0);
|
||||||
|
@ -578,7 +585,6 @@ static qboolean GLTF_GetAccessor(gltf_t *gltf, json_t *accessorid, struct gltf_a
|
||||||
out->maxs[j] = JSON_GetIndexedFloat(maxs, j, 0);
|
out->maxs[j] = JSON_GetIndexedFloat(maxs, j, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON_WarnIfChild(a, "sparse");
|
|
||||||
// JSON_WarnIfChild(a, "name");
|
// JSON_WarnIfChild(a, "name");
|
||||||
GLTF_FlagExtras(a);
|
GLTF_FlagExtras(a);
|
||||||
|
|
||||||
|
@ -1749,6 +1755,8 @@ static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *re
|
||||||
ret->frame->texnums.base = GLTF_LoadTexture(gltf, albedo, 0);
|
ret->frame->texnums.base = GLTF_LoadTexture(gltf, albedo, 0);
|
||||||
if (mrt)
|
if (mrt)
|
||||||
ret->frame->texnums.specular = GLTF_LoadTexture(gltf, mrt, IF_NOSRGB);
|
ret->frame->texnums.specular = GLTF_LoadTexture(gltf, mrt, IF_NOSRGB);
|
||||||
|
else //else depend upon specularfactor
|
||||||
|
ret->frame->texnums.specular = modfuncs->GetTexture("$whiteimage", NULL, IF_NOMIPMAP|IF_NOPICMIP|IF_NEAREST|IF_NOGAMMA, NULL, NULL, 0, 0, TF_INVALID);
|
||||||
|
|
||||||
Q_snprintf(shader, sizeof(shader),
|
Q_snprintf(shader, sizeof(shader),
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -1795,13 +1803,164 @@ static void GLTF_LoadMaterial(gltf_t *gltf, json_t *materialid, galiasskin_t *re
|
||||||
Q_strlcpy(ret->name, ret->frame->shadername, sizeof(ret->name));
|
Q_strlcpy(ret->name, ret->frame->shadername, sizeof(ret->name));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_DRACO
|
||||||
|
#define DRACO_API_ONLY
|
||||||
|
#include "draco.cpp"
|
||||||
|
#endif
|
||||||
|
typedef struct {
|
||||||
|
gltf_t *gltf;
|
||||||
|
json_t *prim;
|
||||||
|
json_t *primattrs;
|
||||||
|
#ifdef HAVE_DRACO
|
||||||
|
json_t *dracoattrs;
|
||||||
|
struct ftedracofuncs_s *draco;
|
||||||
|
#endif
|
||||||
|
} gltf_prim_t;
|
||||||
|
static qboolean GLTF_GetAttributeAccessor(gltf_prim_t *state, char *attributename, struct gltf_accessor *out)
|
||||||
|
{
|
||||||
|
json_t *primaccessor = JSON_FindChild(state->primattrs, attributename);
|
||||||
|
#ifdef HAVE_DRACO
|
||||||
|
if (state->draco && primaccessor)
|
||||||
|
{
|
||||||
|
json_t *da = JSON_FindChild(state->dracoattrs, attributename);
|
||||||
|
if (da)
|
||||||
|
{ //comes from compressed data instead.
|
||||||
|
//we're still meant to require some attributes match the original accessors.
|
||||||
|
struct ftedracoattr_s *dattr;
|
||||||
|
json_t *a, *mins, *maxs;
|
||||||
|
unsigned int j, attridx;
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
|
||||||
|
if (!strcmp(attributename, "NORMAL") || !strcmp(attributename, "TANGENT"))
|
||||||
|
return false; //these come out shite. don't use.
|
||||||
|
|
||||||
|
a = GLTF_FindJSONID(state->gltf, "accessors", primaccessor, NULL);
|
||||||
|
if (!a)
|
||||||
|
return false;
|
||||||
|
j = JSON_GetInteger(da, NULL, -1);
|
||||||
|
for (attridx = 0; attridx < state->draco->num_attribs; attridx++)
|
||||||
|
if (state->draco->attrib[attridx].uniqueid == j)
|
||||||
|
break;
|
||||||
|
if (attridx >= state->draco->num_attribs)
|
||||||
|
{
|
||||||
|
if (state->gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING"%s: draco lacks specified uniqueid %i\n", state->gltf->mod->name, j);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSON_FlagAsUsed(a, "name");
|
||||||
|
|
||||||
|
out->bytestride = 0; //
|
||||||
|
out->componentType = JSON_GetInteger(a, "componentType", 0);
|
||||||
|
out->normalized = JSON_GetInteger(a, "normalized", false);
|
||||||
|
out->count = JSON_GetInteger(a, "count", 0);
|
||||||
|
if (JSON_Equals(a, "type", "SCALAR"))
|
||||||
|
out->type = (1<<8) | 1;
|
||||||
|
else if (JSON_Equals(a, "type", "VEC2"))
|
||||||
|
out->type = (1<<8) | 2;
|
||||||
|
else if (JSON_Equals(a, "type", "VEC3"))
|
||||||
|
out->type = (1<<8) | 3;
|
||||||
|
else if (JSON_Equals(a, "type", "VEC4"))
|
||||||
|
out->type = (1<<8) | 4;
|
||||||
|
else if (JSON_Equals(a, "type", "MAT2"))
|
||||||
|
out->type = (2<<8) | 2;
|
||||||
|
else if (JSON_Equals(a, "type", "MAT3"))
|
||||||
|
out->type = (3<<8) | 3;
|
||||||
|
else if (JSON_Equals(a, "type", "MAT4"))
|
||||||
|
out->type = (4<<8) | 4;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (state->gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING"%s: glTF2 unsupported type\n", state->gltf->mod->name);
|
||||||
|
out->type = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out->bytestride)
|
||||||
|
{
|
||||||
|
out->bytestride = (out->type & 0xff) * (out->type>>8);
|
||||||
|
switch(out->componentType)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if (state->gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING"GLTF_GetAccessor: %s: glTF2 unsupported componentType (%i)\n", state->gltf->mod->name, out->componentType);
|
||||||
|
case 5120: //BYTE
|
||||||
|
case 5121: //UNSIGNED_BYTE
|
||||||
|
break;
|
||||||
|
case 5122: //SHORT
|
||||||
|
case 5123: //UNSIGNED_SHORT
|
||||||
|
out->bytestride *= 2;
|
||||||
|
break;
|
||||||
|
case 5125: //UNSIGNED_INT
|
||||||
|
case 5126: //FLOAT
|
||||||
|
out->bytestride *= 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mins = JSON_FindChild(a, "min");
|
||||||
|
maxs = JSON_FindChild(a, "max");
|
||||||
|
for (j = 0; j < (out->type>>8)*(out->type&0xff); j++)
|
||||||
|
{ //'must' be set in various situations.
|
||||||
|
out->mins[j] = JSON_GetIndexedFloat(mins, j, 0);
|
||||||
|
out->maxs[j] = JSON_GetIndexedFloat(maxs, j, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTF_FlagExtras(a);
|
||||||
|
|
||||||
|
dattr = &state->draco->attrib[attridx];
|
||||||
|
|
||||||
|
if (out->count < state->draco->num_vertexes)
|
||||||
|
out->count = state->draco->num_vertexes; //hack. seems to be needed for one of our test models.
|
||||||
|
if (out->count != state->draco->num_vertexes ||
|
||||||
|
!out->normalized != !dattr->isnormalised ||
|
||||||
|
out->componentType != dattr->type ||
|
||||||
|
out->type != ((1<<8)|dattr->components) ||
|
||||||
|
out->bytestride != dattr->bytestride)
|
||||||
|
{
|
||||||
|
if (state->gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING"%s: %s (%i) draco/accessor mismatch\n", state->gltf->mod->name, attributename, dattr->usage);
|
||||||
|
memset(out, 0, sizeof(*out)); //abort! abort!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->data = dattr->ptr;
|
||||||
|
out->length = out->bytestride*out->count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return GLTF_GetAccessor(state->gltf, primaccessor, out);
|
||||||
|
}
|
||||||
|
static void GLTF_GetIndiciesAccessor(gltf_prim_t *state, struct gltf_accessor *out)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DRACO
|
||||||
|
if (state->draco)
|
||||||
|
{
|
||||||
|
memset(out->mins, 0, sizeof(out->mins));
|
||||||
|
memset(out->maxs, 0, sizeof(out->maxs));
|
||||||
|
out->componentType = 5125; //unsigned int
|
||||||
|
out->normalized = false;
|
||||||
|
out->type = (1<<8) | 1; //'scaler'
|
||||||
|
out->bytestride = sizeof(*state->draco->ptr_indexes);
|
||||||
|
|
||||||
|
out->count = state->draco->num_indexes;
|
||||||
|
out->data = state->draco->ptr_indexes;
|
||||||
|
out->length = out->bytestride*out->count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
GLTF_GetAccessor(state->gltf, JSON_FindChild(state->prim, "indices"), out);
|
||||||
|
}
|
||||||
|
|
||||||
static const float *QDECL GLTF_AnimateMorphs(const galiasinfo_t *surf, const framestate_t *framestate);
|
static const float *QDECL GLTF_AnimateMorphs(const galiasinfo_t *surf, const framestate_t *framestate);
|
||||||
static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, double skinmatrix[])
|
static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, double skinmatrix[])
|
||||||
{
|
{
|
||||||
model_t *mod = gltf->mod;
|
model_t *mod = gltf->mod;
|
||||||
quintptr_t meshidx;
|
quintptr_t meshidx;
|
||||||
json_t *mesh = GLTF_FindJSONID(gltf, "meshes", meshid, &meshidx);
|
json_t *mesh = GLTF_FindJSONID(gltf, "meshes", meshid, &meshidx);
|
||||||
json_t *prim;
|
json_t *primnode;
|
||||||
json_t *meshname = JSON_FindChild(mesh, "name");
|
json_t *meshname = JSON_FindChild(mesh, "name");
|
||||||
json_t *target = NULL;
|
json_t *target = NULL;
|
||||||
float morphweights[MAX_MORPHWEIGHTS];
|
float morphweights[MAX_MORPHWEIGHTS];
|
||||||
|
@ -1813,26 +1972,66 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
morphtargets = ~0;
|
morphtargets = ~0;
|
||||||
GLTF_FlagExtras(mesh);
|
GLTF_FlagExtras(mesh);
|
||||||
|
|
||||||
for(prim = JSON_FindIndexedChild(mesh, "primitives", 0); prim; prim = prim->sibling)
|
for(primnode = JSON_FindIndexedChild(mesh, "primitives", 0); primnode; primnode = primnode->sibling)
|
||||||
{
|
{
|
||||||
int mode = JSON_GetInteger(prim, "mode", 4);
|
int mode = JSON_GetInteger(primnode, "mode", 4);
|
||||||
json_t *attr = JSON_FindChild(prim, "attributes");
|
json_t *attr = JSON_FindChild(primnode, "attributes");
|
||||||
struct gltf_accessor tc_0, tc_1, norm, tang, vpos, col0, idx, sidx, swgt;
|
struct gltf_accessor tc_0, tc_1, norm, tang, vpos, col0, idx, sidx, swgt;
|
||||||
struct gltf_accessor morph_vpos[MAX_MORPHWEIGHTS], morph_norm[MAX_MORPHWEIGHTS], morph_tang[MAX_MORPHWEIGHTS];
|
struct gltf_accessor morph_vpos[MAX_MORPHWEIGHTS], morph_norm[MAX_MORPHWEIGHTS], morph_tang[MAX_MORPHWEIGHTS];
|
||||||
galiasinfo_t *surf;
|
galiasinfo_t *surf;
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
index_t maxvert;
|
||||||
|
|
||||||
prim->used = true;
|
gltf_prim_t prim = {gltf, primnode, attr};
|
||||||
|
|
||||||
if (mode != 4)
|
#ifdef HAVE_DRACO
|
||||||
|
#define PRIMCLEANUP() do{if (prim.draco) prim.draco->Release(prim.draco);}while(0) //frees memory allocations from inside this loop
|
||||||
|
json_t *draconode = JSON_FindChild(primnode, "extensions.KHR_draco_mesh_compression");
|
||||||
|
if (draconode)
|
||||||
|
{ //decompress the ext.bufferview and replace matching primative.attributes[n] with any listed ext.attributes[n] entries, and the indicies
|
||||||
|
//accessor's componentType, type, count should match that from draco.
|
||||||
|
struct gltf_bufferview bv;
|
||||||
|
if (!GLTF_GetBufferViewData(gltf, JSON_FindChild(draconode, "bufferView"), &bv))
|
||||||
|
{
|
||||||
|
if (gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING "%s: KHR_draco_mesh_compression without bufferview\n", gltf->mod->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prim.draco = Draco_Decode(bv.data, bv.length);
|
||||||
|
if (!prim.draco)
|
||||||
|
{
|
||||||
|
if (gltf->warnlimit --> 0)
|
||||||
|
Con_Printf(CON_WARNING "%s: KHR_draco_mesh_compression decompression failure\n", gltf->mod->name); //in case a model tries supplying more. we ought to renormalise the weights in this case.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
prim.dracoattrs = JSON_FindChild(draconode, "attributes");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define PRIMCLEANUP() do{}while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
primnode->used = true;
|
||||||
|
|
||||||
|
switch(mode)
|
||||||
{
|
{
|
||||||
Con_Printf("Primitive mode %i not supported\n", mode);
|
case 4:
|
||||||
|
break;
|
||||||
|
case 0: //points
|
||||||
|
case 1: //lines
|
||||||
|
case 2: //line loop
|
||||||
|
case 3: //line strip
|
||||||
|
case 5: //triangle strip -- FIXME: probably relevant (with degenerates)
|
||||||
|
case 6: //triangle fan
|
||||||
|
default:
|
||||||
|
if (gltf->warnlimit --> 0)
|
||||||
|
Con_Printf("Primitive mode %i not supported\n", mode);
|
||||||
|
PRIMCLEANUP();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; ; i++)
|
for (i = 0; ; i++)
|
||||||
{
|
{
|
||||||
target = JSON_FindIndexedChild(prim, "targets", i);
|
target = JSON_FindIndexedChild(primnode, "targets", i);
|
||||||
if (!target)
|
if (!target)
|
||||||
break;
|
break;
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(target, "POSITION"), &morph_vpos[i]);
|
GLTF_GetAccessor(gltf, JSON_FindChild(target, "POSITION"), &morph_vpos[i]);
|
||||||
|
@ -1853,42 +2052,44 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLTF_FlagExtras(prim);
|
GLTF_FlagExtras(primnode);
|
||||||
|
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "TEXCOORD_0"), &tc_0); //float, ubyte, ushort
|
GLTF_GetAttributeAccessor(&prim, "POSITION", &vpos); //float
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "TEXCOORD_1"), &tc_1); //float, ubyte, ushort
|
if (!vpos.count)
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "NORMAL"), &norm); //float
|
{
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "TANGENT"), &tang); //float
|
PRIMCLEANUP();
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "POSITION"), &vpos); //float
|
continue;
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "COLOR_0"), &col0); //float, ubyte, ushort
|
}
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(prim, "indices"), &idx);
|
GLTF_GetAttributeAccessor(&prim, "TEXCOORD_0", &tc_0); //float, ubyte, ushort
|
||||||
|
GLTF_GetAttributeAccessor(&prim, "TEXCOORD_1", &tc_1); //float, ubyte, ushort
|
||||||
|
GLTF_GetAttributeAccessor(&prim, "NORMAL", &norm); //float
|
||||||
|
GLTF_GetAttributeAccessor(&prim, "TANGENT", &tang); //float
|
||||||
|
GLTF_GetAttributeAccessor(&prim, "COLOR_0", &col0); //float, ubyte, ushort
|
||||||
|
GLTF_GetIndiciesAccessor(&prim, &idx);
|
||||||
if (gltf->ver <= 1)
|
if (gltf->ver <= 1)
|
||||||
{
|
{
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "JOINT"), &sidx); //ubyte, ushort
|
GLTF_GetAttributeAccessor(&prim, "JOINT", &sidx); //ubyte, ushort
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "WEIGHT"), &swgt); //float, ubyte, ushort
|
GLTF_GetAttributeAccessor(&prim, "WEIGHT", &swgt); //float, ubyte, ushort
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //potentially multiple, each a vec4.
|
{ //potentially multiple, each a vec4.
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "JOINTS_0"), &sidx); //ubyte, ushort
|
GLTF_GetAttributeAccessor(&prim, "JOINTS_0", &sidx); //ubyte, ushort
|
||||||
GLTF_GetAccessor(gltf, JSON_FindChild(attr, "WEIGHTS_0"), &swgt); //float, ubyte, ushort
|
GLTF_GetAttributeAccessor(&prim, "WEIGHTS_0", &swgt); //float, ubyte, ushort
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JSON_GetInteger(attr, "JOINTS_1", -1) != -1 || JSON_GetInteger(attr, "WEIGHTS_1", -1) != -1)
|
if (JSON_GetInteger(attr, "JOINTS_1", -1) != -1 || JSON_GetInteger(attr, "WEIGHTS_1", -1) != -1)
|
||||||
if (gltf->warnlimit --> 0)
|
if (gltf->warnlimit --> 0)
|
||||||
Con_Printf(CON_WARNING "%s: only 4 bones supported per vert\n", gltf->mod->name); //in case a model tries supplying more. we ought to renormalise the weights in this case.
|
Con_Printf(CON_WARNING "%s: only 4 bones supported per vert\n", gltf->mod->name); //in case a model tries supplying more. we ought to renormalise the weights in this case.
|
||||||
|
|
||||||
if (!vpos.count)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
surf = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf) + (morphtargets*sizeof(float)));
|
surf = plugfuncs->GMalloc(&mod->memgroup, sizeof(*surf) + (morphtargets*sizeof(float)));
|
||||||
|
|
||||||
surf->surfaceid = JSON_GetInteger(prim, "extras.fte.surfaceid", meshidx);
|
surf->surfaceid = JSON_GetInteger(primnode, "extras.fte.surfaceid", meshidx);
|
||||||
surf->contents = JSON_GetInteger(prim, "extras.fte.contents", FTECONTENTS_BODY);
|
surf->contents = JSON_GetInteger(primnode, "extras.fte.contents", FTECONTENTS_BODY);
|
||||||
surf->csurface.flags = JSON_GetInteger(prim, "extras.fte.surfaceflags", 0);
|
surf->csurface.flags = JSON_GetInteger(primnode, "extras.fte.surfaceflags", 0);
|
||||||
surf->geomset = JSON_GetInteger(prim, "extras.fte.geomset", ~0u);
|
surf->geomset = JSON_GetInteger(primnode, "extras.fte.geomset", ~0u);
|
||||||
surf->geomid = JSON_GetInteger(prim, "extras.fte.geomid", 0);
|
surf->geomid = JSON_GetInteger(primnode, "extras.fte.geomid", 0);
|
||||||
surf->mindist = JSON_GetInteger(prim, "extras.fte.mindist", 0);
|
surf->mindist = JSON_GetInteger(primnode, "extras.fte.mindist", 0);
|
||||||
surf->maxdist = JSON_GetInteger(prim, "extras.fte.maxdist", 0);
|
surf->maxdist = JSON_GetInteger(primnode, "extras.fte.maxdist", 0);
|
||||||
|
|
||||||
surf->shares_bones = gltf->numsurfaces;
|
surf->shares_bones = gltf->numsurfaces;
|
||||||
surf->shares_verts = gltf->numsurfaces;
|
surf->shares_verts = gltf->numsurfaces;
|
||||||
|
@ -1910,12 +2111,15 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
surf->ofs_indexes[i] = *(unsigned char *)((char*)idx.data + i*idx.bytestride);
|
surf->ofs_indexes[i] = *(unsigned char *)((char*)idx.data + i*idx.bytestride);
|
||||||
}
|
}
|
||||||
else if (idx.componentType == 5125)
|
else if (idx.componentType == 5125)
|
||||||
{ //unsigned ints
|
{ //unsigned ints. -- FIXME: catch overflows.
|
||||||
for (i = 0; i < idx.count; i++)
|
for (i = 0; i < idx.count; i++)
|
||||||
surf->ofs_indexes[i] = *(unsigned int *)((char*)idx.data + i*idx.bytestride); //FIXME: bounds check.
|
surf->ofs_indexes[i] = *(unsigned int *)((char*)idx.data + i*idx.bytestride); //FIXME: bounds check.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
PRIMCLEANUP();
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1933,6 +2137,16 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
surf->ofs_indexes[i+2] = t;
|
surf->ofs_indexes[i+2] = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (maxvert = 0, i = 0; i < idx.count; i++)
|
||||||
|
if (maxvert < surf->ofs_indexes[i])
|
||||||
|
maxvert = surf->ofs_indexes[i];
|
||||||
|
if (maxvert >= surf->numverts)
|
||||||
|
{
|
||||||
|
Con_Printf(CON_WARNING "%s: %s Index list exceeds vertex count range\n", gltf->mod->name, surf->surfacename); //in case a model tries supplying more. we ought to renormalise the weights in this case.
|
||||||
|
PRIMCLEANUP();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
surf->AnimateMorphs = GLTF_AnimateMorphs;
|
surf->AnimateMorphs = GLTF_AnimateMorphs;
|
||||||
memcpy((float*)(surf+1), morphweights, sizeof(float)*morphtargets);
|
memcpy((float*)(surf+1), morphweights, sizeof(float)*morphtargets);
|
||||||
surf->nummorphs = morphtargets;
|
surf->nummorphs = morphtargets;
|
||||||
|
@ -2020,11 +2234,11 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
json_t *mapping, *var;
|
json_t *mapping, *var;
|
||||||
surf->numskins = 1+gltf->variations;
|
surf->numskins = 1+gltf->variations;
|
||||||
surf->ofsskins = plugfuncs->GMalloc(&gltf->mod->memgroup, sizeof(*surf->ofsskins)*surf->numskins);
|
surf->ofsskins = plugfuncs->GMalloc(&gltf->mod->memgroup, sizeof(*surf->ofsskins)*surf->numskins);
|
||||||
GLTF_LoadMaterial(gltf, JSON_FindChild(prim, "material"), surf->ofsskins, surf->ofs_rgbaub||surf->ofs_rgbaf);
|
GLTF_LoadMaterial(gltf, JSON_FindChild(primnode, "material"), surf->ofsskins, surf->ofs_rgbaub||surf->ofs_rgbaf);
|
||||||
for (i = 0; i < gltf->variations; i++)
|
for (i = 0; i < gltf->variations; i++)
|
||||||
surf->ofsskins[1+i] = surf->ofsskins[0]; //unspecified matches defaults...
|
surf->ofsskins[1+i] = surf->ofsskins[0]; //unspecified matches defaults...
|
||||||
|
|
||||||
for (mapping=JSON_FindIndexedChild(prim, "extensions.KHR_materials_variants.mappings", 0); mapping; mapping = mapping->sibling)
|
for (mapping=JSON_FindIndexedChild(primnode, "extensions.KHR_materials_variants.mappings", 0); mapping; mapping = mapping->sibling)
|
||||||
{
|
{
|
||||||
i = 0;
|
i = 0;
|
||||||
for(var = JSON_FindIndexedChild(mapping, "variants", 0); var; var = var->sibling)
|
for(var = JSON_FindIndexedChild(mapping, "variants", 0); var; var = var->sibling)
|
||||||
|
@ -2051,6 +2265,8 @@ static qboolean GLTF_ProcessMesh(gltf_t *gltf, json_t *meshid, int basebone, dou
|
||||||
gltf->numsurfaces++;
|
gltf->numsurfaces++;
|
||||||
surf->nextsurf = mod->meshinfo;
|
surf->nextsurf = mod->meshinfo;
|
||||||
mod->meshinfo = surf;
|
mod->meshinfo = surf;
|
||||||
|
|
||||||
|
PRIMCLEANUP();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2741,13 +2957,17 @@ static qboolean GLTF_LoadModel(struct model_s *mod, char *json, size_t jsonsize,
|
||||||
{"KHR_materials_pbrSpecularGlossiness", true, false},
|
{"KHR_materials_pbrSpecularGlossiness", true, false},
|
||||||
// {"KHR_materials_cmnBlinnPhong", true, true},
|
// {"KHR_materials_cmnBlinnPhong", true, true},
|
||||||
{"KHR_materials_unlit", true, false},
|
{"KHR_materials_unlit", true, false},
|
||||||
{"KHR_mesh_quantization", true, true},
|
{"KHR_mesh_quantization", true, false},
|
||||||
{"MSFT_texture_dds", true, false},
|
{"MSFT_texture_dds", true, false},
|
||||||
{"MSFT_packing_occlusionRoughnessMetallic", true, false},
|
{"MSFT_packing_occlusionRoughnessMetallic", true, false},
|
||||||
{"KHR_materials_variants", true, false},
|
{"KHR_materials_variants", true, false},
|
||||||
{"KHR_materials_ior", true, false},
|
{"KHR_materials_ior", true, false},
|
||||||
|
|
||||||
{"KHR_draco_mesh_compression", false, true}, //probably fatal
|
#ifdef HAVE_DRACO
|
||||||
|
{"KHR_draco_mesh_compression", true, false}, //probably fatal
|
||||||
|
#else
|
||||||
|
{"KHR_draco_mesh_compression", false, false}, //probably fatal
|
||||||
|
#endif
|
||||||
{"KHR_texture_transform", false, false}, //requires glsl tweaks, per texmap. can't use tcmod if its only on the bumpmap etc.
|
{"KHR_texture_transform", false, false}, //requires glsl tweaks, per texmap. can't use tcmod if its only on the bumpmap etc.
|
||||||
{"KHR_materials_sheen", false, false}, //requires glsl tweaks, extra brdf layer in the middle for velvet.
|
{"KHR_materials_sheen", false, false}, //requires glsl tweaks, extra brdf layer in the middle for velvet.
|
||||||
{"KHR_materials_clearcoat", false, false}, //requires glsl tweaks, extra brdf layer over the top for varnish etc.
|
{"KHR_materials_clearcoat", false, false}, //requires glsl tweaks, extra brdf layer over the top for varnish etc.
|
||||||
|
|
Loading…
Reference in a new issue