Merge branch 'public_hexang' into 'next'

Hexafaceted sprite angle support.

See merge request STJr/SRB2!652
This commit is contained in:
James R 2020-01-09 16:14:49 -05:00
commit 57a31077e7
7 changed files with 135 additions and 88 deletions

View file

@ -5493,7 +5493,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
spriteinfo_t *sprinfo;
size_t lumpoff;
unsigned rot;
UINT8 flip;
UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
angle_t ang;
@ -5579,12 +5579,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip = sprframe->flip; // Will only be 0x00 or 0xFF
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 255;
}
flip ^= 0xFFFF;
}
else
{
@ -5593,6 +5588,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
rot = 2; // F3 slot
else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
{
rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
rot = ((rot & 1)<<3)|(rot>>1);
}
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
@ -5601,12 +5601,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
flip = sprframe->flip & (1<<rot);
if (papersprite && ang < ANGLE_180)
{
if (flip)
flip = 0;
else
flip = 1<<rot;
}
flip ^= (1<<rot);
}
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
@ -5621,7 +5616,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->rollangle)
{
rollangle = R_GetRollAngle(thing->rollangle);
if (!sprframe->rotsprite.cached[rot])
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)

View file

@ -468,11 +468,11 @@ static int libd_getSpritePatch(lua_State *L)
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
if (angle != 0)
angle--;
if (angle >= 8) // out of range?
if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
return 0;
// push both the patch and it's "flip" value
@ -563,11 +563,11 @@ static int libd_getSprite2Patch(lua_State *L)
// convert WAD editor angle numbers (1-8) to internal angle numbers (0-7)
// keep 0 the same since we'll make it default to angle 1 (which is internally 0)
// in case somebody didn't know that angle 0 really just maps all 8 angles to the same patch
// in case somebody didn't know that angle 0 really just maps all 8/16 angles to the same patch
if (angle != 0)
angle--;
if (angle >= 8) // out of range?
if (angle >= ((sprframe->rotate & SRF_3DGE) ? 16 : 8)) // out of range?
return 0;
// push both the patch and it's "flip" value

View file

@ -2710,14 +2710,29 @@ void R_PrecacheLevel(void)
for (j = 0; j < sprites[i].numframes; j++)
{
sf = &sprites[i].spriteframes[j];
for (k = 0; k < 8; k++)
{
// see R_InitSprites for more about lumppat,lumpid
lump = sf->lumppat[k];
if (devparm)
spritememory += W_LumpLength(lump);
W_CachePatchNum(lump, PU_PATCH);
#define cacheang(a) {\
lump = sf->lumppat[a];\
if (devparm)\
spritememory += W_LumpLength(lump);\
W_CachePatchNum(lump, PU_PATCH);\
}
// see R_InitSprites for more about lumppat,lumpid
switch (sf->rotate)
{
case SRF_SINGLE:
cacheang(0);
break;
case SRF_2D:
cacheang(2);
cacheang(6);
break;
default:
k = (sf->rotate & SRF_3DGE ? 16 : 8);
while (k--)
cacheang(k);
break;
}
#undef cacheang
}
}
free(spritepresent);

View file

@ -727,8 +727,8 @@ typedef struct
#ifdef ROTSPRITE
typedef struct
{
patch_t *patch[8][ROTANGLES];
boolean cached[8];
patch_t *patch[16][ROTANGLES];
UINT16 cached;
} rotsprite_t;
#endif/*ROTSPRITE*/
@ -736,9 +736,11 @@ typedef enum
{
SRF_SINGLE = 0, // 0-angle for all rotations
SRF_3D = 1, // Angles 1-8
SRF_LEFT = 2, // Left side uses single patch
SRF_RIGHT = 4, // Right side uses single patch
SRF_2D = SRF_LEFT|SRF_RIGHT, // 6
SRF_3DGE = 2, // 3DGE, ZDoom and Doom Legacy all have 16-angle support. Why not us?
SRF_3DMASK = SRF_3D|SRF_3DGE, // 3
SRF_LEFT = 4, // Left side uses single patch
SRF_RIGHT = 8, // Right side uses single patch
SRF_2D = SRF_LEFT|SRF_RIGHT, // 12
SRF_NONE = 0xff // Initial value
} spriterotateflags_t; // SRF's up!
@ -764,7 +766,7 @@ typedef struct patchinfo_s patchinfo_t;
// Sprites are patches with a special naming convention so they can be
// recognized by R_InitSprites.
// The base name is NNNNFx or NNNNFxFx, with x indicating the rotation,
// x = 0, 1-8, L/R
// x = 0, 1-8, 9+A-G, L/R
// The sprite and frame specified by a thing_t is range checked at run time.
// A sprite is a patch_t that is assumed to represent a three dimensional
// object and may have multiple rotations predrawn.
@ -781,12 +783,12 @@ typedef struct
// name eight times.
UINT8 rotate; // see spriterotateflags_t above
// Lump to use for view angles 0-7.
lumpnum_t lumppat[8]; // lump number 16 : 16 wad : lump
size_t lumpid[8]; // id in the spriteoffset, spritewidth, etc. tables
// Lump to use for view angles 0-7/15.
lumpnum_t lumppat[16]; // lump number 16 : 16 wad : lump
size_t lumpid[16]; // id in the spriteoffset, spritewidth, etc. tables
// Flip bits (1 = flip) to use for view angles 0-7.
UINT8 flip;
// Flip bits (1 = flip) to use for view angles 0-7/15.
UINT16 flip;
#ifdef ROTSPRITE
rotsprite_t rotsprite;

View file

@ -1205,7 +1205,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
#define ROTSPRITE_XCENTER (newwidth / 2)
#define ROTSPRITE_YCENTER (newheight / 2)
if (!sprframe->rotsprite.cached[rot])
if (!(sprframe->rotsprite.cached & (1<<rot)))
{
INT32 dx, dy;
INT32 px, py;
@ -1375,7 +1375,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp
}
// This rotation is cached now
sprframe->rotsprite.cached[rot] = true;
sprframe->rotsprite.cached |= (1<<rot);
// free image data
Z_Free(patch);
@ -1399,9 +1399,9 @@ void R_FreeSingleRotSprite(spritedef_t *spritedef)
for (frame = 0; frame < spritedef->numframes; frame++)
{
spriteframe_t *sprframe = &spritedef->spriteframes[frame];
for (rot = 0; rot < 8; rot++)
for (rot = 0; rot < 16; rot++)
{
if (sprframe->rotsprite.cached[rot])
if (sprframe->rotsprite.cached & (1<<rot))
{
for (ang = 0; ang < ROTANGLES; ang++)
{
@ -1432,7 +1432,7 @@ void R_FreeSingleRotSprite(spritedef_t *spritedef)
Z_Free(rotsprite);
}
}
sprframe->rotsprite.cached[rot] = false;
sprframe->rotsprite.cached &= ~(1<<rot);
}
}
}

View file

@ -105,24 +105,21 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
UINT8 rotation,
UINT8 flipped)
{
char cn = R_Frame2Char(frame); // for debugging
char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
INT32 r, ang;
lumpnum_t lumppat = wad;
lumppat <<= 16;
lumppat += lump;
if (frame >= 64 || !(R_ValidSpriteAngle(rotation)))
I_Error("R_InstallSpriteLump: Bad frame characters in lump %s", W_CheckNameForNum(lumppat));
if (maxframe ==(size_t)-1 || frame > maxframe)
maxframe = frame;
// rotsprite
#ifdef ROTSPRITE
for (r = 0; r < 8; r++)
sprtemp[frame].rotsprite.cached = 0;
for (r = 0; r < 16; r++)
{
sprtemp[frame].rotsprite.cached[r] = false;
for (ang = 0; ang < ROTANGLES; ang++)
sprtemp[frame].rotsprite.patch[r][ang] = NULL;
}
@ -133,16 +130,16 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
// the lump should be used for all rotations
if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8 and L/R rotations into one debug message.
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
sprtemp[frame].rotate = SRF_SINGLE;
for (r = 0; r < 8; r++)
for (r = 0; r < 16; r++)
{
sprtemp[frame].lumppat[r] = lumppat;
sprtemp[frame].lumpid[r] = lumpid;
}
sprtemp[frame].flip = flipped ? 0xFF : 0; // 11111111 in binary
sprtemp[frame].flip = flipped ? 0xFFFF : 0; // 1111111111111111 in binary
return;
}
@ -151,54 +148,67 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0);
// the lump should be used for half of all rotations
if (sprtemp[frame].rotate == SRF_SINGLE)
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate == SRF_3D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
else if (sprtemp[frame].rotate == SRF_3DGE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn);
else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn);
else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn);
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
if (sprtemp[frame].rotate == (SRF_3D|SRF_2D))
sprtemp[frame].rotate = SRF_2D; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
sprtemp[frame].rotate &= ~SRF_3DMASK; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
for (r = 0; r < 4; r++) // Thanks to R_PrecacheLevel, we can't leave sprtemp[*].lumppat[*] == LUMPERROR... so we load into the front/back angle too.
// load into every relevant angle, including the front one
for (r = 0; r < 4; r++)
{
sprtemp[frame].lumppat[r + rightfactor] = lumppat;
sprtemp[frame].lumpid[r + rightfactor] = lumpid;
sprtemp[frame].lumppat[r + rightfactor + 8] = lumppat;
sprtemp[frame].lumpid[r + rightfactor + 8] = lumpid;
}
if (flipped)
sprtemp[frame].flip |= (0x0F<<rightfactor); // 00001111 or 11110000 in binary, depending on rotation being ROT_L or ROT_R
sprtemp[frame].flip |= (0x0F0F<<rightfactor); // 0000111100001111 or 1111000011110000 in binary, depending on rotation being ROT_L or ROT_R
else
sprtemp[frame].flip &= ~(0x0F<<rightfactor); // ditto
sprtemp[frame].flip &= ~(0x0F0F<<rightfactor); // ditto
return;
}
// the lump is only used for one rotation
if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8 rotations and a rot = 0 lump\n", spritename, cn);
else if ((sprtemp[frame].rotate != SRF_3D) && (sprtemp[frame].rotate != SRF_NONE))
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE;
else if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn);
else if (sprtemp[frame].rotate & SRF_2D)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn);
// make 0 based
rotation--;
{
// SRF_3D|SRF_3DGE being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
UINT8 threedrot = (rotation > 7) ? SRF_3DGE : (sprtemp[frame].rotate & SRF_3DMASK);
if (!threedrot)
threedrot = SRF_3D;
if (rotation == 0 || rotation == 4) // Front or back...
sprtemp[frame].rotate = SRF_3D; // Prevent L and R changeover
else if (rotation > 3) // Right side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
else // if (rotation <= 3) // Left side
sprtemp[frame].rotate = (SRF_3D | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
sprtemp[frame].rotate = threedrot; // Prevent L and R changeover
else if ((rotation & 7) > 3) // Right side
sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
else // if ((rotation & 7) <= 3) // Left side
sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
}
if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, '1'+rotation);
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr);
// lumppat & lumpid are the same for original Doom, but different
// when using sprites in pwad : the lumppat points the new graphics
@ -259,9 +269,9 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
if (memcmp(lumpinfo[l].name,sprname,4)==0)
{
frame = R_Char2Frame(lumpinfo[l].name[4]);
rotation = (UINT8)(lumpinfo[l].name[5] - '0');
rotation = R_Char2Rotation(lumpinfo[l].name[5]);
if (frame >= 64 || !(R_ValidSpriteAngle(rotation))) // Give an actual NAME error -_-...
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
{
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue;
@ -308,7 +318,13 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
if (lumpinfo[l].name[6])
{
frame = R_Char2Frame(lumpinfo[l].name[6]);
rotation = (UINT8)(lumpinfo[l].name[7] - '0');
rotation = R_Char2Rotation(lumpinfo[l].name[7]);
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
{
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue;
}
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
}
@ -369,18 +385,19 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
sprname, R_Frame2Char(frame));
break;
default:
// must have all 8 frames
for (rotation = 0; rotation < 8; rotation++)
// must have all 8/16 frames
rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
while (rotation--)
// we test the patch lump, or the id lump whatever
// if it was not loaded the two are LUMPERROR
if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
sprname, R_Frame2Char(frame));
I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
break;
}
}
@ -1094,7 +1111,7 @@ static void R_ProjectSprite(mobj_t *thing)
size_t lump;
size_t rot;
UINT8 flip;
UINT16 flip;
boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP));
INT32 lindex;
@ -1224,7 +1241,7 @@ static void R_ProjectSprite(mobj_t *thing)
// use single rotation for all views
rot = 0; //Fab: for vis->patch below
lump = sprframe->lumpid[0]; //Fab: see note above
flip = sprframe->flip; // Will only be 0x00 or 0xFF
flip = sprframe->flip; // Will only be 0 or 0xFFFF
}
else
{
@ -1235,6 +1252,11 @@ static void R_ProjectSprite(mobj_t *thing)
rot = 6; // F7 slot
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
rot = 2; // F3 slot
else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
{
rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
rot = ((rot & 1)<<3)|(rot>>1);
}
else // Normal behaviour
rot = (ang+ANGLE_202h)>>29;
@ -1257,7 +1279,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (thing->rollangle)
{
rollangle = R_GetRollAngle(thing->rollangle);
if (!sprframe->rotsprite.cached[rot])
if (!(sprframe->rotsprite.cached & (1<<rot)))
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)

View file

@ -20,10 +20,6 @@
#include "r_portal.h"
#include "r_defs.h"
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L ('L' - '0')
#define ROT_R ('R' - '0')
// number of sprite lumps for spritewidth,offset,topoffset lookup tables
// Fab: this is a hack : should allocate the lookup tables per sprite
#define MAXVISSPRITES 2048 // added 2-2-98 was 128
@ -270,7 +266,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
if (cn == '+') return '\\' - 'A'; // PK3 can't use backslash, so use + instead
return cn - 'A';
#else
if (cn >= 'A' && cn <= 'Z') return cn - 'A';
if (cn >= 'A' && cn <= 'Z') return (cn - 'A');
if (cn >= '0' && cn <= '9') return (cn - '0') + 26;
if (cn >= 'a' && cn <= 'z') return (cn - 'a') + 36;
if (cn == '!') return 62;
@ -279,9 +275,26 @@ FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Frame(char cn)
#endif
}
FUNCMATH FUNCINLINE static ATTRINLINE boolean R_ValidSpriteAngle(UINT8 rotation)
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L 17
#define ROT_R 18
FUNCMATH FUNCINLINE static ATTRINLINE char R_Rotation2Char(UINT8 rot)
{
return ((rotation <= 8) || (rotation == ROT_L) || (rotation == ROT_R));
if (rot <= 9) return '0' + rot;
if (rot <= 16) return 'A' + (rot - 10);
if (rot == ROT_L) return 'L';
if (rot == ROT_R) return 'R';
return '\xFF';
}
FUNCMATH FUNCINLINE static ATTRINLINE UINT8 R_Char2Rotation(char cn)
{
if (cn >= '0' && cn <= '9') return (cn - '0');
if (cn >= 'A' && cn <= 'G') return (cn - 'A') + 10;
if (cn == 'L') return ROT_L;
if (cn == 'R') return ROT_R;
return 255;
}
#endif //__R_THINGS__