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:
Bill Currie 2012-05-17 15:55:38 +09:00
parent e722352a61
commit c0df07b607
7 changed files with 234 additions and 8 deletions

41
include/QF/GL/qf_iqm.h Normal file
View 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

View File

@ -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 \
\

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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,