diff --git a/src/dehacked.c b/src/dehacked.c index 2f28a74cf..0df90c701 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2319,6 +2319,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"}, diff --git a/src/doomdef.h b/src/doomdef.h index c948d7805..767c45020 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -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; @@ -616,4 +618,9 @@ 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) + #endif // __DOOMDEF__ diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 6bc2c712e..8dbf165bb 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -933,10 +933,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); @@ -955,12 +959,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); @@ -1207,6 +1215,22 @@ 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; + 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) diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index 44929dd67..a8f030f73 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -83,6 +83,7 @@ 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 + void *rawpatch; // :^) GLMipmap_t mipmap; }; typedef struct GLPatch_s GLPatch_t; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 5dcead77c..b8354c82d 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -103,6 +103,11 @@ typedef struct FLOAT fovxangle, fovyangle; INT32 splitscreen; boolean flip; // screenflip +#ifdef ROTSPRITE + // rotsprite + boolean roll; + FLOAT centerx,centery; +#endif } FTransform; // Transformed vector, as passed to HWR API diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 9656e54e9..015890f61 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -72,7 +72,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; @@ -109,6 +110,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); // -------- diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c600800fd..ade62bfcf 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -4332,7 +4332,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) @@ -4688,7 +4688,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 || @@ -4833,7 +4833,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 // @@ -5477,10 +5477,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; @@ -5573,6 +5585,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(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)); @@ -5586,13 +5622,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 @@ -5614,13 +5650,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) @@ -5653,7 +5689,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; @@ -5779,7 +5821,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; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index d4728315a..072b17e41 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1401,7 +1401,7 @@ void HWR_DrawMD2(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); } @@ -1503,7 +1503,22 @@ void HWR_DrawMD2(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); } - p.anglex = 0.0f; + + // rotsprite +#ifdef ROTSPRITE + if (spr->mobj->rollangle) + { + // do i have to support ROTANGLES here?????? + fixed_t anglef = AngleFixed(spr->mobj->rollangle); + p.anglex = FIXED_TO_FLOAT(anglef); + // pivot + p.centerx = FIXED_TO_FLOAT(spr->mobj->radius/2); + p.centery = FIXED_TO_FLOAT(spr->mobj->height/2); + p.roll = true; + } + else +#endif + p.anglex = 0.0f; color[0] = Surf.FlatColor.s.red; color[1] = Surf.FlatColor.s.green; diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index dfee19857..e91f29cda 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -1636,7 +1636,18 @@ static void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, INT32 duration, if (flipped) scaley = -scaley; pglRotatef(pos->angley, 0.0f, -1.0f, 0.0f); - pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f); + +#ifdef ROTSPRITE + // rotsprite + if (pos->roll) + { + pglTranslatef(pos->centerx, pos->centery, 0); + pglRotatef(pos->anglex, 1.0f, 0.0f, 0.0f); + pglTranslatef(-pos->centerx, -pos->centery, 0); + } + else +#endif + pglRotatef(pos->anglex, -1.0f, 0.0f, 0.0f); val = *gl_cmd_buffer++; diff --git a/src/info.c b/src/info.c index 9aed563c7..656add08c 100644 --- a/src/info.c +++ b/src/info.c @@ -2408,7 +2408,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 diff --git a/src/info.h b/src/info.h index bb27ac3e3..89c969226 100644 --- a/src/info.h +++ b/src/info.h @@ -153,6 +153,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(); diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 063158b26..71fdab729 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -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", @@ -197,6 +203,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; @@ -447,6 +458,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; diff --git a/src/p_enemy.c b/src/p_enemy.c index 4126d0716..467c4dc26 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -179,6 +179,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); @@ -8172,7 +8177,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) @@ -8206,7 +8211,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) @@ -8217,6 +8222,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 diff --git a/src/p_mobj.h b/src/p_mobj.h index a9d5244b0..b1eda9fb6 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -277,6 +277,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 @@ -397,6 +400,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 diff --git a/src/p_saveg.c b/src/p_saveg.c index ea998b445..c557b2517 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1267,6 +1267,9 @@ typedef enum MD2_SLOPE = 1<<11, #endif MD2_COLORIZED = 1<<12, +#ifdef ROTSPRITE + MD2_ROLLANGLE = 1<<13, +#endif } mobj_diff2_t; typedef enum @@ -1486,6 +1489,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; @@ -1650,6 +1657,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); } @@ -2726,6 +2737,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) { diff --git a/src/p_setup.c b/src/p_setup.c index d0cd14b22..3b533ce43 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -540,9 +540,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++) { lump = levelflats[i].lumpnum; diff --git a/src/p_user.c b/src/p_user.c index b74cafd21..4fad1c087 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6706,6 +6706,11 @@ static void P_NiGHTSMovement(player_t *player) INT32 i; statenum_t flystate; UINT16 visangle; +#ifdef ROTSPRITE + angle_t rollangle = 0; + UINT8 turningstate = 0; + UINT8 turndiff = 24; +#endif player->pflags &= ~PF_DRILLING; @@ -6890,6 +6895,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; } @@ -6904,6 +6912,9 @@ static void P_NiGHTSMovement(player_t *player) P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_DRILL6); player->mo->flags |= MF_NOCLIPHEIGHT; +#ifdef ROTSPRITE + player->mo->rollangle = 0; +#endif return; } @@ -7176,6 +7187,7 @@ static void P_NiGHTSMovement(player_t *player) flystate = (P_IsObjectOnGround(player->mo)) ? S_PLAY_NIGHTS_STAND : S_PLAY_NIGHTS_FLOAT; else { +#ifndef ROTSPRITE visangle = ((player->anotherflyangle + 7) % 360)/15; if (visangle > 18) // Over 270 degrees. visangle = 30 - visangle; @@ -7192,15 +7204,55 @@ static void P_NiGHTSMovement(player_t *player) visangle += 6; // shift to S_PLAY_NIGHTS_FLY7-C } - flystate = S_PLAY_NIGHTS_FLY0 + (visangle*2); // S_PLAY_FLY0-C - the *2 is to skip over drill states + flystate = S_PLAY_NIGHTS_FLY0 + (visangle*2); // S_PLAY_NIGHTS_FLY0-C - the *2 is to skip over drill states if (player->pflags & PF_DRILLING) flystate++; // shift to S_PLAY_NIGHTS_DRILL0-C +#else + angle_t a = R_PointToAngle(player->mo->x, player->mo->y) - player->mo->angle; + visangle = (player->flyangle % 360); + + flystate = S_PLAY_NIGHTS_FLY0; + if (player->pflags & PF_DRILLING) + flystate++; // shift to S_PLAY_NIGHTS_DRILL0-C + else + { + if ((visangle >= (90-turndiff) && visangle <= (90+turndiff)) + || (visangle >= (270-turndiff) && visangle <= (270+turndiff))) + { + turningstate = 3; + flystate = S_PLAY_NIGHTS_DRILL0; + } + } + + 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; + } + + rollangle = FixedAngle(visangle*FRACUNIT); +#endif // ROTSPRITE } if (player->mo->state != &states[flystate]) P_SetPlayerMobjState(player->mo, flystate); +#ifdef ROTSPRITE + player->mo->rollangle = rollangle; + if (turningstate) + { + player->mo->frame = turningstate; + player->mo->tics = -1; + } + else if (player->mo->tics == -1) + player->mo->tics = states[flystate].tics; +#endif // ROTSPRITE + if (player == &players[consoleplayer]) localangle = player->mo->angle; else if (player == &players[secondarydisplayplayer]) diff --git a/src/r_data.c b/src/r_data.c index 6889bddde..bb437719e 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -114,7 +114,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 @@ -2306,3 +2306,211 @@ void R_PrecacheLevel(void) "texturememory: %s k\n" "spritememory: %s k\n", sizeu1(flatmemory>>10), sizeu2(texturememory>>10), sizeu3(spritememory>>10)); } + +#ifdef ROTSPRITE +// https://github.com/coelckers/prboom-plus/blob/master/prboom2/src/r_patch.c#L350 +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; +} + +// https://github.com/Jimita/SRB2/blob/flats-png/src/r_data.c#L2157 +void R_PatchToFlat(patch_t *patch, UINT16 *raw, boolean flip) +{ + fixed_t col, ofs; + column_t *column; + UINT16 *desttop, *dest, *deststop; + UINT8 *source; + + desttop = raw; + deststop = desttop + (SHORT(patch->width) * SHORT(patch->height)); + + #define DEAR_GOD_FORGIVE_ME_FOR_MY_MACROS \ + { \ + 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); \ + } \ + } + + if (!flip) + { + for (col = 0; col < SHORT(patch->width); col++, desttop++) + DEAR_GOD_FORGIVE_ME_FOR_MY_MACROS + } + else + { + // flipped + for (col = SHORT(patch->width)-1; col >= 0; col--, desttop++) + DEAR_GOD_FORGIVE_ME_FOR_MY_MACROS + } +} + +// https://github.com/Jimita/SRB2/blob/flats-png/src/r_data.c#L1970 +static UINT8 imgbuf[1<<26]; +patch_t *R_FlatToPatch(UINT16 *raw, UINT16 width, UINT16 height, size_t *size) +{ + UINT32 x, y; + UINT8 *img; + UINT8 *imgptr = imgbuf; + UINT8 *colpointers, *startofspan; + + #define WRITE8(buf, a) ({*buf = (a); buf++;}) + #define WRITE16(buf, a) ({*buf = (a)&255; buf++; *buf = (a)>>8; buf++;}) + #define WRITE32(buf, a) ({WRITE16(buf, (a)&65535); WRITE16(buf, (a)>>16);}) + + if (!raw) + return NULL; + + // Write image size and offset + WRITE16(imgptr, width); + WRITE16(imgptr, height); + // no offsets + WRITE16(imgptr, 0); + WRITE16(imgptr, 0); + + // 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; + + //printf("%d ", x); + // Write column pointer (@TODO may be wrong) + WRITE32(colpointers, imgptr - imgbuf); + + // Write pixels + for (y = 0; y < height; y++) + { + UINT16 pixel = raw[((y * width) + x)]; + UINT8 paletteIndex = (pixel & 0xFF); + UINT8 opaque = (pixel != 0xFF00); // If 1, we have a pixel + + // End span if we have a transparent pixel + if (!opaque) + { + if (startofspan) + WRITE8(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) + WRITE8(imgptr, 0); + + if (y > 254) + { + // Make sure we're aligned to 254 + if (lastStartY < 254) + { + WRITE8(imgptr, 254); + WRITE8(imgptr, 0); + imgptr += 2; + lastStartY = 254; + } + + // Write stopgap empty spans if needed + writeY = y - lastStartY; + + while (writeY > 254) + { + WRITE8(imgptr, 254); + WRITE8(imgptr, 0); + imgptr += 2; + writeY -= 254; + } + } + + startofspan = imgptr; + WRITE8(imgptr, writeY);///@TODO calculate starting y pos + imgptr += 2; + spanSize = 0; + + lastStartY = y; + } + + // Write the pixel + WRITE8(imgptr, paletteIndex); + spanSize++; + startofspan[1] = spanSize; + } + + if (startofspan) + WRITE8(imgptr, 0); + + WRITE8(imgptr, 0xFF); + } + + #undef WRITE8 + #undef WRITE16 + #undef WRITE32 + + *size = imgptr-imgbuf; + img = malloc(*size); + memcpy(img, imgbuf, *size); + return (patch_t *)img; +} +#endif diff --git a/src/r_data.h b/src/r_data.h index b6b0a16a1..5d4afe791 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -77,13 +77,20 @@ 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); +#ifdef ROTSPRITE +boolean R_CheckIfPatch(lumpnum_t lump); +void R_PatchToFlat(patch_t *patch, UINT16 *raw, boolean flip); +patch_t *R_FlatToPatch(UINT16 *raw, UINT16 width, UINT16 height, size_t *size); +#endif + // 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? diff --git a/src/r_defs.h b/src/r_defs.h index def7b46f3..a04b3128f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -24,6 +24,10 @@ #include "screen.h" // MAXVIDWIDTH, MAXVIDHEIGHT +#ifdef HWRENDER +#include "m_aatree.h" +#endif + #define POLYOBJECTS // @@ -723,6 +727,18 @@ typedef struct #pragma pack() #endif +// Rotated sprite 0-360 +#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 @@ -760,6 +776,10 @@ typedef struct // Flip bits (1 = flip) to use for view angles 0-7. UINT8 flip; + +#ifdef ROTSPRITE + rotsprite_t rotsprite; +#endif } spriteframe_t; // diff --git a/src/r_plane.c b/src/r_plane.c index 2f6f97240..e17116b04 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -1007,8 +1007,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_PI)/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. diff --git a/src/r_things.c b/src/r_things.c index 92f2b9460..ce11a4210 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -22,6 +22,7 @@ #include "m_misc.h" #include "info.h" // spr2names #include "i_video.h" // rendermode +#include "i_system.h" #include "r_things.h" #include "r_plane.h" #include "r_portal.h" @@ -35,6 +36,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 +72,11 @@ static lighttable_t **spritelights; INT16 negonearray[MAXVIDWIDTH]; INT16 screenheightarray[MAXVIDWIDTH]; +#ifdef ROTSPRITE +static fixed_t cosang2rad[ROTANGLES]; +static fixed_t sinang2rad[ROTANGLES]; +#endif + // // INITIALIZATION FUNCTIONS // @@ -100,7 +109,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 +120,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 @@ -193,6 +216,157 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch sprtemp[frame].flip &= ~(1<rotsprite.cached[rot]) + { + INT32 sx,sy; + INT32 dx,dy; + INT32 ox,oy; + INT32 nox,noy; + INT32 width,height; + fixed_t ca, sa; + lumpnum_t lump = sprframe->lumppat[rot]; + + if (lump == LUMPERROR) + return; + // Because there's something wrong with SPR_DFLM, I guess + if (!R_CheckIfPatch(lump)) + return; + + patch = (patch_t *)W_CacheLumpNum(lump, PU_CACHE); + lumpname = W_CheckNameForNum(lump); + CONS_Debug(DBG_RENDER, "R_CacheRotSprite: %s\n", lumpname); + //CONS_Printf("%d\n", angle * ROTANGDIFF); + + width = patch->width; + height = patch->height; + // patch origin + ox = (width / 2); + oy = (height / 2); + + // Draw the sprite to a temporary buffer. + size = (width*height); + rawsrc = Z_Malloc(size * sizeof(UINT16), PU_STATIC, NULL); + + // can't memset here + for (i = 0; i < size; i++) + rawsrc[i] = 0xFF00; + + R_PatchToFlat(patch, rawsrc, (flip != 0x00)); + + // Don't cache angle = 0, that would be stoopid + for (angle = 1; angle < ROTANGLES; angle++) + { + INT32 minx = 32767, maxx = -32767; + INT32 miny = 32767, maxy = -32767; + INT32 newwidth, newheight; + + ca = cosang2rad[angle]; + sa = sinang2rad[angle]; + + // Find the dimensions of the rotated patch. + // This is BROKEN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + for (sy = 0; sy < height; sy++) + { + for (sx = 0; sx < width; sx++) + { + dx = FixedMul((sx-ox) << FRACBITS, ca) + FixedMul((sy-oy) << FRACBITS, sa) + (ox << FRACBITS); + dy = -FixedMul((sx-oy) << FRACBITS, sa) + FixedMul((sy-oy) << FRACBITS, ca) + (oy << FRACBITS); + dx >>= FRACBITS; + dy >>= FRACBITS; + if (dx < minx) minx = dx; + if (dx > maxx) maxx = dx; + if (dy < miny) miny = dy; + if (dy > maxy) maxy = dy; + } + } + + newwidth = (maxx - minx) * 1.5f; + newheight = (maxy - miny) * 1.5f; + + nox = (newwidth / 2); + noy = (newheight / 2); + + size2 = (newwidth * newheight); + if (!size2) + size2 = size; + + rawdst = Z_Malloc(size2 * sizeof(UINT16), PU_STATIC, NULL); + + // can't memset here + for (i = 0; i < size2; i++) + rawdst[i] = 0xFF00; + + // Draw the rotated sprite to a temporary buffer. + for (dy = 0; dy < newheight; dy++) + { + for (dx = 0; dx < newwidth; dx++) + { + sx = FixedMul((dx-nox) << FRACBITS, ca) + FixedMul((dy-noy) << FRACBITS, sa) + (ox << FRACBITS); + sy = -FixedMul((dx-nox) << FRACBITS, sa) + FixedMul((dy-noy) << FRACBITS, ca) + (oy << FRACBITS); + sx >>= FRACBITS; + sy >>= FRACBITS; + if (sx >= 0 && sy >= 0 && sx < width && sy < height) + rawdst[(dy*newwidth)+dx] = rawsrc[(sy*width)+sx]; + } + } + + // make patch + newpatch = R_FlatToPatch(rawdst, newwidth, newheight, &size); + // This is BROKEN!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + newpatch->leftoffset = (newpatch->width / 2) - ((ox - patch->leftoffset) * ((flip != 0x00) ? -1 : 1)); + newpatch->topoffset = (newpatch->height / 2) - (oy - patch->topoffset); + + //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer + if (rendermode != render_none) // not for psprite + newpatch->topoffset += 4; + + // P_PrecacheLevel + if (devparm) spritememory += size; + +#ifdef HWRENDER + if (rendermode == render_opengl) + { + GLPatch_t *grPatch = HWR_GetCachedGLRotSprite(sprframe->rotsprite.hardware_patch[rot], angle, newpatch); + HWR_MakePatch(newpatch, grPatch, &grPatch->mipmap, false); + sprframe->rotsprite.patch[rot][angle] = (patch_t *)grPatch; + } + else +#endif // HWRENDER + sprframe->rotsprite.patch[rot][angle] = newpatch; + + // free rotated image data + Z_Free(rawdst); + } + + // This rotation is cached now + sprframe->rotsprite.cached[rot] = true; + + // free image data + Z_Free(rawsrc); + +#ifdef HWRENDER + if (rendermode == render_soft) +#endif + W_UnlockCachedPatch(patch); + + // Can remove if needed + I_OsPolling(); + I_UpdateNoBlit(); + } +} +#endif + // Install a single sprite, given its identifying name (4 chars) // // (originally part of R_AddSpriteDefs) @@ -214,6 +388,9 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, lumpinfo_t *lumpinfo; patch_t patch; UINT8 numadded = 0; +#ifdef ROTSPRITE + INT32 rot, ang; +#endif memset(sprtemp,0xFF, sizeof (sprtemp)); maxframe = (size_t)-1; @@ -356,6 +533,16 @@ 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 + for (frame = 0; frame < spritedef->numframes; frame++) + { + spriteframe_t *sprframe = &spritedef->spriteframes[frame]; + for (rot = 0; rot < 8; rot++) + if (sprframe->rotsprite.cached[rot]) + for (ang = 0; ang < ROTANGLES; ang++) + Z_Free(sprframe->rotsprite.patch[rot][ang]); + } +#endif // ROTSPRITE Z_Free(spritedef->spriteframes); spritedef->spriteframes = NULL; } @@ -449,7 +636,6 @@ UINT32 visspritecount; static UINT32 clippedvissprites; static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL}; - // // R_InitSprites // Called at program start. @@ -457,11 +643,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<patch, PU_CACHE); + patch_t *patch = vis->patch; fixed_t this_scale = vis->mobj->scale; INT32 x1, x2; INT64 overflow_test; @@ -870,7 +1068,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) INT64 overflow_test; //Fab : R_InitSprites now sets a wad lump number - patch = W_CacheLumpNum(vis->patch, PU_CACHE); + patch = vis->patch; if (!patch) return; @@ -1050,6 +1248,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 @@ -1158,11 +1365,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(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; @@ -1171,7 +1402,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); @@ -1273,13 +1504,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) @@ -1378,7 +1609,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 @@ -1395,7 +1626,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_CacheLumpNum(sprframe->lumppat[rot], PU_CACHE); // // determine the colormap (lightlevel & special effects) @@ -1587,7 +1823,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_CacheLumpNum(sprframe->lumppat[0], PU_CACHE); // specific translucency if (thing->frame & FF_TRANSMASK) diff --git a/src/r_things.h b/src/r_things.h index 9c3d16ab0..8ceb9d07f 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -17,6 +17,7 @@ #include "sounds.h" #include "r_plane.h" #include "r_portal.h" +#include "r_defs.h" // "Left" and "Right" character symbols for additional rotation functionality #define ROT_L ('L' - '0') @@ -51,6 +52,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, INT32 texheight); // (only sprites from namelist are added or replaced) void R_AddSpriteDefs(UINT16 wadnum); +#ifdef ROTSPRITE +void R_CacheRotSprite(spriteframe_t *sprframe, INT32 rot, UINT8 flip); +#endif + //SoM: 6/5/2000: Light sprites correctly! void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); @@ -176,7 +181,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