Skip to content

Commit

Permalink
spearmint: WIP: Add support for Heavy Metal: FAKK2's skelatal models
Browse files Browse the repository at this point in the history
The format is also used by American McGee's Alice. Star Trek: Elite
Force 2 uses the same file extensions but it's a slight different
format -- it's not supported by this commit.

This commit draws the models but there is a few issues for full
support.

This only adds it to opengl1 renderer as it's not deemed complete,
merging into opengl2 will not be very difficult. It's missing
support for run-time level-of-detail change, trap_R_LerpTag,
dynamic bones (no CGame API), and legs rotation (I started trying
to reuse WolfET torso rotate API but it's unfinished).
There may be other issues I don't remember right now.

This is partly derived from the WolfET code for MDM+MDX (GPLv3+ with
additional terms) as it was convenient to reuse the already split
mesh and animation files. (FAKK and WolfET models are both based on
MD4 format but collapse map rendering was only in RTCW/WolfET.)
  • Loading branch information
zturtleman committed Apr 1, 2022
1 parent b46d8cf commit d8f429b
Show file tree
Hide file tree
Showing 8 changed files with 1,378 additions and 8 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,7 @@ Q3ROBJ = \
$(B)/renderergl1/tr_animation.o \
$(B)/renderergl1/tr_animation_mds.o \
$(B)/renderergl1/tr_animation_mdm.o \
$(B)/renderergl1/tr_animation_skb.o \
$(B)/renderergl1/tr_backend.o \
$(B)/renderergl1/tr_bsp.o \
$(B)/renderergl1/tr_cmds.o \
Expand Down Expand Up @@ -2157,6 +2158,7 @@ ifneq ($(SERVER_USE_RENDERER_DLOPEN),1)
$(B)/ded/sv_ref.o \
$(B)/ded/tr_animation_mds.o \
$(B)/ded/tr_animation_mdm.o \
$(B)/ded/tr_animation_skb.o \
$(B)/ded/tr_model.o \
$(B)/ded/tr_model_iqm.o
endif
Expand Down
2 changes: 1 addition & 1 deletion code/qcommon/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -2748,7 +2748,7 @@ char **FS_GetFileList( const char *path, const char *extension, int *numfiles, q
}
else if (Q_stricmp(extension, "$models") == 0)
{
const char *extensions[] = { "md3", "mdr", "mdc", "mds", "mdx", "mdm", "tan", "iqm" };
const char *extensions[] = { "md3", "mdr", "mdc", "mds", "mdx", "mdm", "skb", "ska", "tan", "iqm" };
int extNamesSize = ARRAY_LEN(extensions);
pFiles = FS_ListFilesEx(path, extensions, extNamesSize, &nFiles, allowNonPureFilesOnDisk);
}
Expand Down
128 changes: 128 additions & 0 deletions code/qcommon/qfiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,134 @@ typedef struct {
} mdxHeader_t;


/*
==============================================================================
SKB file format (Heavy Metal FAKK2 Skeletal Mesh)
Ritual's modified version of MD4, split into separate base (mesh) and animation files.
==============================================================================
*/

#define SKB_IDENT ( ( ' ' << 24 ) + ( 'L' << 16 ) + ( 'K' << 8 ) + 'S' )
#define SKB_VERSION 3

// Max verts for collapse map. I set it the same as RTCW/ET limits. --zturtleman
#define SKB_MAX_VERTS 6000

#define SKB_BONEFLAG_LEG 1

typedef struct {
int boneIndex;
float boneWeight;
vec3_t offset;
} skbWeight_t;

typedef struct {
vec3_t normal;
vec2_t texCoords;
int numWeights;
skbWeight_t weights[1]; // variable sized
} skbVertex_t;

typedef struct {
int indexes[3];
} skbTriangle_t;

typedef struct {
int ident;

char name[MAX_QPATH]; // polyset name

int numTriangles;
int numVerts;
int minLod;

int ofsTriangles;
int ofsVerts;
int ofsCollapseMap; // numVerts * int
int ofsEnd; // next surface follows
} skbSurface_t;

typedef struct {
int parent;
int flags;
char name[MAX_QPATH]; // name of bone
} skbBoneInfo_t;

typedef struct {
int ident;
int version;

char name[MAX_QPATH]; // model name

int numSurfaces;
int numBones;

int ofsBones;
int ofsSurfaces;

int ofsEnd; // end of file
} skbHeader_t;

/*
==============================================================================
SKA file format (Heavy Metal FAKK2 Skeletal Data)
==============================================================================
*/

#define SKA_IDENT ( ( 'N' << 24 ) + ( 'A' << 16 ) + ( 'K' << 8 ) + 'S' )
#define SKA_VERSION 3
#define SKA_MAX_BONES 256 // FIXME: Alice model has 131 bones but I haven't checked all models

// NOTE: uncompressed bone/frame is only used at run-time
typedef struct {
float matrix[3][4];
} skaBone_t;

typedef struct {
vec3_t bounds[2]; // bounds of this frame
vec3_t localOrigin;
float radius; // dist from localOrigin to corner
vec3_t delta; // game movement delta
skaBone_t bones[1]; // [numBones]
} skaFrame_t;

typedef struct {
short rotate[4];
short offset[3];
short zero;
} skaCompBone_t;

typedef struct {
vec3_t bounds[2]; // bounds of this frame
float radius; // dist from localOrigin to corner
vec3_t delta; // game movement delta
skaCompBone_t bones[1]; // [numBones]
} skaCompFrame_t;

typedef struct {
int ident;
int version;

char name[MAX_QPATH]; // model name

int flags;

int numFrames;
int numBones;

float totaltime;
float frametime;
float totaldelta[3];

int ofsFrames; // (skaCompFrame_t + skaCompBone_t[numBones-1]) * numframes
} skaHeader_t;


/*
==============================================================================
Expand Down
Loading

0 comments on commit d8f429b

Please sign in to comment.