mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2025-01-09 19:41:04 +00:00
add IQM format support into lib/picomodel
This commit is contained in:
parent
2634c6238d
commit
3408871d79
5 changed files with 445 additions and 3 deletions
|
@ -4255,6 +4255,31 @@
|
|||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_lwo.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
"-c",
|
||||
"-O2",
|
||||
"-fno-strict-aliasing",
|
||||
"-pipe",
|
||||
"-Wall",
|
||||
"-fmessage-length=0",
|
||||
"-fvisibility=hidden",
|
||||
"-I/usr/include/libxml2",
|
||||
"-DQ_NO_STLPORT",
|
||||
"-I/usr/include/glib-2.0",
|
||||
"-I/usr/lib/x86_64-linux-gnu/glib-2.0/include",
|
||||
"-Ibuild/release/q3map2/include",
|
||||
"-Iinclude",
|
||||
"-Ibuild/release/q3map2/libs",
|
||||
"-Ilibs",
|
||||
"-o",
|
||||
"build/release/q3map2/libs/picomodel/pm_iqm.o",
|
||||
"libs/picomodel/pm_iqm.c"
|
||||
],
|
||||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_iqm.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
|
@ -9497,6 +9522,31 @@
|
|||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_lwo.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
"-c",
|
||||
"-O2",
|
||||
"-fno-strict-aliasing",
|
||||
"-pipe",
|
||||
"-Wall",
|
||||
"-fmessage-length=0",
|
||||
"-fvisibility=hidden",
|
||||
"-I/usr/include/libxml2",
|
||||
"-DQ_NO_STLPORT",
|
||||
"-I/usr/include/glib-2.0",
|
||||
"-I/usr/lib/x86_64-linux-gnu/glib-2.0/include",
|
||||
"-Ibuild/release/q3map2_urt/include",
|
||||
"-Iinclude",
|
||||
"-Ibuild/release/q3map2_urt/libs",
|
||||
"-Ilibs",
|
||||
"-o",
|
||||
"build/release/q3map2_urt/libs/picomodel/pm_iqm.o",
|
||||
"libs/picomodel/pm_iqm.c"
|
||||
],
|
||||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_iqm.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
|
@ -13180,6 +13230,32 @@
|
|||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_lwo.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
"-c",
|
||||
"-O2",
|
||||
"-fno-strict-aliasing",
|
||||
"-pipe",
|
||||
"-Wall",
|
||||
"-fmessage-length=0",
|
||||
"-fvisibility=hidden",
|
||||
"-I/usr/include/libxml2",
|
||||
"-fPIC",
|
||||
"-DQ_NO_STLPORT",
|
||||
"-I/usr/include/glib-2.0",
|
||||
"-I/usr/lib/x86_64-linux-gnu/glib-2.0/include",
|
||||
"-Ibuild/release/shobjs/include",
|
||||
"-Iinclude",
|
||||
"-Ibuild/release/shobjs/libs",
|
||||
"-Ilibs",
|
||||
"-o",
|
||||
"build/release/shobjs/libs/picomodel/pm_iqm.os",
|
||||
"libs/picomodel/pm_iqm.c"
|
||||
],
|
||||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/picomodel/pm_iqm.c"
|
||||
},
|
||||
{
|
||||
"arguments": [
|
||||
"cc",
|
||||
|
@ -13277,4 +13353,4 @@
|
|||
"directory": "/home/timo/GtkRadiant/GtkRadiant",
|
||||
"file": "libs/l_net/l_net_berkeley.c"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
<ClCompile Include="pm_mdc.c" />
|
||||
<ClCompile Include="pm_ms3d.c" />
|
||||
<ClCompile Include="pm_obj.c" />
|
||||
<ClCompile Include="pm_iqm.c" />
|
||||
<ClCompile Include="lwo\clip.c" />
|
||||
<ClCompile Include="lwo\envelope.c" />
|
||||
<ClCompile Include="lwo\list.c" />
|
||||
|
@ -152,4 +153,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
<ClCompile Include="pm_lwo.c">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pm_iqm.c">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pm_md2.c">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
|
@ -81,4 +84,4 @@
|
|||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -55,6 +55,7 @@ extern const picoModule_t picoModuleMD2;
|
|||
extern const picoModule_t picoModuleFM;
|
||||
extern const picoModule_t picoModuleLWO;
|
||||
extern const picoModule_t picoModuleTerrain;
|
||||
extern const picoModule_t picoModuleIQM;
|
||||
|
||||
|
||||
|
||||
|
@ -71,6 +72,7 @@ const picoModule_t *picoModules[] =
|
|||
&picoModuleLWO, /* lightwave object */
|
||||
&picoModuleTerrain, /* picoterrain object */
|
||||
&picoModuleOBJ, /* wavefront object */
|
||||
&picoModuleIQM, /* interquake model */
|
||||
NULL /* arnold */
|
||||
};
|
||||
|
||||
|
|
360
libs/picomodel/pm_iqm.c
Normal file
360
libs/picomodel/pm_iqm.c
Normal file
|
@ -0,0 +1,360 @@
|
|||
/* -----------------------------------------------------------------------------
|
||||
|
||||
InterQuake Model - PicoModel Library
|
||||
|
||||
Copyright (c) 2018-2021, FTE Team <fteqw.org>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the names of the copyright holders nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
/* dependencies */
|
||||
#include "picointernal.h"
|
||||
#include "bytebool.h"
|
||||
|
||||
extern const picoModule_t picoModuleIQM;
|
||||
|
||||
#define IQM_MAGIC "INTERQUAKEMODEL" //15+null
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
.IQM triangle model file format
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
IQM_POSITION = 0,
|
||||
IQM_TEXCOORD = 1,
|
||||
IQM_NORMAL = 2,
|
||||
IQM_TANGENT = 3,
|
||||
IQM_BLENDINDEXES = 4,
|
||||
IQM_BLENDWEIGHTS = 5,
|
||||
IQM_COLOR = 6,
|
||||
IQM_CUSTOM = 0x10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
IQM_BYTE = 0,
|
||||
IQM_UBYTE = 1,
|
||||
IQM_SHORT = 2,
|
||||
IQM_USHORT = 3,
|
||||
IQM_INT = 4,
|
||||
IQM_UINT = 5,
|
||||
IQM_HALF = 6,
|
||||
IQM_FLOAT = 7,
|
||||
IQM_DOUBLE = 8
|
||||
};
|
||||
|
||||
// animflags
|
||||
#define IQM_LOOP 1
|
||||
|
||||
typedef struct iqmHeader_s {
|
||||
byte id[16];
|
||||
unsigned int version;
|
||||
unsigned int filesize;
|
||||
unsigned int flags;
|
||||
unsigned int num_text, ofs_text;
|
||||
unsigned int num_meshes, ofs_meshes;
|
||||
unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
|
||||
unsigned int num_triangles, ofs_triangles, ofs_neighbors;
|
||||
unsigned int num_joints, ofs_joints;
|
||||
unsigned int num_poses, ofs_poses;
|
||||
unsigned int num_anims, ofs_anims;
|
||||
unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
|
||||
unsigned int num_comment, ofs_comment;
|
||||
unsigned int num_extensions, ofs_extensions;
|
||||
} iqmHeader_t;
|
||||
|
||||
typedef struct iqmmesh_s {
|
||||
unsigned int name;
|
||||
unsigned int material;
|
||||
unsigned int first_vertex;
|
||||
unsigned int num_vertexes;
|
||||
unsigned int first_triangle;
|
||||
unsigned int num_triangles;
|
||||
} iqmmesh_t;
|
||||
|
||||
typedef struct iqmvertexarray_s {
|
||||
unsigned int type;
|
||||
unsigned int flags;
|
||||
unsigned int format;
|
||||
unsigned int size;
|
||||
unsigned int offset;
|
||||
} iqmvertexarray_t;
|
||||
|
||||
//is anyone actually going to run this on a big-endian cpu?
|
||||
static iqmHeader_t SwapHeader(const iqmHeader_t *h)
|
||||
{
|
||||
iqmHeader_t r = *h;
|
||||
r.version = _pico_little_long(h->version);
|
||||
r.filesize = _pico_little_long(h->filesize);
|
||||
r.flags = _pico_little_long(h->flags);
|
||||
r.num_text = _pico_little_long(h->num_text);
|
||||
r.ofs_text = _pico_little_long(h->ofs_text);
|
||||
r.num_meshes = _pico_little_long(h->num_meshes);
|
||||
r.ofs_meshes = _pico_little_long(h->ofs_meshes);
|
||||
r.num_vertexarrays = _pico_little_long(h->num_vertexarrays);
|
||||
r.num_vertexes = _pico_little_long(h->num_vertexes);
|
||||
r.ofs_vertexarrays = _pico_little_long(h->ofs_vertexarrays);
|
||||
r.num_triangles = _pico_little_long(h->num_triangles);
|
||||
r.ofs_triangles = _pico_little_long(h->ofs_triangles);
|
||||
r.ofs_neighbors = _pico_little_long(h->ofs_neighbors);
|
||||
r.num_joints = _pico_little_long(h->num_joints);
|
||||
r.ofs_joints = _pico_little_long(h->ofs_joints);
|
||||
r.num_poses = _pico_little_long(h->num_poses);
|
||||
r.ofs_poses = _pico_little_long(h->ofs_poses);
|
||||
r.num_anims = _pico_little_long(h->num_anims);
|
||||
r.ofs_anims = _pico_little_long(h->ofs_anims);
|
||||
r.num_frames = _pico_little_long(h->num_frames);
|
||||
r.num_framechannels = _pico_little_long(h->num_framechannels);
|
||||
r.ofs_frames = _pico_little_long(h->ofs_frames);
|
||||
r.ofs_bounds = _pico_little_long(h->ofs_bounds);
|
||||
r.num_comment = _pico_little_long(h->num_comment);
|
||||
r.ofs_comment = _pico_little_long(h->ofs_comment);
|
||||
r.num_extensions = _pico_little_long(h->num_extensions);
|
||||
r.ofs_extensions = _pico_little_long(h->ofs_extensions);
|
||||
return r;
|
||||
}
|
||||
|
||||
// _iqm_canload()
|
||||
static int _iqm_canload( PM_PARAMS_CANLOAD ){
|
||||
iqmHeader_t h;
|
||||
|
||||
//make sure there's enough data for the header...
|
||||
if ((size_t)bufSize < sizeof(h))
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
h = SwapHeader(buffer);
|
||||
|
||||
//make sure its actually an iqm
|
||||
if (memcmp(h.id, IQM_MAGIC, sizeof(h.id)))
|
||||
return PICO_PMV_ERROR_IDENT;
|
||||
//v1 is flawed, we don't know about anything higher either.
|
||||
if (h.version != 2)
|
||||
return PICO_PMV_ERROR_VERSION;
|
||||
//make sure its not truncated
|
||||
if ((size_t)h.filesize != (size_t)bufSize)
|
||||
return PICO_PMV_ERROR_SIZE;
|
||||
|
||||
//looks like we can probably use it.
|
||||
return PICO_PMV_OK;
|
||||
}
|
||||
|
||||
// _iqm_load() loads an interquake model file.
|
||||
static picoModel_t *_iqm_load( PM_PARAMS_LOAD ){
|
||||
picoModel_t *picoModel;
|
||||
picoSurface_t *picoSurface;
|
||||
picoShader_t *picoShader;
|
||||
const float *inf;
|
||||
const byte *inb;
|
||||
picoVec3_t xyz, normal;
|
||||
picoVec2_t st;
|
||||
picoColor_t color;
|
||||
|
||||
iqmHeader_t h;
|
||||
iqmmesh_t m;
|
||||
iqmvertexarray_t a;
|
||||
size_t s, t, j, i;
|
||||
const char *stringtable;
|
||||
char skinname[512];
|
||||
const unsigned int *tri;
|
||||
|
||||
//just in case
|
||||
if (_iqm_canload(fileName, buffer, bufSize) != PICO_PMV_OK)
|
||||
{
|
||||
_pico_printf( PICO_ERROR, "%s is not an IQM File!", fileName );
|
||||
return NULL;
|
||||
}
|
||||
h = SwapHeader(buffer);
|
||||
stringtable = (const char*)buffer + h.ofs_text;
|
||||
|
||||
// do frame check
|
||||
if ( h.num_anims != 0 ) {
|
||||
_pico_printf( PICO_WARNING, "%s has animations! Using base pose only.", fileName );
|
||||
}
|
||||
|
||||
/* create new pico model */
|
||||
picoModel = PicoNewModel();
|
||||
if ( picoModel == NULL ) {
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* do model setup */
|
||||
PicoSetModelFrameNum( picoModel, frameNum );
|
||||
PicoSetModelNumFrames( picoModel, 1 ); /* sea */
|
||||
PicoSetModelName( picoModel, fileName );
|
||||
PicoSetModelFileName( picoModel, fileName );
|
||||
|
||||
for (s = 0; s < h.num_meshes; s++)
|
||||
{
|
||||
m = ((const iqmmesh_t*)((const char*)buffer + h.ofs_meshes))[s];
|
||||
m.first_triangle = _pico_little_long(m.first_triangle);
|
||||
m.first_vertex = _pico_little_long(m.first_vertex);
|
||||
m.material = _pico_little_long(m.material);
|
||||
m.name = _pico_little_long(m.name);
|
||||
m.num_triangles = _pico_little_long(m.num_triangles);
|
||||
m.num_vertexes = _pico_little_long(m.num_vertexes);
|
||||
|
||||
// allocate new pico surface
|
||||
picoSurface = PicoNewSurface( picoModel );
|
||||
if ( picoSurface == NULL ) {
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// detox Skin name
|
||||
memcpy(skinname, stringtable+m.material, sizeof(skinname));
|
||||
_pico_setfext( skinname, "" );
|
||||
_pico_unixify( skinname );
|
||||
|
||||
PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
|
||||
PicoSetSurfaceName( picoSurface, stringtable+m.name );
|
||||
picoShader = PicoNewShader( picoModel );
|
||||
if ( picoShader == NULL ) {
|
||||
_pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
|
||||
PicoFreeModel( picoModel );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PicoSetShaderName( picoShader, skinname );
|
||||
|
||||
// associate current surface with newly created shader
|
||||
PicoSetSurfaceShader( picoSurface, picoShader );
|
||||
|
||||
|
||||
// spew the surface's indexes
|
||||
tri = (const unsigned int *)((const char *)buffer+h.ofs_triangles) + m.first_triangle*3;
|
||||
for (t = 0; t < m.num_triangles*3; t++)
|
||||
PicoSetSurfaceIndex( picoSurface, t, _pico_little_long(*tri++) - m.first_vertex );
|
||||
|
||||
for ( j = 0; j < h.num_vertexarrays; j++)
|
||||
{
|
||||
a = ((const iqmvertexarray_t*)((const char*)buffer + h.ofs_vertexarrays))[j];
|
||||
a.flags = _pico_little_long(a.flags);
|
||||
a.format = _pico_little_long(a.format);
|
||||
a.offset = _pico_little_long(a.offset);
|
||||
a.size = _pico_little_long(a.size);
|
||||
a.type = _pico_little_long(a.type);
|
||||
|
||||
switch(a.type)
|
||||
{
|
||||
case IQM_POSITION:
|
||||
if (a.format == IQM_FLOAT && a.size >= 3)
|
||||
{
|
||||
inf = (const float*)((const char *)buffer + a.offset) + m.first_vertex*a.size;
|
||||
for ( i = 0; i < m.num_vertexes; i++, inf += a.size )
|
||||
{
|
||||
xyz[0] = _pico_little_float(inf[0]);
|
||||
xyz[1] = _pico_little_float(inf[1]);
|
||||
xyz[2] = _pico_little_float(inf[2]);
|
||||
PicoSetSurfaceXYZ( picoSurface, i, xyz );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IQM_TEXCOORD:
|
||||
if (a.format == IQM_FLOAT && a.size >= 2)
|
||||
{
|
||||
inf = (const float*)((const char *)buffer + a.offset) + m.first_vertex*a.size;
|
||||
for ( i = 0; i < m.num_vertexes; i++, inf += a.size )
|
||||
{
|
||||
st[0] = _pico_little_float(inf[0]);
|
||||
st[1] = _pico_little_float(inf[1]);
|
||||
PicoSetSurfaceST( picoSurface, 0, i, st );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IQM_NORMAL:
|
||||
if (a.format == IQM_FLOAT && a.size >= 3)
|
||||
{
|
||||
inf = (const float*)((const char *)buffer + a.offset) + m.first_vertex*a.size;
|
||||
for ( i = 0; i < m.num_vertexes; i++, inf += a.size )
|
||||
{
|
||||
normal[0] = _pico_little_float(inf[0]);
|
||||
normal[1] = _pico_little_float(inf[1]);
|
||||
normal[2] = _pico_little_float(inf[2]);
|
||||
PicoSetSurfaceNormal( picoSurface, i, normal );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IQM_COLOR:
|
||||
if (a.format == IQM_UBYTE && a.size >= 3)
|
||||
{
|
||||
inb = (const byte*)((const char *)buffer + a.offset) + m.first_vertex*a.size;
|
||||
for ( i = 0; i < m.num_vertexes; i++, inb += a.size )
|
||||
{
|
||||
color[0] = inb[0];
|
||||
color[1] = inb[1];
|
||||
color[2] = inb[2];
|
||||
color[3] = (a.size>=4)?inb[3]:255;
|
||||
PicoSetSurfaceColor( picoSurface, 0, i, color );
|
||||
}
|
||||
}
|
||||
else if (a.format == IQM_FLOAT && a.size >= 3)
|
||||
{
|
||||
inf = (const float*)((const char *)buffer + a.offset) + m.first_vertex*a.size;
|
||||
for ( i = 0; i < m.num_vertexes; i++, inf += a.size )
|
||||
{
|
||||
color[0] = inf[0]*255;
|
||||
color[1] = inf[1]*255;
|
||||
color[2] = inf[2]*255;
|
||||
color[3] = (a.size>=4)?inf[3]*255:255;
|
||||
PicoSetSurfaceColor( picoSurface, 0, i, color );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IQM_TANGENT:
|
||||
case IQM_BLENDINDEXES:
|
||||
case IQM_BLENDWEIGHTS:
|
||||
case IQM_CUSTOM:
|
||||
break; // these attributes are not relevant.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return picoModel;
|
||||
}
|
||||
|
||||
/* pico file format module definition */
|
||||
const picoModule_t picoModuleIQM =
|
||||
{
|
||||
"0.1", /* module version string */
|
||||
"InterQuake Model", /* module display name */
|
||||
"Spoike", /* author's name */
|
||||
"2018-2021 FTE Team", /* module copyright */
|
||||
{
|
||||
"iqm", NULL, NULL, NULL /* default extensions to use */
|
||||
},
|
||||
_iqm_canload, /* validation routine */
|
||||
_iqm_load, /* load routine */
|
||||
NULL, /* save validation routine */
|
||||
NULL /* save routine */
|
||||
};
|
Loading…
Reference in a new issue