mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-11 21:31:30 +00:00
c5cfcc7bfd
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.
224 lines
6.3 KiB
C
224 lines
6.3 KiB
C
/*
|
|
model_sprite.c
|
|
|
|
sprite model loading and caching
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
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
|
|
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
# include <string.h>
|
|
#endif
|
|
#ifdef HAVE_STRINGS_H
|
|
# include <strings.h>
|
|
#endif
|
|
|
|
#include "QF/qendian.h"
|
|
#include "QF/sys.h"
|
|
|
|
#include "mod_internal.h"
|
|
#include "qfalloca.h"
|
|
|
|
void
|
|
Mod_LoadSpriteFrame (mspriteframe_t *frame, const dspriteframe_t *dframe)
|
|
{
|
|
frame->width = dframe->width;
|
|
frame->height = dframe->height;
|
|
|
|
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 *
|
|
skip_frame (dspriteframe_t *frame)
|
|
{
|
|
__auto_type pixels = (byte *) (frame + 1);
|
|
return pixels + frame->width * frame->height;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
__auto_type interval = (dspriteinterval_t *) (dgroup + 1);
|
|
for (int i = 0; i < numframes; i++) {
|
|
(*group)->intervals[i] = interval->interval;
|
|
interval++;
|
|
}
|
|
__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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
__auto_type dsprite = (dsprite_t *) buffer;
|
|
msprite_t *sprite;
|
|
|
|
if (LittleLong (dsprite->version) != SPR_VERSION) {
|
|
Sys_Error ("%s has wrong version number (%i should be %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);
|
|
}
|