[sprite] Separate model and texture loading

As much as it can be since the texture data is interleaved with the
model data in the files (I guess not that bad a design for 25 years ago
with the tight memory constraints), but this paves the way for
supporting sprites in Vulkan.
This commit is contained in:
Bill Currie 2021-12-14 08:36:19 +09:00
parent 6eed89151c
commit c5cfcc7bfd
12 changed files with 237 additions and 161 deletions

View file

@ -280,7 +280,6 @@ typedef struct mod_brush_s {
// SPRITE MODELS ==============================================================
// FIXME: shorten these?
typedef struct mspriteframe_s {
int width;
int height;
@ -304,11 +303,10 @@ typedef struct {
} mspriteframedesc_t;
typedef struct {
int type;
int maxwidth;
int maxheight;
float beamlength;
int numframes;
int type;
float beamlength;
int numframes;
int data;
mspriteframedesc_t frames[1];
} msprite_t;

View file

@ -38,6 +38,7 @@ struct cvar_s;
struct skin_s;
struct mod_alias_ctx_s;
struct mod_sprite_ctx_s;
/*
All video plugins must export these functions
@ -99,8 +100,7 @@ typedef struct vid_model_funcs_s {
void (*Mod_LoadExternalSkins) (struct mod_alias_ctx_s *alias_ctx);
void (*Mod_IQMFinish) (model_t *mod);
int alias_cache;
void (*Mod_SpriteLoadTexture) (model_t *mod, mspriteframe_t *pspriteframe,
int framenum);
void (*Mod_SpriteLoadFrames) (struct mod_sprite_ctx_s *sprite_ctx);
struct skin_s *(*Skin_SetColormap) (struct skin_s *skin, int cmap);
struct skin_s *(*Skin_SetSkin) (struct skin_s *skin, int cmap,

View file

@ -19,9 +19,18 @@ typedef struct mod_alias_ctx_s {
trivertxset_t poseverts;
int aliasbboxmins[3];
int aliasbboxmaxs[3];
} mod_alias_ctx_t;
typedef struct mod_sprite_ctx_s {
model_t *mod;
dsprite_t *dsprite;
msprite_t *sprite;
int numframes;
int *frame_numbers;
dspriteframe_t **dframes; ///< array of pointers to dframes (in)
mspriteframe_t ***frames; ///< array of pointers to mframe pointers (out)
} mod_sprite_ctx_t;
int Mod_CalcFullbright (byte *out, const byte *in, size_t pixels);
int Mod_ClearFullbright (byte *out, const byte *in, size_t pixels);
void Mod_FloodFillSkin (byte *skin, int skinwidth, int skinheight);
@ -79,12 +88,10 @@ void Vulkan_Mod_SubdivideSurface (model_t *mod, msurface_t *fa,
void Vulkan_Mod_ProcessTexture (model_t *mod, texture_t *tx,
struct vulkan_ctx_s *ctx);
void gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum);
void glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum);
void sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum);
void Mod_LoadSpriteFrame (mspriteframe_t *frame, const dspriteframe_t *dframe);
void gl_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx);
void glsl_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx);
void sw_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx);
void Mod_LoadIQM (model_t *mod, void *buffer);
void Mod_FreeIQM (iqm_t *iqm);

View file

@ -43,26 +43,36 @@
#include "compat.h"
#include "mod_internal.h"
void
gl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum)
static int
load_texture (model_t *mod, int framenum, const dspriteframe_t *dframe)
{
tex_t *targa;
const char *name;
targa = LoadImage (name = va (0, "%s_%i", mod->path, framenum), 1);
if (targa) {
if (targa->format < 4)
pspriteframe->gl_texturenum = GL_LoadTexture (name,
targa->width, targa->height, targa->data,
true, false, 3);
else
pspriteframe->gl_texturenum = GL_LoadTexture (name,
targa->width, targa->height, targa->data,
true, true, 4);
return;
if (targa->format < 4) {
return GL_LoadTexture (name, targa->width, targa->height,
targa->data, true, false, 3);
} else {
return GL_LoadTexture (name, targa->width, targa->height,
targa->data, true, true, 4);
}
}
return GL_LoadTexture (name, dframe->width, dframe->height,
(const byte *)(dframe + 1), true, true, 1);
}
void
gl_Mod_SpriteLoadFrames (mod_sprite_ctx_t *ctx)
{
for (int i = 0; i < ctx->numframes; i++) {
__auto_type dframe = ctx->dframes[i];
size_t size = sizeof (mspriteframe_t);
mspriteframe_t *frame = Hunk_AllocName (0, size, ctx->mod->name);
*ctx->frames[i] = frame;
Mod_LoadSpriteFrame (frame, dframe);
frame->gl_texturenum = load_texture (ctx->mod, ctx->frame_numbers[i],
dframe);
}
pspriteframe->gl_texturenum =
GL_LoadTexture (name, pspriteframe->width, pspriteframe->height,
pspriteframe->pixels, true, true, 1);
}

View file

@ -71,14 +71,19 @@ glsl_sprite_clear (model_t *m, void *data)
}
void
glsl_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum)
glsl_Mod_SpriteLoadFrames (mod_sprite_ctx_t *ctx)
{
const char *name;
mod->clear = glsl_sprite_clear;
name = va (0, "%s_%i", mod->path, framenum);
pspriteframe->gl_texturenum =
GLSL_LoadQuakeTexture (name, pspriteframe->width, pspriteframe->height,
pspriteframe->pixels);
ctx->mod->clear = glsl_sprite_clear;
for (int i = 0; i < ctx->numframes; i++) {
__auto_type dframe = ctx->dframes[i];
size_t size = sizeof (mspriteframe_t);
mspriteframe_t *frame = Hunk_AllocName (0, size, ctx->mod->name);
*ctx->frames[i] = frame;
Mod_LoadSpriteFrame (frame, dframe);
const char *name = va (0, "%s_%i", ctx->mod->path,
ctx->frame_numbers[i]);
frame->gl_texturenum =
GLSL_LoadQuakeTexture (name, dframe->width, dframe->height,
(const byte *)(dframe + 1));
}
}

View file

@ -38,144 +38,187 @@
#include "QF/qendian.h"
#include "QF/sys.h"
#include "compat.h"
#include "mod_internal.h"
#include "qfalloca.h"
static void *
Mod_LoadSpriteFrame (model_t *mod, void *pin, mspriteframe_t **frame,
int framenum)
void
Mod_LoadSpriteFrame (mspriteframe_t *frame, const dspriteframe_t *dframe)
{
dspriteframe_t *in_frame;
int width, height, size, origin[2];
frame->width = dframe->width;
frame->height = dframe->height;
in_frame = (dspriteframe_t *) pin;
width = LittleLong (in_frame->width);
height = LittleLong (in_frame->height);
size = width * height;
*frame = Hunk_AllocName (0, sizeof (mspriteframe_t) + size, mod->name);
(*frame)->width = width;
(*frame)->height = height;
origin[0] = LittleLong (in_frame->origin[0]);
origin[1] = LittleLong (in_frame->origin[1]);
(*frame)->up = origin[1];
(*frame)->down = origin[1] - height;
(*frame)->left = origin[0];
(*frame)->right = width + origin[0];
memcpy ((*frame)->pixels, (byte *) (in_frame + 1), size);
m_funcs->Mod_SpriteLoadTexture (mod, *frame, framenum);
return (void *) ((byte *) in_frame + sizeof (dspriteframe_t) + size);
frame->up = dframe->origin[1];
frame->down = dframe->origin[1] - dframe->height;
frame->left = dframe->origin[0];
frame->right = dframe->width + dframe->origin[0];
}
static void *
Mod_LoadSpriteGroup (model_t *mod, void *pin, mspritegroup_t **group,
int framenum)
skip_frame (dspriteframe_t *frame)
{
dspritegroup_t *in_group;
dspriteinterval_t *in_intervals;
float *intervals;
int numframes, i;
void *temp;
__auto_type pixels = (byte *) (frame + 1);
return pixels + frame->width * frame->height;
}
in_group = (dspritegroup_t *) pin;
static void *
swap_frame (dspriteframe_t *frame)
{
for (int i = 0; i < 2; i++) {
frame->origin[i] = LittleLong (frame->origin[i]);
}
frame->width = LittleLong (frame->width);
frame->height = LittleLong (frame->height);
return skip_frame (frame);
}
numframes = LittleLong (in_group->numframes);
static void *
swap_group (dspritegroup_t *group)
{
group->numframes = LittleLong (group->numframes);
__auto_type interval = (dspriteinterval_t *) (group + 1);
for (int i = 0; i < group->numframes; i++) {
interval->interval = LittleFloat (interval->interval);
interval++;
}
__auto_type frame = (dspriteframe_t *) interval;
for (int i = 0; i < group->numframes; i++) {
frame = swap_frame (frame);
}
return frame + 1;
}
int size = field_offset (mspritegroup_t, frames[numframes]);
*group = Hunk_AllocName (0, size, mod->name);
static int
swap_sprite (dsprite_t *sprite)
{
sprite->ident = LittleLong (sprite->ident);
sprite->version = LittleLong (sprite->version);
sprite->type = LittleLong (sprite->type);
sprite->boundingradius = LittleFloat (sprite->boundingradius);
sprite->width = LittleLong (sprite->width);
sprite->height = LittleLong (sprite->height);
sprite->numframes = LittleLong (sprite->numframes);
sprite->beamlength = LittleFloat (sprite->beamlength);
sprite->synctype = LittleLong (sprite->synctype);
int numframes = 0;
__auto_type type = (dspriteframetype_t *) (sprite + 1);
for (int i = 0; i < sprite->numframes; i++) {
type->type = LittleLong (type->type);
if (type->type == SPR_SINGLE) {
__auto_type frame = (dspriteframe_t *) (type + 1);
type = swap_frame (frame);
numframes += 1;
} else {
__auto_type group = (dspritegroup_t *) (type + 1);
type = swap_group (group);
numframes += group->numframes;
}
}
return numframes;
}
static void *
find_group_frames (mspritegroup_t **group, dspritegroup_t *dgroup,
mspriteframe_t ***frames, dspriteframe_t **dframes,
int *frame_numbers, const char *modname)
{
int numframes = dgroup->numframes;
size_t size = field_offset (mspritegroup_t, frames[numframes]);
*group = Hunk_AllocName (0, size, modname);
(*group)->numframes = numframes;
(*group)->intervals = Hunk_AllocName (0, numframes * sizeof (float),
modname);
in_intervals = (dspriteinterval_t *) (in_group + 1);
intervals = Hunk_AllocName (0, numframes * sizeof (float), mod->name);
(*group)->intervals = intervals;
for (i = 0; i < numframes; i++) {
*intervals = LittleFloat (in_intervals->interval);
if (*intervals <= 0.0)
Sys_Error ("Mod_LoadSpriteGroup: interval<=0");
intervals++;
in_intervals++;
__auto_type interval = (dspriteinterval_t *) (dgroup + 1);
for (int i = 0; i < numframes; i++) {
(*group)->intervals[i] = interval->interval;
interval++;
}
temp = (void *) in_intervals;
for (i = 0; i < numframes; i++) {
temp = Mod_LoadSpriteFrame (mod, temp, &(*group)->frames[i],
framenum * 100 + i);
__auto_type dframe = (dspriteframe_t *) interval;
for (int i = 0; i < numframes; i++) {
frames[i] = &(*group)->frames[i];
dframes[i] = dframe;
frame_numbers[i] = i;
dframe = skip_frame (dframe);
}
return dframe;
}
return temp;
static void
find_frames (msprite_t *sprite, dsprite_t *dsprite,
mspriteframe_t ***frames, dspriteframe_t **dframes,
int *frame_numbers, const char *modname)
{
int frame_index = 0;
__auto_type type = (dspriteframetype_t *) (dsprite + 1);
for (int i = 0; i < dsprite->numframes; i++) {
sprite->frames[i].type = type->type;
if (type->type == SPR_SINGLE) {
__auto_type frame = (dspriteframe_t *) (type + 1);
dframes[frame_index] = frame;
frames[frame_index] = &sprite->frames[i].frame;
frame_numbers[frame_index] = i;
frame_index += 1;
type = skip_frame (frame);
} else {
__auto_type group = (dspritegroup_t *) (type + 1);
type = find_group_frames (&sprite->frames[i].group, group,
frames + frame_index,
dframes + frame_index,
frame_numbers + frame_index,
modname);
for (int j = 0; j < group->numframes; j++) {
frame_numbers[frame_index + j] += i * 100;
}
frame_index += group->numframes;
}
}
}
void
Mod_LoadSpriteModel (model_t *mod, void *buffer)
{
dsprite_t *pin;
dspriteframetype_t *pframetype;
int numframes, size, version, i;
msprite_t *psprite;
__auto_type dsprite = (dsprite_t *) buffer;
msprite_t *sprite;
pin = (dsprite_t *) buffer;
version = LittleLong (pin->version);
if (version != SPR_VERSION)
if (LittleLong (dsprite->version) != SPR_VERSION) {
Sys_Error ("%s has wrong version number (%i should be %i)",
mod->path, version, SPR_VERSION);
numframes = LittleLong (pin->numframes);
size = field_offset (msprite_t, frames[numframes]);
psprite = Hunk_AllocName (0, size, mod->name);
mod->cache.data = psprite;
psprite->type = LittleLong (pin->type);
psprite->maxwidth = LittleLong (pin->width);
psprite->maxheight = LittleLong (pin->height);
psprite->beamlength = LittleFloat (pin->beamlength);
mod->synctype = LittleLong (pin->synctype);
psprite->numframes = numframes;
mod->mins[0] = mod->mins[1] = -psprite->maxwidth / 2;
mod->maxs[0] = mod->maxs[1] = psprite->maxwidth / 2;
mod->mins[2] = -psprite->maxheight / 2;
mod->maxs[2] = psprite->maxheight / 2;
// load the frames
if (numframes < 1)
Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d", numframes);
mod->numframes = numframes;
pframetype = (dspriteframetype_t *) (pin + 1);
for (i = 0; i < numframes; i++) {
spriteframetype_t frametype;
frametype = LittleLong (pframetype->type);
psprite->frames[i].type = frametype;
if (frametype == SPR_SINGLE) {
pframetype = (dspriteframetype_t *)
Mod_LoadSpriteFrame (mod, pframetype + 1,
&psprite->frames[i].frame, i);
} else {
pframetype = (dspriteframetype_t *)
Mod_LoadSpriteGroup (mod, pframetype + 1,
&psprite->frames[i].group, i);
}
mod->path, LittleLong (dsprite->version), SPR_VERSION);
}
// total number of frames (direct and in groups)
int numframes = swap_sprite (dsprite);
if (numframes < 1) {
Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d", numframes);
}
sprite = Hunk_AllocName (0, field_offset (msprite_t,
frames[dsprite->numframes]),
mod->name);
sprite->type = dsprite->type;
sprite->beamlength = dsprite->beamlength;
sprite->numframes = dsprite->numframes;
sprite->data = 0;
mod->cache.data = sprite;
mod->mins[0] = mod->mins[1] = -dsprite->width / 2;
mod->maxs[0] = mod->maxs[1] = dsprite->width / 2;
mod->mins[2] = -dsprite->height / 2;
mod->maxs[2] = dsprite->height / 2;
mod->numframes = dsprite->numframes;
mod->type = mod_sprite;
mod_sprite_ctx_t sprite_ctx = {
.mod = mod,
.dsprite = dsprite,
.sprite = sprite,
.numframes = numframes,
.frame_numbers = alloca (numframes * sizeof (int)),
.dframes = alloca (numframes * sizeof (dspriteframe_t *)),
.frames = alloca (numframes * sizeof (mspriteframe_t **)),
};
find_frames (sprite, dsprite, sprite_ctx.frames, sprite_ctx.dframes,
sprite_ctx.frame_numbers, mod->name);
m_funcs->Mod_SpriteLoadFrames (&sprite_ctx);
}

View file

@ -28,10 +28,24 @@
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#include "QF/zone.h"
#include "mod_internal.h"
void
sw_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum)
sw_Mod_SpriteLoadFrames (mod_sprite_ctx_t *ctx)
{
for (int i = 0; i < ctx->numframes; i++) {
__auto_type dframe = ctx->dframes[i];
size_t pixels = dframe->width * dframe->height;
size_t size = field_offset (mspriteframe_t, pixels[pixels]);
mspriteframe_t *frame = Hunk_AllocName (0, size, ctx->mod->name);
*ctx->frames[i] = frame;
Mod_LoadSpriteFrame (frame, dframe);
memcpy (frame->pixels, dframe + 1, pixels);
}
}

View file

@ -74,7 +74,7 @@ static vid_model_funcs_t model_funcs = {
gl_Mod_LoadExternalSkins,
gl_Mod_IQMFinish,
1,
gl_Mod_SpriteLoadTexture,
gl_Mod_SpriteLoadFrames,
Skin_SetColormap,
Skin_SetSkin,

View file

@ -74,7 +74,7 @@ static vid_model_funcs_t model_funcs = {
glsl_Mod_LoadExternalSkins,
glsl_Mod_IQMFinish,
0,
glsl_Mod_SpriteLoadTexture,
glsl_Mod_SpriteLoadFrames,
Skin_SetColormap,
Skin_SetSkin,

View file

@ -72,7 +72,7 @@ static vid_model_funcs_t model_funcs = {
0,
sw_Mod_IQMFinish,
1,
sw_Mod_SpriteLoadTexture,
sw_Mod_SpriteLoadFrames,
Skin_SetColormap,
Skin_SetSkin,

View file

@ -77,7 +77,7 @@ static vid_model_funcs_t model_funcs = {
0,
sw_Mod_IQMFinish,
1,
sw_Mod_SpriteLoadTexture,
sw_Mod_SpriteLoadFrames,
Skin_SetColormap,
Skin_SetSkin,

View file

@ -505,8 +505,7 @@ vulkan_Mod_IQMFinish (model_t *mod)
}
static void
vulkan_Mod_SpriteLoadTexture (model_t *mod, mspriteframe_t *pspriteframe,
int framenum)
vulkan_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx)
{
}
@ -582,7 +581,7 @@ static vid_model_funcs_t model_funcs = {
vulkan_Mod_LoadExternalSkins,
vulkan_Mod_IQMFinish,
0,
vulkan_Mod_SpriteLoadTexture,
vulkan_Mod_SpriteLoadFrames,
Skin_SetColormap,
Skin_SetSkin,