Merge branch 'rotsprite_i' into 'master'

Sprite rotation (resolves #183)

Closes #183

See merge request STJr/SRB2Internal!430
This commit is contained in:
MascaraSnake 2019-11-14 14:58:13 -05:00
commit 3352f914d7
37 changed files with 2752 additions and 896 deletions

View File

@ -123,6 +123,7 @@ set(SRB2_CORE_RENDER_SOURCES
r_sky.c
r_splats.c
r_things.c
r_patch.c
r_portal.c
r_bsp.h
@ -137,6 +138,7 @@ set(SRB2_CORE_RENDER_SOURCES
r_splats.h
r_state.h
r_things.h
r_patch.h
r_portal.h
)

View File

@ -471,6 +471,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/r_sky.o \
$(OBJDIR)/r_splats.o \
$(OBJDIR)/r_things.o \
$(OBJDIR)/r_patch.o \
$(OBJDIR)/r_portal.o \
$(OBJDIR)/screen.o \
$(OBJDIR)/v_video.o \

View File

@ -791,7 +791,7 @@ static void resynch_read_player(resynch_pak *rsp)
players[i].mo->scalespeed = LONG(rsp->scalespeed);
// And finally, SET THE MOBJ SKIN damn it.
if ((players[i].powers[pw_carry] == CR_NIGHTSMODE) && (skins[players[i].skin].sprites[SPR2_NGT0].numframes == 0))
if ((players[i].powers[pw_carry] == CR_NIGHTSMODE) && (skins[players[i].skin].sprites[SPR2_NFLY].numframes == 0))
{
players[i].mo->skin = &skins[DEFAULTNIGHTSSKIN];
players[i].mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor; // this will be corrected by thinker to super flash

View File

@ -47,6 +47,7 @@ typedef enum
SF_DASHMODE = 1<<11, // Sonic Advance 2 style top speed increase?
SF_FASTEDGE = 1<<12, // Faster edge teeter?
SF_MULTIABILITY = 1<<13, // Revenge of Final Demo.
SF_NONIGHTSROTATION = 1<<14, // Disable sprite rotation for NiGHTS
// free up to and including 1<<31
} skinflags_t;

View File

@ -29,6 +29,7 @@
#include "p_setup.h"
#include "r_data.h"
#include "r_draw.h"
#include "r_patch.h"
#include "r_sky.h"
#include "fastcmp.h"
#include "lua_script.h"
@ -803,50 +804,251 @@ static void readlight(MYFILE *f, INT32 num)
Z_Free(s);
}
#endif // HWRENDER
static void readspritelight(MYFILE *f, INT32 num)
static void readspriteframe(MYFILE *f, spriteinfo_t *sprinfo, UINT8 frame)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word;
char *word, *word2;
char *tmp;
INT32 value;
char *lastline;
do
{
lastline = f->curpos;
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
value = searchvalue(s);
// Set / reset word
word = s;
while ((*word == '\t') || (*word == ' '))
word++;
word = strtok(s, " ");
if (word)
strupr(word);
else
break;
if (fastcmp(word, "LIGHTTYPE"))
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
{
INT32 oldvar;
for (oldvar = 0; t_lspr[num] != &lspr[oldvar]; oldvar++)
;
t_lspr[num] = &lspr[value];
*(tmp-1) = '\0';
// Now get the part after
word2 = tmp += 2;
}
else
deh_warning("Sprite %d: unknown word '%s'", num, word);
{
// Get the part before the " "
tmp = strchr(s, ' ');
if (tmp)
{
*tmp = '\0';
// Now get the part after
tmp++;
word2 = tmp;
}
else
break;
}
strupr(word);
value = atoi(word2); // used for numerical settings
#ifdef ROTSPRITE
if (fastcmp(word, "XPIVOT"))
sprinfo->pivot[frame].x = value;
else if (fastcmp(word, "YPIVOT"))
sprinfo->pivot[frame].y = value;
else if (fastcmp(word, "ROTAXIS"))
sprinfo->pivot[frame].rotaxis = value;
#endif
else
{
f->curpos = lastline;
break;
}
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word, *word2;
char *tmp;
INT32 value;
char *lastline;
INT32 skinnumbers[MAXSKINS];
INT32 foundskins = 0;
// allocate a spriteinfo
spriteinfo_t *info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL);
info->available = true;
#ifdef ROTSPRITE
if ((sprites != NULL) && (!sprite2))
R_FreeSingleRotSprite(&sprites[num]);
#endif
do
{
lastline = f->curpos;
if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Set / reset word
word = s;
while ((*word == '\t') || (*word == ' '))
word++;
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
{
*(tmp-1) = '\0';
// Now get the part after
word2 = tmp += 2;
}
else
{
// Get the part before the " "
tmp = strchr(s, ' ');
if (tmp)
{
*tmp = '\0';
// Now get the part after
tmp++;
word2 = tmp;
}
else
break;
}
strupr(word);
value = atoi(word2); // used for numerical settings
#ifdef HWRENDER
if (fastcmp(word, "LIGHTTYPE"))
{
if (sprite2)
deh_warning("Sprite2 %s: invalid word '%s'", spr2names[num], word);
else
{
INT32 oldvar;
for (oldvar = 0; t_lspr[num] != &lspr[oldvar]; oldvar++)
;
t_lspr[num] = &lspr[value];
}
}
else
#endif
if (fastcmp(word, "SKIN"))
{
INT32 skinnum = -1;
if (!sprite2)
{
deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word);
continue;
}
// make lowercase
strlwr(word2);
skinnum = R_SkinAvailable(word2);
if (skinnum == -1)
{
deh_warning("Sprite2 %s: unknown skin %s", spr2names[num], word2);
break;
}
skinnumbers[foundskins] = skinnum;
foundskins++;
}
else if (fastcmp(word, "DEFAULT"))
{
if (!sprite2)
{
deh_warning("Sprite %s: %s keyword found outside of SPRITE2INFO block, ignoring", spr2names[num], word);
continue;
}
if (num < (INT32)free_spr2 && num >= (INT32)SPR2_FIRSTFREESLOT)
spr2defaults[num] = get_number(word2);
else
{
deh_warning("Sprite2 %s: out of range (%d - %d), ignoring", spr2names[num], SPR2_FIRSTFREESLOT, free_spr2-1);
continue;
}
}
else if (fastcmp(word, "FRAME"))
{
UINT8 frame = R_Char2Frame(word2[0]);
// frame number too high
if (frame >= 64)
{
if (sprite2)
deh_warning("Sprite2 %s: invalid frame %s", spr2names[num], word2);
else
deh_warning("Sprite %s: invalid frame %s", sprnames[num], word2);
break;
}
// read sprite frame and store it in the spriteinfo_t struct
readspriteframe(f, info, frame);
if (sprite2)
{
INT32 i;
if (!foundskins)
{
deh_warning("Sprite2 %s: no skins specified", spr2names[num]);
break;
}
for (i = 0; i < foundskins; i++)
{
size_t skinnum = skinnumbers[i];
skin_t *skin = &skins[skinnum];
spriteinfo_t *sprinfo = skin->sprinfo;
#ifdef ROTSPRITE
R_FreeSkinRotSprite(skinnum);
#endif
M_Memcpy(&sprinfo[num], info, sizeof(spriteinfo_t));
}
}
else
M_Memcpy(&spriteinfo[num], info, sizeof(spriteinfo_t));
}
else
{
//deh_warning("Sprite %s: unknown word '%s'", sprnames[num], word);
f->curpos = lastline;
break;
}
}
} while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
Z_Free(info);
}
#endif // HWRENDER
static void readsprite2(MYFILE *f, INT32 num)
{
@ -2447,6 +2649,11 @@ static actionpointer_t actionpointers[] =
{{A_SpawnObjectRelative}, "A_SPAWNOBJECTRELATIVE"},
{{A_ChangeAngleRelative}, "A_CHANGEANGLERELATIVE"},
{{A_ChangeAngleAbsolute}, "A_CHANGEANGLEABSOLUTE"},
#ifdef ROTSPRITE
{{A_RollAngle}, "A_ROLLANGLE"},
{{A_ChangeRollAngleRelative},"A_CHANGEROLLANGLERELATIVE"},
{{A_ChangeRollAngleAbsolute},"A_CHANGEROLLANGLEABSOLUTE"},
#endif
{{A_PlaySound}, "A_PLAYSOUND"},
{{A_FindTarget}, "A_FINDTARGET"},
{{A_FindTracer}, "A_FINDTRACER"},
@ -4081,19 +4288,31 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
ignorelines(f);
}
}
else if (fastcmp(word, "SPRITE"))
#endif
else if (fastcmp(word, "SPRITE") || fastcmp(word, "SPRITEINFO"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_sprite(word2); // find a sprite by name
if (i < NUMSPRITES && i > 0)
readspritelight(f, i);
readspriteinfo(f, i, false);
else
{
deh_warning("Sprite number %d out of range (0 - %d)", i, NUMSPRITES-1);
ignorelines(f);
}
}
#endif
else if (fastcmp(word, "SPRITE2INFO"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_sprite2(word2); // find a sprite by name
if (i < NUMPLAYERSPRITES && i >= 0)
readspriteinfo(f, i, true);
else
{
deh_warning("Sprite2 number %d out of range (0 - %d)", i, NUMPLAYERSPRITES-1);
ignorelines(f);
}
}
else if (fastcmp(word, "LEVEL"))
{
// Support using the actual map name,
@ -4425,40 +4644,14 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_NIGHTS_TRANS4",
"S_PLAY_NIGHTS_TRANS5",
"S_PLAY_NIGHTS_TRANS6",
"S_PLAY_NIGHTS_STAND",
"S_PLAY_NIGHTS_FLOAT",
"S_PLAY_NIGHTS_FLY",
"S_PLAY_NIGHTS_DRILL",
"S_PLAY_NIGHTS_STUN",
"S_PLAY_NIGHTS_PULL",
"S_PLAY_NIGHTS_ATTACK",
"S_PLAY_NIGHTS_FLY0",
"S_PLAY_NIGHTS_DRILL0",
"S_PLAY_NIGHTS_FLY1",
"S_PLAY_NIGHTS_DRILL1",
"S_PLAY_NIGHTS_FLY2",
"S_PLAY_NIGHTS_DRILL2",
"S_PLAY_NIGHTS_FLY3",
"S_PLAY_NIGHTS_DRILL3",
"S_PLAY_NIGHTS_FLY4",
"S_PLAY_NIGHTS_DRILL4",
"S_PLAY_NIGHTS_FLY5",
"S_PLAY_NIGHTS_DRILL5",
"S_PLAY_NIGHTS_FLY6",
"S_PLAY_NIGHTS_DRILL6",
"S_PLAY_NIGHTS_FLY7",
"S_PLAY_NIGHTS_DRILL7",
"S_PLAY_NIGHTS_FLY8",
"S_PLAY_NIGHTS_DRILL8",
"S_PLAY_NIGHTS_FLY9",
"S_PLAY_NIGHTS_DRILL9",
"S_PLAY_NIGHTS_FLYA",
"S_PLAY_NIGHTS_DRILLA",
"S_PLAY_NIGHTS_FLYB",
"S_PLAY_NIGHTS_DRILLB",
"S_PLAY_NIGHTS_FLYC",
"S_PLAY_NIGHTS_DRILLC",
// c:
"S_TAILSOVERLAY_STAND",
"S_TAILSOVERLAY_0DEGREES",
@ -8902,6 +9095,7 @@ struct {
{"SF_DASHMODE",SF_DASHMODE},
{"SF_FASTEDGE",SF_FASTEDGE},
{"SF_MULTIABILITY",SF_MULTIABILITY},
{"SF_NONIGHTSROTATION",SF_NONIGHTSROTATION},
// Character abilities!
// Primary
@ -9158,6 +9352,13 @@ struct {
{"DI_SOUTHEAST",DI_SOUTHEAST},
{"NUMDIRS",NUMDIRS},
#ifdef ROTSPRITE
// Sprite rotation axis (rotaxis_t)
{"ROTAXIS_X",ROTAXIS_X},
{"ROTAXIS_Y",ROTAXIS_Y},
{"ROTAXIS_Z",ROTAXIS_Z},
#endif
// Buttons (ticcmd_t)
{"BT_WEAPONMASK",BT_WEAPONMASK}, //our first four bits.
{"BT_WEAPONNEXT",BT_WEAPONNEXT},

View File

@ -489,6 +489,8 @@ extern INT32 cv_debug;
// Misc stuff for later...
// =======================
#define ANG2RAD(angle) ((float)((angle)*M_PI)/ANGLE_180)
// Modifier key variables, accessible anywhere
extern UINT8 shiftdown, ctrldown, altdown;
extern boolean capslock;
@ -621,6 +623,11 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// SRB2CB itself ported this from PrBoom+
#define NEWCLIP
/// Sprite rotation
#define ROTSPRITE
#define ROTANGLES 24 // Needs to be a divisor of 360 (45, 60, 90, 120...)
#define ROTANGDIFF (360 / ROTANGLES)
#ifndef HAVE_PNG
#define NO_PNG_LUMPS
#endif

View File

@ -30,6 +30,7 @@
#include "../z_zone.h"
#include "../v_video.h"
#include "../r_draw.h"
#include "../r_patch.h"
#include "../p_setup.h"
//Hurdler: 25/04/2000: used for new colormap code in hardware mode
@ -1002,10 +1003,14 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch)
{
if (!grmip->downloaded && !grmip->grInfo.data)
{
patch_t *patch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
patch_t *patch = gpatch->rawpatch;
if (!patch)
patch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
HWR_MakePatch(patch, gpatch, grmip, true);
Z_Free(patch);
// You can't free rawpatch for some reason?
if (!gpatch->rawpatch)
Z_Free(patch);
}
HWD.pfnSetTexture(grmip);
@ -1024,12 +1029,16 @@ void HWR_GetPatch(GLPatch_t *gpatch)
{
// load the software patch, PU_STATIC or the Z_Malloc for hardware patch will
// flush the software patch before the conversion! oh yeah I suffered
patch_t *ptr = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
patch_t *ptr = gpatch->rawpatch;
if (!ptr)
ptr = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC);
HWR_MakePatch(ptr, gpatch, gpatch->mipmap, true);
// this is inefficient.. but the hardware patch in heap is purgeable so it should
// not fragment memory, and besides the REAL cache here is the hardware memory
Z_Free(ptr);
// You can't free rawpatch for some reason?
if (!gpatch->rawpatch)
Z_Free(ptr);
}
HWD.pfnSetTexture(gpatch->mipmap);
@ -1265,6 +1274,23 @@ GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum)
return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum));
}
#ifdef ROTSPRITE
GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch)
{
GLPatch_t *grpatch;
if (!(grpatch = M_AATreeGet(hwrcache, rollangle)))
{
grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL);
grpatch->rawpatch = rawpatch;
grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL);
M_AATreeSet(hwrcache, rollangle, grpatch);
}
return grpatch;
}
#endif
// Need to do this because they aren't powers of 2
static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight,
lumpnum_t fademasklumpnum, UINT16 fmwidth, UINT16 fmheight)

View File

@ -83,7 +83,8 @@ struct GLPatch_s
float max_s,max_t;
UINT16 wadnum; // the software patch lump num for when the hardware patch
UINT16 lumpnum; // was flushed, and we need to re-create it
GLMipmap_t *mipmap;
void *rawpatch; // :^)
GLMipmap_t *mipmap;
} ATTRPACK;
typedef struct GLPatch_s GLPatch_t;

View File

@ -115,6 +115,13 @@ typedef struct
FLOAT fovxangle, fovyangle;
UINT8 splitscreen;
boolean flip; // screenflip
#ifdef ROTSPRITE
boolean roll;
SINT8 rollflip;
FLOAT rollangle; // done to not override USE_FTRANSFORM_ANGLEZ
UINT8 rotaxis;
FLOAT centerx, centery;
#endif
#ifdef USE_FTRANSFORM_MIRROR
boolean mirror; // SRB2Kart: Encore Mode
#endif

View File

@ -73,7 +73,8 @@ typedef struct gr_vissprite_s
struct gr_vissprite_s *next;
float x1, x2;
float tz, ty;
lumpnum_t patchlumpnum;
//lumpnum_t patchlumpnum;
GLPatch_t *gpatch;
boolean flip;
UINT8 translucency; //alpha level 0-255
mobj_t *mobj;
@ -111,6 +112,9 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum);
void HWR_SetPalette(RGBA_t *palette);
GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump);
GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum);
#ifdef ROTSPRITE
GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch);
#endif
void HWR_GetFadeMask(lumpnum_t fademasklumpnum);
// --------

View File

@ -30,6 +30,7 @@
#include "../p_local.h"
#include "../p_setup.h"
#include "../r_local.h"
#include "../r_patch.h"
#include "../r_bsp.h"
#include "../d_clisrv.h"
#include "../w_wad.h"
@ -4378,7 +4379,7 @@ static void HWR_SplitSprite(gr_vissprite_t *spr)
if (hires)
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale);
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
// cache the patch in the graphics card memory
//12/12/99: Hurdler: same comment as above (for md2)
@ -4734,7 +4735,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
// sure to do it the right way. So actually, we keep normal sprite
// in memory and we add the md2 model if it exists for that sprite
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
#ifdef ALAM_LIGHTING
if (!(spr->mobj->flags2 & MF2_DEBRIS) && (spr->mobj->sprite != SPR_PLAY ||
@ -4879,7 +4880,7 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
return;
// cache sprite graphics
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
// create the sprite billboard
//
@ -5522,6 +5523,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
float gz, gzt;
spritedef_t *sprdef;
spriteframe_t *sprframe;
spriteinfo_t *sprinfo;
size_t lumpoff;
unsigned rot;
UINT8 flip;
@ -5533,10 +5535,22 @@ static void HWR_ProjectSprite(mobj_t *thing)
angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
float z1, z2;
fixed_t spr_width, spr_height;
fixed_t spr_offset, spr_topoffset;
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
angle_t arollangle;
UINT32 rollangle;
#endif
if (!thing)
return;
else
this_scale = FIXED_TO_FLOAT(thing->scale);
#ifdef ROTSPRITE
arollangle = thing->rollangle;
rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif
this_scale = FIXED_TO_FLOAT(thing->scale);
// transform the origin point
tr_x = FIXED_TO_FLOAT(thing->x) - gr_viewx;
@ -5563,9 +5577,15 @@ static void HWR_ProjectSprite(mobj_t *thing)
//Fab : 02-08-98: 'skin' override spritedef currently used for skin
if (thing->skin && thing->sprite == SPR_PLAY)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
}
else
{
sprdef = &sprites[thing->sprite];
sprinfo = NULL;
}
if (rot >= sprdef->numframes)
{
@ -5574,6 +5594,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
sprinfo = NULL;
rot = thing->frame&FF_FRAMEMASK;
thing->state->sprite = thing->sprite;
thing->state->frame = thing->frame;
@ -5629,6 +5650,30 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale);
spr_width = spritecachedinfo[lumpoff].width;
spr_height = spritecachedinfo[lumpoff].height;
spr_offset = spritecachedinfo[lumpoff].offset;
spr_topoffset = spritecachedinfo[lumpoff].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
{
if (!sprframe->rotsprite.cached[rot])
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{
spr_width = rotsprite->width << FRACBITS;
spr_height = rotsprite->height << FRACBITS;
spr_offset = rotsprite->leftoffset << FRACBITS;
spr_topoffset = rotsprite->topoffset << FRACBITS;
// flip -> rotate, not rotate -> flip
flip = 0;
}
}
#endif
if (papersprite)
{
rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT));
@ -5642,13 +5687,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (flip)
{
x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale);
x2 = (FIXED_TO_FLOAT(spr_offset) * this_scale);
}
else
{
x1 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].offset) * this_scale);
x2 = (FIXED_TO_FLOAT(spritecachedinfo[lumpoff].width - spritecachedinfo[lumpoff].offset) * this_scale);
x1 = (FIXED_TO_FLOAT(spr_offset) * this_scale);
x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale);
}
// test if too close
@ -5670,13 +5715,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (vflip)
{
gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale;
gzt = gz + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale;
gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spr_topoffset) * this_scale;
gzt = gz + FIXED_TO_FLOAT(spr_height) * this_scale;
}
else
{
gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale;
gz = gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale;
gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spr_topoffset) * this_scale;
gz = gzt - FIXED_TO_FLOAT(spr_height) * this_scale;
}
if (thing->subsector->sector->cullheight)
@ -5716,7 +5761,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->x2 = x2;
vis->tz = tz; // Keep tz for the simple sprite sorting that happens
vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
vis->patchlumpnum = sprframe->lumppat[rot];
//vis->patchlumpnum = sprframe->lumppat[rot];
#ifdef ROTSPRITE
if (rotsprite)
vis->gpatch = (GLPatch_t *)rotsprite;
else
#endif
vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE);
vis->flip = flip;
vis->mobj = thing;
vis->z1 = z1;
@ -5851,7 +5902,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->z2 = z2;
vis->tz = tz;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
vis->patchlumpnum = sprframe->lumppat[rot];
//vis->patchlumpnum = sprframe->lumppat[rot];
vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE);
vis->flip = flip;
vis->mobj = (mobj_t *)thing;

View File

@ -961,6 +961,10 @@ void HWR_DrawModel(gr_vissprite_t *spr)
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !(spr->mobj->frame & FF_VERTICALFLIP));
spritedef_t *sprdef;
spriteframe_t *sprframe;
#ifdef ROTSPRITE
spriteinfo_t *sprinfo;
angle_t ang;
#endif
INT32 mod;
float finalscale;
@ -984,9 +988,17 @@ void HWR_DrawModel(gr_vissprite_t *spr)
{
md2 = &md2_playermodels[(skin_t*)spr->mobj->skin-skins];
md2->skin = (skin_t*)spr->mobj->skin-skins;
#ifdef ROTSPRITE
sprinfo = &((skin_t *)spr->mobj->skin)->sprinfo[spr->mobj->sprite2];
#endif
}
else
{
md2 = &md2_models[spr->mobj->sprite];
#ifdef ROTSPRITE
sprinfo = &spriteinfo[spr->mobj->sprite];
#endif
}
if (md2->error)
return; // we already failed loading this before :(
@ -1065,7 +1077,7 @@ void HWR_DrawModel(gr_vissprite_t *spr)
else
{
// Sprite
gpatch = W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE);
HWR_GetMappedPatch(gpatch, spr->colormap);
}
@ -1172,7 +1184,36 @@ void HWR_DrawModel(gr_vissprite_t *spr)
const fixed_t anglef = AngleFixed((R_PointToAngle(spr->mobj->x, spr->mobj->y))-ANGLE_180);
p.angley = FIXED_TO_FLOAT(anglef);
}
#ifdef ROTSPRITE
p.rollangle = 0.0f;
p.rollflip = 0;
p.rotaxis = 0;
if (spr->mobj->rollangle)
{
fixed_t anglef = AngleFixed(spr->mobj->rollangle);
p.rollangle = FIXED_TO_FLOAT(anglef);
p.roll = true;
// rotation pivot
p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2);
p.centery = FIXED_TO_FLOAT(spr->mobj->height/2);
// rotation axis
if (sprinfo->available)
p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis);
// for NiGHTS specifically but should work everywhere else
ang = R_PointToAngle (spr->mobj->x, spr->mobj->y) - (spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle);
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
p.rollflip = 1;
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
p.rollflip = -1;
}
#endif
p.anglex = 0.0f;
#ifdef USE_FTRANSFORM_ANGLEZ
// Slope rotation from Kart
p.anglez = 0.0f;

View File

@ -2059,11 +2059,27 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
pglTranslatef(pos->x, pos->z, pos->y);
if (flipped)
scaley = -scaley;
#ifdef USE_FTRANSFORM_ANGLEZ
pglRotatef(pos->anglez, 0.0f, 0.0f, -1.0f); // rotate by slope from Kart
#endif
pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f);
pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f);
pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f);
#ifdef ROTSPRITE
if (pos->roll)
{
float roll = (1.0f * pos->rollflip);
pglTranslatef(pos->centerx, pos->centery, 0);
if (pos->rotaxis == 2) // Z
pglRotatef(pos->rollangle, 0.0f, 0.0f, roll);
else if (pos->rotaxis == 1) // Y
pglRotatef(pos->rollangle, 0.0f, roll, 0.0f);
else // X
pglRotatef(pos->rollangle, roll, 0.0f, 0.0f);
pglTranslatef(-pos->centerx, -pos->centery, 0);
}
#endif
pglScalef(scalex, scaley, scalez);

View File

@ -553,38 +553,12 @@ char spr2names[NUMPLAYERSPRITES][5] =
"NSTD",
"NFLT",
"NFLY",
"NDRL",
"NSTN",
"NPUL",
"NATK",
"NGT0",
"NGT1",
"NGT2",
"NGT3",
"NGT4",
"NGT5",
"NGT6",
"NGT7",
"NGT8",
"NGT9",
"NGTA",
"NGTB",
"NGTC",
"DRL0",
"DRL1",
"DRL2",
"DRL3",
"DRL4",
"DRL5",
"DRL6",
"DRL7",
"DRL8",
"DRL9",
"DRLA",
"DRLB",
"DRLC",
"TAL0",
"TAL1",
"TAL2",
@ -656,38 +630,12 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
FF_SPR2SUPER|SPR2_STND, // SPR2_NSTD,
FF_SPR2SUPER|SPR2_FLT , // SPR2_NFLT,
0, // SPR2_NFLY, (will never be referenced unless skin 0 lacks this)
SPR2_NFLY, // SPR2_NDRL,
FF_SPR2SUPER|SPR2_STUN, // SPR2_NSTN,
SPR2_NSTN, // SPR2_NPUL,
FF_SPR2SUPER|SPR2_ROLL, // SPR2_NATK,
0, // SPR2_NGT0, (will never be referenced unless skin 0 lacks this)
SPR2_NGT0, // SPR2_NGT1,
SPR2_NGT1, // SPR2_NGT2,
SPR2_NGT2, // SPR2_NGT3,
SPR2_NGT3, // SPR2_NGT4,
SPR2_NGT4, // SPR2_NGT5,
SPR2_NGT5, // SPR2_NGT6,
SPR2_NGT0, // SPR2_NGT7,
SPR2_NGT7, // SPR2_NGT8,
SPR2_NGT8, // SPR2_NGT9,
SPR2_NGT9, // SPR2_NGTA,
SPR2_NGTA, // SPR2_NGTB,
SPR2_NGTB, // SPR2_NGTC,
SPR2_NGT0, // SPR2_DRL0,
SPR2_NGT1, // SPR2_DRL1,
SPR2_NGT2, // SPR2_DRL2,
SPR2_NGT3, // SPR2_DRL3,
SPR2_NGT4, // SPR2_DRL4,
SPR2_NGT5, // SPR2_DRL5,
SPR2_NGT6, // SPR2_DRL6,
SPR2_NGT7, // SPR2_DRL7,
SPR2_NGT8, // SPR2_DRL8,
SPR2_NGT9, // SPR2_DRL9,
SPR2_NGTA, // SPR2_DRLA,
SPR2_NGTB, // SPR2_DRLB,
SPR2_NGTC, // SPR2_DRLC,
0, // SPR2_TAL0, (this will look mighty stupid but oh well)
SPR2_TAL0, // SPR2_TAL1,
SPR2_TAL1, // SPR2_TAL2,
@ -818,41 +766,15 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5
{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 21, {A_FadeOverlay}, 2, 0, S_PLAY_NIGHTS_FLOAT}, // S_PLAY_NIGHTS_TRANS5
// NiGHTS Player, stand, float, pain, pull and attack
// NiGHTS Player
{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND}, // S_PLAY_NIGHTS_STAND
{SPR_PLAY, SPR2_NFLT, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_FLOAT}, // S_PLAY_NIGHTS_FLOAT
{SPR_PLAY, SPR2_NFLY, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY}, // S_PLAY_NIGHTS_FLY
{SPR_PLAY, SPR2_NDRL, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL}, // S_PLAY_NIGHTS_DRILL
{SPR_PLAY, SPR2_NSTN, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_STUN}, // S_PLAY_NIGHTS_STUN
{SPR_PLAY, SPR2_NPUL, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_PULL}, // S_PLAY_NIGHTS_PULL
{SPR_PLAY, SPR2_NATK, 1, {NULL}, 0, 0, S_PLAY_NIGHTS_ATTACK}, // S_PLAY_NIGHTS_ATTACK
// NiGHTS Player, flying and drilling
{SPR_PLAY, SPR2_NGT0, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY0}, // S_PLAY_NIGHTS_FLY0
{SPR_PLAY, SPR2_DRL0, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL0}, // S_PLAY_NIGHTS_DRILL0
{SPR_PLAY, SPR2_NGT1, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY1}, // S_PLAY_NIGHTS_FLY1
{SPR_PLAY, SPR2_DRL1, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL1}, // S_PLAY_NIGHTS_DRILL1
{SPR_PLAY, SPR2_NGT2, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY2}, // S_PLAY_NIGHTS_FLY2
{SPR_PLAY, SPR2_DRL2, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL2}, // S_PLAY_NIGHTS_DRILL2
{SPR_PLAY, SPR2_NGT3, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY3}, // S_PLAY_NIGHTS_FLY3
{SPR_PLAY, SPR2_DRL3, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL3}, // S_PLAY_NIGHTS_DRILL3
{SPR_PLAY, SPR2_NGT4, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY4}, // S_PLAY_NIGHTS_FLY4
{SPR_PLAY, SPR2_DRL4, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL4}, // S_PLAY_NIGHTS_DRILL4
{SPR_PLAY, SPR2_NGT5, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY5}, // S_PLAY_NIGHTS_FLY5
{SPR_PLAY, SPR2_DRL5, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL5}, // S_PLAY_NIGHTS_DRILL5
{SPR_PLAY, SPR2_NGT6, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY6}, // S_PLAY_NIGHTS_FLY6
{SPR_PLAY, SPR2_DRL6, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL6}, // S_PLAY_NIGHTS_DRILL6
{SPR_PLAY, SPR2_NGT7, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY7}, // S_PLAY_NIGHTS_FLY7
{SPR_PLAY, SPR2_DRL7, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL7}, // S_PLAY_NIGHTS_DRILL7
{SPR_PLAY, SPR2_NGT8, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY8}, // S_PLAY_NIGHTS_FLY8
{SPR_PLAY, SPR2_DRL8, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL8}, // S_PLAY_NIGHTS_DRILL8
{SPR_PLAY, SPR2_NGT9, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLY9}, // S_PLAY_NIGHTS_FLY9
{SPR_PLAY, SPR2_DRL9, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILL9}, // S_PLAY_NIGHTS_DRILL9
{SPR_PLAY, SPR2_NGTA, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLYA}, // S_PLAY_NIGHTS_FLYA
{SPR_PLAY, SPR2_DRLA, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILLA}, // S_PLAY_NIGHTS_DRILLA
{SPR_PLAY, SPR2_NGTB, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLYB}, // S_PLAY_NIGHTS_FLYB
{SPR_PLAY, SPR2_DRLB, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILLB}, // S_PLAY_NIGHTS_DRILLB
{SPR_PLAY, SPR2_NGTC, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLYC}, // S_PLAY_NIGHTS_FLYC
{SPR_PLAY, SPR2_DRLC, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILLC}, // S_PLAY_NIGHTS_DRILLC
// c:
{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART, 5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND}, // S_TAILSOVERLAY_STAND
{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES}, // S_TAILSOVERLAY_0DEGREES
@ -2408,7 +2330,11 @@ state_t states[NUMSTATES] =
{SPR_BARX, 2|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL5}, // S_TNTBARREL_EXPL4
{SPR_BARX, 3|FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_TNTBARREL_EXPL6}, // S_TNTBARREL_EXPL5
{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_TNTBARREL_EXPL6
#ifndef ROTSPRITE
{SPR_BARR, 1|FF_ANIMATE, -1, {NULL}, 7, 2, S_NULL}, // S_TNTBARREL_FLYING
#else
{SPR_BARR, 1, 1, {A_RollAngle}, 14, 0, S_TNTBARREL_FLYING}, // S_TNTBARREL_FLYING
#endif
// TNT proximity shell
{SPR_REMT, 0, 10, {A_Look}, 33554433, 0, S_PROXIMITY_TNT}, // S_PROXIMITY_TNT

View File

@ -155,6 +155,11 @@ void A_SpawnObjectAbsolute();
void A_SpawnObjectRelative();
void A_ChangeAngleRelative();
void A_ChangeAngleAbsolute();
#ifdef ROTSPRITE
void A_RollAngle();
void A_ChangeRollAngleRelative();
void A_ChangeRollAngleAbsolute();
#endif
void A_PlaySound();
void A_FindTarget();
void A_FindTracer();
@ -817,40 +822,12 @@ typedef enum playersprite
SPR2_NSTD, // NiGHTS stand
SPR2_NFLT, // NiGHTS float
SPR2_NFLY, // NiGHTS fly
SPR2_NDRL, // NiGHTS drill
SPR2_NSTN, // NiGHTS stun
SPR2_NPUL, // NiGHTS pull
SPR2_NATK, // NiGHTS attack
// NiGHTS flight
SPR2_NGT0,
SPR2_NGT1,
SPR2_NGT2,
SPR2_NGT3,
SPR2_NGT4,
SPR2_NGT5,
SPR2_NGT6,
SPR2_NGT7,
SPR2_NGT8,
SPR2_NGT9,
SPR2_NGTA,
SPR2_NGTB,
SPR2_NGTC,
// NiGHTS drill
SPR2_DRL0,
SPR2_DRL1,
SPR2_DRL2,
SPR2_DRL3,
SPR2_DRL4,
SPR2_DRL5,
SPR2_DRL6,
SPR2_DRL7,
SPR2_DRL8,
SPR2_DRL9,
SPR2_DRLA,
SPR2_DRLB,
SPR2_DRLC,
// c:
SPR2_TAL0,
SPR2_TAL1,
@ -984,40 +961,14 @@ typedef enum state
S_PLAY_NIGHTS_TRANS4,
S_PLAY_NIGHTS_TRANS5,
S_PLAY_NIGHTS_TRANS6,
S_PLAY_NIGHTS_STAND,
S_PLAY_NIGHTS_FLOAT,
S_PLAY_NIGHTS_FLY,
S_PLAY_NIGHTS_DRILL,
S_PLAY_NIGHTS_STUN,
S_PLAY_NIGHTS_PULL,
S_PLAY_NIGHTS_ATTACK,
S_PLAY_NIGHTS_FLY0,
S_PLAY_NIGHTS_DRILL0,
S_PLAY_NIGHTS_FLY1,
S_PLAY_NIGHTS_DRILL1,
S_PLAY_NIGHTS_FLY2,
S_PLAY_NIGHTS_DRILL2,
S_PLAY_NIGHTS_FLY3,
S_PLAY_NIGHTS_DRILL3,
S_PLAY_NIGHTS_FLY4,
S_PLAY_NIGHTS_DRILL4,
S_PLAY_NIGHTS_FLY5,
S_PLAY_NIGHTS_DRILL5,
S_PLAY_NIGHTS_FLY6,
S_PLAY_NIGHTS_DRILL6,
S_PLAY_NIGHTS_FLY7,
S_PLAY_NIGHTS_DRILL7,
S_PLAY_NIGHTS_FLY8,
S_PLAY_NIGHTS_DRILL8,
S_PLAY_NIGHTS_FLY9,
S_PLAY_NIGHTS_DRILL9,
S_PLAY_NIGHTS_FLYA,
S_PLAY_NIGHTS_DRILLA,
S_PLAY_NIGHTS_FLYB,
S_PLAY_NIGHTS_DRILLB,
S_PLAY_NIGHTS_FLYC,
S_PLAY_NIGHTS_DRILLC,
// c:
S_TAILSOVERLAY_STAND,
S_TAILSOVERLAY_0DEGREES,

View File

@ -143,6 +143,11 @@ static const struct {
{META_STATE, "state_t"},
{META_MOBJINFO, "mobjinfo_t"},
{META_SFXINFO, "sfxinfo_t"},
{META_SPRITEINFO, "spriteinfo_t"},
#ifdef ROTSPRITE
{META_PIVOTLIST, "spriteframepivot_t[]"},
{META_FRAMEPIVOT, "spriteframepivot_t"},
#endif
{META_MOBJ, "mobj_t"},
{META_MAPTHING, "mapthing_t"},

View File

@ -18,6 +18,8 @@
#include "p_mobj.h"
#include "p_local.h"
#include "z_zone.h"
#include "r_patch.h"
#include "r_things.h"
#include "doomstat.h" // luabanks[]
#include "lua_script.h"
@ -221,6 +223,401 @@ static int lib_spr2namelen(lua_State *L)
return 1;
}
/////////////////
// SPRITE INFO //
/////////////////
// spriteinfo[]
static int lib_getSpriteInfo(lua_State *L)
{
UINT32 i = NUMSPRITES;
lua_remove(L, 1);
if (lua_isstring(L, 1))
{
const char *name = lua_tostring(L, 1);
INT32 spr;
for (spr = 0; spr < NUMSPRITES; spr++)
{
if (fastcmp(name, sprnames[spr]))
{
i = spr;
break;
}
}
if (i == NUMSPRITES)
{
char *check;
i = strtol(name, &check, 10);
if (check == name || *check != '\0')
return luaL_error(L, "unknown sprite name %s", name);
}
}
else
i = luaL_checkinteger(L, 1);
if (i == 0 || i >= NUMSPRITES)
return luaL_error(L, "spriteinfo[] index %d out of range (1 - %d)", i, NUMSPRITES-1);
LUA_PushUserdata(L, &spriteinfo[i], META_SPRITEINFO);
return 1;
}
#define FIELDERROR(f, e) luaL_error(L, "bad value for " LUA_QL(f) " in table passed to spriteinfo[] (%s)", e);
#define TYPEERROR(f, t1, t2) FIELDERROR(f, va("%s expected, got %s", lua_typename(L, t1), lua_typename(L, t2)))
#ifdef ROTSPRITE
static int PopPivotSubTable(spriteframepivot_t *pivot, lua_State *L, int stk, int idx)
{
int okcool = 0;
switch (lua_type(L, stk))
{
case LUA_TTABLE:
lua_pushnil(L);
while (lua_next(L, stk))
{
const char *key = NULL;
lua_Integer ikey = -1;
lua_Integer value = 0;
// x or y?
switch (lua_type(L, stk+1))
{
case LUA_TSTRING:
key = lua_tostring(L, stk+1);
break;
case LUA_TNUMBER:
ikey = lua_tointeger(L, stk+1);
break;
default:
FIELDERROR("pivot key", va("string or number expected, got %s", luaL_typename(L, stk+1)))
}
// then get value
switch (lua_type(L, stk+2))
{
case LUA_TNUMBER:
value = lua_tonumber(L, stk+2);
break;
case LUA_TBOOLEAN:
value = (UINT8)lua_toboolean(L, stk+2);
break;
default:
TYPEERROR("pivot value", LUA_TNUMBER, lua_type(L, stk+2))
}
// finally set omg!!!!!!!!!!!!!!!!!!
if (ikey == 1 || (key && fastcmp(key, "x")))
pivot[idx].x = (INT32)value;
else if (ikey == 2 || (key && fastcmp(key, "y")))
pivot[idx].y = (INT32)value;
else if (ikey == 3 || (key && fastcmp(key, "rotaxis")))
pivot[idx].rotaxis = (UINT8)value;
else if (ikey == -1 && (key != NULL))
FIELDERROR("pivot key", va("invalid option %s", key));
okcool = 1;
lua_pop(L, 1);
}
break;
default:
TYPEERROR("sprite pivot", LUA_TTABLE, lua_type(L, stk))
}
return okcool;
}
static int PopPivotTable(spriteinfo_t *info, lua_State *L, int stk)
{
// Just in case?
if (!lua_istable(L, stk))
TYPEERROR("pivot table", LUA_TTABLE, lua_type(L, stk));
lua_pushnil(L);
// stk = 0 has the pivot table
// stk = 1 has the frame key
// stk = 2 has the frame table
// stk = 3 has either a string or a number as key
// stk = 4 has the value for the key mentioned above
while (lua_next(L, stk))
{
int idx = 0;
const char *framestr = NULL;
switch (lua_type(L, stk+1))
{
case LUA_TSTRING:
framestr = lua_tostring(L, stk+1);
idx = R_Char2Frame(framestr[0]);
break;
case LUA_TNUMBER:
idx = lua_tonumber(L, stk+1);
break;
default:
TYPEERROR("pivot frame", LUA_TNUMBER, lua_type(L, stk+1));
}
if ((idx < 0) || (idx >= 64))
return luaL_error(L, "pivot frame %d out of range (0 - %d)", idx, 63);
// the values in pivot[] are also tables
if (PopPivotSubTable(info->pivot, L, stk+2, idx))
info->available = true;
lua_pop(L, 1);
}
return 0;
}
#endif
static int lib_setSpriteInfo(lua_State *L)
{
spriteinfo_t *info;
if (!lua_lumploading)
return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
lua_remove(L, 1);
{
UINT32 i = luaL_checkinteger(L, 1);
if (i == 0 || i >= NUMSPRITES)
return luaL_error(L, "spriteinfo[] index %d out of range (1 - %d)", i, NUMSPRITES-1);
#ifdef ROTSPRITE
if (sprites != NULL)
R_FreeSingleRotSprite(&sprites[i]);
#endif
info = &spriteinfo[i]; // get the spriteinfo to assign to.
}
luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
lua_remove(L, 1); // pop sprite num, don't need it any more.
lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the spriteinfo.
lua_pushnil(L);
while (lua_next(L, 1)) {
lua_Integer i = 0;
const char *str = NULL;
if (lua_isnumber(L, 2))
{
i = lua_tointeger(L, 2);
#ifndef ROTSPRITE
i++; // shift index in case of missing rotsprite support
#endif
}
else
str = luaL_checkstring(L, 2);
#ifdef ROTSPRITE
if (i == 1 || (str && fastcmp(str, "pivot")))
{
// pivot[] is a table
if (lua_istable(L, 3))
return PopPivotTable(info, L, 3);
else
FIELDERROR("pivot", va("%s expected, got %s", lua_typename(L, LUA_TTABLE), luaL_typename(L, -1)))
}
#endif
lua_pop(L, 1);
}
return 0;
}
#undef FIELDERROR
#undef TYPEERROR
static int lib_spriteinfolen(lua_State *L)
{
lua_pushinteger(L, NUMSPRITES);
return 1;
}
// spriteinfo_t
static int spriteinfo_get(lua_State *L)
{
spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
const char *field = luaL_checkstring(L, 2);
I_Assert(sprinfo != NULL);
#ifdef ROTSPRITE
// push spriteframepivot_t userdata
if (fastcmp(field, "pivot"))
{
// bypass LUA_PushUserdata
void **userdata = lua_newuserdata(L, sizeof(void *));
*userdata = &sprinfo->pivot;
luaL_getmetatable(L, META_PIVOTLIST);
lua_setmetatable(L, -2);
// stack is left with the userdata on top, as if getting it had originally succeeded.
return 1;
}
else
#endif
return luaL_error(L, LUA_QL("spriteinfo_t") " has no field named " LUA_QS, field);
return 0;
}
static int spriteinfo_set(lua_State *L)
{
spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
const char *field = luaL_checkstring(L, 2);
if (!lua_lumploading)
return luaL_error(L, "Do not alter spriteinfo_t from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter spriteinfo_t in HUD rendering code!");
I_Assert(sprinfo != NULL);
lua_remove(L, 1); // remove spriteinfo
lua_remove(L, 1); // remove field
lua_settop(L, 1); // leave only one value
#ifdef ROTSPRITE
if (sprites != NULL)
R_FreeSingleRotSprite(&sprites[sprinfo-spriteinfo]);
if (fastcmp(field, "pivot"))
{
// pivot[] is a table
if (lua_istable(L, 1))
return PopPivotTable(sprinfo, L, 1);
// pivot[] is userdata
else if (lua_isuserdata(L, 1))
{
spriteframepivot_t *pivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST));
memcpy(&sprinfo->pivot, pivot, sizeof(spriteframepivot_t));
sprinfo->available = true; // Just in case?
}
}
else
#endif
return luaL_error(L, va("Field %s does not exist in spriteinfo_t", field));
return 0;
}
static int spriteinfo_num(lua_State *L)
{
spriteinfo_t *sprinfo = *((spriteinfo_t **)luaL_checkudata(L, 1, META_SPRITEINFO));
I_Assert(sprinfo != NULL);
I_Assert(sprinfo >= spriteinfo);
lua_pushinteger(L, (UINT32)(sprinfo-spriteinfo));
return 1;
}
// framepivot_t
#ifdef ROTSPRITE
static int pivotlist_get(lua_State *L)
{
void **userdata;
spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_PIVOTLIST));
const char *field = luaL_checkstring(L, 2);
UINT8 frame;
I_Assert(framepivot != NULL);
frame = R_Char2Frame(field[0]);
if (frame == 255)
luaL_error(L, "invalid frame %s", field);
// bypass LUA_PushUserdata
userdata = lua_newuserdata(L, sizeof(void *));
*userdata = &framepivot[frame];
luaL_getmetatable(L, META_FRAMEPIVOT);
lua_setmetatable(L, -2);
// stack is left with the userdata on top, as if getting it had originally succeeded.
return 1;
}
static int pivotlist_set(lua_State *L)
{
// Because I already know it's a spriteframepivot_t anyway
spriteframepivot_t *pivotlist = *((spriteframepivot_t **)lua_touserdata(L, 1));
//spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
const char *field = luaL_checkstring(L, 2);
UINT8 frame;
if (!lua_lumploading)
return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
I_Assert(pivotlist != NULL);
frame = R_Char2Frame(field[0]);
if (frame == 255)
luaL_error(L, "invalid frame %s", field);
// pivot[] is a table
if (lua_istable(L, 3))
return PopPivotSubTable(pivotlist, L, 3, frame);
// pivot[] is userdata
else if (lua_isuserdata(L, 3))
{
spriteframepivot_t *copypivot = *((spriteframepivot_t **)luaL_checkudata(L, 3, META_FRAMEPIVOT));
memcpy(&pivotlist[frame], copypivot, sizeof(spriteframepivot_t));
}
return 0;
}
static int pivotlist_num(lua_State *L)
{
lua_pushinteger(L, 64);
return 1;
}
static int framepivot_get(lua_State *L)
{
spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
const char *field = luaL_checkstring(L, 2);
I_Assert(framepivot != NULL);
if (fastcmp("x", field))
lua_pushinteger(L, framepivot->x);
else if (fastcmp("y", field))
lua_pushinteger(L, framepivot->y);
else if (fastcmp("rotaxis", field))
lua_pushinteger(L, (UINT8)framepivot->rotaxis);
else
return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));
return 1;
}
static int framepivot_set(lua_State *L)
{
spriteframepivot_t *framepivot = *((spriteframepivot_t **)luaL_checkudata(L, 1, META_FRAMEPIVOT));
const char *field = luaL_checkstring(L, 2);
if (!lua_lumploading)
return luaL_error(L, "Do not alter spriteframepivot_t from within a hook or coroutine!");
if (hud_running)
return luaL_error(L, "Do not alter spriteframepivot_t in HUD rendering code!");
I_Assert(framepivot != NULL);
if (fastcmp("x", field))
framepivot->x = luaL_checkinteger(L, 3);
else if (fastcmp("y", field))
framepivot->y = luaL_checkinteger(L, 3);
else if (fastcmp("rotaxis", field))
framepivot->rotaxis = luaL_checkinteger(L, 3);
else
return luaL_error(L, va("Field %s does not exist in spriteframepivot_t", field));
return 0;
}
static int framepivot_num(lua_State *L)
{
lua_pushinteger(L, 2);
return 1;
}
#endif
////////////////
// STATE INFO //
////////////////
@ -903,8 +1300,8 @@ static int lib_setSfxInfo(lua_State *L)
info = &S_sfx[i]; // get the sfxinfo to assign to.
}
luaL_checktype(L, 2, LUA_TTABLE); // check that we've been passed a table.
lua_remove(L, 1); // pop mobjtype num, don't need it any more.
lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the mobjinfo.
lua_remove(L, 1); // pop sfx num, don't need it any more.
lua_settop(L, 1); // cut the stack here. the only thing left now is the table of data we're assigning to the sfx.
if (hud_running)
return luaL_error(L, "Do not alter sfxinfo in HUD rendering code!");
@ -1130,6 +1527,41 @@ int LUA_InfoLib(lua_State *L)
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_SPRITEINFO);
lua_pushcfunction(L, spriteinfo_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, spriteinfo_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, spriteinfo_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
#ifdef ROTSPRITE
luaL_newmetatable(L, META_PIVOTLIST);
lua_pushcfunction(L, pivotlist_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, pivotlist_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, pivotlist_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_FRAMEPIVOT);
lua_pushcfunction(L, framepivot_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, framepivot_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, framepivot_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
#endif
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getSprname);
@ -1204,6 +1636,20 @@ int LUA_InfoLib(lua_State *L)
lua_setglobal(L, "S_sfx");
lua_setglobal(L, "sfxinfo");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getSpriteInfo);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_setSpriteInfo);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, lib_spriteinfolen);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_pushvalue(L, -1);
lua_setglobal(L, "spriteinfo");
luaL_newmetatable(L, META_LUABANKS);
lua_pushcfunction(L, lib_getluabanks);
lua_setfield(L, -2, "__index");

View File

@ -22,6 +22,11 @@ extern lua_State *gL;
#define META_STATE "STATE_T*"
#define META_MOBJINFO "MOBJINFO_T*"
#define META_SFXINFO "SFXINFO_T*"
#define META_SPRITEINFO "SPRITEINFO_T*"
#ifdef ROTSPRITE
#define META_PIVOTLIST "SPRITEFRAMEPIVOT_T[]"
#define META_FRAMEPIVOT "SPRITEFRAMEPIVOT_T*"
#endif
#define META_MOBJ "MOBJ_T*"
#define META_MAPTHING "MAPTHING_T*"

View File

@ -32,6 +32,9 @@ enum mobj_e {
mobj_snext,
mobj_sprev,
mobj_angle,
#ifdef ROTSPRITE
mobj_rollangle,
#endif
mobj_sprite,
mobj_frame,
mobj_sprite2,
@ -98,6 +101,9 @@ static const char *const mobj_opt[] = {
"snext",
"sprev",
"angle",
#ifdef ROTSPRITE
"rollangle",
#endif
"sprite",
"frame",
"sprite2",
@ -199,6 +205,11 @@ static int mobj_get(lua_State *L)
case mobj_angle:
lua_pushangle(L, mo->angle);
break;
#ifdef ROTSPRITE
case mobj_rollangle:
lua_pushangle(L, mo->rollangle);
break;
#endif
case mobj_sprite:
lua_pushinteger(L, mo->sprite);
break;
@ -451,6 +462,11 @@ static int mobj_set(lua_State *L)
else if (mo->player == &players[secondarydisplayplayer])
localangle2 = mo->angle;
break;
#ifdef ROTSPRITE
case mobj_rollangle:
mo->rollangle = luaL_checkangle(L, 3);
break;
#endif
case mobj_sprite:
mo->sprite = luaL_checkinteger(L, 3);
break;

View File

@ -181,6 +181,11 @@ void A_SpawnObjectAbsolute(mobj_t *actor);
void A_SpawnObjectRelative(mobj_t *actor);
void A_ChangeAngleRelative(mobj_t *actor);
void A_ChangeAngleAbsolute(mobj_t *actor);
#ifdef ROTSPRITE
void A_RollAngle(mobj_t *actor);
void A_ChangeRollAngleRelative(mobj_t *actor);
void A_ChangeRollAngleAbsolute(mobj_t *actor);
#endif // ROTSPRITE
void A_PlaySound(mobj_t *actor);
void A_FindTarget(mobj_t *actor);
void A_FindTracer(mobj_t *actor);
@ -8519,7 +8524,7 @@ void A_ChangeAngleRelative(mobj_t *actor)
#ifdef PARANOIA
if (amin > amax)
I_Error("A_ChangeAngleRelative: var1 is greater then var2");
I_Error("A_ChangeAngleRelative: var1 is greater than var2");
#endif
/*
if (angle < amin)
@ -8553,7 +8558,7 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
#ifdef PARANOIA
if (amin > amax)
I_Error("A_ChangeAngleAbsolute: var1 is greater then var2");
I_Error("A_ChangeAngleAbsolute: var1 is greater than var2");
#endif
/*
if (angle < amin)
@ -8564,6 +8569,105 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
actor->angle = FixedAngle(P_RandomRange(amin, amax));
}
#ifdef ROTSPRITE
// Function: A_RollAngle
//
// Description: Changes the roll angle.
//
// var1 = angle
// var2 = relative? (default)
//
void A_RollAngle(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
const angle_t angle = FixedAngle(locvar1*FRACUNIT);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_RollAngle", actor))
return;
#endif
// relative (default)
if (!locvar2)
actor->rollangle += angle;
// absolute
else
actor->rollangle = angle;
}
// Function: A_ChangeRollAngleRelative
//
// Description: Changes the roll angle to a random relative value between the min and max. Set min and max to the same value to eliminate randomness
//
// var1 = min
// var2 = max
//
void A_ChangeRollAngleRelative(mobj_t *actor)
{
// Oh god, the old code /sucked/. Changed this and the absolute version to get a random range using amin and amax instead of
// getting a random angle from the _entire_ spectrum and then clipping. While we're at it, do the angle conversion to the result
// rather than the ranges, so <0 and >360 work as possible values. -Red
INT32 locvar1 = var1;
INT32 locvar2 = var2;
//angle_t angle = (P_RandomByte()+1)<<24;
const fixed_t amin = locvar1*FRACUNIT;
const fixed_t amax = locvar2*FRACUNIT;
//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ChangeRollAngleRelative", actor))
return;
#endif
#ifdef PARANOIA
if (amin > amax)
I_Error("A_ChangeRollAngleRelative: var1 is greater than var2");
#endif
/*
if (angle < amin)
angle = amin;
if (angle > amax)
angle = amax;*/
actor->rollangle += FixedAngle(P_RandomRange(amin, amax));
}
// Function: A_ChangeRollAngleAbsolute
//
// Description: Changes the roll angle to a random absolute value between the min and max. Set min and max to the same value to eliminate randomness
//
// var1 = min
// var2 = max
//
void A_ChangeRollAngleAbsolute(mobj_t *actor)
{
INT32 locvar1 = var1;
INT32 locvar2 = var2;
//angle_t angle = (P_RandomByte()+1)<<24;
const fixed_t amin = locvar1*FRACUNIT;
const fixed_t amax = locvar2*FRACUNIT;
//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
#ifdef HAVE_BLUA
if (LUA_CallAction("A_ChangeRollAngleAbsolute", actor))
return;
#endif
#ifdef PARANOIA
if (amin > amax)
I_Error("A_ChangeRollAngleAbsolute: var1 is greater than var2");
#endif
/*
if (angle < amin)
angle = amin;
if (angle > amax)
angle = amax;*/
actor->rollangle = FixedAngle(P_RandomRange(amin, amax));
}
#endif // ROTSPRITE
// Function: A_PlaySound
//
// Description: Plays a sound

View File

@ -279,6 +279,9 @@ typedef struct mobj_s
// More drawing info: to determine current sprite.
angle_t angle; // orientation
#ifdef ROTSPRITE
angle_t rollangle;
#endif
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites
@ -399,6 +402,9 @@ typedef struct precipmobj_s
// More drawing info: to determine current sprite.
angle_t angle; // orientation
#ifdef ROTSPRITE
angle_t rollangle;
#endif
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
UINT8 sprite2; // player sprites

View File

@ -1277,6 +1277,9 @@ typedef enum
MD2_SLOPE = 1<<11,
#endif
MD2_COLORIZED = 1<<12,
#ifdef ROTSPRITE
MD2_ROLLANGLE = 1<<13,
#endif
} mobj_diff2_t;
typedef enum
@ -1496,6 +1499,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
#endif
if (mobj->colorized)
diff2 |= MD2_COLORIZED;
#ifdef ROTSPRITE
if (mobj->rollangle)
diff2 |= MD2_ROLLANGLE;
#endif
if (diff2 != 0)
diff |= MD_MORE;
@ -1660,6 +1667,10 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
#endif
if (diff2 & MD2_COLORIZED)
WRITEUINT8(save_p, mobj->colorized);
#ifdef ROTSPRITE
if (diff2 & MD2_ROLLANGLE)
WRITEANGLE(save_p, mobj->rollangle);
#endif
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2736,6 +2747,12 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
#endif
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
#ifdef ROTSPRITE
if (diff2 & MD2_ROLLANGLE)
mobj->rollangle = READANGLE(save_p);
else
mobj->rollangle = 0;
#endif
if (diff & MD_REDFLAG)
{

View File

@ -28,6 +28,7 @@
#include "r_data.h"
#include "r_things.h"
#include "r_patch.h"
#include "r_sky.h"
#include "r_draw.h"
@ -543,9 +544,10 @@ levelflat_t *levelflats;
size_t P_PrecacheLevelFlats(void)
{
lumpnum_t lump;
size_t i, flatmemory = 0;
size_t i;
//SoM: 4/18/2000: New flat code to make use of levelflats.
flatmemory = 0;
for (i = 0; i < numlevelflats; i++)
{
if (levelflats[i].type == LEVELFLAT_FLAT)
@ -3508,9 +3510,11 @@ boolean P_AddWadFile(const char *wadfilename)
if (!mapsadded)
CONS_Printf(M_GetText("No maps added\n"));
R_LoadSpriteInfoLumps(wadnum, numlumps);
#ifdef HWRENDER
HWR_ReloadModels();
#endif // HWRENDER
#endif
// reload status bar (warning should have valid player!)
if (gamestate == GS_LEVEL)

View File

@ -744,7 +744,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
player->oldscale = player->mo->scale;
if (skins[player->skin].sprites[SPR2_NGT0].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
if (skins[player->skin].sprites[SPR2_NFLY].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
{
player->mo->skin = &skins[DEFAULTNIGHTSSKIN];
if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
@ -6748,6 +6748,17 @@ static void P_DoNiGHTSCapsule(player_t *player)
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
}
#ifdef ROTSPRITE
if (!(player->charflags & SF_NONIGHTSROTATION))
{
if ((player->mo->state == &states[S_PLAY_NIGHTS_PULL])
&& (player->mo->sprite2 == SPR2_NPUL))
player->mo->rollangle -= ANG30;
else
player->mo->rollangle = 0;
}
#endif
if (G_IsSpecialStage(gamemap))
{ // In special stages, share rings. Everyone gives up theirs to the capsule player always, because we can't have any individualism here!
for (i = 0; i < MAXPLAYERS; i++)
@ -7009,6 +7020,9 @@ static void P_NiGHTSMovement(player_t *player)
INT32 i;
statenum_t flystate;
UINT16 visangle;
#ifdef ROTSPRITE
angle_t rollangle = 0;
#endif
player->pflags &= ~PF_DRILLING;
@ -7193,6 +7207,9 @@ static void P_NiGHTSMovement(player_t *player)
&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
{
player->mo->momx = player->mo->momy = player->mo->momz = 0;
#ifdef ROTSPRITE
player->mo->rollangle = 0;
#endif
return;
}
@ -7201,13 +7218,26 @@ static void P_NiGHTSMovement(player_t *player)
player->mo->momx = player->mo->momy = 0;
if (gametype != GT_RACE && gametype != GT_COMPETITION)
P_SetObjectMomZ(player->mo, FRACUNIT/2, true);
P_SetObjectMomZ(player->mo, FRACUNIT/2, (P_MobjFlip(player->mo)*player->mo->momz >= 0));
else
player->mo->momz = 0;
if (player->mo->state != &states[S_PLAY_NIGHTS_DRILL6])
P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_DRILL6);
#if 0//def ROTSPRITE
if (!(player->charflags & SF_NONIGHTSROTATION) && player->mo->momz)
{
if (player->mo->state != &states[S_PLAY_NIGHTS_DRILL])
P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_DRILL);
player->mo->rollangle = ANGLE_90;
}
else
#endif
{
if (player->mo->state != &states[S_PLAY_NIGHTS_FLOAT])
P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_FLOAT);
player->drawangle += ANGLE_22h;
}
player->mo->flags |= MF_NOCLIPHEIGHT;
return;
}
@ -7482,31 +7512,60 @@ static void P_NiGHTSMovement(player_t *player)
flystate = (P_IsObjectOnGround(player->mo)) ? S_PLAY_NIGHTS_STAND : S_PLAY_NIGHTS_FLOAT;
else
{
visangle = ((player->anotherflyangle + 7) % 360)/15;
if (visangle > 18) // Over 270 degrees.
visangle = 30 - visangle;
else if (visangle > 12) // Over 180 degrees.
visangle -= 6;
else if (visangle > 6) // Over 90 degrees.
visangle = 12 - visangle;
if (player->mo->eflags & MFE_VERTICALFLIP && visangle) // S_PLAY_NIGHTS_FLY0 stays the same, even in reverse gravity
flystate = (player->pflags & PF_DRILLING) ? S_PLAY_NIGHTS_DRILL : S_PLAY_NIGHTS_FLY;
if (player->charflags & SF_NONIGHTSROTATION)
{
if (visangle > 6)
visangle -= 6; // shift to S_PLAY_NIGHTS_FLY1-6
else
visangle += 6; // shift to S_PLAY_NIGHTS_FLY7-C
#if 0
visangle = ((player->anotherflyangle + 7) % 360)/15;
if (visangle > 18) // Over 270 degrees.
visangle = 30 - visangle;
else if (visangle > 12) // Over 180 degrees.
visangle -= 6;
else if (visangle > 6) // Over 90 degrees.
visangle = 12 - visangle;
if (player->mo->eflags & MFE_VERTICALFLIP && visangle) // S_PLAY_NIGHTS_FLY0 stays the same, even in reverse gravity
{
if (visangle > 6)
visangle -= 6; // shift to S_PLAY_NIGHTS_FLY1-6
else
visangle += 6; // shift to S_PLAY_NIGHTS_FLY7-C
}
flystate += (visangle*2); // S_PLAY_NIGHTS_FLY0-C - the *2 is to skip over drill states
#endif
}
#ifdef ROTSPRITE
else
{
angle_t a = R_PointToAngle(player->mo->x, player->mo->y) - player->mo->angle;
visangle = (player->flyangle % 360);
flystate = S_PLAY_NIGHTS_FLY0 + (visangle*2); // S_PLAY_FLY0-C - the *2 is to skip over drill states
if (player->flyangle >= 90 && player->flyangle <= 270)
{
if (player->flyangle == 270 && (a < ANGLE_180))
;
else if (player->flyangle == 90 && (a < ANGLE_180))
;
else
visangle += 180;
}
if (player->pflags & PF_DRILLING)
flystate++; // shift to S_PLAY_NIGHTS_DRILL0-C
rollangle = FixedAngle(visangle<<FRACBITS);
}
#endif
}
if (player->mo->state != &states[flystate])
P_SetPlayerMobjState(player->mo, flystate);
#ifdef ROTSPRITE
if (player->charflags & SF_NONIGHTSROTATION)
player->mo->rollangle = 0;
else
player->mo->rollangle = rollangle;
#endif
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])

View File

@ -9,7 +9,7 @@
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file r_data.c
/// \brief Preparation of data for rendering,generation of lookups, caching, retrieval by name
/// \brief Preparation of data for rendering, generation of lookups, caching, retrieval by name
#include "doomdef.h"
#include "g_game.h"
@ -19,6 +19,7 @@
#include "p_local.h"
#include "m_misc.h"
#include "r_data.h"
#include "r_patch.h"
#include "w_wad.h"
#include "z_zone.h"
#include "p_setup.h" // levelflats
@ -41,28 +42,6 @@
#include <errno.h>
#endif
#ifdef HAVE_PNG
#ifndef _MSC_VER
#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif
#endif
#ifndef _LFS64_LARGEFILE
#define _LFS64_LARGEFILE
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 0
#endif
#include "png.h"
#ifndef PNG_READ_SUPPORTED
#undef HAVE_PNG
#endif
#endif
//
// Texture definition.
// Each texture is composed of one or more patches,
@ -136,7 +115,7 @@ sprcache_t *spritecachedinfo;
lighttable_t *colormaps;
// for debugging/info purposes
static size_t flatmemory, spritememory, texturememory;
size_t flatmemory, spritememory, texturememory;
// highcolor stuff
INT16 color8to16[256]; // remap color index to highcolor rgb value
@ -2487,578 +2466,3 @@ void R_PrecacheLevel(void)
"texturememory: %s k\n"
"spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10));
}
//
// R_CheckIfPatch
//
// Returns true if the lump is a valid patch.
//
boolean R_CheckIfPatch(lumpnum_t lump)
{
size_t size;
INT16 width, height;
patch_t *patch;
boolean result;
size = W_LumpLength(lump);
// minimum length of a valid Doom patch
if (size < 13)
return false;
patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC);
width = SHORT(patch->width);
height = SHORT(patch->height);
result = (height > 0 && height <= 16384 && width > 0 && width <= 16384 && width < (INT16)(size / 4));
if (result)
{
// The dimensions seem like they might be valid for a patch, so
// check the column directory for extra security. All columns
// must begin after the column directory, and none of them must
// point past the end of the patch.
INT16 x;
for (x = 0; x < width; x++)
{
UINT32 ofs = LONG(patch->columnofs[x]);
// Need one byte for an empty column (but there's patches that don't know that!)
if (ofs < (UINT32)width * 4 + 8 || ofs >= (UINT32)size)
{
result = false;
break;
}
}
}
return result;
}
//
// R_TextureToFlat
//
// Convert a texture to a flat.
//
void R_TextureToFlat(size_t tex, UINT8 *flat)
{
texture_t *texture = textures[tex];
fixed_t col, ofs;
column_t *column;
UINT8 *desttop, *dest, *deststop;
UINT8 *source;
// yea
R_CheckTextureCache(tex);
desttop = flat;
deststop = desttop + (texture->width * texture->height);
for (col = 0; col < texture->width; col++, desttop++)
{
// no post_t info
if (!texture->holes)
{
column = (column_t *)(R_GetColumn(tex, col));
source = (UINT8 *)(column);
dest = desttop;
for (ofs = 0; dest < deststop && ofs < texture->height; ofs++)
{
if (source[ofs] != TRANSPARENTPIXEL)
*dest = source[ofs];
dest += texture->width;
}
}
else
{
INT32 topdelta, prevdelta = -1;
column = (column_t *)((UINT8 *)R_GetColumn(tex, col) - 3);
while (column->topdelta != 0xff)
{
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
dest = desttop + (topdelta * texture->width);
source = (UINT8 *)column + 3;
for (ofs = 0; dest < deststop && ofs < column->length; ofs++)
{
if (source[ofs] != TRANSPARENTPIXEL)
*dest = source[ofs];
dest += texture->width;
}
column = (column_t *)((UINT8 *)column + column->length + 4);
}
}
}
}
//
// R_PatchToFlat
//
// Convert a patch to a flat.
//
void R_PatchToFlat(patch_t *patch, UINT8 *flat)
{
fixed_t col, ofs;
column_t *column;
UINT8 *desttop, *dest, *deststop;
UINT8 *source;
desttop = flat;
deststop = desttop + (SHORT(patch->width) * SHORT(patch->height));
for (col = 0; col < SHORT(patch->width); col++, desttop++)
{
INT32 topdelta, prevdelta = -1;
column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[col]));
while (column->topdelta != 0xff)
{
topdelta = column->topdelta;
if (topdelta <= prevdelta)
topdelta += prevdelta;
prevdelta = topdelta;
dest = desttop + (topdelta * SHORT(patch->width));
source = (UINT8 *)(column) + 3;
for (ofs = 0; dest < deststop && ofs < column->length; ofs++)
{
*dest = source[ofs];
dest += SHORT(patch->width);
}
column = (column_t *)((UINT8 *)column + column->length + 4);
}
}
}
//
// R_FlatToPatch
//
// Convert a flat to a patch.
//
static unsigned char imgbuf[1<<26];
patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency)
{
UINT32 x, y;
UINT8 *img;
UINT8 *imgptr = imgbuf;
UINT8 *colpointers, *startofspan;
size_t size = 0;
// Write image size and offset
WRITEINT16(imgptr, width);
WRITEINT16(imgptr, height);
WRITEINT16(imgptr, leftoffset);
WRITEINT16(imgptr, topoffset);
// Leave placeholder to column pointers
colpointers = imgptr;
imgptr += width*4;
// Write columns
for (x = 0; x < width; x++)
{
int lastStartY = 0;
int spanSize = 0;
startofspan = NULL;
// Write column pointer
WRITEINT32(colpointers, imgptr - imgbuf);
// Write pixels
for (y = 0; y < height; y++)
{
UINT8 paletteIndex = raw[((y * width) + x)];
boolean opaque = transparency ? (paletteIndex != TRANSPARENTPIXEL) : true;
// End span if we have a transparent pixel
if (!opaque)
{
if (startofspan)
WRITEUINT8(imgptr, 0);
startofspan = NULL;
continue;
}
// Start new column if we need to
if (!startofspan || spanSize == 255)
{
int writeY = y;
// If we reached the span size limit, finish the previous span
if (startofspan)
WRITEUINT8(imgptr, 0);
if (y > 254)
{
// Make sure we're aligned to 254
if (lastStartY < 254)
{
WRITEUINT8(imgptr, 254);
WRITEUINT8(imgptr, 0);
imgptr += 2;
lastStartY = 254;
}
// Write stopgap empty spans if needed
writeY = y - lastStartY;
while (writeY > 254)
{
WRITEUINT8(imgptr, 254);
WRITEUINT8(imgptr, 0);
imgptr += 2;
writeY -= 254;
}
}
startofspan = imgptr;
WRITEUINT8(imgptr, writeY);
imgptr += 2;
spanSize = 0;
lastStartY = y;
}
// Write the pixel
WRITEUINT8(imgptr, paletteIndex);
spanSize++;
startofspan[1] = spanSize;
}
if (startofspan)
WRITEUINT8(imgptr, 0);
WRITEUINT8(imgptr, 0xFF);
}
size = imgptr-imgbuf;
img = Z_Malloc(size, PU_STATIC, NULL);
memcpy(img, imgbuf, size);
Z_Free(raw);
if (destsize != NULL)
*destsize = size;
return (patch_t *)img;
}
#ifndef NO_PNG_LUMPS
//
// R_IsLumpPNG
//
// Returns true if the lump is a valid PNG.
//
boolean R_IsLumpPNG(const UINT8 *d, size_t s)
{
if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/
return false;
// Check for PNG file signature using memcmp
// As it may be faster on CPUs with slow unaligned memory access
// Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature
return (memcmp(&d[0], "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0);
}
#ifdef HAVE_PNG
/*#if PNG_LIBPNG_VER_DLLNUM < 14
typedef PNG_CONST png_byte *png_const_bytep;
#endif*/
typedef struct
{
const UINT8 *buffer;
UINT32 size;
UINT32 position;
} png_io_t;
static void PNG_IOReader(png_structp png_ptr, png_bytep data, png_size_t length)
{
png_io_t *f = png_get_io_ptr(png_ptr);
if (length > (f->size - f->position))
png_error(png_ptr, "PNG_IOReader: buffer overrun");
memcpy(data, f->buffer + f->position, length);
f->position += length;
}
typedef struct
{
char name[4];
void *data;
size_t size;
} png_chunk_t;
static png_byte *chunkname = NULL;
static png_chunk_t chunk;
static int PNG_ChunkReader(png_structp png_ptr, png_unknown_chunkp chonk)
{
(void)png_ptr;
if (!memcmp(chonk->name, chunkname, 4))
{
memcpy(chunk.name, chonk->name, 4);
chunk.size = chonk->size;
chunk.data = Z_Malloc(chunk.size, PU_STATIC, NULL);
memcpy(chunk.data, chonk->data, chunk.size);
return 1;
}
return 0;
}
static void PNG_error(png_structp PNG, png_const_charp pngtext)
{
CONS_Debug(DBG_RENDER, "libpng error at %p: %s", PNG, pngtext);
//I_Error("libpng error at %p: %s", PNG, pngtext);
}
static void PNG_warn(png_structp PNG, png_const_charp pngtext)
{
CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext);
}
static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size)
{
png_structp png_ptr;
png_infop png_info_ptr;
png_uint_32 width, height;
int bit_depth, color_type;
png_uint_32 y;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
jmp_buf jmpbuf;
#endif
#endif
png_io_t png_io;
png_bytep *row_pointers;
png_byte grAb_chunk[5] = {'g', 'r', 'A', 'b', (png_byte)'\0'};
png_voidp *user_chunk_ptr;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn);
if (!png_ptr)
{
CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n");
return NULL;
}
png_info_ptr = png_create_info_struct(png_ptr);
if (!png_info_ptr)
{
CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n");
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
#ifdef USE_FAR_KEYWORD
if (setjmp(jmpbuf))
#else
if (setjmp(png_jmpbuf(png_ptr)))
#endif
{
//CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename);
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
return NULL;
}
#ifdef USE_FAR_KEYWORD
png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
#endif
// set our own read function
png_io.buffer = png;
png_io.size = size;
png_io.position = 0;
png_set_read_fn(png_ptr, &png_io, PNG_IOReader);
memset(&chunk, 0x00, sizeof(png_chunk_t));
chunkname = grAb_chunk; // I want to read a grAb chunk
user_chunk_ptr = png_get_user_chunk_ptr(png_ptr);
png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, PNG_ChunkReader);
png_set_keep_unknown_chunks(png_ptr, 2, chunkname, 1);
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
png_set_user_limits(png_ptr, 2048, 2048);
#endif
png_read_info(png_ptr, png_info_ptr);
png_get_IHDR(png_ptr, png_info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
if (bit_depth == 16)
png_set_strip_16(png_ptr);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
else if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
else if (color_type != PNG_COLOR_TYPE_RGB_ALPHA && color_type != PNG_COLOR_TYPE_GRAY_ALPHA)
{
#if PNG_LIBPNG_VER < 10207
png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER);
#else
png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
#endif
}
png_read_update_info(png_ptr, png_info_ptr);
// Read the image
row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * height);
for (y = 0; y < height; y++)
row_pointers[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, png_info_ptr));
png_read_image(png_ptr, row_pointers);
// Read grAB chunk
if ((topoffset || leftoffset) && (chunk.data != NULL))
{
INT32 *offsets = (INT32 *)chunk.data;
// read left offset
if (leftoffset != NULL)
*leftoffset = (INT16)BIGENDIAN_LONG(*offsets);
offsets++;
// read top offset
if (topoffset != NULL)
*topoffset = (INT16)BIGENDIAN_LONG(*offsets);
}
// bye
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
if (chunk.data)
Z_Free(chunk.data);
*w = (INT32)width;
*h = (INT32)height;
return row_pointers;
}
// Convert a PNG to a raw image.
static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size)
{
UINT8 *flat;
png_uint_32 x, y;
png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size);
png_uint_32 width = *w, height = *h;
if (!row_pointers)
I_Error("PNG_RawConvert: conversion failed");
// Convert the image to 8bpp
flat = Z_Malloc(width * height, PU_LEVEL, NULL);
memset(flat, TRANSPARENTPIXEL, width * height);
for (y = 0; y < height; y++)
{
png_bytep row = row_pointers[y];
for (x = 0; x < width; x++)
{
png_bytep px = &(row[x * 4]);
if ((UINT8)px[3])
flat[((y * width) + x)] = NearestColor((UINT8)px[0], (UINT8)px[1], (UINT8)px[2]);
}
}
free(row_pointers);
return flat;
}
//
// R_PNGToFlat
//
// Convert a PNG to a flat.
//
UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size)
{
return PNG_RawConvert(png, width, height, NULL, NULL, size);
}
//
// R_PNGToPatch
//
// Convert a PNG to a patch.
//
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency)
{
UINT16 width, height;
INT16 topoffset = 0, leftoffset = 0;
UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size);
if (!raw)
I_Error("R_PNGToPatch: conversion failed");
return R_FlatToPatch(raw, width, height, leftoffset, topoffset, destsize, transparency);
}
boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size)
{
png_structp png_ptr;
png_infop png_info_ptr;
png_uint_32 w, h;
int bit_depth, color_type;
#ifdef PNG_SETJMP_SUPPORTED
#ifdef USE_FAR_KEYWORD
jmp_buf jmpbuf;
#endif
#endif
png_io_t png_io;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
PNG_error, PNG_warn);
if (!png_ptr)
{
CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n");
return false;
}
png_info_ptr = png_create_info_struct(png_ptr);
if (!png_info_ptr)
{
CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n");
png_destroy_read_struct(&png_ptr, NULL, NULL);
return false;
}
#ifdef USE_FAR_KEYWORD
if (setjmp(jmpbuf))
#else
if (setjmp(png_jmpbuf(png_ptr)))
#endif
{
//CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename);
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
return false;
}
#ifdef USE_FAR_KEYWORD
png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf);
#endif
// set our own read function
png_io.buffer = png;
png_io.size = size;
png_io.position = 0;
png_set_read_fn(png_ptr, &png_io, PNG_IOReader);
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
png_set_user_limits(png_ptr, 2048, 2048);
#endif
png_read_info(png_ptr, png_info_ptr);
png_get_IHDR(png_ptr, png_info_ptr, &w, &h, &bit_depth, &color_type,
NULL, NULL, NULL);
// okay done. stop.
png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL);
*width = (INT32)w;
*height = (INT32)h;
return true;
}
#endif
#endif

View File

@ -88,13 +88,14 @@ void R_CheckTextureCache(INT32 tex);
// Retrieve column data for span blitting.
UINT8 *R_GetColumn(fixed_t tex, INT32 col);
UINT8 *R_GetFlat(lumpnum_t flatnum);
// I/O, setting up the stuff.
void R_InitData(void);
void R_PrecacheLevel(void);
extern size_t flatmemory, spritememory, texturememory;
// Retrieval.
// Floor/ceiling opaque texture tiles,
// lookup by name. For animation?
@ -158,19 +159,6 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap);
#define R_PutRgbaRGB(r, g, b) (R_PutRgbaR(r) + R_PutRgbaG(g) + R_PutRgbaB(b))
#define R_PutRgbaRGBA(r, g, b, a) (R_PutRgbaRGB(r, g, b) + R_PutRgbaA(a))
boolean R_CheckIfPatch(lumpnum_t lump);
void R_TextureToFlat(size_t tex, UINT8 *flat);
void R_PatchToFlat(patch_t *patch, UINT8 *flat);
patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency);
#ifndef NO_PNG_LUMPS
boolean R_IsLumpPNG(const UINT8 *d, size_t s);
UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size);
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency);
boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
#endif
extern INT32 numtextures;
#endif

View File

@ -24,6 +24,10 @@
#include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT
#ifdef HWRENDER
#include "m_aatree.h"
#endif
#define POLYOBJECTS
//
@ -728,6 +732,18 @@ typedef struct
#pragma pack()
#endif
// rotsprite
#ifdef ROTSPRITE
typedef struct
{
patch_t *patch[8][ROTANGLES];
boolean cached[8];
#ifdef HWRENDER
aatree_t *hardware_patch[8];
#endif
} rotsprite_t;
#endif
typedef enum
{
SRF_SINGLE = 0, // 0-angle for all rotations
@ -765,6 +781,10 @@ typedef struct
// Flip bits (1 = flip) to use for view angles 0-7.
UINT8 flip;
#ifdef ROTSPRITE
rotsprite_t rotsprite;
#endif
} spriteframe_t;
//

1373
src/r_patch.c Normal file

File diff suppressed because it is too large Load Diff

76
src/r_patch.h Normal file
View File

@ -0,0 +1,76 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file r_patch.h
/// \brief Patch generation.
#ifndef __R_PATCH__
#define __R_PATCH__
#include "r_defs.h"
#include "doomdef.h"
// structs
#ifdef ROTSPRITE
typedef enum
{
ROTAXIS_X, // roll (the default)
ROTAXIS_Y, // pitch
ROTAXIS_Z // yaw
} rotaxis_t;
typedef struct
{
INT32 x, y;
rotaxis_t rotaxis;
} spriteframepivot_t;
#endif
typedef struct
{
#ifdef ROTSPRITE
spriteframepivot_t pivot[64];
#endif
boolean available;
} spriteinfo_t;
extern spriteinfo_t spriteinfo[NUMSPRITES];
// patches, flats, textures...
boolean R_CheckIfPatch(lumpnum_t lump);
boolean R_IsLumpPNG(const UINT8 *d, size_t s);
void R_TextureToFlat(size_t tex, UINT8 *flat);
void R_PatchToFlat(patch_t *patch, UINT8 *flat);
void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip);
patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency);
patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size);
// png
#ifndef NO_PNG_LUMPS
UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size);
patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency);
boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
#endif
// spriteinfo
void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum);
// rotsprite
#ifdef ROTSPRITE
void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip);
void R_FreeSingleRotSprite(spritedef_t *spritedef);
void R_FreeSkinRotSprite(size_t skinnum);
extern fixed_t cosang2rad[ROTANGLES];
extern fixed_t sinang2rad[ROTANGLES];
#endif
#endif // __R_PATCH__

View File

@ -1114,8 +1114,6 @@ void R_DrawSinglePlane(visplane_t *pl)
temp = P_GetZAt(pl->slope, pl->viewx, pl->viewy);
zeroheight = FIXED_TO_FLOAT(temp);
#define ANG2RAD(angle) ((float)((angle)*M_PIl)/ANGLE_180)
// p is the texture origin in view space
// Don't add in the offsets at this stage, because doing so can result in
// errors if the flat is rotated.

View File

@ -22,7 +22,9 @@
#include "m_misc.h"
#include "info.h" // spr2names
#include "i_video.h" // rendermode
#include "i_system.h"
#include "r_things.h"
#include "r_patch.h"
#include "r_plane.h"
#include "r_portal.h"
#include "p_tick.h"
@ -35,6 +37,9 @@
#include "fastcmp.h"
#ifdef HWRENDER
#include "hardware/hw_md2.h"
#include "hardware/hw_glob.h"
#include "hardware/hw_light.h"
#include "hardware/hw_drv.h"
#endif
#ifdef PC_DOS
@ -68,6 +73,8 @@ static lighttable_t **spritelights;
INT16 negonearray[MAXVIDWIDTH];
INT16 screenheightarray[MAXVIDWIDTH];
spriteinfo_t spriteinfo[NUMSPRITES];
//
// INITIALIZATION FUNCTIONS
//
@ -100,7 +107,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
{
char cn = R_Frame2Char(frame); // for debugging
INT32 r;
INT32 r, ang;
lumpnum_t lumppat = wad;
lumppat <<= 16;
lumppat += lump;
@ -111,6 +118,20 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch
if (maxframe ==(size_t)-1 || frame > maxframe)
maxframe = frame;
// rotsprite
#ifdef ROTSPRITE
for (r = 0; r < 8; r++)
{
sprtemp[frame].rotsprite.cached[r] = false;
for (ang = 0; ang < ROTANGLES; ang++)
sprtemp[frame].rotsprite.patch[r][ang] = NULL;
#ifdef HWRENDER
if (rendermode == render_opengl)
sprtemp[frame].rotsprite.hardware_patch[r] = M_AATreeAlloc(AATREE_ZUSER);
#endif // HWRENDER
}
#endif
if (rotation == 0)
{
// the lump should be used for all rotations
@ -222,6 +243,9 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
// if so, it might patch only certain frames, not all
if (spritedef->numframes) // (then spriteframes is not null)
{
#ifdef ROTSPRITE
R_FreeSingleRotSprite(spritedef);
#endif
// copy the already defined sprite frames
M_Memcpy(sprtemp, spritedef->spriteframes,
spritedef->numframes * sizeof (spriteframe_t));
@ -274,12 +298,12 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
//BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
if (rendermode != render_none) // not for psprite
spritecachedinfo[numspritelumps].topoffset += 4<<FRACBITS;
spritecachedinfo[numspritelumps].topoffset += FEETADJUST;
// Being selective with this causes bad things. :( Like the special stage tokens breaking apart.
/*if (rendermode != render_none // not for psprite
&& SHORT(patch.topoffset)>0 && SHORT(patch.topoffset)<SHORT(patch.height))
// perfect is patch.height but sometime it is too high
spritecachedinfo[numspritelumps].topoffset = min(SHORT(patch.topoffset)+4,SHORT(patch.height))<<FRACBITS;*/
spritecachedinfo[numspritelumps].topoffset = min(SHORT(patch.topoffset)+(FEETADJUST>>FRACBITS),SHORT(patch.height))<<FRACBITS;*/
//----------------------------------------------------
@ -369,6 +393,9 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
if (spritedef->numframes && // has been allocated
spritedef->numframes < maxframe) // more frames are defined ?
{
#ifdef ROTSPRITE
R_FreeSingleRotSprite(spritedef);
#endif
Z_Free(spritedef->spriteframes);
spritedef->spriteframes = NULL;
}
@ -465,7 +492,6 @@ UINT32 visspritecount;
static UINT32 clippedvissprites;
static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
//
// R_InitSprites
// Called at program start.
@ -473,11 +499,23 @@ static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL
void R_InitSprites(void)
{
size_t i;
#ifdef ROTSPRITE
INT32 angle, realangle = 0;
float fa;
#endif
for (i = 0; i < MAXVIDWIDTH; i++)
{
negonearray[i] = -1;
#ifdef ROTSPRITE
for (angle = 0; angle < ROTANGLES; angle++)
{
fa = ANG2RAD(FixedAngle(realangle<<FRACBITS));
cosang2rad[angle] = FLOAT_TO_FIXED(cos(-fa));
sinang2rad[angle] = FLOAT_TO_FIXED(sin(-fa));
realangle += ROTANGDIFF;
}
#endif
//
// count the number of sprite names, and allocate sprites table
@ -505,6 +543,7 @@ void R_InitSprites(void)
{
R_AddSkins((UINT16)i);
R_PatchSkins((UINT16)i);
R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps);
}
ST_ReloadSkinFaceGraphics();
@ -717,7 +756,7 @@ static void R_DrawVisSprite(vissprite_t *vis)
INT32 texturecolumn;
#endif
fixed_t frac;
patch_t *patch = W_CachePatchNum(vis->patch, PU_CACHE);
patch_t *patch = vis->patch;
fixed_t this_scale = vis->mobj->scale;
INT32 x1, x2;
INT64 overflow_test;
@ -906,7 +945,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
INT64 overflow_test;
//Fab : R_InitSprites now sets a wad lump number
patch = W_CachePatchNum(vis->patch, PU_CACHE);
patch = vis->patch;
if (!patch)
return;
@ -1060,6 +1099,9 @@ static void R_ProjectSprite(mobj_t *thing)
spritedef_t *sprdef;
spriteframe_t *sprframe;
#ifdef ROTSPRITE
spriteinfo_t *sprinfo;
#endif
size_t lump;
size_t rot;
@ -1086,6 +1128,15 @@ static void R_ProjectSprite(mobj_t *thing)
INT32 light = 0;
fixed_t this_scale = thing->scale;
// rotsprite
fixed_t spr_width, spr_height;
fixed_t spr_offset, spr_topoffset;
#ifdef ROTSPRITE
patch_t *rotsprite = NULL;
angle_t arollangle = thing->rollangle;
UINT32 rollangle = AngleFixed(arollangle)>>FRACBITS;
#endif
fixed_t ang_scale = FRACUNIT;
// transform the origin point
@ -1125,16 +1176,27 @@ static void R_ProjectSprite(mobj_t *thing)
if (thing->skin && thing->sprite == SPR_PLAY)
{
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
#ifdef ROTSPRITE
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
#endif
if (rot >= sprdef->numframes) {
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(rot));
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
#ifdef ROTSPRITE
sprinfo = NULL;
#endif
rot = thing->frame&FF_FRAMEMASK;
}
}
else
{
sprdef = &sprites[thing->sprite];
#ifdef ROTSPRITE
sprinfo = NULL;
#endif
}
if (rot >= sprdef->numframes)
{
@ -1194,11 +1256,35 @@ static void R_ProjectSprite(mobj_t *thing)
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale);
spr_width = spritecachedinfo[lump].width;
spr_height = spritecachedinfo[lump].height;
spr_offset = spritecachedinfo[lump].offset;
spr_topoffset = spritecachedinfo[lump].topoffset;
#ifdef ROTSPRITE
if (rollangle > 0)
{
if (!sprframe->rotsprite.cached[rot])
R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip);
rollangle /= ROTANGDIFF;
rotsprite = sprframe->rotsprite.patch[rot][rollangle];
if (rotsprite != NULL)
{
spr_width = rotsprite->width << FRACBITS;
spr_height = rotsprite->height << FRACBITS;
spr_offset = rotsprite->leftoffset << FRACBITS;
spr_topoffset = rotsprite->topoffset << FRACBITS;
// flip -> rotate, not rotate -> flip
flip = 0;
}
}
#endif
// calculate edges of the shape
if (flip)
offset = spritecachedinfo[lump].offset - spritecachedinfo[lump].width;
offset = spr_offset - spr_width;
else
offset = -spritecachedinfo[lump].offset;
offset = -spr_offset;
offset = FixedMul(offset, this_scale);
tx += FixedMul(offset, ang_scale);
x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
@ -1207,7 +1293,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (x1 > viewwidth)
return;
offset2 = FixedMul(spritecachedinfo[lump].width, this_scale);
offset2 = FixedMul(spr_width, this_scale);
tx += FixedMul(offset2, ang_scale);
x2 = ((centerxfrac + FixedMul (tx,xscale)) >> FRACBITS) - (papersprite ? 2 : 1);
@ -1309,13 +1395,13 @@ static void R_ProjectSprite(mobj_t *thing)
// When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned.
// sprite height - sprite topoffset is the proper inverse of the vertical offset, of course.
// remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes!
gz = oldthing->z + oldthing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gzt = gz + FixedMul(spritecachedinfo[lump].height, this_scale);
gz = oldthing->z + oldthing->height - FixedMul(spr_topoffset, this_scale);
gzt = gz + FixedMul(spr_height, this_scale);
}
else
{
gzt = oldthing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale);
gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale);
gzt = oldthing->z + FixedMul(spr_topoffset, this_scale);
gz = gzt - FixedMul(spr_height, this_scale);
}
if (thing->subsector->sector->cullheight)
@ -1414,7 +1500,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (flip)
{
vis->startfrac = spritecachedinfo[lump].width-1;
vis->startfrac = spr_width-1;
vis->xiscale = -iscale;
}
else
@ -1431,7 +1517,12 @@ static void R_ProjectSprite(mobj_t *thing)
//Fab: lumppat is the lump number of the patch to use, this is different
// than lumpid for sprites-in-pwad : the graphics are patched
vis->patch = sprframe->lumppat[rot];
#ifdef ROTSPRITE
if (rotsprite != NULL)
vis->patch = rotsprite;
else
#endif
vis->patch = W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE);
//
// determine the colormap (lightlevel & special effects)
@ -1623,7 +1714,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
//Fab: lumppat is the lump number of the patch to use, this is different
// than lumpid for sprites-in-pwad : the graphics are patched
vis->patch = sprframe->lumppat[0];
vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
// specific translucency
if (thing->frame & FF_TRANSMASK)
@ -2801,7 +2892,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
if (player->mo)
{
fixed_t radius = FixedMul(skin->radius, player->mo->scale);
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NGT0].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NFLY].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
{
skin = &skins[DEFAULTNIGHTSSKIN];
player->followitem = skin->followitem;

View File

@ -16,7 +16,9 @@
#include "sounds.h"
#include "r_plane.h"
#include "r_patch.h"
#include "r_portal.h"
#include "r_defs.h"
// "Left" and "Right" character symbols for additional rotation functionality
#define ROT_L ('L' - '0')
@ -30,6 +32,8 @@
#define VISSPRITESPERCHUNK (1 << VISSPRITECHUNKBITS)
#define VISSPRITEINDEXMASK (VISSPRITESPERCHUNK - 1)
#define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
// Constant arrays used for psprite clipping
// and initializing clipping.
extern INT16 negonearray[MAXVIDWIDTH];
@ -128,7 +132,9 @@ typedef struct
// specific sounds per skin
sfxenum_t soundsid[NUMSKINSOUNDS]; // sound # in S_sfx table
spritedef_t sprites[NUMPLAYERSPRITES*2]; // contains super versions too
// contains super versions too
spritedef_t sprites[NUMPLAYERSPRITES*2];
spriteinfo_t sprinfo[NUMPLAYERSPRITES*2];
UINT8 availability; // lock?
} skin_t;
@ -178,7 +184,7 @@ typedef struct vissprite_s
fixed_t xiscale; // negative if flipped
fixed_t texturemid;
lumpnum_t patch;
patch_t *patch;
lighttable_t *colormap; // for color translation and shadow draw
// maxbright frames as well

View File

@ -281,6 +281,7 @@
<ClInclude Include="..\r_local.h" />
<ClInclude Include="..\r_main.h" />
<ClInclude Include="..\r_plane.h" />
<ClInclude Include="..\r_patch.h" />
<ClInclude Include="..\r_portal.h" />
<ClInclude Include="..\r_segs.h" />
<ClInclude Include="..\r_sky.h" />
@ -439,6 +440,7 @@
</ClCompile>
<ClCompile Include="..\r_main.c" />
<ClCompile Include="..\r_plane.c" />
<ClCompile Include="..\r_patch.c" />
<ClCompile Include="..\r_portal.c" />
<ClCompile Include="..\r_segs.c" />
<ClCompile Include="..\r_sky.c" />
@ -490,4 +492,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -465,6 +465,9 @@
<ClInclude Include="..\hardware\hw_clip.h">
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\r_patch.h">
<Filter>R_Rend</Filter>
</ClInclude>
<ClInclude Include="..\r_portal.h">
<Filter>R_Rend</Filter>
</ClInclude>
@ -922,6 +925,9 @@
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\apng.c" />
<ClCompile Include="..\r_patch.c">
<Filter>R_Rend</Filter>
</ClCompile>
<ClCompile Include="..\r_portal.c">
<Filter>R_Rend</Filter>
</ClCompile>
@ -931,4 +937,4 @@
<Filter>SDLApp</Filter>
</Image>
</ItemGroup>
</Project>
</Project>

View File

@ -1183,21 +1183,6 @@ void zerr(int ret)
}
#endif
#ifdef NO_PNG_LUMPS
static void ErrorIfPNG(UINT8 *d, size_t s, char *f, char *l)
{
if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/
return;
// Check for PNG file signature using memcmp
// As it may be faster on CPUs with slow unaligned memory access
// Ref: http://www.libpng.org/pub/png/spec/1.2/PNG-Rationale.html#R.PNG-file-signature
if (memcmp(&d[0], "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0)
{
I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .PNG - please convert to either Doom or Flat (raw) image format.", l, f);
}
}
#endif
/** Reads bytes from the head of a lump.
* Note: If the lump is compressed, the whole thing has to be read anyway.
*
@ -1240,7 +1225,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
#ifdef NO_PNG_LUMPS
{
size_t bytesread = fread(dest, 1, size, handle);
ErrorIfPNG(dest, bytesread, wadfiles[wad]->filename, l->name2);
if (R_IsLumpPNG((UINT8 *)dest, bytesread))
I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .png - please convert to either Doom or Flat (raw) image format.", l->name2, wadfiles[wad]->filename);
return bytesread;
}
#else

View File

@ -297,6 +297,7 @@
</ClCompile>
<ClCompile Include="..\r_main.c" />
<ClCompile Include="..\r_plane.c" />
<ClCompile Include="..\r_patch.c" />
<ClCompile Include="..\r_portal.c" />
<ClCompile Include="..\r_segs.c" />
<ClCompile Include="..\r_sky.c" />
@ -452,6 +453,7 @@
<ClInclude Include="..\r_local.h" />
<ClInclude Include="..\r_main.h" />
<ClInclude Include="..\r_plane.h" />
<ClInclude Include="..\r_patch.h" />
<ClInclude Include="..\r_portal.h" />
<ClInclude Include="..\r_segs.h" />
<ClInclude Include="..\r_sky.h" />
@ -505,4 +507,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -469,6 +469,9 @@
<Filter>Hw_Hardware</Filter>
</ClCompile>
<ClCompile Include="..\apng.c" />
<ClCompile Include="..\r_patch.c">
<Filter>R_Rend</Filter>
</ClCompile>
<ClCompile Include="..\r_portal.c">
<Filter>R_Rend</Filter>
</ClCompile>
@ -886,6 +889,9 @@
<Filter>Hw_Hardware</Filter>
</ClInclude>
<ClInclude Include="..\apng.h" />
<ClInclude Include="..\r_patch.h">
<Filter>R_Rend</Filter>
</ClInclude>
<ClInclude Include="..\r_portal.h">
<Filter>R_Rend</Filter>
</ClInclude>
@ -919,4 +925,4 @@
<Filter>A_Asm</Filter>
</CustomBuild>
</ItemGroup>
</Project>
</Project>