diff --git a/include/QF/model.h b/include/QF/model.h index 0efd7be00..9f308e997 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -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; diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 699bef12e..8ed240c84 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -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, diff --git a/include/mod_internal.h b/include/mod_internal.h index b82de630b..9126a3280 100644 --- a/include/mod_internal.h +++ b/include/mod_internal.h @@ -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); diff --git a/libs/models/sprite/gl_model_sprite.c b/libs/models/sprite/gl_model_sprite.c index 2abef1dfc..546e97e96 100644 --- a/libs/models/sprite/gl_model_sprite.c +++ b/libs/models/sprite/gl_model_sprite.c @@ -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); } diff --git a/libs/models/sprite/glsl_model_sprite.c b/libs/models/sprite/glsl_model_sprite.c index ae1f12a10..c6f267d57 100644 --- a/libs/models/sprite/glsl_model_sprite.c +++ b/libs/models/sprite/glsl_model_sprite.c @@ -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)); + } } diff --git a/libs/models/sprite/model_sprite.c b/libs/models/sprite/model_sprite.c index a38d66dfa..1bd9ca2cc 100644 --- a/libs/models/sprite/model_sprite.c +++ b/libs/models/sprite/model_sprite.c @@ -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); } diff --git a/libs/models/sprite/sw_model_sprite.c b/libs/models/sprite/sw_model_sprite.c index 8dc5a5461..6834413e9 100644 --- a/libs/models/sprite/sw_model_sprite.c +++ b/libs/models/sprite/sw_model_sprite.c @@ -28,10 +28,24 @@ # include "config.h" #endif +#ifdef HAVE_STRING_H +# include +#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); + } } diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 380ab3ca2..850d13beb 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -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, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 17e7be558..a4ad536f4 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -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, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 992292c7f..cc0186750 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -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, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 4139b9008..3a3638c1a 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -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, diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 0114610b8..c2a5cca21 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -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,