Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
Show changes
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2020-2024 by Lactozilla.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2020-2023 by Lactozilla.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -54,12 +54,26 @@ INT32 R_GetRollAngle(angle_t rollangle) ...@@ -54,12 +54,26 @@ INT32 R_GetRollAngle(angle_t rollangle)
patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip) patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip)
{ {
rotsprite_t *rotsprite = patch->rotated; rotsprite_t *rotsprite = patch->rotated;
if (rotsprite == NULL || angle < 1 || angle >= ROTANGLES) if (angle < 1 || angle >= ROTANGLES)
return NULL; return NULL;
if (rotsprite == NULL)
{
rotsprite = RotatedPatch_Create(ROTANGLES);
patch->rotated = rotsprite;
}
if (flip) if (flip)
angle += rotsprite->angles; angle += rotsprite->angles;
if (rotsprite->patches[angle] == NULL)
{
INT32 xpivot = 0, ypivot = 0;
xpivot = patch->leftoffset;
ypivot = patch->topoffset;
RotatedPatch_DoRotation(rotsprite, patch, angle, xpivot, ypivot, flip);
}
return rotsprite->patches[angle]; return rotsprite->patches[angle];
} }
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2020-2023 by Lactozilla.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 2005-2009 by Andrey "entryway" Budko. // Copyright (C) 2005-2009 by Andrey "entryway" Budko.
// Copyright (C) 2018-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2018-2024 by Lactozilla.
// Copyright (C) 2019-2023 by Sonic Team Junior. // Copyright (C) 2019-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -1570,7 +1570,7 @@ static void R_ParseSpriteInfo(boolean spr2) ...@@ -1570,7 +1570,7 @@ static void R_ParseSpriteInfo(boolean spr2)
spriteinfo_t *info; spriteinfo_t *info;
char *sprinfoToken; char *sprinfoToken;
size_t sprinfoTokenLength; size_t sprinfoTokenLength;
char newSpriteName[5]; // no longer dynamically allocated char newSpriteName[MAXSPRITENAME + 1]; // no longer dynamically allocated
spritenum_t sprnum = NUMSPRITES; spritenum_t sprnum = NUMSPRITES;
playersprite_t spr2num = NUMPLAYERSPRITES; playersprite_t spr2num = NUMPLAYERSPRITES;
INT32 i; INT32 i;
...@@ -1584,31 +1584,17 @@ static void R_ParseSpriteInfo(boolean spr2) ...@@ -1584,31 +1584,17 @@ static void R_ParseSpriteInfo(boolean spr2)
I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be"); I_Error("Error parsing SPRTINFO lump: Unexpected end of file where sprite name should be");
} }
sprinfoTokenLength = strlen(sprinfoToken); sprinfoTokenLength = strlen(sprinfoToken);
if (sprinfoTokenLength != 4) if (sprinfoTokenLength > MAXSPRITENAME)
{ I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" is longer than %d characters", sprinfoToken, MAXSPRITENAME);
I_Error("Error parsing SPRTINFO lump: Sprite name \"%s\" isn't 4 characters long",sprinfoToken); strcpy(newSpriteName, sprinfoToken);
} strupr(newSpriteName); // Just do this now so we don't have to worry about it
else
{
memset(&newSpriteName, 0, 5);
M_Memcpy(newSpriteName, sprinfoToken, sprinfoTokenLength);
// ^^ we've confirmed that the token is == 4 characters so it will never overflow a 5 byte char buffer
strupr(newSpriteName); // Just do this now so we don't have to worry about it
}
Z_Free(sprinfoToken); Z_Free(sprinfoToken);
if (!spr2) if (!spr2)
{ {
for (i = 0; i <= NUMSPRITES; i++) sprnum = R_GetSpriteNumByName(newSpriteName);
{ if (sprnum == NUMSPRITES)
if (i == NUMSPRITES) I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
I_Error("Error parsing SPRTINFO lump: Unknown sprite name \"%s\"", newSpriteName);
if (!memcmp(newSpriteName,sprnames[i],4))
{
sprnum = i;
break;
}
}
} }
else else
{ {
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 2018-2023 by Jaime "Lactozilla" Passos. // Copyright (C) 2018-2024 by Lactozilla.
// Copyright (C) 2019-2023 by Sonic Team Junior. // Copyright (C) 2019-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -100,7 +100,7 @@ typedef struct ...@@ -100,7 +100,7 @@ typedef struct
typedef struct typedef struct
{ {
spriteframepivot_t pivot[64]; spriteframepivot_t pivot[MAXFRAMENUM];
boolean available; boolean available;
} spriteinfo_t; } spriteinfo_t;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2025 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -83,7 +83,7 @@ static fixed_t planeheight; ...@@ -83,7 +83,7 @@ static fixed_t planeheight;
fixed_t yslopetab[MAXVIDHEIGHT*16]; fixed_t yslopetab[MAXVIDHEIGHT*16];
fixed_t *yslope; fixed_t *yslope;
static fixed_t xoffs, yoffs; static INT64 xoffs, yoffs;
static dvector3_t slope_origin, slope_u, slope_v; static dvector3_t slope_origin, slope_u, slope_v;
static dvector3_t slope_lightu, slope_lightv; static dvector3_t slope_lightu, slope_lightv;
...@@ -182,8 +182,8 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2) ...@@ -182,8 +182,8 @@ static void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
R_CalculatePlaneRipple(currentplane->viewangle + currentplane->plangle); R_CalculatePlaneRipple(currentplane->viewangle + currentplane->plangle);
ds_xfrac += planeripple.xfrac; ds_xfrac += FixedMul(planeripple.xfrac, currentplane->xscale);
ds_yfrac += planeripple.yfrac; ds_yfrac += FixedMul(planeripple.yfrac, currentplane->yscale);
ds_bgofs >>= FRACBITS; ds_bgofs >>= FRACBITS;
if ((y + ds_bgofs) >= viewheight) if ((y + ds_bgofs) >= viewheight)
...@@ -376,19 +376,25 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li ...@@ -376,19 +376,25 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
visplane_t *check; visplane_t *check;
unsigned hash; unsigned hash;
float offset_xd = FixedToFloat(xoff) / FixedToFloat(xscale ? xscale : 1);
float offset_yd = FixedToFloat(yoff) / FixedToFloat(yscale ? yscale : 1);
INT64 offset_x = offset_xd * FRACUNIT;
INT64 offset_y = offset_yd * FRACUNIT;
if (!slope) // Don't mess with this right now if a slope is involved if (!slope) // Don't mess with this right now if a slope is involved
{ {
xoff += FixedMul(viewx, xscale); offset_x += viewx;
yoff -= FixedMul(viewy, yscale); offset_y -= viewy;
if (plangle != 0) if (plangle != 0)
{ {
// Add the view offset, rotated by the plane angle. // Add the view offset, rotated by the plane angle.
float ang = ANG2RAD(plangle); float ang = ANG2RAD(plangle);
float x = FixedToFloat(xoff); float x = offset_x / (float)FRACUNIT;
float y = FixedToFloat(yoff); float y = offset_y / (float)FRACUNIT;
xoff = FloatToFixed(x * cos(ang) + y * sin(ang)); offset_x = (x * cos(ang) + y * sin(ang)) * FRACUNIT;
yoff = FloatToFixed(-x * sin(ang) + y * cos(ang)); offset_y = (-x * sin(ang) + y * cos(ang)) * FRACUNIT;
} }
} }
...@@ -399,16 +405,19 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li ...@@ -399,16 +405,19 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
float ang = ANG2RAD(polyobj->angle); float ang = ANG2RAD(polyobj->angle);
float x = FixedToFloat(polyobj->centerPt.x); float x = FixedToFloat(polyobj->centerPt.x);
float y = FixedToFloat(polyobj->centerPt.y); float y = FixedToFloat(polyobj->centerPt.y);
xoff -= FloatToFixed(x * cos(ang) + y * sin(ang)); offset_x -= (x * cos(ang) + y * sin(ang)) * FRACUNIT;
yoff -= FloatToFixed(x * sin(ang) - y * cos(ang)); offset_y -= (x * sin(ang) - y * cos(ang)) * FRACUNIT;
} }
else else
{ {
xoff -= polyobj->centerPt.x; offset_x -= polyobj->centerPt.x;
yoff += polyobj->centerPt.y; offset_y += polyobj->centerPt.y;
} }
} }
offset_x = ((INT64)offset_x * xscale) / FRACUNIT;
offset_y = ((INT64)offset_y * yscale) / FRACUNIT;
// This appears to fix the Nimbus Ruins sky bug. // This appears to fix the Nimbus Ruins sky bug.
if (picnum == skyflatnum && pfloor) if (picnum == skyflatnum && pfloor)
{ {
...@@ -423,7 +432,7 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li ...@@ -423,7 +432,7 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
{ {
if (height == check->height && picnum == check->picnum if (height == check->height && picnum == check->picnum
&& lightlevel == check->lightlevel && lightlevel == check->lightlevel
&& xoff == check->xoffs && yoff == check->yoffs && offset_x == check->xoffs && offset_y == check->yoffs
&& xscale == check->xscale && yscale == check->yscale && xscale == check->xscale && yscale == check->yscale
&& planecolormap == check->extra_colormap && planecolormap == check->extra_colormap
&& check->viewx == viewx && check->viewy == viewy && check->viewz == viewz && check->viewx == viewx && check->viewy == viewy && check->viewz == viewz
...@@ -449,8 +458,8 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li ...@@ -449,8 +458,8 @@ visplane_t *R_FindPlane(sector_t *sector, fixed_t height, INT32 picnum, INT32 li
check->lightlevel = lightlevel; check->lightlevel = lightlevel;
check->minx = vid.width; check->minx = vid.width;
check->maxx = -1; check->maxx = -1;
check->xoffs = xoff; check->xoffs = offset_x;
check->yoffs = yoff; check->yoffs = offset_y;
check->xscale = xscale; check->xscale = xscale;
check->yscale = yscale; check->yscale = yscale;
check->extra_colormap = planecolormap; check->extra_colormap = planecolormap;
...@@ -658,13 +667,13 @@ static void R_DrawSkyPlane(visplane_t *pl) ...@@ -658,13 +667,13 @@ static void R_DrawSkyPlane(visplane_t *pl)
} }
// Returns the height of the sloped plane at (x, y) as a double // Returns the height of the sloped plane at (x, y) as a double
static double R_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) static double R_GetSlopeZAt(const pslope_t *slope, INT64 x, INT64 y)
{ {
// If you want to reimplement this using just the equation constants, use this instead: // If you want to reimplement this using just the equation constants, use this instead:
// (d + a*x + b*y) * -(1.0 / c) // (d + a*x + b*y) * -(1.0 / c)
double px = FixedToDouble(x) - slope->dorigin.x; double px = (x / (double)FRACUNIT) - slope->dorigin.x;
double py = FixedToDouble(y) - slope->dorigin.y; double py = (y / (double)FRACUNIT) - slope->dorigin.y;
double dist = (px * slope->dnormdir.x) + (py * slope->dnormdir.y); double dist = (px * slope->dnormdir.x) + (py * slope->dnormdir.y);
...@@ -672,10 +681,10 @@ static double R_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) ...@@ -672,10 +681,10 @@ static double R_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y)
} }
// Sets the texture origin vector of the sloped plane. // Sets the texture origin vector of the sloped plane.
static void R_SetSlopePlaneOrigin(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, fixed_t angle) static void R_SetSlopePlaneOrigin(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, INT64 xoff, INT64 yoff, fixed_t angle)
{ {
INT64 vx = (INT64)xpos + (INT64)xoff; INT64 vx = (INT64)xpos + xoff;
INT64 vy = (INT64)ypos - (INT64)yoff; INT64 vy = (INT64)ypos - yoff;
float vxf = vx / (float)FRACUNIT; float vxf = vx / (float)FRACUNIT;
float vyf = vy / (float)FRACUNIT; float vyf = vy / (float)FRACUNIT;
...@@ -702,7 +711,7 @@ void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, ...@@ -702,7 +711,7 @@ void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos,
slope->moved = false; slope->moved = false;
} }
R_SetSlopePlaneOrigin(slope, xpos, ypos, zpos, xoff, yoff, angle); R_SetSlopePlaneOrigin(slope, xpos, ypos, zpos, (INT64)xoff, (INT64)yoff, angle);
height = R_GetSlopeZAt(slope, xpos, ypos); height = R_GetSlopeZAt(slope, xpos, ypos);
zeroheight = height - FixedToDouble(zpos); zeroheight = height - FixedToDouble(zpos);
...@@ -735,7 +744,7 @@ void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, ...@@ -735,7 +744,7 @@ void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos,
} }
// This function calculates all of the vectors necessary for drawing a sloped and scaled plane. // This function calculates all of the vectors necessary for drawing a sloped and scaled plane.
void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle) void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, INT64 xoff, INT64 yoff, angle_t angle, angle_t plangle)
{ {
double height, z_at_xy; double height, z_at_xy;
float ang; float ang;
...@@ -836,9 +845,11 @@ static void CalcSlopePlaneVectors(visplane_t *pl, fixed_t xoff, fixed_t yoff) ...@@ -836,9 +845,11 @@ static void CalcSlopePlaneVectors(visplane_t *pl, fixed_t xoff, fixed_t yoff)
{ {
if (!ds_fog && (pl->xscale != FRACUNIT || pl->yscale != FRACUNIT)) if (!ds_fog && (pl->xscale != FRACUNIT || pl->yscale != FRACUNIT))
{ {
float offset_x = FixedToFloat(xoff) / FixedToFloat(pl->xscale ? pl->xscale : 1);
float offset_y = FixedToFloat(yoff) / FixedToFloat(pl->yscale ? pl->yscale : 1);
R_SetScaledSlopePlane(pl->slope, pl->viewx, pl->viewy, pl->viewz, R_SetScaledSlopePlane(pl->slope, pl->viewx, pl->viewy, pl->viewz,
FixedDiv(FRACUNIT, pl->xscale), FixedDiv(FRACUNIT, pl->yscale), FixedDiv(FRACUNIT, pl->xscale), FixedDiv(FRACUNIT, pl->yscale),
FixedDiv(xoff, pl->xscale), FixedDiv(yoff, pl->yscale), pl->viewangle, pl->plangle); (INT64)(offset_x * FRACUNIT), (INT64)(offset_y * FRACUNIT), pl->viewangle, pl->plangle);
} }
else else
R_SetSlopePlane(pl->slope, pl->viewx, pl->viewy, pl->viewz, xoff, yoff, pl->viewangle, pl->plangle); R_SetSlopePlane(pl->slope, pl->viewx, pl->viewy, pl->viewz, xoff, yoff, pl->viewangle, pl->plangle);
...@@ -910,7 +921,7 @@ void R_DrawSinglePlane(visplane_t *pl) ...@@ -910,7 +921,7 @@ void R_DrawSinglePlane(visplane_t *pl)
if (pl->polyobj->translucency == 0 || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) if (pl->polyobj->translucency == 0 || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG)))
light = (pl->lightlevel >> LIGHTSEGSHIFT); light = (pl->lightlevel >> LIGHTSEGSHIFT);
else else // TODO: 2.3: Make transparent polyobject planes always use light level
light = LIGHTLEVELS-1; light = LIGHTLEVELS-1;
} }
else else
...@@ -952,7 +963,7 @@ void R_DrawSinglePlane(visplane_t *pl) ...@@ -952,7 +963,7 @@ void R_DrawSinglePlane(visplane_t *pl)
if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG))) if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG)))
light = (pl->lightlevel >> LIGHTSEGSHIFT); light = (pl->lightlevel >> LIGHTSEGSHIFT);
else else // TODO: 2.3: Make transparent FOF planes use light level instead of always being fullbright
light = LIGHTLEVELS-1; light = LIGHTLEVELS-1;
} }
else if (pl->ffloor->fofflags & FOF_FOG) else if (pl->ffloor->fofflags & FOF_FOG)
...@@ -1079,6 +1090,9 @@ void R_DrawSinglePlane(visplane_t *pl) ...@@ -1079,6 +1090,9 @@ void R_DrawSinglePlane(visplane_t *pl)
case SPANDRAWFUNC_SPLAT: case SPANDRAWFUNC_SPLAT:
spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; spanfunctype = SPANDRAWFUNC_TILTEDSPLAT;
break; break;
case SPANDRAWFUNC_TRANSSPLAT:
spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPLAT;
break;
case SPANDRAWFUNC_SOLID: case SPANDRAWFUNC_SOLID:
spanfunctype = SPANDRAWFUNC_TILTEDSOLID; spanfunctype = SPANDRAWFUNC_TILTEDSOLID;
break; break;
......
...@@ -48,7 +48,7 @@ typedef struct visplane_s ...@@ -48,7 +48,7 @@ typedef struct visplane_s
UINT16 padbottomstart, bottom[MAXVIDWIDTH], padbottomend; UINT16 padbottomstart, bottom[MAXVIDWIDTH], padbottomend;
INT32 high, low; // R_PlaneBounds should set these. INT32 high, low; // R_PlaneBounds should set these.
fixed_t xoffs, yoffs; // Scrolling flats. INT64 xoffs, yoffs; // Scrolling flats.
fixed_t xscale, yscale; fixed_t xscale, yscale;
sector_t *sector; sector_t *sector;
...@@ -85,7 +85,7 @@ void R_DrawSinglePlane(visplane_t *pl); ...@@ -85,7 +85,7 @@ void R_DrawSinglePlane(visplane_t *pl);
// Calculates the slope vectors needed for tilted span drawing. // Calculates the slope vectors needed for tilted span drawing.
void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle); void R_SetSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle);
void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, fixed_t xoff, fixed_t yoff, angle_t angle, angle_t plangle); void R_SetScaledSlopePlane(pslope_t *slope, fixed_t xpos, fixed_t ypos, fixed_t zpos, fixed_t xs, fixed_t ys, INT64 xoff, INT64 yoff, angle_t angle, angle_t plangle);
typedef struct planemgr_s typedef struct planemgr_s
{ {
......
...@@ -101,7 +101,7 @@ void Portal_ClipApply (const portal_t* portal) ...@@ -101,7 +101,7 @@ void Portal_ClipApply (const portal_t* portal)
static portal_t* Portal_Add (const INT16 x1, const INT16 x2) static portal_t* Portal_Add (const INT16 x1, const INT16 x2)
{ {
portal_t *portal = Z_Malloc(sizeof(portal_t), PU_LEVEL, NULL); portal_t *portal = Z_Calloc(sizeof(portal_t), PU_LEVEL, NULL);
INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL); INT16 *ceilingclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL);
INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL); INT16 *floorclipsave = Z_Malloc(sizeof(INT16)*(x2-x1 + 1), PU_LEVEL, NULL);
fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1 + 1), PU_LEVEL, NULL); fixed_t *frontscalesave = Z_Malloc(sizeof(fixed_t)*(x2-x1 + 1), PU_LEVEL, NULL);
...@@ -117,7 +117,7 @@ static portal_t* Portal_Add (const INT16 x1, const INT16 x2) ...@@ -117,7 +117,7 @@ static portal_t* Portal_Add (const INT16 x1, const INT16 x2)
portal_cap->next = portal; portal_cap->next = portal;
portal_cap = portal; portal_cap = portal;
} }
portal->next = NULL; portal->clipline = -1;
// Store clipping values so they can be restored once the portal is rendered. // Store clipping values so they can be restored once the portal is rendered.
portal->ceilingclip = ceilingclipsave; portal->ceilingclip = ceilingclipsave;
...@@ -142,11 +142,9 @@ void Portal_Remove (portal_t* portal) ...@@ -142,11 +142,9 @@ void Portal_Remove (portal_t* portal)
Z_Free(portal); Z_Free(portal);
} }
static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *dest) static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *dest, angle_t dangle)
{ {
// Offset the portal view by the linedef centers // Offset the portal view by the linedef centers
angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0);
fixed_t disttopoint; fixed_t disttopoint;
angle_t angtopoint; angle_t angtopoint;
...@@ -168,7 +166,6 @@ static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t * ...@@ -168,7 +166,6 @@ static void Portal_GetViewpointForLine(portal_t *portal, line_t *start, line_t *
portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); portal->viewx = dest_c.x + FixedMul(FINECOSINE(angtopoint>>ANGLETOFINESHIFT), disttopoint);
portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint); portal->viewy = dest_c.y + FixedMul(FINESINE(angtopoint>>ANGLETOFINESHIFT), disttopoint);
portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight;
portal->viewangle = viewangle + dangle; portal->viewangle = viewangle + dangle;
} }
...@@ -189,12 +186,13 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con ...@@ -189,12 +186,13 @@ void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, con
line_t* start = &lines[line1]; line_t* start = &lines[line1];
line_t* dest = &lines[line2]; line_t* dest = &lines[line2];
Portal_GetViewpointForLine(portal, start, dest); angle_t dangle = R_PointToAngle2(0,0,dest->dx,dest->dy) - R_PointToAngle2(start->dx,start->dy,0,0);
Portal_GetViewpointForLine(portal, start, dest, dangle);
portal->viewz = viewz + dest->frontsector->floorheight - start->frontsector->floorheight;
portal->clipline = line2; portal->clipline = line2;
portal->is_skybox = false;
portal->is_horizon = false;
portal->horizon_sector = NULL;
Portal_ClipRange(portal); Portal_ClipRange(portal);
...@@ -317,10 +315,7 @@ static boolean Portal_AddSkybox (const visplane_t* plane) ...@@ -317,10 +315,7 @@ static boolean Portal_AddSkybox (const visplane_t* plane)
Portal_ClipVisplane(plane, portal); Portal_ClipVisplane(plane, portal);
portal->clipline = -1;
portal->is_skybox = true; portal->is_skybox = true;
portal->is_horizon = false;
portal->horizon_sector = NULL;
Portal_GetViewpointForSkybox(portal); Portal_GetViewpointForSkybox(portal);
...@@ -332,14 +327,28 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se ...@@ -332,14 +327,28 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se
fixed_t x, y, z; fixed_t x, y, z;
angle_t angle; angle_t angle;
sector_t *target = secportal->target;
fixed_t target_x = target->soundorg.x;
fixed_t target_y = target->soundorg.y;
fixed_t target_z;
if (secportal->ceiling)
target_z = P_GetSectorCeilingZAt(target, target_x, target_y);
else
target_z = P_GetSectorFloorZAt(target, target_x, target_y);
switch (secportal->type) switch (secportal->type)
{ {
case SECPORTAL_LINE: case SECPORTAL_LINE:
Portal_GetViewpointForLine(portal, secportal->line.start, secportal->line.dest); angle = secportal->line.dest->angle - secportal->line.start->angle;
Portal_GetViewpointForLine(portal, secportal->line.start, secportal->line.dest, angle);
portal->viewz = viewz; // Apparently it just works like that. Not going to question it.
return; return;
case SECPORTAL_OBJECT: case SECPORTAL_OBJECT:
if (!secportal->mobj || P_MobjWasRemoved(secportal->mobj)) if (P_MobjWasRemoved(secportal->mobj))
return; return;
portal->viewmobj = secportal->mobj;
x = secportal->mobj->x; x = secportal->mobj->x;
y = secportal->mobj->y; y = secportal->mobj->y;
z = secportal->mobj->z; z = secportal->mobj->z;
...@@ -373,8 +382,9 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se ...@@ -373,8 +382,9 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se
return; return;
} }
fixed_t refx = secportal->origin.x - viewx; fixed_t refx = target_x - viewx;
fixed_t refy = secportal->origin.y - viewy; fixed_t refy = target_y - viewy;
fixed_t refz = target_z - viewz;
// Rotate the X/Y to match the target angle // Rotate the X/Y to match the target angle
if (angle != 0) if (angle != 0)
...@@ -387,7 +397,7 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se ...@@ -387,7 +397,7 @@ static void Portal_GetViewpointForSecPortal(portal_t *portal, sectorportal_t *se
portal->viewx = x - refx; portal->viewx = x - refx;
portal->viewy = y - refy; portal->viewy = y - refy;
portal->viewz = z + viewz; portal->viewz = z - refz;
portal->viewangle = angle + viewangle; portal->viewangle = angle + viewangle;
} }
...@@ -413,11 +423,6 @@ static boolean Portal_AddSectorPortal (const visplane_t* plane) ...@@ -413,11 +423,6 @@ static boolean Portal_AddSectorPortal (const visplane_t* plane)
Portal_ClipVisplane(plane, portal); Portal_ClipVisplane(plane, portal);
portal->clipline = -1;
portal->is_horizon = false;
portal->is_skybox = false;
portal->horizon_sector = NULL;
Portal_GetViewpointForSecPortal(portal, secportal); Portal_GetViewpointForSecPortal(portal, secportal);
return true; return true;
...@@ -425,7 +430,7 @@ static boolean Portal_AddSectorPortal (const visplane_t* plane) ...@@ -425,7 +430,7 @@ static boolean Portal_AddSectorPortal (const visplane_t* plane)
/** Creates a transferred sector portal. /** Creates a transferred sector portal.
*/ */
void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2) void Portal_AddTransferred (const UINT32 secportalnum, const INT32 x1, const INT32 x2)
{ {
if (secportalnum >= secportalcount) if (secportalnum >= secportalcount)
return; return;
...@@ -435,9 +440,6 @@ void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2) ...@@ -435,9 +440,6 @@ void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2)
return; return;
portal_t* portal = Portal_Add(x1, x2); portal_t* portal = Portal_Add(x1, x2);
portal->is_skybox = false;
portal->is_horizon = false;
portal->horizon_sector = NULL;
if (secportal->type == SECPORTAL_SKYBOX) if (secportal->type == SECPORTAL_SKYBOX)
Portal_GetViewpointForSkybox(portal); Portal_GetViewpointForSkybox(portal);
......
...@@ -36,6 +36,8 @@ typedef struct portal_s ...@@ -36,6 +36,8 @@ typedef struct portal_s
boolean is_skybox; boolean is_skybox;
mobj_t *viewmobj;
UINT8 pass; /**< Keeps track of the portal's recursion depth. */ UINT8 pass; /**< Keeps track of the portal's recursion depth. */
INT32 clipline; /**< Optional clipline for line-based portals. */ INT32 clipline; /**< Optional clipline for line-based portals. */
...@@ -58,7 +60,7 @@ extern INT32 portalclipstart, portalclipend; ...@@ -58,7 +60,7 @@ extern INT32 portalclipstart, portalclipend;
void Portal_InitList (void); void Portal_InitList (void);
void Portal_Remove (portal_t* portal); void Portal_Remove (portal_t* portal);
void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2); void Portal_Add2Lines (const INT32 line1, const INT32 line2, const INT32 x1, const INT32 x2);
void Portal_AddTransferred (UINT32 secportalnum, const INT32 x1, const INT32 x2); void Portal_AddTransferred (const UINT32 secportalnum, const INT32 x1, const INT32 x2);
void Portal_ClipRange (portal_t* portal); void Portal_ClipRange (portal_t* portal);
void Portal_ClipApply (const portal_t* portal); void Portal_ClipApply (const portal_t* portal);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -94,6 +94,124 @@ transnum_t R_GetLinedefTransTable(fixed_t alpha) ...@@ -94,6 +94,124 @@ transnum_t R_GetLinedefTransTable(fixed_t alpha)
return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1); return (20*(FRACUNIT - alpha - 1) + FRACUNIT) >> (FRACBITS+1);
} }
static UINT8 R_SideLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light +
((side->lightabsolute) ? 0 : base_lightlevel)));
}
/* TODO: implement per-texture lighting
static UINT8 R_TopLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_top +
((side->lightabsolute_top) ? 0 : R_SideLightLevel(side, base_lightlevel))));
}
static UINT8 R_MidLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_mid +
((side->lightabsolute_mid) ? 0 : R_SideLightLevel(side, base_lightlevel))));
}
static UINT8 R_BottomLightLevel(side_t *side, INT16 base_lightlevel)
{
return max(0, min(255, side->light_bottom +
((side->lightabsolute_bottom) ? 0 : R_SideLightLevel(side, base_lightlevel))));
}
*/
// If we have a multi-patch texture on a 2sided wall (rare) then we draw
// it using R_DrawColumn, else we draw it using R_DrawMaskedColumn, this
// way we don't have to store extra post_t info with each column for
// multi-patch textures. They are not normally needed as multi-patch
// textures don't have holes in it. At least not for now.
static void R_Render2sidedMultiPatchColumn(column_t *column, unsigned lengthcol)
{
INT32 topscreen, bottomscreen;
post_t *post = &column->posts[0];
if (!post->length)
return;
topscreen = sprtopscreen;
bottomscreen = topscreen + spryscale * lengthcol;
dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
{
dc_yl = ((windowtop + FRACUNIT)>>FRACBITS);
dc_yh = (windowbottom - 1)>>FRACBITS;
}
if (dc_yh >= mfloorclip[dc_x])
dc_yh = mfloorclip[dc_x] - 1;
if (dc_yl <= mceilingclip[dc_x])
dc_yl = mceilingclip[dc_x] + 1;
if (dc_yl >= vid.height || dc_yh < 0)
return;
if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0)
{
dc_source = column->pixels + post->data_offset;
dc_postlength = post->length;
if (colfunc == colfuncs[BASEDRAWFUNC])
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCH])();
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
(colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS])();
else
colfunc();
}
}
static void R_RenderFlipped2sidedMultiPatchColumn(column_t *column, unsigned lengthcol)
{
INT32 topscreen, bottomscreen;
void (*localcolfunc)(void);
post_t *post = &column->posts[0];
if (!post->length)
return;
topscreen = sprtopscreen;
bottomscreen = topscreen + spryscale * lengthcol;
dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS;
if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
{
dc_yl = ((windowtop + FRACUNIT)>>FRACBITS);
dc_yh = (windowbottom - 1)>>FRACBITS;
}
if (dc_yh >= mfloorclip[dc_x])
dc_yh = mfloorclip[dc_x] - 1;
if (dc_yl <= mceilingclip[dc_x])
dc_yl = mceilingclip[dc_x] + 1;
if (dc_yl >= vid.height || dc_yh < 0)
return;
if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0)
{
dc_postlength = post->length;
if (colfunc == colfuncs[BASEDRAWFUNC])
localcolfunc = colfuncs[COLDRAWFUNC_TWOSMULTIPATCH];
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY])
localcolfunc = colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS];
else
localcolfunc = colfunc;
R_DrawFlippedPost(column->pixels + post->data_offset, post->length, localcolfunc);
}
}
void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{ {
size_t pindex; size_t pindex;
...@@ -181,7 +299,16 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -181,7 +299,16 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
// Texture must be cached // Texture must be cached
R_CheckTextureCache(texnum); R_CheckTextureCache(texnum);
if (vertflip) // vertically flipped? // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (!textures[texnum]->transparency)
{
if (vertflip) // vertically flipped?
colfunc_2s = R_RenderFlipped2sidedMultiPatchColumn;
else
colfunc_2s = R_Render2sidedMultiPatchColumn;
}
else if (vertflip) // vertically flipped?
colfunc_2s = R_DrawFlippedMaskedColumn; colfunc_2s = R_DrawFlippedMaskedColumn;
else else
colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture
...@@ -223,7 +350,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -223,7 +350,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY]) if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (rlight->flags & FOF_FOG) || (rlight->flags & FOF_FOG)
|| (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))) || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, rlight->lightlevel) >> LIGHTSEGSHIFT;
else else
lightnum = LIGHTLEVELS - 1; lightnum = LIGHTLEVELS - 1;
...@@ -241,7 +368,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -241,7 +368,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
{ {
if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY]) if ((colfunc != colfuncs[COLDRAWFUNC_FUZZY])
|| (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, frontsector->lightlevel) >> LIGHTSEGSHIFT;
else else
lightnum = LIGHTLEVELS - 1; lightnum = LIGHTLEVELS - 1;
...@@ -442,26 +569,75 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) ...@@ -442,26 +569,75 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
} }
// Loop through R_DrawMaskedColumn calls // Loop through R_DrawMaskedColumn calls
static fixed_t repeatscroll = 0;
static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol) static void R_DrawRepeatMaskedColumn(column_t *col, unsigned lengthcol)
{ {
while (sprtopscreen < sprbotscreen) { fixed_t topscreen = sprtopscreen;
fixed_t bottomscreen = sprbotscreen;
fixed_t texheight = dc_texheight*spryscale;
fixed_t scroll = -repeatscroll;
if (scroll < 0)
{
scroll = -FixedMul((abs(scroll) % (dc_texheight*FRACUNIT)), spryscale);
bottomscreen += texheight; // Draw an extra time
}
else if (scroll)
{
scroll = FixedMul(scroll % (dc_texheight*FRACUNIT), spryscale);
topscreen -= texheight; // Draw an extra time
}
while (topscreen < bottomscreen)
{
sprtopscreen = topscreen + scroll;
R_DrawMaskedColumn(col, lengthcol); R_DrawMaskedColumn(col, lengthcol);
if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
sprtopscreen = INT32_MAX; break;
else
sprtopscreen += dc_texheight*spryscale; topscreen += texheight;
} }
sprtopscreen = sprbotscreen;
} }
static void R_DrawRepeatFlippedMaskedColumn(column_t *col, unsigned lengthcol) static void R_DrawRepeatFlippedMaskedColumn(column_t *col, unsigned lengthcol)
{ {
while (sprtopscreen < sprbotscreen) { fixed_t topscreen = sprtopscreen;
fixed_t bottomscreen = sprbotscreen;
fixed_t texheight = dc_texheight*spryscale;
fixed_t scroll = -repeatscroll;
if (scroll < 0)
{
scroll = -FixedMul((abs(scroll) % (dc_texheight*FRACUNIT)), spryscale);
bottomscreen += texheight; // Draw an extra time
}
else if (scroll)
{
scroll = FixedMul(scroll % (dc_texheight*FRACUNIT), spryscale);
topscreen -= texheight; // Draw an extra time
}
while (topscreen < bottomscreen)
{
sprtopscreen = topscreen + scroll;
sprbotscreen = bottomscreen + scroll;
R_DrawFlippedMaskedColumn(col, lengthcol); R_DrawFlippedMaskedColumn(col, lengthcol);
if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow if ((INT64)sprtopscreen + (INT64)dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
sprtopscreen = INT32_MAX; break;
else
sprtopscreen += dc_texheight*spryscale; topscreen += texheight;
} }
sprtopscreen = sprbotscreen;
} }
// Returns true if a fake floor is translucent. // Returns true if a fake floor is translucent.
...@@ -497,7 +673,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -497,7 +673,6 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
sector_t tempsec; sector_t tempsec;
INT32 templight; INT32 templight;
INT32 i, p; INT32 i, p;
fixed_t offsetvalue;
lightlist_t *light; lightlist_t *light;
r_lightlist_t *rlight; r_lightlist_t *rlight;
INT32 range; INT32 range;
...@@ -515,6 +690,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -515,6 +690,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
fixed_t wall_scalex, wall_scaley; fixed_t wall_scalex, wall_scaley;
UINT8 vertflip; UINT8 vertflip;
unsigned lengthcol; unsigned lengthcol;
boolean fog = false;
boolean fuzzy = false;
void (*colfunc_2s) (column_t *, unsigned); void (*colfunc_2s) (column_t *, unsigned);
...@@ -526,13 +703,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -526,13 +703,11 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
curline = ds->curline; curline = ds->curline;
backsector = pfloor->target; backsector = pfloor->target;
frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector; frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
sidedef = R_GetFFloorSide(curline, pfloor); sidedef = R_GetFFloorSide(curline->linedef, pfloor, pfloor->target);
colfunc = colfuncs[BASEDRAWFUNC];
if (pfloor->master->flags & ML_TFERLINE) if (pfloor->master->flags & ML_TFERLINE)
{ {
line_t *newline = R_GetFFloorLine(curline, pfloor); line_t *newline = R_GetFFloorLine(curline->linedef, pfloor, pfloor->target);
do_texture_skew = newline->flags & ML_SKEWTD; do_texture_skew = newline->flags & ML_SKEWTD;
dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM; dont_peg_bottom = newline->flags & ML_DONTPEGBOTTOM;
} }
...@@ -547,7 +722,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -547,7 +722,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (pfloor->fofflags & FOF_TRANSLUCENT) if (pfloor->fofflags & FOF_TRANSLUCENT)
{ {
boolean fuzzy = true; fuzzy = true;
// Hacked up support for alpha value in software mode Tails 09-24-2002 // Hacked up support for alpha value in software mode Tails 09-24-2002
// ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021 // ...unhacked by toaster 04-01-2021, re-hacked a little by sphere 19-11-2021
...@@ -560,17 +735,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -560,17 +735,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0) else if (!(dc_transmap = R_GetTranslucencyTable(trans)) || trans == 0)
fuzzy = false; // Opaque fuzzy = false; // Opaque
} }
if (fuzzy)
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
} }
else if (pfloor->fofflags & FOF_FOG) else if (pfloor->fofflags & FOF_FOG)
{
colfunc = colfuncs[COLDRAWFUNC_FOG]; colfunc = colfuncs[COLDRAWFUNC_FOG];
fog = true;
}
range = max(ds->x2-ds->x1, 1); range = max(ds->x2-ds->x1, 1);
//SoM: Moved these up here so they are available for my lightlist calculations
rw_scalestep = ds->scalestep;
spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
dc_numlights = 0; dc_numlights = 0;
if (frontsector->numlights) if (frontsector->numlights)
...@@ -652,9 +824,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -652,9 +824,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Check if the current light effects the colormap/lightlevel // Check if the current light effects the colormap/lightlevel
if (pfloor->fofflags & FOF_FOG) if (pfloor->fofflags & FOF_FOG)
rlight->lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); rlight->lightnum = R_SideLightLevel(curline->sidedef, pfloor->master->frontsector->lightlevel) >> LIGHTSEGSHIFT;
else else
rlight->lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT); rlight->lightnum = R_SideLightLevel(curline->sidedef, rlight->lightlevel) >> LIGHTSEGSHIFT;
if (pfloor->fofflags & FOF_FOG || rlight->flags & FOF_FOG || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG))) if (pfloor->fofflags & FOF_FOG || rlight->flags & FOF_FOG || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
; ;
...@@ -672,18 +844,17 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -672,18 +844,17 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{ {
// Get correct light level! // Get correct light level!
if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))) if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, frontsector->lightlevel) >> LIGHTSEGSHIFT;
else if (pfloor->fofflags & FOF_FOG) else if (fog)
lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, pfloor->master->frontsector->lightlevel) >> LIGHTSEGSHIFT;
else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY]) else if (fuzzy)
lightnum = LIGHTLEVELS-1; lightnum = LIGHTLEVELS-1;
else else
lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) lightnum = R_SideLightLevel(curline->sidedef, R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)->lightlevel) >> LIGHTSEGSHIFT;
->lightlevel >> LIGHTSEGSHIFT;
if (pfloor->fofflags & FOF_FOG || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG))); if (pfloor->fofflags & FOF_FOG || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)));
else if (curline->v1->y == curline->v2->y) else if (curline->v1->y == curline->v2->y)
lightnum--; lightnum--;
else if (curline->v1->x == curline->v2->x) else if (curline->v1->x == curline->v2->x)
lightnum++; lightnum++;
...@@ -703,6 +874,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -703,6 +874,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
vertflip = !vertflip; vertflip = !vertflip;
} }
//SoM: Moved these up here so they are available for my lightlist calculations
// Lactozilla: Moved them back down
// This uses floating point math now, because the fixed-point imprecisions
// become more severe the bigger the texture is scaled.
double dwall_scaley = FixedToDouble(wall_scaley);
double scalestep = FixedToDouble(ds->scalestep) / dwall_scaley;
double yscale = (FixedToDouble(ds->scale1) + (x1 - ds->x1)*scalestep) / dwall_scaley;
thicksidecol = ffloortexturecolumn; thicksidecol = ffloortexturecolumn;
wall_offsetx = ds->offsetx + sidedef->offsetx_mid; wall_offsetx = ds->offsetx + sidedef->offsetx_mid;
...@@ -734,7 +913,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -734,7 +913,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
else else
dc_texturemid = FixedMul(*pfloor->topheight - viewz, wall_scaley); dc_texturemid = FixedMul(*pfloor->topheight - viewz, wall_scaley);
offsetvalue = sidedef->rowoffset + sidedef->offsety_mid; repeatscroll = sidedef->rowoffset + sidedef->offsety_mid;
if (dont_peg_bottom) if (dont_peg_bottom)
{ {
...@@ -744,7 +923,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -744,7 +923,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
dc_texturemid = FixedMul(left_bottom, wall_scaley); dc_texturemid = FixedMul(left_bottom, wall_scaley);
} }
else else
offsetvalue -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley); repeatscroll -= FixedMul(*pfloor->topheight - *pfloor->bottomheight, wall_scaley);
} }
if (skewslope) if (skewslope)
...@@ -753,12 +932,21 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -753,12 +932,21 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
ffloortextureslide = FixedMul(R_GetSlopeTextureSlide(skewslope, lineangle), wall_scaley); ffloortextureslide = FixedMul(R_GetSlopeTextureSlide(skewslope, lineangle), wall_scaley);
} }
dc_texturemid += offsetvalue; dc_texturemid += repeatscroll;
// Texture must be cached // Texture must be cached
R_CheckTextureCache(texnum); R_CheckTextureCache(texnum);
if (vertflip) // vertically flipped? // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
// are not stored per-column with post info in SRB2
if (!textures[texnum]->transparency)
{
if (vertflip) // vertically flipped?
colfunc_2s = R_RenderFlipped2sidedMultiPatchColumn;
else
colfunc_2s = R_Render2sidedMultiPatchColumn;
}
else if (vertflip) // vertically flipped?
colfunc_2s = R_DrawRepeatFlippedMaskedColumn; colfunc_2s = R_DrawRepeatFlippedMaskedColumn;
else else
colfunc_2s = R_DrawRepeatMaskedColumn; colfunc_2s = R_DrawRepeatMaskedColumn;
...@@ -824,15 +1012,41 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -824,15 +1012,41 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
rlight->botheight += rlight->botheightstep; rlight->botheight += rlight->botheightstep;
} }
} }
spryscale += rw_scalestep; yscale += scalestep;
continue; continue;
} }
dc_iscale = FixedMul(0xffffffffu / (unsigned)spryscale, wall_scaley);
// Get data for the column // Get data for the column
col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS)); col = R_GetColumn(texnum, ((thicksidecol[dc_x] + wall_offsetx) >> FRACBITS));
spryscale = DoubleToFixed(yscale);
// Eh. I tried fixing the scaling artifacts but it still wasn't perfect.
// So this checks if the column has gaps in it or not, and if it does, uses a version of the column drawers
// that prevents the artifacts from being visible.
// Note that if rendering fog then none of this matters because there's no texture mapping to be done
if (!fog)
{
dc_iscale = 0xffffffffu / (unsigned)spryscale;
// Column has a single post and it matches the texture height, use regular column drawers
if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight)
{
if (fuzzy)
colfunc = colfuncs[COLDRAWFUNC_FUZZY];
else
colfunc = colfuncs[BASEDRAWFUNC];
}
else
{
// Otherwise use column drawers with extra checks
if (fuzzy)
colfunc = colfuncs[COLDRAWFUNC_CLAMPEDTRANS];
else
colfunc = colfuncs[COLDRAWFUNC_CLAMPED];
}
}
// SoM: New code does not rely on R_DrawColumnShadowed_8 which // SoM: New code does not rely on R_DrawColumnShadowed_8 which
// will (hopefully) put less strain on the stack. // will (hopefully) put less strain on the stack.
if (dc_numlights) if (dc_numlights)
...@@ -947,7 +1161,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -947,7 +1161,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
if (windowtop < windowbottom) if (windowtop < windowbottom)
colfunc_2s (col, lengthcol); colfunc_2s (col, lengthcol);
spryscale += rw_scalestep; yscale += scalestep;
continue; continue;
} }
...@@ -966,7 +1180,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) ...@@ -966,7 +1180,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// draw the texture // draw the texture
colfunc_2s (col, lengthcol); colfunc_2s (col, lengthcol);
spryscale += rw_scalestep; yscale += scalestep;
} }
colfunc = colfuncs[BASEDRAWFUNC]; colfunc = colfuncs[BASEDRAWFUNC];
...@@ -1274,7 +1488,7 @@ static void R_RenderSegLoop (void) ...@@ -1274,7 +1488,7 @@ static void R_RenderSegLoop (void)
for (i = 0; i < dc_numlights; i++) for (i = 0; i < dc_numlights; i++)
{ {
INT32 lightnum; INT32 lightnum;
lightnum = (dc_lightlist[i].lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, dc_lightlist[i].lightlevel) >> LIGHTSEGSHIFT;
if (dc_lightlist[i].extra_colormap) if (dc_lightlist[i].extra_colormap)
; ;
...@@ -2461,7 +2675,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) ...@@ -2461,7 +2675,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
// use different light tables // use different light tables
// for horizontal / vertical / diagonal // for horizontal / vertical / diagonal
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); lightnum = R_SideLightLevel(curline->sidedef, frontsector->lightlevel) >> LIGHTSEGSHIFT;
if (curline->v1->y == curline->v2->y) if (curline->v1->y == curline->v2->y)
lightnum--; lightnum--;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2025 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "p_local.h" #include "p_local.h"
#include "dehacked.h" // get_number (for thok) #include "dehacked.h" // get_number (for thok)
#include "m_cond.h" #include "m_cond.h"
#include "deh_tables.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_md2.h" #include "hardware/hw_md2.h"
#endif #endif
...@@ -43,10 +44,9 @@ UINT16 P_GetStateSprite2(state_t *state) ...@@ -43,10 +44,9 @@ UINT16 P_GetStateSprite2(state_t *state)
else else
{ {
// Transform the state frame into an animation ID // Transform the state frame into an animation ID
UINT32 stateframe = state->frame & FF_FRAMEMASK; UINT16 spr2 = state->frame & FF_FRAMEMASK;
UINT16 spr2 = stateframe & ~FF_SPR2SUPER;
if (stateframe & FF_SPR2SUPER) if (state->frame & SPR2F_SUPER)
spr2 |= SPR2F_SUPER; spr2 |= SPR2F_SUPER;
return spr2; return spr2;
...@@ -70,7 +70,7 @@ boolean P_IsStateSprite2Super(state_t *state) ...@@ -70,7 +70,7 @@ boolean P_IsStateSprite2Super(state_t *state)
if (state->sprite2 & SPR2F_SUPER) if (state->sprite2 & SPR2F_SUPER)
return true; return true;
} }
else if (state->frame & FF_SPR2SUPER) else if (state->frame & SPR2F_SUPER)
return true; return true;
return false; return false;
...@@ -81,10 +81,19 @@ UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj) ...@@ -81,10 +81,19 @@ UINT16 P_ApplySuperFlagToSprite2(UINT16 spr2, mobj_t *mobj)
{ {
if (mobj->player) if (mobj->player)
{ {
if (mobj->player->charflags & SF_NOSUPERSPRITES || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_NONIGHTSSUPER))) boolean is_nights = mobj->player->powers[pw_carry] == CR_NIGHTSMODE;
if (mobj->player->charflags & SF_NOSUPERSPRITES || (is_nights && (mobj->player->charflags & SF_NONIGHTSSUPER)))
spr2 &= ~SPR2F_SUPER; spr2 &= ~SPR2F_SUPER;
else if (mobj->player->powers[pw_super] || (mobj->player->powers[pw_carry] == CR_NIGHTSMODE && (mobj->player->charflags & SF_SUPER))) else if (mobj->player->powers[pw_super] || (is_nights && (mobj->player->charflags & SF_SUPER)))
spr2 |= SPR2F_SUPER; spr2 |= SPR2F_SUPER;
// Special case for transforming when you are NiGHTS.
// Do NOT apply the super sprites in this situation, even if they exist.
if (is_nights && mobj->state >= &states[S_PLAY_NIGHTS_TRANS1] && mobj->state <= &states[S_PLAY_NIGHTS_TRANS6])
{
spr2 &= ~SPR2F_SUPER;
}
} }
if (spr2 & SPR2F_SUPER) if (spr2 & SPR2F_SUPER)
...@@ -625,7 +634,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski ...@@ -625,7 +634,7 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
newlastlump++; newlastlump++;
// load all sprite sets we are aware of... for super! // load all sprite sets we are aware of... for super!
for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump); R_AddSingleSpriteDef(spr2names[sprite2], &skin->super.sprites[sprite2], wadnum, newlastlump, *lastlump, false);
newlastlump--; newlastlump--;
*lastlump = newlastlump; // okay, make the normal sprite set loading end there *lastlump = newlastlump; // okay, make the normal sprite set loading end there
...@@ -633,10 +642,18 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski ...@@ -633,10 +642,18 @@ static void R_LoadSkinSprites(UINT16 wadnum, UINT16 *lump, UINT16 *lastlump, ski
// load all sprite sets we are aware of... for normal stuff. // load all sprite sets we are aware of... for normal stuff.
for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++) for (sprite2 = start_spr2; sprite2 < free_spr2; sprite2++)
R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump); R_AddSingleSpriteDef(spr2names[sprite2], &skin->sprites[sprite2], wadnum, *lump, *lastlump, false);
if (skin->sprites[0].numframes == 0) if (skin->sprites[0].numframes == 0)
CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]); CONS_Alert(CONS_ERROR, M_GetText("No frames found for sprite SPR2_%s\n"), spr2names[0]);
// TODO: 2.3: Delete
memcpy(&skin->sprites_compat[start_spr2],
&skin->sprites[start_spr2],
sizeof(spritedef_t) * (free_spr2 - start_spr2));
memcpy(&skin->sprites_compat[start_spr2 + NUMPLAYERSPRITES],
&skin->super.sprites[start_spr2],
sizeof(spritedef_t) * (free_spr2 - start_spr2));
} }
// returns whether found appropriate property // returns whether found appropriate property
...@@ -723,6 +740,8 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) ...@@ -723,6 +740,8 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
GETFLAG(MACHINE) GETFLAG(MACHINE)
GETFLAG(DASHMODE) GETFLAG(DASHMODE)
GETFLAG(FASTEDGE) GETFLAG(FASTEDGE)
GETFLAG(FASTWAIT)
GETFLAG(JETFUME)
GETFLAG(MULTIABILITY) GETFLAG(MULTIABILITY)
GETFLAG(NONIGHTSROTATION) GETFLAG(NONIGHTSROTATION)
GETFLAG(NONIGHTSSUPER) GETFLAG(NONIGHTSSUPER)
...@@ -773,6 +792,88 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value) ...@@ -773,6 +792,88 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
return true; return true;
} }
// e.g. "RUN" => S_PLAY_RUN, "RUN1" => S_PLAY_RUN, "RUN8" => S_PLAY_RUN
static statenum_t GetCanonicalPlayerStateNumByName(const char *name)
{
if (startswith(name, "STAND")) return S_PLAY_STND;
else if (startswith(name, "STND")) return S_PLAY_STND;
else if (startswith(name, "WAIT")) return S_PLAY_WAIT;
else if (startswith(name, "WALK")) return S_PLAY_WALK;
else if (startswith(name, "SKID")) return S_PLAY_SKID;
else if (startswith(name, "RUN")) return S_PLAY_RUN;
else if (startswith(name, "DASH")) return S_PLAY_DASH;
else if (startswith(name, "PAIN")) return S_PLAY_PAIN;
else if (startswith(name, "STUN")) return S_PLAY_STUN;
else if (startswith(name, "DEAD")) return S_PLAY_DEAD;
else if (startswith(name, "DRWN")) return S_PLAY_DRWN;
else if (startswith(name, "ROLL")) return S_PLAY_ROLL;
else if (startswith(name, "GASP")) return S_PLAY_GASP;
else if (startswith(name, "JUMP")) return S_PLAY_JUMP;
else if (startswith(name, "SPRING")) return S_PLAY_SPRING;
else if (startswith(name, "FALL")) return S_PLAY_FALL;
else if (startswith(name, "EDGE")) return S_PLAY_EDGE;
else if (startswith(name, "RIDE")) return S_PLAY_RIDE;
else if (startswith(name, "SPINDASH")) return S_PLAY_SPINDASH;
else if (startswith(name, "FLY")) return S_PLAY_FLY;
else if (startswith(name, "SWIM")) return S_PLAY_SWIM;
else if (startswith(name, "FLY_TIRED")) return S_PLAY_FLY_TIRED;
else if (startswith(name, "GLIDE")) return S_PLAY_GLIDE;
else if (startswith(name, "GLIDE_LANDING")) return S_PLAY_GLIDE_LANDING;
else if (startswith(name, "CLING")) return S_PLAY_CLING;
else if (startswith(name, "CLIMB")) return S_PLAY_CLIMB;
else if (startswith(name, "FLOAT")) return S_PLAY_FLOAT;
else if (startswith(name, "FLOAT_RUN")) return S_PLAY_FLOAT_RUN;
else if (startswith(name, "BOUNCE")) return S_PLAY_BOUNCE;
else if (startswith(name, "BOUNCE_LANDING")) return S_PLAY_BOUNCE_LANDING;
else if (startswith(name, "FIRE")) return S_PLAY_FIRE;
else if (startswith(name, "FIRE_FINISH")) return S_PLAY_FIRE_FINISH;
else if (startswith(name, "TWINSPIN")) return S_PLAY_TWINSPIN;
else if (startswith(name, "MELEE")) return S_PLAY_MELEE;
else if (startswith(name, "MELEE_FINISH")) return S_PLAY_MELEE_FINISH;
else if (startswith(name, "MELEE_LANDING")) return S_PLAY_MELEE_LANDING;
else if (startswith(name, "NIGHTS_STAND")) return S_PLAY_NIGHTS_STAND;
else if (startswith(name, "NIGHTS_FLOAT")) return S_PLAY_NIGHTS_FLOAT;
else if (startswith(name, "NIGHTS_FLY")) return S_PLAY_NIGHTS_FLY;
else if (startswith(name, "NIGHTS_DRILL")) return S_PLAY_NIGHTS_DRILL;
else if (startswith(name, "NIGHTS_STUN")) return S_PLAY_NIGHTS_STUN;
else if (startswith(name, "NIGHTS_PULL")) return S_PLAY_NIGHTS_PULL;
else if (startswith(name, "NIGHTS_ATTACK")) return S_PLAY_NIGHTS_ATTACK;
else return S_NULL;
}
static void CacheCustomSkinStates(skin_t *skin)
{
SIMPLEHASH_CLEAR(skin->defaulttocustomstate, hashentry_int32_int32_t)
SIMPLEHASH_CLEAR(skin->customtodefaultstate, hashentry_int32_int32_t)
char *skinstateprefix = va("SKIN_%s_", skin->name);
strupr(skinstateprefix);
size_t skinstateprefixlen = strlen(skinstateprefix);
for (INT32 state = S_FIRSTFREESLOT; state <= S_LASTFREESLOT; state++)
{
const char *statename = FREE_STATES[state - S_FIRSTFREESLOT];
if (!statename)
continue;
if (strncmp(statename, skinstateprefix, skinstateprefixlen))
continue;
statenum_t defaultstate = GetCanonicalPlayerStateNumByName(&statename[skinstateprefixlen]);
if (defaultstate)
{
// If a default state is overriden by multiple custom states, use the first one as reference
// e.g. WALK+WALK2+WALK3+WALK4 instead of just WALK
statenum_t alreadyoverriden;
SIMPLEHASH_FIND_INT(skin->defaulttocustomstate, hashentry_int32_int32_t, defaultstate, S_NULL, alreadyoverriden)
if (!alreadyoverriden)
SIMPLEHASH_REPLACE_INT(skin->defaulttocustomstate, hashentry_int32_int32_t, defaultstate, state)
SIMPLEHASH_REPLACE_INT(skin->customtodefaultstate, hashentry_int32_int32_t, state, defaultstate)
}
}
}
// //
// Find skin sprites, sounds & optional status bar face, & add them // Find skin sprites, sounds & optional status bar face, & add them
// //
...@@ -927,6 +1028,8 @@ next_token: ...@@ -927,6 +1028,8 @@ next_token:
R_FlushTranslationColormapCache(); R_FlushTranslationColormapCache();
CacheCustomSkinStates(skin);
if (mainfile == false) if (mainfile == false)
CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name); CONS_Printf(M_GetText("Added skin '%s'\n"), skin->name);
...@@ -1064,6 +1167,8 @@ next_token: ...@@ -1064,6 +1167,8 @@ next_token:
R_FlushTranslationColormapCache(); R_FlushTranslationColormapCache();
CacheCustomSkinStates(skin);
if (mainfile == false) if (mainfile == false)
CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name); CONS_Printf(M_GetText("Patched skin '%s'\n"), skin->name);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "r_patch.h" #include "r_patch.h"
#include "r_picformats.h" // spriteinfo_t #include "r_picformats.h" // spriteinfo_t
#include "r_defs.h" // spritedef_t #include "r_defs.h" // spritedef_t
#include "simple_hashmap.h"
/// Defaults /// Defaults
#define SKINNAMESIZE 16 #define SKINNAMESIZE 16
...@@ -88,6 +89,12 @@ typedef struct ...@@ -88,6 +89,12 @@ typedef struct
spritedef_t sprites[NUMPLAYERSPRITES]; spritedef_t sprites[NUMPLAYERSPRITES];
spriteinfo_t sprinfo[NUMPLAYERSPRITES]; spriteinfo_t sprinfo[NUMPLAYERSPRITES];
} super; } super;
hashentry_int32_int32_t *defaulttocustomstate; // e.g. S_PLAY_WALK => S_SKIN_BIGTHECAT_WALK
hashentry_int32_int32_t *customtodefaultstate; // e.g. S_SKIN_BIGTHECAT_WALK => S_PLAY_WALK
// TODO: 2.3: Delete
spritedef_t sprites_compat[NUMPLAYERSPRITES * 2];
} skin_t; } skin_t;
/// Externs /// Externs
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -53,7 +53,7 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -53,7 +53,7 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
if (dir == 0) if (dir == 0)
{ {
for (;;) for (; count > 0; count--)
{ {
rastertab[y1].maxx = xs; rastertab[y1].maxx = xs;
rastertab[y1].tx2 = xe; rastertab[y1].tx2 = xe;
...@@ -62,13 +62,11 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -62,13 +62,11 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
xs += dx0; xs += dx0;
xe += dx1; xe += dx1;
y1++; y1++;
if (count-- < 1) break;
} }
} }
else else
{ {
for (;;) for (; count > 0; count--)
{ {
rastertab[y1].maxx = xs; rastertab[y1].maxx = xs;
rastertab[y1].tx2 = tc; rastertab[y1].tx2 = tc;
...@@ -77,8 +75,6 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -77,8 +75,6 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
xs += dx0; xs += dx0;
xe += dx1; xe += dx1;
y1++; y1++;
if (count-- < 1) break;
} }
} }
} }
...@@ -95,7 +91,7 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -95,7 +91,7 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
if (dir == 0) if (dir == 0)
{ {
for (;;) for (; count > 0; count--)
{ {
rastertab[y2].minx = xs; rastertab[y2].minx = xs;
rastertab[y2].tx1 = xe; rastertab[y2].tx1 = xe;
...@@ -104,13 +100,11 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -104,13 +100,11 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
xs += dx0; xs += dx0;
xe += dx1; xe += dx1;
y2++; y2++;
if (count-- < 1) break;
} }
} }
else else
{ {
for (;;) for (; count > 0; count--)
{ {
rastertab[y2].minx = xs; rastertab[y2].minx = xs;
rastertab[y2].tx1 = tc; rastertab[y2].tx1 = tc;
...@@ -119,8 +113,6 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 ...@@ -119,8 +113,6 @@ static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32
xs += dx0; xs += dx0;
xe += dx1; xe += dx1;
y2++; y2++;
if (count-- < 1) break;
} }
} }
} }
...@@ -381,7 +373,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr ...@@ -381,7 +373,7 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
if (pSplat->slope) if (pSplat->slope)
{ {
R_SetScaledSlopePlane(pSplat->slope, vis->viewpoint.x, vis->viewpoint.y, vis->viewpoint.z, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, vis->viewpoint.angle, pSplat->angle); R_SetScaledSlopePlane(pSplat->slope, vis->viewpoint.x, vis->viewpoint.y, vis->viewpoint.z, (INT64)pSplat->xscale, (INT64)pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, vis->viewpoint.angle, pSplat->angle);
} }
else if (!ds_solidcolor) else if (!ds_solidcolor)
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -147,9 +147,9 @@ static void R_DrawFlippedColumnInCache(column_t *column, UINT8 *cache, texpatch_ ...@@ -147,9 +147,9 @@ static void R_DrawFlippedColumnInCache(column_t *column, UINT8 *cache, texpatch_
if (count > 0) if (count > 0)
{ {
for (; dest < cache + position + count; --source, is_opaque++) for (; dest < cache + position + count; --source, dest++, is_opaque++)
{ {
*dest++ = *source; *dest = *source;
*is_opaque = true; *is_opaque = true;
} }
} }
...@@ -295,7 +295,6 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -295,7 +295,6 @@ UINT8 *R_GenerateTexture(size_t texnum)
UINT16 lumpnum = patch->lump; UINT16 lumpnum = patch->lump;
UINT8 *pdata; UINT8 *pdata;
softwarepatch_t *realpatch; softwarepatch_t *realpatch;
boolean holey = false;
#ifndef NO_PNG_LUMPS #ifndef NO_PNG_LUMPS
UINT8 header[PNG_HEADER_SIZE]; UINT8 header[PNG_HEADER_SIZE];
...@@ -310,9 +309,11 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -310,9 +309,11 @@ UINT8 *R_GenerateTexture(size_t texnum)
pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
realpatch = (softwarepatch_t *)pdata; realpatch = (softwarepatch_t *)pdata;
texture->transparency = false;
// Check the patch for holes. // Check the patch for holes.
if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height))
holey = true; texture->transparency = true;
else else
{ {
UINT8 *colofs = (UINT8 *)realpatch->columnofs; UINT8 *colofs = (UINT8 *)realpatch->columnofs;
...@@ -332,12 +333,12 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -332,12 +333,12 @@ UINT8 *R_GenerateTexture(size_t texnum)
col = (doompost_t *)((UINT8 *)col + col->length + 4); col = (doompost_t *)((UINT8 *)col + col->length + 4);
} }
if (y < texture->height) if (y < texture->height)
holey = true; // this texture is HOLEy! D: texture->transparency = true; // this texture is HOLEy! D:
} }
} }
// If the patch uses transparency, we have to save it this way. // If the patch uses transparency, we have to save it this way.
if (holey) if (texture->transparency)
{ {
texture->flip = patch->flip; texture->flip = patch->flip;
...@@ -378,6 +379,15 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -378,6 +379,15 @@ UINT8 *R_GenerateTexture(size_t texnum)
temp_columns = Z_Calloc(sizeof(column_t) * texture->width, PU_STATIC, NULL); temp_columns = Z_Calloc(sizeof(column_t) * texture->width, PU_STATIC, NULL);
temp_block = Z_Calloc(total_pixels, PU_STATIC, NULL); temp_block = Z_Calloc(total_pixels, PU_STATIC, NULL);
#ifdef TEXTURE_255_IS_TRANSPARENT
texture->transparency = false;
// Transparency hack
memset(temp_block, TRANSPARENTPIXEL, total_pixels);
#else
texture->transparency = true;
#endif
for (x = 0; x < texture->width; x++) for (x = 0; x < texture->width; x++)
{ {
column_t *column = &temp_columns[x]; column_t *column = &temp_columns[x];
...@@ -474,13 +484,27 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -474,13 +484,27 @@ UINT8 *R_GenerateTexture(size_t texnum)
// Now write the columns // Now write the columns
column_posts = Z_Calloc(sizeof(unsigned) * texture->width, PU_STATIC, NULL); column_posts = Z_Calloc(sizeof(unsigned) * texture->width, PU_STATIC, NULL);
#ifdef TEXTURE_255_IS_TRANSPARENT
total_posts = texture->width;
temp_posts = Z_Realloc(temp_posts, sizeof(post_t) * total_posts, PU_CACHE, NULL);
#endif
for (x = 0; x < texture->width; x++) for (x = 0; x < texture->width; x++)
{ {
post_t *post = NULL; post_t *post = NULL;
boolean was_opaque = false;
column_t *column = &temp_columns[x]; column_t *column = &temp_columns[x];
#ifdef TEXTURE_255_IS_TRANSPARENT
post = &temp_posts[x];
post->topdelta = 0;
post->length = texture->height;
post->data_offset = 0;
column_posts[x] = x;
column->num_posts = 1;
#else
boolean was_opaque = false;
column_posts[x] = (unsigned)-1; column_posts[x] = (unsigned)-1;
for (INT32 y = 0; y < texture->height; y++) for (INT32 y = 0; y < texture->height; y++)
...@@ -510,6 +534,7 @@ UINT8 *R_GenerateTexture(size_t texnum) ...@@ -510,6 +534,7 @@ UINT8 *R_GenerateTexture(size_t texnum)
post->length++; post->length++;
} }
#endif
} }
blocksize = (sizeof(column_t) * texture->width) + (sizeof(post_t) * total_posts) + (sizeof(UINT8) * total_pixels); blocksize = (sizeof(column_t) * texture->width) + (sizeof(post_t) * total_posts) + (sizeof(UINT8) * total_pixels);
...@@ -821,8 +846,8 @@ Rloadflats (INT32 i, INT32 w) ...@@ -821,8 +846,8 @@ Rloadflats (INT32 i, INT32 w)
UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
if (Picture_PNGDimensions((UINT8 *)flatlump, &texw, &texh, NULL, NULL, lumplength)) if (Picture_PNGDimensions((UINT8 *)flatlump, &texw, &texh, NULL, NULL, lumplength))
{ {
width = (INT16)width; width = (INT16)texw;
height = (INT16)height; height = (INT16)texh;
} }
else else
{ {
...@@ -900,7 +925,7 @@ Rloadtextures (INT32 i, INT32 w) ...@@ -900,7 +925,7 @@ Rloadtextures (INT32 i, INT32 w)
// printf("\"%s\" (wad: %u, lump: %u) is a single patch, dimensions %d x %d\n",W_CheckNameForNumPwad(wadnum,lumpnum),wadnum,lumpnum,width,height); // printf("\"%s\" (wad: %u, lump: %u) is a single patch, dimensions %d x %d\n",W_CheckNameForNumPwad(wadnum,lumpnum),wadnum,lumpnum,width,height);
R_AddSinglePatchTexture(i, wadnum, lumpnum, width, height, TEXTURETYPE_SINGLEPATCH); R_AddSinglePatchTexture(i, wadnum, lumpnum, width, height, TEXTURETYPE_TEXTURE);
i++; i++;
} }
...@@ -1068,6 +1093,98 @@ void R_LoadTexturesPwad(UINT16 wadnum) ...@@ -1068,6 +1093,98 @@ void R_LoadTexturesPwad(UINT16 wadnum)
R_FinishLoadingTextures(newtextures); R_FinishLoadingTextures(newtextures);
} }
static lumpnum_t W_GetTexPatchLumpNum(const char *name)
{
// Flats as a texture patch crashes horribly, and flats
// can share the same name as textures.
// But even if they worked, we want to prioritize:
// Patches -> Textures -> anything else
enum
{
USE_PATCHES,
USE_TEXTURES,
USE__MAX,
};
lumpnum_t lump = LUMPERROR;
INT32 lump_type_it;
for (lump_type_it = 0; lump_type_it < USE__MAX; lump_type_it++)
{
INT32 i;
for (i = numwadfiles - 1; i >= 0; i--) // Scan wad files backwards so patched lumps take precedent
{
lumpnum_t start = LUMPERROR;
lumpnum_t end = LUMPERROR;
switch (wadfiles[i]->type)
{
case RET_WAD:
if (lump_type_it == USE_PATCHES)
{
if ((start = W_CheckNumForMarkerStartPwad("P_START", (UINT16)i, 0)) == INT16_MAX)
continue;
else if ((end = W_CheckNumForNamePwad("P_END", (UINT16)i, start)) == INT16_MAX)
continue;
}
else if (lump_type_it == USE_TEXTURES)
{
if ((start = W_CheckNumForMarkerStartPwad("TX_START", (UINT16)i, 0)) == INT16_MAX)
continue;
else if ((end = W_CheckNumForNamePwad("TX_END", (UINT16)i, start)) == INT16_MAX)
continue;
}
break;
case RET_PK3:
case RET_FOLDER:
if (lump_type_it == USE_PATCHES)
{
if ((start = W_CheckNumForFolderStartPK3("Patches/", i, 0)) == INT16_MAX)
continue;
if ((end = W_CheckNumForFolderEndPK3("Patches/", i, start)) == INT16_MAX)
continue;
}
else if (lump_type_it == USE_TEXTURES)
{
if ((start = W_CheckNumForFolderStartPK3("Textures/", i, 0)) == INT16_MAX)
continue;
if ((end = W_CheckNumForFolderEndPK3("Textures/", i, start)) == INT16_MAX)
continue;
}
break;
default:
continue;
}
// Now find lump with specified name in that range.
lump = W_CheckNumForNamePwad(name, (UINT16)i, start);
if (lump < end)
{
lump += (i<<16); // found it, in our constraints
break;
}
lump = LUMPERROR;
}
if (lump != LUMPERROR)
{
break;
}
}
if (lump == LUMPERROR)
{
// Use whatever else you can find.
return W_CheckNumForPatchName(name);
}
return lump;
}
static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
{ {
char *texturesToken; char *texturesToken;
...@@ -1240,13 +1357,13 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) ...@@ -1240,13 +1357,13 @@ static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch)
if (actuallyLoadPatch == true) if (actuallyLoadPatch == true)
{ {
// Check lump exists // Check lump exists
patchLumpNum = W_GetNumForName(patchName); patchLumpNum = W_GetTexPatchLumpNum(patchName);
// If so, allocate memory for texpatch_t and fill 'er up // If so, allocate memory for texpatch_t and fill 'er up
resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL); resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL);
resultPatch->originx = patchXPos; resultPatch->originx = patchXPos;
resultPatch->originy = patchYPos; resultPatch->originy = patchYPos;
resultPatch->lump = patchLumpNum & 65535; resultPatch->lump = LUMPNUM(patchLumpNum);
resultPatch->wad = patchLumpNum>>16; resultPatch->wad = WADFILENUM(patchLumpNum);
resultPatch->flip = flip; resultPatch->flip = flip;
resultPatch->alpha = alpha; resultPatch->alpha = alpha;
resultPatch->style = style; resultPatch->style = style;
...@@ -1377,7 +1494,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) ...@@ -1377,7 +1494,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture)
resultTexture->hash = quickncasehash(newTextureName, 8); resultTexture->hash = quickncasehash(newTextureName, 8);
resultTexture->width = newTextureWidth; resultTexture->width = newTextureWidth;
resultTexture->height = newTextureHeight; resultTexture->height = newTextureHeight;
resultTexture->type = TEXTURETYPE_COMPOSITE; resultTexture->type = TEXTURETYPE_TEXTURE;
} }
Z_Free(texturesToken); Z_Free(texturesToken);
texturesToken = M_GetToken(NULL); texturesToken = M_GetToken(NULL);
...@@ -1563,7 +1680,7 @@ static void AddTextureToCache(const char *name, UINT32 hash, INT32 id, UINT8 typ ...@@ -1563,7 +1680,7 @@ static void AddTextureToCache(const char *name, UINT32 hash, INT32 id, UINT8 typ
// //
// Check whether texture is available. Filter out NoTexture indicator. // Check whether texture is available. Filter out NoTexture indicator.
// //
INT32 R_CheckTextureNumForName(const char *name) INT32 R_CheckTextureNumForName(const char *name, UINT8 type)
{ {
INT32 i; INT32 i;
UINT32 hash; UINT32 hash;
...@@ -1575,14 +1692,14 @@ INT32 R_CheckTextureNumForName(const char *name) ...@@ -1575,14 +1692,14 @@ INT32 R_CheckTextureNumForName(const char *name)
hash = quickncasehash(name, 8); hash = quickncasehash(name, 8);
for (i = 0; i < tidcachelen; i++) for (i = 0; i < tidcachelen; i++)
if (tidcache[i].hash == hash && !strncasecmp(tidcache[i].name, name, 8)) if (tidcache[i].type == type && tidcache[i].hash == hash && !strncasecmp(tidcache[i].name, name, 8))
return tidcache[i].id; return tidcache[i].id;
// Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier // Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier
for (i = numtextures - 1; i >= 0; i--) for (i = numtextures - 1; i >= 0; i--)
if (textures[i]->hash == hash && !strncasecmp(textures[i]->name, name, 8)) if (textures[i]->type == type && textures[i]->hash == hash && !strncasecmp(textures[i]->name, name, 8))
{ {
AddTextureToCache(name, hash, i, textures[i]->type); AddTextureToCache(name, hash, i, type);
return i; return i;
} }
...@@ -1599,7 +1716,7 @@ const char *R_CheckTextureNameForNum(INT32 num) ...@@ -1599,7 +1716,7 @@ const char *R_CheckTextureNameForNum(INT32 num)
{ {
if (num > 0 && num < numtextures) if (num > 0 && num < numtextures)
return textures[num]->name; return textures[num]->name;
return "-"; return "-";
} }
...@@ -1621,47 +1738,29 @@ const char *R_TextureNameForNum(INT32 num) ...@@ -1621,47 +1738,29 @@ const char *R_TextureNameForNum(INT32 num)
// //
// R_TextureNumForName // R_TextureNumForName
// //
// Calls R_CheckTextureNumForName, aborts with error message. // Calls R_CheckTextureNumForName. Returns REDWALL if not found.
// //
INT32 R_TextureNumForName(const char *name) INT32 R_TextureNumForName(const char *name)
{ {
const INT32 i = R_CheckTextureNumForName(name); INT32 i = R_CheckTextureNumForName(name, TEXTURETYPE_TEXTURE);
// Didn't find it, so look for a flat
if (i == -1)
{
i = R_CheckTextureNumForName(name, TEXTURETYPE_FLAT);
}
// Still didn't find it, so return REDWALL
if (i == -1) if (i == -1)
{ {
static INT32 redwall = -2; static INT32 redwall = -2;
CONS_Debug(DBG_SETUP, "WARNING: R_TextureNumForName: %.8s not found\n", name); CONS_Debug(DBG_SETUP, "WARNING: R_TextureNumForName: %.8s not found\n", name);
if (redwall == -2) if (redwall == -2)
redwall = R_CheckTextureNumForName("REDWALL"); redwall = R_CheckTextureNumForName("REDWALL", TEXTURETYPE_TEXTURE);
if (redwall != -1) if (redwall != -1)
return redwall; return redwall;
return 1; return 1;
} }
return i;
}
// Like R_CheckTextureNumForName, but only looks in the flat namespace specifically.
INT32 R_CheckFlatNumForName(const char *name)
{
INT32 i;
UINT32 hash;
// "NoTexture" marker. return i;
if (name[0] == '-')
return 0;
hash = quickncasehash(name, 8);
for (i = 0; i < tidcachelen; i++)
if (tidcache[i].type == TEXTURETYPE_FLAT && tidcache[i].hash == hash && !strncasecmp(tidcache[i].name, name, 8))
return tidcache[i].id;
for (i = numtextures - 1; i >= 0; i--)
if (textures[i]->hash == hash && !strncasecmp(textures[i]->name, name, 8) && textures[i]->type == TEXTURETYPE_FLAT)
{
AddTextureToCache(name, hash, i, TEXTURETYPE_FLAT);
return i;
}
return -1;
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -40,8 +40,7 @@ typedef struct ...@@ -40,8 +40,7 @@ typedef struct
enum enum
{ {
TEXTURETYPE_UNKNOWN, TEXTURETYPE_UNKNOWN,
TEXTURETYPE_SINGLEPATCH, TEXTURETYPE_TEXTURE,
TEXTURETYPE_COMPOSITE,
TEXTURETYPE_FLAT TEXTURETYPE_FLAT
}; };
...@@ -54,6 +53,7 @@ typedef struct ...@@ -54,6 +53,7 @@ typedef struct
char name[8]; char name[8];
UINT32 hash; UINT32 hash;
UINT8 type; // TEXTURETYPE_* UINT8 type; // TEXTURETYPE_*
boolean transparency;
INT16 width, height; INT16 width, height;
UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both
void *flat; // The texture, as a flat. void *flat; // The texture, as a flat.
...@@ -99,8 +99,7 @@ void R_SetFlatVars(size_t length); ...@@ -99,8 +99,7 @@ void R_SetFlatVars(size_t length);
// Returns the texture number for the texture name. // Returns the texture number for the texture name.
INT32 R_TextureNumForName(const char *name); INT32 R_TextureNumForName(const char *name);
INT32 R_CheckTextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name, UINT8 type);
INT32 R_CheckFlatNumForName(const char *name);
// Returns the texture name for the texture number (in case you ever needed it) // Returns the texture name for the texture number (in case you ever needed it)
const char *R_CheckTextureNameForNum(INT32 num); const char *R_CheckTextureNameForNum(INT32 num);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -77,7 +77,7 @@ spriteinfo_t spriteinfo[NUMSPRITES]; ...@@ -77,7 +77,7 @@ spriteinfo_t spriteinfo[NUMSPRITES];
spritedef_t *sprites; spritedef_t *sprites;
size_t numsprites; size_t numsprites;
static spriteframe_t sprtemp[64]; static spriteframe_t sprtemp[MAXFRAMENUM];
static size_t maxframe; static size_t maxframe;
static const char *spritename; static const char *spritename;
...@@ -116,6 +116,14 @@ static INT32 drawsegs_xrange_count = 0; ...@@ -116,6 +116,14 @@ static INT32 drawsegs_xrange_count = 0;
// //
// ========================================================================== // ==========================================================================
spritenum_t R_GetSpriteNumByName(const char *name)
{
for (spritenum_t i = 0; i < NUMSPRITES; i++)
if (!strcmp(name, sprnames[i]))
return i;
return NUMSPRITES;
}
// //
// //
// //
...@@ -128,10 +136,14 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -128,10 +136,14 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{ {
char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
char framedescription[256];
if (cn != '\xFF')
sprintf(framedescription, "%s frame %d (%c)", spritename, frame, cn);
else
sprintf(framedescription, "%s frame %d", spritename, frame);
INT32 r; INT32 r;
lumpnum_t lumppat = wad; lumpnum_t lumppat = (wad << 16) + lump;
lumppat <<= 16;
lumppat += lump;
if (maxframe ==(size_t)-1 || frame > maxframe) if (maxframe ==(size_t)-1 || frame > maxframe)
maxframe = frame; maxframe = frame;
...@@ -147,9 +159,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -147,9 +159,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{ {
// the lump should be used for all rotations // the lump should be used for all rotations
if (sprtemp[frame].rotate == SRF_SINGLE) if (sprtemp[frame].rotate == SRF_SINGLE)
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has rotations and a rot = 0 lump\n", framedescription);
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
for (r = 0; r < 16; r++) for (r = 0; r < 16; r++)
...@@ -169,15 +181,15 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -169,15 +181,15 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (sprtemp[frame].rotate == SRF_NONE) if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
else if (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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has L/R rotations and a rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate == SRF_3D) 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8 rotations\n", framedescription);
else if (sprtemp[frame].rotate == SRF_3DGE) 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-G rotations\n", framedescription);
else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L)) 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple L rotations\n", framedescription);
else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R)) 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has multiple R rotations\n", framedescription);
sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT); sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D) if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
...@@ -204,9 +216,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -204,9 +216,9 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (sprtemp[frame].rotate == SRF_NONE) if (sprtemp[frame].rotate == SRF_NONE)
sprtemp[frame].rotate = SRF_SINGLE; sprtemp[frame].rotate = SRF_SINGLE;
else if (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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has 1-8/G rotations and a rot = 0 lump\n", framedescription);
else if (sprtemp[frame].rotate & SRF_2D) 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); CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s has both L/R and 1-8/G rotations\n", framedescription);
// make 0 based // make 0 based
rotation--; rotation--;
...@@ -226,7 +238,12 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -226,7 +238,12 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
} }
if (sprtemp[frame].lumppat[rotation] != LUMPERROR) 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, cr); {
if (cn != '\xFF')
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c (%c%c) has two lumps mapped to it\n", spritename, frame, cr, cn, cr);
else
CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %d_%c has two lumps mapped to it\n", spritename, frame, cr);
}
// lumppat & lumpid are the same for original Doom, but different // lumppat & lumpid are the same for original Doom, but different
// when using sprites in pwad : the lumppat points the new graphics // when using sprites in pwad : the lumppat points the new graphics
...@@ -238,24 +255,209 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch ...@@ -238,24 +255,209 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
sprtemp[frame].flip &= ~(1<<rotation); sprtemp[frame].flip &= ~(1<<rotation);
} }
static boolean GetFramesAndRotationsFromShortLumpName(
const char *name,
INT32 *ret_frame,
UINT8 *ret_rotation,
INT32 *ret_frame2,
UINT8 *ret_rotation2
)
{
size_t namelen = strlen(name);
if (namelen != 6 && namelen != 8)
return false;
*ret_frame = R_Char2Frame(name[4]);
*ret_rotation = R_Char2Rotation(name[5]);
if (*ret_frame >= 64 || *ret_rotation == 255)
return false;
if (namelen == 8)
{
*ret_frame2 = R_Char2Frame(name[6]);
*ret_rotation2 = R_Char2Rotation(name[7]);
if (*ret_frame2 >= 64 || *ret_rotation2 == 255)
return false;
// TRNSLATE is a valid but extremely unlikely sprite name:
// * The sprite name is "TRNS"
// * The frame is L, rotation A; mirrored to frame T, rotation E
// In the very unfortunate event that TRNSLATE is found between sprite lumps,
// this name check prevents it from being added as a sprite, when it actually isn't.
if (memcmp(name, "TRNSLATE", 8) == 0)
return false;
}
else
{
*ret_frame2 = -1;
*ret_rotation2 = 255;
}
return true;
}
static boolean GetSingleFrameAndRotation(
const char *name,
size_t len,
INT32 *ret_frame,
UINT8 *ret_rotation
)
{
const char *underscore = strchr(name, '_');
// Found but past the part of the name we are parsing
if ((size_t)(underscore - name) >= len)
underscore = NULL;
size_t framelen = underscore ? (size_t)(underscore - name) : len;
if (framelen < 1 || framelen > 4)
return false;
char framepart[4 + 1]; // Max 9999
strlcpy(framepart, name, framelen + 1);
for (size_t i = 0; i < framelen; i++)
if (!isdigit(framepart[i]))
return false;
*ret_frame = atoi(framepart);
*ret_rotation = underscore ? R_Char2Rotation(*(underscore + 1)) : 0;
if (*ret_frame >= MAXFRAMENUM || *ret_rotation == 255)
return false;
return true;
}
static boolean GetFramesAndRotationsFromLongLumpName(
const char *name,
INT32 *ret_frame,
UINT8 *ret_rotation,
INT32 *ret_frame2,
UINT8 *ret_rotation2
)
{
const char *plus = strchr(name, '+');
if (plus)
{
size_t len1 = plus - name;
if (!GetSingleFrameAndRotation(name, len1, ret_frame, ret_rotation))
return false;
if (!GetSingleFrameAndRotation(plus + 1, strlen(name) - len1 - 1, ret_frame2, ret_rotation2))
return false;
}
else
{
if (!GetSingleFrameAndRotation(name, strlen(name), ret_frame, ret_rotation))
return false;
*ret_frame2 = -1;
*ret_rotation2 = 255;
}
return true;
}
static UINT8 GetOppositeRotation(UINT8 rotation, UINT8 flags)
{
if (flags & ~SRF_3DMASK)
I_Error("GetOppositeRotation: rotation type not supported");
UINT8 numrotations = (flags == SRF_3D) ? 8 : 16;
return (rotation == 1) ? 1 : numrotations + 2 - rotation;
}
static void MirrorMissingRotations(void)
{
for (UINT32 framenum = 0; framenum < maxframe; framenum++)
{
spriteframe_t *frame = &sprtemp[framenum];
if (frame->rotate == SRF_NONE || !(frame->rotate & (SRF_3DMASK | SRF_2D)))
continue;
UINT8 numrotations = frame->rotate == SRF_3D ? 8 : 16;
for (UINT8 rotation = 1; rotation <= numrotations; rotation++)
{
if (frame->lumppat[rotation - 1] != LUMPERROR)
continue;
UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate);
UINT32 lumpnum = frame->lumppat[baserotation - 1];
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation - 1], framenum, rotation, 1);
}
}
}
// Some checks to help development
static void CheckFrame(const char *sprname)
{
for (UINT32 frame = 0; frame < maxframe; frame++)
{
spriteframe_t *spriteframe = &sprtemp[frame];
char framedescription[256];
if (frame < 64)
sprintf(framedescription, "%s frame %d (%c)", sprname, frame, R_Frame2Char(frame));
else
sprintf(framedescription, "%s frame %d", sprname, frame);
switch (spriteframe->rotate)
{
case SRF_NONE:
// no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found for %s", framedescription);
break;
case SRF_SINGLE:
// only the first rotation is needed
break;
case SRF_2D: // both Left and Right rotations
// we test to see whether the left and right slots are present
if ((spriteframe->lumppat[2] == LUMPERROR) || (spriteframe->lumppat[6] == LUMPERROR))
I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (L-R mode)",
framedescription);
break;
default:
{
// must have all 8/16 frames
UINT8 rotation = ((spriteframe->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 (spriteframe->lumppat[rotation] == LUMPERROR)
I_Error("R_AddSingleSpriteDef: Sprite %s is missing rotations (1-%c mode)",
framedescription, ((spriteframe->rotate & SRF_3DGE) ? 'G' : '8'));
}
}
break;
}
}
}
// Install a single sprite, given its identifying name (4 chars) // Install a single sprite, given its identifying name (4 chars)
// //
// (originally part of R_AddSpriteDefs) // (originally part of R_AddSpriteDefs)
// //
// Pass: name of sprite : 4 chars // Pass: name of sprite
// spritedef_t // spritedef_t
// wadnum : wad number, indexes wadfiles[], where patches // wadnum : wad number, indexes wadfiles[], where patches
// for frames are found // for frames are found
// startlump : first lump to search for sprite frames // startlump : first lump to search for sprite frames
// endlump : AFTER the last lump to search // endlump : AFTER the last lump to search
// longname : whether to use long sprite names or 4-char names
// //
// Returns true if the sprite was succesfully added // Returns true if the sprite was succesfully added
// //
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump) boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname)
{ {
UINT16 l; UINT16 l;
UINT8 frame;
UINT8 rotation;
lumpinfo_t *lumpinfo; lumpinfo_t *lumpinfo;
UINT16 numadded = 0; UINT16 numadded = 0;
...@@ -282,15 +484,23 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 ...@@ -282,15 +484,23 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
for (l = startlump; l < endlump; l++) for (l = startlump; l < endlump; l++)
{ {
if (memcmp(lumpinfo[l].name,sprname,4)==0) if (longname && W_IsLumpFolder(wadnum, l))
I_Error("R_AddSingleSpriteDef: all frame lumps for a sprite should be contained inside a single folder\n");
// For long sprites, the startlump-endlump range only includes
// relevant lumps, so no check needed in that case
if (longname || (strlen(sprname) == 4 && !memcmp(lumpinfo[l].name, sprname, 4)))
{ {
INT16 width, height; INT16 width, height;
INT16 topoffset, leftoffset; INT16 topoffset, leftoffset;
INT32 frame, frame2;
UINT8 rotation, rotation2;
frame = R_Char2Frame(lumpinfo[l].name[4]); boolean good = longname ?
rotation = R_Char2Rotation(lumpinfo[l].name[5]); GetFramesAndRotationsFromLongLumpName(lumpinfo[l].longname, &frame, &rotation, &frame2, &rotation2) :
GetFramesAndRotationsFromShortLumpName(lumpinfo[l].name, &frame, &rotation, &frame2, &rotation2);
if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-... if (!good) // Give an actual NAME error -_-...
{ {
CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l)); CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
continue; continue;
...@@ -322,19 +532,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 ...@@ -322,19 +532,8 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
//---------------------------------------------------- //----------------------------------------------------
R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0); R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0);
if (frame2 != -1)
if (lumpinfo[l].name[6]) R_InstallSpriteLump(wadnum, l, numspritelumps, frame2, rotation2, 1);
{
frame = R_Char2Frame(lumpinfo[l].name[6]);
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);
}
if (++numspritelumps >= max_spritelumps) if (++numspritelumps >= max_spritelumps)
{ {
...@@ -374,41 +573,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 ...@@ -374,41 +573,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
maxframe++; maxframe++;
// if (longname)
// some checks to help development MirrorMissingRotations();
//
for (frame = 0; frame < maxframe; frame++)
{
switch (sprtemp[frame].rotate)
{
case SRF_NONE:
// no rotations were found for that frame at all
I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
break;
case SRF_SINGLE:
// only the first rotation is needed
break;
case SRF_2D: // both Left and Right rotations CheckFrame(sprname);
// 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 (L-R mode)",
sprname, R_Frame2Char(frame));
break;
default:
// 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 (1-%c mode)",
sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
break;
}
}
// allocate space for the frames present and copy sprtemp to it // allocate space for the frames present and copy sprtemp to it
if (spritedef->numframes && // has been allocated if (spritedef->numframes && // has been allocated
...@@ -429,14 +597,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 ...@@ -429,14 +597,10 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
return true; return true;
} }
// static void AddShortSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
// Search for sprites replacements in a wad whose names are in namelist
//
void R_AddSpriteDefs(UINT16 wadnum)
{ {
size_t i, addsprites = 0; size_t i;
UINT16 start, end; UINT16 start, end;
char wadname[MAX_WADPATH];
// Find the sprites section in this resource file. // Find the sprites section in this resource file.
switch (wadfiles[wadnum]->type) switch (wadfiles[wadnum]->type)
...@@ -474,27 +638,90 @@ void R_AddSpriteDefs(UINT16 wadnum) ...@@ -474,27 +638,90 @@ void R_AddSpriteDefs(UINT16 wadnum)
return; return;
} }
// //
// scan through lumps, for each sprite, find all the sprite frames // scan through lumps, for each sprite, find all the sprite frames
// //
for (i = 0; i < numsprites; i++) for (i = 0; i < numsprites; i++)
{ {
if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4]) if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end, false))
continue;
if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
{ {
// if a new sprite was added (not just replaced) // if a new sprite was added (not just replaced)
addsprites++; (*ptr_spritesadded)++;
#ifndef ZDEBUG #ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum); CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
#endif #endif
} }
} }
nameonly(strcpy(wadname, wadfiles[wadnum]->filename)); *ptr_framesadded += end - start;
CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites)); }
static void AddLongSpriteDefs(UINT16 wadnum, size_t *ptr_spritesadded, size_t *ptr_framesadded)
{
if (!W_FileHasFolders(wadfiles[wadnum]))
return;
UINT16 start = W_CheckNumForFolderStartPK3("LongSprites/", wadnum, 0);
UINT16 end = W_CheckNumForFolderEndPK3("LongSprites/", wadnum, start);
if (start == INT16_MAX || end == INT16_MAX || start >= end)
return;
size_t lumpnum = start;
while (lumpnum < end)
{
if (W_IsLumpFolder(wadnum, lumpnum))
{
lumpnum++;
continue;
}
UINT16 folderstart, folderend;
char *folderpath = W_GetLumpFolderPathPK3(wadnum, lumpnum);
folderstart = lumpnum;
folderend = W_CheckNumForFolderEndPK3(folderpath, wadnum, lumpnum);
Z_Free(folderpath);
spritenum_t sprnum;
char *sprname = W_GetLumpFolderNamePK3(wadnum, lumpnum);
strupr(sprname);
sprnum = R_GetSpriteNumByName(sprname);
if (sprnum != NUMSPRITES && R_AddSingleSpriteDef(sprname, &sprites[sprnum], wadnum, folderstart, folderend, true))
{
// A new sprite was added (not just replaced)
(*ptr_spritesadded)++;
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "long sprite %s set in pwad %d\n", sprname, wadnum);
#endif
}
Z_Free(sprname);
lumpnum = folderend;
}
*ptr_framesadded += end - start;
}
//
// Search for sprites replacements in a wad whose names are in namelist
//
void R_AddSpriteDefs(UINT16 wadnum)
{
char wadname[MAX_WADPATH];
size_t spritesadded = 0;
size_t framesadded = 0;
AddShortSpriteDefs(wadnum, &spritesadded, &framesadded);
AddLongSpriteDefs(wadnum, &spritesadded, &framesadded);
if (spritesadded || framesadded)
{
nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
CONS_Printf(M_GetText("%s added %s frames in %s sprites\n"), wadname, sizeu1(framesadded), sizeu2(spritesadded));
}
} }
// //
...@@ -620,8 +847,10 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol) ...@@ -620,8 +847,10 @@ void R_DrawMaskedColumn(column_t *column, unsigned lengthcol)
{ {
post_t *post = &column->posts[i]; post_t *post = &column->posts[i];
dc_postlength = post->length;
INT32 topscreen = sprtopscreen + spryscale*post->topdelta; INT32 topscreen = sprtopscreen + spryscale*post->topdelta;
INT32 bottomscreen = topscreen + spryscale*post->length; INT32 bottomscreen = topscreen + spryscale*dc_postlength;
dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS;
...@@ -690,10 +919,12 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol) ...@@ -690,10 +919,12 @@ void R_DrawFlippedMaskedColumn(column_t *column, unsigned lengthcol)
if (!post->length) if (!post->length)
continue; continue;
topdelta = lengthcol-post->length-post->topdelta; dc_postlength = post->length;
topdelta = lengthcol-dc_postlength-post->topdelta;
topscreen = sprtopscreen + spryscale*topdelta; topscreen = sprtopscreen + spryscale*topdelta;
bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*post->length bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*dc_postlength
: sprbotscreen + spryscale*post->length; : sprbotscreen + spryscale*dc_postlength;
dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
dc_yh = (bottomscreen-1)>>FRACBITS; dc_yh = (bottomscreen-1)>>FRACBITS;
...@@ -737,7 +968,9 @@ UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 trans ...@@ -737,7 +968,9 @@ UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 trans
if (color != SKINCOLOR_NONE) if (color != SKINCOLOR_NONE)
{ {
// New colormap stuff for skins Tails 06-07-2002 // New colormap stuff for skins Tails 06-07-2002
if (mobj->colorized) if ((mobj->state-states == S_METALSONIC_DASH || mobj->state-states == S_METALSONIC_BOUNCE) && (((leveltime/2) & 1))) // Metal boss doing attack
skinnum = TC_DASHMODE;
else if (mobj->colorized)
skinnum = TC_RAINBOW; skinnum = TC_RAINBOW;
else if (mobj->player && mobj->player->dashmode >= DASHMODE_THRESHOLD else if (mobj->player && mobj->player->dashmode >= DASHMODE_THRESHOLD
&& (mobj->player->charflags & SF_DASHMODE) && (mobj->player->charflags & SF_DASHMODE)
...@@ -773,6 +1006,12 @@ UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 trans ...@@ -773,6 +1006,12 @@ UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 trans
return NULL; return NULL;
} }
// Based off of R_GetLinedefTransTable
transnum_t R_GetThingTransTable(fixed_t alpha, transnum_t transmap)
{
return (20*(FRACUNIT - ((alpha * (10 - transmap))/10) - 1) + FRACUNIT) >> (FRACBITS+1);
}
// //
// R_DrawVisSprite // R_DrawVisSprite
// mfloorclip and mceilingclip should also be set. // mfloorclip and mceilingclip should also be set.
...@@ -1278,6 +1517,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, ...@@ -1278,6 +1517,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
floordiff = abs((isflipped ? interp.height : 0) + interp.z - groundz); floordiff = abs((isflipped ? interp.height : 0) + interp.z - groundz);
trans = floordiff / (100*FRACUNIT) + 3; trans = floordiff / (100*FRACUNIT) + 3;
trans = R_GetThingTransTable(thing->alpha, trans);
if (trans >= 9) return; if (trans >= 9) return;
scalemul = FixedMul(FRACUNIT - floordiff/640, scale); scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
...@@ -1551,6 +1791,10 @@ static void R_ProjectSprite(mobj_t *thing) ...@@ -1551,6 +1791,10 @@ static void R_ProjectSprite(mobj_t *thing)
} }
this_scale = interp.scale; this_scale = interp.scale;
if (this_scale < 1)
return;
radius = interp.radius; // For drop shadows radius = interp.radius; // For drop shadows
height = interp.height; // Ditto height = interp.height; // Ditto
...@@ -1965,6 +2209,11 @@ static void R_ProjectSprite(mobj_t *thing) ...@@ -1965,6 +2209,11 @@ static void R_ProjectSprite(mobj_t *thing)
else else
trans = 0; trans = 0;
if ((oldthing->flags2 & MF2_LINKDRAW) && oldthing->tracer)
trans = R_GetThingTransTable(oldthing->tracer->alpha, trans);
else
trans = R_GetThingTransTable(oldthing->alpha, trans);
// Check if this sprite needs to be rendered like a shadow // Check if this sprite needs to be rendered like a shadow
shadowdraw = (!!(thing->renderflags & RF_SHADOWDRAW) && !(papersprite || splat)); shadowdraw = (!!(thing->renderflags & RF_SHADOWDRAW) && !(papersprite || splat));
shadoweffects = (thing->renderflags & RF_SHADOWEFFECTS); shadoweffects = (thing->renderflags & RF_SHADOWEFFECTS);
...@@ -3425,6 +3674,7 @@ boolean R_ThingVisible (mobj_t *thing) ...@@ -3425,6 +3674,7 @@ boolean R_ThingVisible (mobj_t *thing)
(thing->sprite == SPR_NULL) || // Don't draw null-sprites (thing->sprite == SPR_NULL) || // Don't draw null-sprites
(thing->flags2 & MF2_DONTDRAW) || // Don't draw MF2_LINKDRAW objects (thing->flags2 & MF2_DONTDRAW) || // Don't draw MF2_LINKDRAW objects
(thing->drawonlyforplayer && thing->drawonlyforplayer != viewplayer) || // Don't draw other players' personal objects (thing->drawonlyforplayer && thing->drawonlyforplayer != viewplayer) || // Don't draw other players' personal objects
(!R_BlendLevelVisible(thing->blendmode, R_GetThingTransTable(thing->alpha, 0))) ||
(!P_MobjWasRemoved(r_viewmobj) && ( (!P_MobjWasRemoved(r_viewmobj) && (
(r_viewmobj == thing) || // Don't draw first-person players or awayviewmobj objects (r_viewmobj == thing) || // Don't draw first-person players or awayviewmobj objects
(r_viewmobj->player && r_viewmobj->player->followmobj == thing) || // Don't draw first-person players' followmobj (r_viewmobj->player && r_viewmobj->player->followmobj == thing) || // Don't draw first-person players' followmobj
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team. // Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior. // Copyright (C) 1999-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef #define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump); spritenum_t R_GetSpriteNumByName(const char *name);
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump, boolean longname);
//faB: find sprites in wadfile, replace existing, add new ones //faB: find sprites in wadfile, replace existing, add new ones
// (only sprites from namelist are added or replaced) // (only sprites from namelist are added or replaced)
...@@ -91,6 +93,7 @@ boolean R_ThingIsFullDark (mobj_t *thing); ...@@ -91,6 +93,7 @@ boolean R_ThingIsFullDark (mobj_t *thing);
boolean R_ThingIsFlashing (mobj_t *thing); boolean R_ThingIsFlashing (mobj_t *thing);
UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 translation); UINT8 *R_GetTranslationForThing(mobj_t *mobj, skincolornum_t color, UINT16 translation);
transnum_t R_GetThingTransTable(fixed_t alpha, transnum_t transmap);
void R_ThingOffsetOverlay (mobj_t *thing, fixed_t *outx, fixed_t *outy); void R_ThingOffsetOverlay (mobj_t *thing, fixed_t *outx, fixed_t *outy);
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2006 by Randy Heit. // Copyright (C) 1998-2006 by Randy Heit.
// Copyright (C) 2023 by Sonic Team Junior. // Copyright (C) 2023-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......
// SONIC ROBO BLAST 2 // SONIC ROBO BLAST 2
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 1998-2006 by Randy Heit. // Copyright (C) 1998-2006 by Randy Heit.
// Copyright (C) 2023 by Sonic Team Junior. // Copyright (C) 2023-2024 by Sonic Team Junior.
// //
// This program is free software distributed under the // This program is free software distributed under the
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
......