mirror of
https://github.com/odamex/odamex
synced 2026-08-19 02:23:09 -04:00
281 lines
7.3 KiB
C++
281 lines
7.3 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
// Copyright (C) 2006-2026 by The Odamex Team.
|
|
//
|
|
// 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.
|
|
//
|
|
// DESCRIPTION:
|
|
// Loading sprites, skins.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "odamex.h"
|
|
|
|
#include "r_sprites.h"
|
|
|
|
#include "m_alloc.h"
|
|
|
|
#include "i_system.h"
|
|
#include "z_zone.h"
|
|
#include "w_wad.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#define SPRITE_NEEDS_INFO limits::MAXINT
|
|
|
|
//
|
|
// INITIALIZATION FUNCTIONS
|
|
//
|
|
OHashTable<int32_t, spritedef_t> sprites;
|
|
int numsprites;
|
|
|
|
spriteframe_t sprtemp[MAX_SPRITE_FRAMES];
|
|
int maxframe;
|
|
|
|
// [CMB] This function assumes that sprnames has the correct sprites in order
|
|
void R_CacheSprite(const spritedef_t *sprite)
|
|
{
|
|
auto it = sprnames.find(sprite->spritenum);
|
|
DPrintFmt("cache sprite {}\n",
|
|
it != sprnames.end() ? it->second : "");
|
|
for (int i = 0; i < sprite->numframes; i++)
|
|
{
|
|
for (int r = 0; r < 16; r++)
|
|
{
|
|
if (sprite->spriteframes[i].width[r] == SPRITE_NEEDS_INFO)
|
|
{
|
|
if (sprite->spriteframes[i].lump[r] == -1)
|
|
I_Error("Sprite {}, rotation {} has no lump", i, r);
|
|
|
|
patch_t* patch = W_CachePatch(sprite->spriteframes[i].lump[r]);
|
|
sprite->spriteframes[i].width[r] = patch->width()<<FRACBITS;
|
|
sprite->spriteframes[i].offset[r] = patch->leftoffset()<<FRACBITS;
|
|
sprite->spriteframes[i].topoffset[r] = patch->topoffset()<<FRACBITS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// R_InstallSpriteLump
|
|
// Local function for R_InitSprites.
|
|
//
|
|
// [RH] Removed checks for coexistance of rotation 0 with other
|
|
// rotations and made it look more like BOOM's version.
|
|
//
|
|
static void R_InstallSpriteLump(int lump, unsigned frame, unsigned rot, bool flipped)
|
|
{
|
|
unsigned rotation;
|
|
|
|
if (rot <= 9)
|
|
rotation = rot;
|
|
else
|
|
rotation = (rot >= 17) ? rot - 7 : 17;
|
|
|
|
if (frame >= MAX_SPRITE_FRAMES || rotation > 16)
|
|
I_FatalError("R_InstallSpriteLump: Bad frame characters in lump {}: {}", lump, W_GetOLumpName(lump));
|
|
|
|
if (static_cast<int>(frame) > maxframe)
|
|
maxframe = frame;
|
|
|
|
if (rotation == 0)
|
|
{
|
|
// the lump should be used for all rotations
|
|
// false=0, true=1, but array initialised to -1
|
|
// allows doom to have a "no value set yet" boolean value!
|
|
for (int r = 14; r >= 0; r -= 2)
|
|
{
|
|
if (sprtemp[frame].lump[r] == -1)
|
|
{
|
|
sprtemp[frame].lump[r] = lump;
|
|
sprtemp[frame].flip[r] = flipped;
|
|
sprtemp[frame].rotate = false;
|
|
sprtemp[frame].width[r] = SPRITE_NEEDS_INFO;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
rotation = (rotation <= 8 ? (rotation - 1) * 2 : (rotation - 9) * 2 + 1);
|
|
|
|
if (sprtemp[frame].lump[rotation] == -1)
|
|
{
|
|
// the lump is only used for one rotation
|
|
sprtemp[frame].lump[rotation] = lump;
|
|
sprtemp[frame].flip[rotation] = flipped;
|
|
sprtemp[frame].rotate = true;
|
|
sprtemp[frame].width[rotation] = SPRITE_NEEDS_INFO;
|
|
}
|
|
}
|
|
|
|
|
|
// [RH] Seperated out of R_InitSpriteDefs()
|
|
static void R_InstallSprite(const char *name, int32_t num)
|
|
{
|
|
if (maxframe == -1)
|
|
{
|
|
sprites[num].numframes = 0;
|
|
return;
|
|
}
|
|
|
|
char sprname[5];
|
|
strncpy (sprname, name, 4);
|
|
sprname[4] = 0;
|
|
|
|
maxframe++;
|
|
|
|
for (int frame = 0 ; frame < maxframe ; frame++)
|
|
{
|
|
switch (static_cast<int>(sprtemp[frame].rotate))
|
|
{
|
|
case -1:
|
|
// no rotations were found for that frame at all
|
|
I_FatalError ("R_InstallSprite: No patches found for {} frame {:c}", sprname, frame+'A');
|
|
break;
|
|
|
|
case 0:
|
|
// only the first rotation is needed
|
|
break;
|
|
|
|
case 1:
|
|
// must have all 16 frames
|
|
{
|
|
for (int rotation = 0; rotation < 16; rotation += 2)
|
|
{
|
|
if (sprtemp[frame].lump[rotation + 1] == -1)
|
|
{
|
|
sprtemp[frame].lump[rotation + 1] = sprtemp[frame].lump[rotation];
|
|
sprtemp[frame].flip[rotation + 1] = sprtemp[frame].flip[rotation];
|
|
sprtemp[frame].width[rotation + 1] = SPRITE_NEEDS_INFO;
|
|
}
|
|
|
|
if (sprtemp[frame].lump[rotation] == -1)
|
|
{
|
|
sprtemp[frame].lump[rotation] = sprtemp[frame].lump[rotation + 1];
|
|
sprtemp[frame].flip[rotation] = sprtemp[frame].flip[rotation + 1];
|
|
sprtemp[frame].width[rotation] = SPRITE_NEEDS_INFO;
|
|
}
|
|
}
|
|
|
|
for (int rotation = 0; rotation < 16; ++rotation)
|
|
{
|
|
if (sprtemp[frame].lump[rotation] == -1)
|
|
{
|
|
I_FatalError("R_InstallSprite: Sprite {} frame {:c} is missing rotations",
|
|
sprname, frame + 'A');
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// allocate space for the frames present and copy sprtemp to it
|
|
sprites[num].numframes = maxframe;
|
|
sprites[num].spriteframes = (spriteframe_t *)
|
|
Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
|
|
memcpy (sprites[num].spriteframes, sprtemp, maxframe * sizeof(spriteframe_t));
|
|
sprites[num].spritenum = num;
|
|
}
|
|
|
|
|
|
//
|
|
// R_InitSpriteDefs
|
|
// Pass a null terminated list of sprite names
|
|
// (4 chars exactly) to be used.
|
|
// Builds the sprite rotation matrices to account
|
|
// for horizontally flipped sprites.
|
|
// Will report an error if the lumps are inconsistent.
|
|
// Only called at startup.
|
|
//
|
|
// Sprite lump names are 4 characters for the actor,
|
|
// a letter for the frame, and a number for the rotation.
|
|
// A sprite that is flippable will have an additional
|
|
// letter/number appended.
|
|
// The rotation character can be 0 to signify no rotations.
|
|
//
|
|
static void R_InitSpriteDefs(std::vector<spriteinfo_t*>& namelist)
|
|
{
|
|
numsprites = namelist.size();
|
|
|
|
// scan all the lump names for each of the names,
|
|
// noting the highest frame letter.
|
|
// Just compare 4 characters as ints
|
|
for (int i = 0; i < numsprites; i++)
|
|
{
|
|
memset (sprtemp, -1, sizeof(sprtemp));
|
|
|
|
for (int i = 0; i < MAX_SPRITE_FRAMES; i++) {
|
|
sprtemp[i].rotate = false;
|
|
}
|
|
|
|
maxframe = -1;
|
|
const int intname = *(int *)namelist[i]->sprite;
|
|
|
|
// scan the lumps,
|
|
// filling in the frames for whatever is found
|
|
for (int l = lastspritelump; l >= firstspritelump; l--)
|
|
{
|
|
if (*(int*)lumpinfo[l].name.c_str() == intname && lumpinfo[l].size > 0)
|
|
{
|
|
R_InstallSpriteLump (l,
|
|
lumpinfo[l].name[4] - 'A', // denis - fixme - security
|
|
lumpinfo[l].name[5] - '0',
|
|
false);
|
|
|
|
if (lumpinfo[l].name[6])
|
|
R_InstallSpriteLump (l,
|
|
lumpinfo[l].name[6] - 'A',
|
|
lumpinfo[l].name[7] - '0',
|
|
true);
|
|
}
|
|
}
|
|
|
|
R_InstallSprite(namelist[i]->sprite, namelist[i]->spritenum);
|
|
}
|
|
}
|
|
|
|
//
|
|
// GAME FUNCTIONS
|
|
//
|
|
int MaxVisSprites;
|
|
vissprite_t *vissprites;
|
|
vissprite_t *firstvissprite;
|
|
vissprite_t *lastvissprite;
|
|
|
|
|
|
|
|
//
|
|
// R_InitSprites
|
|
// Called at program start.
|
|
//
|
|
void R_InitSprites(std::vector<spriteinfo_t*>& sprites)
|
|
{
|
|
MaxVisSprites = 128; // [RH] This is the initial default value. It grows as needed.
|
|
|
|
M_Free(vissprites);
|
|
|
|
firstvissprite = vissprites = (vissprite_t *) M_Malloc(MaxVisSprites * sizeof(vissprite_t));
|
|
lastvissprite = &vissprites[MaxVisSprites];
|
|
|
|
R_InitSpriteDefs (sprites);
|
|
}
|
|
|
|
VERSION_CONTROL (r_sprites_cpp, "$Id$")
|
|
|