mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
Enable loading of iqm models in gl.
They don't render yet, but the engine doesn't segfault. The vertex blend indices are rewritten with blend palette indices.
This commit is contained in:
parent
e722352a61
commit
c0df07b607
7 changed files with 234 additions and 8 deletions
41
include/QF/GL/qf_iqm.h
Normal file
41
include/QF/GL/qf_iqm.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
qf_iqm.h
|
||||
|
||||
GL specific IQM stuff
|
||||
|
||||
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
Date: 2012/5/17
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
|
||||
Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
*/
|
||||
#ifndef __QF_GL_qf_iqm_h
|
||||
#define __QF_GL_qf_iqm_h
|
||||
|
||||
#include "QF/iqm.h"
|
||||
|
||||
typedef struct glsliqm_s {
|
||||
int *textures;
|
||||
iqmblend_t *blend_palette; // includes base data from iqm
|
||||
int palette_size; // includes base data from iqm
|
||||
} gliqm_t;
|
||||
|
||||
#endif//__QF_GL_qf_iqm_h
|
|
@ -12,7 +12,7 @@ nobase_pkginclude_HEADERS = \
|
|||
vrect.h view.h wad.h wadfile.h winding.h zone.h \
|
||||
\
|
||||
GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_explosions.h \
|
||||
GL/qf_funcs_list.h GL/qf_lightmap.h \
|
||||
GL/qf_funcs_list.h GL/qf_iqm.h GL/qf_lightmap.h \
|
||||
GL/qf_rlight.h GL/qf_rmain.h GL/qf_rsurf.h GL/qf_sky.h GL/qf_textures.h \
|
||||
GL/qf_vid.h GL/types.h \
|
||||
\
|
||||
|
|
|
@ -122,6 +122,11 @@ typedef struct {
|
|||
quat_t scale;
|
||||
} iqmframe_t;
|
||||
|
||||
typedef struct {
|
||||
byte indices[4];
|
||||
byte weights[4];
|
||||
} iqmblend_t;
|
||||
|
||||
typedef struct {
|
||||
char *text;
|
||||
int num_meshes;
|
||||
|
|
|
@ -53,6 +53,7 @@ void sw_Mod_SpriteLoadTexture (mspriteframe_t *pspriteframe, int framenum);
|
|||
|
||||
void Mod_LoadIQM (model_t *mod, void *buffer);
|
||||
void Mod_FreeIQM (iqm_t *iqm);
|
||||
iqmblend_t *Mod_IQMBuildBlendPalette (iqm_t *iqm, int *size);
|
||||
void Mod_LoadAliasModel (model_t *mod, void *buffer,
|
||||
cache_allocator_t allocator);
|
||||
void Mod_LoadSpriteModel (model_t *mod, void *buffer);
|
||||
|
|
|
@ -39,15 +39,68 @@
|
|||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "QF/dstring.h"
|
||||
#include "QF/image.h"
|
||||
#include "QF/qendian.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/skin.h"
|
||||
#include "QF/sys.h"
|
||||
#include "QF/va.h"
|
||||
#include "QF/vid.h"
|
||||
#include "QF/GL/qf_iqm.h"
|
||||
#include "QF/GL/qf_textures.h"
|
||||
|
||||
#include "mod_internal.h"
|
||||
|
||||
#include "compat.h"
|
||||
static byte null_texture[] = {
|
||||
204, 204, 204, 255,
|
||||
204, 204, 204, 255,
|
||||
204, 204, 204, 255,
|
||||
204, 204, 204, 255,
|
||||
};
|
||||
|
||||
static void
|
||||
gl_iqm_clear (model_t *mod)
|
||||
{
|
||||
iqm_t *iqm = (iqm_t *) mod->aliashdr;
|
||||
gliqm_t *gl = (gliqm_t *) iqm->extra_data;
|
||||
|
||||
mod->needload = true;
|
||||
|
||||
free (gl->blend_palette);
|
||||
free (gl);
|
||||
Mod_FreeIQM (iqm);
|
||||
}
|
||||
|
||||
static void
|
||||
gl_iqm_load_textures (iqm_t *iqm)
|
||||
{
|
||||
gliqm_t *gl = (gliqm_t *) iqm->extra_data;
|
||||
int i;
|
||||
dstring_t *str = dstring_new ();
|
||||
tex_t *tex;
|
||||
|
||||
gl->textures = malloc (iqm->num_meshes * sizeof (int));
|
||||
for (i = 0; i < iqm->num_meshes; i++) {
|
||||
dstring_copystr (str, iqm->text + iqm->meshes[i].material);
|
||||
QFS_StripExtension (str->str, str->str);
|
||||
if ((tex = LoadImage (va ("textures/%s", str->str))))
|
||||
gl->textures[i] = GL_LoadTexture (str->str, tex->width,
|
||||
tex->height, tex->data, true,
|
||||
false,
|
||||
tex->format > 2 ? tex->format
|
||||
: 1);
|
||||
else
|
||||
gl->textures[i] = GL_LoadTexture ("", 2, 2, null_texture, true,
|
||||
false, 4);
|
||||
}
|
||||
dstring_delete (str);
|
||||
}
|
||||
|
||||
void
|
||||
gl_Mod_IQMFinish (model_t *mod)
|
||||
{
|
||||
iqm_t *iqm = (iqm_t *) mod->aliashdr;
|
||||
gliqm_t *gl;
|
||||
|
||||
mod->clear = gl_iqm_clear;
|
||||
iqm->extra_data = gl = calloc (1, sizeof (gliqm_t));
|
||||
gl_iqm_load_textures (iqm);
|
||||
gl->blend_palette = Mod_IQMBuildBlendPalette (iqm, &gl->palette_size);
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@
|
|||
#endif
|
||||
|
||||
#include "QF/crc.h"
|
||||
#include "QF/hash.h"
|
||||
#include "QF/iqm.h"
|
||||
#include "QF/msg.h"
|
||||
#include "QF/qendian.h"
|
||||
#include "QF/quakefs.h"
|
||||
#include "QF/sys.h"
|
||||
|
@ -542,3 +542,129 @@ Mod_FreeIQM (iqm_t *iqm)
|
|||
free (iqm->frames);
|
||||
free (iqm);
|
||||
}
|
||||
|
||||
static void
|
||||
swap_bones (byte *bi, byte *bw, int b1, int b2)
|
||||
{
|
||||
byte t;
|
||||
|
||||
t = bi[b1];
|
||||
bi[b1] = bi[b2];
|
||||
bi[b2] = t;
|
||||
|
||||
t = bw[b1];
|
||||
bw[b1] = bw[b2];
|
||||
bw[b2] = t;
|
||||
}
|
||||
|
||||
static uintptr_t
|
||||
blend_get_hash (void *e, void *unused)
|
||||
{
|
||||
iqmblend_t *b = (iqmblend_t *) e;
|
||||
return CRC_Block ((byte *) b, sizeof (iqmblend_t));
|
||||
}
|
||||
|
||||
static int
|
||||
blend_compare (void *e1, void *e2, void *unused)
|
||||
{
|
||||
iqmblend_t *b1 = (iqmblend_t *) e1;
|
||||
iqmblend_t *b2 = (iqmblend_t *) e2;
|
||||
return !memcmp (b1, b2, sizeof (iqmblend_t));
|
||||
}
|
||||
|
||||
#define MAX_BLENDS 1024
|
||||
|
||||
iqmblend_t *
|
||||
Mod_IQMBuildBlendPalette (iqm_t *iqm, int *size)
|
||||
{
|
||||
int i, j;
|
||||
iqmvertexarray *bindices = 0;
|
||||
iqmvertexarray *bweights = 0;
|
||||
iqmblend_t *blend_list;
|
||||
int num_blends;
|
||||
hashtab_t *blend_hash;
|
||||
|
||||
for (i = 0; i < iqm->num_arrays; i++) {
|
||||
if (iqm->vertexarrays[i].type == IQM_BLENDINDEXES)
|
||||
bindices = &iqm->vertexarrays[i];
|
||||
if (iqm->vertexarrays[i].type == IQM_BLENDWEIGHTS)
|
||||
bweights = &iqm->vertexarrays[i];
|
||||
}
|
||||
if (!bindices || !bweights) {
|
||||
// Not necessarily an error: might be a static model with no bones
|
||||
// Either way, no need to make a blend palette
|
||||
Sys_MaskPrintf (SYS_MODEL, "bone index or weight array missing\n");
|
||||
*size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
blend_list = calloc (MAX_BLENDS, sizeof (iqmblend_t));
|
||||
for (i = 0; i < iqm->num_joints; i++) {
|
||||
blend_list[i].indices[0] = i;
|
||||
blend_list[i].weights[0] = 255;
|
||||
}
|
||||
num_blends = iqm->num_joints;
|
||||
|
||||
blend_hash = Hash_NewTable (1023, 0, 0, 0);
|
||||
Hash_SetHashCompare (blend_hash, blend_get_hash, blend_compare);
|
||||
|
||||
for (i = 0; i < iqm->num_verts; i++) {
|
||||
byte *vert = iqm->vertices + i * iqm->stride;
|
||||
byte *bi = vert + bindices->offset;
|
||||
byte *bw = vert + bweights->offset;
|
||||
iqmblend_t blend;
|
||||
iqmblend_t *bl;
|
||||
|
||||
// First, canonicalize vextex bone data:
|
||||
// bone indices are in increasing order
|
||||
// bone weight of zero is never followed by a non-zero weight
|
||||
// bone weight of zero has bone index of zero
|
||||
|
||||
// if the weight is zero, ensure the index is also zero
|
||||
// also, ensure non-zero weights never follow zero weights
|
||||
for (j = 0; j < 4; j++) {
|
||||
if (!bw[j]) {
|
||||
bi[j] = 0;
|
||||
} else {
|
||||
if (j && !bw[j-1]) {
|
||||
swap_bones (bi, bw, j - 1, j);
|
||||
j = 0; // force a rescan
|
||||
}
|
||||
}
|
||||
}
|
||||
// sort the bones such that the indeces are increasing (unless the
|
||||
// weight is zero)
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (!bw[j+1]) // zero weight == end of list
|
||||
break;
|
||||
if (bi[j] > bi[j+1]) {
|
||||
swap_bones (bi, bw, j, j + 1);
|
||||
j = -1; // force rescan
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the bone data is canonical, it can be hashed.
|
||||
// However, no need to check other combinations if the vertex has
|
||||
// only one influencing bone: the bone index will only change format.
|
||||
if (!bw[1]) {
|
||||
*(uint32_t *) bi = bi[0];
|
||||
continue;
|
||||
}
|
||||
QuatCopy (bi, blend.indices);
|
||||
QuatCopy (bw, blend.weights);
|
||||
if ((bl = Hash_FindElement (blend_hash, &blend))) {
|
||||
*(uint32_t *) bi = (bl - blend_list);
|
||||
continue;
|
||||
}
|
||||
if (num_blends >= MAX_BLENDS)
|
||||
Sys_Error ("Too many blends. Tell taniwha to stop being lazy.");
|
||||
blend_list[num_blends] = blend;
|
||||
Hash_AddElement (blend_hash, &blend_list[num_blends]);
|
||||
*(uint32_t *) bi = num_blends;
|
||||
num_blends++;
|
||||
}
|
||||
|
||||
Hash_DelTable (blend_hash);
|
||||
*size = num_blends;
|
||||
return realloc (blend_list, num_blends * sizeof (iqmblend_t));
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ static vid_model_funcs_t model_funcs = {
|
|||
gl_Mod_LoadSkin,
|
||||
gl_Mod_FinalizeAliasModel,
|
||||
gl_Mod_LoadExternalSkins,
|
||||
0,
|
||||
gl_Mod_IQMFinish,
|
||||
1,
|
||||
gl_Mod_SpriteLoadTexture,
|
||||
|
||||
|
|
Loading…
Reference in a new issue