diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a1f752ed7d540d72ac280aeff28dd4f9c5c0210e..fa09c83246eeb09c7ac68dbac7cece3a1892ae21 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,6 +130,8 @@ set(SRB2_CORE_RENDER_SOURCES r_splats.c r_things.c r_textures.c + r_patch.c + r_patchrotation.c r_picformats.c r_portal.c @@ -147,6 +149,8 @@ set(SRB2_CORE_RENDER_SOURCES r_state.h r_things.h r_textures.h + r_patch.h + r_patchrotation.h r_picformats.h r_portal.h ) @@ -169,6 +173,7 @@ set(SRB2_CORE_GAME_SOURCES p_telept.c p_tick.c p_user.c + taglist.c p_local.h p_maputl.h @@ -180,6 +185,7 @@ set(SRB2_CORE_GAME_SOURCES p_slopes.h p_spec.h p_tick.h + taglist.h ) if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) diff --git a/src/Makefile b/src/Makefile index da918e2057146f2031fce4eec742e85d46e79c3f..fe17846753acfd1017c2f40004d9144d41f9601e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -519,9 +519,12 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ $(OBJDIR)/r_textures.o \ + $(OBJDIR)/r_patch.o \ + $(OBJDIR)/r_patchrotation.o \ $(OBJDIR)/r_picformats.o \ $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ + $(OBJDIR)/taglist.o \ $(OBJDIR)/v_video.o \ $(OBJDIR)/s_sound.o \ $(OBJDIR)/sounds.o \ diff --git a/src/android/i_video.c b/src/android/i_video.c index 18f92955a7e3cba7f6b31ef8f929664a3b700770..bf0decb74118385ff2b776d8d470e5ea3a03a2ba 100644 --- a/src/android/i_video.c +++ b/src/android/i_video.c @@ -9,6 +9,7 @@ #include "utils/Log.h" rendermode_t rendermode = render_soft; +rendermode_t chosenrendermode = render_none; boolean highcolor = false; @@ -52,8 +53,15 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) {} -void VID_CheckGLLoaded(rendermode_t oldrender) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + +void VID_CheckGLLoaded(rendermode_t oldrender) +{ + (void)oldrender; +} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/console.c b/src/console.c index 3eee67bb843e2479c0b86bcd3734288601cb0417..29794d0170e4a578b93a0cc208600ed17a5416c8 100644 --- a/src/console.c +++ b/src/console.c @@ -56,7 +56,8 @@ I_mutex con_mutex; #endif/*HAVE_THREADS*/ static boolean con_started = false; // console has been initialised - boolean con_startup = false; // true at game startup, screen need refreshing + boolean con_startup = false; // true at game startup + boolean con_refresh = false; // screen needs refreshing static boolean con_forcepic = true; // at startup toggle console translucency when first off boolean con_recalc; // set true when screen size has changed @@ -439,7 +440,8 @@ void CON_Init(void) Lock_state(); con_started = true; - con_startup = true; // need explicit screen refresh until we are in Doom loop + con_startup = true; + con_refresh = true; // needs explicit screen refresh until we are in the main game loop consoletoggle = false; Unlock_state(); @@ -457,7 +459,8 @@ void CON_Init(void) Lock_state(); con_started = true; - con_startup = false; // need explicit screen refresh until we are in Doom loop + con_startup = false; + con_refresh = false; // disable explicit screen refresh consoletoggle = true; Unlock_state(); @@ -1438,7 +1441,7 @@ void CONS_Printf(const char *fmt, ...) { va_list argptr; static char *txt = NULL; - boolean startup; + boolean refresh; if (txt == NULL) txt = malloc(8192); @@ -1454,32 +1457,21 @@ void CONS_Printf(const char *fmt, ...) if (con_started) CON_Print(txt); - CON_LogMessage(txt); + CON_LogMessage(txt); Lock_state(); // make sure new text is visible con_scrollup = 0; - startup = con_startup; + refresh = con_refresh; Unlock_state(); // if not in display loop, force screen update - if (startup && (!setrenderneeded)) + if (refresh) { -#ifdef _WINDOWS - patch_t *con_backpic = W_CachePatchName("CONSBACK", PU_PATCH); - - // Jimita: CON_DrawBackpic just called V_DrawScaledPatch - V_DrawScaledPatch(0, 0, 0, con_backpic); - - W_UnlockCachedPatch(con_backpic); - I_LoadingScreen(txt); // Win32/OS2 only -#else - // here we display the console text - CON_Drawer(); + CON_Drawer(); // here we display the console text I_FinishUpdate(); // page flip or blit buffer -#endif } } @@ -1541,7 +1533,7 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) // void CONS_Error(const char *msg) { -#ifdef RPC_NO_WINDOWS_H +#if defined(RPC_NO_WINDOWS_H) && defined(_WINDOWS) if (!graphics_started) { MessageBoxA(vid.WndParent, msg, "SRB2 Warning", MB_OK); @@ -1719,8 +1711,8 @@ static void CON_DrawBackpic(void) if (piclump == LUMPERROR) piclump = W_GetNumForName("MISSING"); - // Cache the Software patch. - con_backpic = W_CacheSoftwarePatchNum(piclump, PU_PATCH); + // Cache the patch. + con_backpic = W_CachePatchNum(piclump, PU_PATCH); // Center the backpic, and draw a vertically cropped patch. w = (con_backpic->width * vid.dupx); @@ -1731,7 +1723,7 @@ static void CON_DrawBackpic(void) // then fill the sides with a solid color. if (x > 0) { - column_t *column = (column_t *)((UINT8 *)(con_backpic) + LONG(con_backpic->columnofs[0])); + column_t *column = (column_t *)((UINT8 *)(con_backpic->columns) + (con_backpic->columnofs[0])); if (!column->topdelta) { UINT8 *source = (UINT8 *)(column) + 3; @@ -1743,8 +1735,7 @@ static void CON_DrawBackpic(void) } } - // Cache the patch normally. - con_backpic = W_CachePatchNum(piclump, PU_PATCH); + // Draw the patch. V_DrawCroppedPatch(x << FRACBITS, 0, FRACUNIT, V_NOSCALESTART, con_backpic, 0, ( BASEVIDHEIGHT - h ), BASEVIDWIDTH, h); @@ -1829,9 +1820,6 @@ void CON_Drawer(void) return; } - if (needpatchrecache) - HU_LoadGraphics(); - if (con_recalc) { CON_RecalcSize(); diff --git a/src/console.h b/src/console.h index c8dd9e3de4485b3ce75eb5b1ecef05237e889f95..0296f4f6e658e82a01d78a2ae05f636d90e411ed 100644 --- a/src/console.h +++ b/src/console.h @@ -25,8 +25,12 @@ extern I_mutex con_mutex; // set true when screen size has changed, to adapt console extern boolean con_recalc; +// console being displayed at game startup extern boolean con_startup; +// needs explicit screen refresh until we are in the main game loop +extern boolean con_refresh; + // top clip value for view render: do not draw part of view hidden by console extern INT32 con_clipviewtop; diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e314d419f46c3250e3436dbca2739a189115f2ad..b198011a0eeff38f0e3936cc7a28b1ce3281554e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -84,6 +84,8 @@ char playeraddress[MAXPLAYERS][64]; // The actual timeout will be longer depending on the savegame length tic_t jointimeout = (10*TICRATE); static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame? +static boolean resendingsavegame[MAXNETNODES]; // Are we resending the savegame? +static tic_t savegameresendcooldown[MAXNETNODES]; // How long before we can resend again? static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout? // Incremented by cv_joindelay when a client joins, decremented each tic. @@ -107,15 +109,8 @@ static tic_t maketic; static INT16 consistancy[BACKUPTICS]; -// Resynching shit! -static UINT32 resynch_score[MAXNETNODES]; // "score" for kicking -- if this gets too high then cfail kick -static UINT16 resynch_delay[MAXNETNODES]; // delay time before the player can be considered to have desynched -static UINT32 resynch_status[MAXNETNODES]; // 0 bit means synched for that player, 1 means possibly desynched -static UINT8 resynch_sent[MAXNETNODES][MAXPLAYERS]; // what synch packets have we attempted to send to the player -static UINT8 resynch_inprogress[MAXNETNODES]; -static UINT8 resynch_local_inprogress = false; // WE are desynched and getting packets to fix it. static UINT8 player_joining = false; -UINT8 hu_resynching = 0; +UINT8 hu_redownloadinggamestate = 0; UINT8 adminpassmd5[16]; boolean adminpasswordset = false; @@ -126,6 +121,7 @@ static ticcmd_t localcmds2; static boolean cl_packetmissed; // here it is for the secondary local player (splitscreen) static UINT8 mynode; // my address pointofview server +static boolean cl_redownloadinggamestate = false; static UINT8 localtextcmd[MAXTEXTCMD]; static UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen @@ -509,603 +505,6 @@ void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum) // end extra data function for lmps // ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// resynch player data -// ----------------------------------------------------------------- -static inline void resynch_write_player(resynch_pak *rsp, const size_t i) -{ - size_t j; - - rsp->playernum = (UINT8)i; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - rsp->playerstate = (UINT8)players[i].playerstate; //playerstate_t - rsp->pflags = (UINT32)LONG(players[i].pflags); //pflags_t - rsp->panim = (UINT8)players[i].panim; //panim_t - - rsp->angleturn = (INT16)SHORT(players[i].angleturn); - rsp->oldrelangleturn = (INT16)SHORT(players[i].oldrelangleturn); - - rsp->aiming = (angle_t)LONG(players[i].aiming); - rsp->currentweapon = LONG(players[i].currentweapon); - rsp->ringweapons = LONG(players[i].ringweapons); - - rsp->ammoremoval = (UINT16)SHORT(players[i].ammoremoval); - rsp->ammoremovaltimer = (tic_t)LONG(players[i].ammoremovaltimer); - rsp->ammoremovalweapon = LONG(players[i].ammoremovalweapon); - - for (j = 0; j < NUMPOWERS; ++j) - rsp->powers[j] = (UINT16)SHORT(players[i].powers[j]); - - // Score is resynched in the rspfirm resync packet - rsp->rings = SHORT(players[i].rings); - rsp->spheres = SHORT(players[i].spheres); - rsp->lives = players[i].lives; - rsp->continues = players[i].continues; - rsp->scoreadd = players[i].scoreadd; - rsp->xtralife = players[i].xtralife; - rsp->pity = players[i].pity; - - rsp->skincolor = players[i].skincolor; - rsp->skin = LONG(players[i].skin); - rsp->availabilities = LONG(players[i].availabilities); - // Just in case Lua does something like - // modify these at runtime - rsp->camerascale = (fixed_t)LONG(players[i].camerascale); - rsp->shieldscale = (fixed_t)LONG(players[i].shieldscale); - rsp->normalspeed = (fixed_t)LONG(players[i].normalspeed); - rsp->runspeed = (fixed_t)LONG(players[i].runspeed); - rsp->thrustfactor = players[i].thrustfactor; - rsp->accelstart = players[i].accelstart; - rsp->acceleration = players[i].acceleration; - rsp->charability = players[i].charability; - rsp->charability2 = players[i].charability2; - rsp->charflags = (UINT32)LONG(players[i].charflags); - rsp->thokitem = (UINT32)LONG(players[i].thokitem); //mobjtype_t - rsp->spinitem = (UINT32)LONG(players[i].spinitem); //mobjtype_t - rsp->revitem = (UINT32)LONG(players[i].revitem); //mobjtype_t - rsp->followitem = (UINT32)LONG(players[i].followitem); //mobjtype_t - rsp->actionspd = (fixed_t)LONG(players[i].actionspd); - rsp->mindash = (fixed_t)LONG(players[i].mindash); - rsp->maxdash = (fixed_t)LONG(players[i].maxdash); - rsp->jumpfactor = (fixed_t)LONG(players[i].jumpfactor); - rsp->playerheight = (fixed_t)LONG(players[i].height); - rsp->playerspinheight = (fixed_t)LONG(players[i].spinheight); - - rsp->speed = (fixed_t)LONG(players[i].speed); - rsp->secondjump = players[i].secondjump; - rsp->fly1 = players[i].fly1; - rsp->glidetime = (tic_t)LONG(players[i].glidetime); - rsp->climbing = players[i].climbing; - rsp->deadtimer = players[i].deadtimer; - rsp->exiting = (tic_t)LONG(players[i].exiting); - rsp->homing = players[i].homing; - rsp->dashmode = (tic_t)LONG(players[i].dashmode); - rsp->skidtime = (tic_t)LONG(players[i].skidtime); - rsp->cmomx = (fixed_t)LONG(players[i].cmomx); - rsp->cmomy = (fixed_t)LONG(players[i].cmomy); - rsp->rmomx = (fixed_t)LONG(players[i].rmomx); - rsp->rmomy = (fixed_t)LONG(players[i].rmomy); - - rsp->weapondelay = LONG(players[i].weapondelay); - rsp->tossdelay = LONG(players[i].tossdelay); - - rsp->starpostx = SHORT(players[i].starpostx); - rsp->starposty = SHORT(players[i].starposty); - rsp->starpostz = SHORT(players[i].starpostz); - rsp->starpostnum = LONG(players[i].starpostnum); - rsp->starposttime = (tic_t)LONG(players[i].starposttime); - rsp->starpostangle = (angle_t)LONG(players[i].starpostangle); - rsp->starpostscale = (fixed_t)LONG(players[i].starpostscale); - - rsp->maxlink = LONG(players[i].maxlink); - rsp->dashspeed = (fixed_t)LONG(players[i].dashspeed); - rsp->angle_pos = (angle_t)LONG(players[i].angle_pos); - rsp->old_angle_pos = (angle_t)LONG(players[i].old_angle_pos); - rsp->bumpertime = (tic_t)LONG(players[i].bumpertime); - rsp->flyangle = LONG(players[i].flyangle); - rsp->drilltimer = (tic_t)LONG(players[i].drilltimer); - rsp->linkcount = LONG(players[i].linkcount); - rsp->linktimer = (tic_t)LONG(players[i].linktimer); - rsp->anotherflyangle = LONG(players[i].anotherflyangle); - rsp->nightstime = (tic_t)LONG(players[i].nightstime); - rsp->drillmeter = LONG(players[i].drillmeter); - rsp->drilldelay = players[i].drilldelay; - rsp->bonustime = players[i].bonustime; - rsp->mare = players[i].mare; - rsp->lastsidehit = SHORT(players[i].lastsidehit); - rsp->lastlinehit = SHORT(players[i].lastlinehit); - - rsp->losstime = (tic_t)LONG(players[i].losstime); - rsp->timeshit = players[i].timeshit; - rsp->onconveyor = LONG(players[i].onconveyor); - - rsp->hasmo = false; - //Transfer important mo information if the player has a body. - //This lets us resync players even if they are dead. - if (!players[i].mo) - return; - rsp->hasmo = true; - - rsp->health = LONG(players[i].mo->health); - rsp->angle = (angle_t)LONG(players[i].mo->angle); - rsp->rollangle = (angle_t)LONG(players[i].mo->rollangle); - rsp->x = LONG(players[i].mo->x); - rsp->y = LONG(players[i].mo->y); - rsp->z = LONG(players[i].mo->z); - rsp->momx = LONG(players[i].mo->momx); - rsp->momy = LONG(players[i].mo->momy); - rsp->momz = LONG(players[i].mo->momz); - rsp->friction = LONG(players[i].mo->friction); - rsp->movefactor = LONG(players[i].mo->movefactor); - - rsp->sprite = (spritenum_t)LONG(players[i].mo->sprite); - rsp->frame = LONG(players[i].mo->frame); - rsp->sprite2 = players[i].mo->sprite2; - rsp->anim_duration = SHORT(players[i].mo->anim_duration); - rsp->tics = LONG(players[i].mo->tics); - rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :( - rsp->eflags = (UINT16)SHORT(players[i].mo->eflags); - rsp->flags = LONG(players[i].mo->flags); - rsp->flags2 = LONG(players[i].mo->flags2); - - rsp->radius = LONG(players[i].mo->radius); - rsp->height = LONG(players[i].mo->height); - rsp->scale = LONG(players[i].mo->scale); - rsp->destscale = LONG(players[i].mo->destscale); - rsp->scalespeed = LONG(players[i].mo->scalespeed); -} - -static void resynch_read_player(resynch_pak *rsp) -{ - INT32 i = rsp->playernum, j; - mobj_t *savedmo = players[i].mo; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - players[i].playerstate = (UINT8)rsp->playerstate; //playerstate_t - players[i].pflags = (UINT32)LONG(rsp->pflags); //pflags_t - players[i].panim = (UINT8)rsp->panim; //panim_t - - players[i].angleturn = (INT16)SHORT(rsp->angleturn); - players[i].oldrelangleturn = (INT16)SHORT(rsp->oldrelangleturn); - - players[i].aiming = (angle_t)LONG(rsp->aiming); - players[i].currentweapon = LONG(rsp->currentweapon); - players[i].ringweapons = LONG(rsp->ringweapons); - - players[i].ammoremoval = (UINT16)SHORT(rsp->ammoremoval); - players[i].ammoremovaltimer = (tic_t)LONG(rsp->ammoremovaltimer); - players[i].ammoremovalweapon = LONG(rsp->ammoremovalweapon); - - for (j = 0; j < NUMPOWERS; ++j) - players[i].powers[j] = (UINT16)SHORT(rsp->powers[j]); - - // Score is resynched in the rspfirm resync packet - players[i].rings = SHORT(rsp->rings); - players[i].spheres = SHORT(rsp->spheres); - players[i].lives = rsp->lives; - players[i].continues = rsp->continues; - players[i].scoreadd = rsp->scoreadd; - players[i].xtralife = rsp->xtralife; - players[i].pity = rsp->pity; - - players[i].skincolor = rsp->skincolor; - players[i].skin = LONG(rsp->skin); - players[i].availabilities = LONG(rsp->availabilities); - // Just in case Lua does something like - // modify these at runtime - players[i].camerascale = (fixed_t)LONG(rsp->camerascale); - players[i].shieldscale = (fixed_t)LONG(rsp->shieldscale); - players[i].normalspeed = (fixed_t)LONG(rsp->normalspeed); - players[i].runspeed = (fixed_t)LONG(rsp->runspeed); - players[i].thrustfactor = rsp->thrustfactor; - players[i].accelstart = rsp->accelstart; - players[i].acceleration = rsp->acceleration; - players[i].charability = rsp->charability; - players[i].charability2 = rsp->charability2; - players[i].charflags = (UINT32)LONG(rsp->charflags); - players[i].thokitem = (UINT32)LONG(rsp->thokitem); //mobjtype_t - players[i].spinitem = (UINT32)LONG(rsp->spinitem); //mobjtype_t - players[i].revitem = (UINT32)LONG(rsp->revitem); //mobjtype_t - players[i].followitem = (UINT32)LONG(rsp->followitem); //mobjtype_t - players[i].actionspd = (fixed_t)LONG(rsp->actionspd); - players[i].mindash = (fixed_t)LONG(rsp->mindash); - players[i].maxdash = (fixed_t)LONG(rsp->maxdash); - players[i].jumpfactor = (fixed_t)LONG(rsp->jumpfactor); - players[i].height = (fixed_t)LONG(rsp->playerheight); - players[i].spinheight = (fixed_t)LONG(rsp->playerspinheight); - - players[i].speed = (fixed_t)LONG(rsp->speed); - players[i].secondjump = rsp->secondjump; - players[i].fly1 = rsp->fly1; - players[i].glidetime = (tic_t)LONG(rsp->glidetime); - players[i].climbing = rsp->climbing; - players[i].deadtimer = rsp->deadtimer; - players[i].exiting = (tic_t)LONG(rsp->exiting); - players[i].homing = rsp->homing; - players[i].dashmode = (tic_t)LONG(rsp->dashmode); - players[i].skidtime = (tic_t)LONG(rsp->skidtime); - players[i].cmomx = (fixed_t)LONG(rsp->cmomx); - players[i].cmomy = (fixed_t)LONG(rsp->cmomy); - players[i].rmomx = (fixed_t)LONG(rsp->rmomx); - players[i].rmomy = (fixed_t)LONG(rsp->rmomy); - - players[i].weapondelay = LONG(rsp->weapondelay); - players[i].tossdelay = LONG(rsp->tossdelay); - - players[i].starpostx = SHORT(rsp->starpostx); - players[i].starposty = SHORT(rsp->starposty); - players[i].starpostz = SHORT(rsp->starpostz); - players[i].starpostnum = LONG(rsp->starpostnum); - players[i].starposttime = (tic_t)LONG(rsp->starposttime); - players[i].starpostangle = (angle_t)LONG(rsp->starpostangle); - players[i].starpostscale = (fixed_t)LONG(rsp->starpostscale); - - players[i].maxlink = LONG(rsp->maxlink); - players[i].dashspeed = (fixed_t)LONG(rsp->dashspeed); - players[i].angle_pos = (angle_t)LONG(rsp->angle_pos); - players[i].old_angle_pos = (angle_t)LONG(rsp->old_angle_pos); - players[i].bumpertime = (tic_t)LONG(rsp->bumpertime); - players[i].flyangle = LONG(rsp->flyangle); - players[i].drilltimer = (tic_t)LONG(rsp->drilltimer); - players[i].linkcount = LONG(rsp->linkcount); - players[i].linktimer = (tic_t)LONG(rsp->linktimer); - players[i].anotherflyangle = LONG(rsp->anotherflyangle); - players[i].nightstime = (tic_t)LONG(rsp->nightstime); - players[i].drillmeter = LONG(rsp->drillmeter); - players[i].drilldelay = rsp->drilldelay; - players[i].bonustime = rsp->bonustime; - players[i].mare = rsp->mare; - players[i].lastsidehit = SHORT(rsp->lastsidehit); - players[i].lastlinehit = SHORT(rsp->lastlinehit); - - players[i].losstime = (tic_t)LONG(rsp->losstime); - players[i].timeshit = rsp->timeshit; - players[i].onconveyor = LONG(rsp->onconveyor); - - //We get a packet for each player in game. - if (!playeringame[i]) - return; - - //...but keep old mo even if it is corrupt or null! - players[i].mo = savedmo; - - //Transfer important mo information if they have a valid mo. - if (!rsp->hasmo) - return; - - //server thinks player has a body. - //Give them a new body that can be then manipulated by the server's info. - if (!players[i].mo) //client thinks it has no body. - P_SpawnPlayer(i); - - //At this point, the player should have a body, whether they were respawned or not. - P_UnsetThingPosition(players[i].mo); - players[i].mo->angle = (angle_t)LONG(rsp->angle); - players[i].mo->rollangle = (angle_t)LONG(rsp->rollangle); - players[i].mo->eflags = (UINT16)SHORT(rsp->eflags); - players[i].mo->flags = LONG(rsp->flags); - players[i].mo->flags2 = LONG(rsp->flags2); - players[i].mo->friction = LONG(rsp->friction); - players[i].mo->health = LONG(rsp->health); - players[i].mo->momx = LONG(rsp->momx); - players[i].mo->momy = LONG(rsp->momy); - players[i].mo->momz = LONG(rsp->momz); - players[i].mo->movefactor = LONG(rsp->movefactor); - - // Don't use P_SetMobjStateNF to restore state, write/read all the values manually! - // This should stop those stupid console errors, hopefully. - // -- Monster Iestyn - players[i].mo->sprite = (spritenum_t)LONG(rsp->sprite); - players[i].mo->frame = LONG(rsp->frame); - players[i].mo->sprite2 = rsp->sprite2; - players[i].mo->anim_duration = SHORT(rsp->anim_duration); - players[i].mo->tics = LONG(rsp->tics); - players[i].mo->state = &states[LONG(rsp->statenum)]; - - players[i].mo->x = LONG(rsp->x); - players[i].mo->y = LONG(rsp->y); - players[i].mo->z = LONG(rsp->z); - players[i].mo->radius = LONG(rsp->radius); - players[i].mo->height = LONG(rsp->height); - // P_SetScale is redundant for this, as all related variables are already restored properly. - players[i].mo->scale = LONG(rsp->scale); - players[i].mo->destscale = LONG(rsp->destscale); - 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_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 - } - else - { - players[i].mo->skin = &skins[players[i].skin]; - players[i].mo->color = players[i].skincolor; // this will be corrected by thinker to super flash/mario star - } - - P_SetThingPosition(players[i].mo); -} - -static inline void resynch_write_ctf(resynchend_pak *rst) -{ - mobj_t *mflag; - UINT8 i, j; - - for (i = 0, mflag = redflag; i < 2; ++i, mflag = blueflag) - { - rst->flagx[i] = rst->flagy[i] = rst->flagz[i] = 0; - rst->flagloose[i] = rst->flagflags[i] = 0; - rst->flagplayer[i] = -1; - - if (!mflag) - { - // Should be held by a player - for (j = 0; j < MAXPLAYERS; ++j) - { - // GF_REDFLAG is 1, GF_BLUEFLAG is 2 - // redflag handling is i=0, blueflag is i=1 - // so check for gotflag == (i+1) - if (!playeringame[j] || players[j].gotflag != (i+1)) - continue; - rst->flagplayer[i] = (SINT8)j; - break; - } - if (j == MAXPLAYERS) // fine, no I_Error - { - CONS_Alert(CONS_ERROR, "One of the flags has gone completely missing...\n"); - rst->flagplayer[i] = -2; - } - continue; - } - - rst->flagx[i] = (fixed_t)LONG(mflag->x); - rst->flagy[i] = (fixed_t)LONG(mflag->y); - rst->flagz[i] = (fixed_t)LONG(mflag->z); - rst->flagflags[i] = LONG(mflag->flags2); - rst->flagloose[i] = LONG(mflag->fuse); // Dropped or not? - } -} - -static inline void resynch_read_ctf(resynchend_pak *p) -{ - UINT8 i; - - for (i = 0; i < MAXPLAYERS; ++i) - players[i].gotflag = 0; - - // Red flag - if (p->flagplayer[0] == -2) - ; // The server doesn't even know what happened to it... - else if (p->flagplayer[0] != -1) // Held by a player - { - if (!playeringame[p->flagplayer[0]]) - I_Error("Invalid red flag player %d who isn't in the game!", (INT32)p->flagplayer[0]); - players[p->flagplayer[0]].gotflag = GF_REDFLAG; - if (redflag) - { - P_RemoveMobj(redflag); - redflag = NULL; - } - } - else - { - if (!redflag) - redflag = P_SpawnMobj(0,0,0,MT_REDFLAG); - - P_UnsetThingPosition(redflag); - redflag->x = (fixed_t)LONG(p->flagx[0]); - redflag->y = (fixed_t)LONG(p->flagy[0]); - redflag->z = (fixed_t)LONG(p->flagz[0]); - redflag->flags2 = LONG(p->flagflags[0]); - redflag->fuse = LONG(p->flagloose[0]); - P_SetThingPosition(redflag); - } - - // Blue flag - if (p->flagplayer[1] == -2) - ; // The server doesn't even know what happened to it... - else if (p->flagplayer[1] != -1) // Held by a player - { - if (!playeringame[p->flagplayer[1]]) - I_Error("Invalid blue flag player %d who isn't in the game!", (INT32)p->flagplayer[1]); - players[p->flagplayer[1]].gotflag = GF_BLUEFLAG; - if (blueflag) - { - P_RemoveMobj(blueflag); - blueflag = NULL; - } - } - else - { - if (!blueflag) - blueflag = P_SpawnMobj(0,0,0,MT_BLUEFLAG); - - P_UnsetThingPosition(blueflag); - blueflag->x = (fixed_t)LONG(p->flagx[1]); - blueflag->y = (fixed_t)LONG(p->flagy[1]); - blueflag->z = (fixed_t)LONG(p->flagz[1]); - blueflag->flags2 = LONG(p->flagflags[1]); - blueflag->fuse = LONG(p->flagloose[1]); - P_SetThingPosition(blueflag); - } -} - -static inline void resynch_write_others(resynchend_pak *rst) -{ - UINT8 i; - - rst->ingame = 0; - rst->outofcoop = 0; - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) - { - rst->ctfteam[i] = 0; - rst->score[i] = 0; - rst->numboxes[i] = 0; - rst->totalring[i] = 0; - rst->realtime[i] = 0; - rst->laps[i] = 0; - continue; - } - - if (!players[i].spectator) - rst->ingame |= (1<<i); - if (players[i].outofcoop) - rst->outofcoop |= (1<<i); - rst->ctfteam[i] = (INT32)LONG(players[i].ctfteam); - rst->score[i] = (UINT32)LONG(players[i].score); - rst->numboxes[i] = SHORT(players[i].numboxes); - rst->totalring[i] = SHORT(players[i].totalring); - rst->realtime[i] = (tic_t)LONG(players[i].realtime); - rst->laps[i] = players[i].laps; - } - - // endian safeness - rst->ingame = (UINT32)LONG(rst->ingame); -} - -static inline void resynch_read_others(resynchend_pak *p) -{ - UINT8 i; - UINT32 loc_ingame = (UINT32)LONG(p->ingame); - UINT32 loc_outofcoop = (UINT32)LONG(p->outofcoop); - - for (i = 0; i < MAXPLAYERS; ++i) - { - // We don't care if they're in the game or not, just write all the data. - players[i].spectator = !(loc_ingame & (1<<i)); - players[i].outofcoop = (loc_outofcoop & (1<<i)); - players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match - players[i].score = (UINT32)LONG(p->score[i]); - players[i].numboxes = SHORT(p->numboxes[i]); - players[i].totalring = SHORT(p->totalring[i]); - players[i].realtime = (tic_t)LONG(p->realtime[i]); - players[i].laps = p->laps[i]; - } -} - -static void SV_InitResynchVars(INT32 node) -{ - resynch_delay[node] = TICRATE; // initial one second delay - resynch_score[node] = 0; // clean slate - resynch_status[node] = 0x00; - resynch_inprogress[node] = false; - memset(resynch_sent[node], 0, MAXPLAYERS); -} - -static void SV_RequireResynch(INT32 node) -{ - INT32 i; - - resynch_delay[node] = 10; // Delay before you can fail sync again - resynch_score[node] += 200; // Add score for initial desynch - resynch_status[node] = 0xFFFFFFFF; // No players assumed synched - resynch_inprogress[node] = true; // so we know to send a PT_RESYNCHEND after sync - - // Initial setup - memset(resynch_sent[node], 0, MAXPLAYERS); - for (i = 0; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) // Player not in game so just drop it from required synch - resynch_status[node] &= ~(1<<i); - else if (playernode[i] == node); // instantly update THEIR position - else // Send at random times based on num players - resynch_sent[node][i] = M_RandomKey(D_NumPlayers()>>1)+1; - } -} - -static void SV_SendResynch(INT32 node) -{ - INT32 i, j; - - if (!nodeingame[node]) - { - // player left during resynch - // so obviously we don't need to do any of this anymore - resynch_inprogress[node] = false; - return; - } - - // resynched? - if (!resynch_status[node]) - { - // you are now synched - resynch_inprogress[node] = false; - - netbuffer->packettype = PT_RESYNCHEND; - - netbuffer->u.resynchend.randomseed = P_GetRandSeed(); - if (gametyperules & GTR_TEAMFLAGS) - resynch_write_ctf(&netbuffer->u.resynchend); - resynch_write_others(&netbuffer->u.resynchend); - - HSendPacket(node, true, 0, (sizeof(resynchend_pak))); - return; - } - - netbuffer->packettype = PT_RESYNCHING; - for (i = 0, j = 0; i < MAXPLAYERS; ++i) - { - // if already synched don't bother - if (!(resynch_status[node] & 1<<i)) - continue; - - // waiting for a reply or just waiting in general - if (resynch_sent[node][i]) - { - --resynch_sent[node][i]; - continue; - } - - resynch_write_player(&netbuffer->u.resynchpak, i); - HSendPacket(node, false, 0, (sizeof(resynch_pak))); - - resynch_sent[node][i] = TICRATE; - resynch_score[node] += 2; // penalty for send - - if (++j > 3) - break; - } - - if (resynch_score[node] > (unsigned)cv_resynchattempts.value*250) - { - SendKick(nodetoplayer[node], KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - resynch_score[node] = 0; - } -} - -static void CL_AcknowledgeResynch(resynch_pak *rsp) -{ - resynch_read_player(rsp); - - netbuffer->packettype = PT_RESYNCHGET; - netbuffer->u.resynchgot = rsp->playernum; - HSendPacket(servernode, true, 0, sizeof(UINT8)); -} - -static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg) -{ - if (rsg >= MAXPLAYERS) - resynch_score[node] += 16384; // lol. - else - { - resynch_status[node] &= ~(1<<rsg); - --resynch_score[node]; // unpenalize - } - - // Don't let resynch cause a timeout - freezetimeout[node] = I_GetTime() + connectiontimeout; -} -// ----------------------------------------------------------------- -// end resynch -// ----------------------------------------------------------------- - static INT16 Consistancy(void); typedef enum @@ -1123,40 +522,6 @@ static void GetPackets(void); static cl_mode_t cl_mode = CL_SEARCHING; -// Player name send/load - -static void CV_SavePlayerNames(UINT8 **p) -{ - INT32 i = 0; - // Players in game only. - for (; i < MAXPLAYERS; ++i) - { - if (!playeringame[i]) - { - WRITEUINT8(*p, 0); - continue; - } - WRITESTRING(*p, player_names[i]); - } -} - -static void CV_LoadPlayerNames(UINT8 **p) -{ - INT32 i = 0; - char tmp_name[MAXPLAYERNAME+1]; - tmp_name[MAXPLAYERNAME] = 0; - - for (; i < MAXPLAYERS; ++i) - { - READSTRING(*p, tmp_name); - if (tmp_name[0] == 0) - continue; - if (tmp_name[MAXPLAYERNAME]) // overflow detected - I_Error("Received bad server config packet when trying to join"); - memcpy(player_names[i], tmp_name, MAXPLAYERNAME+1); - } -} - #ifndef NONET #define SNAKE_SPEED 5 @@ -1975,8 +1340,6 @@ static void SV_SendPlayerInfo(INT32 node) */ static boolean SV_SendServerConfig(INT32 node) { - INT32 i; - UINT8 *p, *op; boolean waspacketsent; netbuffer->packettype = PT_SERVERCFG; @@ -1992,32 +1355,10 @@ static boolean SV_SendServerConfig(INT32 node) netbuffer->u.servercfg.gametype = (UINT8)gametype; netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame; - // we fill these structs with FFs so that any players not in game get sent as 0xFFFF - // which is nice and easy for us to detect - memset(netbuffer->u.servercfg.playerskins, 0xFF, sizeof(netbuffer->u.servercfg.playerskins)); - memset(netbuffer->u.servercfg.playercolor, 0xFF, sizeof(netbuffer->u.servercfg.playercolor)); - memset(netbuffer->u.servercfg.playeravailabilities, 0xFF, sizeof(netbuffer->u.servercfg.playeravailabilities)); - - memset(netbuffer->u.servercfg.adminplayers, -1, sizeof(netbuffer->u.servercfg.adminplayers)); - - for (i = 0; i < MAXPLAYERS; i++) - { - netbuffer->u.servercfg.adminplayers[i] = (SINT8)adminplayers[i]; - - if (!playeringame[i]) - continue; - netbuffer->u.servercfg.playerskins[i] = (UINT8)players[i].skin; - netbuffer->u.servercfg.playercolor[i] = (UINT16)players[i].skincolor; - netbuffer->u.servercfg.playeravailabilities[i] = (UINT32)LONG(players[i].availabilities); - } - memcpy(netbuffer->u.servercfg.server_context, server_context, 8); - op = p = netbuffer->u.servercfg.varlengthinputs; - CV_SavePlayerNames(&p); - CV_SaveNetVars(&p); { - const size_t len = sizeof (serverconfig_pak) + (size_t)(p - op); + const size_t len = sizeof (serverconfig_pak); #ifdef DEBUGFILE if (debugfile) @@ -2050,7 +1391,17 @@ static boolean SV_SendServerConfig(INT32 node) #ifndef NONET #define SAVEGAMESIZE (768*1024) -static void SV_SendSaveGame(INT32 node) +static boolean SV_ResendingSavegameToAnyone(void) +{ + INT32 i; + + for (i = 0; i < MAXNETNODES; i++) + if (resendingsavegame[i]) + return true; + return false; +} + +static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; UINT8 *savebuffer; @@ -2068,7 +1419,7 @@ static void SV_SendSaveGame(INT32 node) // Leave room for the uncompressed length. save_p = savebuffer + sizeof(UINT32); - P_SaveNetGame(); + P_SaveNetGame(resending); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -2141,7 +1492,7 @@ static void SV_SavedGame(void) return; } - P_SaveNetGame(); + P_SaveNetGame(false); length = save_p - savebuffer; if (length > SAVEGAMESIZE) @@ -2164,7 +1515,7 @@ static void SV_SavedGame(void) #define TMPSAVENAME "$$$.sav" -static void CL_LoadReceivedSavegame(void) +static void CL_LoadReceivedSavegame(boolean reloading) { UINT8 *savebuffer = NULL; size_t length, decompressedlen; @@ -2200,7 +1551,7 @@ static void CL_LoadReceivedSavegame(void) automapactive = false; // load a base level - if (P_LoadNetGame()) + if (P_LoadNetGame(reloading)) { const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); @@ -2231,6 +1582,45 @@ static void CL_LoadReceivedSavegame(void) CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); consistancy[gametic%BACKUPTICS] = Consistancy(); CON_ToggleOff(); + + // Tell the server we have received and reloaded the gamestate + // so they know they can resume the game + netbuffer->packettype = PT_RECEIVEDGAMESTATE; + HSendPacket(servernode, true, 0, 0); +} + +static void CL_ReloadReceivedSavegame(void) +{ + INT32 i; + + for (i = 0; i < MAXPLAYERS; i++) + { +#ifdef HAVE_BLUA + LUA_InvalidatePlayer(&players[i]); +#endif + sprintf(player_names[i], "Player %d", i + 1); + } + + CL_LoadReceivedSavegame(true); + + if (neededtic < gametic) + neededtic = gametic; + maketic = neededtic; + + ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn; + P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16)); + if (splitscreen) + { + ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn; + P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16)); + } + + camera.subsector = R_PointInSubsector(camera.x, camera.y); + camera2.subsector = R_PointInSubsector(camera2.x, camera2.y); + + cl_redownloadinggamestate = false; + + CONS_Printf(M_GetText("Game state reloaded\n")); } #endif @@ -2648,7 +2038,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic if (fileneeded[0].status == FS_FOUND) { // Gamestate is now handled within CL_LoadReceivedSavegame() - CL_LoadReceivedSavegame(); + CL_LoadReceivedSavegame(false); cl_mode = CL_CONNECTED; } // don't break case continue to CL_CONNECTED else @@ -3111,10 +2501,14 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } count--; - spheres = players[playernum].spheres; - rings = players[playernum].rings; - sincrement = spheres/count; - rincrement = rings/count; + sincrement = spheres = players[playernum].spheres; + rincrement = rings = players[playernum].rings; + + if (count) + { + sincrement /= count; + rincrement /= count; + } for (i = 0; i < MAXPLAYERS; i++) { @@ -3204,7 +2598,6 @@ void CL_Reset(void) multiplayer = false; servernode = 0; server = true; - resynch_local_inprogress = false; doomcom->numnodes = 1; doomcom->numslots = 1; SV_StopServer(); @@ -3676,6 +3069,34 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum) CL_RemovePlayer(pnum, kickreason); } +static void Command_ResendGamestate(void) +{ + SINT8 playernum; + + if (COM_Argc() == 1) + { + CONS_Printf(M_GetText("resendgamestate <playername/playernum>: resend the game state to a player\n")); + return; + } + else if (client) + { + CONS_Printf(M_GetText("Only the server can use this.\n")); + return; + } + + playernum = nametonum(COM_Argv(1)); + if (playernum == -1 || playernum == 0) + return; + + // Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + if (!HSendPacket(playernode[playernum], true, 0, 0)) + { + CONS_Alert(CONS_ERROR, M_GetText("A problem occured, please try again.\n")); + return; + } +} + static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}}; consvar_t cv_netticbuffer = CVAR_INIT ("netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL); @@ -3719,6 +3140,7 @@ void D_ClientServerInit(void) COM_AddCommand("reloadbans", Command_ReloadBan); COM_AddCommand("connect", Command_connect); COM_AddCommand("nodes", Command_Nodes); + COM_AddCommand("resendgamestate", Command_ResendGamestate); #ifdef PACKETDROP COM_AddCommand("drop", Command_Drop); COM_AddCommand("droprate", Command_Droprate); @@ -3750,14 +3172,18 @@ void D_ClientServerInit(void) static void ResetNode(INT32 node) { nodeingame[node] = false; - nodetoplayer[node] = -1; - nodetoplayer2[node] = -1; + nodewaiting[node] = 0; + nettics[node] = gametic; supposedtics[node] = gametic; - nodewaiting[node] = 0; + + nodetoplayer[node] = -1; + nodetoplayer2[node] = -1; playerpernode[node] = 0; + sendingsavegame[node] = false; - SV_InitResynchVars(node); + resendingsavegame[node] = false; + savegameresendcooldown[node] = 0; } void SV_ResetServer(void) @@ -3791,6 +3217,7 @@ void SV_ResetServer(void) mynode = 0; cl_packetmissed = false; + cl_redownloadinggamestate = false; if (dedicated) { @@ -4260,12 +3687,6 @@ static void HandleConnect(SINT8 node) #endif SV_AddNode(node); - /// \note Wait what??? - /// What if the gamestate takes more than one second to get downloaded? - /// Or if a lagspike happens? - // you get a free second before desynch checks. use it wisely. - SV_InitResynchVars(node); - if (cv_joinnextround.value && gameaction == ga_nothing) G_SetGamestate(GS_WAITINGPLAYERS); if (!SV_SendServerConfig(node)) @@ -4287,7 +3708,7 @@ static void HandleConnect(SINT8 node) { if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) && newnode) { - SV_SendSaveGame(node); // send a complete game state + SV_SendSaveGame(node, false); // send a complete game state DEBFILE("send savegame\n"); } SV_AddWaitingPlayers(names[0], names[1]); @@ -4354,6 +3775,43 @@ static void HandleServerInfo(SINT8 node) } #endif +static void PT_WillResendGamestate(void) +{ + char tmpsave[256]; + + if (server || cl_redownloadinggamestate) + return; + + // Send back a PT_CANRECEIVEGAMESTATE packet to the server + // so they know they can start sending the game state + netbuffer->packettype = PT_CANRECEIVEGAMESTATE; + if (!HSendPacket(servernode, true, 0, 0)) + return; + + CONS_Printf(M_GetText("Reloading game state...\n")); + + sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); + + // Don't get a corrupt savegame error because tmpsave already exists + if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1) + I_Error("Can't delete %s\n", tmpsave); + + CL_PrepareDownloadSaveGame(tmpsave); + + cl_redownloadinggamestate = true; +} + +static void PT_CanReceiveGamestate(SINT8 node) +{ + if (client || sendingsavegame[node]) + return; + + CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[nodetoplayer[node]]); + + SV_SendSaveGame(node, true); // Resend a complete game state + resendingsavegame[node] = true; +} + /** Handles a packet received from a node that isn't in game * * \param node The packet sender @@ -4444,9 +3902,6 @@ static void HandlePacketFromAwayNode(SINT8 node) case PT_SERVERCFG: // Positive response of client join request { - INT32 j; - UINT8 *scp; - if (server && serverrunning && node != servernode) { // but wait I thought I'm the server? Net_CloseConnection(node); @@ -4462,8 +3917,6 @@ static void HandlePacketFromAwayNode(SINT8 node) maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic); G_SetGametype(netbuffer->u.servercfg.gametype); modifiedgame = netbuffer->u.servercfg.modifiedgame; - for (j = 0; j < MAXPLAYERS; j++) - adminplayers[j] = netbuffer->u.servercfg.adminplayers[j]; memcpy(server_context, netbuffer->u.servercfg.server_context, 8); } @@ -4482,23 +3935,6 @@ static void HandlePacketFromAwayNode(SINT8 node) #endif DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode)); - memset(playeringame, 0, sizeof(playeringame)); - for (j = 0; j < MAXPLAYERS; j++) - { - if (netbuffer->u.servercfg.playerskins[j] == 0xFF - && netbuffer->u.servercfg.playercolor[j] == 0xFFFF - && netbuffer->u.servercfg.playeravailabilities[j] == 0xFFFFFFFF) - continue; // not in game - - playeringame[j] = true; - players[j].availabilities = (UINT32)LONG(netbuffer->u.servercfg.playeravailabilities[j]); - SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]); - players[j].skincolor = netbuffer->u.servercfg.playercolor[j]; - } - - scp = netbuffer->u.servercfg.varlengthinputs; - CV_LoadPlayerNames(&scp); - CV_LoadNetVars(&scp); #ifndef NONET /// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook? /// Shouldn't them be downloaded even at intermission time? @@ -4598,11 +4034,6 @@ static void HandlePacketFromPlayer(SINT8 node) switch (netbuffer->packettype) { // -------------------------------------------- SERVER RECEIVE ---------- - case PT_RESYNCHGET: - if (client) - break; - SV_AcknowledgeResynchAck(node, netbuffer->u.resynchgot); - break; case PT_CLIENTCMD: case PT_CLIENT2CMD: case PT_CLIENTMIS: @@ -4612,10 +4043,6 @@ static void HandlePacketFromPlayer(SINT8 node) if (client) break; - // Ignore tics from those not synched - if (resynch_inprogress[node] && nettics[node] == gametic) - break; - // To save bytes, only the low byte of tic numbers are sent // Use ExpandTics to figure out what the rest of the bytes are realstart = ExpandTics(netbuffer->u.clientpak.client_tic, node); @@ -4642,9 +4069,6 @@ static void HandlePacketFromPlayer(SINT8 node) || netbuffer->packettype == PT_NODEKEEPALIVEMIS) break; - // If a client sends a ticcmd it should mean they are done receiving the savegame - sendingsavegame[node] = false; - // As long as clients send valid ticcmds, the server can keep running, so reset the timeout /// \todo Use a separate cvar for that kind of timeout? freezetimeout[node] = I_GetTime() + connectiontimeout; @@ -4669,21 +4093,20 @@ static void HandlePacketFromPlayer(SINT8 node) G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); - // A delay before we check resynching - // Used on join or just after a synch fail - if (resynch_delay[node]) - { - --resynch_delay[node]; - break; - } // Check player consistancy during the level - if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL - && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy)) + if (realstart <= gametic && realstart + BACKUPTICS - 1 > gametic && gamestate == GS_LEVEL + && consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy) + && !resendingsavegame[node] && savegameresendcooldown[node] <= I_GetTime() + && !SV_ResendingSavegameToAnyone()) { - SV_RequireResynch(node); - - if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250) + if (cv_resynchattempts.value) { + // Tell the client we are about to resend them the gamestate + netbuffer->packettype = PT_WILLRESENDGAMESTATE; + HSendPacket(node, true, 0, 0); + + resendingsavegame[node] = true; + if (cv_blamecfail.value) CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"), netconsole+1, player_names[netconsole], @@ -4703,8 +4126,6 @@ static void HandlePacketFromPlayer(SINT8 node) break; } } - else if (resynch_score[node]) - --resynch_score[node]; break; case PT_TEXTCMD2: // splitscreen special netconsole = nodetoplayer2[node]; @@ -4830,6 +4251,9 @@ static void HandlePacketFromPlayer(SINT8 node) Net_CloseConnection(node); nodeingame[node] = false; break; + case PT_CANRECEIVEGAMESTATE: + PT_CanReceiveGamestate(node); + break; case PT_ASKLUAFILE: if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_ASKED) AddLuaFileToSendQueue(node, luafiletransfers->realfilename); @@ -4838,25 +4262,12 @@ static void HandlePacketFromPlayer(SINT8 node) if (server && luafiletransfers && luafiletransfers->nodestatus[node] == LFTNS_SENDING) SV_HandleLuaFileSent(node); break; -// -------------------------------------------- CLIENT RECEIVE ---------- - case PT_RESYNCHEND: - // Only accept PT_RESYNCHEND from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - resynch_local_inprogress = false; - - P_SetRandSeed(netbuffer->u.resynchend.randomseed); - - if (gametyperules & GTR_TEAMFLAGS) - resynch_read_ctf(&netbuffer->u.resynchend); - resynch_read_others(&netbuffer->u.resynchend); - + case PT_RECEIVEDGAMESTATE: + sendingsavegame[node] = false; + resendingsavegame[node] = false; + savegameresendcooldown[node] = I_GetTime() + 15 * TICRATE; break; +// -------------------------------------------- CLIENT RECEIVE ---------- case PT_SERVERTICS: // Only accept PT_SERVERTICS from the server. if (node != servernode) @@ -4917,18 +4328,6 @@ static void HandlePacketFromPlayer(SINT8 node) "IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/ } break; - case PT_RESYNCHING: - // Only accept PT_RESYNCHING from the server. - if (node != servernode) - { - CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node); - if (server) - SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); - break; - } - resynch_local_inprogress = true; - CL_AcknowledgeResynch(&netbuffer->u.resynchpak); - break; case PT_PING: // Only accept PT_PING from the server. if (node != servernode) @@ -4973,6 +4372,9 @@ static void HandlePacketFromPlayer(SINT8 node) if (server) PT_FileReceived(); break; + case PT_WILLRESENDGAMESTATE: + PT_WillResendGamestate(); + break; case PT_SENDINGLUAFILE: if (client) CL_PrepareDownloadLuaFile(); @@ -5430,7 +4832,7 @@ void TryRunTics(tic_t realtics) if (player_joining) return; - if (neededtic > gametic && !resynch_local_inprogress) + if (neededtic > gametic) { if (advancedemo) { @@ -5596,9 +4998,12 @@ void NetUpdate(void) if (client) { - if (!resynch_local_inprogress) - CL_SendClientCmd(); // Send tic cmd - hu_resynching = resynch_local_inprogress; + // If the client just finished redownloading the game state, load it + if (cl_redownloadinggamestate && fileneeded[0].status == FS_FOUND) + CL_ReloadReceivedSavegame(); + + CL_SendClientCmd(); // Send tic cmd + hu_redownloadinggamestate = cl_redownloadinggamestate; } else { @@ -5606,7 +5011,7 @@ void NetUpdate(void) { INT32 counts; - hu_resynching = false; + hu_redownloadinggamestate = false; firstticstosend = gametic; for (i = 0; i < MAXNETNODES; i++) @@ -5621,36 +5026,18 @@ void NetUpdate(void) // Don't erase tics not acknowledged counts = realtics; - for (i = 0; i < MAXNETNODES; ++i) - if (resynch_inprogress[i]) - { - if (!nodeingame[i] || nettics[i] == gametic) - { - SV_SendResynch(i); - counts = -666; - } - else - counts = 0; // Let the client catch up with the server - } + if (maketic + counts >= firstticstosend + BACKUPTICS) + counts = firstticstosend+BACKUPTICS-maketic-1; - // Do not make tics while resynching - if (counts != -666) - { - if (maketic + counts >= firstticstosend + BACKUPTICS) - counts = firstticstosend+BACKUPTICS-maketic-1; - - for (i = 0; i < counts; i++) - SV_Maketic(); // Create missed tics and increment maketic + for (i = 0; i < counts; i++) + SV_Maketic(); // Create missed tics and increment maketic - for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged - D_Clearticcmd(tictoclear); // Clear the maketic the new tic + for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged + D_Clearticcmd(tictoclear); // Clear the maketic the new tic - SV_SendTics(); + SV_SendTics(); - neededtic = maketic; // The server is a client too - } - else - hu_resynching = true; + neededtic = maketic; // The server is a client too } } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index adc8a7cc9b090cf4bf5d5881f08070bf34ba1093..3d67525dacc65dd6c79d18c544cb7ff9fdffebac 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -64,8 +64,10 @@ typedef enum PT_REQUESTFILE, // Client requests a file transfer PT_ASKINFOVIAMS, // Packet from the MS requesting info be sent to new client. // If this ID changes, update masterserver definition. - PT_RESYNCHEND, // Player is now resynched and is being requested to remake the gametic - PT_RESYNCHGET, // Player got resynch packet + + PT_WILLRESENDGAMESTATE, // Hey Client, I am about to resend you the gamestate! + PT_CANRECEIVEGAMESTATE, // Okay Server, I'm ready to receive it, you can go ahead. + PT_RECEIVEDGAMESTATE, // Thank you Server, I am ready to play again! PT_SENDINGLUAFILE, // Server telling a client Lua needs to open a file PT_ASKLUAFILE, // Client telling the server they don't have the file @@ -85,8 +87,6 @@ typedef enum PT_TEXTCMD2, // Splitscreen text commands. PT_CLIENTJOIN, // Client wants to join; used in start game. PT_NODETIMEOUT, // Packet sent to self if the connection times out. - PT_RESYNCHING, // Packet sent to resync players. - // Blocks game advance until synched. PT_LOGIN, // Login attempt from the client. @@ -139,168 +139,6 @@ typedef struct ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large } ATTRPACK servertics_pak; -// Sent to client when all consistency data -// for players has been restored -typedef struct -{ - UINT32 randomseed; - - // CTF flag stuff - SINT8 flagplayer[2]; - INT32 flagloose[2]; - INT32 flagflags[2]; - fixed_t flagx[2]; - fixed_t flagy[2]; - fixed_t flagz[2]; - - UINT32 ingame; // Spectator bit for each player - UINT32 outofcoop; // outofcoop bit for each player - INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams) - - // Resynch game scores and the like all at once - UINT32 score[MAXPLAYERS]; // Everyone's score - INT16 numboxes[MAXPLAYERS]; - INT16 totalring[MAXPLAYERS]; - tic_t realtime[MAXPLAYERS]; - UINT8 laps[MAXPLAYERS]; -} ATTRPACK resynchend_pak; - -typedef struct -{ - // Player stuff - UINT8 playernum; - - // Do not send anything visual related. - // Only send data that we need to know for physics. - UINT8 playerstate; // playerstate_t - UINT32 pflags; // pflags_t - UINT8 panim; // panim_t - - INT16 angleturn; - INT16 oldrelangleturn; - - angle_t aiming; - INT32 currentweapon; - INT32 ringweapons; - UINT16 ammoremoval; - tic_t ammoremovaltimer; - INT32 ammoremovalweapon; - UINT16 powers[NUMPOWERS]; - - // Score is resynched in the confirm resync packet - INT16 rings; - INT16 spheres; - SINT8 lives; - SINT8 continues; - UINT8 scoreadd; - SINT8 xtralife; - SINT8 pity; - - UINT16 skincolor; - INT32 skin; - UINT32 availabilities; - // Just in case Lua does something like - // modify these at runtime - fixed_t camerascale; - fixed_t shieldscale; - fixed_t normalspeed; - fixed_t runspeed; - UINT8 thrustfactor; - UINT8 accelstart; - UINT8 acceleration; - UINT8 charability; - UINT8 charability2; - UINT32 charflags; - UINT32 thokitem; // mobjtype_t - UINT32 spinitem; // mobjtype_t - UINT32 revitem; // mobjtype_t - UINT32 followitem; // mobjtype_t - fixed_t actionspd; - fixed_t mindash; - fixed_t maxdash; - fixed_t jumpfactor; - fixed_t playerheight; - fixed_t playerspinheight; - - fixed_t speed; - UINT8 secondjump; - UINT8 fly1; - tic_t glidetime; - UINT8 climbing; - INT32 deadtimer; - tic_t exiting; - UINT8 homing; - tic_t dashmode; - tic_t skidtime; - fixed_t cmomx; - fixed_t cmomy; - fixed_t rmomx; - fixed_t rmomy; - - INT32 weapondelay; - INT32 tossdelay; - - INT16 starpostx; - INT16 starposty; - INT16 starpostz; - INT32 starpostnum; - tic_t starposttime; - angle_t starpostangle; - fixed_t starpostscale; - - INT32 maxlink; - fixed_t dashspeed; - angle_t angle_pos; - angle_t old_angle_pos; - tic_t bumpertime; - INT32 flyangle; - tic_t drilltimer; - INT32 linkcount; - tic_t linktimer; - INT32 anotherflyangle; - tic_t nightstime; - INT32 drillmeter; - UINT8 drilldelay; - UINT8 bonustime; - UINT8 mare; - INT16 lastsidehit, lastlinehit; - - tic_t losstime; - UINT8 timeshit; - INT32 onconveyor; - - //player->mo stuff - UINT8 hasmo; // Boolean - - INT32 health; - angle_t angle; - angle_t rollangle; - fixed_t x; - fixed_t y; - fixed_t z; - fixed_t momx; - fixed_t momy; - fixed_t momz; - fixed_t friction; - fixed_t movefactor; - - spritenum_t sprite; - UINT32 frame; - UINT8 sprite2; - UINT16 anim_duration; - INT32 tics; - statenum_t statenum; - UINT32 flags; - UINT32 flags2; - UINT16 eflags; - - fixed_t radius; - fixed_t height; - fixed_t scale; - fixed_t destscale; - fixed_t scalespeed; -} ATTRPACK resynch_pak; - typedef struct { UINT8 version; // Different versions don't work @@ -314,18 +152,10 @@ typedef struct UINT8 clientnode; UINT8 gamestate; - // 0xFF == not in game; else player skin num - UINT8 playerskins[MAXPLAYERS]; - UINT16 playercolor[MAXPLAYERS]; - UINT32 playeravailabilities[MAXPLAYERS]; - UINT8 gametype; UINT8 modifiedgame; - SINT8 adminplayers[MAXPLAYERS]; // Needs to be signed char server_context[8]; // Unique context id, generated at server startup. - - UINT8 varlengthinputs[0]; // Playernames and netvars } ATTRPACK serverconfig_pak; typedef struct @@ -462,9 +292,6 @@ typedef struct client2cmd_pak client2pak; // 200 bytes servertics_pak serverpak; // 132495 bytes (more around 360, no?) serverconfig_pak servercfg; // 773 bytes - resynchend_pak resynchend; // - resynch_pak resynchpak; // - UINT8 resynchgot; // UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) filetx_pak filetxpak; // 139 bytes fileack_pak fileack; @@ -606,7 +433,7 @@ UINT8 GetFreeXCmdSize(void); void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest); -extern UINT8 hu_resynching; +extern UINT8 hu_redownloadinggamestate; extern UINT8 adminpassmd5[16]; extern boolean adminpasswordset; diff --git a/src/d_main.c b/src/d_main.c index ce1331fe3abf12eb1f0a9dfb01d01777ecaf7959..53798d4466ac56ef9e083e50fe78074541e242b3 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -107,8 +107,6 @@ boolean devparm = false; // started game with -devparm boolean singletics = false; // timedemo boolean lastdraw = false; -static void D_CheckRendererState(void); - postimg_t postimgtype = postimg_none; INT32 postimgparam; postimg_t postimgtype2 = postimg_none; @@ -237,7 +235,6 @@ INT16 wipetypepost = -1; static void D_Display(void) { - INT32 setrenderstillneeded = 0; boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; @@ -260,48 +257,28 @@ static void D_Display(void) // create plane polygons, if necessary. // 3. Functions related to switching video // modes (resolution) are called. - // 4. Patch data is freed from memory, - // and recached if necessary. - // 5. The frame is ready to be drawn! - - // stop movie if needs to change renderer - if (setrenderneeded && (moviemode == MM_APNG)) - M_StopMovie(); + // 4. The frame is ready to be drawn! - // check for change of renderer or screen size (video mode) + // Check for change of renderer or screen size (video mode) if ((setrenderneeded || setmodeneeded) && !wipe) - { - if (setrenderneeded) - { - CONS_Debug(DBG_RENDER, "setrenderneeded set (%d)\n", setrenderneeded); - setrenderstillneeded = setrenderneeded; - } SCR_SetMode(); // change video mode - } - if (vid.recalc || setrenderstillneeded) - { + // Recalc the screen + if (vid.recalc) SCR_Recalc(); // NOTE! setsizeneeded is set by SCR_Recalc() -#ifdef HWRENDER - // Shoot! The screen texture was flushed! - if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION)) - usebuffer = false; -#endif - } + // View morph if (rendermode == render_soft && !splitscreen) R_CheckViewMorph(); - // change the view size if needed - if (setsizeneeded || setrenderstillneeded) + // Change the view size if needed + // Set by changing video mode or renderer + if (setsizeneeded) { R_ExecuteSetViewSize(); forcerefresh = true; // force background redraw } - // Lactozilla: Renderer switching - D_CheckRendererState(); - // draw buffered stuff to screen // Used only by linux GGI version I_UpdateNoBlit(); @@ -642,26 +619,6 @@ static void D_Display(void) I_FinishUpdate(); // page flip or blit buffer ps_swaptime = I_GetTimeMicros() - ps_swaptime; } - - needpatchflush = false; - needpatchrecache = false; -} - -// Check the renderer's state -// after a possible renderer switch. -void D_CheckRendererState(void) -{ - // flush all patches from memory - if (needpatchflush) - { - Z_FlushCachedPatches(); - needpatchflush = false; - } - - // some patches have been freed, - // so cache them again - if (needpatchrecache) - R_ReloadHUDGraphics(); } // ========================================================================= @@ -688,6 +645,7 @@ void D_SRB2Loop(void) oldentertics = I_GetTime(); // end of loading screen: CONS_Printf() will no more call FinishUpdate() + con_refresh = false; con_startup = false; // make sure to do a d_display to init mode _before_ load a level @@ -1338,22 +1296,17 @@ void D_SRB2Main(void) // set user default mode or mode set at cmdline SCR_CheckDefaultMode(); - // Lactozilla: Does the render mode need to change? - if ((setrenderneeded != 0) && (setrenderneeded != rendermode)) + // Lactozilla: Check if the render mode needs to change. + if (setrenderneeded) { CONS_Printf(M_GetText("Switching the renderer...\n")); - Z_PreparePatchFlush(); - // set needpatchflush / needpatchrecache true for D_CheckRendererState - needpatchflush = true; - needpatchrecache = true; + // Switch the renderer in the interface + if (VID_CheckRenderer()) + con_refresh = true; // Allow explicit screen refresh again // Set cv_renderer to the new render mode - VID_CheckRenderer(); - SCR_ChangeRendererCVars(rendermode); - - // check the renderer's state - D_CheckRendererState(); + CV_StealthSetValue(&cv_renderer, rendermode); } wipegamestate = gamestate; @@ -1598,7 +1551,7 @@ void D_SRB2Main(void) { levelstarttic = gametic; G_SetGamestate(GS_LEVEL); - if (!P_LoadLevel(false)) + if (!P_LoadLevel(false, false)) I_Quit(); // fail so reset game stuff } } diff --git a/src/d_net.c b/src/d_net.c index 2823ce2191ebcde53dc1c2a21d1a8ff9e03bef08..d534b1b081360da6f7274f33e14cb178c1d2f632 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -798,8 +798,9 @@ static const char *packettypename[NUMPACKETTYPE] = "REQUESTFILE", "ASKINFOVIAMS", - "RESYNCHEND", - "RESYNCHGET", + "WILLRESENDGAMESTATE", + "CANRECEIVEGAMESTATE", + "RECEIVEDGAMESTATE", "SENDINGLUAFILE", "ASKLUAFILE", @@ -813,7 +814,6 @@ static const char *packettypename[NUMPACKETTYPE] = "TEXTCMD2", "CLIENTJOIN", "NODETIMEOUT", - "RESYNCHING", "LOGIN", "PING" }; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 87abd596a1520b1b6088eacb476af290abcefa84..31c10f58a8e0dbe7f709c0ffd98e63772fe175d6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -374,6 +374,7 @@ consvar_t cv_sleep = CVAR_INIT ("cpusleep", "1", CV_SAVE, sleeping_cons_t, NULL) static CV_PossibleValue_t perfstats_cons_t[] = { {0, "Off"}, {1, "Rendering"}, {2, "Logic"}, {3, "ThinkFrame"}, {0, NULL}}; consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL); +consvar_t cv_freedemocamera = CVAR_INIT("freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL); char timedemo_name[256]; boolean timedemo_csv; @@ -675,10 +676,6 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_gif_dynamicdelay); CV_RegisterVar(&cv_gif_localcolortable); -#ifdef WALLSPLATS - CV_RegisterVar(&cv_splats); -#endif - // register these so it is saved to config CV_RegisterVar(&cv_playername); CV_RegisterVar(&cv_playercolor); @@ -880,6 +877,8 @@ void D_RegisterClientCommands(void) // CV_RegisterVar(&cv_grid); // CV_RegisterVar(&cv_snapto); + CV_RegisterVar(&cv_freedemocamera); + // add cheat commands COM_AddCommand("noclip", Command_CheatNoClip_f); COM_AddCommand("god", Command_CheatGod_f); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 841f71acd6692341af29928b117b36699e295080..98d8f142576e46d18dd84a2820a1812b3289d7d6 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -75,9 +75,6 @@ extern consvar_t cv_teamscramble; extern consvar_t cv_scrambleonchange; extern consvar_t cv_netstat; -#ifdef WALLSPLATS -extern consvar_t cv_splats; -#endif extern consvar_t cv_countdowntime; extern consvar_t cv_runscripts; @@ -121,6 +118,8 @@ extern boolean timedemo_csv; extern char timedemo_csv_id[256]; extern boolean timedemo_quit; +extern consvar_t cv_freedemocamera; + typedef enum { XD_NAMEANDCOLOR = 1, diff --git a/src/dehacked.c b/src/dehacked.c index 0380cc30eb86a5d6a543e02227fefb98c5259592..eb8951569600628c05a03333b2b15b9de09fa40c 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -26,11 +26,13 @@ #include "dehacked.h" #include "st_stuff.h" #include "i_system.h" +#include "i_sound.h" // musictype_t (for lua) #include "p_local.h" // for var1 and var2, and some constants #include "p_setup.h" #include "r_data.h" #include "r_textures.h" #include "r_draw.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_things.h" // R_Char2Frame #include "r_sky.h" @@ -1040,11 +1042,6 @@ static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2) 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; @@ -1173,9 +1170,6 @@ static void readspriteinfo(MYFILE *f, INT32 num, boolean sprite2) 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)); } } @@ -9044,6 +9038,7 @@ static const char *const MOBJFLAG2_LIST[] = { "AMBUSH", // Alternate behaviour typically set by MTF_AMBUSH "LINKDRAW", // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) "SHIELD", // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) + "SPLAT", // Object is a splat NULL }; @@ -9588,6 +9583,36 @@ struct { {"tr_trans90",tr_trans90}, {"NUMTRANSMAPS",NUMTRANSMAPS}, + // Alpha styles (blend modes) + {"AST_COPY",AST_COPY}, + {"AST_TRANSLUCENT",AST_TRANSLUCENT}, + {"AST_ADD",AST_ADD}, + {"AST_SUBTRACT",AST_SUBTRACT}, + {"AST_REVERSESUBTRACT",AST_REVERSESUBTRACT}, + {"AST_MODULATE",AST_MODULATE}, + {"AST_OVERLAY",AST_OVERLAY}, + + // Render flags + {"RF_HORIZONTALFLIP",RF_HORIZONTALFLIP}, + {"RF_VERTICALFLIP",RF_VERTICALFLIP}, + {"RF_ABSOLUTEOFFSETS",RF_ABSOLUTEOFFSETS}, + {"RF_FLIPOFFSETS",RF_FLIPOFFSETS}, + {"RF_SPLATMASK",RF_SLOPESPLAT}, + {"RF_SLOPESPLAT",RF_SLOPESPLAT}, + {"RF_OBJECTSLOPESPLAT",RF_OBJECTSLOPESPLAT}, + {"RF_NOSPLATBILLBOARD",RF_NOSPLATBILLBOARD}, + {"RF_NOSPLATROLLANGLE",RF_NOSPLATROLLANGLE}, + {"RF_BLENDMASK",RF_BLENDMASK}, + {"RF_FULLBRIGHT",RF_FULLBRIGHT}, + {"RF_FULLDARK",RF_FULLDARK}, + {"RF_NOCOLORMAPS",RF_NOCOLORMAPS}, + {"RF_SPRITETYPEMASK",RF_SPRITETYPEMASK}, + {"RF_PAPERSPRITE",RF_PAPERSPRITE}, + {"RF_FLOORSPRITE",RF_FLOORSPRITE}, + {"RF_SHADOWDRAW",RF_SHADOWDRAW}, + {"RF_SHADOWEFFECTS",RF_SHADOWEFFECTS}, + {"RF_DROPSHADOW",RF_DROPSHADOW}, + // Level flags {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, {"LF_SPEEDMUSIC",LF_SPEEDMUSIC}, @@ -10108,6 +10133,18 @@ struct { {"MA_NOCUTSCENES",MA_NOCUTSCENES}, {"MA_INGAME",MA_INGAME}, + // music types + {"MU_NONE", MU_NONE}, + {"MU_WAV", MU_WAV}, + {"MU_MOD", MU_MOD}, + {"MU_MID", MU_MID}, + {"MU_OGG", MU_OGG}, + {"MU_MP3", MU_MP3}, + {"MU_FLAC", MU_FLAC}, + {"MU_GME", MU_GME}, + {"MU_MOD_EX", MU_MOD_EX}, + {"MU_MID_EX", MU_MID_EX}, + // gamestates {"GS_NULL",GS_NULL}, {"GS_LEVEL",GS_LEVEL}, diff --git a/src/doomdata.h b/src/doomdata.h index f3890c846536dc438573104f98398bace13f7415..b3f7f5c4dbcc4ea5ce9ee8ff1cdf34a1845cdafa 100644 --- a/src/doomdata.h +++ b/src/doomdata.h @@ -23,6 +23,7 @@ // Some global defines, that configure the game. #include "doomdef.h" +#include "taglist.h" #include "m_fixed.h" // See the mapthing_t scale. // @@ -208,11 +209,10 @@ typedef struct UINT16 options; INT16 z; UINT8 extrainfo; + taglist_t tags; fixed_t scale; - INT16 tag; INT32 args[NUMMAPTHINGARGS]; char *stringargs[NUMMAPTHINGSTRINGARGS]; - struct mobj_s *mobj; } mapthing_t; diff --git a/src/doomdef.h b/src/doomdef.h index b9ee1ce5f59cb7bd3c66beab532256533550687b..d0b7ea0c2391334c703051d02e0dae693dfdfe19 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -628,9 +628,6 @@ extern const char *compdate, *comptime, *comprevision, *compbranch; /// \note Required for proper collision with moving sloped surfaces that have sector specials on them. #define SECTORSPECIALSAFTERTHINK -/// Cache patches in Lua in a way that renderer switching will work flawlessly. -//#define LUA_PATCH_SAFETY - /// Sprite rotation #define ROTSPRITE #define ROTANGLES 72 // Needs to be a divisor of 360 (45, 60, 90, 120...) diff --git a/src/dummy/i_video.c b/src/dummy/i_video.c index 2b0478220eac8119ec36dff4b0b8a05cf92158fc..3b0a12a328df587e1cd20d0312cf96ce6c8df847 100644 --- a/src/dummy/i_video.c +++ b/src/dummy/i_video.c @@ -3,6 +3,7 @@ #include "../i_video.h" rendermode_t rendermode = render_none; +rendermode_t chosenrendermode = render_none; boolean highcolor = false; @@ -40,8 +41,15 @@ INT32 VID_SetMode(INT32 modenum) return 0; } -void VID_CheckRenderer(void) {} -void VID_CheckGLLoaded(rendermode_t oldrender) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + +void VID_CheckGLLoaded(rendermode_t oldrender) +{ + (void)oldrender; +} const char *VID_GetModeName(INT32 modenum) { diff --git a/src/f_finale.c b/src/f_finale.c index d7f81b9df0e7f3f4f31d56e12d84368a457b149b..268bc79f5fd99e685bdf12b75b2e94ff31cab3c2 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -533,78 +533,78 @@ static void F_IntroDrawScene(void) bgxoffs = 28; break; case 1: - background = W_CachePatchName("INTRO1", PU_PATCH); + background = W_CachePatchName("INTRO1", PU_PATCH_LOWPRIORITY); break; case 2: - background = W_CachePatchName("INTRO2", PU_PATCH); + background = W_CachePatchName("INTRO2", PU_PATCH_LOWPRIORITY); break; case 3: - background = W_CachePatchName("INTRO3", PU_PATCH); + background = W_CachePatchName("INTRO3", PU_PATCH_LOWPRIORITY); break; case 4: - background = W_CachePatchName("INTRO4", PU_PATCH); + background = W_CachePatchName("INTRO4", PU_PATCH_LOWPRIORITY); break; case 5: if (intro_curtime >= 5*TICRATE) - background = W_CachePatchName("RADAR", PU_PATCH); + background = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DRAT", PU_PATCH); + background = W_CachePatchName("DRAT", PU_PATCH_LOWPRIORITY); break; case 6: - background = W_CachePatchName("INTRO6", PU_PATCH); + background = W_CachePatchName("INTRO6", PU_PATCH_LOWPRIORITY); cx = 180; cy = 8; break; case 7: { if (intro_curtime >= 7*TICRATE + ((TICRATE/7)*2)) - background = W_CachePatchName("SGRASS5", PU_PATCH); + background = W_CachePatchName("SGRASS5", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 7*TICRATE + (TICRATE/7)) - background = W_CachePatchName("SGRASS4", PU_PATCH); + background = W_CachePatchName("SGRASS4", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SGRASS3", PU_PATCH); + background = W_CachePatchName("SGRASS3", PU_PATCH_LOWPRIORITY); else if (intro_curtime >= 6*TICRATE) - background = W_CachePatchName("SGRASS2", PU_PATCH); + background = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("SGRASS1", PU_PATCH); + background = W_CachePatchName("SGRASS1", PU_PATCH_LOWPRIORITY); break; } case 8: - background = W_CachePatchName("WATCHING", PU_PATCH); + background = W_CachePatchName("WATCHING", PU_PATCH_LOWPRIORITY); break; case 9: - background = W_CachePatchName("ZOOMING", PU_PATCH); + background = W_CachePatchName("ZOOMING", PU_PATCH_LOWPRIORITY); break; case 10: break; case 11: - background = W_CachePatchName("INTRO5", PU_PATCH); + background = W_CachePatchName("INTRO5", PU_PATCH_LOWPRIORITY); break; case 12: - background = W_CachePatchName("REVENGE", PU_PATCH); + background = W_CachePatchName("REVENGE", PU_PATCH_LOWPRIORITY); cx = 208; cy = 8; break; case 13: - background = W_CachePatchName("CONFRONT", PU_PATCH); + background = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY); cy += 48; break; case 14: - background = W_CachePatchName("TAILSSAD", PU_PATCH); + background = W_CachePatchName("TAILSSAD", PU_PATCH_LOWPRIORITY); bgxoffs = 144; cx = 8; cy = 8; break; case 15: if (intro_curtime >= 7*TICRATE) - background = W_CachePatchName("SONICDO2", PU_PATCH); + background = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("SONICDO1", PU_PATCH); + background = W_CachePatchName("SONICDO1", PU_PATCH_LOWPRIORITY); cx = 224; cy = 8; break; case 16: - background = W_CachePatchName("INTRO7", PU_PATCH); + background = W_CachePatchName("INTRO7", PU_PATCH_LOWPRIORITY); break; default: break; @@ -635,7 +635,7 @@ static void F_IntroDrawScene(void) strncpy(stjrintro, "STJRI029", 9); S_ChangeMusicInternal("_stjr", false); - background = W_CachePatchName(stjrintro, PU_PATCH); + background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY); wipestyleflags = WSF_FADEIN; F_WipeStartScreen(); F_TryColormapFade(31); @@ -646,7 +646,7 @@ static void F_IntroDrawScene(void) if (!WipeInAction) // Draw the patch if not in a wipe { - background = W_CachePatchName(stjrintro, PU_PATCH); + background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(bgxoffs, 84, 0, background); } } @@ -656,27 +656,27 @@ static void F_IntroDrawScene(void) if (timetonext > 5*TICRATE && timetonext < 6*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG1", PU_PATCH); + background = W_CachePatchName("BRITEGG1", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG1", PU_PATCH); + background = W_CachePatchName("DARKEGG1", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 3*TICRATE && timetonext < 4*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG2", PU_PATCH); + background = W_CachePatchName("BRITEGG2", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG2", PU_PATCH); + background = W_CachePatchName("DARKEGG2", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } else if (timetonext > 1*TICRATE && timetonext < 2*TICRATE) { if (!(finalecount & 3)) - background = W_CachePatchName("BRITEGG3", PU_PATCH); + background = W_CachePatchName("BRITEGG3", PU_PATCH_LOWPRIORITY); else - background = W_CachePatchName("DARKEGG3", PU_PATCH); + background = W_CachePatchName("DARKEGG3", PU_PATCH_LOWPRIORITY); V_DrawSmallScaledPatch(0, 0, 0, background); } @@ -708,79 +708,79 @@ static void F_IntroDrawScene(void) knucklesx += sonicx; sonicx += P_ReturnThrustX(NULL, finalecount * ANG10, 3); - V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_PATCH))); + V_DrawSmallScaledPatch(skyx, 0, 0, (patch = W_CachePatchName("INTROSKY", PU_PATCH_LOWPRIORITY))); V_DrawSmallScaledPatch(skyx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); - V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH))); + V_DrawSmallScaledPatch(grassx, 0, 0, (patch = W_CachePatchName("INTROGRS", PU_PATCH_LOWPRIORITY))); V_DrawSmallScaledPatch(grassx - 320, 0, 0, patch); W_UnlockCachedPatch(patch); if (finalecount & 1) { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT4", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic - V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx, 54, 0, (patch = W_CachePatchName("RUN1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Appendages if (finalecount & 2) { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT3", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP2", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } else { // Sonic's feet - V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH))); + V_DrawSmallScaledPatch(sonicx - 8, 92, 0, (patch = W_CachePatchName("PEELOUT1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Tails' tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("HELICOP1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } // Tails - V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH))); + V_DrawSmallScaledPatch(tailsx, tailsy, 0, (patch = W_CachePatchName("FLY1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); // Knuckles - V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH))); + V_DrawSmallScaledPatch(knucklesx, knucklesy, 0, (patch = W_CachePatchName("GLIDE1", PU_PATCH_LOWPRIORITY))); W_UnlockCachedPatch(patch); } @@ -813,8 +813,8 @@ static void F_IntroDrawScene(void) y += (30*(FRACUNIT-scale)); } - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_PATCH); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (worktics % 35)), PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(worktics & 1)), PU_PATCH_LOWPRIORITY); if (worktics >= 5) trans = (worktics-5)>>1; @@ -934,7 +934,7 @@ void F_IntroDrawer(void) { if (intro_scenenum == 5 && intro_curtime == 5*TICRATE) { - patch_t *radar = W_CachePatchName("RADAR", PU_PATCH); + patch_t *radar = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -947,7 +947,7 @@ void F_IntroDrawer(void) } else if (intro_scenenum == 7 && intro_curtime == 6*TICRATE) // Force a wipe here { - patch_t *grass = W_CachePatchName("SGRASS2", PU_PATCH); + patch_t *grass = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -960,7 +960,7 @@ void F_IntroDrawer(void) } /*else if (intro_scenenum == 11 && intro_curtime == 7*TICRATE) { - patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH); + patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -973,7 +973,7 @@ void F_IntroDrawer(void) }*/ if (intro_scenenum == 15 && intro_curtime == 7*TICRATE) { - patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH); + patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY); F_WipeStartScreen(); F_WipeColorFill(31); @@ -1303,14 +1303,14 @@ void F_CreditDrawer(void) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); // Zig Zagz - V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH)); - V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH)); - V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH)); + V_DrawScaledPatch(-16, zagpos, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(-16, zagpos - 320, V_SNAPTOLEFT, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); + V_DrawScaledPatch(BASEVIDWIDTH + 16, zagpos - 320, V_SNAPTORIGHT|V_FLIP, W_CachePatchName("LTZIGZAG", PU_PATCH_LOWPRIORITY)); // Draw background pictures first for (i = 0; credits_pics[i].patch; i++) - V_DrawSciencePatch(credits_pics[i].x<<FRACBITS, (280<<FRACBITS) + (((i*credits_height)<<FRACBITS)/(credits_numpics)) - 4*(animtimer<<FRACBITS)/5, 0, W_CachePatchName(credits_pics[i].patch, PU_PATCH), FRACUNIT>>1); + V_DrawSciencePatch(credits_pics[i].x<<FRACBITS, (280<<FRACBITS) + (((i*credits_height)<<FRACBITS)/(credits_numpics)) - 4*(animtimer<<FRACBITS)/5, 0, W_CachePatchName(credits_pics[i].patch, PU_PATCH_LOWPRIORITY), FRACUNIT>>1); // Dim the background V_DrawFadeScreen(0xFF00, 16); @@ -1519,14 +1519,14 @@ void F_GameEvaluationDrawer(void) if (goodending) { - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH); - glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - (finalecount % 35)), PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", 2+(finalecount & 1)), PU_PATCH_LOWPRIORITY); x -= FRACUNIT; } else { - rockpat = W_CachePatchName("ROID0000", PU_LEVEL); - glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH); + rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY); + glow = W_CachePatchName(va("ENDGLOW%.1d", (finalecount & 1)), PU_PATCH_LOWPRIORITY); } if (finalecount >= 5) @@ -1558,20 +1558,20 @@ void F_GameEvaluationDrawer(void) // if j == 0 - alternate between 0 and 1 // 1 - 1 and 2 // 2 - 2 and not rendered - V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_PATCH), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); + V_DrawFixedPatch(x+sparkloffs[j-1][0], y+sparkloffs[j-1][1], FRACUNIT, 0, W_CachePatchName(va("ENDSPKL%.1d", (j - ((sparklloop & 1) ? 0 : 1))), PU_PATCH_LOWPRIORITY), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_AQUA, GTC_CACHE)); } j--; } } else { - patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH); + patch_t *eggrock = W_CachePatchName("ENDEGRK5", PU_PATCH_LOWPRIORITY); V_DrawFixedPatch(x, y, scale, 0, eggrock, colormap[0]); if (trans < 10) V_DrawFixedPatch(x, y, scale, trans<<V_ALPHASHIFT, eggrock, colormap[1]); else if (sparklloop) V_DrawFixedPatch(x, y, scale, (10-sparklloop)<<V_ALPHASHIFT, - W_CachePatchName("ENDEGRK0", PU_PATCH), colormap[1]); + W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY), colormap[1]); } } @@ -1585,7 +1585,7 @@ void F_GameEvaluationDrawer(void) eemeralds_cur += (360<<FRACBITS)/7; patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_PATCH), NULL); + V_DrawFixedPatch(x, y, FRACUNIT, ((emeralds & (1<<i)) ? 0 : V_80TRANS), W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY), NULL); } V_DrawCreditString((BASEVIDWIDTH - V_CreditStringWidth(endingtext))<<(FRACBITS-1), (BASEVIDHEIGHT-100)<<(FRACBITS-1), 0, endingtext); @@ -1714,32 +1714,32 @@ void F_GameEvaluationTicker(void) static void F_CacheEnding(void) { - endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_PATCH); + endbrdr[1] = W_CachePatchName("ENDBRDR1", PU_PATCH_LOWPRIORITY); - endegrk[0] = W_CachePatchName("ENDEGRK0", PU_PATCH); - endegrk[1] = W_CachePatchName("ENDEGRK1", PU_PATCH); + endegrk[0] = W_CachePatchName("ENDEGRK0", PU_PATCH_LOWPRIORITY); + endegrk[1] = W_CachePatchName("ENDEGRK1", PU_PATCH_LOWPRIORITY); - endglow[0] = W_CachePatchName("ENDGLOW0", PU_PATCH); - endglow[1] = W_CachePatchName("ENDGLOW1", PU_PATCH); + endglow[0] = W_CachePatchName("ENDGLOW0", PU_PATCH_LOWPRIORITY); + endglow[1] = W_CachePatchName("ENDGLOW1", PU_PATCH_LOWPRIORITY); - endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_PATCH); - endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_PATCH); - endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_PATCH); + endbgsp[0] = W_CachePatchName("ENDBGSP0", PU_PATCH_LOWPRIORITY); + endbgsp[1] = W_CachePatchName("ENDBGSP1", PU_PATCH_LOWPRIORITY); + endbgsp[2] = W_CachePatchName("ENDBGSP2", PU_PATCH_LOWPRIORITY); - endspkl[0] = W_CachePatchName("ENDSPKL0", PU_PATCH); - endspkl[1] = W_CachePatchName("ENDSPKL1", PU_PATCH); - endspkl[2] = W_CachePatchName("ENDSPKL2", PU_PATCH); + endspkl[0] = W_CachePatchName("ENDSPKL0", PU_PATCH_LOWPRIORITY); + endspkl[1] = W_CachePatchName("ENDSPKL1", PU_PATCH_LOWPRIORITY); + endspkl[2] = W_CachePatchName("ENDSPKL2", PU_PATCH_LOWPRIORITY); - endxpld[0] = W_CachePatchName("ENDXPLD0", PU_PATCH); - endxpld[1] = W_CachePatchName("ENDXPLD1", PU_PATCH); - endxpld[2] = W_CachePatchName("ENDXPLD2", PU_PATCH); - endxpld[3] = W_CachePatchName("ENDXPLD3", PU_PATCH); + endxpld[0] = W_CachePatchName("ENDXPLD0", PU_PATCH_LOWPRIORITY); + endxpld[1] = W_CachePatchName("ENDXPLD1", PU_PATCH_LOWPRIORITY); + endxpld[2] = W_CachePatchName("ENDXPLD2", PU_PATCH_LOWPRIORITY); + endxpld[3] = W_CachePatchName("ENDXPLD3", PU_PATCH_LOWPRIORITY); - endescp[0] = W_CachePatchName("ENDESCP0", PU_PATCH); - endescp[1] = W_CachePatchName("ENDESCP1", PU_PATCH); - endescp[2] = W_CachePatchName("ENDESCP2", PU_PATCH); - endescp[3] = W_CachePatchName("ENDESCP3", PU_PATCH); - endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH); + endescp[0] = W_CachePatchName("ENDESCP0", PU_PATCH_LOWPRIORITY); + endescp[1] = W_CachePatchName("ENDESCP1", PU_PATCH_LOWPRIORITY); + endescp[2] = W_CachePatchName("ENDESCP2", PU_PATCH_LOWPRIORITY); + endescp[3] = W_CachePatchName("ENDESCP3", PU_PATCH_LOWPRIORITY); + endescp[4] = W_CachePatchName("ENDESCP4", PU_PATCH_LOWPRIORITY); // so we only need to check once if ((goodending = ALL7EMERALDS(emeralds))) @@ -1752,41 +1752,41 @@ static void F_CacheEnding(void) sprdef = &skins[skinnum].sprites[SPR2_XTRA]; // character head, skin specific sprframe = &sprdef->spriteframes[XTRA_ENDING]; - endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[0] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); sprframe = &sprdef->spriteframes[XTRA_ENDING+1]; - endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[1] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); sprframe = &sprdef->spriteframes[XTRA_ENDING+2]; - endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH); + endfwrk[2] = W_CachePatchNum(sprframe->lumppat[0], PU_PATCH_LOWPRIORITY); } else // Show a star if your character doesn't have an ending firework display. (Basically the MISSINGs for this) { - endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH); - endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH); - endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_PATCH); + endfwrk[0] = W_CachePatchName("ENDFWRK3", PU_PATCH_LOWPRIORITY); + endfwrk[1] = W_CachePatchName("ENDFWRK4", PU_PATCH_LOWPRIORITY); + endfwrk[2] = W_CachePatchName("ENDFWRK5", PU_PATCH_LOWPRIORITY); } - endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH); + endbrdr[0] = W_CachePatchName("ENDBRDR2", PU_PATCH_LOWPRIORITY); } else { // eggman, skin nonspecific - endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_PATCH); - endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_PATCH); - endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_PATCH); + endfwrk[0] = W_CachePatchName("ENDFWRK0", PU_PATCH_LOWPRIORITY); + endfwrk[1] = W_CachePatchName("ENDFWRK1", PU_PATCH_LOWPRIORITY); + endfwrk[2] = W_CachePatchName("ENDFWRK2", PU_PATCH_LOWPRIORITY); - endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_LEVEL); + endbrdr[0] = W_CachePatchName("ENDBRDR0", PU_PATCH_LOWPRIORITY); } } static void F_CacheGoodEnding(void) { - endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH); - endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH); + endegrk[0] = W_CachePatchName("ENDEGRK2", PU_PATCH_LOWPRIORITY); + endegrk[1] = W_CachePatchName("ENDEGRK3", PU_PATCH_LOWPRIORITY); - endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH); - endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH); + endglow[0] = W_CachePatchName("ENDGLOW2", PU_PATCH_LOWPRIORITY); + endglow[1] = W_CachePatchName("ENDGLOW3", PU_PATCH_LOWPRIORITY); - endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH); + endxpld[0] = W_CachePatchName("ENDEGRK4", PU_PATCH_LOWPRIORITY); } void F_StartEnding(void) @@ -1843,17 +1843,10 @@ void F_EndingDrawer(void) INT32 x, y, i, j, parallaxticker; patch_t *rockpat; - if (needpatchrecache) - { - F_CacheEnding(); - if (goodending && finalecount >= INFLECTIONPOINT) // time to swap some assets - F_CacheGoodEnding(); - } - if (!goodending || finalecount < INFLECTIONPOINT) - rockpat = W_CachePatchName("ROID0000", PU_PATCH); + rockpat = W_CachePatchName("ROID0000", PU_PATCH_LOWPRIORITY); else - rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH); + rockpat = W_CachePatchName(va("ROID00%.2d", 34 - ((finalecount - INFLECTIONPOINT) % 35)), PU_PATCH_LOWPRIORITY); V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); @@ -2190,7 +2183,7 @@ void F_EndingDrawer(void) eemeralds_cur[0] += (360<<FRACBITS)/7; patchname[4] = 'A'+(char)i; - V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_LEVEL), NULL); + V_DrawFixedPatch(x, y, FRACUNIT, 0, W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY), NULL); } } // if (goodending... } // (finalecount > 20) @@ -2337,11 +2330,11 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) if (!scrollxspeed && !scrollyspeed) { - V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH)); + V_DrawPatchFill(W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY)); return; } - pat = W_CachePatchName(patchname, PU_PATCH); + pat = W_CachePatchName(patchname, PU_PATCH_LOWPRIORITY); patwidth = SHORT(pat->width); patheight = SHORT(pat->height); @@ -2380,7 +2373,7 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) lumpnum = W_CheckNumForName(name); \ if (lumpnum != LUMPERROR) \ { \ - arr[0] = W_CachePatchName(name, PU_LEVEL); \ + arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \ arr[min(1, maxf-1)] = 0; \ } \ else if (strlen(name) <= 6) \ @@ -2393,7 +2386,7 @@ else if (strlen(name) <= 6) \ lumpname[8] = 0; \ lumpnum = W_CheckNumForName(lumpname); \ if (lumpnum != LUMPERROR) \ - arr[i] = W_CachePatchName(lumpname, PU_LEVEL); \ + arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \ else \ break; \ } \ @@ -2408,21 +2401,21 @@ static void F_CacheTitleScreen(void) { case TTMODE_OLD: case TTMODE_NONE: - ttbanner = W_CachePatchName("TTBANNER", PU_LEVEL); - ttwing = W_CachePatchName("TTWING", PU_LEVEL); - ttsonic = W_CachePatchName("TTSONIC", PU_LEVEL); - ttswave1 = W_CachePatchName("TTSWAVE1", PU_LEVEL); - ttswave2 = W_CachePatchName("TTSWAVE2", PU_LEVEL); - ttswip1 = W_CachePatchName("TTSWIP1", PU_LEVEL); - ttsprep1 = W_CachePatchName("TTSPREP1", PU_LEVEL); - ttsprep2 = W_CachePatchName("TTSPREP2", PU_LEVEL); - ttspop1 = W_CachePatchName("TTSPOP1", PU_LEVEL); - ttspop2 = W_CachePatchName("TTSPOP2", PU_LEVEL); - ttspop3 = W_CachePatchName("TTSPOP3", PU_LEVEL); - ttspop4 = W_CachePatchName("TTSPOP4", PU_LEVEL); - ttspop5 = W_CachePatchName("TTSPOP5", PU_LEVEL); - ttspop6 = W_CachePatchName("TTSPOP6", PU_LEVEL); - ttspop7 = W_CachePatchName("TTSPOP7", PU_LEVEL); + ttbanner = W_CachePatchName("TTBANNER", PU_PATCH_LOWPRIORITY); + ttwing = W_CachePatchName("TTWING", PU_PATCH_LOWPRIORITY); + ttsonic = W_CachePatchName("TTSONIC", PU_PATCH_LOWPRIORITY); + ttswave1 = W_CachePatchName("TTSWAVE1", PU_PATCH_LOWPRIORITY); + ttswave2 = W_CachePatchName("TTSWAVE2", PU_PATCH_LOWPRIORITY); + ttswip1 = W_CachePatchName("TTSWIP1", PU_PATCH_LOWPRIORITY); + ttsprep1 = W_CachePatchName("TTSPREP1", PU_PATCH_LOWPRIORITY); + ttsprep2 = W_CachePatchName("TTSPREP2", PU_PATCH_LOWPRIORITY); + ttspop1 = W_CachePatchName("TTSPOP1", PU_PATCH_LOWPRIORITY); + ttspop2 = W_CachePatchName("TTSPOP2", PU_PATCH_LOWPRIORITY); + ttspop3 = W_CachePatchName("TTSPOP3", PU_PATCH_LOWPRIORITY); + ttspop4 = W_CachePatchName("TTSPOP4", PU_PATCH_LOWPRIORITY); + ttspop5 = W_CachePatchName("TTSPOP5", PU_PATCH_LOWPRIORITY); + ttspop6 = W_CachePatchName("TTSPOP6", PU_PATCH_LOWPRIORITY); + ttspop7 = W_CachePatchName("TTSPOP7", PU_PATCH_LOWPRIORITY); break; // don't load alacroix gfx yet; we do that upon first draw. @@ -2542,7 +2535,7 @@ void F_StartTitleScreen(void) static void F_UnloadAlacroixGraphics(SINT8 oldttscale) { - // This all gets freed by PU_LEVEL when exiting the menus. + // This all gets freed by PU_PATCH_LOWPRIORITY when exiting the menus. // When re-visiting the menus (e.g., from exiting in-game), the gfx are force-reloaded. // So leftover addresses here should not be a problem. @@ -2648,17 +2641,12 @@ static void F_FigureActiveTtScale(void) SINT8 newttscale = max(1, min(6, vid.dupx)); SINT8 oldttscale = activettscale; - if (needpatchrecache) - ttloaded[0] = ttloaded[1] = ttloaded[2] = ttloaded[3] = ttloaded[4] = ttloaded[5] = 0; - else - { - if (newttscale == testttscale) - return; + if (newttscale == testttscale) + return; - // We have a new ttscale, so load gfx - if(oldttscale > 0) - F_UnloadAlacroixGraphics(oldttscale); - } + // We have a new ttscale, so load gfx + if(oldttscale > 0) + F_UnloadAlacroixGraphics(oldttscale); testttscale = newttscale; @@ -2692,9 +2680,6 @@ void F_TitleScreenDrawer(void) if (modeattacking) return; // We likely came here from retrying. Don't do a damn thing. - if (needpatchrecache && (curttmode != TTMODE_ALACROIX)) - F_CacheTitleScreen(); - // Draw that sky! if (curbgcolor >= 0) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, curbgcolor); @@ -3658,7 +3643,7 @@ void F_ContinueDrawer(void) V_DrawLevelTitle(x - (V_LevelNameWidth("Continue?")>>1), 16, 0, "Continue?"); // Two stars... - patch = W_CachePatchName("CONTSTAR", PU_PATCH); + patch = W_CachePatchName("CONTSTAR", PU_PATCH_LOWPRIORITY); V_DrawScaledPatch(x-32, 160, 0, patch); V_DrawScaledPatch(x+32, 160, 0, patch); @@ -3666,14 +3651,14 @@ void F_ContinueDrawer(void) if (timeleft > 9) { numbuf[7] = '1'; - V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x - 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); numbuf[7] = '0'; - V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x + 10, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); } else { numbuf[7] = '0'+timeleft; - V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH)); + V_DrawScaledPatch(x, 160, 0, W_CachePatchName(numbuf, PU_PATCH_LOWPRIORITY)); } // Draw the continue markers! Show continues. @@ -3702,7 +3687,7 @@ void F_ContinueDrawer(void) } // Spotlight - V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH)); + V_DrawScaledPatch(x, 140, 0, W_CachePatchName("CONTSPOT", PU_PATCH_LOWPRIORITY)); // warping laser if (continuetime) @@ -3739,7 +3724,7 @@ void F_ContinueDrawer(void) #define drawchar(dx, dy, n) {\ sprdef = &contskins[n]->sprites[cont_spr2[n][0]];\ sprframe = &sprdef->spriteframes[cont_spr2[n][1]];\ - patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH);\ + patch = W_CachePatchNum(sprframe->lumppat[cont_spr2[n][2]], PU_PATCH_LOWPRIORITY);\ V_DrawFixedPatch((dx), (dy), contskins[n]->highresscale, (sprframe->flip & (1<<cont_spr2[n][2])) ? V_FLIP : 0, patch, contcolormaps[n]);\ } @@ -4004,10 +3989,10 @@ void F_CutsceneDrawer(void) { if (cutscenes[cutnum]->scene[scenenum].pichires[picnum]) V_DrawSmallScaledPatch(picxpos, picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); } if (dofadenow && rendermode != render_none) @@ -4493,10 +4478,10 @@ void F_TextPromptDrawer(void) { if (textprompts[cutnum]->page[scenenum].pichires[picnum]) V_DrawSmallScaledPatch(picxpos, picypos, 0, - W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); else V_DrawScaledPatch(picxpos,picypos, 0, - W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH)); + W_CachePatchName(textprompts[cutnum]->page[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); } // Draw background @@ -4506,7 +4491,7 @@ void F_TextPromptDrawer(void) if (iconlump != LUMPERROR) { INT32 iconx, icony, scale, scaledsize; - patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH); + patch = W_CachePatchName(textprompts[cutnum]->page[scenenum].iconname, PU_PATCH_LOWPRIORITY); // scale and center if (patch->width > patch->height) diff --git a/src/f_wipe.c b/src/f_wipe.c index f5b9bd72230ae7f5763b7fdc97cbbca9398d0ff5..6afb8a6a7934709c90b1428fcd5f5a6f55d54c20 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -293,7 +293,7 @@ static void F_DoWipe(fademask_t *fademask) else { // pointer to transtable that this mask would use - transtbl = transtables + ((9 - *mask)<<FF_TRANSSHIFT); + transtbl = R_GetTranslucencyTable((9 - *mask) + 1); // DRAWING LOOP while (draw_linestogo--) diff --git a/src/g_demo.c b/src/g_demo.c index 0f72ad1094e443523f6be3fdb6b5fa345fa48539..9d3b8601584385d06bbd14e5ff8a2ec4ea63ca3c 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -453,8 +453,7 @@ void G_WriteGhostTic(mobj_t *ghost) WRITEUINT16(demo_p,oldghost.sprite); if (ghostext.flags & EZT_HEIGHT) { - height >>= FRACBITS; - WRITEINT16(demo_p, height); + WRITEFIXED(demo_p, height); } ghostext.flags = 0; } @@ -610,7 +609,7 @@ void G_ConsGhostTic(void) if (xziptic & EZT_SPRITE) demo_p += sizeof(UINT16); if (xziptic & EZT_HEIGHT) - demo_p += sizeof(INT16); + demo_p += (demoversion < 0x000e) ? sizeof(INT16) : sizeof(fixed_t); } if (ziptic & GZT_FOLLOW) @@ -842,7 +841,7 @@ void G_GhostTicker(void) g->mo->sprite = READUINT16(g->p); if (xziptic & EZT_HEIGHT) { - fixed_t temp = READINT16(g->p)<<FRACBITS; + fixed_t temp = (g->version < 0x000e) ? READINT16(g->p)<<FRACBITS : READFIXED(g->p); g->mo->height = FixedMul(temp, g->mo->scale); } } @@ -1106,7 +1105,7 @@ void G_ReadMetalTic(mobj_t *metal) metal->sprite = READUINT16(metal_p); if (xziptic & EZT_HEIGHT) { - fixed_t temp = READINT16(metal_p)<<FRACBITS; + fixed_t temp = (metalversion < 0x000e) ? READINT16(metal_p)<<FRACBITS : READFIXED(metal_p); metal->height = FixedMul(temp, metal->scale); } } @@ -1293,8 +1292,7 @@ void G_WriteMetalTic(mobj_t *metal) WRITEUINT16(demo_p,oldmetal.sprite); if (ghostext.flags & EZT_HEIGHT) { - height >>= FRACBITS; - WRITEINT16(demo_p, height); + WRITEFIXED(demo_p, height); } ghostext.flags = 0; } @@ -1474,8 +1472,8 @@ void G_BeginRecording(void) WRITEUINT8(demo_p,player->thrustfactor); WRITEUINT8(demo_p,player->accelstart); WRITEUINT8(demo_p,player->acceleration); - WRITEUINT8(demo_p,player->height>>FRACBITS); - WRITEUINT8(demo_p,player->spinheight>>FRACBITS); + WRITEFIXED(demo_p,player->height); + WRITEFIXED(demo_p,player->spinheight); WRITEUINT8(demo_p,player->camerascale>>FRACBITS); WRITEUINT8(demo_p,player->shieldscale>>FRACBITS); @@ -1901,8 +1899,8 @@ void G_DoPlayDemo(char *defdemoname) thrustfactor = READUINT8(demo_p); accelstart = READUINT8(demo_p); acceleration = READUINT8(demo_p); - height = (fixed_t)READUINT8(demo_p)<<FRACBITS; - spinheight = (fixed_t)READUINT8(demo_p)<<FRACBITS; + height = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); + spinheight = (demoversion < 0x000e) ? (fixed_t)READUINT8(demo_p)<<FRACBITS : READFIXED(demo_p); camerascale = (fixed_t)READUINT8(demo_p)<<FRACBITS; shieldscale = (fixed_t)READUINT8(demo_p)<<FRACBITS; jumpfactor = READFIXED(demo_p); @@ -2150,8 +2148,7 @@ void G_AddGhost(char *defdemoname) p++; // thrustfactor p++; // accelstart p++; // acceleration - p++; // height - p++; // spinheight + p += (ghostversion < 0x000e) ? 2 : 2 * sizeof(fixed_t); // height and spinheight p++; // camerascale p++; // shieldscale p += 4; // jumpfactor diff --git a/src/g_game.c b/src/g_game.c index 1ea7cd0809a4cfdf59242812421636b79cfc6bb9..228295b629539da319ee874798a26c91fcca0aa7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1829,7 +1829,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_LoadLevel(false)) // this never returns false? + if (!P_LoadLevel(false, false)) // this never returns false? { // fail so reset game stuff Command_ExitGame_f(); diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 8c85c5112b09aa38ebd619b13c7c7b07a147e92f..85dabbcec317be2ae1a9ac1dfd8bdd7354ccd431 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -25,6 +25,7 @@ #include "../z_zone.h" #include "../v_video.h" #include "../r_draw.h" +#include "../r_patch.h" #include "../r_picformats.h" #include "../p_setup.h" @@ -306,7 +307,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, // Draw each column to the block cache for (; ncols--; block += bpp, xfrac += xfracstep) { - patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS])); + patchcol = (const column_t *)((const UINT8 *)realpatch->columns + (realpatch->columnofs[xfrac>>FRACBITS])); HWR_DrawColumnInCache(patchcol, block, mipmap, pblockheight, blockmodulo, @@ -320,7 +321,7 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight, texture_t *texture, texpatch_t *patch, - const patch_t *realpatch) + const softwarepatch_t *realpatch) { INT32 x, x1, x2; INT32 col, ncols; @@ -391,7 +392,7 @@ static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, bpp = format2bpp(mipmap->format); if (bpp < 1 || bpp > 4) - I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); + I_Error("HWR_DrawTexturePatchInCache: no drawer defined for this bpp (%d)\n",bpp); // NOTE: should this actually be pblockwidth*bpp? blockmodulo = pblockwidth*bpp; @@ -446,7 +447,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) UINT8 *block; texture_t *texture; texpatch_t *patch; - patch_t *realpatch; + softwarepatch_t *realpatch; UINT8 *pdata; INT32 blockwidth, blockheight, blocksize; @@ -502,16 +503,16 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) boolean dealloc = true; size_t lumplength = W_LumpLengthPwad(patch->wad, patch->lump); pdata = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); + realpatch = (softwarepatch_t *)Picture_PNGConvert(pdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); + realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -544,36 +545,20 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex) // patch may be NULL if grMipmap has been initialised already and makebitmap is false void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap) { -#ifndef NO_PNG_LUMPS - // lump is a png so convert it - size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum); - if ((patch != NULL) && Picture_IsLumpPNG((const UINT8 *)patch, len)) - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, NULL, 0); -#endif - - // don't do it twice (like a cache) if (grMipmap->width == 0) { - // save the original patch header so that the GLPatch can be casted - // into a standard patch_t struct and the existing code can get the - // orginal patch dimensions and offsets. - grPatch->width = SHORT(patch->width); - grPatch->height = SHORT(patch->height); - grPatch->leftoffset = SHORT(patch->leftoffset); - grPatch->topoffset = SHORT(patch->topoffset); - grMipmap->width = grMipmap->height = 1; - while (grMipmap->width < grPatch->width) grMipmap->width <<= 1; - while (grMipmap->height < grPatch->height) grMipmap->height <<= 1; + while (grMipmap->width < patch->width) grMipmap->width <<= 1; + while (grMipmap->height < patch->height) grMipmap->height <<= 1; // no wrap around, no chroma key grMipmap->flags = 0; + // setup the texture info grMipmap->format = patchformat; - //grPatch->max_s = grPatch->max_t = 1.0f; - grPatch->max_s = (float)grPatch->width / (float)grMipmap->width; - grPatch->max_t = (float)grPatch->height / (float)grMipmap->height; + grPatch->max_s = (float)patch->width / (float)grMipmap->width; + grPatch->max_t = (float)patch->height / (float)grMipmap->height; } Z_Free(grMipmap->data); @@ -585,7 +570,7 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm HWR_DrawPatchInCache(grMipmap, grMipmap->width, grMipmap->height, - grPatch->width, grPatch->height, + patch->width, patch->height, patch); } } @@ -598,20 +583,44 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm static size_t gl_numtextures = 0; // Texture count static GLMapTexture_t *gl_textures; // For all textures static GLMapTexture_t *gl_flats; // For all (texture) flats, as normal flats don't need to be cached +boolean gl_maptexturesloaded = false; -void HWR_InitTextureCache(void) +void HWR_FreeTexture(patch_t *patch) { - gl_textures = NULL; - gl_flats = NULL; + if (!patch) + return; + + if (patch->hardware) + { + GLPatch_t *grPatch = patch->hardware; + + HWR_FreeTextureColormaps(patch); + + if (grPatch->mipmap) + { + if (vid.glstate == VID_GL_LIBRARY_LOADED) + HWD.pfnDeleteTexture(grPatch->mipmap); + if (grPatch->mipmap->data) + Z_Free(grPatch->mipmap->data); + Z_Free(grPatch->mipmap); + } + + Z_Free(patch->hardware); + } + + patch->hardware = NULL; } -// Callback function for HWR_FreeTextureCache. -static void FreeMipmapColormap(INT32 patchnum, void *patch) +// Called by HWR_FreePatchCache. +void HWR_FreeTextureColormaps(patch_t *patch) { - GLPatch_t* const pat = patch; - (void)patchnum; //unused + GLPatch_t *pat; // The patch must be valid, obviously + if (!patch) + return; + + pat = patch->hardware; if (!pat) return; @@ -639,34 +648,65 @@ static void FreeMipmapColormap(INT32 patchnum, void *patch) if (next->data) Z_Free(next->data); next->data = NULL; + HWD.pfnDeleteTexture(next); // Free the old colormap mipmap from memory. free(next); } } -void HWR_FreeMipmapCache(void) +static void HWR_FreePatchCache(boolean freeall) { INT32 i; + for (i = 0; i < numwadfiles; i++) + { + INT32 j = 0; + for (; j < wadfiles[i]->numlumps; j++) + (freeall ? HWR_FreeTexture : HWR_FreeTextureColormaps)(wadfiles[i]->patchcache[j]); + } +} + +void HWR_ClearAllTextures(void) +{ + HWR_FreeMapTextures(); + // free references to the textures HWD.pfnClearMipMapCache(); - // free all hardware-converted graphics cached in the heap - // our gool is only the textures since user of the texture is the texture cache - Z_FreeTag(PU_HWRCACHE); - Z_FreeTag(PU_HWRCACHE_UNLOCKED); - // Alam: free the Z_Blocks before freeing it's users - // free all patch colormaps after each level: must be done after ClearMipMapCache! - for (i = 0; i < numwadfiles; i++) - M_AATreeIterate(wadfiles[i]->hwrcache, FreeMipmapColormap); + HWR_FreePatchCache(true); } -void HWR_FreeTextureCache(void) +// free all patch colormaps after each level: must be done after ClearMipMapCache! +void HWR_FreeColormapCache(void) { - // free references to the textures - HWR_FreeMipmapCache(); + HWR_FreePatchCache(false); +} + +void HWR_InitMapTextures(void) +{ + gl_textures = NULL; + gl_flats = NULL; + gl_maptexturesloaded = false; +} + +static void FreeMapTexture(GLMapTexture_t *tex) +{ + HWD.pfnDeleteTexture(&tex->mipmap); + if (tex->mipmap.data) + Z_Free(tex->mipmap.data); +} + +void HWR_FreeMapTextures(void) +{ + size_t i; + + for (i = 0; i < gl_numtextures; i++) + { + FreeMapTexture(&gl_textures[i]); + FreeMapTexture(&gl_flats[i]); + } // now the heap don't have any 'user' pointing to our // texturecache info, we can free it @@ -677,12 +717,13 @@ void HWR_FreeTextureCache(void) gl_textures = NULL; gl_flats = NULL; gl_numtextures = 0; + gl_maptexturesloaded = false; } -void HWR_LoadTextures(size_t pnumtextures) +void HWR_LoadMapTextures(size_t pnumtextures) { // we must free it since numtextures changed - HWR_FreeTextureCache(); + HWR_FreeMapTextures(); // Why not Z_Malloc? gl_numtextures = pnumtextures; @@ -692,7 +733,9 @@ void HWR_LoadTextures(size_t pnumtextures) // Doesn't tell you which it _is_, but hopefully // should never ever happen (right?!) if ((gl_textures == NULL) || (gl_flats == NULL)) - I_Error("HWR_LoadTextures: ran out of memory for OpenGL textures. Sad!"); + I_Error("HWR_LoadMapTextures: ran out of memory for OpenGL textures. Sad!"); + + gl_maptexturesloaded = true; } void HWR_SetPalette(RGBA_t *palette) @@ -730,7 +773,6 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex) // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grtex->mipmap.downloaded) HWD.pfnSetTexture(&grtex->mipmap); - HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. @@ -806,17 +848,19 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) { GLMipmap_t *grmip; + patch_t *patch; + if (flatlumpnum == LUMPERROR) return; - grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap; + patch = HWR_GetCachedGLPatch(flatlumpnum); + grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap; if (!grmip->downloaded && !grmip->data) HWR_CacheFlat(grmip, flatlumpnum); // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grmip->downloaded) HWD.pfnSetTexture(grmip); - HWR_SetCurrentTexture(grmip); // The system-memory data can be purged now. @@ -854,7 +898,6 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) // If hardware does not have the texture, then call pfnSetTexture to upload it if (!grtex->mipmap.downloaded) HWD.pfnSetTexture(&grtex->mipmap); - HWR_SetCurrentTexture(&grtex->mipmap); // The system-memory data can be purged now. @@ -862,9 +905,9 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) } else if (levelflat->type == LEVELFLAT_PATCH) { - GLPatch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE); - levelflat->width = (UINT16)SHORT(patch->width); - levelflat->height = (UINT16)SHORT(patch->height); + patch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE); + levelflat->width = (UINT16)(patch->width); + levelflat->height = (UINT16)(patch->height); HWR_GetPatch(patch); } #ifndef NO_PNG_LUMPS @@ -911,89 +954,61 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) HWR_SetCurrentTexture(NULL); } -// -// HWR_LoadMappedPatch(): replace the skin color of the sprite in cache -// : load it first in doom cache if not already -// -static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) +// --------------------+ +// HWR_LoadPatchMipmap : Generates a patch into a mipmap, usually the mipmap inside the patch itself +// --------------------+ +static void HWR_LoadPatchMipmap(patch_t *patch, GLMipmap_t *grMipmap) { - if (!grmip->downloaded && !grmip->data) - { - patch_t *patch = gpatch->rawpatch; - if (!patch) - patch = W_CacheLumpNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - HWR_MakePatch(patch, gpatch, grmip, true); - - // You can't free rawpatch for some reason? - // (Obviously I can't, sprite rotation needs that...) - if (!gpatch->rawpatch) - Z_Free(patch); - } + GLPatch_t *grPatch = patch->hardware; + if (!grMipmap->downloaded && !grMipmap->data) + HWR_MakePatch(patch, grPatch, grMipmap, true); // If hardware does not have the texture, then call pfnSetTexture to upload it - if (!grmip->downloaded) - HWD.pfnSetTexture(grmip); - - HWR_SetCurrentTexture(grmip); + if (!grMipmap->downloaded) + HWD.pfnSetTexture(grMipmap); + HWR_SetCurrentTexture(grMipmap); // The system-memory data can be purged now. - Z_ChangeTag(grmip->data, PU_HWRCACHE_UNLOCKED); + Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); } // -----------------+ // HWR_GetPatch : Download a patch to the hardware cache and make it ready for use // -----------------+ -void HWR_GetPatch(GLPatch_t *gpatch) +void HWR_GetPatch(patch_t *patch) { - // is it in hardware cache - if (!gpatch->mipmap->downloaded && !gpatch->mipmap->data) - { - // 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 = 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 - if (!gpatch->rawpatch) - Z_Free(ptr); - } - - // If hardware does not have the texture, then call pfnSetTexture to upload it - if (!gpatch->mipmap->downloaded) - HWD.pfnSetTexture(gpatch->mipmap); - - HWR_SetCurrentTexture(gpatch->mipmap); - - // The system-memory patch data can be purged now. - Z_ChangeTag(gpatch->mipmap->data, PU_HWRCACHE_UNLOCKED); + if (!patch->hardware) + Patch_CreateGL(patch); + HWR_LoadPatchMipmap(patch, ((GLPatch_t *)patch->hardware)->mipmap); } - // -------------------+ // HWR_GetMappedPatch : Same as HWR_GetPatch for sprite color // -------------------+ -void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) +void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap) { - GLMipmap_t *grmip, *newmip; + GLPatch_t *grPatch; + GLMipmap_t *grMipmap, *newMipmap; + + if (!patch->hardware) + Patch_CreateGL(patch); + grPatch = patch->hardware; if (colormap == colormaps || colormap == NULL) { - // Load the default (green) color in doom cache (temporary?) AND hardware cache - HWR_GetPatch(gpatch); + // Load the default (green) color in hardware cache + HWR_GetPatch(patch); return; } // search for the mimmap // skip the first (no colormap translated) - for (grmip = gpatch->mipmap; grmip->nextcolormap; ) + for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { - grmip = grmip->nextcolormap; - if (grmip->colormap == colormap) + grMipmap = grMipmap->nextcolormap; + if (grMipmap->colormap == colormap) { - HWR_LoadMappedPatch(grmip, gpatch); + HWR_LoadPatchMipmap(patch, grMipmap); return; } } @@ -1002,15 +1017,15 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) //BP: WARNING: don't free it manually without clearing the cache of harware renderer // (it have a liste of mipmap) - // this malloc is cleared in HWR_FreeTextureCache + // this malloc is cleared in HWR_FreeColormapCache // (...) unfortunately z_malloc fragment alot the memory :(so malloc is better - newmip = calloc(1, sizeof (*newmip)); - if (newmip == NULL) + newMipmap = calloc(1, sizeof (*newMipmap)); + if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetMappedPatch"); - grmip->nextcolormap = newmip; + grMipmap->nextcolormap = newMipmap; - newmip->colormap = colormap; - HWR_LoadMappedPatch(newmip, gpatch); + newMipmap->colormap = colormap; + HWR_LoadPatchMipmap(patch, newMipmap); } void HWR_UnlockCachedPatch(GLPatch_t *gpatch) @@ -1100,79 +1115,73 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig // HWR_GetPic : Download a Doom pic (raw row encoded with no 'holes') // Returns : // -----------------+ -GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) +patch_t *HWR_GetPic(lumpnum_t lumpnum) { - GLPatch_t *grpatch = HWR_GetCachedGLPatch(lumpnum); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + patch_t *patch = HWR_GetCachedGLPatch(lumpnum); + GLPatch_t *grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { pic_t *pic; UINT8 *block; size_t len; pic = W_CacheLumpNum(lumpnum, PU_CACHE); - grpatch->width = SHORT(pic->width); - grpatch->height = SHORT(pic->height); + patch->width = SHORT(pic->width); + patch->height = SHORT(pic->height); len = W_LumpLength(lumpnum) - sizeof (pic_t); - grpatch->leftoffset = 0; - grpatch->topoffset = 0; - - grpatch->mipmap->width = (UINT16)grpatch->width; - grpatch->mipmap->height = (UINT16)grpatch->height; + grPatch->mipmap->width = (UINT16)patch->width; + grPatch->mipmap->height = (UINT16)patch->height; if (pic->mode == PALETTE) - grpatch->mipmap->format = textureformat; // can be set by driver + grPatch->mipmap->format = textureformat; // can be set by driver else - grpatch->mipmap->format = picmode2GR[pic->mode]; + grPatch->mipmap->format = picmode2GR[pic->mode]; - Z_Free(grpatch->mipmap->data); + Z_Free(grPatch->mipmap->data); // allocate block - block = MakeBlock(grpatch->mipmap); + block = MakeBlock(grPatch->mipmap); - if (grpatch->width == SHORT(pic->width) && - grpatch->height == SHORT(pic->height) && - format2bpp(grpatch->mipmap->format) == format2bpp(picmode2GR[pic->mode])) + if (patch->width == SHORT(pic->width) && + patch->height == SHORT(pic->height) && + format2bpp(grPatch->mipmap->format) == format2bpp(picmode2GR[pic->mode])) { // no conversion needed - M_Memcpy(grpatch->mipmap->data, pic->data,len); + M_Memcpy(grPatch->mipmap->data, pic->data,len); } else HWR_DrawPicInCache(block, SHORT(pic->width), SHORT(pic->height), - SHORT(pic->width)*format2bpp(grpatch->mipmap->format), + SHORT(pic->width)*format2bpp(grPatch->mipmap->format), pic, - format2bpp(grpatch->mipmap->format)); + format2bpp(grPatch->mipmap->format)); Z_Unlock(pic); Z_ChangeTag(block, PU_HWRCACHE_UNLOCKED); - grpatch->mipmap->flags = 0; - grpatch->max_s = grpatch->max_t = 1.0f; + grPatch->mipmap->flags = 0; + grPatch->max_s = grPatch->max_t = 1.0f; } - HWD.pfnSetTexture(grpatch->mipmap); - //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grpatch->mipmap.data, grpatch->mipmap.downloaded); + HWD.pfnSetTexture(grPatch->mipmap); + //CONS_Debug(DBG_RENDER, "picloaded at %x as texture %d\n",grPatch->mipmap->data, grPatch->mipmap->downloaded); - return grpatch; + return patch; } -GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum) +patch_t *HWR_GetCachedGLPatchPwad(UINT16 wadnum, UINT16 lumpnum) { - aatree_t *hwrcache = wadfiles[wadnum]->hwrcache; - GLPatch_t *grpatch; - - if (!(grpatch = M_AATreeGet(hwrcache, lumpnum))) + lumpcache_t *lumpcache = wadfiles[wadnum]->patchcache; + if (!lumpcache[lumpnum]) { - grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grpatch->wadnum = wadnum; - grpatch->lumpnum = lumpnum; - grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - M_AATreeSet(hwrcache, lumpnum, grpatch); + void *ptr = Z_Calloc(sizeof(patch_t), PU_PATCH, &lumpcache[lumpnum]); + Patch_Create(NULL, 0, ptr); + Patch_AllocateHardwarePatch(ptr); } - - return grpatch; + return (patch_t *)(lumpcache[lumpnum]); } -GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum) +patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum) { return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } @@ -1265,7 +1274,8 @@ static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum) void HWR_GetFadeMask(lumpnum_t fademasklumpnum) { - GLMipmap_t *grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; + patch_t *patch = HWR_GetCachedGLPatch(fademasklumpnum); + GLMipmap_t *grmip = ((GLPatch_t *)Patch_AllocateHardwarePatch(patch))->mipmap; if (!grmip->downloaded && !grmip->data) HWR_CacheFadeMask(grmip, fademasklumpnum); diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h index e5477d7292b3701a4bb8966c19715c0cd508d881..6a872d25876b159562d45452095f9dfd4da5c974 100644 --- a/src/hardware/hw_data.h +++ b/src/hardware/hw_data.h @@ -73,23 +73,10 @@ struct GLMapTexture_s typedef struct GLMapTexture_s GLMapTexture_t; -// a cached patch as converted to hardware format, holding the original patch_t -// header so that the existing code can retrieve ->width, ->height as usual -// This is returned by W_CachePatchNum()/W_CachePatchName(), when rendermode -// is 'render_opengl'. Else it returns the normal patch_t data. - +// a cached patch as converted to hardware format struct GLPatch_s { - // the 4 first fields come right away from the original patch_t - INT16 width; - INT16 height; - INT16 leftoffset; // pixels to the left of origin - INT16 topoffset; // pixels below the origin - // 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; } ATTRPACK; typedef struct GLPatch_s GLPatch_t; diff --git a/src/hardware/hw_defs.h b/src/hardware/hw_defs.h index 607d21ef52dd6863f5bafc72f736cc27f2a475b5..a782762a38c46dbb4161468b43b3041d215e8d2e 100644 --- a/src/hardware/hw_defs.h +++ b/src/hardware/hw_defs.h @@ -212,35 +212,32 @@ typedef struct // You pass a combination of these flags to DrawPolygon() enum EPolyFlags { - // the first 5 are mutually exclusive - - PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pels are discarded (holes in texture) + // Mutually exclusive blend flags + PF_Masked = 0x00000001, // Poly is alpha scaled and 0 alpha pixels are discarded (holes in texture) PF_Translucent = 0x00000002, // Poly is transparent, alpha = level of transparency - PF_Additive = 0x00000004, // Poly is added to the frame buffer - PF_Environment = 0x00000008, // Poly should be drawn environment mapped. - // Hurdler: used for text drawing - PF_Substractive = 0x00000010, // for splat - PF_NoAlphaTest = 0x00000020, // hiden param - PF_Fog = 0x00000040, // Fog blocks - PF_Blending = (PF_Environment|PF_Additive|PF_Translucent|PF_Masked|PF_Substractive|PF_Fog)&~PF_NoAlphaTest, - - // other flag bits - - PF_Occlude = 0x00000100, // Update the depth buffer - PF_NoDepthTest = 0x00000200, // Disable the depth test mode - PF_Invisible = 0x00000400, // Disable write to color buffer - PF_Decal = 0x00000800, // Enable polygon offset + PF_Environment = 0x00000004, // Poly should be drawn environment mapped. (Hurdler: used for text drawing) + PF_Additive = 0x00000008, // Additive color blending + PF_AdditiveSource = 0x00000010, // Source blending factor is additive. This is the opposite of regular additive blending. + PF_Subtractive = 0x00000020, // Subtractive color blending + PF_ReverseSubtract = 0x00000040, // Reverse subtract, used in wall splats (decals) + PF_Multiplicative = 0x00000080, // Multiplicative color blending + PF_Fog = 0x20000000, // Fog blocks + PF_NoAlphaTest = 0x40000000, // Disables alpha testing + PF_Blending = (PF_Masked|PF_Translucent|PF_Environment|PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative|PF_Fog) & ~PF_NoAlphaTest, + + // other flag bits + PF_Occlude = 0x00000100, // Updates the depth buffer + PF_NoDepthTest = 0x00000200, // Disables the depth test mode + PF_Invisible = 0x00000400, // Disables write to color buffer + PF_Decal = 0x00000800, // Enables polygon offset PF_Modulated = 0x00001000, // Modulation (multiply output with constant ARGB) // When set, pass the color constant into the FSurfaceInfo -> PolyColor - PF_NoTexture = 0x00002000, // Use the small white texture - PF_Corona = 0x00004000, // Tell the rendrer we are drawing a corona - PF_Ripple = 0x00008000, // Water shader effect - PF_RemoveYWrap = 0x00010000, // Force clamp texture on Y - PF_ForceWrapX = 0x00020000, // Force repeat texture on X - PF_ForceWrapY = 0x00040000, // Force repeat texture on Y - PF_Clip = 0x40000000, // clip to frustum and nearz plane (glide only, automatic in opengl) - PF_NoZClip = 0x20000000, // in conjonction with PF_Clip - PF_Debug = 0x80000000 // print debug message in driver :) + PF_NoTexture = 0x00002000, // Disables texturing + PF_Corona = 0x00004000, // Tells the renderer we are drawing a corona + PF_Ripple = 0x00008000, // Water effect shader + PF_RemoveYWrap = 0x00010000, // Forces clamp texture on Y + PF_ForceWrapX = 0x00020000, // Forces repeat texture on X + PF_ForceWrapY = 0x00040000 // Forces repeat texture on Y }; @@ -295,6 +292,16 @@ enum hwdsetspecialstate typedef enum hwdsetspecialstate hwdspecialstate_t; +// Lactozilla: Shader options +enum hwdshaderoption +{ + HWD_SHADEROPTION_OFF, + HWD_SHADEROPTION_ON, + HWD_SHADEROPTION_NOCUSTOM, +}; + +typedef enum hwdshaderoption hwdshaderoption_t; + // Lactozilla: Shader info // Generally set at the start of the frame. enum hwdshaderinfo diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c index f5a984d5d3a23ed3bd80d4d7e690bcba8d42422c..faf7a9f8c6d65f65cda61f890b04f332b8f319b7 100644 --- a/src/hardware/hw_draw.c +++ b/src/hardware/hw_draw.c @@ -68,10 +68,11 @@ static UINT8 softwaretranstogl_lo[11] = { 0, 12, 24, 36, 48, 60, 71, 83, 95,111 // Notes : x,y : positions relative to the original Doom resolution // : textes(console+score) + menus + status bar // -----------------+ -void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) +void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option) { FOutVector v[4]; FBITFIELD flags; + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -84,6 +85,7 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) // make patch ready in hardware cache HWR_GetPatch(gpatch); + hwrPatch = ((GLPatch_t *)gpatch->hardware); switch (option & V_SCALEPATCHMASK) { @@ -103,17 +105,17 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) if (option & V_NOSCALESTART) sdupx = sdupy = 2.0f; - v[0].x = v[3].x = (x*sdupx-SHORT(gpatch->leftoffset)*pdupx)/vid.width - 1; - v[2].x = v[1].x = (x*sdupx+(SHORT(gpatch->width)-SHORT(gpatch->leftoffset))*pdupx)/vid.width - 1; - v[0].y = v[1].y = 1-(y*sdupy-SHORT(gpatch->topoffset)*pdupy)/vid.height; - v[2].y = v[3].y = 1-(y*sdupy+(SHORT(gpatch->height)-SHORT(gpatch->topoffset))*pdupy)/vid.height; + v[0].x = v[3].x = (x*sdupx-(gpatch->leftoffset)*pdupx)/vid.width - 1; + v[2].x = v[1].x = (x*sdupx+(gpatch->width-gpatch->leftoffset)*pdupx)/vid.width - 1; + v[0].y = v[1].y = 1-(y*sdupy-(gpatch->topoffset)*pdupy)/vid.height; + v[2].y = v[3].y = 1-(y*sdupy+(gpatch->height-gpatch->topoffset)*pdupy)/vid.height; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].s = v[3].s = 0.0f; - v[2].s = v[1].s = gpatch->max_s; + v[2].s = v[1].s = hwrPatch->max_s; v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = gpatch->max_t; + v[2].t = v[3].t = hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -126,13 +128,14 @@ void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option) HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) +void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -151,6 +154,8 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t else HWR_GetMappedPatch(gpatch, colormap); + hwrPatch = ((GLPatch_t *)gpatch->hardware); + dupx = (float)vid.dupx; dupy = (float)vid.dupy; @@ -181,13 +186,13 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t // left offset if (option & V_FLIP) - offsetx = (float)(SHORT(gpatch->width) - SHORT(gpatch->leftoffset)) * fscalew; + offsetx = (float)(gpatch->width - gpatch->leftoffset) * fscalew; else - offsetx = (float)SHORT(gpatch->leftoffset) * fscalew; + offsetx = (float)(gpatch->leftoffset) * fscalew; // top offset // TODO: make some kind of vertical version of V_FLIP, maybe by deprecating V_OFFSET in future?!? - offsety = (float)SHORT(gpatch->topoffset) * fscaleh; + offsety = (float)(gpatch->topoffset) * fscaleh; if ((option & (V_NOSCALESTART|V_OFFSET)) == (V_NOSCALESTART|V_OFFSET)) // Multiply by dupx/dupy for crosshairs { @@ -277,17 +282,14 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) // cx and cy are possibly *slightly* off from float maths // This is done before here compared to software because we directly alter cx and cy to centre - if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) + if (cx >= -0.1f && cx <= 0.1f && (gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) { - // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); if (!column->topdelta) { const UINT8 *source = (const UINT8 *)(column) + 3; HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } - Z_Free(realpatch); } // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) @@ -317,13 +319,13 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (pscale != FRACUNIT || (splitscreen && option & V_PERPLAYER)) { - fwidth = (float)SHORT(gpatch->width) * fscalew * dupx; - fheight = (float)SHORT(gpatch->height) * fscaleh * dupy; + fwidth = (float)(gpatch->width) * fscalew * dupx; + fheight = (float)(gpatch->height) * fscaleh * dupy; } else { - fwidth = (float)SHORT(gpatch->width) * dupx; - fheight = (float)SHORT(gpatch->height) * dupy; + fwidth = (float)(gpatch->width) * dupx; + fheight = (float)(gpatch->height) * dupy; } // positions of the cx, cy, are between 0 and vid.width/vid.height now, we need them to be between -1 and 1 @@ -345,17 +347,17 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t if (option & V_FLIP) { - v[0].s = v[3].s = gpatch->max_s; + v[0].s = v[3].s = hwrPatch->max_s; v[2].s = v[1].s = 0.0f; } else { v[0].s = v[3].s = 0.0f; - v[2].s = v[1].s = gpatch->max_s; + v[2].s = v[1].s = hwrPatch->max_s; } v[0].t = v[1].t = 0.0f; - v[2].t = v[3].t = gpatch->max_t; + v[2].t = v[3].t = hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -380,13 +382,14 @@ void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t HWD.pfnDrawPolygon(NULL, v, 4, flags); } -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h) { FOutVector v[4]; FBITFIELD flags; float cx = FIXED_TO_FLOAT(x); float cy = FIXED_TO_FLOAT(y); UINT8 alphalevel = ((option & V_ALPHAMASK) >> V_ALPHASHIFT); + GLPatch_t *hwrPatch; // 3--2 // | /| @@ -399,6 +402,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // make patch ready in hardware cache HWR_GetPatch(gpatch); + hwrPatch = ((GLPatch_t *)gpatch->hardware); dupx = (float)vid.dupx; dupy = (float)vid.dupy; @@ -438,15 +442,12 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal // This is done before here compared to software because we directly alter cx and cy to centre if (cx >= -0.1f && cx <= 0.1f && SHORT(gpatch->width) == BASEVIDWIDTH && cy >= -0.1f && cy <= 0.1f && SHORT(gpatch->height) == BASEVIDHEIGHT) { - // Need to temporarily cache the real patch to get the colour of the top left pixel - patch_t *realpatch = W_CacheSoftwarePatchNumPwad(gpatch->wadnum, gpatch->lumpnum, PU_STATIC); - const column_t *column = (const column_t *)((const UINT8 *)(realpatch) + LONG((realpatch)->columnofs[0])); + const column_t *column = (const column_t *)((const UINT8 *)(gpatch->columns) + (gpatch->columnofs[0])); if (!column->topdelta) { const UINT8 *source = (const UINT8 *)(column) + 3; HWR_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, (column->topdelta == 0xff ? 31 : source[0])); } - Z_Free(realpatch); } // centre screen if (fabsf((float)vid.width - (float)BASEVIDWIDTH * dupx) > 1.0E-36f) @@ -469,11 +470,11 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal fwidth = w; fheight = h; - if (fwidth > SHORT(gpatch->width)) - fwidth = SHORT(gpatch->width); + if (fwidth > gpatch->width) + fwidth = gpatch->width; - if (fheight > SHORT(gpatch->height)) - fheight = SHORT(gpatch->height); + if (fheight > gpatch->height) + fheight = gpatch->height; if (pscale != FRACUNIT) { @@ -503,17 +504,17 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].s = v[3].s = ((sx )/(float)SHORT(gpatch->width) )*gpatch->max_s; - if (sx + w > SHORT(gpatch->width)) - v[2].s = v[1].s = gpatch->max_s; + v[0].s = v[3].s = ((sx)/(float)(gpatch->width))*hwrPatch->max_s; + if (sx + w > gpatch->width) + v[2].s = v[1].s = hwrPatch->max_s; else - v[2].s = v[1].s = ((sx+w)/(float)SHORT(gpatch->width) )*gpatch->max_s; + v[2].s = v[1].s = ((sx+w)/(float)(gpatch->width))*hwrPatch->max_s; - v[0].t = v[1].t = ((sy )/(float)SHORT(gpatch->height))*gpatch->max_t; - if (sy + h > SHORT(gpatch->height)) - v[2].t = v[3].t = gpatch->max_t; + v[0].t = v[1].t = ((sy)/(float)(gpatch->height))*hwrPatch->max_t; + if (sy + h > gpatch->height) + v[2].t = v[3].t = hwrPatch->max_t; else - v[2].t = v[3].t = ((sy+h)/(float)SHORT(gpatch->height))*gpatch->max_t; + v[2].t = v[3].t = ((sy+h)/(float)(gpatch->height))*hwrPatch->max_t; flags = PF_Translucent|PF_NoDepthTest; @@ -541,7 +542,7 @@ void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscal void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) { FOutVector v[4]; - const GLPatch_t *patch; + const patch_t *patch; // make pic ready in hardware cache patch = HWR_GetPic(lumpnum); @@ -558,10 +559,10 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; - v[0].s = v[3].s = 0; - v[2].s = v[1].s = patch->max_s; - v[0].t = v[1].t = 0; - v[2].t = v[3].t = patch->max_t; + v[0].s = v[3].s = 0; + v[2].s = v[1].s = ((GLPatch_t *)patch->hardware)->max_s; + v[0].t = v[1].t = 0; + v[2].t = v[3].t = ((GLPatch_t *)patch->hardware)->max_t; //Hurdler: Boris, the same comment as above... but maybe for pics @@ -570,7 +571,7 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum) // But then, the question is: why not 0 instead of PF_Masked ? // or maybe PF_Environment ??? (like what I said above) // BP: PF_Environment don't change anything ! and 0 is undifined - HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest | PF_Clip | PF_NoZClip); + HWD.pfnDrawPolygon(NULL, v, 4, PF_Translucent | PF_NoDepthTest); } // ========================================================================== @@ -934,7 +935,7 @@ void HWR_DrawViewBorder(INT32 clearlines) INT32 top, side; INT32 baseviewwidth, baseviewheight; INT32 basewindowx, basewindowy; - GLPatch_t *patch; + patch_t *patch; // if (gl_viewwidth == vid.width) // return; diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index aaa41e86f4a2f0a6daa9d4378c8fc1edc717f736..de17f97d255509d6b335fd26ac378e577ab1649e 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -42,6 +42,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags); EXPORT void HWRAPI(ClearBuffer) (FBOOLEAN ColorMask, FBOOLEAN DepthMask, FRGBAFloat *ClearColor); EXPORT void HWRAPI(SetTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(UpdateTexture) (FTextureInfo *TexInfo); +EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *TexInfo); EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height, INT32 dst_stride, UINT16 *dst_data); EXPORT void HWRAPI(GClipRect) (INT32 minx, INT32 miny, INT32 maxx, INT32 maxy, float nearclip); EXPORT void HWRAPI(ClearMipMapCache) (void); @@ -70,7 +71,7 @@ EXPORT void HWRAPI(PostImgRedraw) (float points[SCREENVERTS][SCREENVERTS][2]); // jimita EXPORT boolean HWRAPI(CompileShaders) (void); EXPORT void HWRAPI(CleanShaders) (void); -EXPORT void HWRAPI(SetShader) (int shader); +EXPORT void HWRAPI(SetShader) (int type); EXPORT void HWRAPI(UnSetShader) (void); EXPORT void HWRAPI(SetShaderInfo) (hwdshaderinfo_t info, INT32 value); @@ -95,6 +96,7 @@ struct hwdriver_s ClearBuffer pfnClearBuffer; SetTexture pfnSetTexture; UpdateTexture pfnUpdateTexture; + DeleteTexture pfnDeleteTexture; ReadRect pfnReadRect; GClipRect pfnGClipRect; ClearMipMapCache pfnClearMipMapCache; diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 6ede8448bf88cc6ee2b9a7083546e2b2e059e904..112b241ef2a04375012821711bbd9fe7d5714806 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -62,19 +62,32 @@ typedef struct typedef struct gl_vissprite_s { float x1, x2; - float tz, ty; + float z1, z2; + float gz, gzt; + + float tz; float tracertz; // for MF2_LINKDRAW sprites, this contains tracer's tz for use in sorting - //lumpnum_t patchlumpnum; - GLPatch_t *gpatch; - boolean flip; - UINT8 translucency; //alpha level 0-255 - mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. + + float scale; + float shadowheight, shadowscale; + + float spritexscale, spriteyscale; + float spritexoffset, spriteyoffset; + + UINT32 renderflags; + UINT8 rotateflags; + + boolean flip, vflip; boolean precip; // Tails 08-25-2002 - boolean vflip; - //Hurdler: 25/04/2000: now support colormap in hardware mode + boolean rotated; + UINT8 translucency; //alpha level 0-255 + + //Hurdler: 25/04/2000: now support colormap in hardware mode UINT8 *colormap; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing - float z1, z2; + + patch_t *gpatch; + mobj_t *mobj; // NOTE: This is a precipmobj_t if precip is true !!! Watch out. } gl_vissprite_t; // -------- @@ -86,25 +99,35 @@ extern size_t addsubsector; void HWR_InitPolyPool(void); void HWR_FreePolyPool(void); +void HWR_FreeExtraSubsectors(void); + // -------- // hw_cache.c // -------- -void HWR_InitTextureCache(void); -void HWR_FreeTextureCache(void); -void HWR_FreeMipmapCache(void); -void HWR_FreeExtraSubsectors(void); +void HWR_InitMapTextures(void); +void HWR_LoadMapTextures(size_t pnumtextures); +void HWR_FreeMapTextures(void); + +patch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump); +patch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum); + +void HWR_GetPatch(patch_t *patch); +void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap); +void HWR_GetFadeMask(lumpnum_t fademasklumpnum); +patch_t *HWR_GetPic(lumpnum_t lumpnum); +GLMapTexture_t *HWR_GetTexture(INT32 tex); void HWR_GetLevelFlat(levelflat_t *levelflat); void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum); -GLMapTexture_t *HWR_GetTexture(INT32 tex); -void HWR_GetPatch(GLPatch_t *gpatch); -void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap); + +void HWR_FreeTexture(patch_t *patch); +void HWR_FreeTextureColormaps(patch_t *patch); +void HWR_ClearAllTextures(void); +void HWR_FreeColormapCache(void); void HWR_UnlockCachedPatch(GLPatch_t *gpatch); -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); -void HWR_GetFadeMask(lumpnum_t fademasklumpnum); + // -------- // hw_draw.c diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 32c2d550d4355b02b039bb2a8ee708b9afd17c51..987d70c69e22b293bb8d07cce5ce10520b5d387e 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -35,8 +35,7 @@ #define DL_HIGH_QUALITY //#define STATICLIGHT //Hurdler: TODO! -//#define LIGHTMAPFLAGS (PF_Masked|PF_Clip|PF_NoAlphaTest) // debug see overdraw -#define LIGHTMAPFLAGS (PF_Modulated|PF_Additive|PF_Clip) +#define LIGHTMAPFLAGS (PF_Modulated|PF_AdditiveSource) #ifdef ALAM_LIGHTING static dynlights_t view_dynlights[2]; // 2 players in splitscreen mode @@ -1056,7 +1055,7 @@ void HWR_DoCoronasLighting(FOutVector *outVerts, gl_vissprite_t *spr) HWR_GetPic(coronalumpnum); /// \todo use different coronas - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Clip | PF_Corona | PF_NoDepthTest); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_Corona | PF_NoDepthTest); } } #endif @@ -1144,7 +1143,7 @@ void HWR_DrawCoronas(void) light[3].y = cy+size*1.33f; light[3].s = 0.0f; light[3].t = 1.0f; - HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_Additive | PF_Clip | PF_NoDepthTest | PF_Corona); + HWD.pfnDrawPolygon (&Surf, light, 4, PF_Modulated | PF_AdditiveSource | PF_NoDepthTest | PF_Corona); } } #endif diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4268556e3b02508e8ee25ce04caad0ac78824e7a..2a694b95f2670e9c2054702eaf933472796a2cad 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -25,6 +25,7 @@ #include "../p_local.h" #include "../p_setup.h" #include "../r_local.h" +#include "../r_patch.h" #include "../r_picformats.h" #include "../r_bsp.h" #include "../d_clisrv.h" @@ -163,9 +164,11 @@ int ps_hw_numcolors = 0; int ps_hw_batchsorttime = 0; int ps_hw_batchdrawtime = 0; +boolean gl_init = false; +boolean gl_maploaded = false; +boolean gl_sessioncommandsadded = false; boolean gl_shadersavailable = true; - // ========================================================================== // Lighting // ========================================================================== @@ -693,101 +696,73 @@ static void HWR_RenderSkyPlane(extrasubsector_t *xsub, fixed_t fixedheight) v3d->z = pv->y; } - HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, - PF_Clip|PF_Invisible|PF_NoTexture|PF_Occlude); + HWD.pfnDrawPolygon(NULL, planeVerts, nrPlaneVerts, PF_Invisible|PF_NoTexture|PF_Occlude); } #endif //polysky #endif //doplanes -/* - wallVerts order is : - 3--2 - | /| - |/ | - 0--1 -*/ -#ifdef WALLSPLATS -static void HWR_DrawSegsSplats(FSurfaceInfo * pSurf) +FBITFIELD HWR_GetBlendModeFlag(INT32 ast) { - FOutVector wallVerts[4]; - wallsplat_t *splat; - GLPatch_t *gpatch; - fixed_t i; - // seg bbox - fixed_t segbbox[4]; - - M_ClearBox(segbbox); - M_AddToBox(segbbox, - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->x), - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv1)->y)); - M_AddToBox(segbbox, - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->x), - FLOAT_TO_FIXED(((polyvertex_t *)gl_curline->pv2)->y)); - - splat = (wallsplat_t *)gl_curline->linedef->splats; - for (; splat; splat = splat->next) - { - //BP: don't draw splat extern to this seg - // this is quick fix best is explain in logboris.txt at 12-4-2000 - if (!M_PointInBox(segbbox,splat->v1.x,splat->v1.y) && !M_PointInBox(segbbox,splat->v2.x,splat->v2.y)) - continue; - - gpatch = W_CachePatchNum(splat->patch, PU_PATCH); - HWR_GetPatch(gpatch); - - wallVerts[0].x = wallVerts[3].x = FIXED_TO_FLOAT(splat->v1.x); - wallVerts[0].z = wallVerts[3].z = FIXED_TO_FLOAT(splat->v1.y); - wallVerts[2].x = wallVerts[1].x = FIXED_TO_FLOAT(splat->v2.x); - wallVerts[2].z = wallVerts[1].z = FIXED_TO_FLOAT(splat->v2.y); + switch (ast) + { + case AST_ADD: + return PF_Additive; + case AST_SUBTRACT: + return PF_Subtractive; + case AST_REVERSESUBTRACT: + return PF_ReverseSubtract; + case AST_MODULATE: + return PF_Multiplicative; + default: + return PF_Translucent; + } - i = splat->top; - if (splat->yoffset) - i += *splat->yoffset; + return 0; +} - wallVerts[2].y = wallVerts[3].y = FIXED_TO_FLOAT(i)+(gpatch->height>>1); - wallVerts[0].y = wallVerts[1].y = FIXED_TO_FLOAT(i)-(gpatch->height>>1); +UINT8 HWR_GetTranstableAlpha(INT32 transtablenum) +{ + transtablenum = max(min(transtablenum, tr_trans90), 0); - wallVerts[3].s = wallVerts[3].t = wallVerts[2].s = wallVerts[0].t = 0.0f; - wallVerts[1].s = wallVerts[1].t = wallVerts[2].t = wallVerts[0].s = 1.0f; + switch (transtablenum) + { + case 0 : return 0xff; + case tr_trans10 : return 0xe6; + case tr_trans20 : return 0xcc; + case tr_trans30 : return 0xb3; + case tr_trans40 : return 0x99; + case tr_trans50 : return 0x80; + case tr_trans60 : return 0x66; + case tr_trans70 : return 0x4c; + case tr_trans80 : return 0x33; + case tr_trans90 : return 0x19; + } - switch (splat->flags & SPLATDRAWMODE_MASK) - { - case SPLATDRAWMODE_OPAQUE : - pSurf.PolyColor.s.alpha = 0xff; - i = PF_Translucent; - break; - case SPLATDRAWMODE_TRANS : - pSurf.PolyColor.s.alpha = 128; - i = PF_Translucent; - break; - case SPLATDRAWMODE_SHADE : - pSurf.PolyColor.s.alpha = 0xff; - i = PF_Substractive; - break; - } + return 0xff; +} - HWD.pfnSetShader(SHADER_WALL); // wall shader - HWD.pfnDrawPolygon(&pSurf, wallVerts, 4, i|PF_Modulated|PF_Decal); +FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf) +{ + if (!transtablenum) + { + pSurf->PolyColor.s.alpha = 0xff; + return PF_Masked; } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); + return HWR_GetBlendModeFlag(style); } -#endif FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf) { - switch (transtablenum) + if (!transtablenum) { - case 0 : pSurf->PolyColor.s.alpha = 0x00;return PF_Masked; - case tr_trans10 : pSurf->PolyColor.s.alpha = 0xe6;return PF_Translucent; - case tr_trans20 : pSurf->PolyColor.s.alpha = 0xcc;return PF_Translucent; - case tr_trans30 : pSurf->PolyColor.s.alpha = 0xb3;return PF_Translucent; - case tr_trans40 : pSurf->PolyColor.s.alpha = 0x99;return PF_Translucent; - case tr_trans50 : pSurf->PolyColor.s.alpha = 0x80;return PF_Translucent; - case tr_trans60 : pSurf->PolyColor.s.alpha = 0x66;return PF_Translucent; - case tr_trans70 : pSurf->PolyColor.s.alpha = 0x4c;return PF_Translucent; - case tr_trans80 : pSurf->PolyColor.s.alpha = 0x33;return PF_Translucent; - case tr_trans90 : pSurf->PolyColor.s.alpha = 0x19;return PF_Translucent; + pSurf->PolyColor.s.alpha = 0x00; + return PF_Masked; } + + pSurf->PolyColor.s.alpha = HWR_GetTranstableAlpha(transtablenum); return PF_Translucent; } @@ -797,19 +772,21 @@ static void HWR_AddTransparentWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, I // Wall generation from subsector segs // ========================================================================== +/* + wallVerts order is : + 3--2 + | /| + |/ | + 0--1 +*/ + // // HWR_ProjectWall // static void HWR_ProjectWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blendmode, INT32 lightlevel, extracolormap_t *wallcolormap) { HWR_Lighting(pSurf, lightlevel, wallcolormap); - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode|PF_Modulated|PF_Occlude, SHADER_WALL, false); // wall shader - -#ifdef WALLSPLATS - if (gl_curline->linedef->splats && cv_splats.value) - HWR_DrawSegsSplats(pSurf); -#endif } // ========================================================================== @@ -1608,7 +1585,7 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom //Hurdler: 3d-floors test - if (gl_frontsector && gl_backsector && gl_frontsector->tag != gl_backsector->tag && (gl_backsector->ffloors || gl_frontsector->ffloors)) + if (gl_frontsector && gl_backsector && !Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags) && (gl_backsector->ffloors || gl_frontsector->ffloors)) { ffloor_t * rover; fixed_t highcut = 0, lowcut = 0; @@ -1625,6 +1602,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { for (rover = gl_backsector->ffloors; rover; rover = rover->next) { + boolean bothsides = false; + // Skip if it exists on both sectors. + ffloor_t * r2; + for (r2 = gl_frontsector->ffloors; r2; r2 = r2->next) + if (rover->master == r2->master) + { + bothsides = true; + break; + } + + if (bothsides) continue; + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) continue; if (!(rover->flags & FF_ALLSIDES) && rover->flags & FF_INVERTSIDES) @@ -1759,6 +1748,18 @@ static void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom { for (rover = gl_frontsector->ffloors; rover; rover = rover->next) { + boolean bothsides = false; + // Skip if it exists on both sectors. + ffloor_t * r2; + for (r2 = gl_backsector->ffloors; r2; r2 = r2->next) + if (rover->master == r2->master) + { + bothsides = true; + break; + } + + if (bothsides) continue; + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERSIDES)) continue; if (!(rover->flags & FF_ALLSIDES || rover->flags & FF_INVERTSIDES)) @@ -2384,7 +2385,7 @@ static void HWR_AddLine(seg_t * line) if (!line->polyseg && !line->sidedef->midtexture && ((!gl_frontsector->ffloors && !gl_backsector->ffloors) - || (gl_frontsector->tag == gl_backsector->tag))) + || Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags))) return; // line is empty, don't even bother // treat like wide open window instead HWR_ProcessSeg(); // Doesn't need arguments because they're defined globally :D @@ -2423,7 +2424,7 @@ static void HWR_AddLine(seg_t * line) if (!line->polyseg && !line->sidedef->midtexture && ((!gl_frontsector->ffloors && !gl_backsector->ffloors) - || (gl_frontsector->tag == gl_backsector->tag))) + || Tag_Compare(&gl_frontsector->tags, &gl_backsector->tags))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead @@ -2839,10 +2840,10 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, if (blendmode & PF_Translucent) { Surf.PolyColor.s.alpha = (UINT8)alpha; - blendmode |= PF_Modulated|PF_Occlude|PF_Clip; + blendmode |= PF_Modulated|PF_Occlude; } else - blendmode |= PF_Masked|PF_Modulated|PF_Clip; + blendmode |= PF_Masked|PF_Modulated; HWR_ProcessPolygon(&Surf, planeVerts, nrPlaneVerts, blendmode, SHADER_FLOOR, false); // floor shader } @@ -3512,7 +3513,7 @@ static void HWR_LinkDrawHackFinish(void) { // draw sprite shape, only to z-buffer HWR_GetPatch(linkdrawlist[i].spr->gpatch); - HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible|PF_Clip, 0, false); + HWR_ProcessPolygon(&surf, linkdrawlist[i].verts, 4, PF_Translucent|PF_Occlude|PF_Invisible, 0, false); } // reset list linkdrawcount = 0; @@ -3560,7 +3561,7 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { - GLPatch_t *gpatch; + patch_t *gpatch; FOutVector shadowVerts[4]; FSurfaceInfo sSurf; float fscale; float fx; float fy; float offset; @@ -3586,12 +3587,12 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) if (alpha >= 255) return; alpha = 255 - alpha; - gpatch = (GLPatch_t *)W_CachePatchName("DSHADOW", PU_CACHE); - if (!(gpatch && gpatch->mipmap->format)) return; + gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE); + if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return; HWR_GetPatch(gpatch); scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - scalemul = FixedMul(scalemul, (thing->radius*2) / SHORT(gpatch->height)); + scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); fx = FIXED_TO_FLOAT(thing->x); @@ -3603,9 +3604,9 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) // 0--1 if (thing && fabsf(fscale - 1.0f) > 1.0E-36f) - offset = (SHORT(gpatch->height)/2) * fscale; + offset = ((gpatch->height)/2) * fscale; else - offset = (float)(SHORT(gpatch->height)/2); + offset = (float)((gpatch->height)/2); shadowVerts[2].x = shadowVerts[3].x = fx + offset; shadowVerts[1].x = shadowVerts[0].x = fx - offset; @@ -3635,28 +3636,29 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) } shadowVerts[0].s = shadowVerts[3].s = 0; - shadowVerts[2].s = shadowVerts[1].s = gpatch->max_s; + shadowVerts[2].s = shadowVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; shadowVerts[3].t = shadowVerts[2].t = 0; - shadowVerts[0].t = shadowVerts[1].t = gpatch->max_t; + shadowVerts[0].t = shadowVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; - if (thing->subsector->sector->numlights) + if (!(thing->renderflags & RF_NOCOLORMAPS)) { - light = R_GetPlaneLight(thing->subsector->sector, groundz, false); // Always use the light at the top instead of whatever I was doing before + if (thing->subsector->sector->numlights) + { + // Always use the light at the top instead of whatever I was doing before + light = R_GetPlaneLight(thing->subsector->sector, groundz, false); - if (*thing->subsector->sector->lightlist[light].extra_colormap) - colormap = *thing->subsector->sector->lightlist[light].extra_colormap; - } - else - { - if (thing->subsector->sector->extra_colormap) + if (*thing->subsector->sector->lightlist[light].extra_colormap) + colormap = *thing->subsector->sector->lightlist[light].extra_colormap; + } + else if (thing->subsector->sector->extra_colormap) colormap = thing->subsector->sector->extra_colormap; } HWR_Lighting(&sSurf, 0, colormap); sSurf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&sSurf, shadowVerts, 4, PF_Translucent|PF_Modulated, SHADER_SPRITE, false); // sprite shader } // This is expecting a pointer to an array containing 4 wallVerts for a sprite @@ -3676,17 +3678,17 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts // X, Y, AND Z need to be manipulated for the polys to rotate around the // origin, because of how the origin setting works I believe that should // be mobj->z or mobj->z + mobj->height - wallVerts[2].y = wallVerts[3].y = (spr->ty - basey) * gl_viewludsin + basey; + wallVerts[2].y = wallVerts[3].y = (spr->gzt - basey) * gl_viewludsin + basey; wallVerts[0].y = wallVerts[1].y = (lowy - basey) * gl_viewludsin + basey; // translate back to be around 0 before translating back - wallVerts[3].x += ((spr->ty - basey) * gl_viewludcos) * gl_viewcos; - wallVerts[2].x += ((spr->ty - basey) * gl_viewludcos) * gl_viewcos; + wallVerts[3].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos; + wallVerts[2].x += ((spr->gzt - basey) * gl_viewludcos) * gl_viewcos; wallVerts[0].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos; wallVerts[1].x += ((lowy - basey) * gl_viewludcos) * gl_viewcos; - wallVerts[3].z += ((spr->ty - basey) * gl_viewludcos) * gl_viewsin; - wallVerts[2].z += ((spr->ty - basey) * gl_viewludcos) * gl_viewsin; + wallVerts[3].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin; + wallVerts[2].z += ((spr->gzt - basey) * gl_viewludcos) * gl_viewsin; wallVerts[0].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin; wallVerts[1].z += ((lowy - basey) * gl_viewludcos) * gl_viewsin; @@ -3695,17 +3697,17 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts static void HWR_SplitSprite(gl_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; FOutVector baseWallVerts[4]; // This is what the verts should end up as - GLPatch_t *gpatch; + patch_t *gpatch; FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); - extracolormap_t *colormap; + extracolormap_t *colormap = NULL; FUINT lightlevel; + boolean lightset = true; FBITFIELD blend = 0; FBITFIELD occlusion; boolean use_linkdraw_hack = false; + boolean splat = R_ThingIsFloorSprite(spr->mobj); UINT8 alpha; INT32 i; @@ -3721,12 +3723,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) fixed_t temp; fixed_t v1x, v1y, v2x, v2y; - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); - - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; // cache the patch in the graphics card memory //12/12/99: Hurdler: same comment as above (for md2) @@ -3738,11 +3735,8 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) baseWallVerts[0].z = baseWallVerts[3].z = spr->z1; baseWallVerts[1].z = baseWallVerts[2].z = spr->z2; - baseWallVerts[2].y = baseWallVerts[3].y = spr->ty; - if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) - baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height * this_scale; - else - baseWallVerts[0].y = baseWallVerts[1].y = spr->ty - gpatch->height; + baseWallVerts[2].y = baseWallVerts[3].y = spr->gzt; + baseWallVerts[0].y = baseWallVerts[1].y = spr->gz; v1x = FLOAT_TO_FIXED(spr->x1); v1y = FLOAT_TO_FIXED(spr->z1); @@ -3751,39 +3745,42 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) if (spr->flip) { - baseWallVerts[0].s = baseWallVerts[3].s = gpatch->max_s; + baseWallVerts[0].s = baseWallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s; baseWallVerts[2].s = baseWallVerts[1].s = 0; } else { baseWallVerts[0].s = baseWallVerts[3].s = 0; - baseWallVerts[2].s = baseWallVerts[1].s = gpatch->max_s; + baseWallVerts[2].s = baseWallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - baseWallVerts[3].t = baseWallVerts[2].t = gpatch->max_t; + baseWallVerts[3].t = baseWallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t; baseWallVerts[0].t = baseWallVerts[1].t = 0; } else { baseWallVerts[3].t = baseWallVerts[2].t = 0; - baseWallVerts[0].t = baseWallVerts[1].t = gpatch->max_t; + baseWallVerts[0].t = baseWallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } - // if it has a dispoffset, push it a little towards the camera - if (spr->dispoffset) { - float co = -gl_viewcos*(0.05f*spr->dispoffset); - float si = -gl_viewsin*(0.05f*spr->dispoffset); - baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; - baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; - baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; - baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; - } + if (!splat) + { + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gl_viewcos*(0.05f*spr->dispoffset); + float si = -gl_viewsin*(0.05f*spr->dispoffset); + baseWallVerts[0].z = baseWallVerts[3].z = baseWallVerts[0].z+si; + baseWallVerts[1].z = baseWallVerts[2].z = baseWallVerts[1].z+si; + baseWallVerts[0].x = baseWallVerts[3].x = baseWallVerts[0].x+co; + baseWallVerts[1].x = baseWallVerts[2].x = baseWallVerts[1].x+co; + } - // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, baseWallVerts, false); + } realtop = top = baseWallVerts[3].y; realbot = bot = baseWallVerts[0].y; @@ -3815,10 +3812,15 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -3826,7 +3828,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|occlusion; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; if (!occlusion) use_linkdraw_hack = true; } @@ -3834,21 +3836,28 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // Start with the lightlevel and colormap from the top of the sprite lightlevel = *list[sector->numlights - 1].lightlevel; - colormap = *list[sector->numlights - 1].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[sector->numlights - 1].extra_colormap; + i = 0; temp = FLOAT_TO_FIXED(realtop); - if (spr->mobj->frame & FF_FULLBRIGHT) + if (R_ThingIsFullBright(spr->mobj)) lightlevel = 255; + else if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else + lightset = false; for (i = 1; i < sector->numlights; i++) { fixed_t h = P_GetLightZAt(§or->lightlist[i], spr->mobj->x, spr->mobj->y); if (h <= temp) { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!lightset) lightlevel = *list[i-1].lightlevel > 255 ? 255 : *list[i-1].lightlevel; - colormap = *list[i-1].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[i-1].extra_colormap; break; } } @@ -3861,9 +3870,10 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // even if we aren't changing colormap or lightlevel, we still need to continue drawing down the sprite if (!(list[i].flags & FF_NOSHADE) && (list[i].flags & FF_CUTSPRITES)) { - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!lightset) lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel; - colormap = *list[i].extra_colormap; + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *list[i].extra_colormap; } if (i + 1 < sector->numlights) @@ -3930,7 +3940,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3959,7 +3969,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) Surf.PolyColor.s.alpha = alpha; - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -3972,16 +3982,10 @@ static void HWR_SplitSprite(gl_vissprite_t *spr) // -----------------+ static void HWR_DrawSprite(gl_vissprite_t *spr) { - float this_scale = 1.0f; FOutVector wallVerts[4]; - GLPatch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; - const boolean hires = (spr->mobj && spr->mobj->skin && ((skin_t *)spr->mobj->skin)->flags & SF_HIRES); - //const boolean papersprite = (spr->mobj && (spr->mobj->frame & FF_PAPERSPRITE)); - if (spr->mobj) - this_scale = FIXED_TO_FLOAT(spr->mobj->scale); - if (hires) - this_scale = this_scale * FIXED_TO_FLOAT(((skin_t *)spr->mobj->skin)->highresscale); + const boolean splat = R_ThingIsFloorSprite(spr->mobj); if (!spr->mobj) return; @@ -3989,7 +3993,7 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) if (!spr->mobj->subsector) return; - if (spr->mobj->subsector->sector->numlights) + if (spr->mobj->subsector->sector->numlights && !splat) { HWR_SplitSprite(spr); return; @@ -4001,7 +4005,7 @@ static void HWR_DrawSprite(gl_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 = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; #ifdef ALAM_LIGHTING if (!(spr->mobj->flags2 & MF2_DEBRIS) && (spr->mobj->sprite != SPR_PLAY || @@ -4016,37 +4020,144 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // |/ | // 0--1 - // these were already scaled in HWR_ProjectSprite - wallVerts[0].x = wallVerts[3].x = spr->x1; - wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[2].y = wallVerts[3].y = spr->ty; - if (spr->mobj && fabsf(this_scale - 1.0f) > 1.0E-36f) - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height * this_scale; + if (splat) + { + F2DCoord verts[4]; + F2DCoord rotated[4]; + + angle_t angle; + float ca, sa; + float w, h; + float xscale, yscale; + float xoffset, yoffset; + float leftoffset, topoffset; + float scale = spr->scale; + float zoffset = (P_MobjFlip(spr->mobj) * 0.05f); + pslope_t *splatslope = NULL; + INT32 i; + + renderflags_t renderflags = spr->renderflags; + if (renderflags & RF_SHADOWEFFECTS) + scale *= spr->shadowscale; + + if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) + angle = spr->mobj->angle; + else + angle = viewangle; + + if (!spr->rotated) + angle += spr->mobj->rollangle; + + angle = -angle; + angle += ANGLE_90; + + topoffset = spr->spriteyoffset; + leftoffset = spr->spritexoffset; + if (spr->flip) + leftoffset = ((float)gpatch->width - leftoffset); + + xscale = spr->scale * spr->spritexscale; + yscale = spr->scale * spr->spriteyscale; + + xoffset = leftoffset * xscale; + yoffset = topoffset * yscale; + + w = (float)gpatch->width * xscale; + h = (float)gpatch->height * yscale; + + // Set positions + + // 3--2 + // | | + // 0--1 + + verts[3].x = -xoffset; + verts[3].y = yoffset; + + verts[2].x = w - xoffset; + verts[2].y = yoffset; + + verts[1].x = w - xoffset; + verts[1].y = -h + yoffset; + + verts[0].x = -xoffset; + verts[0].y = -h + yoffset; + + ca = FIXED_TO_FLOAT(FINECOSINE((-angle)>>ANGLETOFINESHIFT)); + sa = FIXED_TO_FLOAT(FINESINE((-angle)>>ANGLETOFINESHIFT)); + + // Rotate + for (i = 0; i < 4; i++) + { + rotated[i].x = (verts[i].x * ca) - (verts[i].y * sa); + rotated[i].y = (verts[i].x * sa) + (verts[i].y * ca); + } + + // Translate + for (i = 0; i < 4; i++) + { + wallVerts[i].x = rotated[i].x + FIXED_TO_FLOAT(spr->mobj->x); + wallVerts[i].z = rotated[i].y + FIXED_TO_FLOAT(spr->mobj->y); + } + + if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT)) + { + pslope_t *standingslope = spr->mobj->standingslope; // The slope that the object is standing on. + + // The slope that was defined for the sprite. + if (renderflags & RF_SLOPESPLAT) + splatslope = spr->mobj->floorspriteslope; + + if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT)) + splatslope = standingslope; + } + + // Set vertical position + if (splatslope) + { + for (i = 0; i < 4; i++) + { + fixed_t slopez = P_GetSlopeZAt(splatslope, FLOAT_TO_FIXED(wallVerts[i].x), FLOAT_TO_FIXED(wallVerts[i].z)); + wallVerts[i].y = FIXED_TO_FLOAT(slopez) + zoffset; + } + } + else + { + for (i = 0; i < 4; i++) + wallVerts[i].y = FIXED_TO_FLOAT(spr->mobj->z) + zoffset; + } + } else - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + { + // these were already scaled in HWR_ProjectSprite + wallVerts[0].x = wallVerts[3].x = spr->x1; + wallVerts[2].x = wallVerts[1].x = spr->x2; + wallVerts[2].y = wallVerts[3].y = spr->gzt; + wallVerts[0].y = wallVerts[1].y = spr->gz; - // make a wall polygon (with 2 triangles), using the floor/ceiling heights, - // and the 2d map coords of start/end vertices - wallVerts[0].z = wallVerts[3].z = spr->z1; - wallVerts[1].z = wallVerts[2].z = spr->z2; + // make a wall polygon (with 2 triangles), using the floor/ceiling heights, + // and the 2d map coords of start/end vertices + wallVerts[0].z = wallVerts[3].z = spr->z1; + wallVerts[1].z = wallVerts[2].z = spr->z2; + } if (spr->flip) { - wallVerts[0].s = wallVerts[3].s = gpatch->max_s; + wallVerts[0].s = wallVerts[3].s = ((GLPatch_t *)gpatch->hardware)->max_s; wallVerts[2].s = wallVerts[1].s = 0; }else{ wallVerts[0].s = wallVerts[3].s = 0; - wallVerts[2].s = wallVerts[1].s = gpatch->max_s; + wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; } // flip the texture coords (look familiar?) if (spr->vflip) { - wallVerts[3].t = wallVerts[2].t = gpatch->max_t; + wallVerts[3].t = wallVerts[2].t = ((GLPatch_t *)gpatch->hardware)->max_t; wallVerts[0].t = wallVerts[1].t = 0; }else{ wallVerts[3].t = wallVerts[2].t = 0; - wallVerts[0].t = wallVerts[1].t = gpatch->max_t; + wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; } // cache the patch in the graphics card memory @@ -4054,18 +4165,21 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) //Hurdler: 25/04/2000: now support colormap in hardware mode HWR_GetMappedPatch(gpatch, spr->colormap); - // if it has a dispoffset, push it a little towards the camera - if (spr->dispoffset) { - float co = -gl_viewcos*(0.05f*spr->dispoffset); - float si = -gl_viewsin*(0.05f*spr->dispoffset); - wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; - wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; - wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; - wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; - } + if (!splat) + { + // if it has a dispoffset, push it a little towards the camera + if (spr->dispoffset) { + float co = -gl_viewcos*(0.05f*spr->dispoffset); + float si = -gl_viewsin*(0.05f*spr->dispoffset); + wallVerts[0].z = wallVerts[3].z = wallVerts[0].z+si; + wallVerts[1].z = wallVerts[2].z = wallVerts[1].z+si; + wallVerts[0].x = wallVerts[3].x = wallVerts[0].x+co; + wallVerts[1].x = wallVerts[2].x = wallVerts[1].x+co; + } - // Let dispoffset work first since this adjust each vertex - HWR_RotateSpritePolyToAim(spr, wallVerts, false); + // Let dispoffset work first since this adjust each vertex + HWR_RotateSpritePolyToAim(spr, wallVerts, false); + } // This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black. // sprite lighting by modulating the RGB components @@ -4074,10 +4188,31 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // colormap test { sector_t *sector = spr->mobj->subsector->sector; - UINT8 lightlevel = 255; - extracolormap_t *colormap = sector->extra_colormap; + UINT8 lightlevel = 0; + boolean lightset = true; + extracolormap_t *colormap = NULL; + + if (R_ThingIsFullBright(spr->mobj)) + lightlevel = 255; + else if (R_ThingIsFullDark(spr->mobj)) + lightlevel = 0; + else + lightset = false; + + if (!(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = sector->extra_colormap; + + if (splat && sector->numlights) + { + INT32 light = R_GetPlaneLight(sector, spr->mobj->z, false); - if (!(spr->mobj->frame & FF_FULLBRIGHT)) + if (!lightset) + lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; + + if (*sector->lightlist[light].extra_colormap && !(spr->mobj->renderflags & RF_NOCOLORMAPS)) + colormap = *sector->lightlist[light].extra_colormap; + } + else if (!lightset) lightlevel = sector->lightlevel > 255 ? 255 : sector->lightlevel; HWR_Lighting(&Surf, lightlevel, colormap); @@ -4104,10 +4239,15 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) else if (spr->mobj->flags2 & MF2_SHADOW) { Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode); } else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + { + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); + } else { // BP: i agree that is little better in environement but it don't @@ -4115,11 +4255,23 @@ static void HWR_DrawSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|occlusion; + if (!occlusion) use_linkdraw_hack = true; + } + + if (spr->renderflags & RF_SHADOWEFFECTS) + { + INT32 alpha = Surf.PolyColor.s.alpha; + alpha -= ((INT32)(spr->shadowheight / 4.0f)) + 75; + if (alpha < 1) + return; + + Surf.PolyColor.s.alpha = (UINT8)(alpha); blend = PF_Translucent|occlusion; if (!occlusion) use_linkdraw_hack = true; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader if (use_linkdraw_hack) HWR_LinkDrawHackAdd(wallVerts, spr); @@ -4132,7 +4284,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) { FBITFIELD blend = 0; FOutVector wallVerts[4]; - GLPatch_t *gpatch; // sprite patch converted to hardware + patch_t *gpatch; // sprite patch converted to hardware FSurfaceInfo Surf; if (!spr->mobj) @@ -4142,7 +4294,7 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) return; // cache sprite graphics - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); + gpatch = spr->gpatch; // create the sprite billboard // @@ -4152,8 +4304,8 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // 0--1 wallVerts[0].x = wallVerts[3].x = spr->x1; wallVerts[2].x = wallVerts[1].x = spr->x2; - wallVerts[2].y = wallVerts[3].y = spr->ty; - wallVerts[0].y = wallVerts[1].y = spr->ty - gpatch->height; + wallVerts[2].y = wallVerts[3].y = spr->gzt; + wallVerts[0].y = wallVerts[1].y = spr->gz; // make a wall polygon (with 2 triangles), using the floor/ceiling heights, // and the 2d map coords of start/end vertices @@ -4164,10 +4316,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_RotateSpritePolyToAim(spr, wallVerts, true); wallVerts[0].s = wallVerts[3].s = 0; - wallVerts[2].s = wallVerts[1].s = gpatch->max_s; + wallVerts[2].s = wallVerts[1].s = ((GLPatch_t *)gpatch->hardware)->max_s; wallVerts[3].t = wallVerts[2].t = 0; - wallVerts[0].t = wallVerts[1].t = gpatch->max_t; + wallVerts[0].t = wallVerts[1].t = ((GLPatch_t *)gpatch->hardware)->max_t; // cache the patch in the graphics card memory //12/12/99: Hurdler: same comment as above (for md2) @@ -4182,9 +4334,8 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) if (sector->numlights) { - INT32 light; - - light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before + // Always use the light at the top instead of whatever I was doing before + INT32 light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); if (!(spr->mobj->frame & FF_FULLBRIGHT)) lightlevel = *sector->lightlist[light].lightlevel > 255 ? 255 : *sector->lightlist[light].lightlevel; @@ -4204,13 +4355,13 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) HWR_Lighting(&Surf, lightlevel, colormap); } - if (spr->mobj->flags2 & MF2_SHADOW) + if (spr->mobj->frame & FF_TRANSMASK) { - Surf.PolyColor.s.alpha = 0x40; - blend = PF_Translucent; + INT32 trans = (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT; + if (spr->mobj->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; + blend = HWR_SurfaceBlend(spr->mobj->blendmode, trans, &Surf); } - else if (spr->mobj->frame & FF_TRANSMASK) - blend = HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else { // BP: i agree that is little better in environement but it don't @@ -4218,10 +4369,10 @@ static inline void HWR_DrawPrecipitationSprite(gl_vissprite_t *spr) // Hurdler: PF_Environement would be cool, but we need to fix // the issue with the fog before Surf.PolyColor.s.alpha = 0xFF; - blend = PF_Translucent|PF_Occlude; + blend = HWR_GetBlendModeFlag(spr->mobj->blendmode)|PF_Occlude; } - HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated|PF_Clip, SHADER_SPRITE, false); // sprite shader + HWR_ProcessPolygon(&Surf, wallVerts, 4, blend|PF_Modulated, SHADER_SPRITE, false); // sprite shader } #endif @@ -4685,7 +4836,7 @@ static void HWR_DrawSprites(void) // (Other states probably don't matter. Here I left them same as in LinkDrawHackFinish) // Without this workaround the rest of the draw calls in this frame (including UI, screen texture) // can get drawn using an incorrect glBlendFunc, resulting in a occasional black screen. - HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Clip|PF_Masked); + HWD.pfnSetBlend(PF_Translucent|PF_Occlude|PF_Masked); } // -------------------------------------------------------------------------- @@ -4750,23 +4901,28 @@ static void HWR_ProjectSprite(mobj_t *thing) float tracertz = 0.0f; float x1, x2; float rightsin, rightcos; - float this_scale; + float this_scale, this_xscale, this_yscale; + float spritexscale, spriteyscale; + float shadowheight = 1.0f, shadowscale = 1.0f; float gz, gzt; spritedef_t *sprdef; spriteframe_t *sprframe; +#ifdef ROTSPRITE spriteinfo_t *sprinfo; +#endif md2_t *md2; size_t lumpoff; unsigned rot; UINT16 flip; - boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing)); boolean mirrored = thing->mirrored; - boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); + boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored); INT32 dispoffset; angle_t ang; INT32 heightsec, phs; - const boolean papersprite = (thing->frame & FF_PAPERSPRITE); + const boolean papersprite = R_ThingIsPaperSprite(thing); + const boolean splat = R_ThingIsFloorSprite(thing); angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle); float z1, z2; @@ -4780,9 +4936,14 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; + if (thing->spritexscale < 1 || thing->spriteyscale < 1) + return; + dispoffset = thing->info->dispoffset; this_scale = FIXED_TO_FLOAT(thing->scale); + spritexscale = FIXED_TO_FLOAT(thing->spritexscale); + spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); // transform the origin point tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx; @@ -4792,7 +4953,7 @@ static void HWR_ProjectSprite(mobj_t *thing) tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); // thing is behind view plane? - if (tz < ZCLIP_PLANE && !papersprite) + if (tz < ZCLIP_PLANE && !(papersprite || splat)) { if (cv_glmodels.value) //Yellow: Only MD2's dont disappear { @@ -4824,12 +4985,16 @@ static void HWR_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 } else { sprdef = &sprites[thing->sprite]; - sprinfo = NULL; +#ifdef ROTSPRITE + sprinfo = &spriteinfo[thing->sprite]; +#endif } if (rot >= sprdef->numframes) @@ -4839,7 +5004,9 @@ 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; +#ifdef ROTSPRITE + sprinfo = &spriteinfo[thing->sprite]; +#endif rot = thing->frame&FF_FRAMEMASK; thing->state->sprite = thing->sprite; thing->state->frame = thing->frame; @@ -4890,7 +5057,7 @@ 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); + this_scale *= FIXED_TO_FLOAT(((skin_t *)thing->skin)->highresscale); spr_width = spritecachedinfo[lumpoff].width; spr_height = spritecachedinfo[lumpoff].height; @@ -4898,24 +5065,42 @@ static void HWR_ProjectSprite(mobj_t *thing) spr_topoffset = spritecachedinfo[lumpoff].topoffset; #ifdef ROTSPRITE - if (thing->rollangle) + if (thing->rollangle + && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { rollangle = R_GetRollAngle(thing->rollangle); - if (!(sprframe->rotsprite.cached & (1<<rot))) - R_CacheRotSprite(thing->sprite, (thing->frame & FF_FRAMEMASK), sprinfo, sprframe, rot, flip); - rotsprite = sprframe->rotsprite.patch[rot][rollangle]; + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + if (rotsprite != NULL) { - spr_width = SHORT(rotsprite->width) << FRACBITS; - spr_height = SHORT(rotsprite->height) << FRACBITS; - spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; - spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; + spr_width = rotsprite->width << FRACBITS; + spr_height = rotsprite->height << FRACBITS; + spr_offset = rotsprite->leftoffset << FRACBITS; + spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_topoffset += FEETADJUST; + // flip -> rotate, not rotate -> flip flip = 0; } } #endif + if (thing->renderflags & RF_ABSOLUTEOFFSETS) + { + spr_offset = thing->spritexoffset; + spr_topoffset = thing->spriteyoffset; + } + else + { + SINT8 flipoffset = 1; + + if ((thing->renderflags & RF_FLIPOFFSETS) && flip) + flipoffset = -1; + + spr_offset += thing->spritexoffset * flipoffset; + spr_topoffset += thing->spriteyoffset * flipoffset; + } + if (papersprite) { rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT)); @@ -4929,15 +5114,36 @@ static void HWR_ProjectSprite(mobj_t *thing) flip = !flip != !hflip; + if (thing->renderflags & RF_SHADOWEFFECTS) + { + mobj_t *caster = thing->target; + + if (caster && !P_MobjWasRemoved(caster)) + { + fixed_t groundz = R_GetShadowZ(thing, NULL); + fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz); + + shadowheight = FIXED_TO_FLOAT(floordiff); + shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, caster->scale)); + + if (splat) + spritexscale *= shadowscale; + spriteyscale *= shadowscale; + } + } + + this_xscale = spritexscale * this_scale; + this_yscale = spriteyscale * this_scale; + if (flip) { - x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale); - x2 = (FIXED_TO_FLOAT(spr_offset) * this_scale); + x1 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); } else { - x1 = (FIXED_TO_FLOAT(spr_offset) * this_scale); - x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_scale); + x1 = (FIXED_TO_FLOAT(spr_offset) * this_xscale); + x2 = (FIXED_TO_FLOAT(spr_width - spr_offset) * this_xscale); } // test if too close @@ -4959,13 +5165,13 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spr_topoffset) * this_scale; - gzt = gz + FIXED_TO_FLOAT(spr_height) * this_scale; + gz = FIXED_TO_FLOAT(thing->z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); } else { - gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spr_topoffset) * this_scale; - gz = gzt - FIXED_TO_FLOAT(spr_height) * this_scale; + gzt = FIXED_TO_FLOAT(thing->z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); } if (thing->subsector->sector->cullheight) @@ -5022,20 +5228,39 @@ static void HWR_ProjectSprite(mobj_t *thing) vis = HWR_NewVisSprite(); vis->x1 = x1; vis->x2 = x2; + vis->z1 = z1; + vis->z2 = z2; + vis->tz = tz; // Keep tz for the simple sprite sorting that happens vis->tracertz = tracertz; + + vis->renderflags = thing->renderflags; + vis->rotateflags = sprframe->rotate; + + vis->shadowheight = shadowheight; + vis->shadowscale = shadowscale; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST - //vis->patchlumpnum = sprframe->lumppat[rot]; + vis->flip = flip; + + vis->scale = this_scale; + vis->spritexscale = spritexscale; + vis->spriteyscale = spriteyscale; + vis->spritexoffset = FIXED_TO_FLOAT(spr_offset); + vis->spriteyoffset = FIXED_TO_FLOAT(spr_topoffset); + + vis->rotated = false; + #ifdef ROTSPRITE if (rotsprite) - vis->gpatch = (GLPatch_t *)rotsprite; + { + vis->gpatch = (patch_t *)rotsprite; + vis->rotated = true; + } else #endif - vis->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); - vis->flip = flip; + vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); + vis->mobj = thing; - vis->z1 = z1; - vis->z2 = z2; //Hurdler: 25/04/2000: now support colormap in hardware mode if ((vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" @@ -5073,7 +5298,8 @@ static void HWR_ProjectSprite(mobj_t *thing) vis->colormap = colormaps; // set top/bottom coords - vis->ty = gzt; + vis->gzt = gzt; + vis->gz = gz; //CONS_Debug(DBG_RENDER, "------------------\nH: sprite : %d\nH: frame : %x\nH: type : %d\nH: sname : %s\n\n", // thing->sprite, thing->frame, thing->type, sprnames[thing->sprite]); @@ -5166,15 +5392,15 @@ 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->gpatch = (GLPatch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); + vis->gpatch = (patch_t *)W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); vis->flip = flip; vis->mobj = (mobj_t *)thing; vis->colormap = colormaps; // set top/bottom coords - vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); + vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); + vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; @@ -5556,6 +5782,20 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean trans->anglex = (float)(gl_aimingangle>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); } +// +// Sets the shader state. +// +static void HWR_SetShaderState(void) +{ + hwdshaderoption_t state = cv_glshaders.value; + + if (!cv_glallowshaders.value) + state = (cv_glshaders.value == HWD_SHADEROPTION_ON ? HWD_SHADEROPTION_NOCUSTOM : cv_glshaders.value); + + HWD.pfnSetSpecialState(HWD_SET_SHADERS, (INT32)state); + HWD.pfnSetShader(SHADER_DEFAULT); +} + // ========================================================================== // Same as rendering the player view, but from the skybox object // ========================================================================== @@ -5674,8 +5914,7 @@ void HWR_RenderSkyboxView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); validcount++; @@ -5889,8 +6128,7 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnSetTransform(&atransform); // Reset the shader state. - HWD.pfnSetSpecialState(HWD_SET_SHADERS, cv_glshaders.value); - HWD.pfnSetShader(SHADER_DEFAULT); + HWR_SetShaderState(); ps_numbspcalls = 0; ps_numpolyobjects = 0; @@ -5981,13 +6219,41 @@ void HWR_RenderPlayerView(INT32 viewnumber, player_t *player) HWD.pfnGClipRect(0, 0, vid.width, vid.height, NZCLIP_PLANE); } +void HWR_LoadLevel(void) +{ + // Lactozilla (December 8, 2019) + // Level setup used to free EVERY mipmap from memory. + // Even mipmaps that aren't related to level textures. + // Presumably, the hardware render code used to store textures as level data. + // Meaning, they had memory allocated and marked with the PU_LEVEL tag. + // Level textures are only reloaded after R_LoadTextures, which is + // when the texture list is loaded. + + // Sal: Unfortunately, NOT freeing them causes the dreaded Color Bug. + HWR_FreeColormapCache(); + +#ifdef ALAM_LIGHTING + // BP: reset light between levels (we draw preview frame lights on current frame) + HWR_ResetLights(); +#endif + + HWR_CreatePlanePolygons((INT32)numnodes - 1); + + // Build the sky dome + HWR_ClearSkyDome(); + HWR_BuildSkyDome(); + + gl_maploaded = true; +} + // ========================================================================== // 3D ENGINE COMMANDS // ========================================================================== -static CV_PossibleValue_t grmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; -static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; -static CV_PossibleValue_t grshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; +static CV_PossibleValue_t glshaders_cons_t[] = {{HWD_SHADEROPTION_OFF, "Off"}, {HWD_SHADEROPTION_ON, "On"}, {HWD_SHADEROPTION_NOCUSTOM, "Ignore custom shaders"}, {0, NULL}}; +static CV_PossibleValue_t glmodelinterpolation_cons_t[] = {{0, "Off"}, {1, "Sometimes"}, {2, "Always"}, {0, NULL}}; +static CV_PossibleValue_t glfakecontrast_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Smooth"}, {0, NULL}}; +static CV_PossibleValue_t glshearing_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "Third-person"}, {0, NULL}}; static void CV_glfiltermode_OnChange(void); static void CV_glanisotropic_OnChange(void); @@ -5998,9 +6264,10 @@ static CV_PossibleValue_t glfiltermode_cons_t[]= {{HWD_SET_TEXTUREFILTER_POINTSA {HWD_SET_TEXTUREFILTER_MIXED2, "Nearest_Linear"}, {HWD_SET_TEXTUREFILTER_MIXED3, "Nearest_Mipmap"}, {0, NULL}}; -CV_PossibleValue_t granisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; +CV_PossibleValue_t glanisotropicmode_cons_t[] = {{1, "MIN"}, {16, "MAX"}, {0, NULL}}; -consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_glshaders = CVAR_INIT ("gr_shaders", "On", CV_SAVE, glshaders_cons_t, NULL); +consvar_t cv_glallowshaders = CVAR_INIT ("gr_allowclientshaders", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_fovchange = CVAR_INIT ("gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL); #ifdef ALAM_LIGHTING @@ -6011,17 +6278,17 @@ consvar_t cv_glcoronasize = CVAR_INIT ("gr_coronasize", "1", CV_SAVE|CV_FLOAT, 0 #endif consvar_t cv_glmodels = CVAR_INIT ("gr_models", "Off", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, grmodelinterpolation_cons_t, NULL); +consvar_t cv_glmodelinterpolation = CVAR_INIT ("gr_modelinterpolation", "Sometimes", CV_SAVE, glmodelinterpolation_cons_t, NULL); consvar_t cv_glmodellighting = CVAR_INIT ("gr_modellighting", "Off", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, grshearing_cons_t, NULL); +consvar_t cv_glshearing = CVAR_INIT ("gr_shearing", "Off", CV_SAVE, glshearing_cons_t, NULL); consvar_t cv_glspritebillboarding = CVAR_INIT ("gr_spritebillboarding", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glskydome = CVAR_INIT ("gr_skydome", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, grfakecontrast_cons_t, NULL); +consvar_t cv_glfakecontrast = CVAR_INIT ("gr_fakecontrast", "Smooth", CV_SAVE, glfakecontrast_cons_t, NULL); consvar_t cv_glslopecontrast = CVAR_INIT ("gr_slopecontrast", "Off", CV_SAVE, CV_OnOff, NULL); consvar_t cv_glfiltermode = CVAR_INIT ("gr_filtermode", "Nearest", CV_SAVE|CV_CALL, glfiltermode_cons_t, CV_glfiltermode_OnChange); -consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, granisotropicmode_cons_t, CV_glanisotropic_OnChange); +consvar_t cv_glanisotropicmode = CVAR_INIT ("gr_anisotropicmode", "1", CV_CALL, glanisotropicmode_cons_t, CV_glanisotropic_OnChange); consvar_t cv_glsolvetjoin = CVAR_INIT ("gr_solvetjoin", "On", 0, CV_OnOff, NULL); @@ -6060,6 +6327,7 @@ void HWR_AddCommands(void) CV_RegisterVar(&cv_glfakecontrast); CV_RegisterVar(&cv_glshearing); CV_RegisterVar(&cv_glshaders); + CV_RegisterVar(&cv_glallowshaders); CV_RegisterVar(&cv_glfiltermode); CV_RegisterVar(&cv_glsolvetjoin); @@ -6073,13 +6341,10 @@ void HWR_AddCommands(void) void HWR_AddSessionCommands(void) { - static boolean alreadycalled = false; - if (alreadycalled) + if (gl_sessioncommandsadded) return; - CV_RegisterVar(&cv_glanisotropicmode); - - alreadycalled = true; + gl_sessioncommandsadded = true; } // -------------------------------------------------------------------------- @@ -6087,16 +6352,13 @@ void HWR_AddSessionCommands(void) // -------------------------------------------------------------------------- void HWR_Startup(void) { - static boolean startupdone = false; - - // do this once - if (!startupdone) + if (!gl_init) { CONS_Printf("HWR_Startup()...\n"); HWR_InitPolyPool(); HWR_AddSessionCommands(); - HWR_InitTextureCache(); + HWR_InitMapTextures(); HWR_InitModels(); #ifdef ALAM_LIGHTING HWR_InitLight(); @@ -6110,7 +6372,7 @@ void HWR_Startup(void) if (rendermode == render_opengl) textureformat = patchformat = GL_TEXFMT_RGBA; - startupdone = true; + gl_init = true; } // -------------------------------------------------------------------------- @@ -6118,9 +6380,21 @@ void HWR_Startup(void) // -------------------------------------------------------------------------- void HWR_Switch(void) { + // Add session commands + if (!gl_sessioncommandsadded) + HWR_AddSessionCommands(); + // Set special states from CVARs HWD.pfnSetSpecialState(HWD_SET_TEXTUREFILTERMODE, cv_glfiltermode.value); HWD.pfnSetSpecialState(HWD_SET_TEXTUREANISOTROPICMODE, cv_glanisotropicmode.value); + + // Load textures + if (!gl_maptexturesloaded) + HWR_LoadMapTextures(numtextures); + + // Create plane polygons + if (!gl_maploaded && (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction))) + HWR_LoadLevel(); } // -------------------------------------------------------------------------- @@ -6131,7 +6405,7 @@ void HWR_Shutdown(void) CONS_Printf("HWR_Shutdown()\n"); HWR_FreeExtraSubsectors(); HWR_FreePolyPool(); - HWR_FreeTextureCache(); + HWR_FreeMapTextures(); HWD.pfnFlushScreenTextures(); } @@ -6207,13 +6481,7 @@ void HWR_RenderWall(FOutVector *wallVerts, FSurfaceInfo *pSurf, FBITFIELD blend, } blendmode |= PF_Modulated; // No PF_Occlude means overlapping (incorrect) transparency - HWR_ProcessPolygon(pSurf, wallVerts, 4, blendmode, shader, false); - -#ifdef WALLSPLATS - if (gl_curline->linedef->splats && cv_splats.value) - HWR_DrawSegsSplats(pSurf); -#endif } INT32 HWR_GetTextureUsed(void) @@ -6254,7 +6522,7 @@ void HWR_DoPostProcessor(player_t *player) Surf.PolyColor.s.alpha = 0xc0; // match software mode - HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_Additive|PF_NoTexture|PF_NoDepthTest|PF_Clip|PF_NoZClip); + HWD.pfnDrawPolygon(&Surf, v, 4, PF_Modulated|PF_AdditiveSource|PF_NoTexture|PF_NoDepthTest); } // Capture the screen for intermission and screen waving diff --git a/src/hardware/hw_main.h b/src/hardware/hw_main.h index 85072dfd9c483456206d0315f248d606cd18f380..2ce918408b041780b3a5e0294a9ce059a5326381 100644 --- a/src/hardware/hw_main.h +++ b/src/hardware/hw_main.h @@ -37,13 +37,12 @@ void HWR_DrawViewBorder(INT32 clearlines); void HWR_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum); void HWR_InitTextureMapping(void); void HWR_SetViewSize(void); -void HWR_DrawPatch(GLPatch_t *gpatch, INT32 x, INT32 y, INT32 option); -void HWR_DrawStretchyFixedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); -void HWR_DrawCroppedPatch(GLPatch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); +void HWR_DrawPatch(patch_t *gpatch, INT32 x, INT32 y, INT32 option); +void HWR_DrawStretchyFixedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t pscale, fixed_t vscale, INT32 option, const UINT8 *colormap); +void HWR_DrawCroppedPatch(patch_t *gpatch, fixed_t x, fixed_t y, fixed_t scale, INT32 option, fixed_t sx, fixed_t sy, fixed_t w, fixed_t h); void HWR_MakePatch(const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipmap, boolean makebitmap); void HWR_CreatePlanePolygons(INT32 bspnum); void HWR_CreateStaticLightmaps(INT32 bspnum); -void HWR_LoadTextures(size_t pnumtextures); void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color); void HWR_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT16 actualcolor, UINT8 strength); void HWR_DrawConsoleFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color, UINT32 actualcolor); // Lat: separate flags from color since color needs to be an uint to work right. @@ -55,7 +54,6 @@ boolean HWR_Screenshot(const char *pathname); void HWR_AddCommands(void); void HWR_AddSessionCommands(void); void transform(float *cx, float *cy, float *cz); -FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); INT32 HWR_GetTextureUsed(void); void HWR_DoPostProcessor(player_t *player); void HWR_StartScreenWipe(void); @@ -66,10 +64,15 @@ void HWR_DoTintedWipe(UINT8 wipenum, UINT8 scrnnum); void HWR_MakeScreenFinalTexture(void); void HWR_DrawScreenFinalTexture(int width, int height); -// This stuff is put here so MD2's can use them +// This stuff is put here so models can use them void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *colormap); UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap); // Let's see if this can work +UINT8 HWR_GetTranstableAlpha(INT32 transtablenum); +FBITFIELD HWR_GetBlendModeFlag(INT32 ast); +FBITFIELD HWR_SurfaceBlend(INT32 style, INT32 transtablenum, FSurfaceInfo *pSurf); +FBITFIELD HWR_TranstableToAlpha(INT32 transtablenum, FSurfaceInfo *pSurf); + boolean HWR_CompileShaders(void); void HWR_LoadAllCustomShaders(void); @@ -78,7 +81,7 @@ const char *HWR_GetShaderName(INT32 shader); extern customshaderxlat_t shaderxlat[]; -extern CV_PossibleValue_t granisotropicmode_cons_t[]; +extern CV_PossibleValue_t glanisotropicmode_cons_t[]; #ifdef ALAM_LIGHTING extern consvar_t cv_gldynamiclighting; @@ -87,7 +90,7 @@ extern consvar_t cv_glcoronas; extern consvar_t cv_glcoronasize; #endif -extern consvar_t cv_glshaders; +extern consvar_t cv_glshaders, cv_glallowshaders; extern consvar_t cv_glmodels; extern consvar_t cv_glmodelinterpolation; extern consvar_t cv_glmodellighting; @@ -130,6 +133,10 @@ extern int ps_hw_numcolors; extern int ps_hw_batchsorttime; extern int ps_hw_batchdrawtime; +extern boolean gl_init; +extern boolean gl_maploaded; +extern boolean gl_maptexturesloaded; +extern boolean gl_sessioncommandsadded; extern boolean gl_shadersavailable; #endif diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0c1b14b20879f1136a33b7ccd982c7436fbbd0bb..670a405a1e311e67bfa4135b3fd5a3ea7926ab2e 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -364,48 +364,53 @@ static GLTextureFormat_t PCX_Load(const char *filename, int *w, int *h, // -----------------+ static void md2_loadTexture(md2_t *model) { - GLPatch_t *grpatch; + patch_t *patch; + GLPatch_t *grPatch = NULL; const char *filename = model->filename; if (model->grpatch) { - grpatch = model->grpatch; - Z_Free(grpatch->mipmap->data); + patch = model->grpatch; + grPatch = (GLPatch_t *)(patch->hardware); + if (grPatch) + Z_Free(grPatch->mipmap->data); } else - { - grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO, - &(model->grpatch)); - grpatch->mipmap = Z_Calloc(sizeof (GLMipmap_t), PU_HWRPATCHINFO, NULL); - } + model->grpatch = patch = Patch_Create(NULL, 0, NULL); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + if (!patch->hardware) + Patch_AllocateHardwarePatch(patch); + + if (grPatch == NULL) + grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; UINT32 size; RGBA_t *image; #ifdef HAVE_PNG - grpatch->mipmap->format = PNG_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) #endif - grpatch->mipmap->format = PCX_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) { model->notexturefile = true; // mark it so its not searched for again repeatedly return; } - grpatch->mipmap->downloaded = 0; - grpatch->mipmap->flags = 0; + grPatch->mipmap->downloaded = 0; + grPatch->mipmap->flags = 0; - grpatch->width = (INT16)w; - grpatch->height = (INT16)h; - grpatch->mipmap->width = (UINT16)w; - grpatch->mipmap->height = (UINT16)h; + patch->width = (INT16)w; + patch->height = (INT16)h; + grPatch->mipmap->width = (UINT16)w; + grPatch->mipmap->height = (UINT16)h; // Lactozilla: Apply colour cube - image = grpatch->mipmap->data; + image = grPatch->mipmap->data; size = w*h; while (size--) { @@ -413,7 +418,7 @@ static void md2_loadTexture(md2_t *model) image++; } } - HWD.pfnSetTexture(grpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); } // -----------------+ @@ -421,48 +426,53 @@ static void md2_loadTexture(md2_t *model) // -----------------+ static void md2_loadBlendTexture(md2_t *model) { - GLPatch_t *grpatch; + patch_t *patch; + GLPatch_t *grPatch = NULL; char *filename = Z_Malloc(strlen(model->filename)+7, PU_STATIC, NULL); - strcpy(filename, model->filename); + strcpy(filename, model->filename); FIL_ForceExtension(filename, "_blend.png"); if (model->blendgrpatch) { - grpatch = model->blendgrpatch; - Z_Free(grpatch->mipmap->data); + patch = model->blendgrpatch; + grPatch = (GLPatch_t *)(patch->hardware); + if (grPatch) + Z_Free(grPatch->mipmap->data); } else - { - grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO, - &(model->blendgrpatch)); - grpatch->mipmap = Z_Calloc(sizeof (GLMipmap_t), PU_HWRPATCHINFO, NULL); - } + model->blendgrpatch = patch = Patch_Create(NULL, 0, NULL); + + if (!patch->hardware) + Patch_AllocateHardwarePatch(patch); - if (!grpatch->mipmap->downloaded && !grpatch->mipmap->data) + if (grPatch == NULL) + grPatch = (GLPatch_t *)(patch->hardware); + + if (!grPatch->mipmap->downloaded && !grPatch->mipmap->data) { int w = 0, h = 0; #ifdef HAVE_PNG - grpatch->mipmap->format = PNG_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PNG_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) #endif - grpatch->mipmap->format = PCX_Load(filename, &w, &h, grpatch); - if (grpatch->mipmap->format == 0) + grPatch->mipmap->format = PCX_Load(filename, &w, &h, grPatch); + if (grPatch->mipmap->format == 0) { model->noblendfile = true; // mark it so its not searched for again repeatedly Z_Free(filename); return; } - grpatch->mipmap->downloaded = 0; - grpatch->mipmap->flags = 0; + grPatch->mipmap->downloaded = 0; + grPatch->mipmap->flags = 0; - grpatch->width = (INT16)w; - grpatch->height = (INT16)h; - grpatch->mipmap->width = (UINT16)w; - grpatch->mipmap->height = (UINT16)h; + patch->width = (INT16)w; + patch->height = (INT16)h; + grPatch->mipmap->width = (UINT16)w; + grPatch->mipmap->height = (UINT16)h; } - HWD.pfnSetTexture(grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary + HWD.pfnSetTexture(grPatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary Z_Free(filename); } @@ -692,8 +702,10 @@ spritemodelfound: #define SETBRIGHTNESS(brightness,r,g,b) \ brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) -static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolornum_t color) +static void HWR_CreateBlendedTexture(patch_t *gpatch, patch_t *blendgpatch, GLMipmap_t *grMipmap, INT32 skinnum, skincolornum_t color) { + GLPatch_t *hwrPatch = gpatch->hardware; + GLPatch_t *hwrBlendPatch = blendgpatch->hardware; UINT16 w = gpatch->width, h = gpatch->height; UINT32 size = w*h; RGBA_t *image, *blendimage, *cur, blendcolor; @@ -706,28 +718,29 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, memset(translation, 0, sizeof(translation)); memset(cutoff, 0, sizeof(cutoff)); - if (grmip->width == 0) + if (grMipmap->width == 0) { - grmip->width = gpatch->width; - grmip->height = gpatch->height; + grMipmap->width = gpatch->width; + grMipmap->height = gpatch->height; // no wrap around, no chroma key - grmip->flags = 0; + grMipmap->flags = 0; + // setup the texture info - grmip->format = GL_TEXFMT_RGBA; + grMipmap->format = GL_TEXFMT_RGBA; } - if (grmip->data) + if (grMipmap->data) { - Z_Free(grmip->data); - grmip->data = NULL; + Z_Free(grMipmap->data); + grMipmap->data = NULL; } - cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grmip->data); + cur = Z_Malloc(size*4, PU_HWRMODELTEXTURE, &grMipmap->data); memset(cur, 0x00, size*4); - image = gpatch->mipmap->data; - blendimage = blendgpatch->mipmap->data; + image = hwrPatch->mipmap->data; + blendimage = hwrBlendPatch->mipmap->data; // TC_METALSONIC includes an actual skincolor translation, on top of its flashing. if (skinnum == TC_METALSONIC) @@ -1066,37 +1079,39 @@ skippixel: #undef SETBRIGHTNESS -static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolornum_t color) +static void HWR_GetBlendedTexture(patch_t *patch, patch_t *blendpatch, INT32 skinnum, const UINT8 *colormap, skincolornum_t color) { // mostly copied from HWR_GetMappedPatch, hence the similarities and comment - GLMipmap_t *grmip, *newmip; + GLPatch_t *grPatch = patch->hardware; + GLPatch_t *grBlendPatch = NULL; + GLMipmap_t *grMipmap, *newMipmap; - if (colormap == colormaps || colormap == NULL) + if (blendpatch == NULL || colormap == colormaps || colormap == NULL) { // Don't do any blending - HWD.pfnSetTexture(gpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); return; } - if ((blendgpatch && blendgpatch->mipmap->format) - && (gpatch->width != blendgpatch->width || gpatch->height != blendgpatch->height)) + if ((blendpatch && (grBlendPatch = blendpatch->hardware) && grBlendPatch->mipmap->format) + && (patch->width != blendpatch->width || patch->height != blendpatch->height)) { // Blend image exists, but it's bad. - HWD.pfnSetTexture(gpatch->mipmap); + HWD.pfnSetTexture(grPatch->mipmap); return; } // search for the mipmap // skip the first (no colormap translated) - for (grmip = gpatch->mipmap; grmip->nextcolormap; ) + for (grMipmap = grPatch->mipmap; grMipmap->nextcolormap; ) { - grmip = grmip->nextcolormap; - if (grmip->colormap == colormap) + grMipmap = grMipmap->nextcolormap; + if (grMipmap->colormap == colormap) { - if (grmip->downloaded && grmip->data) + if (grMipmap->downloaded && grMipmap->data) { - HWD.pfnSetTexture(grmip); // found the colormap, set it to the correct texture - Z_ChangeTag(grmip->data, PU_HWRMODELTEXTURE_UNLOCKED); + HWD.pfnSetTexture(grMipmap); // found the colormap, set it to the correct texture + Z_ChangeTag(grMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); return; } } @@ -1107,18 +1122,18 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT //BP: WARNING: don't free it manually without clearing the cache of harware renderer // (it have a liste of mipmap) - // this malloc is cleared in HWR_FreeTextureCache + // this malloc is cleared in HWR_FreeColormapCache // (...) unfortunately z_malloc fragment alot the memory :(so malloc is better - newmip = calloc(1, sizeof (*newmip)); - if (newmip == NULL) + newMipmap = calloc(1, sizeof (*newMipmap)); + if (newMipmap == NULL) I_Error("%s: Out of memory", "HWR_GetBlendedTexture"); - grmip->nextcolormap = newmip; - newmip->colormap = colormap; + grMipmap->nextcolormap = newMipmap; + newMipmap->colormap = colormap; - HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color); + HWR_CreateBlendedTexture(patch, blendpatch, newMipmap, skinnum, color); - HWD.pfnSetTexture(newmip); - Z_ChangeTag(newmip->data, PU_HWRMODELTEXTURE_UNLOCKED); + HWD.pfnSetTexture(newMipmap); + Z_ChangeTag(newMipmap->data, PU_HWRMODELTEXTURE_UNLOCKED); } #define NORMALFOG 0x00000000 @@ -1206,9 +1221,11 @@ static UINT8 HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT8 spr2, player_t } // Adjust texture coords of model to fit into a patch's max_s and max_t -static void adjustTextureCoords(model_t *model, GLPatch_t *gpatch) +static void adjustTextureCoords(model_t *model, patch_t *patch) { int i; + GLPatch_t *gpatch = ((GLPatch_t *)patch->hardware); + for (i = 0; i < model->numMeshes; i++) { int j; @@ -1308,7 +1325,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // Look at HWR_ProjectSprite for more { - GLPatch_t *gpatch; + patch_t *gpatch, *blendgpatch; + GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL; INT32 durs = spr->mobj->state->tics; INT32 tics = spr->mobj->tics; //mdlframe_t *next = NULL; @@ -1326,15 +1344,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) //if (tics > durs) //durs = tics; - if (spr->mobj->flags2 & MF2_SHADOW) - Surf.PolyColor.s.alpha = 0x40; - else if (spr->mobj->frame & FF_TRANSMASK) - HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); + if (spr->mobj->frame & FF_TRANSMASK) + Surf.PolyFlags = HWR_SurfaceBlend(spr->mobj->blendmode, (spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf); else - Surf.PolyColor.s.alpha = 0xFF; + { + Surf.PolyColor.s.alpha = (spr->mobj->flags2 & MF2_SHADOW) ? 0x40 : 0xff; + Surf.PolyFlags = HWR_GetBlendModeFlag(spr->mobj->blendmode); + } - // dont forget to enabled the depth test because we can't do this like - // before: polygons models are not sorted + // don't forget to enable the depth test because we can't do this + // like before: model polygons are not sorted // 1. load model+texture if not already loaded // 2. draw model with correct position, rotation,... @@ -1353,14 +1372,26 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) // texture loading before model init, so it knows if sprite graphics are used, which // means that texture coordinates have to be adjusted gpatch = md2->grpatch; - if (!gpatch || ((!gpatch->mipmap->format || !gpatch->mipmap->downloaded) && !md2->notexturefile)) + if (gpatch) + hwrPatch = ((GLPatch_t *)gpatch->hardware); + + if (!gpatch || !hwrPatch + || ((!hwrPatch->mipmap->format || !hwrPatch->mipmap->downloaded) && !md2->notexturefile)) md2_loadTexture(md2); - gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... - if ((gpatch && gpatch->mipmap->format) // don't load the blend texture if the base texture isn't available - && (!md2->blendgrpatch - || ((!((GLPatch_t *)md2->blendgrpatch)->mipmap->format || !((GLPatch_t *)md2->blendgrpatch)->mipmap->downloaded) - && !md2->noblendfile))) + // Load it again, because it isn't being loaded into gpatch after md2_loadtexture... + gpatch = md2->grpatch; + if (gpatch) + hwrPatch = ((GLPatch_t *)gpatch->hardware); + + // Load blend texture + blendgpatch = md2->blendgrpatch; + if (blendgpatch) + hwrBlendPatch = ((GLPatch_t *)blendgpatch->hardware); + + if ((gpatch && hwrPatch && hwrPatch->mipmap->format) // don't load the blend texture if the base texture isn't available + && (!blendgpatch || !hwrBlendPatch + || ((!hwrBlendPatch->mipmap->format || !hwrBlendPatch->mipmap->downloaded) && !md2->noblendfile))) md2_loadBlendTexture(md2); if (md2->error) @@ -1376,7 +1407,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) md2_printModelInfo(md2->model); // If model uses sprite patch as texture, then // adjust texture coordinates to take power of two textures into account - if (!gpatch || !gpatch->mipmap->format) + if (!gpatch || !hwrPatch->mipmap->format) adjustTextureCoords(md2->model, spr->gpatch); // note down the max_s and max_t that end up in the VBO md2->model->vbo_max_s = md2->model->max_s; @@ -1395,7 +1426,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) finalscale = md2->scale; //Hurdler: arf, I don't like that implementation at all... too much crappy - if (gpatch && gpatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture + if (gpatch && hwrPatch && hwrPatch->mipmap->format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture { INT32 skinnum = TC_DEFAULT; @@ -1428,21 +1459,19 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } // Translation or skin number found - HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); + HWR_GetBlendedTexture(gpatch, blendgpatch, skinnum, spr->colormap, (skincolornum_t)spr->mobj->color); } - else + else // Sprite { - // Sprite - gpatch = spr->gpatch; //W_CachePatchNum(spr->patchlumpnum, PU_CACHE); // Check if sprite dimensions are different from previously used sprite. // If so, uvs need to be readjusted. // Comparing floats with the != operator here should be okay because they // are just copies of glpatches' max_s and max_t values. // Instead of the != operator, memcmp is used to avoid a compiler warning. - if (memcmp(&(gpatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || - memcmp(&(gpatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) + if (memcmp(&(hwrPatch->max_s), &(md2->model->max_s), sizeof(md2->model->max_s)) != 0 || + memcmp(&(hwrPatch->max_t), &(md2->model->max_t), sizeof(md2->model->max_t)) != 0) adjustTextureCoords(md2->model, gpatch); - HWR_GetMappedPatch(gpatch, spr->colormap); + HWR_GetMappedPatch(spr->gpatch, spr->colormap); } if (spr->mobj->frame & FF_ANIMATE) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index db3c6a17dfe6f8cf6b4787a8d009c96779916c76..39552dc1cfc9d4da74329a0b22b6b34017ab406e 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -91,13 +91,6 @@ static GLuint startScreenWipe = 0; static GLuint endScreenWipe = 0; static GLuint finalScreenTexture = 0; -// Lactozilla: Shader functions -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); -static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); - -static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; - // shortcut for ((float)1/i) static const GLfloat byte2float[256] = { 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, @@ -426,6 +419,10 @@ static PFNglBufferData pglBufferData; typedef void (APIENTRY * PFNglDeleteBuffers) (GLsizei n, const GLuint *buffers); static PFNglDeleteBuffers pglDeleteBuffers; +/* 2.0 functions */ +typedef void (APIENTRY * PFNglBlendEquation) (GLenum mode); +static PFNglBlendEquation pglBlendEquation; + /* 1.2 Parms */ /* GL_CLAMP_TO_EDGE_EXT */ @@ -533,8 +530,8 @@ boolean SetupGLfunc(void) return true; } -static boolean gl_allowshaders = false; static boolean gl_shadersenabled = false; +static hwdshaderoption_t gl_allowshaders = HWD_SHADEROPTION_OFF; #ifdef GL_SHADERS typedef GLuint (APIENTRY *PFNglCreateShader) (GLenum); @@ -544,6 +541,7 @@ typedef void (APIENTRY *PFNglGetShaderiv) (GLuint, GLenum, GLint*); typedef void (APIENTRY *PFNglGetShaderInfoLog) (GLuint, GLsizei, GLsizei*, GLchar*); typedef void (APIENTRY *PFNglDeleteShader) (GLuint); typedef GLuint (APIENTRY *PFNglCreateProgram) (void); +typedef void (APIENTRY *PFNglDeleteProgram) (GLuint); typedef void (APIENTRY *PFNglAttachShader) (GLuint, GLuint); typedef void (APIENTRY *PFNglLinkProgram) (GLuint); typedef void (APIENTRY *PFNglGetProgramiv) (GLuint, GLenum, GLint*); @@ -565,6 +563,7 @@ static PFNglGetShaderiv pglGetShaderiv; static PFNglGetShaderInfoLog pglGetShaderInfoLog; static PFNglDeleteShader pglDeleteShader; static PFNglCreateProgram pglCreateProgram; +static PFNglDeleteProgram pglDeleteProgram; static PFNglAttachShader pglAttachShader; static PFNglLinkProgram pglLinkProgram; static PFNglGetProgramiv pglGetProgramiv; @@ -579,12 +578,6 @@ static PFNglUniform2fv pglUniform2fv; static PFNglUniform3fv pglUniform3fv; static PFNglGetUniformLocation pglGetUniformLocation; -// 18032019 -static GLuint gl_currentshaderprogram = 0; -static boolean gl_shaderprogramchanged = true; - -static shadersource_t gl_customshaders[HWR_MAXSHADERS]; - // 13062019 typedef enum { @@ -602,17 +595,37 @@ typedef enum gluniform_max, } gluniform_t; -typedef struct gl_shaderprogram_s +typedef struct gl_shader_s { GLuint program; - boolean custom; GLint uniforms[gluniform_max+1]; -} gl_shaderprogram_t; -static gl_shaderprogram_t gl_shaderprograms[HWR_MAXSHADERS]; + boolean custom; +} gl_shader_t; + +static gl_shader_t gl_shaders[HWR_MAXSHADERS]; +static gl_shader_t gl_usershaders[HWR_MAXSHADERS]; +static shadersource_t gl_customshaders[HWR_MAXSHADERS]; + +// 09102020 +typedef struct gl_shaderstate_s +{ + gl_shader_t *current; + GLuint type; + GLuint program; + boolean changed; +} gl_shaderstate_t; +static gl_shaderstate_t gl_shaderstate; // Shader info static INT32 shader_leveltime = 0; +// Lactozilla: Shader functions +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader); +static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum); +static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade); + +static GLRGBAFloat shader_defaultcolor = {1.0f, 1.0f, 1.0f, 1.0f}; + // ================ // Vertex shaders // ================ @@ -865,6 +878,9 @@ void SetupGLFunc4(void) pglBufferData = GetGLFunc("glBufferData"); pglDeleteBuffers = GetGLFunc("glDeleteBuffers"); + /* 2.0 funcs */ + pglBlendEquation = GetGLFunc("glBlendEquation"); + #ifdef GL_SHADERS pglCreateShader = GetGLFunc("glCreateShader"); pglShaderSource = GetGLFunc("glShaderSource"); @@ -873,6 +889,7 @@ void SetupGLFunc4(void) pglGetShaderInfoLog = GetGLFunc("glGetShaderInfoLog"); pglDeleteShader = GetGLFunc("glDeleteShader"); pglCreateProgram = GetGLFunc("glCreateProgram"); + pglDeleteProgram = GetGLFunc("glDeleteProgram"); pglAttachShader = GetGLFunc("glAttachShader"); pglLinkProgram = GetGLFunc("glLinkProgram"); pglGetProgramiv = GetGLFunc("glGetProgramiv"); @@ -896,113 +913,56 @@ void SetupGLFunc4(void) EXPORT boolean HWRAPI(CompileShaders) (void) { #ifdef GL_SHADERS - GLuint gl_vertShader, gl_fragShader; - GLint i, result; + GLint i; - if (!pglUseProgram) return false; + if (!pglUseProgram) + return false; - gl_customshaders[0].vertex = NULL; - gl_customshaders[0].fragment = NULL; + gl_customshaders[SHADER_DEFAULT].vertex = NULL; + gl_customshaders[SHADER_DEFAULT].fragment = NULL; for (i = 0; gl_shadersources[i].vertex && gl_shadersources[i].fragment; i++) { - gl_shaderprogram_t *shader; + gl_shader_t *shader, *usershader; const GLchar *vert_shader = gl_shadersources[i].vertex; const GLchar *frag_shader = gl_shadersources[i].fragment; - boolean custom = ((gl_customshaders[i].vertex || gl_customshaders[i].fragment) && (i > 0)); - - // 18032019 - if (gl_customshaders[i].vertex) - vert_shader = gl_customshaders[i].vertex; - if (gl_customshaders[i].fragment) - frag_shader = gl_customshaders[i].fragment; if (i >= HWR_MAXSHADERS) break; - shader = &gl_shaderprograms[i]; - shader->program = 0; - shader->custom = custom; + shader = &gl_shaders[i]; + usershader = &gl_usershaders[i]; - // - // Load and compile vertex shader - // - gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); - if (!gl_vertShader) - { - GL_MSG_Error("CompileShaders: Error creating vertex shader %s\n", HWR_GetShaderName(i)); - continue; - } - - pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); - pglCompileShader(gl_vertShader); - - // check for compile errors - pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); - continue; - } + if (shader->program) + pglDeleteProgram(shader->program); + if (usershader->program) + pglDeleteProgram(usershader->program); - // - // Load and compile fragment shader - // - gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); - if (!gl_fragShader) - { - GL_MSG_Error("CompileShaders: Error creating fragment shader %s\n", HWR_GetShaderName(i)); - continue; - } + shader->program = 0; + usershader->program = 0; - pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); - pglCompileShader(gl_fragShader); + if (!Shader_CompileProgram(shader, i, vert_shader, frag_shader)) + shader->program = 0; - // check for compile errors - pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); - if (result == GL_FALSE) - { - Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + // Compile custom shader + if ((i == SHADER_DEFAULT) || !(gl_customshaders[i].vertex || gl_customshaders[i].fragment)) continue; - } - - shader->program = pglCreateProgram(); - pglAttachShader(shader->program, gl_vertShader); - pglAttachShader(shader->program, gl_fragShader); - pglLinkProgram(shader->program); - // check link status - pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); - - // delete the shader objects - pglDeleteShader(gl_vertShader); - pglDeleteShader(gl_fragShader); + // 18032019 + if (gl_customshaders[i].vertex) + vert_shader = gl_customshaders[i].vertex; + if (gl_customshaders[i].fragment) + frag_shader = gl_customshaders[i].fragment; - // couldn't link? - if (result != GL_TRUE) + if (!Shader_CompileProgram(usershader, i, vert_shader, frag_shader)) { - shader->program = 0; - shader->custom = false; - GL_MSG_Error("CompileShaders: Error linking shader program %s\n", HWR_GetShaderName(i)); - continue; + GL_MSG_Warning("CompileShaders: Could not compile custom shader program for %s\n", HWR_GetShaderName(i)); + usershader->program = 0; } + } - // 13062019 -#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); - - // lighting - shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); - shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); - shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); - shader->uniforms[gluniform_lighting] = GETUNI("lighting"); - shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); - shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); - - // misc. (custom shaders) - shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + SetShader(SHADER_DEFAULT); -#undef GETUNI - } return true; #else return false; @@ -1070,26 +1030,45 @@ EXPORT void HWRAPI(LoadCustomShader) (int number, char *code, size_t size, boole #endif } -EXPORT void HWRAPI(SetShader) (int shader) +EXPORT void HWRAPI(SetShader) (int type) { #ifdef GL_SHADERS - if (gl_allowshaders) + if (gl_allowshaders != HWD_SHADEROPTION_OFF) { + gl_shader_t *shader = gl_shaderstate.current; + // If using model lighting, set the appropriate shader. // However don't override a custom shader. - if (shader == SHADER_MODEL && model_lighting - && !(gl_shaderprograms[SHADER_MODEL].custom && !gl_shaderprograms[SHADER_MODEL_LIGHTING].custom)) - shader = SHADER_MODEL_LIGHTING; - if ((GLuint)shader != gl_currentshaderprogram) + if (type == SHADER_MODEL && model_lighting + && !(gl_shaders[SHADER_MODEL].custom && !gl_shaders[SHADER_MODEL_LIGHTING].custom)) + type = SHADER_MODEL_LIGHTING; + + if ((shader == NULL) || (GLuint)type != gl_shaderstate.type) + { + gl_shader_t *baseshader = &gl_shaders[type]; + gl_shader_t *usershader = &gl_usershaders[type]; + + if (usershader->program) + shader = (gl_allowshaders == HWD_SHADEROPTION_NOCUSTOM) ? baseshader : usershader; + else + shader = baseshader; + + gl_shaderstate.current = shader; + gl_shaderstate.type = type; + gl_shaderstate.changed = true; + } + + if (gl_shaderstate.program != shader->program) { - gl_currentshaderprogram = shader; - gl_shaderprogramchanged = true; + gl_shaderstate.program = shader->program; + gl_shaderstate.changed = true; } - gl_shadersenabled = true; + + gl_shadersenabled = (shader->program != 0); return; } #else - (void)shader; + (void)type; #endif gl_shadersenabled = false; } @@ -1097,11 +1076,15 @@ EXPORT void HWRAPI(SetShader) (int shader) EXPORT void HWRAPI(UnSetShader) (void) { #ifdef GL_SHADERS - gl_shadersenabled = false; - gl_currentshaderprogram = 0; - if (!pglUseProgram) return; - pglUseProgram(0); + gl_shaderstate.current = NULL; + gl_shaderstate.type = 0; + gl_shaderstate.program = 0; + + if (pglUseProgram) + pglUseProgram(0); #endif + + gl_shadersenabled = false; } EXPORT void HWRAPI(CleanShaders) (void) @@ -1258,6 +1241,7 @@ void SetStates(void) pglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + pglEnable(GL_ALPHA_TEST); pglAlphaFunc(GL_NOTEQUAL, 0.0f); //pglBlendFunc(GL_ONE, GL_ZERO); // copy pixel to frame buffer (opaque) @@ -1300,6 +1284,17 @@ void SetStates(void) } +// -----------------+ +// DeleteTexture : Deletes a texture from the GPU and frees its data +// -----------------+ +EXPORT void HWRAPI(DeleteTexture) (FTextureInfo *pTexInfo) +{ + if (pTexInfo->downloaded) + pglDeleteTextures(1, (GLuint *)&pTexInfo->downloaded); + pTexInfo->downloaded = 0; +} + + // -----------------+ // Flush : flush OpenGL textures // : Clear list of downloaded mipmaps @@ -1310,9 +1305,7 @@ void Flush(void) while (gl_cachehead) { - if (gl_cachehead->downloaded) - pglDeleteTextures(1, (GLuint *)&gl_cachehead->downloaded); - gl_cachehead->downloaded = 0; + DeleteTexture(gl_cachehead); gl_cachehead = gl_cachehead->nextmipmap; } gl_cachetail = gl_cachehead = NULL; //Hurdler: well, gl_cachehead is already NULL @@ -1517,64 +1510,110 @@ EXPORT void HWRAPI(Draw2DLine) (F2DCoord * v1, pglEnable(GL_TEXTURE_2D); } + +// -----------------+ +// SetBlend : Set render mode +// -----------------+ +// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, +// is it faster when pixels are discarded ? + static void Clamp2D(GLenum pname) { pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP); // fallback clamp pglTexParameteri(GL_TEXTURE_2D, pname, GL_CLAMP_TO_EDGE); } +static void SetBlendEquation(GLenum mode) +{ + if (pglBlendEquation) + pglBlendEquation(mode); +} + +static void SetBlendMode(FBITFIELD flags) +{ + // Set blending function + switch (flags) + { + case PF_Translucent & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency + break; + case PF_Masked & PF_Blending: + // Hurdler: does that mean lighting is only made by alpha src? + // it sounds ok, but not for polygonsmooth + pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture + break; + case PF_Additive & PF_Blending: + case PF_Subtractive & PF_Blending: + case PF_ReverseSubtract & PF_Blending: + case PF_Environment & PF_Blending: + pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case PF_AdditiveSource & PF_Blending: + pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest + break; + case PF_Multiplicative & PF_Blending: + pglBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case PF_Fog & PF_Fog: + // Sryder: Fog + // multiplies input colour by input alpha, and destination colour by input colour, then adds them + pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); + break; + default: // must be 0, otherwise it's an error + // No blending + pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending + break; + } + + // Set blending equation + switch (flags) + { + case PF_Subtractive & PF_Blending: + SetBlendEquation(GL_FUNC_SUBTRACT); + break; + case PF_ReverseSubtract & PF_Blending: + // good for shadow + // not really but what else ? + SetBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + break; + default: + SetBlendEquation(GL_FUNC_ADD); + break; + } + + // Alpha test + switch (flags) + { + case PF_Masked & PF_Blending: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + case PF_Translucent & PF_Blending: + case PF_Additive & PF_Blending: + case PF_AdditiveSource & PF_Blending: + case PF_Subtractive & PF_Blending: + case PF_ReverseSubtract & PF_Blending: + case PF_Environment & PF_Blending: + case PF_Multiplicative & PF_Blending: + pglAlphaFunc(GL_NOTEQUAL, 0.0f); + break; + case PF_Fog & PF_Fog: + pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments + break; + default: + pglAlphaFunc(GL_GREATER, 0.5f); + break; + } +} -// -----------------+ -// SetBlend : Set render mode -// -----------------+ -// PF_Masked - we could use an ALPHA_TEST of GL_EQUAL, and alpha ref of 0, -// is it faster when pixels are discarded ? EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) { FBITFIELD Xor; Xor = CurrentPolyFlags^PolyFlags; - if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible|PF_NoAlphaTest)) + if (Xor & (PF_Blending|PF_RemoveYWrap|PF_ForceWrapX|PF_ForceWrapY|PF_Occlude|PF_NoTexture|PF_Modulated|PF_NoDepthTest|PF_Decal|PF_Invisible)) { - if (Xor&(PF_Blending)) // if blending mode must be changed - { - switch (PolyFlags & PF_Blending) { - case PF_Translucent & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Masked & PF_Blending: - // Hurdler: does that mean lighting is only made by alpha src? - // it sounds ok, but not for polygonsmooth - pglBlendFunc(GL_SRC_ALPHA, GL_ZERO); // 0 alpha = holes in texture - pglAlphaFunc(GL_GREATER, 0.5f); - break; - case PF_Additive & PF_Blending: - pglBlendFunc(GL_SRC_ALPHA, GL_ONE); // src * alpha + dest - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Environment & PF_Blending: - pglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Substractive & PF_Blending: - // good for shadow - // not really but what else ? - pglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - pglAlphaFunc(GL_NOTEQUAL, 0.0f); - break; - case PF_Fog & PF_Fog: - // Sryder: Fog - // multiplies input colour by input alpha, and destination colour by input colour, then adds them - pglBlendFunc(GL_SRC_ALPHA, GL_SRC_COLOR); - pglAlphaFunc(GL_ALWAYS, 0.0f); // Don't discard zero alpha fragments - break; - default : // must be 0, otherwise it's an error - // No blending - pglBlendFunc(GL_ONE, GL_ZERO); // the same as no blending - pglAlphaFunc(GL_GREATER, 0.5f); - break; - } - } + if (Xor & PF_Blending) // if blending mode must be changed + SetBlendMode(PolyFlags & PF_Blending); + if (Xor & PF_NoAlphaTest) { if (PolyFlags & PF_NoAlphaTest) @@ -1591,7 +1630,7 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglDisable(GL_POLYGON_OFFSET_FILL); } - if (Xor&PF_NoDepthTest) + if (Xor & PF_NoDepthTest) { if (PolyFlags & PF_NoDepthTest) pglDepthFunc(GL_ALWAYS); //pglDisable(GL_DEPTH_TEST); @@ -1599,25 +1638,25 @@ EXPORT void HWRAPI(SetBlend) (FBITFIELD PolyFlags) pglDepthFunc(GL_LEQUAL); //pglEnable(GL_DEPTH_TEST); } - if (Xor&PF_RemoveYWrap) + if (Xor & PF_RemoveYWrap) { if (PolyFlags & PF_RemoveYWrap) Clamp2D(GL_TEXTURE_WRAP_T); } - if (Xor&PF_ForceWrapX) + if (Xor & PF_ForceWrapX) { if (PolyFlags & PF_ForceWrapX) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); } - if (Xor&PF_ForceWrapY) + if (Xor & PF_ForceWrapY) { if (PolyFlags & PF_ForceWrapY) pglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - if (Xor&PF_Modulated) + if (Xor & PF_Modulated) { #if defined (__unix__) || defined (UNIXCOMMON) if (oglflags & GLF_NOTEXENV) @@ -1901,42 +1940,24 @@ EXPORT void HWRAPI(SetTexture) (FTextureInfo *pTexInfo) } } -static void *Shader_Load(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) -{ -#ifdef GL_SHADERS - if (gl_shadersenabled && pglUseProgram) - { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; - if (shader->program) - { - if (gl_shaderprogramchanged) - { - pglUseProgram(gl_shaderprograms[gl_currentshaderprogram].program); - gl_shaderprogramchanged = false; - } - Shader_SetUniforms(Surface, poly, tint, fade); - return shader; - } - else - pglUseProgram(0); - } -#else - (void)Surface; - (void)poly; - (void)tint; - (void)fade; -#endif - return NULL; -} - static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAFloat *tint, GLRGBAFloat *fade) { #ifdef GL_SHADERS - if (gl_shadersenabled) + gl_shader_t *shader = gl_shaderstate.current; + + if (gl_shadersenabled && (shader != NULL) && pglUseProgram) { - gl_shaderprogram_t *shader = &gl_shaderprograms[gl_currentshaderprogram]; if (!shader->program) + { + pglUseProgram(0); return; + } + + if (gl_shaderstate.changed) + { + pglUseProgram(shader->program); + gl_shaderstate.changed = false; + } // Color uniforms can be left NULL and will be set to white (1.0f, 1.0f, 1.0f, 1.0f) if (poly == NULL) @@ -1989,6 +2010,97 @@ static void Shader_SetUniforms(FSurfaceInfo *Surface, GLRGBAFloat *poly, GLRGBAF #endif } +static boolean Shader_CompileProgram(gl_shader_t *shader, GLint i, const GLchar *vert_shader, const GLchar *frag_shader) +{ + GLuint gl_vertShader, gl_fragShader; + GLint result; + + // + // Load and compile vertex shader + // + gl_vertShader = pglCreateShader(GL_VERTEX_SHADER); + if (!gl_vertShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating vertex shader %s\n", HWR_GetShaderName(i)); + return false; + } + + pglShaderSource(gl_vertShader, 1, &vert_shader, NULL); + pglCompileShader(gl_vertShader); + + // check for compile errors + pglGetShaderiv(gl_vertShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling vertex shader", gl_vertShader, i); + pglDeleteShader(gl_vertShader); + return false; + } + + // + // Load and compile fragment shader + // + gl_fragShader = pglCreateShader(GL_FRAGMENT_SHADER); + if (!gl_fragShader) + { + GL_MSG_Error("Shader_CompileProgram: Error creating fragment shader %s\n", HWR_GetShaderName(i)); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + pglShaderSource(gl_fragShader, 1, &frag_shader, NULL); + pglCompileShader(gl_fragShader); + + // check for compile errors + pglGetShaderiv(gl_fragShader, GL_COMPILE_STATUS, &result); + if (result == GL_FALSE) + { + Shader_CompileError("Error compiling fragment shader", gl_fragShader, i); + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + return false; + } + + shader->program = pglCreateProgram(); + pglAttachShader(shader->program, gl_vertShader); + pglAttachShader(shader->program, gl_fragShader); + pglLinkProgram(shader->program); + + // check link status + pglGetProgramiv(shader->program, GL_LINK_STATUS, &result); + + // delete the shader objects + pglDeleteShader(gl_vertShader); + pglDeleteShader(gl_fragShader); + + // couldn't link? + if (result != GL_TRUE) + { + GL_MSG_Error("Shader_CompileProgram: Error linking shader program %s\n", HWR_GetShaderName(i)); + pglDeleteProgram(shader->program); + return false; + } + + // 13062019 +#define GETUNI(uniform) pglGetUniformLocation(shader->program, uniform); + + // lighting + shader->uniforms[gluniform_poly_color] = GETUNI("poly_color"); + shader->uniforms[gluniform_tint_color] = GETUNI("tint_color"); + shader->uniforms[gluniform_fade_color] = GETUNI("fade_color"); + shader->uniforms[gluniform_lighting] = GETUNI("lighting"); + shader->uniforms[gluniform_fade_start] = GETUNI("fade_start"); + shader->uniforms[gluniform_fade_end] = GETUNI("fade_end"); + + // misc. (custom shaders) + shader->uniforms[gluniform_leveltime] = GETUNI("leveltime"); + +#undef GETUNI + + return true; +} + static void Shader_CompileError(const char *message, GLuint program, INT32 shadernum) { GLchar *infoLog = NULL; @@ -2002,7 +2114,7 @@ static void Shader_CompileError(const char *message, GLuint program, INT32 shade pglGetShaderInfoLog(program, logLength, NULL, infoLog); } - GL_MSG_Error("CompileShaders: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); + GL_MSG_Error("Shader_CompileProgram: %s (%s)\n%s", message, HWR_GetShaderName(shadernum), (infoLog ? infoLog : "")); if (infoLog) free(infoLog); @@ -2112,7 +2224,7 @@ static void PreparePolygon(FSurfaceInfo *pSurf, FOutVector *pOutVerts, FBITFIELD pglColor4ubv(c); } - Shader_Load(pSurf, &poly, &tint, &fade); + Shader_SetUniforms(pSurf, &poly, &tint, &fade); } // -----------------+ @@ -2158,7 +2270,7 @@ EXPORT void HWRAPI(RenderSkyDome) (gl_sky_t *sky) { int i, j; - Shader_Load(NULL, NULL, NULL, NULL); + Shader_SetUniforms(NULL, NULL, NULL, NULL); // Build the sky dome! Yes! if (sky->rebuild) @@ -2250,15 +2362,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value) break; case HWD_SET_SHADERS: - switch (Value) - { - case 1: - gl_allowshaders = true; - break; - default: - gl_allowshaders = false; - break; - } + gl_allowshaders = (hwdshaderoption_t)Value; break; case HWD_SET_TEXTUREFILTERMODE: @@ -2528,6 +2632,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 boolean useVBO = true; + FBITFIELD flags; int i; // Because otherwise, scaling the screen negatively vertically breaks the lighting @@ -2595,8 +2700,6 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 else pglColor4ubv((GLubyte*)&Surface->PolyColor.s); - SetBlend((poly.alpha < 1 ? PF_Translucent : (PF_Masked|PF_Occlude))|PF_Modulated); - tint.red = byte2float[Surface->TintColor.s.red]; tint.green = byte2float[Surface->TintColor.s.green]; tint.blue = byte2float[Surface->TintColor.s.blue]; @@ -2607,7 +2710,14 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 fade.blue = byte2float[Surface->FadeColor.s.blue]; fade.alpha = byte2float[Surface->FadeColor.s.alpha]; - Shader_Load(Surface, &poly, &tint, &fade); + flags = (Surface->PolyFlags | PF_Modulated); + if (Surface->PolyFlags & (PF_Additive|PF_AdditiveSource|PF_Subtractive|PF_ReverseSubtract|PF_Multiplicative)) + flags |= PF_Occlude; + else if (Surface->PolyColor.s.alpha == 0xFF) + flags |= (PF_Occlude | PF_Masked); + + SetBlend(flags); + Shader_SetUniforms(Surface, &poly, &tint, &fade); pglEnable(GL_CULL_FACE); pglEnable(GL_NORMALIZE); @@ -3176,7 +3286,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - SetBlend(PF_Modulated|PF_NoDepthTest|PF_Clip|PF_NoZClip); + SetBlend(PF_Modulated|PF_NoDepthTest); pglEnable(GL_TEXTURE_2D); // Draw the original screen @@ -3186,7 +3296,7 @@ EXPORT void HWRAPI(DoScreenWipe)(void) pglVertexPointer(3, GL_FLOAT, 0, screenVerts); pglDrawArrays(GL_TRIANGLE_FAN, 0, 4); - SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest|PF_Clip|PF_NoZClip); + SetBlend(PF_Modulated|PF_Translucent|PF_NoDepthTest); // Draw the end screen that fades in pglActiveTexture(GL_TEXTURE0); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 72fb9272d441135456286f908da9ba7e2ff9dc98..604a509e0d447420ed835e4d22e2def744af78de 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2120,7 +2120,7 @@ void HU_Drawer(void) HU_DrawCrosshair2(); // draw desynch text - if (hu_resynching) + if (hu_redownloadinggamestate) { static UINT32 resynch_ticker = 0; char resynch_text[14]; diff --git a/src/i_sound.h b/src/i_sound.h index a2249a10273fa48c95650a75fa692b84d4de37d8..d45c0b323ef4ca34ea936e49b8e598471eb9d290 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -21,15 +21,12 @@ // copied from SDL mixer, plus GME typedef enum { MU_NONE, - MU_CMD, MU_WAV, MU_MOD, MU_MID, MU_OGG, MU_MP3, - MU_MP3_MAD_UNUSED, // use MU_MP3 instead MU_FLAC, - MU_MODPLUG_UNUSED, // use MU_MOD instead MU_GME, MU_MOD_EX, // libopenmpt MU_MID_EX // Non-native MIDI diff --git a/src/i_video.h b/src/i_video.h index 98ed7f38a18822d8038ec0973ef3c680572c2d89..ab48881d4405036b515ff65988a81bab89e7236a 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -36,10 +36,9 @@ typedef enum */ extern rendermode_t rendermode; -/** \brief OpenGL state - 0 = never loaded, 1 = loaded successfully, -1 = failed loading +/** \brief render mode set by command line arguments */ -extern INT32 vid_opengl_state; +extern rendermode_t chosenrendermode; /** \brief use highcolor modes if true */ @@ -90,8 +89,9 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h); INT32 VID_SetMode(INT32 modenum); /** \brief Checks the render state + \return true if the renderer changed */ -void VID_CheckRenderer(void); +boolean VID_CheckRenderer(void); /** \brief Load OpenGL mode */ diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 132ebc1a8bda0fcd370a81ef38f8597a7743df5f..4667fdbf4a7549ae226075ff8d5f09feeb9cc05f 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -32,6 +32,7 @@ #include "lua_script.h" #include "lua_libs.h" #include "lua_hud.h" // hud_running errors +#include "taglist.h" // P_FindSpecialLineFromTag #include "lua_hook.h" // hook_cmd_running errors #define NOHUD if (hud_running)\ @@ -246,6 +247,56 @@ static int lib_userdataType(lua_State *L) return luaL_typerror(L, 1, "userdata"); } +// Takes a metatable as first and only argument +// Only callable during script loading +static int lib_registerMetatable(lua_State *L) +{ + static UINT16 nextid = 1; + + if (!lua_lumploading) + return luaL_error(L, "This function cannot be called from within a hook or coroutine!"); + luaL_checktype(L, 1, LUA_TTABLE); + + if (nextid == 0) + return luaL_error(L, "Too many metatables registered?! Please consider rewriting your script once you are sober again.\n"); + + lua_getfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); // 2 + // registry.metatables[metatable] = nextid + lua_pushvalue(L, 1); // 3 + lua_pushnumber(L, nextid); // 4 + lua_settable(L, 2); + + // registry.metatables[nextid] = metatable + lua_pushnumber(L, nextid); // 3 + lua_pushvalue(L, 1); // 4 + lua_settable(L, 2); + lua_pop(L, 1); + + nextid++; + + return 0; +} + +// Takes a string as only argument and returns the metatable +// associated to the userdata type this string refers to +// Returns nil if the string does not refer to a valid userdata type +static int lib_userdataMetatable(lua_State *L) +{ + UINT32 i; + const char *udname = luaL_checkstring(L, 1); + + // Find internal metatable name + for (i = 0; meta2utype[i].meta; i++) + if (!strcmp(udname, meta2utype[i].utype)) + { + luaL_getmetatable(L, meta2utype[i].meta); + return 1; + } + + lua_pushnil(L); + return 1; +} + static int lib_isPlayerAdmin(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); @@ -915,6 +966,28 @@ static int lib_pMaceRotate(lua_State *L) return 0; } +static int lib_pCreateFloorSpriteSlope(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + LUA_PushUserdata(L, (pslope_t *)P_CreateFloorSpriteSlope(mobj), META_SLOPE); + return 1; +} + +static int lib_pRemoveFloorSpriteSlope(lua_State *L) +{ + mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + NOHUD + INLEVEL + if (!mobj) + return LUA_ErrInvalid(L, "mobj_t"); + P_RemoveFloorSpriteSlope(mobj); + return 1; +} + static int lib_pRailThinker(lua_State *L) { mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); @@ -3006,6 +3079,185 @@ static int lib_sStartMusicCaption(lua_State *L) return 0; } +static int lib_sMusicType(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, S_MusicType()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicPlaying(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_MusicPlaying()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicPaused(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_MusicPaused()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicName(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushstring(L, S_MusicName()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sMusicExists(lua_State *L) +{ + boolean checkMIDI = lua_opttrueboolean(L, 2); + boolean checkDigi = lua_opttrueboolean(L, 3); +#ifdef MUSICSLOT_COMPATIBILITY + const char *music_name; + UINT32 music_num; + char music_compat_name[7]; + UINT16 music_flags = 0; + NOHUD + if (lua_isnumber(L, 1)) + { + music_num = (UINT32)luaL_checkinteger(L, 1); + music_flags = (UINT16)(music_num & 0x0000FFFF); + if (music_flags && music_flags <= 1035) + snprintf(music_compat_name, 7, "%sM", G_BuildMapName((INT32)music_flags)); + else if (music_flags && music_flags <= 1050) + strncpy(music_compat_name, compat_special_music_slots[music_flags - 1036], 7); + else + music_compat_name[0] = 0; // becomes empty string + music_compat_name[6] = 0; + music_name = (const char *)&music_compat_name; + } + else + { + music_num = 0; + music_name = luaL_checkstring(L, 1); + } +#else + const char *music_name = luaL_checkstring(L, 1); +#endif + NOHUD + lua_pushboolean(L, S_MusicExists(music_name, checkMIDI, checkDigi)); + return 1; +} + +static int lib_sSetMusicLoopPoint(lua_State *L) +{ + UINT32 looppoint = (UINT32)luaL_checkinteger(L, 1); + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) + { + player = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushboolean(L, S_SetMusicLoopPoint(looppoint)); + else + lua_pushnil(L); + return 1; +} + +static int lib_sGetMusicLoopPoint(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + lua_pushinteger(L, (int)S_GetMusicLoopPoint()); + else + lua_pushnil(L); + return 1; +} + +static int lib_sPauseMusic(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_PauseAudio(); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + +static int lib_sResumeMusic(lua_State *L) +{ + player_t *player = NULL; + NOHUD + if (!lua_isnone(L, 1) && lua_isuserdata(L, 1)) + { + player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); + if (!player) + return LUA_ErrInvalid(L, "player_t"); + } + if (!player || P_IsLocalPlayer(player)) + { + S_ResumeAudio(); + lua_pushboolean(L, true); + } + else + lua_pushnil(L); + return 1; +} + // G_GAME //////////// @@ -3494,6 +3746,8 @@ static luaL_Reg lib[] = { {"chatprint", lib_chatprint}, {"chatprintf", lib_chatprintf}, {"userdataType", lib_userdataType}, + {"registerMetatable", lib_registerMetatable}, + {"userdataMetatable", lib_userdataMetatable}, {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, @@ -3553,6 +3807,8 @@ static luaL_Reg lib[] = { {"P_CheckSolidLava",lib_pCheckSolidLava}, {"P_CanRunOnWater",lib_pCanRunOnWater}, {"P_MaceRotate",lib_pMaceRotate}, + {"P_CreateFloorSpriteSlope",lib_pCreateFloorSpriteSlope}, + {"P_RemoveFloorSpriteSlope",lib_pRemoveFloorSpriteSlope}, {"P_RailThinker",lib_pRailThinker}, {"P_XYMovement",lib_pXYMovement}, {"P_RingXYMovement",lib_pRingXYMovement}, @@ -3712,6 +3968,15 @@ static luaL_Reg lib[] = { {"S_IdPlaying",lib_sIdPlaying}, {"S_SoundPlaying",lib_sSoundPlaying}, {"S_StartMusicCaption", lib_sStartMusicCaption}, + {"S_MusicType",lib_sMusicType}, + {"S_MusicPlaying",lib_sMusicPlaying}, + {"S_MusicPaused",lib_sMusicPaused}, + {"S_MusicName",lib_sMusicName}, + {"S_MusicExists",lib_sMusicExists}, + {"S_SetMusicLoopPoint",lib_sSetMusicLoopPoint}, + {"S_GetMusicLoopPoint",lib_sGetMusicLoopPoint}, + {"S_PauseMusic",lib_sPauseMusic}, + {"S_ResumeMusic", lib_sResumeMusic}, // g_game {"G_AddGametype", lib_gAddGametype}, diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c index c6b082930385d3edd4762d846532028be1c9ade1..32d64b5b5333729b5dc4cb6220f93c20393815e8 100644 --- a/src/lua_consolelib.c +++ b/src/lua_consolelib.c @@ -440,6 +440,9 @@ static int CVarSetFunction ){ consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + if (cvar->flags & CV_NOLUA) + return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); + switch (lua_type(L, 2)) { case LUA_TSTRING: @@ -468,7 +471,12 @@ static int lib_cvStealthSet(lua_State *L) static int lib_cvAddValue(lua_State *L) { consvar_t *cvar = (consvar_t *)luaL_checkudata(L, 1, META_CVAR); + + if (cvar->flags & CV_NOLUA) + return luaL_error(L, "Variable %s cannot be set from Lua.", cvar->name); + CV_AddValue(cvar, (INT32)luaL_checknumber(L, 2)); + return 0; } diff --git a/src/lua_hook.h b/src/lua_hook.h index 47850812f059c5825e3f53428c4bbecda4e7a5ef..796f3a9d287dcf0e3997d6963949b33111dceb0d 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -60,6 +60,7 @@ enum hook { hook_ShouldJingleContinue, hook_GameQuit, hook_PlayerCmd, + hook_MusicChange, hook_MAX // last hook }; @@ -118,3 +119,4 @@ boolean LUAh_SeenPlayer(player_t *player, player_t *seenfriend); // Hook for MT_ boolean LUAh_ShouldJingleContinue(player_t *player, const char *musname); // Hook for whether a jingle of the given music should continue playing void LUAh_GameQuit(void); // Hook for game quitting boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd); // Hook for building player's ticcmd struct (Ported from SRB2Kart) +boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms); // Hook for music changes \ No newline at end of file diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 65d483dc1a9f1518fab22a70adde2bc78aa20ad3..117aa48a303e7ba7945f2b970cb20d0292cced2a 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -76,6 +76,7 @@ const char *const hookNames[hook_MAX+1] = { "ShouldJingleContinue", "GameQuit", "PlayerCmd", + "MusicChange", NULL }; @@ -1912,3 +1913,62 @@ boolean LUAh_PlayerCmd(player_t *player, ticcmd_t *cmd) hook_cmd_running = false; return hooked; } + +// Hook for music changes +boolean LUAh_MusicChange(const char *oldname, char *newname, UINT16 *mflags, boolean *looping, + UINT32 *position, UINT32 *prefadems, UINT32 *fadeinms) +{ + hook_p hookp; + boolean hooked = false; + + if (!gL || !(hooksAvailable[hook_MusicChange/8] & (1<<(hook_MusicChange%8)))) + return false; + + lua_settop(gL, 0); + lua_pushcfunction(gL, LUA_GetErrorMessage); + + for (hookp = roothook; hookp; hookp = hookp->next) + if (hookp->type == hook_MusicChange) + { + PushHook(gL, hookp); + lua_pushstring(gL, oldname); + lua_pushstring(gL, newname); + lua_pushinteger(gL, *mflags); + lua_pushboolean(gL, *looping); + lua_pushinteger(gL, *position); + lua_pushinteger(gL, *prefadems); + lua_pushinteger(gL, *fadeinms); + if (lua_pcall(gL, 7, 6, 1)) { + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL,-1)); + lua_pop(gL, 1); + continue; + } + + // output 1: true, false, or string musicname override + if (lua_isboolean(gL, -6) && lua_toboolean(gL, -6)) + hooked = true; + else if (lua_isstring(gL, -6)) + strncpy(newname, lua_tostring(gL, -6), 7); + // output 2: mflags override + if (lua_isnumber(gL, -5)) + *mflags = lua_tonumber(gL, -5); + // output 3: looping override + if (lua_isboolean(gL, -4)) + *looping = lua_toboolean(gL, -4); + // output 4: position override + if (lua_isboolean(gL, -3)) + *position = lua_tonumber(gL, -3); + // output 5: prefadems override + if (lua_isboolean(gL, -2)) + *prefadems = lua_tonumber(gL, -2); + // output 6: fadeinms override + if (lua_isboolean(gL, -1)) + *fadeinms = lua_tonumber(gL, -1); + + lua_pop(gL, 7); // Pop returned values and error handler + } + + lua_settop(gL, 0); + newname[6] = 0; + return hooked; +} \ No newline at end of file diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 6b87dc93034060d5af15ff1d7a5687cb3fcb8b12..7b290bf3ff3a87d8e9d80f14c9c1c84c29a91e15 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -35,11 +35,6 @@ static UINT8 hud_enabled[(hud_MAX/8)+1]; static UINT8 hudAvailable; // hud hooks field -#ifdef LUA_PATCH_SAFETY -static patchinfo_t *patchinfo, *patchinfohead; -static int numluapatches; -#endif - // must match enum hud in lua_hud.h static const char *const hud_disable_options[] = { "stagetitle", @@ -292,11 +287,7 @@ static int colormap_get(lua_State *L) static int patch_get(lua_State *L) { -#ifdef LUA_PATCH_SAFETY patch_t *patch = *((patch_t **)luaL_checkudata(L, 1, META_PATCH)); -#else - patchinfo_t *patch = *((patchinfo_t **)luaL_checkudata(L, 1, META_PATCH)); -#endif enum patch field = luaL_checkoption(L, 2, NULL, patch_opt); // patches are invalidated when switching renderers @@ -403,59 +394,8 @@ static int libd_patchExists(lua_State *L) static int libd_cachePatch(lua_State *L) { -#ifdef LUA_PATCH_SAFETY - int i; - lumpnum_t lumpnum; - patchinfo_t *luapat; - patch_t *realpatch; - - HUDONLY - - luapat = patchinfohead; - lumpnum = W_CheckNumForLongName(luaL_checkstring(L, 1)); - if (lumpnum == LUMPERROR) - lumpnum = W_GetNumForLongName("MISSING"); - - for (i = 0; i < numluapatches; i++) - { - // check if already cached - if (luapat->wadnum == WADFILENUM(lumpnum) && luapat->lumpnum == LUMPNUM(lumpnum)) - { - LUA_PushUserdata(L, luapat, META_PATCH); - return 1; - } - luapat = luapat->next; - if (!luapat) - break; - } - - if (numluapatches > 0) - { - patchinfo->next = Z_Malloc(sizeof(patchinfo_t), PU_STATIC, NULL); - patchinfo = patchinfo->next; - } - else - { - patchinfo = Z_Malloc(sizeof(patchinfo_t), PU_STATIC, NULL); - patchinfohead = patchinfo; - } - - realpatch = W_CachePatchNum(lumpnum, PU_PATCH); - - patchinfo->width = realpatch->width; - patchinfo->height = realpatch->height; - patchinfo->leftoffset = realpatch->leftoffset; - patchinfo->topoffset = realpatch->topoffset; - - patchinfo->wadnum = WADFILENUM(lumpnum); - patchinfo->lumpnum = LUMPNUM(lumpnum); - - LUA_PushUserdata(L, patchinfo, META_PATCH); - numluapatches++; -#else HUDONLY LUA_PushUserdata(L, W_CachePatchLongName(luaL_checkstring(L, 1), PU_PATCH), META_PATCH); -#endif return 1; } @@ -518,9 +458,8 @@ static int libd_getSpritePatch(lua_State *L) INT32 rot = R_GetRollAngle(rollangle); if (rot) { - if (!(sprframe->rotsprite.cached & (1<<angle))) - R_CacheRotSprite(i, frame, NULL, sprframe, angle, sprframe->flip & (1<<angle)); - LUA_PushUserdata(L, sprframe->rotsprite.patch[angle][rot], META_PATCH); + patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &spriteinfo[i], rot); + LUA_PushUserdata(L, rotsprite, META_PATCH); lua_pushboolean(L, false); lua_pushboolean(L, true); return 3; @@ -529,7 +468,7 @@ static int libd_getSpritePatch(lua_State *L) #endif // push both the patch and it's "flip" value - LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0); return 2; } @@ -631,9 +570,8 @@ static int libd_getSprite2Patch(lua_State *L) INT32 rot = R_GetRollAngle(rollangle); if (rot) { - if (!(sprframe->rotsprite.cached & (1<<angle))) - R_CacheRotSprite(SPR_PLAY, frame, &skins[i].sprinfo[j], sprframe, angle, sprframe->flip & (1<<angle)); - LUA_PushUserdata(L, sprframe->rotsprite.patch[angle][rot], META_PATCH); + patch_t *rotsprite = Patch_GetRotatedSprite(sprframe, frame, angle, sprframe->flip & (1<<angle), true, &skins[i].sprinfo[j], rot); + LUA_PushUserdata(L, rotsprite, META_PATCH); lua_pushboolean(L, false); lua_pushboolean(L, true); return 3; @@ -642,7 +580,7 @@ static int libd_getSprite2Patch(lua_State *L) #endif // push both the patch and it's "flip" value - LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_PATCH), META_PATCH); + LUA_PushUserdata(L, W_CachePatchNum(sprframe->lumppat[angle], PU_SPRITE), META_PATCH); lua_pushboolean(L, (sprframe->flip & (1<<angle)) != 0); return 2; } @@ -651,22 +589,14 @@ static int libd_draw(lua_State *L) { INT32 x, y, flags; patch_t *patch; -#ifdef LUA_PATCH_SAFETY - patchinfo_t *luapat; -#endif const UINT8 *colormap = NULL; HUDONLY x = luaL_checkinteger(L, 1); y = luaL_checkinteger(L, 2); -#ifdef LUA_PATCH_SAFETY - luapat = *((patchinfo_t **)luaL_checkudata(L, 3, META_PATCH)); - patch = W_CachePatchNum((luapat->wadnum<<16)+luapat->lumpnum, PU_PATCH); -#else patch = *((patch_t **)luaL_checkudata(L, 3, META_PATCH)); if (!patch) return LUA_ErrInvalid(L, "patch_t"); -#endif flags = luaL_optinteger(L, 4, 0); if (!lua_isnoneornil(L, 5)) colormap = *((UINT8 **)luaL_checkudata(L, 5, META_COLORMAP)); @@ -682,9 +612,6 @@ static int libd_drawScaled(lua_State *L) fixed_t x, y, scale; INT32 flags; patch_t *patch; -#ifdef LUA_PATCH_SAFETY - patchinfo_t *luapat; -#endif const UINT8 *colormap = NULL; HUDONLY @@ -693,14 +620,9 @@ static int libd_drawScaled(lua_State *L) scale = luaL_checkinteger(L, 3); if (scale < 0) return luaL_error(L, "negative scale"); -#ifdef LUA_PATCH_SAFETY - luapat = *((patchinfo_t **)luaL_checkudata(L, 4, META_PATCH)); - patch = W_CachePatchNum((luapat->wadnum<<16)+luapat->lumpnum, PU_PATCH); -#else patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH)); if (!patch) return LUA_ErrInvalid(L, "patch_t"); -#endif flags = luaL_optinteger(L, 5, 0); if (!lua_isnoneornil(L, 6)) colormap = *((UINT8 **)luaL_checkudata(L, 6, META_COLORMAP)); @@ -1261,10 +1183,6 @@ int LUA_HudLib(lua_State *L) { memset(hud_enabled, 0xff, (hud_MAX/8)+1); -#ifdef LUA_PATCH_SAFETY - numluapatches = 0; -#endif - lua_newtable(L); // HUD registry table lua_newtable(L); luaL_register(L, NULL, lib_draw); diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 5e5a1dbc4029ba27f338c525340570e2b9141c7a..18e51995117717fd5ca47a0182876ecdea7eac1f 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -17,6 +17,7 @@ #include "p_mobj.h" #include "p_local.h" #include "z_zone.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_things.h" #include "r_draw.h" // R_GetColorByName @@ -382,10 +383,6 @@ static int lib_setSpriteInfo(lua_State *L) 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. @@ -469,11 +466,6 @@ static int spriteinfo_set(lua_State *L) lua_remove(L, 1); // remove field lua_settop(L, 1); // leave only one value -#ifdef ROTSPRITE - if (sprites != NULL) - R_FreeSingleRotSprite(&sprites[sprinfo-spriteinfo]); -#endif - if (fastcmp(field, "pivot")) { // pivot[] is a table diff --git a/src/lua_libs.h b/src/lua_libs.h index 03bd99cd29a53f531ed5c6412e101ede97a79893..062a3fe5009fb2beda2c2a5545243ab350a2cdf5 100644 --- a/src/lua_libs.h +++ b/src/lua_libs.h @@ -16,6 +16,7 @@ extern lua_State *gL; #define LREG_EXTVARS "LUA_VARS" #define LREG_STATEACTION "STATE_ACTION" #define LREG_ACTIONS "MOBJ_ACTION" +#define LREG_METATABLES "METATABLES" #define META_STATE "STATE_T*" #define META_MOBJINFO "MOBJINFO_T*" diff --git a/src/lua_maplib.c b/src/lua_maplib.c index 5f6dbc4d6480c0d92e942ded4d01f0524207ae70..95cc8c1019e88de52213a0fac5ebff9d42ffa8d0 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -99,8 +99,6 @@ enum line_e { line_slopetype, line_frontsector, line_backsector, - line_firsttag, - line_nexttag, line_polyobj, line_text, line_callcount @@ -125,8 +123,6 @@ static const char *const line_opt[] = { "slopetype", "frontsector", "backsector", - "firsttag", - "nexttag", "polyobj", "text", "callcount", @@ -583,7 +579,7 @@ static int sector_get(lua_State *L) lua_pushinteger(L, sector->special); return 1; case sector_tag: - lua_pushinteger(L, sector->tag); + lua_pushinteger(L, Tag_FGet(§or->tags)); return 1; case sector_thinglist: // thinglist lua_pushcfunction(L, lib_iterateSectorThinglist); @@ -684,7 +680,7 @@ static int sector_set(lua_State *L) sector->special = (INT16)luaL_checkinteger(L, 3); break; case sector_tag: - P_ChangeSectorTag((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); + Tag_SectorFSet((UINT32)(sector - sectors), (INT16)luaL_checkinteger(L, 3)); break; } return 0; @@ -823,7 +819,7 @@ static int line_get(lua_State *L) lua_pushinteger(L, line->special); return 1; case line_tag: - lua_pushinteger(L, line->tag); + lua_pushinteger(L, Tag_FGet(&line->tags)); return 1; case line_args: LUA_PushUserdata(L, line->args, META_LINEARGS); @@ -871,12 +867,6 @@ static int line_get(lua_State *L) case line_backsector: LUA_PushUserdata(L, line->backsector, META_SECTOR); return 1; - case line_firsttag: - lua_pushinteger(L, line->firsttag); - return 1; - case line_nexttag: - lua_pushinteger(L, line->nexttag); - return 1; case line_polyobj: LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); return 1; diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index a1a3e96c93afd9d036ad6f8120e6a1c0bf82b9ac..7aae18c90a31f43dd43fefc6e33c6085003d20af 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -39,6 +39,11 @@ enum mobj_e { mobj_frame, mobj_sprite2, mobj_anim_duration, + mobj_spritexscale, + mobj_spriteyscale, + mobj_spritexoffset, + mobj_spriteyoffset, + mobj_floorspriteslope, mobj_touching_sectorlist, mobj_subsector, mobj_floorz, @@ -56,8 +61,10 @@ enum mobj_e { mobj_flags, mobj_flags2, mobj_eflags, + mobj_renderflags, mobj_skin, mobj_color, + mobj_blendmode, mobj_bnext, mobj_bprev, mobj_hnext, @@ -108,6 +115,11 @@ static const char *const mobj_opt[] = { "frame", "sprite2", "anim_duration", + "spritexscale", + "spriteyscale", + "spritexoffset", + "spriteyoffset", + "floorspriteslope", "touching_sectorlist", "subsector", "floorz", @@ -125,8 +137,10 @@ static const char *const mobj_opt[] = { "flags", "flags2", "eflags", + "renderflags", "skin", "color", + "blendmode", "bnext", "bprev", "hnext", @@ -227,6 +241,21 @@ static int mobj_get(lua_State *L) case mobj_anim_duration: lua_pushinteger(L, mo->anim_duration); break; + case mobj_spritexscale: + lua_pushfixed(L, mo->spritexscale); + break; + case mobj_spriteyscale: + lua_pushfixed(L, mo->spriteyscale); + break; + case mobj_spritexoffset: + lua_pushfixed(L, mo->spritexoffset); + break; + case mobj_spriteyoffset: + lua_pushfixed(L, mo->spriteyoffset); + break; + case mobj_floorspriteslope: + LUA_PushUserdata(L, mo->floorspriteslope, META_SLOPE); + break; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -277,6 +306,9 @@ static int mobj_get(lua_State *L) case mobj_eflags: lua_pushinteger(L, mo->eflags); break; + case mobj_renderflags: + lua_pushinteger(L, mo->renderflags); + break; case mobj_skin: // skin name or nil, not struct if (!mo->skin) return 0; @@ -285,6 +317,9 @@ static int mobj_get(lua_State *L) case mobj_color: lua_pushinteger(L, mo->color); break; + case mobj_blendmode: + lua_pushinteger(L, mo->blendmode); + break; case mobj_bnext: LUA_PushUserdata(L, mo->bnext, META_MOBJ); break; @@ -492,6 +527,20 @@ static int mobj_set(lua_State *L) case mobj_anim_duration: mo->anim_duration = (UINT16)luaL_checkinteger(L, 3); break; + case mobj_spritexscale: + mo->spritexscale = luaL_checkfixed(L, 3); + break; + case mobj_spriteyscale: + mo->spriteyscale = luaL_checkfixed(L, 3); + break; + case mobj_spritexoffset: + mo->spritexoffset = luaL_checkfixed(L, 3); + break; + case mobj_spriteyoffset: + mo->spriteyoffset = luaL_checkfixed(L, 3); + break; + case mobj_floorspriteslope: + return NOSET; case mobj_touching_sectorlist: return UNIMPLEMENTED; case mobj_subsector: @@ -580,6 +629,9 @@ static int mobj_set(lua_State *L) case mobj_eflags: mo->eflags = (UINT32)luaL_checkinteger(L, 3); break; + case mobj_renderflags: + mo->renderflags = (UINT32)luaL_checkinteger(L, 3); + break; case mobj_skin: // set skin by name { INT32 i; @@ -603,6 +655,9 @@ static int mobj_set(lua_State *L) mo->color = newcolor; break; } + case mobj_blendmode: + mo->blendmode = (INT32)luaL_checkinteger(L, 3); + break; case mobj_bnext: return NOSETPOS; case mobj_bprev: @@ -848,7 +903,7 @@ static int mapthing_get(lua_State *L) else if(fastcmp(field,"extrainfo")) number = mt->extrainfo; else if(fastcmp(field,"tag")) - number = mt->tag; + number = Tag_FGet(&mt->tags); else if(fastcmp(field,"args")) { LUA_PushUserdata(L, mt->args, META_THINGARGS); @@ -910,7 +965,7 @@ static int mapthing_set(lua_State *L) mt->extrainfo = (UINT8)extrainfo; } else if (fastcmp(field,"tag")) - mt->tag = (INT16)luaL_checkinteger(L, 3); + Tag_FSet(&mt->tags, (INT16)luaL_checkinteger(L, 3)); else if(fastcmp(field,"mobj")) mt->mobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)); else diff --git a/src/lua_script.c b/src/lua_script.c index 6e40cb785444d15b39f7aacdd571e6d1cb393ab4..bb022f9ce1b4d52c92b0ebbb11dbf5469ce0ce53 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -443,6 +443,10 @@ static void LUA_ClearState(void) lua_newtable(L); lua_setfield(L, LUA_REGISTRYINDEX, LREG_VALID); + // make LREG_METATABLES table for all registered metatables + lua_newtable(L); + lua_setfield(L, LUA_REGISTRYINDEX, LREG_METATABLES); + // open srb2 libraries for(i = 0; liblist[i]; i++) { lua_pushcfunction(L, liblist[i]); @@ -980,8 +984,17 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex) lua_pop(gL, 1); } if (!found) + { t++; + if (t == 0) + { + CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); + WRITEUINT8(save_p, ARCH_NULL); + return 0; + } + } + WRITEUINT8(save_p, ARCH_TABLE); WRITEUINT16(save_p, t); @@ -1294,8 +1307,22 @@ static void ArchiveTables(void) lua_pop(gL, 1); } - lua_pop(gL, 1); WRITEUINT8(save_p, ARCH_TEND); + + // Write metatable ID + if (lua_getmetatable(gL, -1)) + { + // registry.metatables[metatable] + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_pushvalue(gL, -2); + lua_gettable(gL, -2); + WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); + lua_pop(gL, 3); + } + else + WRITEUINT16(save_p, 0); + + lua_pop(gL, 1); } } @@ -1466,6 +1493,7 @@ static void UnArchiveTables(void) { int TABLESINDEX; UINT16 i, n; + UINT16 metatableid; if (!gL) return; @@ -1490,6 +1518,19 @@ static void UnArchiveTables(void) else lua_rawset(gL, -3); } + + metatableid = READUINT16(save_p); + if (metatableid) + { + // setmetatable(table, registry.metatables[metatableid]) + lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); + lua_rawgeti(gL, -1, metatableid); + if (lua_isnil(gL, -1)) + I_Error("Unknown metatable ID %d\n", metatableid); + lua_setmetatable(gL, -3); + lua_pop(gL, 1); + } + lua_pop(gL, 1); } } diff --git a/src/m_anigif.c b/src/m_anigif.c index 85118790bf6f72b28a81069d3a59117a5bb57cbf..dbc8d3422366f4c8cf255cde5e66ea55cb9cbddf 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -29,15 +29,21 @@ // GIFs are always little-endian #include "byteptr.h" +CV_PossibleValue_t gif_dynamicdelay_cons_t[] = { + {0, "Off"}, + {1, "On"}, + {2, "Accurate, experimental"}, +{0, NULL}}; + consvar_t cv_gif_optimize = CVAR_INIT ("gif_optimize", "On", CV_SAVE, CV_OnOff, NULL); consvar_t cv_gif_downscale = CVAR_INIT ("gif_downscale", "On", CV_SAVE, CV_OnOff, NULL); -consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, CV_OnOff, NULL); +consvar_t cv_gif_dynamicdelay = CVAR_INIT ("gif_dynamicdelay", "On", CV_SAVE, gif_dynamicdelay_cons_t, NULL); consvar_t cv_gif_localcolortable = CVAR_INIT ("gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL); #ifdef HAVE_ANIGIF static boolean gif_optimize = false; // So nobody can do something dumb static boolean gif_downscale = false; // like changing cvars mid output -static boolean gif_dynamicdelay = false; // and messing something up +static UINT8 gif_dynamicdelay = (UINT8)0; // and messing something up // Palette handling static boolean gif_localcolortable = false; @@ -47,7 +53,8 @@ static RGBA_t *gif_framepalette = NULL; static FILE *gif_out = NULL; static INT32 gif_frames = 0; -static UINT32 gif_prevframems = 0; +static UINT32 gif_prevframeus = 0; // "us" is microseconds +static UINT32 gif_delayus = 0; static UINT8 gif_writeover = 0; @@ -594,16 +601,30 @@ static void GIF_framewrite(void) // screen regions are handled in GIF_lzw { - UINT16 delay; + UINT16 delay = 0; INT32 startline; - if (gif_dynamicdelay) { + if (gif_dynamicdelay ==(UINT8) 2) + { // golden's attempt at creating a "dynamic delay" + UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). + gif_delayus += (I_GetTimeMicros() - gif_prevframeus); // increase delay by how much time was spent between last measurement + + if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay? + { + int frames = (gif_delayus/1000) / mingifdelay; // get amount of frames to delay. + delay = frames; // set the delay to delay that amount of frames. + gif_delayus -= frames*(mingifdelay*1000); // remove frames by the amount of milliseconds they take. don't reset to 0, the microseconds help consistency. + } + } + else if (gif_dynamicdelay ==(UINT8) 1) + { float delayf = ceil(100.0f/NEWTICRATE); - delay = (UINT16)((I_GetTimeMicros() - gif_prevframems)/10/1000); - if (delay < (int)(delayf)) - delay = (int)(delayf); + delay = (UINT16)((I_GetTimeMicros() - gif_prevframeus)/10/1000); + + if (delay < (UINT16)(delayf)) + delay = (UINT16)(delayf); } else { @@ -690,7 +711,7 @@ static void GIF_framewrite(void) } fwrite(gifframe_data, 1, (p - gifframe_data), gif_out); ++gif_frames; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); } @@ -711,14 +732,15 @@ INT32 GIF_open(const char *filename) gif_optimize = (!!cv_gif_optimize.value); gif_downscale = (!!cv_gif_downscale.value); - gif_dynamicdelay = (!!cv_gif_dynamicdelay.value); + gif_dynamicdelay = (UINT8)cv_gif_dynamicdelay.value; gif_localcolortable = (!!cv_gif_localcolortable.value); gif_colorprofile = (!!cv_screenshot_colorprofile.value); gif_headerpalette = GIF_getpalette(0); GIF_headwrite(); gif_frames = 0; - gif_prevframems = I_GetTimeMicros(); + gif_prevframeus = I_GetTimeMicros(); + gif_delayus = 0; return 1; } diff --git a/src/m_cheat.c b/src/m_cheat.c index 8e9cd9f51d9020e63b47f7f2ac66274c22cc9d13..6e0fb8c5c0784f66be508981aa33d75f9a661d89 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1108,7 +1108,6 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value; mt->scale = player->mo->scale; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; @@ -1435,7 +1434,7 @@ void Command_Writethings_f(void) REQUIRE_SINGLEPLAYER; REQUIRE_OBJECTPLACE; - P_WriteThings(W_GetNumForName(G_BuildMapName(gamemap)) + ML_THINGS); + P_WriteThings(); } void Command_ObjectPlace_f(void) diff --git a/src/m_menu.c b/src/m_menu.c index 5860f00ca1a1f4dc5399982f06ccebc21c3d469b..d31e2154ce099671f1c9abcf740fb8ff42219454 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1483,7 +1483,7 @@ static menuitem_t OP_SoundOptionsMenu[] = {IT_STRING | IT_CVAR, NULL, "MIDI Music", &cv_gamemidimusic, 36}, {IT_STRING | IT_CVAR | IT_CV_SLIDER, NULL, "MIDI Music Volume", &cv_midimusicvolume, 41}, - + {IT_STRING | IT_CVAR, NULL, "Music Preference", &cv_musicpref, 51}, {IT_HEADER, NULL, "Miscellaneous", NULL, 61}, @@ -2145,15 +2145,20 @@ menu_t OP_PlaystyleDef = { static void M_VideoOptions(INT32 choice) { (void)choice; + + OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR); + OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer"; + OP_VideoOptionsMenu[op_video_renderer].text = "Software"; + #ifdef HWRENDER - if (vid_opengl_state == -1) + if (vid.glstate != VID_GL_LIBRARY_ERROR) { - OP_VideoOptionsMenu[op_video_renderer].status = (IT_TRANSTEXT | IT_PAIR); - OP_VideoOptionsMenu[op_video_renderer].patch = "Renderer"; - OP_VideoOptionsMenu[op_video_renderer].text = "Software"; + OP_VideoOptionsMenu[op_video_renderer].status = (IT_STRING | IT_CVAR); + OP_VideoOptionsMenu[op_video_renderer].patch = NULL; + OP_VideoOptionsMenu[op_video_renderer].text = "Renderer"; } - #endif + M_SetupNextMenu(&OP_VideoOptionsDef); } @@ -5585,9 +5590,6 @@ static void M_DrawLevelPlatterWideMap(UINT8 row, UINT8 col, INT32 x, INT32 y, bo if (map <= 0) return; - if (needpatchrecache) - M_CacheLevelPlatter(); - // A 564x100 image of the level as entry MAPxxW if (!(levelselect.rows[row].mapavailable[col])) { @@ -5619,9 +5621,6 @@ static void M_DrawLevelPlatterMap(UINT8 row, UINT8 col, INT32 x, INT32 y, boolea if (map <= 0) return; - if (needpatchrecache) - M_CacheLevelPlatter(); - // A 160x100 image of the level as entry MAPxxP if (!(levelselect.rows[row].mapavailable[col])) { @@ -5831,8 +5830,6 @@ static void M_DrawNightsAttackSuperSonic(void) const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE); INT32 timer = (ntsatkdrawtimer/4) % 2; angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK; - ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH); - ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); V_DrawFixedPatch(235<<FRACBITS, (120<<FRACBITS) - (8*FINESINE(fa)), FRACUNIT, 0, ntssupersonic[timer], colormap); } @@ -6176,7 +6173,7 @@ static void M_StopMessage(INT32 choice) static void M_DrawImageDef(void) { // Grr. Need to autodetect for pic_ts. - pic_t *pictest = (pic_t *)W_CachePatchName(currentMenu->menuitems[itemOn].text,PU_CACHE); + pic_t *pictest = (pic_t *)W_CacheLumpName(currentMenu->menuitems[itemOn].text,PU_CACHE); if (!pictest->zero) V_DrawScaledPic(0,0,0,W_GetNumForName(currentMenu->menuitems[itemOn].text)); else @@ -6444,10 +6441,6 @@ static void M_DrawAddons(void) return; } - // Lactozilla: Load addons menu patches. - if (needpatchrecache) - M_LoadAddonsPatches(); - if (Playing()) V_DrawCenteredString(BASEVIDWIDTH/2, 5, warningflags, "Adding files mid-game may cause problems."); else @@ -7602,9 +7595,6 @@ static void M_DrawSoundTest(void) fixed_t hscale = FRACUNIT/2, vscale = FRACUNIT/2, bounce = 0; UINT8 frame[4] = {0, 0, -1, SKINCOLOR_RUBY}; - if (needpatchrecache) - M_CacheSoundTest(); - // let's handle the ticker first. ideally we'd tick this somewhere else, BUT... if (curplaying) { @@ -8252,9 +8242,6 @@ static void M_DrawLoadGameData(void) if (vid.width != BASEVIDWIDTH*vid.dupx) hsep = (hsep*vid.width)/(BASEVIDWIDTH*vid.dupx); - if (needpatchrecache) - M_CacheLoadGameData(); - for (i = 2; prev_i; i = -(i + ((UINT32)i >> 31))) // draws from outwards in; 2, -2, 1, -1, 0 { prev_i = i; @@ -8958,6 +8945,7 @@ void M_ForceSaveSlotSelected(INT32 sslot) // ================ // CHARACTER SELECT // ================ + static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) { if (!(description[i].picname[0])) @@ -8978,22 +8966,6 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); } -static void M_CacheCharacterSelect(void) -{ - INT32 i, skinnum; - - for (i = 0; i < MAXSKINS; i++) - { - if (!description[i].used) - continue; - - // Already set in M_SetupChoosePlayer - skinnum = description[i].skinnum[0]; - if ((skinnum != -1) && (R_SkinUsable(-1, skinnum))) - M_CacheCharacterSelectEntry(i, skinnum); - } -} - static UINT8 M_SetupChoosePlayerDirect(INT32 choice) { INT32 skinnum; @@ -9200,9 +9172,6 @@ static void M_DrawSetupChoosePlayerMenu(void) INT32 x, y; INT32 w = (vid.width/vid.dupx); - if (needpatchrecache) - M_CacheCharacterSelect(); - if (abs(char_scroll) > FRACUNIT) char_scroll -= (char_scroll>>2); else // close enough. @@ -10173,6 +10142,9 @@ static void M_NightsAttack(INT32 choice) // This is really just to make sure Sonic is the played character, just in case M_PatchSkinNameTable(); + ntssupersonic[0] = W_CachePatchName("NTSSONC1", PU_PATCH); + ntssupersonic[1] = W_CachePatchName("NTSSONC2", PU_PATCH); + G_SetGamestate(GS_TIMEATTACK); // do this before M_SetupNextMenu so that menu meta state knows that we're switching titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please M_SetupNextMenu(&SP_NightsAttackDef); @@ -10574,10 +10546,6 @@ void M_DrawMarathon(void) angle_t fa; INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy), xspan = (vid.width/dupz), yspan = (vid.height/dupz), diffx = (xspan - BASEVIDWIDTH)/2, diffy = (yspan - BASEVIDHEIGHT)/2, maxy = BASEVIDHEIGHT + diffy; - // lactozilla: the renderer changed so recache patches - if (needpatchrecache) - M_CacheCharacterSelect(); - curbgxspeed = 0; curbgyspeed = 18; diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 3c3c507cd168e46a50ccdce3a503c8570c028797..f12499d5ce6315e1a8baf70b43f454443ae0bef8 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -394,8 +394,10 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -593,7 +595,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) } - ceiling->tag = sec->tag; + ceiling->tag = tag; ceiling->type = type; firstone = 0; } @@ -614,8 +616,10 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) INT32 secnum = -1; sector_t *sec; ceiling_t *ceiling; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -670,7 +674,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) break; } - ceiling->tag = sec->tag; + ceiling->tag = tag; ceiling->type = type; } return rtn; diff --git a/src/p_enemy.c b/src/p_enemy.c index ddb01b63ba4fdb2a0fa7ea1cc524a4f531f1b5d8..f9baf1813c7d7d894f2707d14f6f19a75682c6f7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3925,11 +3925,12 @@ void A_BossDeath(mobj_t *mo) else { // Bring the egg trap up to the surface - junk.tag = LE_CAPSULE0; + // Incredibly shitty code ahead + Tag_FSet(&junk.tags, LE_CAPSULE0); EV_DoElevator(&junk, elevateHighest, false); - junk.tag = LE_CAPSULE1; + Tag_FSet(&junk.tags, LE_CAPSULE1); EV_DoElevator(&junk, elevateUp, false); - junk.tag = LE_CAPSULE2; + Tag_FSet(&junk.tags, LE_CAPSULE2); EV_DoElevator(&junk, elevateHighest, false); if (mapheaderinfo[gamemap-1]->muspostbossname[0] && @@ -4052,7 +4053,7 @@ bossjustdie: } case MT_KOOPA: { - junk.tag = LE_KOOPA; + Tag_FSet(&junk.tags, LE_KOOPA); EV_DoCeiling(&junk, raiseToHighest); return; } @@ -6157,7 +6158,7 @@ void A_RockSpawn(mobj_t *actor) { mobj_t *mo; mobjtype_t type; - INT32 i = P_FindSpecialLineFromTag(12, (INT16)actor->threshold, -1); + INT32 i = Tag_FindLineSpecial(12, (INT16)actor->threshold); line_t *line; fixed_t dist; fixed_t randomoomph; diff --git a/src/p_floor.c b/src/p_floor.c index a0f7edd9ca0e68617b1eede0441c5a14a2dbe549..ed49b03a38ef8b4381ad968a4540c09952d1d018 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -632,8 +632,10 @@ void T_BounceCheese(bouncecheese_t *bouncer) fixed_t waterheight; fixed_t floorheight; sector_t *actionsector; - INT32 i; boolean remove; + INT32 i; + mtag_t tag = Tag_FGet(&bouncer->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); if (bouncer->sector->crumblestate == CRUMBLE_RESTORE || bouncer->sector->crumblestate == CRUMBLE_WAIT || bouncer->sector->crumblestate == CRUMBLE_ACTIVATED) // Oops! Crumbler says to remove yourself! @@ -648,7 +650,7 @@ void T_BounceCheese(bouncecheese_t *bouncer) } // You can use multiple target sectors, but at your own risk!!! - for (i = -1; (i = P_FindSectorFromTag(bouncer->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { actionsector = §ors[i]; actionsector->moved = true; @@ -772,6 +774,8 @@ void T_StartCrumble(crumble_t *crumble) ffloor_t *rover; sector_t *sector; INT32 i; + mtag_t tag = Tag_FGet(&crumble->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); // Once done, the no-return thinker just sits there, // constantly 'returning'... kind of an oxymoron, isn't it? @@ -800,7 +804,7 @@ void T_StartCrumble(crumble_t *crumble) } else if (++crumble->timer == 0) // Reposition back to original spot { - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -836,7 +840,7 @@ void T_StartCrumble(crumble_t *crumble) // Flash to indicate that the platform is about to return. if (crumble->timer > -224 && (leveltime % ((abs(crumble->timer)/8) + 1) == 0)) { - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -928,7 +932,7 @@ void T_StartCrumble(crumble_t *crumble) P_RemoveThinker(&crumble->thinker); } - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; sector->moved = true; @@ -944,6 +948,7 @@ void T_StartCrumble(crumble_t *crumble) void T_MarioBlock(mariothink_t *block) { INT32 i; + TAG_ITER_DECLARECOUNTER(0); T_MovePlane ( @@ -978,8 +983,7 @@ void T_MarioBlock(mariothink_t *block) block->sector->ceilspeed = 0; block->direction = 0; } - - for (i = -1; (i = P_FindSectorFromTag(block->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, (INT16)block->tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -992,8 +996,7 @@ void T_FloatSector(floatthink_t *floater) // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag(floater->tag, -1); - if (secnum <= 0) + if ((secnum = Tag_Iterate_Sectors((INT16)floater->tag, 0)) < 0) return; actionsector = §ors[secnum]; @@ -1131,10 +1134,8 @@ void T_ThwompSector(thwomp_t *thwomp) // Just find the first sector with the tag. // Doesn't work with multiple sectors that have different floor/ceiling heights. - secnum = P_FindSectorFromTag(thwomp->tag, -1); - - if (secnum <= 0) - return; // Bad bad bad! + if ((secnum = Tag_Iterate_Sectors((INT16)thwomp->tag, 0)) < 0) + return; actionsector = §ors[secnum]; @@ -1293,8 +1294,10 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) sector_t *sec = NULL; INT32 secnum = -1; boolean FOFsector = false; + mtag_t tag = Tag_FGet(&nobaddies->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(nobaddies->sourceline->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -1304,13 +1307,15 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) for (i = 0; i < sec->linecount; i++) { INT32 targetsecnum = -1; + mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); + TAG_ITER_DECLARECOUNTER(1); if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) continue; FOFsector = true; - while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) + TAG_ITER_SECTORS(1, tag2, targetsecnum) { if (T_SectorHasEnemies(§ors[targetsecnum])) return; @@ -1321,7 +1326,7 @@ void T_NoEnemiesSector(noenemies_t *nobaddies) return; } - CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag); + CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", tag); // No enemies found, run the linedef exec and terminate this thinker P_RunTriggerLinedef(nobaddies->sourceline, NULL, NULL); @@ -1396,6 +1401,8 @@ void T_EachTimeThinker(eachtime_t *eachtime) boolean floortouch = false; fixed_t bottomheight, topheight; ffloor_t *rover; + mtag_t tag = Tag_FGet(&eachtime->sourceline->tags); + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < MAXPLAYERS; i++) { @@ -1405,7 +1412,7 @@ void T_EachTimeThinker(eachtime_t *eachtime) eachtime->playersOnArea[i] = false; } - while ((secnum = P_FindSectorFromTag(eachtime->sourceline->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -1422,13 +1429,15 @@ void T_EachTimeThinker(eachtime_t *eachtime) for (i = 0; i < sec->linecount; i++) { INT32 targetsecnum = -1; + mtag_t tag2 = Tag_FGet(&sec->lines[i]->tags); + TAG_ITER_DECLARECOUNTER(1); if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300) continue; FOFsector = true; - while ((targetsecnum = P_FindSectorFromTag(sec->lines[i]->tag, targetsecnum)) >= 0) + TAG_ITER_SECTORS(1, tag2, targetsecnum) { targetsec = §ors[targetsecnum]; @@ -1530,7 +1539,7 @@ void T_EachTimeThinker(eachtime_t *eachtime) if (!playersArea[i] && (!eachtime->triggerOnExit || !P_IsPlayerValid(i))) continue; - CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", eachtime->sourceline->tag); + CONS_Debug(DBG_GAMELOGIC, "Trying to activate each time executor with tag %d\n", tag); // 03/08/14 -Monster Iestyn // No more stupid hacks involving changing eachtime->sourceline's tag or special or whatever! @@ -1562,11 +1571,13 @@ void T_RaiseSector(raise_t *raise) fixed_t distToNearestEndpoint; INT32 direction; result_e res = 0; + mtag_t tag = raise->tag; + TAG_ITER_DECLARECOUNTER(0); if (raise->sector->crumblestate >= CRUMBLE_FALL || raise->sector->ceilingdata) return; - for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { sector = §ors[i]; @@ -1693,7 +1704,7 @@ void T_RaiseSector(raise_t *raise) raise->sector->ceilspeed = 42; raise->sector->floorspeed = speed*direction; - for (i = -1; (i = P_FindSectorFromTag(raise->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) P_RecalcPrecipInSector(§ors[i]); } @@ -1810,8 +1821,10 @@ void EV_DoFloor(line_t *line, floor_e floortype) INT32 secnum = -1; sector_t *sec; floormove_t *dofloor; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -2025,9 +2038,11 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) INT32 secnum = -1; sector_t *sec; elevator_t *elevator; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromTag(line->tag,secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; @@ -2148,6 +2163,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) INT16 flags; sector_t *controlsec = rover->master->frontsector; + mtag_t tag = Tag_FGet(&controlsec->tags); if (sec == NULL) { @@ -2176,9 +2192,9 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) lifetime = 3*TICRATE; flags = 0; - if (controlsec->tag != 0) + if (tag != 0) { - INT32 tagline = P_FindSpecialLineFromTag(14, controlsec->tag, -1); + INT32 tagline = Tag_FindLineSpecial(14, tag); if (tagline != -1) { if (sides[lines[tagline].sidenum[0]].toptexture) @@ -2322,6 +2338,8 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble_t *crumble; sector_t *foundsec; INT32 i; + mtag_t tag = Tag_FGet(&rover->master->tags); + TAG_ITER_DECLARECOUNTER(0); // If floor is already activated, skip it if (sec->floordata) @@ -2364,7 +2382,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble->sector->crumblestate = CRUMBLE_ACTIVATED; - for (i = -1; (i = P_FindSectorFromTag(crumble->sourceline->tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { foundsec = §ors[i]; @@ -2413,7 +2431,7 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) block->direction = 1; block->floorstartheight = block->sector->floorheight; block->ceilingstartheight = block->sector->ceilingheight; - block->tag = (INT16)sector->tag; + block->tag = (INT16)Tag_FGet(§or->tags); if (itsamonitor) { diff --git a/src/p_inter.c b/src/p_inter.c index bd044f32a1672f81eacb28c1b9a284643d796591..415c679e4922b1d55920bc5f937c39fee1927e30 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1388,7 +1388,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (player->bot) return; - junk.tag = LE_AXE; + Tag_FSet(&junk.tags, LE_AXE); EV_DoElevator(&junk, bridgeFall, false); // scan the remaining thinkers to find koopa diff --git a/src/p_lights.c b/src/p_lights.c index 371077a302d39b903b88658baf492d38680dcbb7..d396e92d3dedff6ac56f40901335ec701d6625e9 100644 --- a/src/p_lights.c +++ b/src/p_lights.c @@ -374,8 +374,10 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean void P_FadeLight(INT16 tag, INT32 destvalue, INT32 speed, boolean ticbased, boolean force) { INT32 i; + TAG_ITER_DECLARECOUNTER(0); + // search all sectors for ones with tag - for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, i) { if (!force && ticbased // always let speed fader execute && sectors[i].lightingdata diff --git a/src/p_map.c b/src/p_map.c index 0a9107ee546239a47309d9600421ef4d1a6e29c7..922c0d9ec06c8a7f6c74d73b209ab961cc8ec571 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -2735,7 +2735,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) // Step up if (thing->z < tmfloorz) { - if (tmfloorz - thing->z <= maxstep) + if (maxstep > 0 && tmfloorz - thing->z <= maxstep) { thing->z = thing->floorz = tmfloorz; thing->floorrover = tmfloorrover; @@ -2748,7 +2748,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff) } else if (tmceilingz < thingtop) { - if (thingtop - tmceilingz <= maxstep) + if (maxstep > 0 && thingtop - tmceilingz <= maxstep) { thing->z = ( thing->ceilingz = tmceilingz ) - thing->height; thing->ceilingrover = tmceilingrover; @@ -3107,7 +3107,7 @@ static void P_HitSlideLine(line_t *ld) lineangle >>= ANGLETOFINESHIFT; deltaangle >>= ANGLETOFINESHIFT; - movelen = P_AproxDistance(tmxmove, tmymove); + movelen = R_PointToDist2(0, 0, tmxmove, tmymove); newlen = FixedMul(movelen, FINECOSINE(deltaangle)); tmxmove = FixedMul(newlen, FINECOSINE(lineangle)); diff --git a/src/p_mobj.c b/src/p_mobj.c index 414d0435c7246fea7e2669f826bf66cc25cf5bda..7ba6d1fad979ff68c563f00693c1ba94b5fbdf93 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -38,10 +38,6 @@ static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); -#ifdef WALLSPLATS -consvar_t cv_splats = CVAR_INIT ("splats", "On", CV_SAVE, CV_OnOff, NULL); -#endif - actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; @@ -1961,29 +1957,6 @@ void P_XYMovement(mobj_t *mo) return; } - // draw damage on wall - //SPLAT TEST ---------------------------------------------------------- -#ifdef WALLSPLATS - if (blockingline && mo->type != MT_REDRING && mo->type != MT_FIREBALL - && !(mo->flags2 & (MF2_AUTOMATIC|MF2_RAILRING|MF2_BOUNCERING|MF2_EXPLOSION|MF2_SCATTER))) - // set by last P_TryMove() that failed - { - divline_t divl; - divline_t misl; - fixed_t frac; - - P_MakeDivline(blockingline, &divl); - misl.x = mo->x; - misl.y = mo->y; - misl.dx = mo->momx; - misl.dy = mo->momy; - frac = P_InterceptVector(&divl, &misl); - R_AddWallSplat(blockingline, P_PointOnLineSide(mo->x,mo->y,blockingline), - "A_DMG3", mo->z, frac, SPLATDRAWMODE_SHADE); - } -#endif - // --------------------------------------------------------- SPLAT TEST - P_ExplodeMissile(mo); return; } @@ -3536,16 +3509,19 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) { sector_t *sector; fixed_t halfheight = thiscam->z + (thiscam->height >> 1); + size_t i; // see if we are in water sector = thiscam->subsector->sector; - if (P_FindSpecialLineFromTag(13, sector->tag, -1) != -1) - return true; + for (i = 0; i < sector->tags.count; i++) + if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) + return true; if (sector->ffloors) { ffloor_t *rover; + size_t j; for (rover = sector->ffloors; rover; rover = rover->next) { @@ -3557,7 +3533,8 @@ static boolean P_CameraCheckHeat(camera_t *thiscam) if (halfheight <= P_GetFFloorBottomZAt(rover, thiscam->x, thiscam->y)) continue; - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) + for (j = 0; j < rover->master->frontsector->tags.count; j++) + if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) return true; } } @@ -4626,16 +4603,18 @@ static boolean P_Boss4MoveCage(mobj_t *mobj, fixed_t delta) const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); INT32 snum; sector_t *sector; - for (snum = sectors[tag%numsectors].firsttag; snum != -1; snum = sector->nexttag) + boolean gotcage = false; + TAG_ITER_DECLARECOUNTER(0); + + TAG_ITER_SECTORS(0, tag, snum) { sector = §ors[snum]; - if (sector->tag != tag) - continue; sector->floorheight += delta; sector->ceilingheight += delta; P_CheckSector(sector, true); + gotcage = true; } - return sectors[tag%numsectors].firsttag != -1; + return gotcage; } // Move Boss4's arms to angle @@ -4707,26 +4686,16 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t dz) static void P_Boss4DestroyCage(mobj_t *mobj) { const UINT16 tag = 65534 + (mobj->spawnpoint ? mobj->spawnpoint->extrainfo*LE_PARAMWIDTH : 0); - INT32 snum, next; + INT32 snum; size_t a; sector_t *sector, *rsec; ffloor_t *rover; + TAG_ITER_DECLARECOUNTER(0); - // This will be the final iteration of sector tag. - // We'll destroy the tag list as we go. - next = sectors[tag%numsectors].firsttag; - sectors[tag%numsectors].firsttag = -1; - - for (snum = next; snum != -1; snum = next) + TAG_ITER_SECTORS(0, tag, snum) { sector = §ors[snum]; - next = sector->nexttag; - sector->nexttag = -1; - if (sector->tag != tag) - continue; - sector->tag = 0; - // Destroy the FOFs. for (a = 0; a < sector->numattached; a++) { @@ -9614,12 +9583,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) mobj->fuse = 1; // Return to base. break; } - case MT_CANNONBALL: -#ifdef FLOORSPLATS - R_AddFloorSplat(mobj->tracer->subsector, mobj->tracer, "TARGET", mobj->tracer->x, - mobj->tracer->y, mobj->tracer->floorz, SPLATDRAWMODE_SHADE); -#endif - break; case MT_SPINDUST: // Spindash dust mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same @@ -10046,11 +10009,12 @@ void P_MobjThinker(mobj_t *mobj) // Sector special (2,8) allows ANY mobj to trigger a linedef exec if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8) { - sector_t *sec2; - - sec2 = P_ThingOnSpecial3DFloor(mobj); + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - P_LinedefExecute(sec2->tag, mobj, sec2); + { + mtag_t tag = Tag_FGet(&sec2->tags); + P_LinedefExecute(tag, mobj, sec2); + } } if (mobj->scale != mobj->destscale) @@ -10274,14 +10238,19 @@ void P_PushableThinker(mobj_t *mobj) sec = mobj->subsector->sector; if (GETSECSPECIAL(sec->special, 2) == 1 && mobj->z == sec->floorheight) - P_LinedefExecute(sec->tag, mobj, sec); -// else if (GETSECSPECIAL(sec->special, 2) == 8) { - sector_t *sec2; + mtag_t tag = Tag_FGet(&sec->tags); + P_LinedefExecute(tag, mobj, sec); + } - sec2 = P_ThingOnSpecial3DFloor(mobj); +// else if (GETSECSPECIAL(sec->special, 2) == 8) + { + sector_t *sec2 = P_ThingOnSpecial3DFloor(mobj); if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - P_LinedefExecute(sec2->tag, mobj, sec2); + { + mtag_t tag = Tag_FGet(&sec2->tags); + P_LinedefExecute(tag, mobj, sec2); + } } // it has to be pushable RIGHT NOW for this part to happen @@ -10502,6 +10471,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if ((maptol & TOL_ERZ3) && !(mobj->type == MT_BLACKEGGMAN)) mobj->destscale = FRACUNIT/2; + // Sprite rendering + mobj->blendmode = AST_TRANSLUCENT; + mobj->spritexscale = mobj->spriteyscale = mobj->scale; + mobj->spritexoffset = mobj->spriteyoffset = 0; + mobj->floorspriteslope = NULL; + // set subsector and/or block links P_SetThingPosition(mobj); I_Assert(mobj->subsector != NULL); @@ -10902,6 +10877,22 @@ static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mob return mo; } +void *P_CreateFloorSpriteSlope(mobj_t *mobj) +{ + if (mobj->floorspriteslope) + Z_Free(mobj->floorspriteslope); + mobj->floorspriteslope = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL); + mobj->floorspriteslope->normal.z = FRACUNIT; + return (void *)mobj->floorspriteslope; +} + +void P_RemoveFloorSpriteSlope(mobj_t *mobj) +{ + if (mobj->floorspriteslope) + Z_Free(mobj->floorspriteslope); + mobj->floorspriteslope = NULL; +} + // // P_RemoveMobj // @@ -10958,11 +10949,14 @@ void P_RemoveMobj(mobj_t *mobj) P_DelSeclist(sector_list); sector_list = NULL; } + mobj->flags |= MF_NOSECTOR|MF_NOBLOCKMAP; mobj->subsector = NULL; mobj->state = NULL; mobj->player = NULL; + P_RemoveFloorSpriteSlope(mobj); + // stop any playing sound S_StopSound(mobj); @@ -12030,8 +12024,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) const size_t mthingi = (size_t)(mthing - mapthings); // Find the corresponding linedef special, using angle as tag - // P_FindSpecialLineFromTag works here now =D - line = P_FindSpecialLineFromTag(9, mthing->angle, -1); + line = Tag_FindLineSpecial(9, mthing->angle); if (line == -1) { @@ -12341,7 +12334,7 @@ static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj) const size_t mthingi = (size_t)(mthing - mapthings); // Find the corresponding linedef special, using angle as tag - line = P_FindSpecialLineFromTag(15, mthing->angle, -1); + line = Tag_FindLineSpecial(15, mthing->angle); if (line == -1) { @@ -12580,17 +12573,20 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean break; } case MT_SKYBOX: - if (mthing->tag < 0 || mthing->tag > 15) + { + mtag_t tag = Tag_FGet(&mthing->tags); + if (tag < 0 || tag > 15) { - CONS_Debug(DBG_GAMELOGIC, "P_SetupSpawnedMapThing: Skybox ID %d of mapthing %s is not between 0 and 15!\n", mthing->tag, sizeu1((size_t)(mthing - mapthings))); + CONS_Debug(DBG_GAMELOGIC, "P_SetupSpawnedMapThing: Skybox ID %d of mapthing %s is not between 0 and 15!\n", tag, sizeu1((size_t)(mthing - mapthings))); break; } if (mthing->options & MTF_OBJECTSPECIAL) - skyboxcenterpnts[mthing->tag] = mobj; + skyboxcenterpnts[tag] = mobj; else - skyboxviewpnts[mthing->tag] = mobj; + skyboxviewpnts[tag] = mobj; break; + } case MT_EGGSTATUE: if (mthing->options & MTF_EXTRA) { @@ -13077,8 +13073,8 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, mobj = P_SpawnMobj(x, y, z, i); mobj->spawnpoint = mthing; - P_SetScale(mobj, mthing->scale); - mobj->destscale = mthing->scale; + P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale)); + mobj->destscale = FixedMul(mobj->destscale, mthing->scale); if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle)) return mobj; diff --git a/src/p_mobj.h b/src/p_mobj.h index 27a6ef4f05d3a2f8a5a9cf57b8fe495fe4325ff0..5bb7c908e85463020507f1e02dbb7059d904ddf6 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -194,6 +194,7 @@ typedef enum MF2_AMBUSH = 1<<27, // Alternate behaviour typically set by MTF_AMBUSH MF2_LINKDRAW = 1<<28, // Draw vissprite of mobj immediately before/after tracer's vissprite (dependent on dispoffset and position) MF2_SHIELD = 1<<29, // Thinker calls P_AddShield/P_ShieldLook (must be partnered with MF_SCENERY to use) + MF2_SPLAT = 1<<30, // Renders as a splat // free: to and including 1<<31 } mobjflag2_t; @@ -264,6 +265,7 @@ typedef enum { // Ran the thinker this tic. PCF_THUNK = 32, } precipflag_t; + // Map Object definition. typedef struct mobj_s { @@ -285,6 +287,12 @@ typedef struct mobj_s UINT8 sprite2; // player sprites UINT16 anim_duration; // for FF_ANIMATE states + UINT32 renderflags; // render flags + INT32 blendmode; // blend mode + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by + struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears struct subsector_s *subsector; // Subsector the mobj resides in. @@ -399,13 +407,19 @@ typedef struct precipmobj_s struct precipmobj_s **sprev; // killough 8/11/98: change to ptr-to-ptr // More drawing info: to determine current sprite. - angle_t angle, pitch, roll; // orientation + angle_t angle, pitch, roll; // orientation angle_t rollangle; 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 UINT16 anim_duration; // for FF_ANIMATE states + UINT32 renderflags; // render flags + INT32 blendmode; // blend mode + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by + struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears struct subsector_s *subsector; // Subsector the mobj resides in. @@ -462,6 +476,8 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime); void P_SpawnHoopOfSomething(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle); void P_SpawnPrecipitation(void); void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, statenum_t nstate, angle_t rotangle, boolean spawncenter); +void *P_CreateFloorSpriteSlope(mobj_t *mobj); +void P_RemoveFloorSpriteSlope(mobj_t *mobj); boolean P_BossTargetPlayer(mobj_t *actor, boolean closest); boolean P_SupermanLook4Players(mobj_t *actor); void P_DestroyRobots(void); diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 63d062c224bf2dbcbaa733215cfb653f711fd60b..874edbd50cfb60d6ff0308748dd149c96f8480c3 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -556,10 +556,11 @@ static void Polyobj_moveToSpawnSpot(mapthing_t *anchor) polyobj_t *po; vertex_t dist, sspot; size_t i; + mtag_t tag = Tag_FGet(&anchor->tags); - if (!(po = Polyobj_GetForNum(anchor->tag))) + if (!(po = Polyobj_GetForNum(tag))) { - CONS_Debug(DBG_POLYOBJ, "Bad polyobject %d for anchor point\n", anchor->tag); + CONS_Debug(DBG_POLYOBJ, "Bad polyobject %d for anchor point\n", tag); return; } @@ -1342,7 +1343,7 @@ void Polyobj_InitLevel(void) { qitem = (mobjqitem_t *)M_QueueIterator(&spawnqueue); - Polyobj_spawnPolyObj(i, qitem->mo, qitem->mo->spawnpoint->tag); + Polyobj_spawnPolyObj(i, qitem->mo, Tag_FGet(&qitem->mo->spawnpoint->tags)); } // move polyobjects to spawn points @@ -2444,10 +2445,11 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) polymove_t *th; size_t i; INT32 start; + mtag_t tag = pfdata->polyObjNum; - if (!(po = Polyobj_GetForNum(pfdata->polyObjNum))) + if (!(po = Polyobj_GetForNum(tag))) { - CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", pfdata->polyObjNum); + CONS_Debug(DBG_POLYOBJ, "EV_DoPolyFlag: bad polyobj %d\n", tag); return false; } @@ -2470,7 +2472,7 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) po->thinker = &th->thinker; // set fields - th->polyObjNum = pfdata->polyObjNum; + th->polyObjNum = tag; th->distance = 0; th->speed = pfdata->speed; th->angle = pfdata->angle; diff --git a/src/p_saveg.c b/src/p_saveg.c index 4f6f31803998d8cf8c19472a21d4090d779b2119..30a0c9c893088e412545c81217156deb864c4352 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -98,13 +98,16 @@ static void P_NetArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + WRITESINT8(save_p, (SINT8)adminplayers[i]); + if (!playeringame[i]) continue; flags = 0; - // no longer send ticcmds, player name, skin, or color + // no longer send ticcmds + WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); WRITEINT16(save_p, players[i].angleturn); WRITEINT16(save_p, players[i].oldrelangleturn); WRITEANGLE(save_p, players[i].aiming); @@ -134,6 +137,9 @@ static void P_NetArchivePlayers(void) WRITEUINT16(save_p, players[i].flashpal); WRITEUINT16(save_p, players[i].flashcount); + WRITEUINT8(save_p, players[i].skincolor); + WRITEINT32(save_p, players[i].skin); + WRITEUINT32(save_p, players[i].availabilities); WRITEUINT32(save_p, players[i].score); WRITEFIXED(save_p, players[i].dashspeed); WRITESINT8(save_p, players[i].lives); @@ -305,6 +311,8 @@ static void P_NetUnArchivePlayers(void) for (i = 0; i < MAXPLAYERS; i++) { + adminplayers[i] = (INT32)READSINT8(save_p); + // Do NOT memset player struct to 0 // other areas may initialize data elsewhere //memset(&players[i], 0, sizeof (player_t)); @@ -312,9 +320,8 @@ static void P_NetUnArchivePlayers(void) continue; // NOTE: sending tics should (hopefully) no longer be necessary - // sending player names, skin and color should not be necessary at all! - // (that data is handled in the server config now) + READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); players[i].angleturn = READINT16(save_p); players[i].oldrelangleturn = READINT16(save_p); players[i].aiming = READANGLE(save_p); @@ -344,6 +351,9 @@ static void P_NetUnArchivePlayers(void) players[i].flashpal = READUINT16(save_p); players[i].flashcount = READUINT16(save_p); + players[i].skincolor = READUINT8(save_p); + players[i].skin = READINT32(save_p); + players[i].availabilities = READUINT32(save_p); players[i].score = READUINT32(save_p); players[i].dashspeed = READFIXED(save_p); // dashing speed players[i].lives = READSINT8(save_p); @@ -913,7 +923,7 @@ static void UnArchiveFFloors(const sector_t *ss) static void ArchiveSectors(void) { - size_t i; + size_t i, j; const sector_t *ss = sectors; const sector_t *spawnss = spawnsectors; UINT8 diff, diff2, diff3; @@ -951,10 +961,8 @@ static void ArchiveSectors(void) if (ss->ceilingpic_angle != spawnss->ceilingpic_angle) diff2 |= SD_CEILANG; - if (ss->tag != spawnss->tag) + if (!Tag_Compare(&ss->tags, &spawnss->tags)) diff2 |= SD_TAG; - if (ss->nexttag != spawnss->nexttag || ss->firsttag != spawnss->firsttag) - diff3 |= SD_TAGLIST; if (ss->extra_colormap != spawnss->extra_colormap) diff3 |= SD_COLORMAP; @@ -1002,12 +1010,11 @@ static void ArchiveSectors(void) WRITEANGLE(save_p, ss->floorpic_angle); if (diff2 & SD_CEILANG) WRITEANGLE(save_p, ss->ceilingpic_angle); - if (diff2 & SD_TAG) // save only the tag - WRITEINT16(save_p, ss->tag); - if (diff3 & SD_TAGLIST) // save both firsttag and nexttag - { // either of these could be changed even if tag isn't - WRITEINT32(save_p, ss->firsttag); - WRITEINT32(save_p, ss->nexttag); + if (diff2 & SD_TAG) + { + WRITEUINT32(save_p, ss->tags.count); + for (j = 0; j < ss->tags.count; j++) + WRITEINT16(save_p, ss->tags.tags[j]); } if (diff3 & SD_COLORMAP) @@ -1025,7 +1032,7 @@ static void ArchiveSectors(void) static void UnArchiveSectors(void) { - UINT16 i; + UINT16 i, j; UINT8 diff, diff2, diff3; for (;;) { @@ -1079,13 +1086,29 @@ static void UnArchiveSectors(void) if (diff2 & SD_CEILANG) sectors[i].ceilingpic_angle = READANGLE(save_p); if (diff2 & SD_TAG) - sectors[i].tag = READINT16(save_p); // DON'T use P_ChangeSectorTag - if (diff3 & SD_TAGLIST) { - sectors[i].firsttag = READINT32(save_p); - sectors[i].nexttag = READINT32(save_p); + size_t ncount = READUINT32(save_p); + + // Remove entries from global lists. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); + + // Reallocate if size differs. + if (ncount != sectors[i].tags.count) + { + sectors[i].tags.count = ncount; + sectors[i].tags.tags = Z_Realloc(sectors[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); + } + + for (j = 0; j < ncount; j++) + sectors[i].tags.tags[j] = READINT16(save_p); + + // Add new entries. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); } + if (diff3 & SD_COLORMAP) sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); if (diff3 & SD_CRUMBLESTATE) @@ -1394,6 +1417,13 @@ typedef enum MD2_MIRRORED = 1<<13, MD2_ROLLANGLE = 1<<14, MD2_SHADOWSCALE = 1<<15, + MD2_RENDERFLAGS = 1<<16, + MD2_BLENDMODE = 1<<17, + MD2_SPRITEXSCALE = 1<<18, + MD2_SPRITEYSCALE = 1<<19, + MD2_SPRITEXOFFSET = 1<<20, + MD2_SPRITEYOFFSET = 1<<21, + MD2_FLOORSPRITESLOPE = 1<<22, } mobj_diff2_t; typedef enum @@ -1606,6 +1636,27 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_ROLLANGLE; if (mobj->shadowscale) diff2 |= MD2_SHADOWSCALE; + if (mobj->renderflags) + diff2 |= MD2_RENDERFLAGS; + if (mobj->renderflags) + diff2 |= MD2_BLENDMODE; + if (mobj->spritexscale != FRACUNIT) + diff2 |= MD2_SPRITEXSCALE; + if (mobj->spriteyscale != FRACUNIT) + diff2 |= MD2_SPRITEYSCALE; + if (mobj->spritexoffset) + diff2 |= MD2_SPRITEXOFFSET; + if (mobj->floorspriteslope) + { + pslope_t *slope = mobj->floorspriteslope; + if (slope->zangle || slope->zdelta || slope->xydirection + || slope->o.x || slope->o.y || slope->o.z + || slope->d.x || slope->d.y + || slope->normal.x || slope->normal.y + || (slope->normal.z != FRACUNIT)) + diff2 |= MD2_FLOORSPRITESLOPE; + } + if (diff2 != 0) diff |= MD_MORE; @@ -1748,6 +1799,37 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEANGLE(save_p, mobj->rollangle); if (diff2 & MD2_SHADOWSCALE) WRITEFIXED(save_p, mobj->shadowscale); + if (diff2 & MD2_RENDERFLAGS) + WRITEUINT32(save_p, mobj->renderflags); + if (diff2 & MD2_BLENDMODE) + WRITEINT32(save_p, mobj->blendmode); + if (diff2 & MD2_SPRITEXSCALE) + WRITEFIXED(save_p, mobj->spritexscale); + if (diff2 & MD2_SPRITEYSCALE) + WRITEFIXED(save_p, mobj->spriteyscale); + if (diff2 & MD2_SPRITEXOFFSET) + WRITEFIXED(save_p, mobj->spritexoffset); + if (diff2 & MD2_SPRITEYOFFSET) + WRITEFIXED(save_p, mobj->spriteyoffset); + if (diff2 & MD2_FLOORSPRITESLOPE) + { + pslope_t *slope = mobj->floorspriteslope; + + WRITEFIXED(save_p, slope->zdelta); + WRITEANGLE(save_p, slope->zangle); + WRITEANGLE(save_p, slope->xydirection); + + WRITEFIXED(save_p, slope->o.x); + WRITEFIXED(save_p, slope->o.y); + WRITEFIXED(save_p, slope->o.z); + + WRITEFIXED(save_p, slope->d.x); + WRITEFIXED(save_p, slope->d.y); + + WRITEFIXED(save_p, slope->normal.x); + WRITEFIXED(save_p, slope->normal.y); + WRITEFIXED(save_p, slope->normal.z); + } WRITEUINT32(save_p, mobj->mobjnum); } @@ -2757,6 +2839,37 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->rollangle = READANGLE(save_p); if (diff2 & MD2_SHADOWSCALE) mobj->shadowscale = READFIXED(save_p); + if (diff2 & MD2_RENDERFLAGS) + mobj->renderflags = READUINT32(save_p); + if (diff2 & MD2_BLENDMODE) + mobj->blendmode = READINT32(save_p); + if (diff2 & MD2_SPRITEXSCALE) + mobj->spritexscale = READFIXED(save_p); + if (diff2 & MD2_SPRITEYSCALE) + mobj->spriteyscale = READFIXED(save_p); + if (diff2 & MD2_SPRITEXOFFSET) + mobj->spritexoffset = READFIXED(save_p); + if (diff2 & MD2_SPRITEYOFFSET) + mobj->spriteyoffset = READFIXED(save_p); + if (diff2 & MD2_FLOORSPRITESLOPE) + { + pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); + + slope->zdelta = READFIXED(save_p); + slope->zangle = READANGLE(save_p); + slope->xydirection = READANGLE(save_p); + + slope->o.x = READFIXED(save_p); + slope->o.y = READFIXED(save_p); + slope->o.z = READFIXED(save_p); + + slope->d.x = READFIXED(save_p); + slope->d.y = READFIXED(save_p); + + slope->normal.x = READFIXED(save_p); + slope->normal.y = READFIXED(save_p); + slope->normal.z = READFIXED(save_p); + } if (diff & MD_REDFLAG) { @@ -3951,14 +4064,17 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) playeringame[consoleplayer] = true; } -static void P_NetArchiveMisc(void) +static void P_NetArchiveMisc(boolean resending) { INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); + if (resending) + WRITEUINT32(save_p, gametic); WRITEINT16(save_p, gamemap); WRITEINT16(save_p, gamestate); + WRITEINT16(save_p, gametype); { UINT32 pig = 0; @@ -4021,13 +4137,16 @@ static void P_NetArchiveMisc(void) WRITEUINT8(save_p, 0x2e); } -static inline boolean P_NetUnArchiveMisc(void) +static inline boolean P_NetUnArchiveMisc(boolean reloading) { INT32 i; if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) I_Error("Bad $$$.sav at archive block Misc"); + if (reloading) + gametic = READUINT32(save_p); + gamemap = READINT16(save_p); // gamemap changed; we assume that its map header is always valid, @@ -4041,6 +4160,8 @@ static inline boolean P_NetUnArchiveMisc(void) G_SetGamestate(READINT16(save_p)); + gametype = READINT16(save_p); + { UINT32 pig = READUINT32(save_p); for (i = 0; i < MAXPLAYERS; i++) @@ -4054,7 +4175,7 @@ static inline boolean P_NetUnArchiveMisc(void) tokenlist = READUINT32(save_p); - if (!P_LoadLevel(true)) + if (!P_LoadLevel(true, reloading)) return false; // get the time @@ -4153,14 +4274,14 @@ void P_SaveGame(INT16 mapnum) P_ArchiveLuabanksAndConsistency(); } -void P_SaveNetGame(void) +void P_SaveNetGame(boolean resending) { thinker_t *th; mobj_t *mobj; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise CV_SaveNetVars(&save_p); - P_NetArchiveMisc(); + P_NetArchiveMisc(resending); // Assign the mobjnumber for pointer tracking for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -4208,10 +4329,10 @@ boolean P_LoadGame(INT16 mapoverride) return true; } -boolean P_LoadNetGame(void) +boolean P_LoadNetGame(boolean reloading) { CV_LoadNetVars(&save_p); - if (!P_NetUnArchiveMisc()) + if (!P_NetUnArchiveMisc(reloading)) return false; P_NetUnArchivePlayers(); if (gamestate == GS_LEVEL) diff --git a/src/p_saveg.h b/src/p_saveg.h index d8756a7a9b955e4520e46849c3d76313329b1623..be98953eb232198e88fb757840f9e0021fa48f2d 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -22,9 +22,9 @@ // These are the load / save game routines. void P_SaveGame(INT16 mapnum); -void P_SaveNetGame(void); +void P_SaveNetGame(boolean resending); boolean P_LoadGame(INT16 mapoverride); -boolean P_LoadNetGame(void); +boolean P_LoadNetGame(boolean reloading); mobj_t *P_FindNewPosition(UINT32 oldposition); diff --git a/src/p_setup.c b/src/p_setup.c index 8e09c34df9fa97fda3dea95b99b6abf05440d761..cfee0500971ad334d8ee7ade1a482687305718d4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -29,6 +29,7 @@ #include "r_data.h" #include "r_things.h" // for R_AddSpriteDefs #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_sky.h" #include "r_draw.h" @@ -82,6 +83,8 @@ #include "fastcmp.h" // textmap parsing +#include "taglist.h" + // // Map MD5, calculated on level load. // Sent to clients in PT_SERVERINFO. @@ -548,7 +551,7 @@ Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize) lumpnum_t flatnum; int texturenum; - patch_t *flatpatch; + UINT8 *flatpatch; size_t lumplength; size_t i; @@ -608,7 +611,7 @@ flatfound: /* This could be a flat, patch, or PNG. */ flatpatch = W_CacheLumpNum(flatnum, PU_CACHE); lumplength = W_LumpLength(flatnum); - if (Picture_CheckIfPatch(flatpatch, lumplength)) + if (Picture_CheckIfDoomPatch((softwarepatch_t *)flatpatch, lumplength)) levelflat->type = LEVELFLAT_PATCH; else { @@ -904,16 +907,13 @@ static void P_SpawnMapThings(boolean spawnemblems) } // Experimental groovy write function! -void P_WriteThings(lumpnum_t lumpnum) +void P_WriteThings(void) { size_t i, length; mapthing_t *mt; - UINT8 *data; UINT8 *savebuffer, *savebuf_p; INT16 temp; - data = W_CacheLumpNum(lumpnum, PU_LEVEL); - savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); if (!savebuf_p) @@ -935,8 +935,6 @@ void P_WriteThings(lumpnum_t lumpnum) WRITEUINT16(savebuf_p, mt->options); } - Z_Free(data); - length = savebuf_p - savebuffer; FIL_WriteFile(va("newthings%d.lmp", gamemap), savebuffer, length); @@ -968,8 +966,6 @@ static void P_LoadVertices(UINT8 *data) static void P_InitializeSector(sector_t *ss) { - ss->nexttag = ss->firsttag = -1; - memset(&ss->soundorg, 0, sizeof(ss->soundorg)); ss->validcount = 0; @@ -1040,7 +1036,7 @@ static void P_LoadSectors(UINT8 *data) ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); - ss->tag = SHORT(ms->tag); + Tag_FSet(&ss->tags, SHORT(ms->tag)); ss->floor_xoffs = ss->floor_yoffs = 0; ss->ceiling_xoffs = ss->ceiling_yoffs = 0; @@ -1079,10 +1075,6 @@ static void P_InitializeLinedef(line_t *ld) ld->frontsector = ld->backsector = NULL; ld->validcount = 0; -#ifdef WALLSPLATS - ld->splats = NULL; -#endif - ld->firsttag = ld->nexttag = -1; ld->polyobj = NULL; ld->text = NULL; @@ -1154,7 +1146,7 @@ static void P_LoadLinedefs(UINT8 *data) { ld->flags = SHORT(mld->flags); ld->special = SHORT(mld->special); - ld->tag = SHORT(mld->tag); + Tag_FSet(&ld->tags, SHORT(mld->tag)); memset(ld->args, 0, NUMLINEARGS*sizeof(*ld->args)); memset(ld->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ld->stringargs)); ld->alpha = FRACUNIT; @@ -1347,7 +1339,7 @@ static void P_LoadSidedefs(UINT8 *data) || (msd->toptexture[0] >= 'A' && msd->toptexture[0] <= 'F')) sd->toptexture = axtoi(msd->toptexture); else - I_Error("Custom FOF (tag %d) needs a value in the linedef's back side upper texture field.", sd->line->tag); + I_Error("Custom FOF (line id %s) needs a value in the linedef's back side upper texture field.", sizeu1(sd->line - lines)); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); @@ -1387,8 +1379,8 @@ static void P_LoadThings(UINT8 *data) mt->type = READUINT16(data); mt->options = READUINT16(data); mt->extrainfo = (UINT8)(mt->type >> 12); + Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->pitch = mt->roll = 0; @@ -1524,7 +1516,17 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val) else if (fastcmp(param, "special")) sectors[i].special = atol(val); else if (fastcmp(param, "id")) - sectors[i].tag = atol(val); + Tag_FSet(§ors[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(§ors[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } else if (fastcmp(param, "xpanningfloor")) sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "ypanningfloor")) @@ -1602,7 +1604,17 @@ static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val) static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) { if (fastcmp(param, "id")) - lines[i].tag = atol(val); + Tag_FSet(&lines[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(&lines[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } else if (fastcmp(param, "special")) lines[i].special = atol(val); else if (fastcmp(param, "v1")) @@ -1671,8 +1683,18 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val) static void ParseTextmapThingParameter(UINT32 i, char *param, char *val) { if (fastcmp(param, "id")) - mapthings[i].tag = atol(val); - if (fastcmp(param, "x")) + Tag_FSet(&mapthings[i].tags, atol(val)); + else if (fastcmp(param, "moreids")) + { + char* id = val; + while (id) + { + Tag_Add(&mapthings[i].tags, atol(id)); + if ((id = strchr(id, ' '))) + id++; + } + } + else if (fastcmp(param, "x")) mapthings[i].x = atol(val); else if (fastcmp(param, "y")) mapthings[i].y = atol(val); @@ -1829,7 +1851,7 @@ static void P_LoadTextmap(void) sc->lightlevel = 255; sc->special = 0; - sc->tag = 0; + Tag_FSet(&sc->tags, 0); sc->floor_xoffs = sc->floor_yoffs = 0; sc->ceiling_xoffs = sc->ceiling_yoffs = 0; @@ -1847,6 +1869,7 @@ static void P_LoadTextmap(void) textmap_colormap.fadeend = 31; textmap_colormap.flags = 0; TextmapParse(sectorsPos[i], i, ParseTextmapSectorParameter); + P_InitializeSector(sc); if (textmap_colormap.used) { @@ -1863,7 +1886,8 @@ static void P_LoadTextmap(void) ld->v1 = ld->v2 = NULL; ld->flags = 0; ld->special = 0; - ld->tag = 0; + Tag_FSet(&ld->tags, 0); + memset(ld->args, 0, NUMLINEARGS*sizeof(*ld->args)); memset(ld->stringargs, 0x00, NUMLINESTRINGARGS*sizeof(*ld->stringargs)); ld->alpha = FRACUNIT; @@ -1911,8 +1935,8 @@ static void P_LoadTextmap(void) mt->options = 0; mt->z = 0; mt->extrainfo = 0; + Tag_FSet(&mt->tags, 0); mt->scale = FRACUNIT; - mt->tag = 0; memset(mt->args, 0, NUMMAPTHINGARGS*sizeof(*mt->args)); memset(mt->stringargs, 0x00, NUMMAPTHINGSTRINGARGS*sizeof(*mt->stringargs)); mt->mobj = NULL; @@ -2080,9 +2104,6 @@ static boolean P_LoadMapData(const virtres_t *virt) static void P_InitializeSubsector(subsector_t *ss) { ss->sector = NULL; -#ifdef FLOORSPLATS - ss->splats = NULL; -#endif ss->validcount = 0; } @@ -2127,7 +2148,7 @@ static void P_LoadNodes(UINT8 *data) * \param seg Seg to compute length for. * \return Length in fracunits. */ -fixed_t P_SegLength(seg_t *seg) +static fixed_t P_SegLength(seg_t *seg) { INT64 dx = (seg->v2->x - seg->v1->x)>>1; INT64 dy = (seg->v2->y - seg->v1->y)>>1; @@ -2929,30 +2950,6 @@ static void P_LinkMapData(void) } } -/** Hashes the sector tags across the sectors and linedefs. - * - * \sa P_FindSectorFromTag, P_ChangeSectorTag - * \author Lee Killough - */ -static inline void P_InitTagLists(void) -{ - register size_t i; - - for (i = numsectors - 1; i != (size_t)-1; i--) - { - size_t j = (unsigned)sectors[i].tag % numsectors; - sectors[i].nexttag = sectors[j].firsttag; - sectors[j].firsttag = (INT32)i; - } - - for (i = numlines - 1; i != (size_t)-1; i--) - { - size_t j = (unsigned)lines[i].tag % numlines; - lines[i].nexttag = lines[j].firsttag; - lines[j].firsttag = (INT32)i; - } -} - //For maps in binary format, converts setup of specials to UDMF format. static void P_ConvertBinaryMap(void) { @@ -2960,14 +2957,28 @@ static void P_ConvertBinaryMap(void) for (i = 0; i < numlines; i++) { + mtag_t tag = Tag_FGet(&lines[i].tags); + switch (lines[i].special) { case 20: //PolyObject first line { - INT32 paramline = P_FindSpecialLineFromTag(22, lines[i].tag, -1); + INT32 check = -1; + INT32 paramline = -1; + + TAG_ITER_DECLARECOUNTER(0); + + TAG_ITER_LINES(0, tag, check) + { + if (lines[check].special == 22) + { + paramline = check; + break; + } + } //PolyObject ID - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = tag; //Default: Invisible planes lines[i].args[3] |= TMPF_INVISIBLEPLANES; @@ -3013,7 +3024,7 @@ static void P_ConvertBinaryMap(void) CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(i)); break; case 447: //Change colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); if (lines[i].flags & ML_EFFECT3) lines[i].args[2] |= TMCF_RELATIVE; if (lines[i].flags & ML_EFFECT1) @@ -3029,7 +3040,7 @@ static void P_ConvertBinaryMap(void) abs(sides[lines[i].sidenum[1]].rowoffset >> FRACBITS) : abs(sides[lines[i].sidenum[0]].rowoffset >> FRACBITS)); - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); if (lines[i].flags & ML_EFFECT4) lines[i].args[2] = speed; else @@ -3049,10 +3060,10 @@ static void P_ConvertBinaryMap(void) break; } case 456: //Stop fading colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); break; case 606: //Colormap - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = Tag_FGet(&lines[i].tags); break; case 700: //Slope front sector floor case 701: //Slope front sector ceiling @@ -3093,7 +3104,7 @@ static void P_ConvertBinaryMap(void) else if (lines[i].special == 715) lines[i].args[0] = TMSP_BACKCEILING; - lines[i].args[1] = lines[i].tag; + lines[i].args[1] = tag; if (lines[i].flags & ML_EFFECT6) { @@ -3125,9 +3136,9 @@ static void P_ConvertBinaryMap(void) case 721: //Copy front side ceiling slope case 722: //Copy front side floor and ceiling slope if (lines[i].special != 721) - lines[i].args[0] = lines[i].tag; + lines[i].args[0] = tag; if (lines[i].special != 720) - lines[i].args[1] = lines[i].tag; + lines[i].args[1] = tag; lines[i].special = 720; break; case 900: //Translucent wall (10%) @@ -3160,21 +3171,39 @@ static void P_ConvertBinaryMap(void) switch (mapthings[i].type) { case 750: + Tag_Add(&mapthings[i].tags, mapthings[i].angle); + break; case 760: case 761: - mapthings[i].tag = mapthings[i].angle; + Tag_FSet(&mapthings[i].tags, mapthings[i].angle); break; case 762: { - INT32 firstline = P_FindSpecialLineFromTag(20, mapthings[i].angle, -1); + INT32 check = -1; + INT32 firstline = -1; + mtag_t tag = mapthings[i].angle; + + TAG_ITER_DECLARECOUNTER(0); + + Tag_FSet(&mapthings[i].tags, tag); + + TAG_ITER_LINES(0, tag, check) + { + if (lines[check].special == 20) + { + firstline = check; + break; + } + } + if (firstline != -1) lines[firstline].args[3] |= TMPF_CRUSH; - mapthings[i].tag = mapthings[i].angle; + mapthings[i].type = 761; break; } case 780: - mapthings[i].tag = mapthings[i].extrainfo; + Tag_FSet(&mapthings[i].tags, mapthings[i].extrainfo); break; default: break; @@ -3248,6 +3277,7 @@ static boolean P_LoadMapFromFile(void) { virtres_t *virt = vres_GetMap(lastloadedmaplumpnum); virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + size_t i; udmf = textmap != NULL; if (!P_LoadMapData(virt)) @@ -3257,7 +3287,7 @@ static boolean P_LoadMapFromFile(void) P_LinkMapData(); - P_InitTagLists(); // Create xref tables for tags + Taglist_InitGlobalTables(); if (!udmf) P_ConvertBinaryMap(); @@ -3271,6 +3301,10 @@ static boolean P_LoadMapFromFile(void) memcpy(spawnlines, lines, numlines * sizeof(*lines)); memcpy(spawnsides, sides, numsides * sizeof(*sides)); + for (i = 0; i < numsectors; i++) + if (sectors[i].tags.count) + spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t)); + P_MakeMapMD5(virt, &mapmd5); vres_Free(virt); @@ -3319,8 +3353,6 @@ static void P_InitLevelSettings(void) leveltime = 0; - localaiming = 0; - localaiming2 = 0; modulothing = 0; // special stage tokens, emeralds, and ring total @@ -3435,6 +3467,9 @@ void P_RespawnThings(void) P_InitLevelSettings(); + localaiming = 0; + localaiming2 = 0; + P_SpawnMapThings(true); // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that @@ -3942,7 +3977,7 @@ static void P_InitGametype(void) * \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot. * \todo Clean up, refactor, split up; get rid of the bloat. */ -boolean P_LoadLevel(boolean fromnetsave) +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) { // use gamemap to get map number. // 99% of the things already did, so. @@ -4012,7 +4047,10 @@ boolean P_LoadLevel(boolean fromnetsave) players[consoleplayer].viewz = 1; // Cancel all d_main.c fadeouts (keep fade in though). - wipegamestate = FORCEWIPEOFF; + if (reloadinggamestate) + wipegamestate = gamestate; // Don't fade if reloading the gamestate + else + wipegamestate = FORCEWIPEOFF; wipestyleflags = 0; // Special stage & record attack retry fade to white @@ -4038,18 +4076,20 @@ boolean P_LoadLevel(boolean fromnetsave) // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction && (RESETMUSIC || + if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC || strnicmp(S_MusicName(), (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + { S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + } // Let's fade to black here // But only if we didn't do the special stage wipe - if (rendermode != render_none && !ranspecialwipe) + if (rendermode != render_none && !(ranspecialwipe || reloadinggamestate)) P_RunLevelWipe(); - if (!titlemapinaction) + if (!(reloadinggamestate || titlemapinaction)) { if (ranspecialwipe == 2) { @@ -4093,13 +4133,10 @@ boolean P_LoadLevel(boolean fromnetsave) // Clear pointers that would be left dangling by the purge R_FlushTranslationColormapCache(); + Patch_FreeTag(PU_PATCH_LOWPRIORITY); + Patch_FreeTag(PU_PATCH_ROTATED); Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); -#if defined (WALLSPLATS) || defined (FLOORSPLATS) - // clear the splats from previous level - R_ClearLevelSplats(); -#endif - P_InitThinkers(); P_InitCachedActions(); @@ -4156,14 +4193,14 @@ boolean P_LoadLevel(boolean fromnetsave) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin + gl_maploaded = false; + // Lactozilla: Free extrasubsectors regardless of renderer. - // Maybe we're not in OpenGL anymore. - if (extrasubsectors) - free(extrasubsectors); - extrasubsectors = NULL; - // stuff like HWR_CreatePlanePolygons is called there + HWR_FreeExtraSubsectors(); + + // Create plane polygons. if (rendermode == render_opengl) - HWR_SetupLevel(); + HWR_LoadLevel(); #endif // oh god I hope this helps @@ -4174,7 +4211,12 @@ boolean P_LoadLevel(boolean fromnetsave) if (!fromnetsave) P_InitGametype(); - P_InitCamera(); + if (!reloadinggamestate) + { + P_InitCamera(); + localaiming = 0; + localaiming2 = 0; + } // clear special respawning que iquehead = iquetail = 0; @@ -4182,7 +4224,7 @@ boolean P_LoadLevel(boolean fromnetsave) P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none && !titlemapinaction) + if (rendermode != render_none && !(titlemapinaction || reloadinggamestate)) F_WipeColorFill(levelfadecol); if (precache || dedicated) @@ -4226,8 +4268,8 @@ boolean P_LoadLevel(boolean fromnetsave) LUAh_MapLoad(); } - // No render mode, stop here. - if (rendermode == render_none) + // No render mode or reloading gamestate, stop here. + if (rendermode == render_none || reloadinggamestate) return true; // Title card! @@ -4245,33 +4287,6 @@ boolean P_LoadLevel(boolean fromnetsave) return true; } -#ifdef HWRENDER -void HWR_SetupLevel(void) -{ - // Lactozilla (December 8, 2019) - // Level setup used to free EVERY mipmap from memory. - // Even mipmaps that aren't related to level textures. - // Presumably, the hardware render code used to store textures as level data. - // Meaning, they had memory allocated and marked with the PU_LEVEL tag. - // Level textures are only reloaded after R_LoadTextures, which is - // when the texture list is loaded. - - // Sal: Unfortunately, NOT freeing them causes the dreaded Color Bug. - HWR_FreeMipmapCache(); - -#ifdef ALAM_LIGHTING - // BP: reset light between levels (we draw preview frame lights on current frame) - HWR_ResetLights(); -#endif - - HWR_CreatePlanePolygons((INT32)numnodes - 1); - - // Build the sky dome - HWR_ClearSkyDome(); - HWR_BuildSkyDome(); -} -#endif - // // P_RunSOC // @@ -4481,6 +4496,8 @@ boolean P_AddWadFile(const char *wadfilename) // // search for sprite replacements // + Patch_FreeTag(PU_SPRITE); + Patch_FreeTag(PU_PATCH_ROTATED); R_AddSpriteDefs(wadnum); // Reload it all anyway, just in case they diff --git a/src/p_setup.h b/src/p_setup.h index ef903e103725194d058e0a8bfac1e6a929c7373b..34de9c93da1c4a91f7c46cc25af8107136df530e 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -97,15 +97,15 @@ void P_SetupLevelSky(INT32 skynum, boolean global); void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_RespawnThings(void); -boolean P_LoadLevel(boolean fromnetsave); +boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate); #ifdef HWRENDER -void HWR_SetupLevel(void); +void HWR_LoadLevel(void); #endif boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 num); -void P_WriteThings(lumpnum_t lump); +void P_WriteThings(void); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); diff --git a/src/p_slopes.c b/src/p_slopes.c index e93b0f6c993650043a1afe588c21aa1b64bbac37..aa46a84024d459e2c3dab0164d4122b59f30b126 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -139,7 +139,7 @@ void T_DynamicSlopeVert (dynplanethink_t* th) INT32 l; for (i = 0; i < 3; i++) { - l = P_FindSpecialLineFromTag(799, th->tags[i], -1); + l = Tag_FindLineSpecial(799, th->tags[i]); if (l != -1) { th->vex[i].z = lines[l].frontsector->floorheight; } @@ -405,9 +405,6 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker) P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL); } } - - if(!line->tag) - return; } /// Creates a new slope from three mapthings with the specified IDs @@ -426,11 +423,11 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something! continue; - if (!vertices[0] && mt->tag == tag1) + if (!vertices[0] && Tag_Find(&mt->tags, tag1)) vertices[0] = mt; - else if (!vertices[1] && mt->tag == tag2) + else if (!vertices[1] && Tag_Find(&mt->tags, tag2)) vertices[1] = mt; - else if (!vertices[2] && mt->tag == tag3) + else if (!vertices[2] && Tag_Find(&mt->tags, tag3)) vertices[2] = mt; } @@ -549,11 +546,11 @@ static boolean P_SetSlopeFromTag(sector_t *sec, INT32 tag, boolean ceiling) { INT32 i; pslope_t **secslope = ceiling ? &sec->c_slope : &sec->f_slope; + TAG_ITER_DECLARECOUNTER(0); if (!tag || *secslope) return false; - - for (i = -1; (i = P_FindSectorFromTag(tag, i)) >= 0;) + TAG_ITER_SECTORS(0, tag, i) { pslope_t *srcslope = ceiling ? sectors[i].c_slope : sectors[i].f_slope; if (srcslope) diff --git a/src/p_spec.c b/src/p_spec.c index 7a79bd494f951e8a0befbf2812a23b2326200624..a1afdd00ddb12c4c4253e4dfe4547a8e3391734d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -988,99 +988,12 @@ static sector_t *P_FindModelCeilingSector(fixed_t ceildestheight, INT32 secnum) } #endif -/** Searches the tag lists for the next sector with a given tag. - * - * \param tag Tag number to look for. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of the next tagged sector found. - */ -INT32 P_FindSectorFromTag(INT16 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - if (start >= (INT32)numsectors) - return -1; - - return start; - } - else - { - start = start >= 0 ? sectors[start].nexttag : - sectors[(unsigned)tag % numsectors].firsttag; - while (start >= 0 && sectors[start].tag != tag) - start = sectors[start].nexttag; - return start; - } -} - -/** Searches the tag lists for the next line with a given tag and special. - * - * \param tag Tag number. - * \param start -1 to start anew, or the result of a previous call to keep - * searching. - * \return Number of next suitable line found. - * \author Graue <graue@oceanbase.org> - */ -static INT32 P_FindLineFromTag(INT32 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - if (start >= (INT32)numlines) - return -1; - - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)tag % numlines].firsttag; - while (start >= 0 && lines[start].tag != tag) - start = lines[start].nexttag; - return start; - } -} - -INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) -{ - if (tag == -1) - { - start++; - - // This redundant check stops the compiler from complaining about function expansion - // elsewhere for some reason and everything is awful - if (start >= (INT32)numlines) - return -1; - - while (start < (INT32)numlines && lines[start].special != special) - start++; - - if (start >= (INT32)numlines) - return -1; - - return start; - } - else - { - start = start >= 0 ? lines[start].nexttag : - lines[(unsigned)tag % numlines].firsttag; - while (start >= 0 && (lines[start].tag != tag || lines[start].special != special)) - start = lines[start].nexttag; - return start; - } -} - - // Parses arguments for parameterized polyobject door types static boolean PolyDoor(line_t *line) { polydoordata_t pdd; - pdd.polyObjNum = line->tag; // polyobject id + pdd.polyObjNum = Tag_FGet(&line->tags); // polyobject id switch(line->special) { @@ -1117,7 +1030,7 @@ static boolean PolyMove(line_t *line) { polymovedata_t pmd; - pmd.polyObjNum = line->tag; + pmd.polyObjNum = Tag_FGet(&line->tags); pmd.speed = sides[line->sidenum[0]].textureoffset / 8; pmd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); pmd.distance = sides[line->sidenum[0]].rowoffset; @@ -1131,7 +1044,7 @@ static boolean PolyMove(line_t *line) // If NOCLIMB is ticked, the polyobject will still be tangible, just not visible. static void PolyInvisible(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1155,7 +1068,7 @@ static void PolyInvisible(line_t *line) // If NOCLIMB is ticked, the polyobject will not be tangible, just visible. static void PolyVisible(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; if (!(po = Polyobj_GetForNum(polyObjNum))) @@ -1180,7 +1093,7 @@ static void PolyVisible(line_t *line) // Frontsector floor / 100 = translevel static void PolyTranslucency(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; INT32 value; @@ -1212,7 +1125,7 @@ static void PolyTranslucency(line_t *line) // Makes a polyobject translucency fade and applies tangibility static boolean PolyFade(line_t *line) { - INT32 polyObjNum = line->tag; + INT32 polyObjNum = Tag_FGet(&line->tags); polyobj_t *po; polyfadedata_t pfd; INT32 value; @@ -1274,7 +1187,7 @@ static boolean PolyWaypoint(line_t *line) { polywaypointdata_t pwd; - pwd.polyObjNum = line->tag; + pwd.polyObjNum = Tag_FGet(&line->tags); pwd.speed = sides[line->sidenum[0]].textureoffset / 8; pwd.sequence = sides[line->sidenum[0]].rowoffset >> FRACBITS; // Sequence # @@ -1301,7 +1214,7 @@ static boolean PolyRotate(line_t *line) { polyrotdata_t prd; - prd.polyObjNum = line->tag; + prd.polyObjNum = Tag_FGet(&line->tags); prd.speed = sides[line->sidenum[0]].textureoffset >> FRACBITS; // angular speed prd.distance = sides[line->sidenum[0]].rowoffset >> FRACBITS; // angular distance @@ -1326,7 +1239,7 @@ static boolean PolyFlag(line_t *line) { polyflagdata_t pfd; - pfd.polyObjNum = line->tag; + pfd.polyObjNum = Tag_FGet(&line->tags); pfd.speed = P_AproxDistance(line->dx, line->dy) >> FRACBITS; pfd.angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y) >> ANGLETOFINESHIFT; pfd.momx = sides[line->sidenum[0]].textureoffset >> FRACBITS; @@ -1339,7 +1252,7 @@ static boolean PolyDisplace(line_t *line) { polydisplacedata_t pdd; - pdd.polyObjNum = line->tag; + pdd.polyObjNum = Tag_FGet(&line->tags); pdd.controlSector = line->frontsector; pdd.dx = line->dx>>8; @@ -1355,7 +1268,7 @@ static boolean PolyRotDisplace(line_t *line) polyrotdisplacedata_t pdd; fixed_t anginter, distinter; - pdd.polyObjNum = line->tag; + pdd.polyObjNum = Tag_FGet(&line->tags); pdd.controlSector = line->frontsector; // Rotate 'anginter' interval for each 'distinter' interval from the control sector. @@ -1375,66 +1288,6 @@ static boolean PolyRotDisplace(line_t *line) return EV_DoPolyObjRotDisplace(&pdd); } -/** Changes a sector's tag. - * Used by the linedef executor tag changer and by crumblers. - * - * \param sector Sector whose tag will be changed. - * \param newtag New tag number for this sector. - * \sa P_InitTagLists, P_FindSectorFromTag - * \author Graue <graue@oceanbase.org> - */ -void P_ChangeSectorTag(UINT32 sector, INT16 newtag) -{ - INT16 oldtag; - INT32 i; - - I_Assert(sector < numsectors); - - if ((oldtag = sectors[sector].tag) == newtag) - return; - - // first you have to remove it from the old tag's taglist - i = sectors[(unsigned)oldtag % numsectors].firsttag; - - if (i == -1) // shouldn't happen - I_Error("Corrupt tag list for sector %u\n", sector); - else if ((UINT32)i == sector) - sectors[(unsigned)oldtag % numsectors].firsttag = sectors[sector].nexttag; - else - { - while (sectors[i].nexttag != -1 && (UINT32)sectors[i].nexttag < sector ) - i = sectors[i].nexttag; - - sectors[i].nexttag = sectors[sector].nexttag; - } - - sectors[sector].tag = newtag; - - // now add it to the new tag's taglist - if ((UINT32)sectors[(unsigned)newtag % numsectors].firsttag > sector) - { - sectors[sector].nexttag = sectors[(unsigned)newtag % numsectors].firsttag; - sectors[(unsigned)newtag % numsectors].firsttag = sector; - } - else - { - i = sectors[(unsigned)newtag % numsectors].firsttag; - - if (i == -1) - { - sectors[(unsigned)newtag % numsectors].firsttag = sector; - sectors[sector].nexttag = -1; - } - else - { - while (sectors[i].nexttag != -1 && (UINT32)sectors[i].nexttag < sector ) - i = sectors[i].nexttag; - - sectors[sector].nexttag = sectors[i].nexttag; - sectors[i].nexttag = sector; - } - } -} // // P_RunNightserizeExecutors @@ -2103,7 +1956,7 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller) for (masterline = 0; masterline < numlines; masterline++) { - if (lines[masterline].tag != tag) + if (Tag_FGet(&lines[masterline].tags) != tag) continue; // "No More Enemies" and "Level Load" take care of themselves. @@ -2369,6 +2222,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 secnum = -1; mobj_t *bot = NULL; + mtag_t tag = Tag_FGet(&line->tags); + TAG_ITER_DECLARECOUNTER(0); I_Assert(!mo || !P_MobjWasRemoved(mo)); // If mo is there, mo must be valid! @@ -2396,7 +2251,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) newceilinglightsec = line->frontsector->ceilinglightsec; // act on all sectors with the same tag as the triggering linedef - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (sectors[secnum].lightingdata) { @@ -2451,17 +2306,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 409: // Change tagged sectors' tag // (formerly "Change calling sectors' tag", but behavior was changed) { - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) - P_ChangeSectorTag(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + TAG_ITER_SECTORS(0, tag, secnum) + Tag_SectorFSet(secnum,(INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; } case 410: // Change front sector's tag - P_ChangeSectorTag((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); + Tag_SectorFSet((UINT32)(line->frontsector - sectors), (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS)); break; case 411: // Stop floor/ceiling movement in tagged sector(s) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (sectors[secnum].floordata) { @@ -2531,7 +2386,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } else { - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; dest = P_GetObjectTypeInSectorNum(MT_TELEPORTMAN, secnum); @@ -2638,7 +2493,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) return; } - if (line->tag != 0) // Do special stuff only if a non-zero linedef tag is set + if (tag != 0) // Do special stuff only if a non-zero linedef tag is set { // Play sounds from tagged sectors' origins. if (line->flags & ML_EFFECT5) // Repeat Midtexture @@ -2646,7 +2501,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Additionally play the sound from tagged sectors' soundorgs sector_t *sec; - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { sec = §ors[secnum]; S_StartSound(&sec->soundorg, sfxnum); @@ -2666,7 +2521,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!camobj) continue; - if (foundit || (camobj->subsector->sector->tag == line->tag)) + if (foundit || Tag_Find(&camobj->subsector->sector->tags, tag)) { foundit = true; break; @@ -2675,7 +2530,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Only trigger if mobj is touching the tag for(rover = camobj->subsector->sector->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag != line->tag) + if (!Tag_Find(&rover->master->frontsector->tags, tag)) continue; if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector)) @@ -2761,7 +2616,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 416: // Spawn adjustable fire flicker - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2795,7 +2650,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 417: // Spawn adjustable glowing light - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2829,7 +2684,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 418: // Spawn adjustable strobe flash (unsynchronized) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2863,7 +2718,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 419: // Spawn adjustable strobe flash (synchronized) - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { if (line->flags & ML_NOCLIMB && line->backsector) { @@ -2897,7 +2752,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 420: // Fade light levels in tagged sectors to new value - P_FadeLight(line->tag, + P_FadeLight(tag, (line->flags & ML_DONTPEGBOTTOM) ? max(sides[line->sidenum[0]].textureoffset>>FRACBITS, 0) : line->frontsector->lightlevel, // failsafe: if user specifies Back Y Offset and NOT Front Y Offset, use the Back Offset // to be consistent with other light and fade specials @@ -2911,7 +2766,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; case 421: // Stop lighting effect in tagged sectors - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) if (sectors[secnum].lightingdata) { P_RemoveThinker(&((elevator_t *)sectors[secnum].lightingdata)->thinker); @@ -2926,7 +2781,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if ((!mo || !mo->player) && !titlemapinaction) // only players have views, and title screens return; - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; altview = P_GetObjectTypeInSectorNum(MT_ALTVIEWMAN, secnum); @@ -3108,8 +2963,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) continue; scroller = (scroll_t *)th; - - if (sectors[scroller->affectee].tag != line->tag) + if (!Tag_Find(§ors[scroller->affectee].tags, tag)) continue; scroller->dx = FixedMul(line->dx>>SCROLL_SHIFT, CARRYFACTOR); @@ -3126,7 +2980,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to crumble boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3138,7 +2992,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3185,12 +3039,13 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) size_t linenum; side_t *set = &sides[line->sidenum[0]], *this; boolean always = !(line->flags & ML_NOCLIMB); // If noclimb: Only change mid texture if mid texture already exists on tagged lines, etc. + for (linenum = 0; linenum < numlines; linenum++) { if (lines[linenum].special == 439) continue; // Don't override other set texture lines! - if (lines[linenum].tag != line->tag) + if (!Tag_Find(&lines[linenum].tags, tag)) continue; // Find tagged lines // Front side @@ -3250,7 +3105,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->sidenum[1] != 0xffff) state = (statenum_t)sides[line->sidenum[1]].toptexture; - while ((secnum = P_FindSectorFromTag(line->tag, secnum)) >= 0) + TAG_ITER_SECTORS(0, tag, secnum) { boolean tryagain; sec = sectors + secnum; @@ -3310,7 +3165,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean foundrover = false; // for debug, "Can't find a FOF" message ffloortype_e oldflags; // store FOF's old flags - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3322,7 +3177,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3368,7 +3223,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (line->flags & ML_NOCLIMB) // don't respawn! respawn = false; - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3380,7 +3235,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3415,7 +3270,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) source = line->frontsector->extra_colormap; else { - INT32 sourcesec = P_FindSectorFromTag(line->args[1], -1); + INT32 sourcesec = Tag_Iterate_Sectors(line->args[1], 0); if (sourcesec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 447 Executor: Can't find sector with source colormap (tag %d)!\n", line->args[1]); @@ -3424,8 +3279,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) source = sectors[sourcesec].extra_colormap; } } - - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0;) + TAG_ITER_SECTORS(0, line->args[0], secnum) { if (sectors[secnum].colormap_protected) continue; @@ -3477,7 +3331,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { CONS_Alert(CONS_WARNING, M_GetText("Skybox switch linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - line->tag); + tag); } else { @@ -3515,7 +3369,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { CONS_Alert(CONS_WARNING, M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - line->tag); + tag); break; } if (line->flags & ML_NOCLIMB) @@ -3532,7 +3386,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } case 450: // Execute Linedef Executor - for recursion - P_LinedefExecute(line->tag, mo, NULL); + P_LinedefExecute(tag, mo, NULL); break; case 451: // Execute Random Linedef Executor @@ -3560,7 +3414,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3572,7 +3426,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3624,7 +3478,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean foundrover = false; // for debug, "Can't find a FOF" message size_t j = 0; // sec->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3636,7 +3490,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3709,7 +3563,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) ffloor_t *rover; // FOF that we are going to operate boolean foundrover = false; // for debug, "Can't find a FOF" message - for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, sectag, secnum) { sec = sectors + secnum; @@ -3721,7 +3575,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) for (rover = sec->ffloors; rover; rover = rover->next) { - if (rover->master->frontsector->tag == foftag) + if (Tag_Find(&rover->master->frontsector->tags, foftag)) { foundrover = true; @@ -3750,7 +3604,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) dest = line->frontsector->extra_colormap; else { - INT32 destsec = P_FindSectorFromTag(line->args[1], -1); + INT32 destsec = Tag_Iterate_Sectors(line->args[1], 0); if (destsec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 455 Executor: Can't find sector with destination colormap (tag %d)!\n", line->args[1]); @@ -3760,7 +3614,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) } } - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0;) + TAG_ITER_SECTORS(0, line->args[0], secnum) { extracolormap_t *source_exc, *dest_exc, *exc; @@ -3840,7 +3694,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) break; } case 456: // Stop fade colormap - for (secnum = -1; (secnum = P_FindSectorFromTag(line->args[0], secnum)) >= 0 ;) + TAG_ITER_SECTORS(0, line->args[0], secnum) P_ResetColormapFader(§ors[secnum]); break; @@ -3854,7 +3708,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) boolean persist = (line->flags & ML_EFFECT2); mobj_t *anchormo; - if ((secnum = P_FindSectorFromTag(line->tag, -1)) < 0) + if ((secnum = Tag_Iterate_Sectors(tag, 0)) < 0) return; anchormo = P_GetObjectTypeInSectorNum(MT_ANGLEMAN, secnum); @@ -3885,7 +3739,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) { INT32 promptnum = max(0, (sides[line->sidenum[0]].textureoffset>>FRACBITS)-1); INT32 pagenum = max(0, (sides[line->sidenum[0]].rowoffset>>FRACBITS)-1); - INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : line->tag); + INT32 postexectag = abs((line->sidenum[1] != 0xFFFF) ? sides[line->sidenum[1]].textureoffset>>FRACBITS : tag); boolean closetextprompt = (line->flags & ML_BLOCKMONSTERS); //boolean allplayers = (line->flags & ML_NOCLIMB); @@ -4009,7 +3863,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (!mo2->spawnpoint) continue; - if (mo2->spawnpoint->angle != line->tag) + if (mo2->spawnpoint->angle != tag) continue; P_KillMobj(mo2, NULL, mo, 0); @@ -4033,11 +3887,12 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 465: // Set linedef executor delay { INT32 linenum; + TAG_ITER_DECLARECOUNTER(1); if (!udmf) break; - for (linenum = -1; (linenum = P_FindLineFromTag(line->args[0], linenum)) >= 0 ;) + TAG_ITER_LINES(1, line->args[0], linenum) { if (line->args[2]) lines[linenum].executordelay += line->args[1]; @@ -4382,6 +4237,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers INT32 i = 0; INT32 section1, section2, section3, section4; INT32 special; + mtag_t sectag = Tag_FGet(§or->tags); section1 = GETSECSPECIAL(sector->special, 1); section2 = GETSECSPECIAL(sector->special, 2); @@ -4536,7 +4392,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers case 6: // Linedef executor (7 Emeralds) case 7: // Linedef executor (NiGHTS Mare) if (!player->bot) - P_LinedefExecute(sector->tag, player->mo, sector); + P_LinedefExecute(sectag, player->mo, sector); break; case 8: // Tells pushable things to check FOFs break; @@ -4565,14 +4421,14 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers sector->special = 0; // Move the button down - junk.tag = 680; + Tag_FSet(&junk.tags, 680); EV_DoElevator(&junk, elevateDown, false); // Open the top FOF - junk.tag = 681; + Tag_FSet(&junk.tags, 681); EV_DoFloor(&junk, raiseFloorToNearestFast); // Open the bottom FOF - junk.tag = 682; + Tag_FSet(&junk.tags, 682); EV_DoCeiling(&junk, lowerToLowestFast); // Mark all players with the time to exit thingy! @@ -4607,7 +4463,7 @@ DoneSection2: if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) break; - i = P_FindSpecialLineFromTag(4, sector->tag, -1); + i = Tag_FindLineSpecial(4, sectag); if (i != -1) { @@ -4620,7 +4476,7 @@ DoneSection2: if (linespeed == 0) { - CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sector->tag); + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sectag); break; } @@ -4714,7 +4570,7 @@ DoneSection2: // important: use sector->tag on next line instead of player->mo->subsector->tag // this part is different from in P_PlayerThink, this is what was causing // FOF custom exits not to work. - lineindex = P_FindSpecialLineFromTag(2, sector->tag, -1); + lineindex = Tag_FindLineSpecial(2, sectag); if (G_CoopGametype() && lineindex != -1) // Custom exit! { @@ -4840,7 +4696,7 @@ DoneSection2: break; // Find line #3 tagged to this sector - lineindex = P_FindSpecialLineFromTag(3, sector->tag, -1); + lineindex = Tag_FindLineSpecial(3, sectag); if (lineindex == -1) { @@ -4905,7 +4761,7 @@ DoneSection2: break; // Find line #3 tagged to this sector - lineindex = P_FindSpecialLineFromTag(3, sector->tag, -1); + lineindex = Tag_FindLineSpecial(3, sectag); if (lineindex == -1) { @@ -5034,7 +4890,7 @@ DoneSection2: memset(&resulthigh, 0x00, sizeof(resulthigh)); // Find line #11 tagged to this sector - lineindex = P_FindSpecialLineFromTag(11, sector->tag, -1); + lineindex = Tag_FindLineSpecial(11, sectag); if (lineindex == -1) { @@ -5654,7 +5510,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f { fixed_t tempceiling = sec2->ceilingheight; //flip the sector around and print an error instead of crashing 12.1.08 -Inuyasha - CONS_Alert(CONS_ERROR, M_GetText("A FOF tagged %d has a top height below its bottom.\n"), master->tag); + CONS_Alert(CONS_ERROR, M_GetText("FOF (line %s) has a top height below its bottom.\n"), sizeu1(master - lines)); sec2->ceilingheight = sec2->floorheight; sec2->floorheight = tempceiling; } @@ -5794,7 +5650,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if ((flags & FF_FLOATBOB)) { - P_AddFloatThinker(sec2, sec->tag, master); + P_AddFloatThinker(sec2, Tag_FGet(&master->tags), master); CheckForFloatBob = true; } @@ -5950,7 +5806,7 @@ static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, b * \sa P_SpawnSpecials, T_ThwompSector * \author SSNTails <http://www.ssntails.org> */ -static inline void P_AddThwompThinker(sector_t *sec, INT16 tag, line_t *sourceline, fixed_t crushspeed, fixed_t retractspeed, UINT16 sound) +static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t crushspeed, fixed_t retractspeed, UINT16 sound) { thwomp_t *thwomp; @@ -5974,7 +5830,7 @@ static inline void P_AddThwompThinker(sector_t *sec, INT16 tag, line_t *sourceli thwomp->floorstartheight = sec->floorheight; thwomp->ceilingstartheight = sec->ceilingheight; thwomp->delay = 1; - thwomp->tag = tag; + thwomp->tag = Tag_FGet(&sourceline->tags); thwomp->sound = sound; sec->floordata = thwomp; @@ -6066,8 +5922,9 @@ void T_LaserFlash(laserthink_t *flash) sector_t *sector; sector_t *sourcesec = flash->sourceline->frontsector; fixed_t top, bottom; + TAG_ITER_DECLARECOUNTER(0); - for (s = -1; (s = P_FindSectorFromTag(flash->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, flash->tag, s) { sector = §ors[s]; for (fflr = sector->ffloors; fflr; fflr = fflr->next) @@ -6322,6 +6179,8 @@ void P_SpawnSpecials(boolean fromnetsave) // Init line EFFECTs for (i = 0; i < numlines; i++) { + mtag_t tag = Tag_FGet(&lines[i].tags); + if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames... { // set line specials to 0 here too, same reason as above @@ -6345,10 +6204,11 @@ void P_SpawnSpecials(boolean fromnetsave) INT32 s; size_t sec; ffloortype_e ffloorflags; + TAG_ITER_DECLARECOUNTER(0); case 1: // Definable gravity per sector sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { sectors[s].gravity = §ors[sec].floorheight; // This allows it to change in realtime! @@ -6372,7 +6232,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 5: // Change camera info sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddCameraScanner(§ors[sec], §ors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y)); break; @@ -6395,22 +6255,22 @@ void P_SpawnSpecials(boolean fromnetsave) } //If no tag is given, apply to front sector - if (lines[i].tag == 0) + if (tag == 0) P_ApplyFlatAlignment(lines + i, lines[i].frontsector, flatangle, xoffs, yoffs); else { - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0;) + TAG_ITER_SECTORS(0, tag, s) P_ApplyFlatAlignment(lines + i, sectors + s, flatangle, xoffs, yoffs); } } else // Otherwise, print a helpful warning. Can I do no less? CONS_Alert(CONS_WARNING, M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), - lines[i].tag); + tag); break; case 8: // Sector Parameters - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { if (lines[i].flags & ML_NOCLIMB) { @@ -6437,8 +6297,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 10: // Vertical culling plane for sprites and FOFs - sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].cullheight = &lines[i]; // This allows it to change in realtime! break; @@ -6499,36 +6358,38 @@ void P_SpawnSpecials(boolean fromnetsave) case 63: // support for drawn heights coming from different sector sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].heightsec = (INT32)sec; break; case 64: // Appearing/Disappearing FOF option if (lines[i].flags & ML_BLOCKMONSTERS) { // Find FOFs by control sector tag - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) for (j = 0; (unsigned)j < sectors[s].linecount; j++) if (sectors[s].lines[j]->special >= 100 && sectors[s].lines[j]->special < 300) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), (INT32)(sectors[s].lines[j]-lines), (INT32)i); } else // Find FOFs by effect sector tag - for (s = -1; (s = P_FindLineFromTag(lines[i].tag, s)) >= 0 ;) + { + TAG_ITER_LINES(0, tag, s) { if ((size_t)s == i) continue; - if (sides[lines[s].sidenum[0]].sector->tag == sides[lines[i].sidenum[0]].sector->tag) + if (Tag_Find(&sides[lines[s].sidenum[0]].sector->tags, Tag_FGet(&sides[lines[i].sidenum[0]].sector->tags))) Add_MasterDisappearer(abs(lines[i].dx>>FRACBITS), abs(lines[i].dy>>FRACBITS), abs(sides[lines[i].sidenum[0]].sector->floorheight>>FRACBITS), s, (INT32)i); } + } break; case 66: // Displace floor by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 67: // Displace ceiling by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; case 68: // Displace both floor AND ceiling by front sector - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s, !!(lines[i].flags & ML_NOCLIMB)); break; @@ -6725,16 +6586,16 @@ void P_SpawnSpecials(boolean fromnetsave) { fixed_t dist = (lines[i].special == 150) ? 16*FRACUNIT : P_AproxDistance(lines[i].dx, lines[i].dy); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, dist, false, !!(lines[i].flags & ML_NOCLIMB), false); break; } case 152: // Adjustable air bobbing platform in reverse P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), true, !!(lines[i].flags & ML_NOCLIMB), false); break; case 153: // Dynamic Sinking Platform P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); + P_AddAirbob(lines[i].frontsector, tag, P_AproxDistance(lines[i].dx, lines[i].dy), false, !!(lines[i].flags & ML_NOCLIMB), true); break; case 160: // Float/bob platform @@ -6784,13 +6645,13 @@ void P_SpawnSpecials(boolean fromnetsave) case 176: // Air bobbing platform that will crumble and bob on the water when it falls and hits P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_FLOATBOB|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 177: // Air bobbing platform that will crumble and bob on // the water when it falls and hits, then never return P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_FLOATBOB|FF_CRUMBLE|FF_NORETURN, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 178: // Crumbling platform that will float when it hits water @@ -6803,7 +6664,7 @@ void P_SpawnSpecials(boolean fromnetsave) case 180: // Air bobbing platform that will crumble P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_CRUMBLE, secthinkers); - P_AddAirbob(lines[i].frontsector, lines[i].tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); + P_AddAirbob(lines[i].frontsector, tag, 16*FRACUNIT, false, !!(lines[i].flags & ML_NOCLIMB), false); break; case 190: // Rising Platform FOF (solid, opaque, shadows) @@ -6830,7 +6691,7 @@ void P_SpawnSpecials(boolean fromnetsave) ffloorflags |= FF_NOSHADE; P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); - P_AddRaiseThinker(lines[i].frontsector, lines[i].tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); + P_AddRaiseThinker(lines[i].frontsector, tag, speed, ceilingtop, ceilingbottom, !!(lines[i].flags & ML_BLOCKMONSTERS), !!(lines[i].flags & ML_NOCLIMB)); break; } @@ -6892,7 +6753,7 @@ void P_SpawnSpecials(boolean fromnetsave) fixed_t crushspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dy >> 3 : 10*FRACUNIT; fixed_t retractspeed = (lines[i].flags & ML_EFFECT5) ? lines[i].dx >> 3 : 2*FRACUNIT; UINT16 sound = (lines[i].flags & ML_EFFECT4) ? sides[lines[i].sidenum[0]].textureoffset >> FRACBITS : sfx_thwomp; - P_AddThwompThinker(lines[i].frontsector, lines[i].tag, &lines[i], crushspeed, retractspeed, sound); + P_AddThwompThinker(lines[i].frontsector, &lines[i], crushspeed, retractspeed, sound); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); break; } @@ -6934,7 +6795,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 258: // Laser block - P_AddLaserThinker(lines[i].tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); + P_AddLaserThinker(tag, lines + i, !!(lines[i].flags & ML_EFFECT1)); P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT, secthinkers); break; @@ -6945,7 +6806,7 @@ void P_SpawnSpecials(boolean fromnetsave) P_AddFakeFloorsByLine(i, fofflags, secthinkers); } else - I_Error("Custom FOF (tag %d) found without a linedef back side!", lines[i].tag); + I_Error("Custom FOF (tag %d) found without a linedef back side!", tag); break; case 300: // Linedef executor (combines with sector special 974/975) and commands @@ -7075,7 +6936,7 @@ void P_SpawnSpecials(boolean fromnetsave) { CONS_Alert(CONS_WARNING, M_GetText("Boss enable linedef (tag %d) has an invalid texture x offset.\nConsider changing it or removing it entirely.\n"), - lines[i].tag); + tag); break; } if (!(lines[i].flags & ML_NOCLIMB)) @@ -7124,46 +6985,46 @@ void P_SpawnSpecials(boolean fromnetsave) case 600: // floor lighting independently (e.g. lava) sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].floorlightsec = (INT32)sec; break; case 601: // ceiling lighting independently sec = sides[*lines[i].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) sectors[s].ceilinglightsec = (INT32)sec; break; case 602: // Adjustable pulsating light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableGlowingLight(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 603: // Adjustable flickering light sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableFireFlicker(§ors[sec], §ors[s], P_AproxDistance(lines[i].dx, lines[i].dy)>>FRACBITS); break; case 604: // Adjustable Blinking Light (unsynchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, false); break; case 605: // Adjustable Blinking Light (synchronized) sec = sides[*lines[i].sidenum].sector - sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[i].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) P_SpawnAdjustableStrobeFlash(§ors[sec], §ors[s], abs(lines[i].dx)>>FRACBITS, abs(lines[i].dy)>>FRACBITS, true); break; case 606: // HACK! Copy colormaps. Just plain colormaps. - for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0], s)) >= 0;) + TAG_ITER_SECTORS(0, lines[i].args[0], s) { extracolormap_t *exc; @@ -7178,7 +7039,7 @@ void P_SpawnSpecials(boolean fromnetsave) exc = lines[i].frontsector->extra_colormap; else { - INT32 sourcesec = P_FindSectorFromTag(lines[i].args[1], -1); + INT32 sourcesec = Tag_Iterate_Sectors(lines[i].args[1], 0); if (sourcesec == -1) { CONS_Debug(DBG_GAMELOGIC, "Line type 606: Can't find sector with source colormap (tag %d)!\n", lines[i].args[1]); @@ -7237,11 +7098,14 @@ void P_SpawnSpecials(boolean fromnetsave) */ static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers) { + TAG_ITER_DECLARECOUNTER(0); INT32 s; + mtag_t tag = Tag_FGet(&lines[line].tags); size_t sec = sides[*lines[line].sidenum].sector-sectors; - for (s = -1; (s = P_FindSectorFromTag(lines[line].tag, s)) >= 0 ;) - P_AddFakeFloor(§ors[s], §ors[sec], lines+line, ffloorflags, secthinkers); + line_t* li = lines + line; + TAG_ITER_SECTORS(0, tag, s) + P_AddFakeFloor(§ors[s], §ors[sec], li, ffloorflags, secthinkers); } /* @@ -7350,6 +7214,7 @@ void T_Scroll(scroll_t *s) size_t i; INT32 sect; ffloor_t *rover; + TAG_ITER_DECLARECOUNTER(0); case sc_side: // scroll wall texture side = sides + s->affectee; @@ -7386,7 +7251,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - for (sect = -1; (sect = P_FindSectorFromTag(line->tag, sect)) >= 0 ;) + TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) { sector_t *psec; psec = sectors + sect; @@ -7461,8 +7326,7 @@ void T_Scroll(scroll_t *s) if (!is3dblock) continue; - - for (sect = -1; (sect = P_FindSectorFromTag(line->tag, sect)) >= 0 ;) + TAG_ITER_SECTORS(0, Tag_FGet(&line->tags), sect) { sector_t *psec; psec = sectors + sect; @@ -7560,6 +7424,7 @@ static void P_SpawnScrollers(void) { size_t i; line_t *l = lines; + mtag_t tag; for (i = 0; i < numlines; i++, l++) { @@ -7568,6 +7433,8 @@ static void P_SpawnScrollers(void) INT32 control = -1, accel = 0; // no control sector or acceleration INT32 special = l->special; + tag = Tag_FGet(&l->tags); + // These types are same as the ones they get set to except that the // first side's sector's heights cause scrolling when they change, and // this linedef controls the direction and speed of the scrolling. The @@ -7599,10 +7466,11 @@ static void P_SpawnScrollers(void) switch (special) { register INT32 s; + TAG_ITER_DECLARECOUNTER(0); case 513: // scroll effect ceiling case 533: // scroll and carry objects on ceiling - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_ceiling, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 533) break; @@ -7611,13 +7479,13 @@ static void P_SpawnScrollers(void) case 523: // carry objects on ceiling dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_carry_ceiling, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; case 510: // scroll effect floor case 530: // scroll and carry objects on floor - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_floor, -dx, dy, control, s, accel, l->flags & ML_NOCLIMB); if (special != 530) break; @@ -7626,14 +7494,15 @@ static void P_SpawnScrollers(void) case 520: // carry objects on floor dx = FixedMul(dx, CARRYFACTOR); dy = FixedMul(dy, CARRYFACTOR); - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Scroller(sc_carry, dx, dy, control, s, accel, l->flags & ML_NOCLIMB); break; // scroll wall according to linedef // (same direction and speed as scrolling floors) case 502: - for (s = -1; (s = P_FindLineFromTag(l->tag, s)) >= 0 ;) + { + TAG_ITER_LINES(0, tag, s) if (s != (INT32)i) { if (l->flags & ML_EFFECT2) // use texture offsets instead @@ -7650,6 +7519,7 @@ static void P_SpawnScrollers(void) Add_Scroller(sc_side, dx, dy, control, lines[s].sidenum[0], accel, 0); } break; + } case 505: s = lines[i].sidenum[0]; @@ -7733,8 +7603,10 @@ void T_Disappear(disappear_t *d) { ffloor_t *rover; register INT32 s; + mtag_t afftag = Tag_FGet(&lines[d->affectee].tags); + TAG_ITER_DECLARECOUNTER(0); - for (s = -1; (s = P_FindSectorFromTag(lines[d->affectee].tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, afftag, s) { for (rover = sectors[s].ffloors; rover; rover = rover->next) { @@ -8460,14 +8332,17 @@ static void P_SpawnFriction(void) { size_t i; line_t *l = lines; + mtag_t tag; register INT32 s; fixed_t strength; // frontside texture offset controls magnitude fixed_t friction; // friction value to be applied during movement INT32 movefactor; // applied to each player move to simulate inertia + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < numlines; i++, l++) if (l->special == 540) { + tag = Tag_FGet(&l->tags); strength = sides[l->sidenum[0]].textureoffset>>FRACBITS; if (strength > 0) // sludge strength = strength*2; // otherwise, the maximum sludginess value is +967... @@ -8488,7 +8363,7 @@ static void P_SpawnFriction(void) else movefactor = FRACUNIT; - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Friction(friction, movefactor, s, -1); } } @@ -9004,22 +8879,26 @@ static void P_SpawnPushers(void) { size_t i; line_t *l = lines; + mtag_t tag; register INT32 s; mobj_t *thing; + TAG_ITER_DECLARECOUNTER(0); for (i = 0; i < numlines; i++, l++) + { + tag = Tag_FGet(&l->tags); switch (l->special) { case 541: // wind - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_wind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 544: // current - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_current, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 547: // push/pull - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) { thing = P_GetPushThing(s); if (thing) // No MT_P* means no effect @@ -9027,20 +8906,21 @@ static void P_SpawnPushers(void) } break; case 545: // current up - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_upcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 546: // current down - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_downcurrent, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 542: // wind up - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_upwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; case 543: // wind down - for (s = -1; (s = P_FindSectorFromTag(l->tag, s)) >= 0 ;) + TAG_ITER_SECTORS(0, tag, s) Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4); break; } + } } diff --git a/src/p_spec.h b/src/p_spec.h index 596d8171d2acfb8b8b337f8a4fc4c686f2d3ce9b..bba7c4a40a090084cce1f9738dc414c5a0c1c013 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -55,9 +55,6 @@ fixed_t P_FindNextLowestFloor(sector_t *sec, fixed_t currentheight); fixed_t P_FindLowestCeilingSurrounding(sector_t *sec); fixed_t P_FindHighestCeilingSurrounding(sector_t *sec); -INT32 P_FindSectorFromTag(INT16 tag, INT32 start); -INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); - INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max); void P_SetupSignExit(player_t *player); @@ -67,7 +64,6 @@ void P_SwitchWeather(INT32 weathernum); boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller); -void P_ChangeSectorTag(UINT32 sector, INT16 newtag); void P_RunNightserizeExecutors(mobj_t *actor); void P_RunDeNightserizeExecutors(mobj_t *actor); void P_RunNightsLapExecutors(mobj_t *actor); diff --git a/src/p_tick.c b/src/p_tick.c index 451e5e6266d9084586e21f0211e9a4ff3b15210d..da2a980c480a54f22d2dc2c3ef2904e96c07a1e8 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -643,7 +643,15 @@ void P_Ticker(boolean run) if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); if (demoplayback) - G_ReadDemoTiccmd(&players[consoleplayer].cmd, 0); + { + player_t* p = &players[consoleplayer]; + G_ReadDemoTiccmd(&p->cmd, 0); + if (!cv_freedemocamera.value) + { + P_ForceLocalAngle(p, p->cmd.angleturn << 16); + localaiming = p->aiming; + } + } ps_lua_mobjhooks = 0; ps_checkposition_calls = 0; diff --git a/src/p_user.c b/src/p_user.c index f9593158f3b269e2dd03c3bd64fec9ec4f8ebcc8..bb2b20cf7a01f532ec6cd9709c4d58bfc3d3f2ef 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8692,12 +8692,6 @@ void P_MovePlayer(player_t *player) player->fovadd = 0; #endif -#ifdef FLOORSPLATS - if (cv_shadow.value && rendermode == render_soft) - R_AddFloorSplat(player->mo->subsector, player->mo, "SHADOW", player->mo->x, - player->mo->y, player->mo->floorz, SPLATDRAWMODE_OPAQUE); -#endif - // Look for blocks to bust up // Because of FF_SHATTER, we should look for blocks constantly, // not just when spinning or playing as Knuckles @@ -10579,6 +10573,7 @@ static void P_CalcPostImg(player_t *player) postimg_t *type; INT32 *param; fixed_t pviewheight; + size_t i; if (player->mo->eflags & MFE_VERTICALFLIP) pviewheight = player->mo->z + player->mo->height - player->viewheight; @@ -10603,28 +10598,45 @@ static void P_CalcPostImg(player_t *player) } // see if we are in heat (no, not THAT kind of heat...) - - if (P_FindSpecialLineFromTag(13, sector->tag, -1) != -1) - *type = postimg_heat; - else if (sector->ffloors) + for (i = 0; i < sector->tags.count; i++) { - ffloor_t *rover; - fixed_t topheight; - fixed_t bottomheight; - - for (rover = sector->ffloors; rover; rover = rover->next) + if (Tag_FindLineSpecial(13, sector->tags.tags[i]) != -1) { - if (!(rover->flags & FF_EXISTS)) - continue; + *type = postimg_heat; + break; + } + else if (sector->ffloors) + { + ffloor_t *rover; + fixed_t topheight; + fixed_t bottomheight; + boolean gotres = false; - topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); - bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); + for (rover = sector->ffloors; rover; rover = rover->next) + { + size_t j; - if (pviewheight >= topheight || pviewheight <= bottomheight) - continue; + if (!(rover->flags & FF_EXISTS)) + continue; - if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1) - *type = postimg_heat; + topheight = P_GetFFloorTopZAt (rover, player->mo->x, player->mo->y); + bottomheight = P_GetFFloorBottomZAt(rover, player->mo->x, player->mo->y); + + if (pviewheight >= topheight || pviewheight <= bottomheight) + continue; + + for (j = 0; j < rover->master->frontsector->tags.count; j++) + { + if (Tag_FindLineSpecial(13, rover->master->frontsector->tags.tags[j]) != -1) + { + *type = postimg_heat; + gotres = true; + break; + } + } + } + if (gotres) + break; } } @@ -10723,22 +10735,21 @@ static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z, fixed_t *n static INT32 P_GetMinecartSpecialLine(sector_t *sec) { INT32 line = -1; + size_t i; if (!sec) return line; - if (sec->tag != 0) - line = P_FindSpecialLineFromTag(16, sec->tag, -1); + for (i = 0; i < sec->tags.count; i++) + if (sec->tags.tags[i] != 0) + line = Tag_FindLineSpecial(16, sec->tags.tags[i]); // Also try for lines facing the sector itself, with tag 0. + for (i = 0; i < sec->linecount; i++) { - UINT32 i; - for (i = 0; i < sec->linecount; i++) - { - line_t *li = sec->lines[i]; - if (li->tag == 0 && li->special == 16 && li->frontsector == sec) - line = li - lines; - } + line_t *li = sec->lines[i]; + if (Tag_Find(&li->tags, 0) && li->special == 16 && li->frontsector == sec) + line = li - lines; } return line; @@ -12297,12 +12308,14 @@ void P_PlayerThink(player_t *player) sector_t *controlsec; for (j=0; j<numsectors; j++) { + mtag_t sectag = Tag_FGet(§ors[j].tags); controlsec = NULL; // Does this sector have a water linedef? for (i=0; i<numlines;i++) { + mtag_t linetag = Tag_FGet(&lines[i].tags); if ((lines[i].special == 121 || lines[i].special == 123) - && lines[i].tag == sectors[j].tag) + && linetag == sectag) { controlsec = lines[i].frontsector; break; @@ -12311,15 +12324,16 @@ void P_PlayerThink(player_t *player) if (i < numlines && controlsec) { + controlsectag = Tag_FGet(&controlsec->tags); // Does this sector have a colormap? for (i=0; i<numlines;i++) { - if (lines[i].special == 606 && lines[i].tag == controlsec->tag) + if (lines[i].special == 606 && linetag == controlsectag) break; } if (i == numlines) - CONS_Debug(DBG_GAMELOGIC, "%d, %d\n", j, sectors[j].tag); + CONS_Debug(DBG_GAMELOGIC, "%d, %d\n", j, sectag); } } diff --git a/src/r_bsp.c b/src/r_bsp.c index 56d038b44183a49ee7a5571251fce4af8fe888c8..6f2a90d2d5e6c8642b4dc0eded0d47afb189012b 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -21,6 +21,7 @@ #include "p_local.h" // camera #include "p_slopes.h" #include "z_zone.h" // Check R_Prep3DFloors +#include "taglist.h" seg_t *curline; side_t *sidedef; @@ -374,7 +375,7 @@ boolean R_IsEmptyLine(seg_t *line, sector_t *front, sector_t *back) // Consider colormaps && back->extra_colormap == front->extra_colormap && ((!front->ffloors && !back->ffloors) - || front->tag == back->tag)); + || Tag_Compare(&front->tags, &back->tags))); } // @@ -448,21 +449,25 @@ static void R_AddLine(seg_t *line) // Portal line if (line->linedef->special == 40 && line->side == 0) { + // Render portal if recursiveness limit hasn't been reached. + // Otherwise, render the wall normally. if (portalrender < cv_maxportals.value) { - // Find the other side! - INT32 line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, -1); - if (line->linedef == &lines[line2]) - line2 = P_FindSpecialLineFromTag(40, line->linedef->tag, line2); - if (line2 >= 0) // found it! + size_t p; + mtag_t tag = Tag_FGet(&line->linedef->tags); + INT32 li1 = line->linedef-lines; + INT32 li2; + + for (p = 0; (li2 = Tag_Iterate_Lines(tag, p)) >= 0; p++) { - Portal_Add2Lines(line->linedef-lines, line2, x1, x2); // Remember the lines for later rendering - //return; // Don't fill in that space now! + // Skip invalid lines. + if ((tag != Tag_FGet(&lines[li2].tags)) || (lines[li1].special != lines[li2].special) || (li1 == li2)) + continue; + + Portal_Add2Lines(li1, li2, x1, x2); goto clipsolid; } } - // Recursed TOO FAR (viewing a portal within a portal) - // So uhhh, render it as a normal wall instead or something ??? } // Single sided line? @@ -483,7 +488,7 @@ static void R_AddLine(seg_t *line) if (!line->polyseg && !line->sidedef->midtexture && ((!frontsector->ffloors && !backsector->ffloors) - || (frontsector->tag == backsector->tag))) + || Tag_Compare(&frontsector->tags, &backsector->tags))) return; // line is empty, don't even bother goto clippass; // treat like wide open window instead @@ -1048,11 +1053,6 @@ static void R_Subsector(size_t num) } } -#ifdef FLOORSPLATS - if (sub->splats) - R_AddVisibleFloorSplats(sub); -#endif - // killough 9/18/98: Fix underwater slowdown, by passing real sector // instead of fake one. Improve sprite lighting by basing sprite // lightlevels on floor & ceiling lightlevels in the surrounding area. diff --git a/src/r_data.c b/src/r_data.c index dd36c2ee28623ce1ce16aa49709196009702e08b..af672f6dc024ee2c6840818982d586b17ceacb07 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -20,6 +20,7 @@ #include "m_misc.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" @@ -174,13 +175,15 @@ UINT8 ASTBlendPaletteIndexes(UINT8 background, UINT8 foreground, int style, UINT if (alpha <= ASTTextureBlendingThreshold[1]) { UINT8 *mytransmap; + INT32 trans; // Is the patch way too translucent? Don't blend then. if (alpha < ASTTextureBlendingThreshold[0]) return background; // The equation's not exact but it works as intended. I'll call it a day for now. - mytransmap = transtables + ((8*(alpha) + 255/8)/(255 - 255/11) << FF_TRANSSHIFT); + trans = (8*(alpha) + 255/8)/(255 - 255/11); + mytransmap = R_GetTranslucencyTable(trans + 1); if (background != 0xFF) return *(mytransmap + (background<<8) + foreground); } @@ -1307,7 +1310,7 @@ void R_PrecacheLevel(void) lump = sf->lumppat[a];\ if (devparm)\ spritememory += W_LumpLength(lump);\ - W_CachePatchNum(lump, PU_PATCH);\ + W_CachePatchNum(lump, PU_SPRITE);\ } // see R_InitSprites for more about lumppat,lumpid switch (sf->rotate) diff --git a/src/r_defs.h b/src/r_defs.h index 132106bc88c0dd0b28d93fb0cf24e51947bf804d..9c649fbc4508bf148787566eb6692f6111d24706 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -28,6 +28,8 @@ #include "m_aatree.h" #endif +#include "taglist.h" + // // ClipWallSegment // Clips the given range of columns @@ -281,8 +283,7 @@ typedef struct sector_s INT32 ceilingpic; INT16 lightlevel; INT16 special; - UINT16 tag; - INT32 nexttag, firsttag; // for fast tag searches + taglist_t tags; // origin for any sounds played by the sector // also considered the center for e.g. Mario blocks @@ -389,7 +390,7 @@ typedef struct line_s // Animation related. INT16 flags; INT16 special; - INT16 tag; + taglist_t tags; INT32 args[NUMLINEARGS]; char *stringargs[NUMLINESTRINGARGS]; @@ -409,10 +410,6 @@ typedef struct line_s sector_t *backsector; size_t validcount; // if == validcount, already checked -#if 1//#ifdef WALLSPLATS - void *splats; // wallsplat_t list -#endif - INT32 firsttag, nexttag; // improves searches for tags. polyobj_t *polyobj; // Belongs to a polyobject? char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. @@ -457,9 +454,6 @@ typedef struct subsector_s INT16 numlines; UINT16 firstline; struct polyobj_s *polyList; // haleyjd 02/19/06: list of polyobjects -#if 1//#ifdef FLOORSPLATS - void *splats; // floorsplat_t list -#endif size_t validcount; } subsector_t; @@ -652,8 +646,12 @@ typedef enum RGBA32 = 4, // 32 bit rgba } pic_mode_t; -#if defined(_MSC_VER) -#pragma pack(1) +#ifdef ROTSPRITE +typedef struct +{ + INT32 angles; + void **patches; +} rotsprite_t; #endif // Patches. @@ -661,7 +659,26 @@ typedef enum // Patches are used for sprites and all masked pictures, and we compose // textures from the TEXTURES list of patches. // -// WARNING: this structure is cloned in GLPatch_t +typedef struct +{ + INT16 width, height; + INT16 leftoffset, topoffset; + + INT32 *columnofs; // Column offsets. This is relative to patch->columns + UINT8 *columns; // Software column data + + void *hardware; // OpenGL patch, allocated whenever necessary + void *flats[4]; // The patch as flats + +#ifdef ROTSPRITE + rotsprite_t *rotated; // Rotated patches +#endif +} patch_t; + +#if defined(_MSC_VER) +#pragma pack(1) +#endif + typedef struct { INT16 width; // bounding box size @@ -670,7 +687,7 @@ typedef struct INT16 topoffset; // pixels below the origin INT32 columnofs[8]; // only [width] used // the [0] is &columnofs[width] -} ATTRPACK patch_t; +} ATTRPACK softwarepatch_t; #ifdef _MSC_VER #pragma warning(disable : 4200) @@ -696,14 +713,32 @@ typedef struct #pragma pack() #endif -// rotsprite -#ifdef ROTSPRITE -typedef struct +typedef enum { - patch_t *patch[16][ROTANGLES]; - UINT16 cached; -} rotsprite_t; -#endif/*ROTSPRITE*/ + RF_HORIZONTALFLIP = 0x0001, // Flip sprite horizontally + RF_VERTICALFLIP = 0x0002, // Flip sprite vertically + RF_ABSOLUTEOFFSETS = 0x0004, // Sprite uses the object's offsets absolutely, instead of relatively + RF_FLIPOFFSETS = 0x0008, // Relative object offsets are flipped with the sprite + + RF_SPLATMASK = 0x00F0, // --Floor sprite flags + RF_SLOPESPLAT = 0x0010, // Rotate floor sprites by a slope + RF_OBJECTSLOPESPLAT = 0x0020, // Rotate floor sprites by the object's standing slope + RF_NOSPLATBILLBOARD = 0x0040, // Don't billboard floor sprites (faces forward from the view angle) + RF_NOSPLATROLLANGLE = 0x0080, // Don't rotate floor sprites by the object's rollangle (uses rotated patches instead) + + RF_BLENDMASK = 0x0F00, // --Blending modes + RF_FULLBRIGHT = 0x0100, // Sprite is drawn at full brightness + RF_FULLDARK = 0x0200, // Sprite is drawn completely dark + RF_NOCOLORMAPS = 0x0400, // Sprite is not drawn with colormaps + + RF_SPRITETYPEMASK = 0x7000, // ---Different sprite types + RF_PAPERSPRITE = 0x1000, // Paper sprite + RF_FLOORSPRITE = 0x2000, // Floor sprite + + RF_SHADOWDRAW = 0x10000, // Stretches and skews the sprite like a shadow. + RF_SHADOWEFFECTS = 0x20000, // Scales and becomes transparent like a shadow. + RF_DROPSHADOW = (RF_SHADOWDRAW | RF_SHADOWEFFECTS | RF_FULLDARK), +} renderflags_t; typedef enum { @@ -717,24 +752,6 @@ typedef enum SRF_NONE = 0xff // Initial value } spriterotateflags_t; // SRF's up! -// Same as a patch_t, except just the header -// and the wadnum/lumpnum combination that points -// to wherever the patch is in memory. -struct patchinfo_s -{ - INT16 width; // bounding box size - INT16 height; - INT16 leftoffset; // pixels to the left of origin - INT16 topoffset; // pixels below the origin - - UINT16 wadnum; // the software patch lump num for when the patch - UINT16 lumpnum; // was flushed, and we need to re-create it - - // next patchinfo_t in memory - struct patchinfo_s *next; -}; -typedef struct patchinfo_s patchinfo_t; - // // Sprites are patches with a special naming convention so they can be // recognized by R_InitSprites. @@ -764,7 +781,7 @@ typedef struct UINT16 flip; #ifdef ROTSPRITE - rotsprite_t rotsprite; + rotsprite_t *rotated[2][16]; // Rotated patches #endif } spriteframe_t; diff --git a/src/r_draw.c b/src/r_draw.c index 2b798c3bf383c42d22e99674e1ceb4521a85c352..d9ea942a2f22b301bdbd1762e0635f31ba085d6e 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -75,6 +75,7 @@ UINT8 *dc_source; #define NUMTRANSTABLES 9 // how many translucency tables are used UINT8 *transtables; // translucency tables +UINT8 *blendtables[NUMBLENDMAPS]; /** \brief R_DrawTransColumn uses this */ @@ -98,15 +99,19 @@ INT32 dc_numlights = 0, dc_maxlights, dc_texheight; INT32 ds_y, ds_x1, ds_x2; lighttable_t *ds_colormap; +lighttable_t *ds_translation; // Lactozilla: Sprite splat drawer + fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; +INT32 ds_waterofs, ds_bgofs; + UINT16 ds_flatwidth, ds_flatheight; boolean ds_powersoftwo; -UINT8 *ds_source; // start of a 64*64 tile image +UINT8 *ds_source; // points to the start of a flat UINT8 *ds_transmap; // one of the translucency tables -pslope_t *ds_slope; // Current slope being used -floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? +// Vectors for Software's tilted slope drawers +floatv3_t *ds_su, *ds_sv, *ds_sz; floatv3_t *ds_sup, *ds_svp, *ds_szp; float focallengthf, zeroheight; @@ -115,10 +120,6 @@ float focallengthf, zeroheight; UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask; -// ========================================================================== -// OLD DOOM FUZZY EFFECT -// ========================================================================== - // ========================================================================= // TRANSLATION COLORMAP CODE // ========================================================================= @@ -138,11 +139,11 @@ UINT8 skincolor_modified[MAXSKINCOLORS]; CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; -/** \brief The R_InitTranslationTables +#define TRANSTAB_AMTMUL10 (256.0f / 10.0f) - load in color translation tables +/** \brief Initializes the translucency tables used by the Software renderer. */ -void R_InitTranslationTables(void) +void R_InitTranslucencyTables(void) { // Load here the transparency lookup tables 'TINTTAB' // NOTE: the TINTTAB resource MUST BE aligned on 64k for the asm @@ -159,17 +160,94 @@ void R_InitTranslationTables(void) W_ReadLump(W_GetNumForName("TRANS70"), transtables+0x60000); W_ReadLump(W_GetNumForName("TRANS80"), transtables+0x70000); W_ReadLump(W_GetNumForName("TRANS90"), transtables+0x80000); + + R_GenerateBlendTables(); } +void R_GenerateBlendTables(void) +{ + INT32 i; -/** \brief Generates a translation colormap. + for (i = 0; i < NUMBLENDMAPS; i++) + { + if (i == blendtab_modulate) + continue; + blendtables[i] = Z_MallocAlign((NUMTRANSTABLES + 1) * 0x10000, PU_STATIC, NULL, 16); + } - \param dest_colormap colormap to populate - \param skinnum number of skin, TC_DEFAULT or TC_BOSS - \param color translation color + for (i = 0; i <= 9; i++) + { + const size_t offs = (0x10000 * i); + const UINT8 alpha = TRANSTAB_AMTMUL10 * i; - \return void -*/ + R_GenerateTranslucencyTable(blendtables[blendtab_add] + offs, AST_ADD, alpha); + R_GenerateTranslucencyTable(blendtables[blendtab_subtract] + offs, AST_SUBTRACT, alpha); + R_GenerateTranslucencyTable(blendtables[blendtab_reversesubtract] + offs, AST_REVERSESUBTRACT, alpha); + } + + // Modulation blending only requires a single table + blendtables[blendtab_modulate] = Z_MallocAlign(0x10000, PU_STATIC, NULL, 16); + R_GenerateTranslucencyTable(blendtables[blendtab_modulate], AST_MODULATE, 0); +} + +static colorlookup_t transtab_lut; + +void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt) +{ + INT16 bg, fg; + + if (table == NULL) + I_Error("R_GenerateTranslucencyTable: input table was NULL!"); + + InitColorLUT(&transtab_lut, pMasterPalette, false); + + for (bg = 0; bg < 0xFF; bg++) + { + for (fg = 0; fg < 0xFF; fg++) + { + RGBA_t backrgba = V_GetMasterColor(bg); + RGBA_t frontrgba = V_GetMasterColor(fg); + RGBA_t result; + + result.rgba = ASTBlendPixel(backrgba, frontrgba, style, blendamt); + table[((bg * 0x100) + fg)] = GetColorLUT(&transtab_lut, result.s.red, result.s.green, result.s.blue); + } + } +} + +#define ClipTransLevel(trans) max(min((trans), NUMTRANSMAPS-2), 0) + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel) +{ + return transtables + (ClipTransLevel(alphalevel-1) << FF_TRANSSHIFT); +} + +UINT8 *R_GetBlendTable(int style, INT32 alphalevel) +{ + size_t offs = (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + + // Lactozilla: Returns the equivalent to AST_TRANSLUCENT + // if no alpha style matches any of the blend tables. + switch (style) + { + case AST_ADD: + return blendtables[blendtab_add] + offs; + case AST_SUBTRACT: + return blendtables[blendtab_subtract] + offs; + case AST_REVERSESUBTRACT: + return blendtables[blendtab_reversesubtract] + offs; + case AST_MODULATE: + return blendtables[blendtab_modulate]; + default: + break; + } + + // Return a normal translucency table + if (--alphalevel >= 0) + return transtables + (ClipTransLevel(alphalevel) << FF_TRANSSHIFT); + else + return NULL; +} // Define for getting accurate color brightness readings according to how the human eye sees them. // https://en.wikipedia.org/wiki/Relative_luminance @@ -227,6 +305,14 @@ static void R_RainbowColormap(UINT8 *dest_colormap, UINT16 skincolor) #undef SETBRIGHTNESS +/** \brief Generates a translation colormap. + + \param dest_colormap colormap to populate + \param skinnum number of skin, TC_DEFAULT or TC_BOSS + \param color translation color + + \return void +*/ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT16 color) { INT32 i, starttranscolor, skinramplength; diff --git a/src/r_draw.h b/src/r_draw.h index 1ca22f18aa7f80840c9c367dcb2c0199bb62a5c0..9957541ca33bcfd84c37b03f4375184a722da459 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -37,7 +37,6 @@ extern UINT8 dc_hires; extern UINT8 *dc_source; // first pixel in a column // translucency stuff here -extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] extern UINT8 *dc_transmap; // translation stuff here @@ -56,9 +55,14 @@ extern INT32 dc_texheight; extern INT32 ds_y, ds_x1, ds_x2; extern lighttable_t *ds_colormap; +extern lighttable_t *ds_translation; + extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep; +extern INT32 ds_waterofs, ds_bgofs; + extern UINT16 ds_flatwidth, ds_flatheight; extern boolean ds_powersoftwo; + extern UINT8 *ds_source; extern UINT8 *ds_transmap; @@ -66,8 +70,8 @@ typedef struct { float x, y, z; } floatv3_t; -extern pslope_t *ds_slope; // Current slope being used -extern floatv3_t ds_su[MAXVIDHEIGHT], ds_sv[MAXVIDHEIGHT], ds_sz[MAXVIDHEIGHT]; // Vectors for... stuff? +// Vectors for Software's tilted slope drawers +extern floatv3_t *ds_su, *ds_sv, *ds_sz; extern floatv3_t *ds_sup, *ds_svp, *ds_szp; extern float focallengthf, zeroheight; @@ -110,17 +114,36 @@ extern lumpnum_t viewborderlump[8]; #define TC_BLINK -6 // For item blinking, according to kart #define TC_DASHMODE -7 // For Metal Sonic's dashmode +// Custom player skin translation // Initialize color translation tables, for player rendering etc. -void R_InitTranslationTables(void); UINT8* R_GetTranslationColormap(INT32 skinnum, skincolornum_t color, UINT8 flags); void R_FlushTranslationColormapCache(void); UINT16 R_GetColorByName(const char *name); UINT16 R_GetSuperColorByName(const char *name); +extern UINT8 *transtables; // translucency tables, should be (*transtables)[5][256][256] + +enum +{ + blendtab_add, + blendtab_subtract, + blendtab_reversesubtract, + blendtab_modulate, + NUMBLENDMAPS +}; + +extern UINT8 *blendtables[NUMBLENDMAPS]; + +void R_InitTranslucencyTables(void); +void R_GenerateBlendTables(void); +void R_GenerateTranslucencyTable(UINT8 *table, int style, UINT8 blendamt); + +UINT8 *R_GetTranslucencyTable(INT32 alphalevel); +UINT8 *R_GetBlendTable(int style, INT32 alphalevel); + // Color ramp modification should force a recache extern UINT8 skincolor_modified[]; -// Custom player skin translation void R_InitViewBuffer(INT32 width, INT32 height); void R_InitViewBorder(void); void R_VideoErase(size_t ofs, INT32 count); @@ -149,39 +172,47 @@ void R_Draw2sMultiPatchTranslucentColumn_8(void); void R_DrawFogColumn_8(void); void R_DrawColumnShadowed_8(void); +#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) + void R_DrawSpan_8(void); -void R_DrawSplat_8(void); void R_DrawTranslucentSpan_8(void); -void R_DrawTranslucentSplat_8(void); void R_DrawTiltedSpan_8(void); void R_DrawTiltedTranslucentSpan_8(void); -#ifndef NOWATER -void R_DrawTiltedTranslucentWaterSpan_8(void); -#endif + +void R_DrawSplat_8(void); +void R_DrawTranslucentSplat_8(void); void R_DrawTiltedSplat_8(void); + +void R_DrawFloorSprite_8(void); +void R_DrawTranslucentFloorSprite_8(void); +void R_DrawTiltedFloorSprite_8(void); +void R_DrawTiltedTranslucentFloorSprite_8(void); + void R_CalcTiltedLighting(fixed_t start, fixed_t end); extern INT32 tiltlighting[MAXVIDWIDTH]; -#ifndef NOWATER + void R_DrawTranslucentWaterSpan_8(void); -extern INT32 ds_bgofs; -extern INT32 ds_waterofs; -#endif +void R_DrawTiltedTranslucentWaterSpan_8(void); + void R_DrawFogSpan_8(void); // Lactozilla: Non-powers-of-two void R_DrawSpan_NPO2_8(void); void R_DrawTranslucentSpan_NPO2_8(void); -void R_DrawSplat_NPO2_8(void); -void R_DrawTranslucentSplat_NPO2_8(void); void R_DrawTiltedSpan_NPO2_8(void); void R_DrawTiltedTranslucentSpan_NPO2_8(void); -#ifndef NOWATER -void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); -#endif + +void R_DrawSplat_NPO2_8(void); +void R_DrawTranslucentSplat_NPO2_8(void); void R_DrawTiltedSplat_NPO2_8(void); -#ifndef NOWATER + +void R_DrawFloorSprite_NPO2_8(void); +void R_DrawTranslucentFloorSprite_NPO2_8(void); +void R_DrawTiltedFloorSprite_NPO2_8(void); +void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void); + void R_DrawTranslucentWaterSpan_NPO2_8(void); -#endif +void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); #ifdef USEASM void ASMCALL R_DrawColumn_8_ASM(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index 940ea724b31ef2411514799d4a9f7df7e284c907..e78ba8a6c49b8f39a9c54fe0af814340c9462641 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -536,6 +536,9 @@ void R_DrawTranslatedColumn_8(void) // SPANS // ========================================================================== +#define SPANSIZE 16 +#define INVSPAN 0.0625f + /** \brief The R_DrawSpan_8 function Draws the actual span. */ @@ -643,8 +646,6 @@ void R_CalcTiltedLighting(fixed_t start, fixed_t end) } } -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) - /** \brief The R_DrawTiltedSpan_8 function Draw slopes! Holy sheit! */ @@ -704,9 +705,6 @@ void R_DrawTiltedSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -839,9 +837,6 @@ void R_DrawTiltedTranslucentSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -916,7 +911,6 @@ void R_DrawTiltedTranslucentSpan_8(void) #endif } -#ifndef NOWATER /** \brief The R_DrawTiltedTranslucentWaterSpan_8 function Like DrawTiltedTranslucentSpan, but for water */ @@ -977,9 +971,6 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1053,7 +1044,6 @@ void R_DrawTiltedTranslucentWaterSpan_8(void) } #endif } -#endif // NOWATER void R_DrawTiltedSplat_8(void) { @@ -1116,9 +1106,6 @@ void R_DrawTiltedSplat_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1419,6 +1406,448 @@ void R_DrawTranslucentSplat_8 (void) } } +/** \brief The R_DrawFloorSprite_8 function + Just like R_DrawSplat_8, but for floor sprites. +*/ +void R_DrawFloorSprite_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + // + // <Callum> 4194303 = (2048x2048)-1 (2048x2048 is maximum flat size) + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[0] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[1] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[2] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[3] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[4] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[5] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[6] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + val = (((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift); + val &= 4194303; + val = source[val]; + if (val & 0xFF00) + dest[7] = colormap[translation[val & 0xFF]]; + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTranslucentFloorSplat_8 function + Just like R_DrawFloorSprite_8, but is translucent! +*/ +void R_DrawTranslucentFloorSprite_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + // SoM: we only need 6 bits for the integer part (0 thru 63) so the rest + // can be used for the fraction part. This allows calculation of the memory address in the + // texture with two shifts, an OR and one AND. (see below) + // for texture sizes > 64 the amount of precision we can allow will decrease, but only by one + // bit per power of two (obviously) + // Ok, because I was able to eliminate the variable spot below, this function is now FASTER + // than the original span renderer. Whodathunkit? + xposition <<= nflatshiftup; yposition <<= nflatshiftup; + xstep <<= nflatshiftup; ystep <<= nflatshiftup; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + while (count >= 8) + { + // SoM: Why didn't I see this earlier? the spot variable is a waste now because we don't + // have the uber complicated math to calculate it now, so that was a memory write we didn't + // need! + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[0] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[0]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[1] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[1]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[2] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[2]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[3] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[3]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[4] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[4]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[5] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[5]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[6] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[6]); + xposition += xstep; + yposition += ystep; + + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + dest[7] = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + dest[7]); + xposition += xstep; + yposition += ystep; + + dest += 8; + count -= 8; + } + while (count-- && dest <= deststop) + { + val = source[(((UINT32)yposition >> nflatyshift) & nflatmask) | ((UINT32)xposition >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTiltedFloorSprite_8 function + Draws a tilted floor sprite. +*/ +void R_DrawTiltedFloorSprite_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + } + } +} + +/** \brief The R_DrawTiltedTranslucentFloorSprite_8 function + Draws a tilted, translucent, floor sprite. +*/ +void R_DrawTiltedTranslucentFloorSprite_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + } + } +} + /** \brief The R_DrawTranslucentSpan_8 function Draws the actual span with translucency. */ @@ -1503,7 +1932,6 @@ void R_DrawTranslucentSpan_8 (void) } } -#ifndef NOWATER void R_DrawTranslucentWaterSpan_8(void) { UINT32 xposition; @@ -1580,7 +2008,6 @@ void R_DrawTranslucentWaterSpan_8(void) yposition += ystep; } } -#endif /** \brief The R_DrawFogSpan_8 function Draws the actual span with fogging. diff --git a/src/r_draw8_npo2.c b/src/r_draw8_npo2.c index 630b36e6f7cd9afce187ac5e29738b94c7f63708..a34a20e9a9737241bbc183d71f8bae01a982cb7a 100644 --- a/src/r_draw8_npo2.c +++ b/src/r_draw8_npo2.c @@ -15,6 +15,9 @@ // SPANS // ========================================================================== +#define SPANSIZE 16 +#define INVSPAN 0.0625f + /** \brief The R_DrawSpan_NPO2_8 function Draws the actual span. */ @@ -83,8 +86,6 @@ void R_DrawSpan_NPO2_8 (void) } } -#define PLANELIGHTFLOAT (BASEVIDWIDTH * BASEVIDWIDTH / vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f * FIXED_TO_FLOAT(fovtan)) - /** \brief The R_DrawTiltedSpan_NPO2_8 function Draw slopes! Holy sheit! */ @@ -159,9 +160,6 @@ void R_DrawTiltedSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -354,9 +352,6 @@ void R_DrawTiltedTranslucentSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -553,9 +548,6 @@ void R_DrawTiltedSplat_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -818,6 +810,446 @@ void R_DrawTranslucentSplat_NPO2_8 (void) } } +/** \brief The R_DrawFloorSprite_NPO2_8 function + Just like R_DrawSplat_NPO2_8, but for floor sprites. +*/ +void R_DrawFloorSprite_NPO2_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + fixed_t x, y; + fixed_t fixedwidth, fixedheight; + + UINT16 *source; + UINT8 *translation; + UINT8 *colormap; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + fixedwidth = ds_flatwidth << FRACBITS; + fixedheight = ds_flatheight << FRACBITS; + + // Fix xposition and yposition if they are out of bounds. + if (xposition < 0) + xposition = fixedwidth - ((UINT32)(fixedwidth - xposition) % fixedwidth); + else if (xposition >= fixedwidth) + xposition %= fixedwidth; + if (yposition < 0) + yposition = fixedheight - ((UINT32)(fixedheight - yposition) % fixedheight); + else if (yposition >= fixedheight) + yposition %= fixedheight; + + while (count-- && dest <= deststop) + { + // The loops here keep the texture coordinates within the texture. + // They will rarely iterate multiple times, and are cheaper than a modulo operation, + // even if using libdivide. + if (xstep < 0) // These if statements are hopefully hoisted by the compiler to above this loop + while (xposition < 0) + xposition += fixedwidth; + else + while (xposition >= fixedwidth) + xposition -= fixedwidth; + if (ystep < 0) + while (yposition < 0) + yposition += fixedheight; + else + while (yposition >= fixedheight) + yposition -= fixedheight; + + x = (xposition >> FRACBITS); + y = (yposition >> FRACBITS); + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTranslucentFloorSprite_NPO2_8 function + Just like R_DrawFloorSprite_NPO2_8, but is translucent! +*/ +void R_DrawTranslucentFloorSprite_NPO2_8 (void) +{ + fixed_t xposition; + fixed_t yposition; + fixed_t xstep, ystep; + fixed_t x, y; + fixed_t fixedwidth, fixedheight; + + UINT16 *source; + UINT8 *translation; + UINT8 *colormap; + UINT8 *dest; + const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; + + size_t count = (ds_x2 - ds_x1 + 1); + UINT32 val; + + xposition = ds_xfrac; yposition = ds_yfrac; + xstep = ds_xstep; ystep = ds_ystep; + + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + dest = ylookup[ds_y] + columnofs[ds_x1]; + + fixedwidth = ds_flatwidth << FRACBITS; + fixedheight = ds_flatheight << FRACBITS; + + // Fix xposition and yposition if they are out of bounds. + if (xposition < 0) + xposition = fixedwidth - ((UINT32)(fixedwidth - xposition) % fixedwidth); + else if (xposition >= fixedwidth) + xposition %= fixedwidth; + if (yposition < 0) + yposition = fixedheight - ((UINT32)(fixedheight - yposition) % fixedheight); + else if (yposition >= fixedheight) + yposition %= fixedheight; + + while (count-- && dest <= deststop) + { + // The loops here keep the texture coordinates within the texture. + // They will rarely iterate multiple times, and are cheaper than a modulo operation, + // even if using libdivide. + if (xstep < 0) // These if statements are hopefully hoisted by the compiler to above this loop + while (xposition < 0) + xposition += fixedwidth; + else + while (xposition >= fixedwidth) + xposition -= fixedwidth; + if (ystep < 0) + while (yposition < 0) + yposition += fixedheight; + else + while (yposition >= fixedheight) + yposition -= fixedheight; + + x = (xposition >> FRACBITS); + y = (yposition >> FRACBITS); + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + xposition += xstep; + yposition += ystep; + } +} + +/** \brief The R_DrawTiltedFloorSprite_NPO2_8 function + Draws a tilted floor sprite. +*/ +void R_DrawTiltedFloorSprite_NPO2_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + // Lactozilla: Non-powers-of-two + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + } + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = colormap[translation[val & 0xFF]]; + dest++; + + u += stepu; + v += stepv; + } + } + } +} + +/** \brief The R_DrawTiltedTranslucentFloorSprite_NPO2_8 function + Draws a tilted, translucent, floor sprite. +*/ +void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void) +{ + // x1, x2 = ds_x1, ds_x2 + int width = ds_x2 - ds_x1; + double iz, uz, vz; + UINT32 u, v; + int i; + + UINT16 *source; + UINT8 *colormap; + UINT8 *translation; + UINT8 *dest; + UINT16 val; + + double startz, startu, startv; + double izstep, uzstep, vzstep; + double endz, endu, endv; + UINT32 stepu, stepv; + + iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx); + uz = ds_sup->z + ds_sup->y*(centery-ds_y) + ds_sup->x*(ds_x1-centerx); + vz = ds_svp->z + ds_svp->y*(centery-ds_y) + ds_svp->x*(ds_x1-centerx); + + dest = ylookup[ds_y] + columnofs[ds_x1]; + source = (UINT16 *)ds_source; + colormap = ds_colormap; + translation = ds_translation; + + startz = 1.f/iz; + startu = uz*startz; + startv = vz*startz; + + izstep = ds_szp->x * SPANSIZE; + uzstep = ds_sup->x * SPANSIZE; + vzstep = ds_svp->x * SPANSIZE; + //x1 = 0; + width++; + + while (width >= SPANSIZE) + { + iz += izstep; + uz += uzstep; + vz += vzstep; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + stepu = (INT64)((endu - startu) * INVSPAN); + stepv = (INT64)((endv - startv) * INVSPAN); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (i = SPANSIZE-1; i >= 0; i--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + startu = endu; + startv = endv; + width -= SPANSIZE; + } + if (width > 0) + { + if (width == 1) + { + u = (INT64)(startu); + v = (INT64)(startv); + // Lactozilla: Non-powers-of-two + { + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + } + } + else + { + double left = width; + iz += ds_szp->x * left; + uz += ds_sup->x * left; + vz += ds_svp->x * left; + + endz = 1.f/iz; + endu = uz*endz; + endv = vz*endz; + left = 1.f/left; + stepu = (INT64)((endu - startu) * left); + stepv = (INT64)((endv - startv) * left); + u = (INT64)(startu) + viewx; + v = (INT64)(startv) + viewy; + + for (; width != 0; width--) + { + // Lactozilla: Non-powers-of-two + fixed_t x = (((fixed_t)u-viewx) >> FRACBITS); + fixed_t y = (((fixed_t)v-viewy) >> FRACBITS); + + // Carefully align all of my Friends. + if (x < 0) + x = ds_flatwidth - ((UINT32)(ds_flatwidth - x) % ds_flatwidth); + if (y < 0) + y = ds_flatheight - ((UINT32)(ds_flatheight - y) % ds_flatheight); + + x %= ds_flatwidth; + y %= ds_flatheight; + + val = source[((y * ds_flatwidth) + x)]; + if (val & 0xFF00) + *dest = *(ds_transmap + (colormap[translation[val & 0xFF]] << 8) + *dest); + dest++; + + u += stepu; + v += stepv; + } + } + } +} + /** \brief The R_DrawTranslucentSpan_NPO2_8 function Draws the actual span with translucency. */ @@ -885,7 +1317,6 @@ void R_DrawTranslucentSpan_NPO2_8 (void) } } -#ifndef NOWATER void R_DrawTranslucentWaterSpan_NPO2_8(void) { fixed_t xposition; @@ -1024,9 +1455,6 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) vz += ds_svp->x; } while (--width >= 0); #else -#define SPANSIZE 16 -#define INVSPAN 0.0625f - startz = 1.f/iz; startu = uz*startz; startv = vz*startz; @@ -1145,4 +1573,3 @@ void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) } #endif } -#endif // NOWATER diff --git a/src/r_main.c b/src/r_main.c index 5165b3c87b3fa51a1505fb9033715c2f713d6a46..165f74a7975515011d81b4ad8a0d2346b0ad4600 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -959,6 +959,16 @@ void R_ExecuteSetViewSize(void) dy = FixedMul(abs(dy), fovtan); yslopetab[i] = FixedDiv(centerx*FRACUNIT, dy); } + + if (ds_su) + Z_Free(ds_su); + if (ds_sv) + Z_Free(ds_sv); + if (ds_sz) + Z_Free(ds_sz); + + ds_su = ds_sv = ds_sz = NULL; + ds_sup = ds_svp = ds_szp = NULL; } memset(scalelight, 0xFF, sizeof(scalelight)); @@ -1011,8 +1021,8 @@ void R_Init(void) //I_OutputMsg("\nR_InitLightTables"); R_InitLightTables(); - //I_OutputMsg("\nR_InitTranslationTables\n"); - R_InitTranslationTables(); + //I_OutputMsg("\nR_InitTranslucencyTables\n"); + R_InitTranslucencyTables(); R_InitDrawNodes(); @@ -1473,9 +1483,6 @@ void R_RenderPlayerView(player_t *player) } R_ClearDrawSegs(); R_ClearSprites(); -#ifdef FLOORSPLATS - R_ClearVisibleFloorSplats(); -#endif Portal_InitList(); // check for new console commands. @@ -1558,9 +1565,6 @@ void R_RenderPlayerView(player_t *player) ps_sw_planetime = I_GetTimeMicros(); R_DrawPlanes(); -#ifdef FLOORSPLATS - R_DrawVisibleFloorSplats(); -#endif ps_sw_planetime = I_GetTimeMicros() - ps_sw_planetime; // draw mid texture and sprite @@ -1572,24 +1576,6 @@ void R_RenderPlayerView(player_t *player) free(masks); } -#ifdef HWRENDER -void R_InitHardwareMode(void) -{ - HWR_AddSessionCommands(); - HWR_Switch(); - HWR_LoadTextures(numtextures); - if (gamestate == GS_LEVEL || (gamestate == GS_TITLESCREEN && titlemapinaction)) - HWR_SetupLevel(); -} -#endif - -void R_ReloadHUDGraphics(void) -{ - ST_LoadGraphics(); - HU_LoadGraphics(); - ST_ReloadSkinFaceGraphics(); -} - // ========================================================================= // ENGINE COMMANDS & VARS // ========================================================================= diff --git a/src/r_main.h b/src/r_main.h index 379b5b8df1f5d306e50b2eed802c058749cb3928..f1cc9621f00f320ffdbb363b08b783af89fda75b 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -114,10 +114,6 @@ extern consvar_t cv_tailspickup; // Called by startup code. void R_Init(void); -#ifdef HWRENDER -void R_InitHardwareMode(void); -#endif -void R_ReloadHUDGraphics(void); void R_CheckViewMorph(void); void R_ApplyViewMorph(void); diff --git a/src/r_patch.c b/src/r_patch.c new file mode 100644 index 0000000000000000000000000000000000000000..c78ffdd67adcf9f8c59864ce36a0b58dda61d5f9 --- /dev/null +++ b/src/r_patch.c @@ -0,0 +1,160 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// 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.c +/// \brief Patch generation. + +#include "doomdef.h" +#include "r_patch.h" +#include "r_picformats.h" +#include "r_defs.h" +#include "z_zone.h" + +#ifdef HWRENDER +#include "hardware/hw_glob.h" +#endif + +// +// Creates a patch. +// Assumes a PU_PATCH zone memory tag and no user, but can always be set later +// + +patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest) +{ + patch_t *patch = (dest == NULL) ? Z_Calloc(sizeof(patch_t), PU_PATCH, NULL) : (patch_t *)(dest); + + if (source) + { + INT32 col, colsize; + size_t size = sizeof(INT32) * source->width; + size_t offs = (sizeof(INT16) * 4) + size; + + patch->width = source->width; + patch->height = source->height; + patch->leftoffset = source->leftoffset; + patch->topoffset = source->topoffset; + patch->columnofs = Z_Calloc(size, PU_PATCH_DATA, NULL); + + for (col = 0; col < source->width; col++) + { + // This makes the column offsets relative to the column data itself, + // instead of the entire patch data + patch->columnofs[col] = LONG(source->columnofs[col]) - offs; + } + + if (!srcsize) + I_Error("Patch_Create: no source size!"); + + colsize = (INT32)(srcsize) - (INT32)offs; + if (colsize <= 0) + I_Error("Patch_Create: no column data!"); + + patch->columns = Z_Calloc(colsize, PU_PATCH_DATA, NULL); + M_Memcpy(patch->columns, ((UINT8 *)source + LONG(source->columnofs[0])), colsize); + } + + return patch; +} + +// +// Frees a patch from memory. +// + +static void Patch_FreeData(patch_t *patch) +{ + INT32 i; + +#ifdef HWRENDER + if (patch->hardware) + HWR_FreeTexture(patch); +#endif + + for (i = 0; i < 2; i++) + { + if (patch->flats[i]) + Z_Free(patch->flats[i]); + } + +#ifdef ROTSPRITE + if (patch->rotated) + { + rotsprite_t *rotsprite = patch->rotated; + + for (i = 0; i < rotsprite->angles; i++) + { + if (rotsprite->patches[i]) + Patch_Free(rotsprite->patches[i]); + } + + Z_Free(rotsprite->patches); + Z_Free(rotsprite); + } +#endif + + if (patch->columnofs) + Z_Free(patch->columnofs); + if (patch->columns) + Z_Free(patch->columns); +} + +void Patch_Free(patch_t *patch) +{ + Patch_FreeData(patch); + Z_Free(patch); +} + +// +// Frees patches with a tag range. +// + +static boolean Patch_FreeTagsCallback(void *mem) +{ + patch_t *patch = (patch_t *)mem; + Patch_FreeData(patch); + return true; +} + +void Patch_FreeTags(INT32 lowtag, INT32 hightag) +{ + Z_IterateTags(lowtag, hightag, Patch_FreeTagsCallback); +} + +void Patch_GenerateFlat(patch_t *patch, pictureflags_t flags) +{ + UINT8 flip = (flags & (PICFLAGS_XFLIP | PICFLAGS_YFLIP)); + if (patch->flats[flip] == NULL) + patch->flats[flip] = Picture_Convert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, NULL, 0, 0, 0, 0, flags); +} + +#ifdef HWRENDER +// +// Allocates a hardware patch. +// + +void *Patch_AllocateHardwarePatch(patch_t *patch) +{ + if (!patch->hardware) + { + GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, &patch->hardware); + grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, &grPatch->mipmap); + } + return (void *)(patch->hardware); +} + +// +// Creates a hardware patch. +// + +void *Patch_CreateGL(patch_t *patch) +{ + GLPatch_t *grPatch = (GLPatch_t *)Patch_AllocateHardwarePatch(patch); + if (!grPatch->mipmap->data) // Run HWR_MakePatch in all cases, to recalculate some things + HWR_MakePatch(patch, grPatch, grPatch->mipmap, false); + return grPatch; +} +#endif // HWRENDER diff --git a/src/r_patch.h b/src/r_patch.h new file mode 100644 index 0000000000000000000000000000000000000000..32bcb3909efe057af98d54cd151f56414c71deb1 --- /dev/null +++ b/src/r_patch.h @@ -0,0 +1,44 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// 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 "r_picformats.h" +#include "doomdef.h" + +// Patch functions +patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest); +void Patch_Free(patch_t *patch); + +#define Patch_FreeTag(tagnum) Patch_FreeTags(tagnum, tagnum) +void Patch_FreeTags(INT32 lowtag, INT32 hightag); + +void Patch_GenerateFlat(patch_t *patch, pictureflags_t flags); + +#ifdef HWRENDER +void *Patch_AllocateHardwarePatch(patch_t *patch); +void *Patch_CreateGL(patch_t *patch); +#endif + +#ifdef ROTSPRITE +void Patch_Rotate(patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip); +patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip); +patch_t *Patch_GetRotatedSprite( + spriteframe_t *sprite, + size_t frame, size_t spriteangle, + boolean flip, boolean adjustfeet, + void *info, INT32 rotationangle); +INT32 R_GetRollAngle(angle_t rollangle); +#endif + +#endif // __R_PATCH__ diff --git a/src/r_patchrotation.c b/src/r_patchrotation.c new file mode 100644 index 0000000000000000000000000000000000000000..123c4eef229a20fa554094bf44a2cc3853e72dc8 --- /dev/null +++ b/src/r_patchrotation.c @@ -0,0 +1,273 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// 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_patchrotation.c +/// \brief Patch rotation. + +#include "r_patchrotation.h" +#include "r_things.h" // FEETADJUST +#include "z_zone.h" +#include "w_wad.h" + +#ifdef ROTSPRITE +fixed_t rollcosang[ROTANGLES]; +fixed_t rollsinang[ROTANGLES]; + +INT32 R_GetRollAngle(angle_t rollangle) +{ + INT32 ra = AngleFixed(rollangle)>>FRACBITS; +#if (ROTANGDIFF > 1) + ra += (ROTANGDIFF/2); +#endif + ra /= ROTANGDIFF; + ra %= ROTANGLES; + return ra; +} + +patch_t *Patch_GetRotated(patch_t *patch, INT32 angle, boolean flip) +{ + rotsprite_t *rotsprite = patch->rotated; + if (rotsprite == NULL || angle < 1 || angle >= ROTANGLES) + return NULL; + + if (flip) + angle += rotsprite->angles; + + return rotsprite->patches[angle]; +} + +patch_t *Patch_GetRotatedSprite( + spriteframe_t *sprite, + size_t frame, size_t spriteangle, + boolean flip, boolean adjustfeet, + void *info, INT32 rotationangle) +{ + rotsprite_t *rotsprite; + spriteinfo_t *sprinfo = (spriteinfo_t *)info; + INT32 idx = rotationangle; + UINT8 type = (adjustfeet ? 1 : 0); + + if (rotationangle < 1 || rotationangle >= ROTANGLES) + return NULL; + + rotsprite = sprite->rotated[type][spriteangle]; + + if (rotsprite == NULL) + { + rotsprite = RotatedPatch_Create(ROTANGLES); + sprite->rotated[type][spriteangle] = rotsprite; + } + + if (flip) + idx += rotsprite->angles; + + if (rotsprite->patches[idx] == NULL) + { + patch_t *patch; + INT32 xpivot = 0, ypivot = 0; + lumpnum_t lump = sprite->lumppat[spriteangle]; + + if (lump == LUMPERROR) + return NULL; + + patch = W_CachePatchNum(lump, PU_SPRITE); + + if (sprinfo->available) + { + xpivot = sprinfo->pivot[frame].x; + ypivot = sprinfo->pivot[frame].y; + } + else + { + xpivot = patch->leftoffset; + ypivot = patch->height / 2; + } + + RotatedPatch_DoRotation(rotsprite, patch, rotationangle, xpivot, ypivot, flip); + + //BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer + if (adjustfeet) + ((patch_t *)rotsprite->patches[idx])->topoffset += FEETADJUST>>FRACBITS; + } + + return rotsprite->patches[idx]; +} + +void Patch_Rotate(patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip) +{ + if (patch->rotated == NULL) + patch->rotated = RotatedPatch_Create(ROTANGLES); + RotatedPatch_DoRotation(patch->rotated, patch, angle, xpivot, ypivot, flip); +} + +rotsprite_t *RotatedPatch_Create(INT32 numangles) +{ + rotsprite_t *rotsprite = Z_Calloc(sizeof(rotsprite_t), PU_STATIC, NULL); + rotsprite->angles = numangles; + rotsprite->patches = Z_Calloc(rotsprite->angles * 2 * sizeof(void *), PU_STATIC, NULL); + return rotsprite; +} + +static void RotatedPatch_CalculateDimensions( + INT32 width, INT32 height, + fixed_t ca, fixed_t sa, + INT32 *newwidth, INT32 *newheight) +{ + fixed_t fixedwidth = (width * FRACUNIT); + fixed_t fixedheight = (height * FRACUNIT); + + fixed_t w1 = abs(FixedMul(fixedwidth, ca) - FixedMul(fixedheight, sa)); + fixed_t w2 = abs(FixedMul(-fixedwidth, ca) - FixedMul(fixedheight, sa)); + fixed_t h1 = abs(FixedMul(fixedwidth, sa) + FixedMul(fixedheight, ca)); + fixed_t h2 = abs(FixedMul(-fixedwidth, sa) + FixedMul(fixedheight, ca)); + + w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2))); + w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2))); + h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2))); + h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2))); + + *newwidth = max(width, max(w1, w2)); + *newheight = max(height, max(h1, h2)); +} + +void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip) +{ + patch_t *rotated; + UINT16 *rawdst, *rawconv; + size_t size; + pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0; + + INT32 width = patch->width; + INT32 height = patch->height; + INT32 leftoffset = patch->leftoffset; + INT32 newwidth, newheight; + + fixed_t ca = rollcosang[angle]; + fixed_t sa = rollsinang[angle]; + fixed_t xcenter, ycenter; + INT32 idx = angle; + INT32 x, y; + INT32 sx, sy; + INT32 dx, dy; + INT32 ox, oy; + INT32 minx, miny, maxx, maxy; + + // Don't cache angle = 0 + if (angle < 1 || angle >= ROTANGLES) + return; + + if (flip) + { + idx += rotsprite->angles; + xpivot = width - xpivot; + leftoffset = width - leftoffset; + } + + if (rotsprite->patches[idx]) + return; + + // Find the dimensions of the rotated patch. + RotatedPatch_CalculateDimensions(width, height, ca, sa, &newwidth, &newheight); + + xcenter = (xpivot * FRACUNIT); + ycenter = (ypivot * FRACUNIT); + + if (xpivot != width / 2 || ypivot != height / 2) + { + newwidth *= 2; + newheight *= 2; + } + + minx = newwidth; + miny = newheight; + maxx = 0; + maxy = 0; + + // Draw the rotated sprite to a temporary buffer. + size = (newwidth * newheight); + if (!size) + size = (width * height); + rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); + + for (dy = 0; dy < newheight; dy++) + { + for (dx = 0; dx < newwidth; dx++) + { + x = (dx - (newwidth / 2)) * FRACUNIT; + y = (dy - (newheight / 2)) * FRACUNIT; + sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter; + sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter; + + sx >>= FRACBITS; + sy >>= FRACBITS; + + if (sx >= 0 && sy >= 0 && sx < width && sy < height) + { + void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); + if (input != NULL) + { + rawdst[(dy * newwidth) + dx] = (0xFF00 | (*(UINT8 *)input)); + if (dx < minx) + minx = dx; + if (dy < miny) + miny = dy; + if (dx > maxx) + maxx = dx; + if (dy > maxy) + maxy = dy; + } + } + } + } + + ox = (newwidth / 2) + (leftoffset - xpivot); + oy = (newheight / 2) + (patch->topoffset - ypivot); + width = (maxx - minx); + height = (maxy - miny); + + if ((unsigned)(width * height) != size) + { + UINT16 *src, *dest; + + size = (width * height); + rawconv = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); + + src = &rawdst[(miny * newwidth) + minx]; + dest = rawconv; + dy = height; + + while (dy--) + { + M_Memcpy(dest, src, width * sizeof(UINT16)); + dest += width; + src += newwidth; + } + + ox -= minx; + oy -= miny; + + Z_Free(rawdst); + } + else + { + rawconv = rawdst; + width = newwidth; + height = newheight; + } + + // make patch + rotated = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawconv, PICFMT_PATCH, 0, NULL, width, height, 0, 0, 0); + + Z_ChangeTag(rotated, PU_PATCH_ROTATED); + Z_SetUser(rotated, (void **)(&rotsprite->patches[idx])); + Z_Free(rawconv); + + rotated->leftoffset = ox; + rotated->topoffset = oy; +} +#endif diff --git a/src/r_patchrotation.h b/src/r_patchrotation.h new file mode 100644 index 0000000000000000000000000000000000000000..2744f71d25380469b30b1fdcf8b5112578a2abd8 --- /dev/null +++ b/src/r_patchrotation.h @@ -0,0 +1,21 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by Jaime "Lactozilla" Passos. +// +// 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_patchrotation.h +/// \brief Patch rotation. + +#include "r_patch.h" +#include "r_picformats.h" + +#ifdef ROTSPRITE +rotsprite_t *RotatedPatch_Create(INT32 numangles); +void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip); + +extern fixed_t rollcosang[ROTANGLES]; +extern fixed_t rollsinang[ROTANGLES]; +#endif diff --git a/src/r_picformats.c b/src/r_picformats.c index 95fe23aeb11e6e355ed84644e3b9aa1b421b2f7c..02f1de4ab20d1f0edaeb8753459eacc8c452de23 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -16,10 +16,11 @@ #include "dehacked.h" #include "i_video.h" #include "r_data.h" -#include "r_textures.h" -#include "r_draw.h" +#include "r_patch.h" #include "r_picformats.h" +#include "r_textures.h" #include "r_things.h" +#include "r_draw.h" #include "v_video.h" #include "z_zone.h" #include "w_wad.h" @@ -142,10 +143,21 @@ void *Picture_PatchConvert( if (Picture_IsPatchFormat(informat)) { inpatch = (patch_t *)picture; - inwidth = SHORT(inpatch->width); - inheight = SHORT(inpatch->height); - inleftoffset = SHORT(inpatch->leftoffset); - intopoffset = SHORT(inpatch->topoffset); + if (Picture_IsDoomPatchFormat(informat)) + { + softwarepatch_t *doompatch = (softwarepatch_t *)picture; + inwidth = SHORT(doompatch->width); + inheight = SHORT(doompatch->height); + inleftoffset = SHORT(doompatch->leftoffset); + intopoffset = SHORT(doompatch->topoffset); + } + else + { + inwidth = inpatch->width; + inheight = inpatch->height; + inleftoffset = inpatch->leftoffset; + intopoffset = inpatch->topoffset; + } } // Write image size and offset @@ -275,6 +287,7 @@ void *Picture_PatchConvert( switch (outformat) { case PICFMT_PATCH32: + case PICFMT_DOOMPATCH32: { if (inbpp == PICDEPTH_32BPP) { @@ -294,6 +307,7 @@ void *Picture_PatchConvert( break; } case PICFMT_PATCH16: + case PICFMT_DOOMPATCH16: if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; @@ -338,9 +352,26 @@ void *Picture_PatchConvert( img = Z_Malloc(size, PU_STATIC, NULL); memcpy(img, imgbuf, size); - if (outsize != NULL) - *outsize = size; - return img; + if (Picture_IsInternalPatchFormat(outformat)) + { + patch_t *converted = Patch_Create((softwarepatch_t *)img, size, NULL); + +#ifdef HWRENDER + Patch_CreateGL(converted); +#endif + + Z_Free(img); + + if (outsize != NULL) + *outsize = sizeof(patch_t); + return converted; + } + else + { + if (outsize != NULL) + *outsize = size; + return img; + } } /** Converts a picture to a flat. @@ -391,8 +422,17 @@ void *Picture_FlatConvert( if (Picture_IsPatchFormat(informat)) { inpatch = (patch_t *)picture; - inwidth = SHORT(inpatch->width); - inheight = SHORT(inpatch->height); + if (Picture_IsDoomPatchFormat(informat)) + { + softwarepatch_t *doompatch = ((softwarepatch_t *)picture); + inwidth = SHORT(doompatch->width); + inheight = SHORT(doompatch->height); + } + else + { + inwidth = inpatch->width; + inheight = inpatch->height; + } } size = (inwidth * inheight) * (outbpp / 8); @@ -503,22 +543,25 @@ void *Picture_GetPatchPixel( UINT8 *s8 = NULL; UINT16 *s16 = NULL; UINT32 *s32 = NULL; + softwarepatch_t *doompatch = (softwarepatch_t *)patch; + INT16 width; if (patch == NULL) I_Error("Picture_GetPatchPixel: patch == NULL"); - if (x >= 0 && x < SHORT(patch->width)) + width = (Picture_IsDoomPatchFormat(informat) ? patch->width : SHORT(patch->width)); + + if (x >= 0 && x < width) { + INT32 colx = (flags & PICFLAGS_XFLIP) ? (width-1)-x : x; INT32 topdelta, prevdelta = -1; - INT32 colofs = 0; - - if (flags & PICFLAGS_XFLIP) - colofs = LONG(patch->columnofs[(SHORT(patch->width)-1)-x]); - else - colofs = LONG(patch->columnofs[x]); + INT32 colofs = (Picture_IsDoomPatchFormat(informat) ? LONG(patch->columnofs[colx]) : patch->columnofs[colx]); // Column offsets are pointers so no casting required - column = (column_t *)((UINT8 *)patch + colofs); + if (Picture_IsDoomPatchFormat(informat)) + column = (column_t *)((UINT8 *)doompatch + colofs); + else + column = (column_t *)((UINT8 *)patch->columns + colofs); while (column->topdelta != 0xff) { @@ -527,25 +570,25 @@ void *Picture_GetPatchPixel( topdelta += prevdelta; prevdelta = topdelta; s8 = (UINT8 *)(column) + 3; - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) s32 = (UINT32 *)s8; - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) s16 = (UINT16 *)s8; for (ofs = 0; ofs < column->length; ofs++) { if ((topdelta + ofs) == y) { - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) return &s32[ofs]; - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) return &s16[ofs]; - else // PICFMT_PATCH + else // PICDEPTH_8BPP return &s8[ofs]; } } - if (informat == PICFMT_PATCH32) + if (Picture_FormatBPP(informat) == PICDEPTH_32BPP) column = (column_t *)((UINT32 *)column + column->length); - else if (informat == PICFMT_PATCH16) + else if (Picture_FormatBPP(informat) == PICDEPTH_16BPP) column = (column_t *)((UINT16 *)column + column->length); else column = (column_t *)((UINT8 *)column + column->length); @@ -568,15 +611,18 @@ INT32 Picture_FormatBPP(pictureformat_t format) { case PICFMT_PATCH32: case PICFMT_FLAT32: + case PICFMT_DOOMPATCH32: case PICFMT_PNG: bpp = PICDEPTH_32BPP; break; case PICFMT_PATCH16: case PICFMT_FLAT16: + case PICFMT_DOOMPATCH16: bpp = PICDEPTH_16BPP; break; case PICFMT_PATCH: case PICFMT_FLAT: + case PICFMT_DOOMPATCH: bpp = PICDEPTH_8BPP; break; default: @@ -592,7 +638,43 @@ INT32 Picture_FormatBPP(pictureformat_t format) */ boolean Picture_IsPatchFormat(pictureformat_t format) { - return (format == PICFMT_PATCH || format == PICFMT_PATCH16 || format == PICFMT_PATCH32); + return (Picture_IsInternalPatchFormat(format) || Picture_IsDoomPatchFormat(format)); +} + +/** Checks if the specified picture format is an internal patch. + * + * \param format Input picture format. + * \return True if the picture format is an internal patch, false if not. + */ +boolean Picture_IsInternalPatchFormat(pictureformat_t format) +{ + switch (format) + { + case PICFMT_PATCH: + case PICFMT_PATCH16: + case PICFMT_PATCH32: + return true; + default: + return false; + } +} + +/** Checks if the specified picture format is a Doom patch. + * + * \param format Input picture format. + * \return True if the picture format is a Doom patch, false if not. + */ +boolean Picture_IsDoomPatchFormat(pictureformat_t format) +{ + switch (format) + { + case PICFMT_DOOMPATCH: + case PICFMT_DOOMPATCH16: + case PICFMT_DOOMPATCH32: + return true; + default: + return false; + } } /** Checks if the specified picture format is a flat. @@ -605,14 +687,14 @@ boolean Picture_IsFlatFormat(pictureformat_t format) return (format == PICFMT_FLAT || format == PICFMT_FLAT16 || format == PICFMT_FLAT32); } -/** Returns true if the lump is a valid patch. - * PICFMT_PATCH only, I think?? +/** Returns true if the lump is a valid Doom patch. + * PICFMT_DOOMPATCH only. * * \param patch Input patch. * \param picture Input patch size. * \return True if the input patch is valid. */ -boolean Picture_CheckIfPatch(patch_t *patch, size_t size) +boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size) { INT16 width, height; boolean result; @@ -887,26 +969,45 @@ static png_bytep *PNG_Read( // matches the color count of SRB2's palette: 256 colors. if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size)) { - if (palette_size == 256) + if (palette_size == 256 && pMasterPalette) + { + png_colorp pal = palette; + INT32 i; + usepal = true; + + for (i = 0; i < 256; i++) + { + UINT32 rgb = R_PutRgbaRGBA(pal->red, pal->green, pal->blue, 0xFF); + if (rgb != pMasterPalette[i].rgba) + { + usepal = false; + break; + } + pal++; + } + } } // If any of the tRNS colors have an alpha lower than 0xFF, and that // color is present on the image, the palette flag is disabled. - png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); - - if (trans && trans_num == 256) + if (usepal) { - int i; - for (i = 0; i < trans_num; i++) + png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); + + if (trans && trans_num == 256) { - // libpng will transform this image into RGB even if - // the transparent index does not exist in the image, - // and there is no way around that. - if (trans[i] < 0xFF) + INT32 i; + for (i = 0; i < trans_num; i++) { - usepal = false; - break; + // libpng will transform this image into RGB even if + // the transparent index does not exist in the image, + // and there is no way around that. + if (trans[i] < 0xFF) + { + usepal = false; + break; + } } } } @@ -1446,11 +1547,6 @@ static void R_ParseSpriteInfo(boolean spr2) info = Z_Calloc(sizeof(spriteinfo_t), PU_STATIC, NULL); info->available = true; -#ifdef ROTSPRITE - if ((sprites != NULL) && (!spr2)) - R_FreeSingleRotSprite(&sprites[sprnum]); -#endif - // Left Curly Brace sprinfoToken = M_GetToken(NULL); if (sprinfoToken == NULL) @@ -1511,9 +1607,6 @@ static void R_ParseSpriteInfo(boolean spr2) size_t skinnum = skinnumbers[i]; skin_t *skin = &skins[skinnum]; spriteinfo_t *sprinfo = skin->sprinfo; -#ifdef ROTSPRITE - R_FreeSkinRotSprite(skinnum); -#endif M_Memcpy(&sprinfo[spr2num], info, sizeof(spriteinfo_t)); } } @@ -1603,316 +1696,3 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps) R_ParseSPRTINFOLump(wadnum, i); } } - -#ifdef ROTSPRITE -// -// R_GetRollAngle -// -// Angles precalculated in R_InitSprites. -// -fixed_t rollcosang[ROTANGLES]; -fixed_t rollsinang[ROTANGLES]; -INT32 R_GetRollAngle(angle_t rollangle) -{ - INT32 ra = AngleFixed(rollangle)>>FRACBITS; -#if (ROTANGDIFF > 1) - ra += (ROTANGDIFF/2); -#endif - ra /= ROTANGDIFF; - ra %= ROTANGLES; - return ra; -} - -// -// R_CacheRotSprite -// -// Create a rotated sprite. -// -void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip) -{ - INT32 angle; - patch_t *patch; - patch_t *newpatch; - UINT16 *rawdst; - size_t size; - pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0; - -#define SPRITE_XCENTER (leftoffset) -#define SPRITE_YCENTER (height / 2) -#define ROTSPRITE_XCENTER (newwidth / 2) -#define ROTSPRITE_YCENTER (newheight / 2) - - if (!(sprframe->rotsprite.cached & (1<<rot))) - { - INT32 dx, dy; - INT32 px, py; - INT32 width, height, leftoffset; - fixed_t ca, sa; - lumpnum_t lump = sprframe->lumppat[rot]; -#ifndef NO_PNG_LUMPS - size_t lumplength; -#endif - - if (lump == LUMPERROR) - return; - - patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); -#ifndef NO_PNG_LUMPS - lumplength = W_LumpLength(lump); - - if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength)) - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); - else -#endif - // Because there's something wrong with SPR_DFLM, I guess - if (!Picture_CheckIfPatch(patch, lumplength)) - return; - - width = SHORT(patch->width); - height = SHORT(patch->height); - leftoffset = SHORT(patch->leftoffset); - - // rotation pivot - px = SPRITE_XCENTER; - py = SPRITE_YCENTER; - - // get correct sprite info for sprite - if (sprinfo == NULL) - sprinfo = &spriteinfo[sprnum]; - if (sprinfo->available) - { - px = sprinfo->pivot[frame].x; - py = sprinfo->pivot[frame].y; - } - if (bflip) - { - px = width - px; - leftoffset = width - leftoffset; - } - - // Don't cache angle = 0 - for (angle = 1; angle < ROTANGLES; angle++) - { - INT32 newwidth, newheight; - - ca = rollcosang[angle]; - sa = rollsinang[angle]; - - // Find the dimensions of the rotated patch. - { - INT32 w1 = abs(FixedMul(width << FRACBITS, ca) - FixedMul(height << FRACBITS, sa)); - INT32 w2 = abs(FixedMul(-(width << FRACBITS), ca) - FixedMul(height << FRACBITS, sa)); - INT32 h1 = abs(FixedMul(width << FRACBITS, sa) + FixedMul(height << FRACBITS, ca)); - INT32 h2 = abs(FixedMul(-(width << FRACBITS), sa) + FixedMul(height << FRACBITS, ca)); - w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2))); - w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2))); - h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2))); - h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2))); - newwidth = max(width, max(w1, w2)); - newheight = max(height, max(h1, h2)); - } - - // check boundaries - { - fixed_t top[2][2]; - fixed_t bottom[2][2]; - - top[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - top[0][1] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - top[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - top[1][1] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - - bottom[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - bottom[0][1] = -FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - bottom[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (px << FRACBITS); - bottom[1][1] = -FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (py << FRACBITS); - - top[0][0] >>= FRACBITS; - top[0][1] >>= FRACBITS; - top[1][0] >>= FRACBITS; - top[1][1] >>= FRACBITS; - - bottom[0][0] >>= FRACBITS; - bottom[0][1] >>= FRACBITS; - bottom[1][0] >>= FRACBITS; - bottom[1][1] >>= FRACBITS; - -#define BOUNDARYWCHECK(b) (b[0] < 0 || b[0] >= width) -#define BOUNDARYHCHECK(b) (b[1] < 0 || b[1] >= height) -#define BOUNDARYADJUST(x) x *= 2 - // top left/right - if (BOUNDARYWCHECK(top[0]) || BOUNDARYWCHECK(top[1])) - BOUNDARYADJUST(newwidth); - // bottom left/right - else if (BOUNDARYWCHECK(bottom[0]) || BOUNDARYWCHECK(bottom[1])) - BOUNDARYADJUST(newwidth); - // top left/right - if (BOUNDARYHCHECK(top[0]) || BOUNDARYHCHECK(top[1])) - BOUNDARYADJUST(newheight); - // bottom left/right - else if (BOUNDARYHCHECK(bottom[0]) || BOUNDARYHCHECK(bottom[1])) - BOUNDARYADJUST(newheight); -#undef BOUNDARYWCHECK -#undef BOUNDARYHCHECK -#undef BOUNDARYADJUST - } - - // Draw the rotated sprite to a temporary buffer. - size = (newwidth * newheight); - if (!size) - size = (width * height); - rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); - - for (dy = 0; dy < newheight; dy++) - { - for (dx = 0; dx < newwidth; dx++) - { - INT32 x = (dx-ROTSPRITE_XCENTER) << FRACBITS; - INT32 y = (dy-ROTSPRITE_YCENTER) << FRACBITS; - INT32 sx = FixedMul(x, ca) + FixedMul(y, sa) + (px << FRACBITS); - INT32 sy = -FixedMul(x, sa) + FixedMul(y, ca) + (py << FRACBITS); - sx >>= FRACBITS; - sy >>= FRACBITS; - if (sx >= 0 && sy >= 0 && sx < width && sy < height) - { - void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); - if (input != NULL) - rawdst[(dy*newwidth)+dx] = (0xFF00 | (*(UINT8 *)input)); - } - } - } - - // make patch - newpatch = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawdst, PICFMT_PATCH, 0, &size, newwidth, newheight, 0, 0, 0); - { - newpatch->leftoffset = (newpatch->width / 2) + (leftoffset - px); - newpatch->topoffset = (newpatch->height / 2) + (SHORT(patch->topoffset) - py); - } - - //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 += FEETADJUST>>FRACBITS; - - // P_PrecacheLevel - if (devparm) spritememory += size; - - // convert everything to little-endian, for big-endian support - newpatch->width = SHORT(newpatch->width); - newpatch->height = SHORT(newpatch->height); - newpatch->leftoffset = SHORT(newpatch->leftoffset); - newpatch->topoffset = SHORT(newpatch->topoffset); - -#ifdef HWRENDER - if (rendermode == render_opengl) - { - GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - grPatch->rawpatch = newpatch; - sprframe->rotsprite.patch[rot][angle] = (patch_t *)grPatch; - HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false); - } - else -#endif // HWRENDER - sprframe->rotsprite.patch[rot][angle] = newpatch; - - // free rotated image data - Z_Free(rawdst); - } - - // This rotation is cached now - sprframe->rotsprite.cached |= (1<<rot); - - // free image data - Z_Free(patch); - } -#undef SPRITE_XCENTER -#undef SPRITE_YCENTER -#undef ROTSPRITE_XCENTER -#undef ROTSPRITE_YCENTER -} - -// -// R_FreeSingleRotSprite -// -// Free sprite rotation data from memory, for a single spritedef. -// -void R_FreeSingleRotSprite(spritedef_t *spritedef) -{ - UINT8 frame; - INT32 rot, ang; - - for (frame = 0; frame < spritedef->numframes; frame++) - { - spriteframe_t *sprframe = &spritedef->spriteframes[frame]; - for (rot = 0; rot < 16; rot++) - { - if (sprframe->rotsprite.cached & (1<<rot)) - { - for (ang = 0; ang < ROTANGLES; ang++) - { - patch_t *rotsprite = sprframe->rotsprite.patch[rot][ang]; - if (rotsprite) - { -#ifdef HWRENDER - if (rendermode == render_opengl) - { - GLPatch_t *grPatch = (GLPatch_t *)rotsprite; - if (grPatch->rawpatch) - { - Z_Free(grPatch->rawpatch); - grPatch->rawpatch = NULL; - } - if (grPatch->mipmap) - { - if (grPatch->mipmap->data) - { - Z_Free(grPatch->mipmap->data); - grPatch->mipmap->data = NULL; - } - Z_Free(grPatch->mipmap); - grPatch->mipmap = NULL; - } - } -#endif - Z_Free(rotsprite); - } - } - sprframe->rotsprite.cached &= ~(1<<rot); - } - } - } -} - -// -// R_FreeSkinRotSprite -// -// Free sprite rotation data from memory, for a skin. -// Calls R_FreeSingleRotSprite. -// -void R_FreeSkinRotSprite(size_t skinnum) -{ - size_t i; - skin_t *skin = &skins[skinnum]; - spritedef_t *skinsprites = skin->sprites; - for (i = 0; i < NUMPLAYERSPRITES*2; i++) - { - R_FreeSingleRotSprite(skinsprites); - skinsprites++; - } -} - -// -// R_FreeAllRotSprite -// -// Free ALL sprite rotation data from memory. -// -void R_FreeAllRotSprite(void) -{ - INT32 i; - size_t s; - for (s = 0; s < numsprites; s++) - R_FreeSingleRotSprite(&sprites[s]); - for (i = 0; i < numskins; ++i) - R_FreeSkinRotSprite(i); -} -#endif diff --git a/src/r_picformats.h b/src/r_picformats.h index 3ee76a92f1bf2c521ef92372429543e7de10cba8..8d3999013475f23b9428e0e252148d91c88c8ea2 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -24,6 +24,7 @@ typedef enum // Doom formats PICFMT_PATCH, PICFMT_FLAT, + PICFMT_DOOMPATCH, // PNG PICFMT_PNG, @@ -31,10 +32,12 @@ typedef enum // 16bpp PICFMT_PATCH16, PICFMT_FLAT16, + PICFMT_DOOMPATCH16, // 32bpp PICFMT_PATCH32, - PICFMT_FLAT32 + PICFMT_FLAT32, + PICFMT_DOOMPATCH32 } pictureformat_t; typedef enum @@ -76,8 +79,10 @@ void *Picture_TextureToFlat(size_t trickytex); INT32 Picture_FormatBPP(pictureformat_t format); boolean Picture_IsPatchFormat(pictureformat_t format); +boolean Picture_IsInternalPatchFormat(pictureformat_t format); +boolean Picture_IsDoomPatchFormat(pictureformat_t format); boolean Picture_IsFlatFormat(pictureformat_t format); -boolean Picture_CheckIfPatch(patch_t *patch, size_t size); +boolean Picture_CheckIfDoomPatch(softwarepatch_t *patch, size_t size); // Structs typedef enum @@ -120,15 +125,4 @@ extern spriteinfo_t spriteinfo[NUMSPRITES]; void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps); void R_ParseSPRTINFOLump(UINT16 wadNum, UINT16 lumpNum); -// Sprite rotation -#ifdef ROTSPRITE -INT32 R_GetRollAngle(angle_t rollangle); -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 rollcosang[ROTANGLES]; -extern fixed_t rollsinang[ROTANGLES]; -void R_FreeAllRotSprite(void); -#endif - -#endif // __R_PATCH__ +#endif // __R_PICFORMATS__ diff --git a/src/r_plane.c b/src/r_plane.c index 9d36c07dc2db74838e853eed12b8381a606fff40..f4fd9c39764ef1542a3c61168717261cd2a67825 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -115,33 +115,40 @@ void R_InitPlanes(void) } // -// Water ripple effect!! +// Water ripple effect // Needs the height of the plane, and the vertical position of the span. -// Sets ripple_xfrac and ripple_yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. +// Sets planeripple.xfrac and planeripple.yfrac, added to ds_xfrac and ds_yfrac, if the span is not tilted. // -#ifndef NOWATER -INT32 ds_bgofs; -INT32 ds_waterofs; - -static INT32 wtofs=0; -static boolean itswater; -static fixed_t ripple_xfrac; -static fixed_t ripple_yfrac; +struct +{ + INT32 offset; + fixed_t xfrac, yfrac; + boolean active; +} planeripple; -static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight) +static void R_CalculatePlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight, boolean calcfrac) { fixed_t distance = FixedMul(plheight, yslope[y]); - const INT32 yay = (wtofs + (distance>>9) ) & 8191; + const INT32 yay = (planeripple.offset + (distance>>9)) & 8191; + // ripples da water texture - angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; ds_bgofs = FixedDiv(FINESINE(yay), (1<<12) + (distance>>11))>>FRACBITS; - angle = (angle + 2048) & 8191; // 90 degrees - ripple_xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS)); - ripple_yfrac = FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS)); + if (calcfrac) + { + angle_t angle = (plane->viewangle + plane->plangle)>>ANGLETOFINESHIFT; + angle = (angle + 2048) & 8191; // 90 degrees + planeripple.xfrac = FixedMul(FINECOSINE(angle), (ds_bgofs<<FRACBITS)); + planeripple.yfrac = FixedMul(FINESINE(angle), (ds_bgofs<<FRACBITS)); + } +} + +static void R_UpdatePlaneRipple(void) +{ + ds_waterofs = (leveltime & 1)*16384; + planeripple.offset = (leveltime * 140); } -#endif // // R_MapPlane @@ -159,7 +166,7 @@ static void R_PlaneRipple(visplane_t *plane, INT32 y, fixed_t plheight) void R_MapPlane(INT32 y, INT32 x1, INT32 x2) { angle_t angle, planecos, planesin; - fixed_t distance, span; + fixed_t distance = 0, span; size_t pindex; #ifdef RANGECHECK @@ -167,41 +174,51 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) I_Error("R_MapPlane: %d, %d at %d", x1, x2, y); #endif - // from r_splats's R_RenderFloorSplat - if (x1 >= vid.width) x1 = vid.width - 1; + if (x1 >= vid.width) + x1 = vid.width - 1; - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); - - if (planeheight != cachedheight[y]) + if (!currentplane->slope) { - cachedheight[y] = planeheight; - distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); - ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale); - ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale); + angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; + planecos = FINECOSINE(angle); + planesin = FINESINE(angle); - if ((span = abs(centery-y))) + if (planeheight != cachedheight[y]) { - ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; - ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; + cachedheight[y] = planeheight; + cacheddistance[y] = distance = FixedMul(planeheight, yslope[y]); + span = abs(centery - y); + + if (span) // don't divide by zero + { + ds_xstep = FixedMul(planesin, planeheight) / span; + ds_ystep = FixedMul(planecos, planeheight) / span; + } + else + { + ds_xstep = FixedMul(distance, basexscale); + ds_ystep = FixedMul(distance, baseyscale); + } + + cachedxstep[y] = ds_xstep; + cachedystep[y] = ds_ystep; + } + else + { + distance = cacheddistance[y]; + ds_xstep = cachedxstep[y]; + ds_ystep = cachedystep[y]; } - } - else - { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; - } - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; + ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; + ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; + } -#ifndef NOWATER - if (itswater) + // Water ripple effect + if (planeripple.active) { // Needed for ds_bgofs - R_PlaneRipple(currentplane, y, planeheight); + R_CalculatePlaneRipple(currentplane, y, planeheight, (!currentplane->slope)); if (currentplane->slope) { @@ -211,25 +228,25 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2) } else { - ds_xfrac += ripple_xfrac; - ds_yfrac += ripple_yfrac; + ds_xfrac += planeripple.xfrac; + ds_yfrac += planeripple.yfrac; } - if (y+ds_bgofs>=viewheight) + if ((y + ds_bgofs) >= viewheight) ds_bgofs = viewheight-y-1; - if (y+ds_bgofs<0) + if ((y + ds_bgofs) < 0) ds_bgofs = -y; } -#endif - - pindex = distance >> LIGHTZSHIFT; - if (pindex >= MAXLIGHTZ) - pindex = MAXLIGHTZ - 1; if (currentplane->slope) ds_colormap = colormaps; else + { + pindex = distance >> LIGHTZSHIFT; + if (pindex >= MAXLIGHTZ) + pindex = MAXLIGHTZ - 1; ds_colormap = planezlight[pindex]; + } if (currentplane->extra_colormap) ds_colormap = currentplane->extra_colormap->colormap + (ds_colormap - colormaps); @@ -592,9 +609,7 @@ void R_DrawPlanes(void) visplane_t *pl; INT32 i; - // Note: are these two lines really needed? - // R_DrawSinglePlane and R_DrawSkyPlane do span/column drawer resets themselves anyway - spanfunc = spanfuncs[BASEDRAWFUNC]; + R_UpdatePlaneRipple(); for (i = 0; i < MAXVISPLANES; i++, pl++) { @@ -606,10 +621,6 @@ void R_DrawPlanes(void) R_DrawSinglePlane(pl); } } -#ifndef NOWATER - ds_waterofs = (leveltime & 1)*16384; - wtofs = leveltime * 140; -#endif } // R_DrawSkyPlane @@ -655,46 +666,48 @@ static void R_DrawSkyPlane(visplane_t *pl) } } -static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) +// Potentially override other stuff for now cus we're mean. :< But draw a slope plane! +// I copied ZDoom's code and adapted it to SRB2... -Red +void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge) { - // Potentially override other stuff for now cus we're mean. :< But draw a slope plane! - // I copied ZDoom's code and adapted it to SRB2... -Red floatv3_t p, m, n; float ang; float vx, vy, vz; + float xscale = FIXED_TO_FLOAT(planexscale); + float yscale = FIXED_TO_FLOAT(planeyscale); // compiler complains when P_GetSlopeZAt is used in FLOAT_TO_FIXED directly // use this as a temp var to store P_GetSlopeZAt's return value each time fixed_t temp; - vx = FIXED_TO_FLOAT(pl->viewx+xoffs); - vy = FIXED_TO_FLOAT(pl->viewy-yoffs); - vz = FIXED_TO_FLOAT(pl->viewz); + vx = FIXED_TO_FLOAT(planeviewx+planexoffset); + vy = FIXED_TO_FLOAT(planeviewy-planeyoffset); + vz = FIXED_TO_FLOAT(planeviewz); - temp = P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy); + temp = P_GetSlopeZAt(slope, planeviewx, planeviewy); zeroheight = FIXED_TO_FLOAT(temp); // 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. - ang = ANG2RAD(ANGLE_270 - pl->viewangle); + ang = ANG2RAD(ANGLE_270 - planeviewangle); p.x = vx * cos(ang) - vy * sin(ang); p.z = vx * sin(ang) + vy * cos(ang); - temp = P_GetSlopeZAt(pl->slope, -xoffs, yoffs); + temp = P_GetSlopeZAt(slope, -planexoffset, planeyoffset); p.y = FIXED_TO_FLOAT(temp) - vz; // m is the v direction vector in view space - ang = ANG2RAD(ANGLE_180 - (pl->viewangle + pl->plangle)); - m.x = cos(ang); - m.z = sin(ang); + ang = ANG2RAD(ANGLE_180 - (planeviewangle + planeangle)); + m.x = yscale * cos(ang); + m.z = yscale * sin(ang); // n is the u direction vector in view space - n.x = sin(ang); - n.z = -cos(ang); + n.x = xscale * sin(ang); + n.z = -xscale * cos(ang); - ang = ANG2RAD(pl->plangle); - temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(sin(ang)), pl->viewy + FLOAT_TO_FIXED(cos(ang))); + ang = ANG2RAD(planeangle); + temp = P_GetSlopeZAt(slope, planeviewx + yscale * FLOAT_TO_FIXED(sin(ang)), planeviewy + yscale * FLOAT_TO_FIXED(cos(ang))); m.y = FIXED_TO_FLOAT(temp) - zeroheight; - temp = P_GetSlopeZAt(pl->slope, pl->viewx + FLOAT_TO_FIXED(cos(ang)), pl->viewy - FLOAT_TO_FIXED(sin(ang))); + temp = P_GetSlopeZAt(slope, planeviewx + xscale * FLOAT_TO_FIXED(cos(ang)), planeviewy - xscale * FLOAT_TO_FIXED(sin(ang))); n.y = FIXED_TO_FLOAT(temp) - zeroheight; if (ds_powersoftwo) @@ -710,42 +723,58 @@ static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) // Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using. #define CROSS(d, v1, v2) \ -d.x = (v1.y * v2.z) - (v1.z * v2.y);\ -d.y = (v1.z * v2.x) - (v1.x * v2.z);\ -d.z = (v1.x * v2.y) - (v1.y * v2.x) - CROSS(ds_su[i], p, m); - CROSS(ds_sv[i], p, n); - CROSS(ds_sz[i], m, n); +d->x = (v1.y * v2.z) - (v1.z * v2.y);\ +d->y = (v1.z * v2.x) - (v1.x * v2.z);\ +d->z = (v1.x * v2.y) - (v1.y * v2.x) + CROSS(ds_sup, p, m); + CROSS(ds_svp, p, n); + CROSS(ds_szp, m, n); #undef CROSS - ds_su[i].z *= focallengthf; - ds_sv[i].z *= focallengthf; - ds_sz[i].z *= focallengthf; + ds_sup->z *= focallengthf; + ds_svp->z *= focallengthf; + ds_szp->z *= focallengthf; // Premultiply the texture vectors with the scale factors #define SFMULT 65536.f if (ds_powersoftwo) { - ds_su[i].x *= (SFMULT * (1<<nflatshiftup)); - ds_su[i].y *= (SFMULT * (1<<nflatshiftup)); - ds_su[i].z *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].x *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].y *= (SFMULT * (1<<nflatshiftup)); - ds_sv[i].z *= (SFMULT * (1<<nflatshiftup)); + ds_sup->x *= (SFMULT * (1<<nflatshiftup)); + ds_sup->y *= (SFMULT * (1<<nflatshiftup)); + ds_sup->z *= (SFMULT * (1<<nflatshiftup)); + ds_svp->x *= (SFMULT * (1<<nflatshiftup)); + ds_svp->y *= (SFMULT * (1<<nflatshiftup)); + ds_svp->z *= (SFMULT * (1<<nflatshiftup)); } else { // Lactozilla: I'm essentially multiplying the vectors by FRACUNIT... - ds_su[i].x *= SFMULT; - ds_su[i].y *= SFMULT; - ds_su[i].z *= SFMULT; - ds_sv[i].x *= SFMULT; - ds_sv[i].y *= SFMULT; - ds_sv[i].z *= SFMULT; + ds_sup->x *= SFMULT; + ds_sup->y *= SFMULT; + ds_sup->z *= SFMULT; + ds_svp->x *= SFMULT; + ds_svp->y *= SFMULT; + ds_svp->z *= SFMULT; } #undef SFMULT } +static void R_SetSlopePlaneVectors(visplane_t *pl, INT32 y, fixed_t xoff, fixed_t yoff, float fudge) +{ + if (ds_su == NULL) + ds_su = Z_Malloc(sizeof(*ds_su) * vid.height, PU_STATIC, NULL); + if (ds_sv == NULL) + ds_sv = Z_Malloc(sizeof(*ds_sv) * vid.height, PU_STATIC, NULL); + if (ds_sz == NULL) + ds_sz = Z_Malloc(sizeof(*ds_sz) * vid.height, PU_STATIC, NULL); + + ds_sup = &ds_su[y]; + ds_svp = &ds_sv[y]; + ds_szp = &ds_sz[y]; + + R_CalculateSlopeVectors(pl->slope, pl->viewx, pl->viewy, pl->viewz, FRACUNIT, FRACUNIT, xoff, yoff, pl->viewangle, pl->plangle, fudge); +} + void R_DrawSinglePlane(visplane_t *pl) { levelflat_t *levelflat; @@ -755,6 +784,7 @@ void R_DrawSinglePlane(visplane_t *pl) ffloor_t *rover; int type; int spanfunctype = BASEDRAWFUNC; + angle_t viewang = viewangle; if (!(pl->minx <= pl->maxx)) return; @@ -766,9 +796,7 @@ void R_DrawSinglePlane(visplane_t *pl) return; } -#ifndef NOWATER - itswater = false; -#endif + planeripple.active = false; spanfunc = spanfuncs[BASEDRAWFUNC]; if (pl->polyobj) @@ -779,7 +807,7 @@ void R_DrawSinglePlane(visplane_t *pl) else if (pl->polyobj->translucency > 0) { spanfunctype = (pl->polyobj->flags & POF_SPLAT) ? SPANDRAWFUNC_TRANSSPLAT : SPANDRAWFUNC_TRANS; - ds_transmap = transtables + ((pl->polyobj->translucency-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(pl->polyobj->translucency); } else if (pl->polyobj->flags & POF_SPLAT) // Opaque, but allow transparent flat pixels spanfunctype = SPANDRAWFUNC_SPLAT; @@ -818,23 +846,23 @@ void R_DrawSinglePlane(visplane_t *pl) if (pl->ffloor->alpha < 12) return; // Don't even draw it else if (pl->ffloor->alpha < 38) - ds_transmap = transtables + ((tr_trans90-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans90); else if (pl->ffloor->alpha < 64) - ds_transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans80); else if (pl->ffloor->alpha < 89) - ds_transmap = transtables + ((tr_trans70-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans70); else if (pl->ffloor->alpha < 115) - ds_transmap = transtables + ((tr_trans60-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans60); else if (pl->ffloor->alpha < 140) - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans50); else if (pl->ffloor->alpha < 166) - ds_transmap = transtables + ((tr_trans40-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans40); else if (pl->ffloor->alpha < 192) - ds_transmap = transtables + ((tr_trans30-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans30); else if (pl->ffloor->alpha < 217) - ds_transmap = transtables + ((tr_trans20-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans20); else if (pl->ffloor->alpha < 243) - ds_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans10); else // Opaque, but allow transparent flat pixels spanfunctype = SPANDRAWFUNC_SPLAT; @@ -850,12 +878,12 @@ void R_DrawSinglePlane(visplane_t *pl) } else light = (pl->lightlevel >> LIGHTSEGSHIFT); - #ifndef NOWATER if (pl->ffloor->flags & FF_RIPPLE) { INT32 top, bottom; - itswater = true; + planeripple.active = true; + if (spanfunctype == SPANDRAWFUNC_TRANS) { spanfunctype = SPANDRAWFUNC_WATER; @@ -875,26 +903,11 @@ void R_DrawSinglePlane(visplane_t *pl) vid.width, vid.width); } } - #endif } else light = (pl->lightlevel >> LIGHTSEGSHIFT); } - if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later - && viewangle != pl->viewangle+pl->plangle) - { - memset(cachedheight, 0, sizeof (cachedheight)); - angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; - basexscale = FixedDiv(FINECOSINE(angle),centerxfrac); - baseyscale = -FixedDiv(FINESINE(angle),centerxfrac); - viewangle = pl->viewangle+pl->plangle; - } - - xoffs = pl->xoffs; - yoffs = pl->yoffs; - planeheight = abs(pl->height - pl->viewz); - currentplane = pl; levelflat = &levelflats[pl->picnum]; @@ -919,6 +932,20 @@ void R_DrawSinglePlane(visplane_t *pl) R_CheckFlatLength(ds_flatwidth * ds_flatheight); } + if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later + && viewangle != pl->viewangle+pl->plangle) + { + memset(cachedheight, 0, sizeof (cachedheight)); + angle = (pl->viewangle+pl->plangle-ANGLE_90)>>ANGLETOFINESHIFT; + basexscale = FixedDiv(FINECOSINE(angle),centerxfrac); + baseyscale = -FixedDiv(FINESINE(angle),centerxfrac); + viewangle = pl->viewangle+pl->plangle; + } + + xoffs = pl->xoffs; + yoffs = pl->yoffs; + planeheight = abs(pl->height - pl->viewz); + if (light >= LIGHTLEVELS) light = LIGHTLEVELS-1; @@ -978,50 +1005,41 @@ void R_DrawSinglePlane(visplane_t *pl) xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1); } + xoffs = (fixed_t)(xoffs*fudgecanyon); yoffs = (fixed_t)(yoffs/fudgecanyon); } - ds_sup = &ds_su[0]; - ds_svp = &ds_sv[0]; - ds_szp = &ds_sz[0]; - -#ifndef NOWATER - if (itswater) + if (planeripple.active) { - INT32 i; fixed_t plheight = abs(P_GetSlopeZAt(pl->slope, pl->viewx, pl->viewy) - pl->viewz); - fixed_t rxoffs = xoffs; - fixed_t ryoffs = yoffs; R_PlaneBounds(pl); - for (i = pl->high; i < pl->low; i++) + for (x = pl->high; x < pl->low; x++) { - R_PlaneRipple(pl, i, plheight); - xoffs = rxoffs + ripple_xfrac; - yoffs = ryoffs + ripple_yfrac; - R_SlopeVectors(pl, i, fudgecanyon); + R_CalculatePlaneRipple(pl, x, plheight, true); + R_SetSlopePlaneVectors(pl, x, (xoffs + planeripple.xfrac), (yoffs + planeripple.yfrac), fudgecanyon); } - - xoffs = rxoffs; - yoffs = ryoffs; } else -#endif - R_SlopeVectors(pl, 0, fudgecanyon); + R_SetSlopePlaneVectors(pl, 0, xoffs, yoffs, fudgecanyon); -#ifndef NOWATER - if (itswater && (spanfunctype == SPANDRAWFUNC_WATER)) - spanfunctype = SPANDRAWFUNC_TILTEDWATER; - else -#endif - if (spanfunctype == SPANDRAWFUNC_TRANS) - spanfunctype = SPANDRAWFUNC_TILTEDTRANS; - else if (spanfunctype == SPANDRAWFUNC_SPLAT) - spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; - else - spanfunctype = SPANDRAWFUNC_TILTED; + switch (spanfunctype) + { + case SPANDRAWFUNC_WATER: + spanfunctype = SPANDRAWFUNC_TILTEDWATER; + break; + case SPANDRAWFUNC_TRANS: + spanfunctype = SPANDRAWFUNC_TILTEDTRANS; + break; + case SPANDRAWFUNC_SPLAT: + spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; + break; + default: + spanfunctype = SPANDRAWFUNC_TILTED; + break; + } planezlight = scalelight[light]; } @@ -1081,7 +1099,7 @@ using the palette colors. if (spanfunc == spanfuncs[BASEDRAWFUNC]) { INT32 i; - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + ds_transmap = R_GetTranslucencyTable(tr_trans50); spanfunc = spanfuncs[SPANDRAWFUNC_TRANS]; for (i=0; i<4; i++) { @@ -1131,6 +1149,8 @@ using the palette colors. } } #endif + + viewangle = viewang; } void R_PlaneBounds(visplane_t *plane) diff --git a/src/r_plane.h b/src/r_plane.h index 8d5ce9ee42330149e2b39255e580831dfd752f7f..7664858c9a88e44c4ca29946fd34a0c47f9acde8 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -87,11 +87,15 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_PlaneBounds(visplane_t *plane); -// Draws a single visplane. -void R_DrawSinglePlane(visplane_t *pl); void R_CheckFlatLength(size_t size); boolean R_CheckPowersOfTwo(void); +// Draws a single visplane. +void R_DrawSinglePlane(visplane_t *pl); + +// Calculates the slope vectors needed for tilted span drawing. +void R_CalculateSlopeVectors(pslope_t *slope, fixed_t planeviewx, fixed_t planeviewy, fixed_t planeviewz, fixed_t planexscale, fixed_t planeyscale, fixed_t planexoffset, fixed_t planeyoffset, angle_t planeviewangle, angle_t planeangle, float fudge); + typedef struct planemgr_s { visplane_t *plane; diff --git a/src/r_segs.c b/src/r_segs.c index 2cd7ebab2b5ea3018f29dbda41c6e6bc7d2c8ac2..1ed1f0285f785465ea3a307c0a6250b4db0d5c49 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -25,6 +25,7 @@ #include "p_local.h" // Camera... #include "p_slopes.h" #include "console.h" // con_clipviewtop +#include "taglist.h" // OPTIMIZE: closed two sided lines as single sided @@ -72,170 +73,6 @@ static lighttable_t **walllights; static INT16 *maskedtexturecol; static fixed_t *maskedtextureheight = NULL; -// ========================================================================== -// R_Splats Wall Splats Drawer -// ========================================================================== - -#ifdef WALLSPLATS -static INT16 last_ceilingclip[MAXVIDWIDTH]; -static INT16 last_floorclip[MAXVIDWIDTH]; - -static void R_DrawSplatColumn(column_t *column) -{ - INT32 topscreen, bottomscreen; - fixed_t basetexturemid; - INT32 topdelta, prevdelta = -1; - - basetexturemid = dc_texturemid; - - for (; column->topdelta != 0xff ;) - { - // calculate unclipped screen coordinates for post - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - topscreen = sprtopscreen + spryscale*topdelta; - bottomscreen = topscreen + spryscale*column->length; - - dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS; - dc_yh = (bottomscreen-1)>>FRACBITS; - - if (dc_yh >= last_floorclip[dc_x]) - dc_yh = last_floorclip[dc_x] - 1; - if (dc_yl <= last_ceilingclip[dc_x]) - dc_yl = last_ceilingclip[dc_x] + 1; - if (dc_yl <= dc_yh && dl_yh < vid.height && yh > 0) - { - dc_source = (UINT8 *)column + 3; - dc_texturemid = basetexturemid - (topdelta<<FRACBITS); - - // Drawn by R_DrawColumn. - colfunc(); - } - column = (column_t *)((UINT8 *)column + column->length + 4); - } - - dc_texturemid = basetexturemid; -} - -static void R_DrawWallSplats(void) -{ - wallsplat_t *splat; - seg_t *seg; - angle_t angle, angle1, angle2; - INT32 x1, x2; - size_t pindex; - column_t *col; - patch_t *patch; - fixed_t texturecolumn; - - splat = (wallsplat_t *)linedef->splats; - - I_Assert(splat != NULL); - - seg = ds_p->curline; - - // draw all splats from the line that touches the range of the seg - for (; splat; splat = splat->next) - { - angle1 = R_PointToAngle(splat->v1.x, splat->v1.y); - angle2 = R_PointToAngle(splat->v2.x, splat->v2.y); - angle1 = (angle1 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - angle2 = (angle2 - viewangle + ANGLE_90)>>ANGLETOFINESHIFT; - // out of the viewangletox lut - /// \todo clip it to the screen - if (angle1 > FINEANGLES/2 || angle2 > FINEANGLES/2) - continue; - x1 = viewangletox[angle1]; - x2 = viewangletox[angle2]; - - if (x1 >= x2) - continue; // does not cross a pixel - - // splat is not in this seg range - if (x2 < ds_p->x1 || x1 > ds_p->x2) - continue; - - if (x1 < ds_p->x1) - x1 = ds_p->x1; - if (x2 > ds_p->x2) - x2 = ds_p->x2; - if (x2 <= x1) - continue; - - // calculate incremental stepping values for texture edges - rw_scalestep = ds_p->scalestep; - spryscale = ds_p->scale1 + (x1 - ds_p->x1)*rw_scalestep; - mfloorclip = floorclip; - mceilingclip = ceilingclip; - - patch = W_CachePatchNum(splat->patch, PU_PATCH); - - dc_texturemid = splat->top + (SHORT(patch->height)<<(FRACBITS-1)) - viewz; - if (splat->yoffset) - dc_texturemid += *splat->yoffset; - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - - // set drawing mode - switch (splat->flags & SPLATDRAWMODE_MASK) - { - case SPLATDRAWMODE_OPAQUE: - colfunc = colfuncs[BASEDRAWFUNC]; - break; - case SPLATDRAWMODE_TRANS: - if (!cv_translucency.value) - colfunc = colfuncs[BASEDRAWFUNC]; - else - { - dc_transmap = transtables + ((tr_trans50 - 1)<<FF_TRANSSHIFT); - colfunc = colfuncs[COLDRAWFUNC_FUZZY]; - } - - break; - case SPLATDRAWMODE_SHADE: - colfunc = colfuncs[COLDRAWFUNC_SHADE]; - break; - } - - dc_texheight = 0; - - // draw the columns - for (dc_x = x1; dc_x <= x2; dc_x++, spryscale += rw_scalestep) - { - pindex = FixedMul(spryscale, LIGHTRESOLUTIONFIX)>>LIGHTSCALESHIFT; - if (pindex >= MAXLIGHTSCALE) - pindex = MAXLIGHTSCALE - 1; - dc_colormap = walllights[pindex]; - - if (frontsector->extra_colormap) - dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); - - sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale); - dc_iscale = 0xffffffffu / (unsigned)spryscale; - - // find column of patch, from perspective - angle = (rw_centerangle + xtoviewangle[dc_x])>>ANGLETOFINESHIFT; - texturecolumn = rw_offset2 - splat->offset - - FixedMul(FINETANGENT(angle), rw_distance); - - // FIXME! - texturecolumn >>= FRACBITS; - if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) - continue; - - // draw the texture - col = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); - R_DrawSplatColumn(col); - } - } // next splat - - colfunc = colfuncs[BASEDRAWFUNC]; -} - -#endif //WALLSPLATS - // ========================================================================== // R_RenderMaskedSegRange // ========================================================================== @@ -320,7 +157,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (ldef->alpha > 0 && ldef->alpha < FRACUNIT) { - dc_transmap = transtables + ((R_GetLinedefTransTable(ldef->alpha) - 1) << FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(R_GetLinedefTransTable(ldef->alpha)); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } @@ -338,7 +175,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (curline->polyseg->translucency >= NUMTRANSMAPS) return; - dc_transmap = transtables + ((curline->polyseg->translucency-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(curline->polyseg->translucency); colfunc = colfuncs[COLDRAWFUNC_FUZZY]; } @@ -766,23 +603,23 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->alpha < 12) return; // Don't even draw it else if (pfloor->alpha < 38) - dc_transmap = transtables + ((tr_trans90-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans90); else if (pfloor->alpha < 64) - dc_transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans80); else if (pfloor->alpha < 89) - dc_transmap = transtables + ((tr_trans70-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans70); else if (pfloor->alpha < 115) - dc_transmap = transtables + ((tr_trans60-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans60); else if (pfloor->alpha < 140) - dc_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans50); else if (pfloor->alpha < 166) - dc_transmap = transtables + ((tr_trans40-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans40); else if (pfloor->alpha < 192) - dc_transmap = transtables + ((tr_trans30-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans30); else if (pfloor->alpha < 217) - dc_transmap = transtables + ((tr_trans20-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans20); else if (pfloor->alpha < 243) - dc_transmap = transtables + ((tr_trans10-1)<<FF_TRANSSHIFT); + dc_transmap = R_GetTranslucencyTable(tr_trans10); else fuzzy = false; // Opaque @@ -2067,7 +1904,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->floorlightsec != frontsector->floorlightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markfloor = true; } @@ -2098,7 +1935,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) || backsector->ceilinglightsec != frontsector->ceilinglightsec //SoM: 4/3/2000: Check for colormaps || frontsector->extra_colormap != backsector->extra_colormap - || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag)) + || (frontsector->ffloors != backsector->ffloors && !Tag_Compare(&frontsector->tags, &backsector->tags))) { markceiling = true; } @@ -2188,7 +2025,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_bottomtexturemid += sidedef->rowoffset; // allocate space for masked texture tables - if (frontsector && backsector && frontsector->tag != backsector->tag && (backsector->ffloors || frontsector->ffloors)) + if (frontsector && backsector && !Tag_Compare(&frontsector->tags, &backsector->tags) && (backsector->ffloors || frontsector->ffloors)) { ffloor_t *rover; ffloor_t *r2; @@ -2230,6 +2067,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (r2 = frontsector->ffloors; r2; r2 = r2->next) { + if (r2->master == rover->master) // Skip if same control line. + break; + if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)) continue; @@ -2285,6 +2125,9 @@ void R_StoreWallRange(INT32 start, INT32 stop) for (r2 = backsector->ffloors; r2; r2 = r2->next) { + if (r2->master == rover->master) // Skip if same control line. + break; + if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)) continue; @@ -2880,20 +2723,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) rw_tsilheight = &(ds_p->tsilheight); rw_bsilheight = &(ds_p->bsilheight); -#ifdef WALLSPLATS - if (linedef->splats && cv_splats.value) - { - // Isn't a bit wasteful to copy the ENTIRE array for every drawseg? - M_Memcpy(last_ceilingclip + ds_p->x1, ceilingclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - M_Memcpy(last_floorclip + ds_p->x1, floorclip + ds_p->x1, - sizeof (INT16) * (ds_p->x2 - ds_p->x1 + 1)); - R_RenderSegLoop(); - R_DrawWallSplats(); - } - else -#endif - R_RenderSegLoop(); + R_RenderSegLoop(); colfunc = colfuncs[BASEDRAWFUNC]; if (portalline) // if curline is a portal, set portalrender for drawseg diff --git a/src/r_skins.h b/src/r_skins.h index 04ce459a37889d9455be439da72e3cbd34318966..fbbb38743d84704d3373aafd9e5cc1a7135a46d2 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -17,6 +17,7 @@ #include "info.h" #include "sounds.h" #include "d_player.h" // skinflags +#include "r_patch.h" #include "r_picformats.h" // spriteinfo_t #include "r_defs.h" // spritedef_t diff --git a/src/r_splats.c b/src/r_splats.c index dfec185a11ef2f4d6fc30ca532bd3de003d61942..636aa30edc160976e291ea6e91ff1b9e3b552e19 100644 --- a/src/r_splats.c +++ b/src/r_splats.c @@ -8,619 +8,592 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file r_splats.c -/// \brief floor and wall splats +/// \brief Floor splats #include "r_draw.h" #include "r_main.h" -#include "r_plane.h" #include "r_splats.h" +#include "r_bsp.h" +#include "p_local.h" +#include "p_slopes.h" #include "w_wad.h" #include "z_zone.h" -#include "d_netcmd.h" -#ifdef WALLSPLATS -static wallsplat_t wallsplats[MAXLEVELSPLATS]; // WALL splats -static INT32 freewallsplat; -#endif - -#ifdef USEASM -/// \brief for floorsplats \note accessed by asm code -struct rastery_s *prastertab; -#endif +struct rastery_s *prastertab; // for ASM code -#ifdef FLOORSPLATS -static floorsplat_t floorsplats[1]; // FLOOR splats -static INT32 freefloorsplat; - -struct rastery_s -{ - fixed_t minx, maxx; // for each raster line starting at line 0 - fixed_t tx1, ty1; - fixed_t tx2, ty2; // start/end points in texture at this line -}; static struct rastery_s rastertab[MAXVIDHEIGHT]; - static void prepare_rastertab(void); -#endif -// -------------------------------------------------------------------------- -// setup splat cache -// -------------------------------------------------------------------------- -void R_ClearLevelSplats(void) -{ -#ifdef WALLSPLATS - freewallsplat = 0; - memset(wallsplats, 0, sizeof (wallsplats)); -#endif -#ifdef FLOORSPLATS - freefloorsplat = 0; - memset(floorsplats, 0, sizeof (floorsplats)); +// ========================================================================== +// FLOOR SPLATS +// ========================================================================== - // setup to draw floorsplats - prastertab = rastertab; - prepare_rastertab(); +#ifdef USEASM +void ASMCALL rasterize_segment_tex_asm(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir); #endif -} -// ========================================================================== -// WALL SPLATS -// ========================================================================== -#ifdef WALLSPLATS -// -------------------------------------------------------------------------- -// Return a pointer to a splat free for use, or NULL if no more splats are -// available -// -------------------------------------------------------------------------- -static wallsplat_t *R_AllocWallSplat(void) +// Lactozilla +static void rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, INT32 tc, INT32 dir) { - wallsplat_t *splat; - wallsplat_t *p_splat; - line_t *li; - - // clear the splat from the line if it was in use - splat = &wallsplats[freewallsplat]; - li = splat->line; - if (li) +#ifdef USEASM + if (R_ASM) { - // remove splat from line splats list - if (li->splats == splat) - li->splats = splat->next; // remove from head - else - { - I_Assert(li->splats != NULL); - for (p_splat = li->splats; p_splat->next; p_splat = p_splat->next) - if (p_splat->next == splat) - { - p_splat->next = splat->next; - break; - } - } + rasterize_segment_tex_asm(x1, y1, x2, y2, tv1, tv2, tc, dir); + return; } + else +#endif + { + fixed_t xs, xe, count; + fixed_t dx0, dx1; - memset(splat, 0, sizeof (wallsplat_t)); + if (y1 == y2) + return; - // for next allocation - freewallsplat++; - if (freewallsplat >= 20) - freewallsplat = 0; + if (y2 > y1) + { + count = (y2-y1)+1; - return splat; -} + dx0 = FixedDiv((x2-x1)<<FRACBITS, count<<FRACBITS); + dx1 = FixedDiv((tv2-tv1)<<FRACBITS, count<<FRACBITS); -// Add a new splat to the linedef: -// top: top z coord -// wallfrac: frac along the linedef vector (0 to FRACUNIT) -// splatpatchname: name of patch to draw -void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top, - fixed_t wallfrac, INT32 flags) -{ - fixed_t fracsplat, linelength; - wallsplat_t *splat = NULL; - wallsplat_t *p_splat; - patch_t *patch; - sector_t *backsector = NULL; - - if (W_CheckNumForName(patchname) != LUMPERROR) - splat = R_AllocWallSplat(); - if (!splat) - return; + xs = x1 << FRACBITS; + xe = tv1 << FRACBITS; + tc <<= FRACBITS; - // set the splat - splat->patch = W_GetNumForName(patchname); - sectorside ^= 1; - if (wallline->sidenum[sectorside] != 0xffff) - { - backsector = sides[wallline->sidenum[sectorside]].sector; + if (dir == 0) + { + for (;;) + { + rastertab[y1].maxx = xs; + rastertab[y1].tx2 = xe; + rastertab[y1].ty2 = tc; - if (top < backsector->floorheight) - { - splat->yoffset = &backsector->floorheight; - top -= backsector->floorheight; - } - else if (top > backsector->ceilingheight) - { - splat->yoffset = &backsector->ceilingheight; - top -= backsector->ceilingheight; - } - } + xs += dx0; + xe += dx1; + y1++; - splat->top = top; - splat->flags = flags; + if (count-- < 1) break; + } + } + else + { + for (;;) + { + rastertab[y1].maxx = xs; + rastertab[y1].tx2 = tc; + rastertab[y1].ty2 = xe; - // bad.. but will be needed for drawing anyway.. - patch = W_CachePatchNum(splat->patch, PU_PATCH); + xs += dx0; + xe += dx1; + y1++; - // offset needed by draw code for texture mapping - linelength = P_SegLength((seg_t *)wallline); - splat->offset = FixedMul(wallfrac, linelength) - (SHORT(patch->width)<<(FRACBITS-1)); - fracsplat = FixedDiv(((SHORT(patch->width)<<FRACBITS)>>1), linelength); + if (count-- < 1) break; + } + } + } + else + { + count = (y1-y2)+1; - wallfrac -= fracsplat; - if (wallfrac > linelength) - return; - splat->v1.x = wallline->v1->x + FixedMul(wallline->dx, wallfrac); - splat->v1.y = wallline->v1->y + FixedMul(wallline->dy, wallfrac); - wallfrac += fracsplat + fracsplat; - if (wallfrac < 0) - return; - splat->v2.x = wallline->v1->x + FixedMul(wallline->dx, wallfrac); - splat->v2.y = wallline->v1->y + FixedMul(wallline->dy, wallfrac); + dx0 = FixedDiv((x1-x2)<<FRACBITS, count<<FRACBITS); + dx1 = FixedDiv((tv1-tv2)<<FRACBITS, count<<FRACBITS); - if (wallline->frontsector && wallline->frontsector == backsector) - return; + xs = x2 << FRACBITS; + xe = tv2 << FRACBITS; + tc <<= FRACBITS; - // insert splat in the linedef splat list - // BP: why not insert in head is much more simple? - // BP: because for remove it is more simple! - splat->line = wallline; - splat->next = NULL; - if (wallline->splats) - { - p_splat = wallline->splats; - while (p_splat->next) - p_splat = p_splat->next; - p_splat->next = splat; - } - else - wallline->splats = splat; -} -#endif // WALLSPLATS + if (dir == 0) + { + for (;;) + { + rastertab[y2].minx = xs; + rastertab[y2].tx1 = xe; + rastertab[y2].ty1 = tc; -// ========================================================================== -// FLOOR SPLATS -// ========================================================================== -#ifdef FLOORSPLATS + xs += dx0; + xe += dx1; + y2++; -// -------------------------------------------------------------------------- -// Return a pointer to a splat free for use, or NULL if no more splats are -// available -// -------------------------------------------------------------------------- -static floorsplat_t *R_AllocFloorSplat(void) -{ - floorsplat_t *splat; - floorsplat_t *p_splat; - subsector_t *sub; - - // find splat to use - freefloorsplat++; - if (freefloorsplat >= 1) - freefloorsplat = 0; - - // clear the splat from the line if it was in use - splat = &floorsplats[freefloorsplat]; - sub = splat->subsector; - if (sub) - { - // remove splat from subsector splats list - if (sub->splats == splat) - sub->splats = splat->next; // remove from head - else - { - p_splat = sub->splats; - while (p_splat->next) + if (count-- < 1) break; + } + } + else { - if (p_splat->next == splat) - p_splat->next = splat->next; + for (;;) + { + rastertab[y2].minx = xs; + rastertab[y2].tx1 = tc; + rastertab[y2].ty1 = xe; + + xs += dx0; + xe += dx1; + y2++; + + if (count-- < 1) break; + } } } } - - memset(splat, 0, sizeof (floorsplat_t)); - return splat; } -// -------------------------------------------------------------------------- -// Add a floor splat to the subsector -// -------------------------------------------------------------------------- -void R_AddFloorSplat(subsector_t *subsec, mobj_t *mobj, const char *picname, fixed_t x, fixed_t y, fixed_t z, - INT32 flags) +void R_DrawFloorSprite(vissprite_t *spr) { - floorsplat_t *splat = NULL; - floorsplat_t *p_splat; - INT32 size; + floorsplat_t splat; + mobj_t *mobj = spr->mobj; + fixed_t tr_x, tr_y, rot_x, rot_y, rot_z; + + vector3_t *v3d; + vector2_t v2d[4]; + vector2_t rotated[4]; + + fixed_t x, y; + fixed_t w, h; + angle_t angle, splatangle; + fixed_t ca, sa; + fixed_t xscale, yscale; + fixed_t xoffset, yoffset; + fixed_t leftoffset, topoffset; + pslope_t *slope = NULL; + INT32 i; + + boolean hflip = (spr->xiscale < 0); + boolean vflip = (spr->cut & SC_VFLIP); + UINT8 flipflags = 0; + + renderflags_t renderflags = spr->renderflags; + + if (hflip) + flipflags |= PICFLAGS_XFLIP; + if (vflip) + flipflags |= PICFLAGS_YFLIP; + + if (!mobj || P_MobjWasRemoved(mobj)) + return; - if (W_CheckNumForName(picname) != LUMPERROR) - splat = R_AllocFloorSplat(); - if (!splat) + Patch_GenerateFlat(spr->patch, flipflags); + splat.pic = spr->patch->flats[flipflags]; + if (splat.pic == NULL) return; - // set the splat - splat->pic = W_GetNumForName(picname); - splat->flags = flags; - splat->mobj = mobj; + splat.mobj = mobj; + splat.width = spr->patch->width; + splat.height = spr->patch->height; + splat.scale = mobj->scale; - splat->z = z; + if (mobj->skin && ((skin_t *)mobj->skin)->flags & SF_HIRES) + splat.scale = FixedMul(splat.scale, ((skin_t *)mobj->skin)->highresscale); - size = W_LumpLength(splat->pic); + if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) + splatangle = mobj->angle; + else + splatangle = viewangle; - switch (size) - { - case 4194304: // 2048x2048 lump - splat->size = 1024; - break; - case 1048576: // 1024x1024 lump - splat->size = 512; - break; - case 262144:// 512x512 lump - splat->size = 256; - break; - case 65536: // 256x256 lump - splat->size = 128; - break; - case 16384: // 128x128 lump - splat->size = 64; - break; - case 1024: // 32x32 lump - splat->size = 16; - break; - default: // 64x64 lump - splat->size = 32; - break; - } + if (!(spr->cut & SC_ISROTATED)) + splatangle += mobj->rollangle; + + splat.angle = -splatangle; + splat.angle += ANGLE_90; + + topoffset = spr->spriteyoffset; + leftoffset = spr->spritexoffset; + if (hflip) + leftoffset = ((splat.width * FRACUNIT) - leftoffset); + + xscale = spr->spritexscale; + yscale = spr->spriteyscale; + + splat.xscale = FixedMul(splat.scale, xscale); + splat.yscale = FixedMul(splat.scale, yscale); + + xoffset = FixedMul(leftoffset, splat.xscale); + yoffset = FixedMul(topoffset, splat.yscale); + + x = mobj->x; + y = mobj->y; + w = (splat.width * splat.xscale); + h = (splat.height * splat.yscale); + + splat.x = x; + splat.y = y; + splat.z = mobj->z; + splat.tilted = false; + + // Set positions // 3--2 // | | // 0--1 - // - splat->verts[0].x = splat->verts[3].x = x - (splat->size<<FRACBITS); - splat->verts[2].x = splat->verts[1].x = x + ((splat->size-1)<<FRACBITS); - splat->verts[3].y = splat->verts[2].y = y + ((splat->size-1)<<FRACBITS); - splat->verts[0].y = splat->verts[1].y = y - (splat->size<<FRACBITS); - - // insert splat in the subsector splat list - splat->subsector = subsec; - splat->next = NULL; - if (subsec->splats) + + splat.verts[0].x = w - xoffset; + splat.verts[0].y = yoffset; + + splat.verts[1].x = -xoffset; + splat.verts[1].y = yoffset; + + splat.verts[2].x = -xoffset; + splat.verts[2].y = -h + yoffset; + + splat.verts[3].x = w - xoffset; + splat.verts[3].y = -h + yoffset; + + angle = -splat.angle; + ca = FINECOSINE(angle>>ANGLETOFINESHIFT); + sa = FINESINE(angle>>ANGLETOFINESHIFT); + + // Rotate + for (i = 0; i < 4; i++) { - p_splat = subsec->splats; - while (p_splat->next) - p_splat = p_splat->next; - p_splat->next = splat; + rotated[i].x = FixedMul(splat.verts[i].x, ca) - FixedMul(splat.verts[i].y, sa); + rotated[i].y = FixedMul(splat.verts[i].x, sa) + FixedMul(splat.verts[i].y, ca); } - else - subsec->splats = splat; -} -// -------------------------------------------------------------------------- -// Before each frame being rendered, clear the visible floorsplats list -// -------------------------------------------------------------------------- -static floorsplat_t *visfloorsplats; + if (renderflags & (RF_SLOPESPLAT | RF_OBJECTSLOPESPLAT)) + { + pslope_t *standingslope = mobj->standingslope; // The slope that the object is standing on. -void R_ClearVisibleFloorSplats(void) -{ - visfloorsplats = NULL; -} + // The slope that was defined for the sprite. + if (renderflags & RF_SLOPESPLAT) + slope = mobj->floorspriteslope; -// -------------------------------------------------------------------------- -// Add a floorsplat to the visible floorsplats list, for the current frame -// -------------------------------------------------------------------------- -void R_AddVisibleFloorSplats(subsector_t *subsec) -{ - floorsplat_t *pSplat; - I_Assert(subsec->splats != NULL); - - pSplat = subsec->splats; - // the splat is not visible from below - // FIXME: depending on some flag in pSplat->flags, some splats may be visible from 2 sides - // (above/below) - if (pSplat->z < viewz) + if (standingslope && (renderflags & RF_OBJECTSLOPESPLAT)) + slope = standingslope; + + // Set splat as tilted + splat.tilted = (slope != NULL); + } + + if (splat.tilted) { - pSplat->nextvis = visfloorsplats; - visfloorsplats = pSplat; + // Lactozilla: Just copy the entire slope LMFAOOOO + pslope_t *s = &splat.slope; + + s->o.x = slope->o.x; + s->o.y = slope->o.y; + s->o.z = slope->o.z; + + s->d.x = slope->d.x; + s->d.y = slope->d.y; + + s->normal.x = slope->normal.x; + s->normal.y = slope->normal.y; + s->normal.z = slope->normal.z; + + s->zdelta = slope->zdelta; + s->zangle = slope->zangle; + s->xydirection = slope->xydirection; + + s->next = NULL; + s->flags = 0; } - while (pSplat->next) + // Translate + for (i = 0; i < 4; i++) { - pSplat = pSplat->next; - if (pSplat->z < viewz) + tr_x = rotated[i].x + x; + tr_y = rotated[i].y + y; + + if (slope) { - pSplat->nextvis = visfloorsplats; - visfloorsplats = pSplat; + rot_z = P_GetSlopeZAt(slope, tr_x, tr_y); + splat.verts[i].z = rot_z; } + else + splat.verts[i].z = splat.z; + + splat.verts[i].x = tr_x; + splat.verts[i].y = tr_y; } -} -#ifdef USEASM -// tv1, tv2 = x/y qui varie dans la texture, tc = x/y qui est constant. -void ASMCALL rasterize_segment_tex(INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 tv1, INT32 tv2, - INT32 tc, INT32 dir); -#endif + for (i = 0; i < 4; i++) + { + v3d = &splat.verts[i]; + + // transform the origin point + tr_x = v3d->x - viewx; + tr_y = v3d->y - viewy; -// current test with floor tile -//#define FLOORSPLATSOLIDCOLOR + // rotation around vertical y axis + rot_x = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); + rot_y = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + rot_z = v3d->z - viewz; + + if (rot_y < FRACUNIT) + return; + + // note: y from view above of map, is distance far away + xscale = FixedDiv(projection, rot_y); + yscale = -FixedDiv(projectiony, rot_y); + + // projection + v2d[i].x = (centerxfrac + FixedMul(rot_x, xscale))>>FRACBITS; + v2d[i].y = (centeryfrac + FixedMul(rot_z, yscale))>>FRACBITS; + } + + R_RenderFloorSplat(&splat, v2d, spr); +} // -------------------------------------------------------------------------- // Rasterize the four edges of a floor splat polygon, // fill the polygon with linear interpolation, call span drawer for each // scan line // -------------------------------------------------------------------------- -static void R_RenderFloorSplat(floorsplat_t *pSplat, vertex_t *verts, UINT8 *pTex) +void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis) { // rasterizing - INT32 miny = vid.height + 1, maxy = 0, y, x1, ry1, x2, y2; - fixed_t offsetx, offsety; - -#ifdef FLOORSPLATSOLIDCOLOR - UINT8 *pDest; - INT32 tdx, tdy, ty, tx, x; -#else - lighttable_t **planezlight; - fixed_t planeheight; - angle_t angle, planecos, planesin; - fixed_t distance, span; - size_t indexr; - INT32 light; -#endif - (void)pTex; + INT32 miny = viewheight + 1, maxy = 0; + INT32 y, x1, ry1, x2, y2, i; + fixed_t offsetx = 0, offsety = 0; + fixed_t planeheight = 0; + fixed_t step; - offsetx = pSplat->verts[0].x & ((pSplat->size << FRACBITS)-1); - offsety = pSplat->verts[0].y & ((pSplat->size << FRACBITS)-1); + int spanfunctype = SPANDRAWFUNC_SPRITE; - // do segment a -> top of texture - x1 = verts[3].x; - ry1 = verts[3].y; - x2 = verts[2].x; - y2 = verts[2].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, 0, pSplat->size - 1, 0, 0); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; + prepare_rastertab(); - // do segment b -> right side of texture - x1 = x2; - ry1 = y2; - x2 = verts[1].x; - y2 = verts[1].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, 0, pSplat->size - 1, pSplat->size - 1, 1); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; +#define RASTERPARAMS(vnum1, vnum2, tv1, tv2, tc, dir) \ + x1 = verts[vnum1].x; \ + ry1 = verts[vnum1].y; \ + x2 = verts[vnum2].x; \ + y2 = verts[vnum2].y; \ + if (y2 > ry1) \ + step = FixedDiv(x2-x1, y2-ry1+1); \ + else if (y2 == ry1) \ + step = 0; \ + else \ + step = FixedDiv(x2-x1, ry1-y2+1); \ + if (ry1 < 0) { \ + if (step) { \ + x1 <<= FRACBITS; \ + x1 += (-ry1)*step; \ + x1 >>= FRACBITS; \ + } \ + ry1 = 0; \ + } \ + if (ry1 >= vid.height) { \ + if (step) { \ + x1 <<= FRACBITS; \ + x1 -= (vid.height-1-ry1)*step; \ + x1 >>= FRACBITS; \ + } \ + ry1 = vid.height - 1; \ + } \ + if (y2 < 0) { \ + if (step) { \ + x2 <<= FRACBITS; \ + x2 -= (-y2)*step; \ + x2 >>= FRACBITS; \ + } \ + y2 = 0; \ + } \ + if (y2 >= vid.height) { \ + if (step) { \ + x2 <<= FRACBITS; \ + x2 += (vid.height-1-y2)*step; \ + x2 >>= FRACBITS; \ + } \ + y2 = vid.height - 1; \ + } \ + rasterize_segment_tex(x1, ry1, x2, y2, tv1, tv2, tc, dir); \ + if (ry1 < miny) \ + miny = ry1; \ + if (ry1 > maxy) \ + maxy = ry1; + // do segment a -> top of texture + RASTERPARAMS(3,2,0,pSplat->width-1,0,0); + // do segment b -> right side of texture + RASTERPARAMS(2,1,0,pSplat->width-1,pSplat->height-1,0); // do segment c -> bottom of texture - x1 = x2; - ry1 = y2; - x2 = verts[0].x; - y2 = verts[0].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, pSplat->size - 1, 0, pSplat->size - 1, 0); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; - + RASTERPARAMS(1,0,pSplat->width-1,0,pSplat->height-1,0); // do segment d -> left side of texture - x1 = x2; - ry1 = y2; - x2 = verts[3].x; - y2 = verts[3].y; - if (ry1 < 0) - ry1 = 0; - if (ry1 >= vid.height) - ry1 = vid.height - 1; - if (y2 < 0) - y2 = 0; - if (y2 >= vid.height) - y2 = vid.height - 1; - rasterize_segment_tex(x1, ry1, x2, y2, pSplat->size - 1, 0, 0, 1); - if (ry1 < miny) - miny = ry1; - if (ry1 > maxy) - maxy = ry1; - -#ifndef FLOORSPLATSOLIDCOLOR - // prepare values for all the splat - ds_source = W_CacheLumpNum(pSplat->pic, PU_CACHE); - planeheight = abs(pSplat->z - viewz); - light = (pSplat->subsector->sector->lightlevel >> LIGHTSEGSHIFT); - if (light >= LIGHTLEVELS) - light = LIGHTLEVELS - 1; - if (light < 0) - light = 0; - planezlight = zlight[light]; + RASTERPARAMS(0,3,pSplat->width-1,0,0,1); - for (y = miny; y <= maxy; y++) - { - x1 = rastertab[y].minx>>FRACBITS; - x2 = rastertab[y].maxx>>FRACBITS; + ds_source = (UINT8 *)pSplat->pic; + ds_flatwidth = pSplat->width; + ds_flatheight = pSplat->height; - if (x1 < 0) - x1 = 0; - if (x2 >= vid.width) - x2 = vid.width - 1; + if (R_CheckPowersOfTwo()) + R_CheckFlatLength(ds_flatwidth * ds_flatheight); - angle = (currentplane->viewangle + currentplane->plangle)>>ANGLETOFINESHIFT; - planecos = FINECOSINE(angle); - planesin = FINESINE(angle); + // Lactozilla: I don't know what I'm doing + if (pSplat->tilted) + { + ds_sup = &ds_su[0]; + ds_svp = &ds_sv[0]; + ds_szp = &ds_sz[0]; + R_CalculateSlopeVectors(&pSplat->slope, viewx, viewy, viewz, pSplat->xscale, pSplat->yscale, -pSplat->verts[0].x, pSplat->verts[0].y, viewangle, pSplat->angle, 1.0f); + spanfunctype = SPANDRAWFUNC_TILTEDSPRITE; + } + else + { + planeheight = abs(pSplat->z - viewz); - if (planeheight != cachedheight[y]) + if (pSplat->angle) { - cachedheight[y] = planeheight; - distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); - ds_xstep = cachedxstep[y] = FixedMul(distance,basexscale); - ds_ystep = cachedystep[y] = FixedMul(distance,baseyscale); - - if ((span = abs(centery-y))) - { - ds_xstep = cachedxstep[y] = FixedMul(planesin, planeheight) / span; - ds_ystep = cachedystep[y] = FixedMul(planecos, planeheight) / span; - } + // Add the view offset, rotated by the plane angle. + fixed_t a = -pSplat->verts[0].x + viewx; + fixed_t b = -pSplat->verts[0].y + viewy; + angle_t angle = (pSplat->angle >> ANGLETOFINESHIFT); + offsetx = FixedMul(a, FINECOSINE(angle)) - FixedMul(b,FINESINE(angle)); + offsety = -FixedMul(a, FINESINE(angle)) - FixedMul(b,FINECOSINE(angle)); + memset(cachedheight, 0, sizeof(cachedheight)); } else { - distance = cacheddistance[y]; - ds_xstep = cachedxstep[y]; - ds_ystep = cachedystep[y]; + offsetx = viewx - pSplat->verts[0].x; + offsety = pSplat->verts[0].y - viewy; } + } - ds_xfrac = xoffs + FixedMul(planecos, distance) + (x1 - centerx) * ds_xstep; - ds_yfrac = yoffs - FixedMul(planesin, distance) + (x1 - centerx) * ds_ystep; - ds_xfrac -= offsetx; - ds_yfrac += offsety; + ds_colormap = vis->colormap; + ds_translation = R_GetSpriteTranslation(vis); + if (ds_translation == NULL) + ds_translation = colormaps; - indexr = distance >> LIGHTZSHIFT; - if (indexr >= MAXLIGHTZ) - indexr = MAXLIGHTZ - 1; - ds_colormap = planezlight[indexr]; + if (vis->extra_colormap) + { + if (!ds_colormap) + ds_colormap = vis->extra_colormap->colormap; + else + ds_colormap = &vis->extra_colormap->colormap[ds_colormap - colormaps]; + } - ds_y = y; - if (x2 >= x1) // sanity check - { - ds_x1 = x1; - ds_x2 = x2; - ds_transmap = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); - (spanfuncs[SPANDRAWFUNC_SPLAT])(); - } + if (vis->transmap) + { + ds_transmap = vis->transmap; - // reset for next calls to edge rasterizer - rastertab[y].minx = INT32_MAX; - rastertab[y].maxx = INT32_MIN; + if (pSplat->tilted) + spanfunctype = SPANDRAWFUNC_TILTEDTRANSSPRITE; + else + spanfunctype = SPANDRAWFUNC_TRANSSPRITE; } + else + ds_transmap = NULL; + + if (ds_powersoftwo) + spanfunc = spanfuncs[spanfunctype]; + else + spanfunc = spanfuncs_npo2[spanfunctype]; + + if (maxy >= vid.height) + maxy = vid.height-1; -#else for (y = miny; y <= maxy; y++) { + boolean cliptab[MAXVIDWIDTH+1]; + x1 = rastertab[y].minx>>FRACBITS; x2 = rastertab[y].maxx>>FRACBITS; + + if (x1 > x2) + { + INT32 swap = x1; + x1 = x2; + x2 = swap; + } + + if (x1 == INT16_MIN || x2 == INT16_MAX) + continue; + if (x1 < 0) x1 = 0; - if (x2 >= vid.width) - x2 = vid.width - 1; + if (x2 >= viewwidth) + x2 = viewwidth - 1; -// pDest = ylookup[y] + columnofs[x1]; - pDest = &topleft[y*vid.width + x1]; + if (x1 >= viewwidth || x2 < 0) + continue; - x = x2 - x1 + 1; + for (i = x1; i <= x2; i++) + cliptab[i] = (y >= mfloorclip[i]); - // starting point of the texture - tx = rastertab[y].tx1; - ty = rastertab[y].ty1; - - // HORRIBLE BUG!!! - if (x > 0) + // clip left + while (cliptab[x1]) { - tdx = (rastertab[y].tx2 - tx) / x; - tdy = (rastertab[y].ty2 - ty) / x; - - while (x-- > 0) - { - *(pDest++) = (UINT8)(y&1); - tx += tdx; - ty += tdy; - } + x1++; + if (x1 >= viewwidth) + break; } - // reinitialise the minimum and maximum for the next approach - rastertab[y].minx = INT32_MAX; - rastertab[y].maxx = INT32_MIN; - } -#endif -} + // clip right + i = x2; -// -------------------------------------------------------------------------- -// R_DrawVisibleFloorSplats -// draw the flat floor/ceiling splats -// -------------------------------------------------------------------------- -void R_DrawVisibleFloorSplats(void) -{ - floorsplat_t *pSplat; - INT32 iCount = 0, i; - fixed_t tr_x, tr_y, rot_x, rot_y, rot_z, xscale, yscale; - vertex_t *v3d; - vertex_t v2d[4]; - - pSplat = visfloorsplats; - while (pSplat) - { - iCount++; + while (i > x1) + { + if (cliptab[i]) + x2 = i-1; + i--; + if (i < 0) + break; + } - // Draw a floor splat - // 3--2 - // | | - // 0--1 + if (x2 < x1) + continue; - rot_z = pSplat->z - viewz; - for (i = 0; i < 4; i++) + if (!pSplat->tilted) { - v3d = &pSplat->verts[i]; + fixed_t xstep, ystep; + fixed_t distance, span; - // transform the origin point - tr_x = v3d->x - viewx; - tr_y = v3d->y - viewy; + angle_t angle = (viewangle + pSplat->angle)>>ANGLETOFINESHIFT; + angle_t planecos = FINECOSINE(angle); + angle_t planesin = FINESINE(angle); - // rotation around vertical y axis - rot_x = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); - rot_y = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + if (planeheight != cachedheight[y]) + { + cachedheight[y] = planeheight; + distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]); + span = abs(centery - y); - if (rot_y < 4*FRACUNIT) - goto skipit; + if (span) // don't divide by zero + { + xstep = FixedMul(planesin, planeheight) / span; + ystep = FixedMul(planecos, planeheight) / span; + } + else + { + // ah + xstep = FRACUNIT; + ystep = FRACUNIT; + } + + cachedxstep[y] = xstep; + cachedystep[y] = ystep; + } + else + { + distance = cacheddistance[y]; + xstep = cachedxstep[y]; + ystep = cachedystep[y]; + } - // note: y from view above of map, is distance far away - xscale = FixedDiv(projection, rot_y); - yscale = -FixedDiv(projectiony, rot_y); + ds_xstep = FixedDiv(xstep, pSplat->xscale); + ds_ystep = FixedDiv(ystep, pSplat->yscale); - // projection - v2d[i].x = (centerxfrac + FixedMul (rot_x, xscale))>>FRACBITS; - v2d[i].y = (centeryfrac + FixedMul (rot_z, yscale))>>FRACBITS; + ds_xfrac = FixedDiv(offsetx + FixedMul(planecos, distance) + (x1 - centerx) * xstep, pSplat->xscale); + ds_yfrac = FixedDiv(offsety - FixedMul(planesin, distance) + (x1 - centerx) * ystep, pSplat->yscale); } - R_RenderFloorSplat(pSplat, v2d, NULL); -skipit: - pSplat = pSplat->nextvis; + ds_y = y; + ds_x1 = x1; + ds_x2 = x2; + spanfunc(); + + rastertab[y].minx = INT32_MAX; + rastertab[y].maxx = INT32_MIN; } + + if (pSplat->angle && !pSplat->tilted) + memset(cachedheight, 0, sizeof(cachedheight)); } static void prepare_rastertab(void) { - INT32 iLine; - for (iLine = 0; iLine < vid.height; iLine++) + INT32 i; + prastertab = rastertab; + for (i = 0; i < vid.height; i++) { - rastertab[iLine].minx = INT32_MAX; - rastertab[iLine].maxx = INT32_MIN; + rastertab[i].minx = INT32_MAX; + rastertab[i].maxx = INT32_MIN; } } - -#endif // FLOORSPLATS diff --git a/src/r_splats.h b/src/r_splats.h index 4ad893abbb2db5dcde78116fd94b65cf8f373aa4..e1f836f489bab54513dafd5b867ebfd7dbc79f44 100644 --- a/src/r_splats.h +++ b/src/r_splats.h @@ -14,68 +14,35 @@ #define __R_SPLATS_H__ #include "r_defs.h" - -//#define WALLSPLATS // comment this out to compile without splat effects -/*#ifdef USEASM -#define FLOORSPLATS -#endif*/ - -#define MAXLEVELSPLATS 1024 - -// splat flags -#define SPLATDRAWMODE_MASK 0x03 // mask to get drawmode from flags -#define SPLATDRAWMODE_OPAQUE 0x00 -#define SPLATDRAWMODE_SHADE 0x01 -#define SPLATDRAWMODE_TRANS 0x02 +#include "r_things.h" // ========================================================================== // DEFINITIONS // ========================================================================== -// WALL SPLATS are patches drawn on top of wall segs -typedef struct wallsplat_s +struct rastery_s { - lumpnum_t patch; // lump id. - vertex_t v1, v2; // vertices along the linedef - fixed_t top; - fixed_t offset; // offset in columns<<FRACBITS from start of linedef to start of splat - INT32 flags; - fixed_t *yoffset; - line_t *line; // the parent line of the splat seg - struct wallsplat_s *next; -} wallsplat_t; + fixed_t minx, maxx; // for each raster line starting at line 0 + fixed_t tx1, ty1; // start points in texture at this line + fixed_t tx2, ty2; // end points in texture at this line +}; +extern struct rastery_s *prastertab; // for ASM code -// FLOOR SPLATS are pic_t (raw horizontally stored) drawn on top of the floor or ceiling typedef struct floorsplat_s { - lumpnum_t pic; // a pic_t lump id - INT32 flags; - INT32 size; // 64, 128, 256, etc. - vertex_t verts[4]; // (x,y) as viewn from above on map - fixed_t z; // z (height) is constant for all the floorsplats - subsector_t *subsector; // the parent subsector + UINT16 *pic; + INT32 width, height; + fixed_t scale, xscale, yscale; + angle_t angle; + boolean tilted; // Uses the tilted drawer + pslope_t slope; + + vector3_t verts[4]; // (x,y,z) as viewed from above on map + fixed_t x, y, z; // position mobj_t *mobj; // Mobj it is tied to - struct floorsplat_s *next; - struct floorsplat_s *nextvis; } floorsplat_t; -// p_setup.c -fixed_t P_SegLength(seg_t *seg); - -// call at P_SetupLevel() -void R_ClearLevelSplats(void); - -#ifdef WALLSPLATS -void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top, - fixed_t wallfrac, INT32 flags); -#endif -#ifdef FLOORSPLATS -void R_AddFloorSplat(subsector_t *subsec, mobj_t *mobj, const char *picname, fixed_t x, fixed_t y, fixed_t z, - INT32 flags); -#endif - -void R_ClearVisibleFloorSplats(void); -void R_AddVisibleFloorSplats(subsector_t *subsec); -void R_DrawVisibleFloorSplats(void); +void R_DrawFloorSprite(vissprite_t *spr); +void R_RenderFloorSplat(floorsplat_t *pSplat, vector2_t *verts, vissprite_t *vis); #endif /*__R_SPLATS_H__*/ diff --git a/src/r_textures.c b/src/r_textures.c index a34c29c728c79395d56ad93864b32c575032d5aa..9de9649e222a9628f0917592570c899917e62722 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -20,6 +20,7 @@ #include "m_misc.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" @@ -33,7 +34,7 @@ #endif #ifdef HWRENDER -#include "hardware/hw_main.h" // HWR_LoadTextures +#include "hardware/hw_glob.h" // HWR_LoadMapTextures #endif #include <errno.h> @@ -266,7 +267,7 @@ UINT8 *R_GenerateTexture(size_t texnum) UINT8 *blocktex; texture_t *texture; texpatch_t *patch; - patch_t *realpatch; + softwarepatch_t *realpatch; UINT8 *pdata; int x, x1, x2, i, width, height; size_t blocksize; @@ -296,7 +297,7 @@ UINT8 *R_GenerateTexture(size_t texnum) lumpnum = patch->lump; lumplength = W_LumpLengthPwad(wadnum, lumpnum); pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) @@ -392,17 +393,17 @@ UINT8 *R_GenerateTexture(size_t texnum) lumpnum = patch->lump; pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = (patch_t *)pdata; + realpatch = (softwarepatch_t *)pdata; dealloc = true; #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); + realpatch = (softwarepatch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, lumplength, NULL, 0); else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); + realpatch = (softwarepatch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_DOOMPATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -597,13 +598,13 @@ void *R_GetLevelFlat(levelflat_t *levelflat) { UINT8 *converted; size_t size; - patch_t *patch = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); + softwarepatch_t *patch = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); levelflat->width = ds_flatwidth = SHORT(patch->width); levelflat->height = ds_flatheight = SHORT(patch->height); levelflat->picture = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); - converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + converted = Picture_FlatConvert(PICFMT_DOOMPATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); M_Memcpy(levelflat->picture, converted, size); Z_Free(converted); } @@ -839,7 +840,7 @@ Rloadtextures (INT32 i, INT32 w) UINT16 j; UINT16 texstart, texend, texturesLumpPos; texture_t *texture; - patch_t *patchlump; + softwarepatch_t *patchlump; texpatch_t *patch; // Get the lump numbers for the markers in the WAD, if they exist. @@ -1062,7 +1063,7 @@ void R_LoadTextures(void) #ifdef HWRENDER if (rendermode == render_opengl) - HWR_LoadTextures(numtextures); + HWR_LoadMapTextures(numtextures); #endif } diff --git a/src/r_things.c b/src/r_things.c index 7d3f2be3dd8c1fdb9fc602023afa51006ac0807a..2daa6984dc8b1101b9c72e5375d7d092bd2e4b74 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -24,9 +24,12 @@ #include "i_video.h" // rendermode #include "i_system.h" #include "r_things.h" +#include "r_patch.h" +#include "r_patchrotation.h" #include "r_picformats.h" #include "r_plane.h" #include "r_portal.h" +#include "r_splats.h" #include "p_tick.h" #include "p_local.h" #include "p_slopes.h" @@ -96,7 +99,7 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch { char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging - INT32 r, ang; + INT32 r; lumpnum_t lumppat = wad; lumppat <<= 16; lumppat += lump; @@ -104,15 +107,13 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch if (maxframe ==(size_t)-1 || frame > maxframe) maxframe = frame; - // rotsprite #ifdef ROTSPRITE - sprtemp[frame].rotsprite.cached = 0; for (r = 0; r < 16; r++) { - for (ang = 0; ang < ROTANGLES; ang++) - sprtemp[frame].rotsprite.patch[r][ang] = NULL; + sprtemp[frame].rotated[0][r] = NULL; + sprtemp[frame].rotated[1][r] = NULL; } -#endif/*ROTSPRITE*/ +#endif if (rotation == 0) { @@ -228,7 +229,7 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 UINT8 frame; UINT8 rotation; lumpinfo_t *lumpinfo; - patch_t patch; + softwarepatch_t patch; UINT8 numadded = 0; memset(sprtemp,0xFF, sizeof (sprtemp)); @@ -240,9 +241,6 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 // 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)); @@ -283,7 +281,7 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 #ifndef NO_PNG_LUMPS { - patch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC); + softwarepatch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC); size_t len = W_LumpLengthPwad(wadnum, l); if (Picture_IsLumpPNG((UINT8 *)png, len)) @@ -414,9 +412,6 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 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; } @@ -746,6 +741,55 @@ void R_DrawFlippedMaskedColumn(column_t *column) dc_texturemid = basetexturemid; } +boolean R_SpriteIsFlashing(vissprite_t *vis) +{ + return (!(vis->cut & SC_PRECIP) + && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) + && (vis->mobj->flags2 & MF2_FRET) + && !(vis->mobj->flags & MF_GRENADEBOUNCE) + && (leveltime & 1)); +} + +UINT8 *R_GetSpriteTranslation(vissprite_t *vis) +{ + if (R_SpriteIsFlashing(vis)) // Bosses "flash" + { + if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) + return R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); + else if (vis->mobj->type == MT_METALSONIC_BATTLE) + return R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); + else + return R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); + } + else if (vis->mobj->color) + { + // New colormap stuff for skins Tails 06-07-2002 + if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) + return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + else if (!(vis->cut & SC_PRECIP) + && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD + && (vis->mobj->player->charflags & SF_DASHMODE) + && ((leveltime/2) & 1)) + { + if (vis->mobj->player->charflags & SF_MACHINE) + return R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); + else + return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); + } + else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! + { + size_t skinnum = (skin_t*)vis->mobj->skin-skins; + return R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); + } + else // Use the defaults + return R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); + } + else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. + return R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); + + return NULL; +} + // // R_DrawVisSprite // mfloorclip and mceilingclip should also be set. @@ -779,79 +823,26 @@ static void R_DrawVisSprite(vissprite_t *vis) colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere. dc_colormap = vis->colormap; - if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash" - { - // translate certain pixels to white - colfunc = colfuncs[COLDRAWFUNC_TRANS]; - if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE); - else if (vis->mobj->type == MT_METALSONIC_BATTLE) - dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE); - } + dc_translation = R_GetSpriteTranslation(vis); + + if (R_SpriteIsFlashing(vis)) // Bosses "flash" + colfunc = colfuncs[COLDRAWFUNC_TRANS]; // translate certain pixels to white else if (vis->mobj->color && vis->transmap) // Color mapping { colfunc = colfuncs[COLDRAWFUNC_TRANSTRANS]; dc_transmap = vis->transmap; - if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - else if (!(vis->cut & SC_PRECIP) - && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD - && (vis->mobj->player->charflags & SF_DASHMODE) - && ((leveltime/2) & 1)) - { - if (vis->mobj->player->charflags & SF_MACHINE) - dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - } - else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_> - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } - else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); } else if (vis->transmap) { colfunc = colfuncs[COLDRAWFUNC_FUZZY]; dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table } - else if (vis->mobj->color) - { - // translate green skin to another color + else if (vis->mobj->color) // translate green skin to another color colfunc = colfuncs[COLDRAWFUNC_TRANS]; - - // New colormap stuff for skins Tails 06-07-2002 - if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized) - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - else if (!(vis->cut & SC_PRECIP) - && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD - && (vis->mobj->player->charflags & SF_DASHMODE) - && ((leveltime/2) & 1)) - { - if (vis->mobj->player->charflags & SF_MACHINE) - dc_translation = R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE); - else - dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE); - } - else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player! - { - size_t skinnum = (skin_t*)vis->mobj->skin-skins; - dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE); - } - else // Use the defaults - dc_translation = R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE); - } else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome. - { colfunc = colfuncs[COLDRAWFUNC_TRANS]; - dc_translation = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE); - } - if (vis->extra_colormap) + if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS)) { if (!dc_colormap) dc_colormap = vis->extra_colormap->colormap; @@ -910,13 +901,16 @@ static void R_DrawVisSprite(vissprite_t *vis) // Split drawing loops for paper and non-paper to reduce conditional checks per sprite if (vis->scalestep) { + fixed_t horzscale = FixedMul(vis->spritexscale, this_scale); + fixed_t scalestep = FixedMul(vis->scalestep, vis->spriteyscale); + pwidth = SHORT(patch->width); // Papersprite drawing loop - for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += vis->scalestep) + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += scalestep) { angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF; - texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / this_scale; + texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / horzscale; if (texturecolumn < 0 || texturecolumn >= pwidth) continue; @@ -927,8 +921,30 @@ static void R_DrawVisSprite(vissprite_t *vis) sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); dc_iscale = (0xffffffffu / (unsigned)spryscale); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); + + localcolfunc (column); + } + } + else if (vis->cut & SC_SHEAR) + { +#ifdef RANGECHECK + pwidth = SHORT(patch->width); +#endif + + // Vertically sheared sprite + for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, dc_texturemid -= vis->shear.tan) + { +#ifdef RANGECHECK + texturecolumn = frac>>FRACBITS; + if (texturecolumn < 0 || texturecolumn >= pwidth) + I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); +#else + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); +#endif + sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); localcolfunc (column); } } @@ -945,9 +961,9 @@ static void R_DrawVisSprite(vissprite_t *vis) texturecolumn = frac>>FRACBITS; if (texturecolumn < 0 || texturecolumn >= pwidth) I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); #else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif localcolfunc (column); } @@ -1012,9 +1028,9 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width)) I_Error("R_DrawPrecipitationSpriteRange: bad texturecolumn"); - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[texturecolumn])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); #else - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[frac>>FRACBITS])); + column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif R_DrawMaskedColumn(column); } @@ -1218,6 +1234,29 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) #undef CHECKZ } +static void R_SkewShadowSprite( + mobj_t *thing, pslope_t *groundslope, + fixed_t groundz, INT32 spriteheight, fixed_t scalemul, + fixed_t *shadowyscale, fixed_t *shadowskew) +{ + // haha let's try some dumb stuff + fixed_t xslope, zslope; + angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; + + xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); + zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); + + //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); + + if (viewz < groundz) + *shadowyscale += FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + else + *shadowyscale -= FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope); + + *shadowyscale = abs((*shadowyscale)); + *shadowskew = xslope; +} + static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz) { vissprite_t *shadow; @@ -1241,45 +1280,27 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, scalemul = FixedMul(FRACUNIT - floordiff/640, scale); - patch = W_CachePatchName("DSHADOW", PU_CACHE); + patch = W_CachePatchName("DSHADOW", PU_SPRITE); xscale = FixedDiv(projection, tz); yscale = FixedDiv(projectiony, tz); shadowxscale = FixedMul(thing->radius*2, scalemul); shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz)); - shadowyscale = min(shadowyscale, shadowxscale) / SHORT(patch->height); - shadowxscale /= SHORT(patch->width); + shadowyscale = min(shadowyscale, shadowxscale) / patch->height; + shadowxscale /= patch->width; shadowskew = 0; if (groundslope) - { - // haha let's try some dumb stuff - fixed_t xslope, zslope; - angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; + R_SkewShadowSprite(thing, groundslope, groundz, patch->height, scalemul, &shadowyscale, &shadowskew); - xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); - zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); - - //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope); - - if (viewz < groundz) - shadowyscale += FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); - else - shadowyscale -= FixedMul(FixedMul(thing->radius*2 / SHORT(patch->height), scalemul), zslope); - - shadowyscale = abs(shadowyscale); - - shadowskew = xslope; - } - - tx -= SHORT(patch->width) * shadowxscale/2; + tx -= patch->width * shadowxscale/2; x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS; if (x1 >= viewwidth) return; - tx += SHORT(patch->width) * shadowxscale; + tx += patch->width * shadowxscale; x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--; if (x2 < 0 || x2 <= x1) return; - if (shadowyscale < FRACUNIT/SHORT(patch->height)) return; // fix some crashes? + if (shadowyscale < FRACUNIT/patch->height) return; // fix some crashes? shadow = R_NewVisSprite(); shadow->patch = patch; @@ -1290,8 +1311,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->dispoffset = vis->dispoffset - 5; shadow->gx = thing->x; shadow->gy = thing->y; - shadow->gzt = groundz + SHORT(patch->height) * shadowyscale / 2; - shadow->gz = shadow->gzt - SHORT(patch->height) * shadowyscale; + shadow->gzt = groundz + patch->height * shadowyscale / 2; + shadow->gz = shadow->gzt - patch->height * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale); @@ -1312,7 +1333,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->startfrac = 0; //shadow->xiscale = 0x7ffffff0 / (shadow->xscale/2); - shadow->xiscale = (SHORT(patch->width)<<FRACBITS)/(x2-x1+1); // fuck it + shadow->xiscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it if (shadow->x1 > x1) shadow->startfrac += shadow->xiscale*(shadow->x1-x1); @@ -1321,28 +1342,32 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, x1 += (x2-x1)/2; shadow->shear.offset = shadow->x1-x1; - if (thing->subsector->sector->numlights) + if (thing->renderflags & RF_NOCOLORMAPS) + shadow->extra_colormap = NULL; + else { - INT32 lightnum; - light = thing->subsector->sector->numlights - 1; - - // R_GetPlaneLight won't work on sloped lights! - for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); - if (h <= shadow->gzt) { - light = lightnum - 1; - break; + if (thing->subsector->sector->numlights) + { + INT32 lightnum; + light = thing->subsector->sector->numlights - 1; + + // R_GetPlaneLight won't work on sloped lights! + for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); + if (h <= shadow->gzt) { + light = lightnum - 1; + break; + } } } - //light = R_GetPlaneLight(thing->subsector->sector, shadow->gzt, false); - } - if (thing->subsector->sector->numlights) - shadow->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; - else - shadow->extra_colormap = thing->subsector->sector->extra_colormap; + if (thing->subsector->sector->numlights) + shadow->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; + else + shadow->extra_colormap = thing->subsector->sector->extra_colormap; + } - shadow->transmap = transtables + (trans<<FF_TRANSSHIFT); + shadow->transmap = R_GetTranslucencyTable(trans + 1); shadow->colormap = scalelight[0][0]; // full dark! objectsdrawn++; @@ -1358,7 +1383,9 @@ static void R_ProjectSprite(mobj_t *thing) mobj_t *oldthing = thing; fixed_t tr_x, tr_y; fixed_t tx, tz; - fixed_t xscale, yscale, sortscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!! + fixed_t sortscale, sortsplat = 0; + fixed_t sort_x = 0, sort_y = 0, sort_z; INT32 x1, x2; @@ -1371,13 +1398,15 @@ static void R_ProjectSprite(mobj_t *thing) size_t frame, rot; UINT16 flip; - boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !(thing->frame & FF_VERTICALFLIP)); + boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing)); boolean mirrored = thing->mirrored; - boolean hflip = (!(thing->frame & FF_HORIZONTALFLIP) != !mirrored); + boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored); INT32 lindex; + INT32 trans; vissprite_t *vis; + patch_t *patch; spritecut_e cut = SC_NONE; @@ -1386,22 +1415,29 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t scalestep; fixed_t offset, offset2; + fixed_t sheartan = 0; + fixed_t shadowscale = FRACUNIT; fixed_t basetx; // drop shadows - boolean papersprite = !!(thing->frame & FF_PAPERSPRITE); - fixed_t paperoffset = 0, paperdistance = 0; angle_t centerangle = 0; + boolean shadowdraw, shadoweffects, shadowskew; + boolean splat = R_ThingIsFloorSprite(thing); + boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat); + fixed_t paperoffset = 0, paperdistance = 0; + angle_t centerangle = 0; INT32 dispoffset = thing->info->dispoffset; //SoM: 3/17/2000 - fixed_t gz, gzt; + fixed_t gz = 0, gzt = 0; INT32 heightsec, phs; INT32 light = 0; fixed_t this_scale = thing->scale; + fixed_t spritexscale, spriteyscale; // rotsprite fixed_t spr_width, spr_height; fixed_t spr_offset, spr_topoffset; + #ifdef ROTSPRITE patch_t *rotsprite = NULL; INT32 rollangle = 0; @@ -1448,7 +1484,7 @@ static void R_ProjectSprite(mobj_t *thing) thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; #ifdef ROTSPRITE - sprinfo = NULL; + sprinfo = &spriteinfo[thing->sprite]; #endif frame = thing->frame&FF_FRAMEMASK; } @@ -1457,7 +1493,7 @@ static void R_ProjectSprite(mobj_t *thing) { sprdef = &sprites[thing->sprite]; #ifdef ROTSPRITE - sprinfo = NULL; + sprinfo = &spriteinfo[thing->sprite]; #endif if (frame >= sprdef->numframes) @@ -1472,6 +1508,7 @@ static void R_ProjectSprite(mobj_t *thing) thing->sprite = states[S_UNKNOWN].sprite; thing->frame = states[S_UNKNOWN].frame; sprdef = &sprites[thing->sprite]; + sprinfo = &spriteinfo[thing->sprite]; frame = thing->frame&FF_FRAMEMASK; } } @@ -1529,19 +1566,28 @@ static void R_ProjectSprite(mobj_t *thing) spr_offset = spritecachedinfo[lump].offset; spr_topoffset = spritecachedinfo[lump].topoffset; + //Fab: lumppat is the lump number of the patch to use, this is different + // than lumpid for sprites-in-pwad : the graphics are patched + patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE); + #ifdef ROTSPRITE - if (thing->rollangle) + if (thing->rollangle + && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE))) { rollangle = R_GetRollAngle(thing->rollangle); - if (!(sprframe->rotsprite.cached & (1<<rot))) - R_CacheRotSprite(thing->sprite, frame, sprinfo, sprframe, rot, flip); - rotsprite = sprframe->rotsprite.patch[rot][rollangle]; + rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle); + if (rotsprite != NULL) { - spr_width = SHORT(rotsprite->width) << FRACBITS; - spr_height = SHORT(rotsprite->height) << FRACBITS; - spr_offset = SHORT(rotsprite->leftoffset) << FRACBITS; - spr_topoffset = SHORT(rotsprite->topoffset) << FRACBITS; + patch = rotsprite; + cut |= SC_ISROTATED; + + spr_width = rotsprite->width << FRACBITS; + spr_height = rotsprite->height << FRACBITS; + spr_offset = rotsprite->leftoffset << FRACBITS; + spr_topoffset = rotsprite->topoffset << FRACBITS; + spr_topoffset += FEETADJUST; + // flip -> rotate, not rotate -> flip flip = 0; } @@ -1551,12 +1597,34 @@ static void R_ProjectSprite(mobj_t *thing) flip = !flip != !hflip; // calculate edges of the shape + spritexscale = thing->spritexscale; + spriteyscale = thing->spriteyscale; + if (spritexscale < 1 || spriteyscale < 1) + return; + + if (thing->renderflags & RF_ABSOLUTEOFFSETS) + { + spr_offset = thing->spritexoffset; + spr_topoffset = thing->spriteyoffset; + } + else + { + SINT8 flipoffset = 1; + + if ((thing->renderflags & RF_FLIPOFFSETS) && flip) + flipoffset = -1; + + spr_offset += thing->spritexoffset * flipoffset; + spr_topoffset += thing->spriteyoffset * flipoffset; + } + if (flip) offset = spr_offset - spr_width; else offset = -spr_offset; - offset = FixedMul(offset, this_scale); - offset2 = FixedMul(spr_width, this_scale); + + offset = FixedMul(offset, FixedMul(spritexscale, this_scale)); + offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale)); if (papersprite) { @@ -1663,6 +1731,15 @@ static void R_ProjectSprite(mobj_t *thing) return; } + // Adjust the sort scale if needed + if (splat) + { + sort_z = (patch->height - patch->topoffset) * FRACUNIT; + ang = (viewangle >> ANGLETOFINESHIFT); + sort_x = FixedMul(FixedMul(FixedMul(spritexscale, this_scale), sort_z), FINECOSINE(ang)); + sort_y = FixedMul(FixedMul(FixedMul(spriteyscale, this_scale), sort_z), FINESINE(ang)); + } + if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) { fixed_t linkscale; @@ -1672,8 +1749,8 @@ static void R_ProjectSprite(mobj_t *thing) if (! R_ThingVisible(thing)) return; - tr_x = thing->x - viewx; - tr_y = thing->y - viewy; + tr_x = (thing->x + sort_x) - viewx; + tr_y = (thing->y + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); @@ -1684,7 +1761,23 @@ static void R_ProjectSprite(mobj_t *thing) dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0) sortscale = linkscale; // now make sure it's linked - cut = SC_LINKDRAW; + cut |= SC_LINKDRAW; + } + else if (splat) + { + tr_x = (thing->x + sort_x) - viewx; + tr_y = (thing->y + sort_y) - viewy; + sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + sortscale = FixedDiv(projectiony, sort_z); + } + + // Calculate the splat's sortscale + if (splat) + { + tr_x = (thing->x - sort_x) - viewx; + tr_y = (thing->y - sort_y) - viewy; + sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); + sortsplat = FixedDiv(projectiony, sort_z); } // PORTAL SPRITE CLIPPING @@ -1697,19 +1790,93 @@ static void R_ProjectSprite(mobj_t *thing) return; } - //SoM: 3/17/2000: Disregard sprites that are out of view.. - if (vflip) + // Determine the translucency value. + if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) + trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK + else if (oldthing->frame & FF_TRANSMASK) { - // 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(spr_topoffset, this_scale); - gzt = gz + FixedMul(spr_height, this_scale); + trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT; + if (oldthing->blendmode == AST_TRANSLUCENT && trans >= NUMTRANSMAPS) + return; } else + trans = 0; + + // Check if this sprite needs to be rendered like a shadow + shadowdraw = (!!(thing->renderflags & RF_SHADOWDRAW) && !(papersprite || splat)); + shadoweffects = (thing->renderflags & RF_SHADOWEFFECTS); + shadowskew = (shadowdraw && thing->standingslope); + + if (shadowdraw || shadoweffects) + { + fixed_t groundz = R_GetShadowZ(thing, NULL); + boolean isflipped = (thing->eflags & MFE_VERTICALFLIP); + + if (shadoweffects) + { + mobj_t *caster = thing->target; + + if (caster && !P_MobjWasRemoved(caster)) + { + fixed_t floordiff; + + if (abs(groundz-viewz)/tz > 4) + return; // Prevent stretchy shadows and possible crashes + + floordiff = abs((isflipped ? caster->height : 0) + caster->z - groundz); + trans += ((floordiff / (100*FRACUNIT)) + 3); + shadowscale = FixedMul(FRACUNIT - floordiff/640, caster->scale); + } + else + trans += 3; + + if (trans >= NUMTRANSMAPS) + return; + + trans--; + } + + if (shadowdraw) + { + spritexscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spritexscale)); + spriteyscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spriteyscale)); + spriteyscale = FixedMul(spriteyscale, FixedDiv(abs(groundz - viewz), tz)); + spriteyscale = min(spriteyscale, spritexscale) / patch->height; + spritexscale /= patch->width; + } + else + { + spritexscale = FixedMul(shadowscale, spritexscale); + spriteyscale = FixedMul(shadowscale, spriteyscale); + } + + if (shadowskew) + { + R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan); + + gzt = (isflipped ? (thing->z + thing->height) : thing->z) + patch->height * spriteyscale / 2; + gz = gzt - patch->height * spriteyscale; + + cut |= SC_SHEAR; + } + } + + if (!shadowskew) { - gzt = oldthing->z + FixedMul(spr_topoffset, this_scale); - gz = gzt - FixedMul(spr_height, this_scale); + //SoM: 3/17/2000: Disregard sprites that are out of view.. + if (vflip) + { + // 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(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); + } + else + { + gzt = oldthing->z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); + } } if (thing->subsector->sector->cullheight) @@ -1721,12 +1888,13 @@ static void R_ProjectSprite(mobj_t *thing) if (thing->subsector->sector->numlights) { INT32 lightnum; + fixed_t top = (splat) ? gz : gzt; light = thing->subsector->sector->numlights - 1; // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); - if (h <= gzt) { + if (h <= top) { light = lightnum - 1; break; } @@ -1762,21 +1930,23 @@ static void R_ProjectSprite(mobj_t *thing) // store information in a vissprite vis = R_NewVisSprite(); + vis->renderflags = thing->renderflags; + vis->rotateflags = sprframe->rotate; vis->heightsec = heightsec; //SoM: 3/17/2000 vis->mobjflags = thing->flags; - vis->scale = yscale; //<<detailshift; vis->sortscale = sortscale; + vis->sortsplat = sortsplat; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 vis->gx = thing->x; vis->gy = thing->y; vis->gz = gz; vis->gzt = gzt; - vis->texturemid = vis->gzt - viewz; + vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; vis->paperoffset = paperoffset; vis->paperdistance = paperdistance; vis->centerangle = centerangle; - vis->shear.tan = 0; + vis->shear.tan = sheartan; vis->shear.offset = 0; vis->mobj = thing; // Easy access! Tails 06-07-2002 @@ -1784,17 +1954,34 @@ static void R_ProjectSprite(mobj_t *thing) vis->x1 = x1 < portalclipstart ? portalclipstart : x1; vis->x2 = x2 >= portalclipend ? portalclipend-1 : x2; - vis->xscale = xscale; //SoM: 4/17/2000 vis->sector = thing->subsector->sector; vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS); vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS); vis->cut = cut; + if (thing->subsector->sector->numlights) vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap; else vis->extra_colormap = thing->subsector->sector->extra_colormap; - iscale = FixedDiv(FRACUNIT, xscale); + vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 + vis->scale = FixedMul(spriteyscale, yscale); //<<detailshift; + + vis->spritexscale = spritexscale; + vis->spriteyscale = spriteyscale; + vis->spritexoffset = spr_offset; + vis->spriteyoffset = spr_topoffset; + + if (shadowdraw || shadoweffects) + { + iscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it + x1 += (x2-x1)/2; // reusing x1 variable + vis->shear.offset = vis->x1-x1; + } + else + iscale = FixedDiv(FRACUNIT, vis->xscale); + + vis->shadowscale = shadowscale; if (flip) { @@ -1809,41 +1996,31 @@ static void R_ProjectSprite(mobj_t *thing) if (vis->x1 > x1) { - vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1); - vis->scale += scalestep*(vis->x1 - x1); + vis->startfrac += FixedDiv(vis->xiscale, this_scale) * (vis->x1 - x1); + vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1); } - //Fab: lumppat is the lump number of the patch to use, this is different - // than lumpid for sprites-in-pwad : the graphics are patched -#ifdef ROTSPRITE - if (rotsprite != NULL) - vis->patch = rotsprite; + if ((oldthing->blendmode != AST_COPY) && cv_translucency.value) + vis->transmap = R_GetBlendTable(oldthing->blendmode, trans); else -#endif - vis->patch = W_CachePatchNum(sprframe->lumppat[rot], PU_CACHE); - -// -// determine the colormap (lightlevel & special effects) -// - vis->transmap = NULL; - - // specific translucency - if (!cv_translucency.value) - ; // no translucency - else if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility) - vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK - else if (oldthing->frame & FF_TRANSMASK) - vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000; + vis->transmap = NULL; - if (oldthing->frame & FF_FULLBRIGHT || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) + if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) vis->cut |= SC_FULLBRIGHT; + else if (R_ThingIsFullDark(oldthing)) + vis->cut |= SC_FULLDARK; + // + // determine the colormap (lightlevel & special effects) + // if (vis->cut & SC_FULLBRIGHT && (!vis->extra_colormap || !(vis->extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES))) { // full bright: goggles vis->colormap = colormaps; } + else if (vis->cut & SC_FULLDARK) + vis->colormap = scalelight[0][0]; else { // diminished light @@ -1857,8 +2034,12 @@ static void R_ProjectSprite(mobj_t *thing) if (vflip) vis->cut |= SC_VFLIP; + if (splat) + vis->cut |= SC_SPLAT; // I like ya cut g - if (thing->subsector->sector->numlights) + vis->patch = patch; + + if (thing->subsector->sector->numlights && !(shadowdraw || splat)) R_SplitSprite(vis); if (oldthing->shadowscale && cv_shadow.value) @@ -2000,7 +2181,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 = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE); + vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE); // specific translucency if (thing->frame & FF_TRANSMASK) @@ -2464,13 +2645,45 @@ static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean temps } else if (r2->sprite) { - if (r2->sprite->x1 > rover->x2 || r2->sprite->x2 < rover->x1) - continue; - if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) - continue; + boolean infront = (r2->sprite->sortscale > rover->sortscale + || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)); + + if (rover->cut & SC_SPLAT || r2->sprite->cut & SC_SPLAT) + { + fixed_t scale1 = (rover->cut & SC_SPLAT ? rover->sortsplat : rover->sortscale); + fixed_t scale2 = (r2->sprite->cut & SC_SPLAT ? r2->sprite->sortsplat : r2->sprite->sortscale); + boolean behind = (scale2 > scale1 || (scale2 == scale1 && r2->sprite->dispoffset > rover->dispoffset)); + + if (!behind) + { + fixed_t z1 = 0, z2 = 0; + + if (rover->mobj->z - viewz > 0) + { + z1 = rover->pz; + z2 = r2->sprite->pz; + } + else + { + z1 = r2->sprite->pz; + z2 = rover->pz; + } + + z1 -= viewz; + z2 -= viewz; - if (r2->sprite->sortscale > rover->sortscale - || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset)) + infront = (z1 >= z2); + } + } + else + { + if (r2->sprite->x1 > rover->x2 || r2->sprite->x2 < rover->x1) + continue; + if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt) + continue; + } + + if (infront) { entry = R_CreateDrawNode(NULL); (entry->prev = r2->prev)->next = entry; @@ -2556,7 +2769,11 @@ static void R_DrawSprite(vissprite_t *spr) { mfloorclip = spr->clipbot; mceilingclip = spr->cliptop; - R_DrawVisSprite(spr); + + if (spr->cut & SC_SPLAT) + R_DrawFloorSprite(spr); + else + R_DrawVisSprite(spr); } // Special drawer for precipitation sprites Tails 08-18-2002 @@ -2567,207 +2784,212 @@ static void R_DrawPrecipitationSprite(vissprite_t *spr) R_DrawPrecipitationVisSprite(spr); } -// R_ClipSprites +// R_ClipVisSprite // Clips vissprites without drawing, so that portals can work. -Red -void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) +void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal) { - vissprite_t *spr; - for (; clippedvissprites < visspritecount; clippedvissprites++) - { - drawseg_t *ds; - INT32 x; - INT32 r1; - INT32 r2; - fixed_t scale; - fixed_t lowscale; - INT32 silhouette; - - spr = R_GetVisSprite(clippedvissprites); - - for (x = spr->x1; x <= spr->x2; x++) - spr->clipbot[x] = spr->cliptop[x] = -2; - - // Scan drawsegs from end to start for obscuring segs. - // The first drawseg that has a greater scale - // is the clip seg. - //SoM: 4/8/2000: - // Pointer check was originally nonportable - // and buggy, by going past LEFT end of array: + drawseg_t *ds; + INT32 x; + INT32 r1; + INT32 r2; + fixed_t scale; + fixed_t lowscale; + INT32 silhouette; + + for (x = x1; x <= x2; x++) + spr->clipbot[x] = spr->cliptop[x] = -2; + + // Scan drawsegs from end to start for obscuring segs. + // The first drawseg that has a greater scale + // is the clip seg. + //SoM: 4/8/2000: + // Pointer check was originally nonportable + // and buggy, by going past LEFT end of array: + + // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code + for (ds = ds_p; ds-- > dsstart;) + { + // determine if the drawseg obscures the sprite + if (ds->x1 > x2 || + ds->x2 < x1 || + (!ds->silhouette + && !ds->maskedtexturecol)) + { + // does not cover sprite + continue; + } - // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code - for (ds = ds_p; ds-- > dsstart;) + if (ds->portalpass != 66) { - // determine if the drawseg obscures the sprite - if (ds->x1 > spr->x2 || - ds->x2 < spr->x1 || - (!ds->silhouette - && !ds->maskedtexturecol)) + if (ds->portalpass > 0 && ds->portalpass <= portalrender) + continue; // is a portal + + if (ds->scale1 > ds->scale2) { - // does not cover sprite - continue; + lowscale = ds->scale2; + scale = ds->scale1; } - - if (ds->portalpass != 66) + else { - if (ds->portalpass > 0 && ds->portalpass <= portalrender) - continue; // is a portal - - if (ds->scale1 > ds->scale2) - { - lowscale = ds->scale2; - scale = ds->scale1; - } - else - { - lowscale = ds->scale1; - scale = ds->scale2; - } + lowscale = ds->scale1; + scale = ds->scale2; + } - if (scale < spr->sortscale || - (lowscale < spr->sortscale && - !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) - { - // masked mid texture? - /*if (ds->maskedtexturecol) - R_RenderMaskedSegRange (ds, r1, r2);*/ - // seg is behind sprite - continue; - } + if (scale < spr->sortscale || + (lowscale < spr->sortscale && + !R_PointOnSegSide (spr->gx, spr->gy, ds->curline))) + { + // masked mid texture? + /*if (ds->maskedtexturecol) + R_RenderMaskedSegRange (ds, r1, r2);*/ + // seg is behind sprite + continue; } + } - r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1; - r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2; + r1 = ds->x1 < x1 ? x1 : ds->x1; + r2 = ds->x2 > x2 ? x2 : ds->x2; - // clip this piece of the sprite - silhouette = ds->silhouette; + // clip this piece of the sprite + silhouette = ds->silhouette; - if (spr->gz >= ds->bsilheight) - silhouette &= ~SIL_BOTTOM; + if (spr->gz >= ds->bsilheight) + silhouette &= ~SIL_BOTTOM; - if (spr->gzt <= ds->tsilheight) - silhouette &= ~SIL_TOP; + if (spr->gzt <= ds->tsilheight) + silhouette &= ~SIL_TOP; - if (silhouette == SIL_BOTTOM) + if (silhouette == SIL_BOTTOM) + { + // bottom sil + for (x = r1; x <= r2; x++) + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + } + else if (silhouette == SIL_TOP) + { + // top sil + for (x = r1; x <= r2; x++) + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; + } + else if (silhouette == (SIL_TOP|SIL_BOTTOM)) + { + // both + for (x = r1; x <= r2; x++) { - // bottom sil - for (x = r1; x <= r2; x++) - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->clipbot[x] == -2) + spr->clipbot[x] = ds->sprbottomclip[x]; + if (spr->cliptop[x] == -2) + spr->cliptop[x] = ds->sprtopclip[x]; } - else if (silhouette == SIL_TOP) - { - // top sil - for (x = r1; x <= r2; x++) - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; + } + } + //SoM: 3/17/2000: Clip sprites in water. + if (spr->heightsec != -1) // only things in specially marked sectors + { + fixed_t mh, h; + INT32 phs = viewplayer->mo->subsector->sector->heightsec; + if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && + (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) + { + if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; } - else if (silhouette == (SIL_TOP|SIL_BOTTOM)) + else // clip top { - // both - for (x = r1; x <= r2; x++) - { - if (spr->clipbot[x] == -2) - spr->clipbot[x] = ds->sprbottomclip[x]; - if (spr->cliptop[x] == -2) - spr->cliptop[x] = ds->sprtopclip[x]; - } + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; } } - //SoM: 3/17/2000: Clip sprites in water. - if (spr->heightsec != -1) // only things in specially marked sectors + + if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && + (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && + (h >>= FRACBITS) < viewheight) { - fixed_t mh, h; - INT32 phs = viewplayer->mo->subsector->sector->heightsec; - if ((mh = sectors[spr->heightsec].floorheight) > spr->gz && - (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) - { - if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight)) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } + if (phs != -1 && viewz >= sectors[phs].ceilingheight) + { // clip bottom + for (x = x1; x <= x2; x++) + if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) + spr->clipbot[x] = (INT16)h; } - - if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt && - (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 && - (h >>= FRACBITS) < viewheight) + else // clip top { - if (phs != -1 && viewz >= sectors[phs].ceilingheight) - { // clip bottom - for (x = spr->x1; x <= spr->x2; x++) - if (spr->clipbot[x] == -2 || h < spr->clipbot[x]) - spr->clipbot[x] = (INT16)h; - } - else // clip top - { - for (x = spr->x1; x <= spr->x2; x++) - if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) - spr->cliptop[x] = (INT16)h; - } + for (x = x1; x <= x2; x++) + if (spr->cliptop[x] == -2 || h > spr->cliptop[x]) + spr->cliptop[x] = (INT16)h; } } - if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) + } + if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) - spr->cliptop[x] = spr->szt; + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; - if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) - spr->clipbot[x] = spr->sz; - } + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; } - else if (spr->cut & SC_TOP) + } + else if (spr->cut & SC_TOP) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) - spr->cliptop[x] = spr->szt; - } + if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x]) + spr->cliptop[x] = spr->szt; } - else if (spr->cut & SC_BOTTOM) + } + else if (spr->cut & SC_BOTTOM) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) - spr->clipbot[x] = spr->sz; - } + if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x]) + spr->clipbot[x] = spr->sz; } + } - // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? + // all clipping has been performed, so store the values - what, did you think we were drawing them NOW? - // check for unclipped columns - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] == -2) - spr->clipbot[x] = (INT16)viewheight; + // check for unclipped columns + for (x = x1; x <= x2; x++) + { + if (spr->clipbot[x] == -2) + spr->clipbot[x] = (INT16)viewheight; - if (spr->cliptop[x] == -2) - //Fab : 26-04-98: was -1, now clips against console bottom - spr->cliptop[x] = (INT16)con_clipviewtop; - } + if (spr->cliptop[x] == -2) + //Fab : 26-04-98: was -1, now clips against console bottom + spr->cliptop[x] = (INT16)con_clipviewtop; + } - if (portal) + if (portal) + { + for (x = x1; x <= x2; x++) { - for (x = spr->x1; x <= spr->x2; x++) - { - if (spr->clipbot[x] > portal->floorclip[x - portal->start]) - spr->clipbot[x] = portal->floorclip[x - portal->start]; - if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) - spr->cliptop[x] = portal->ceilingclip[x - portal->start]; - } + if (spr->clipbot[x] > portal->floorclip[x - portal->start]) + spr->clipbot[x] = portal->floorclip[x - portal->start]; + if (spr->cliptop[x] < portal->ceilingclip[x - portal->start]) + spr->cliptop[x] = portal->ceilingclip[x - portal->start]; } } } +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal) +{ + for (; clippedvissprites < visspritecount; clippedvissprites++) + { + vissprite_t *spr = R_GetVisSprite(clippedvissprites); + INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1; + INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2; + R_ClipVisSprite(spr, x1, x2, dsstart, portal); + } +} + /* Check if thing may be drawn from our current view. */ boolean R_ThingVisible (mobj_t *thing) { @@ -2817,6 +3039,36 @@ boolean R_PrecipThingVisible (precipmobj_t *precipthing, return ( approx_dist <= limit_dist ); } +boolean R_ThingHorizontallyFlipped(mobj_t *thing) +{ + return (thing->frame & FF_HORIZONTALFLIP || thing->renderflags & RF_HORIZONTALFLIP); +} + +boolean R_ThingVerticallyFlipped(mobj_t *thing) +{ + return (thing->frame & FF_VERTICALFLIP || thing->renderflags & RF_VERTICALFLIP); +} + +boolean R_ThingIsPaperSprite(mobj_t *thing) +{ + return (thing->frame & FF_PAPERSPRITE || thing->renderflags & RF_PAPERSPRITE); +} + +boolean R_ThingIsFloorSprite(mobj_t *thing) +{ + return (thing->flags2 & MF2_SPLAT || thing->renderflags & RF_FLOORSPRITE); +} + +boolean R_ThingIsFullBright(mobj_t *thing) +{ + return (thing->frame & FF_FULLBRIGHT || thing->renderflags & RF_FULLBRIGHT); +} + +boolean R_ThingIsFullDark(mobj_t *thing) +{ + return (thing->renderflags & RF_FULLDARK); +} + // // R_DrawMasked // diff --git a/src/r_things.h b/src/r_things.h index c9a48dd2813271ab92c5af93f2e6e5934c4f4194..d15ae818c4c273dee396fe9c6b7919a95c87b98b 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -15,6 +15,7 @@ #define __R_THINGS__ #include "r_plane.h" +#include "r_patch.h" #include "r_picformats.h" #include "r_portal.h" #include "r_defs.h" @@ -64,7 +65,6 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope); void R_AddSprites(sector_t *sec, INT32 lightlevel); void R_InitSprites(void); void R_ClearSprites(void); -void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); boolean R_ThingVisible (mobj_t *thing); @@ -75,6 +75,15 @@ boolean R_ThingVisibleWithinDist (mobj_t *thing, boolean R_PrecipThingVisible (precipmobj_t *precipthing, fixed_t precip_draw_dist); +boolean R_ThingHorizontallyFlipped (mobj_t *thing); +boolean R_ThingVerticallyFlipped (mobj_t *thing); + +boolean R_ThingIsPaperSprite (mobj_t *thing); +boolean R_ThingIsFloorSprite (mobj_t *thing); + +boolean R_ThingIsFullBright (mobj_t *thing); +boolean R_ThingIsFullDark (mobj_t *thing); + // -------------- // MASKED DRAWING // -------------- @@ -107,19 +116,23 @@ void R_DrawMasked(maskcount_t* masks, UINT8 nummasks); typedef enum { // actual cuts - SC_NONE = 0, - SC_TOP = 1, - SC_BOTTOM = 1<<1, + SC_NONE = 0, + SC_TOP = 1, + SC_BOTTOM = 1<<1, // other flags - SC_PRECIP = 1<<2, - SC_LINKDRAW = 1<<3, + SC_PRECIP = 1<<2, + SC_LINKDRAW = 1<<3, SC_FULLBRIGHT = 1<<4, - SC_VFLIP = 1<<5, - SC_ISSCALED = 1<<6, - SC_SHADOW = 1<<7, + SC_FULLDARK = 1<<5, + SC_VFLIP = 1<<6, + SC_ISSCALED = 1<<7, + SC_ISROTATED = 1<<8, + SC_SHADOW = 1<<9, + SC_SHEAR = 1<<10, + SC_SPLAT = 1<<11, // masks - SC_CUTMASK = SC_TOP|SC_BOTTOM, - SC_FLAGMASK = ~SC_CUTMASK + SC_CUTMASK = SC_TOP|SC_BOTTOM, + SC_FLAGMASK = ~SC_CUTMASK } spritecut_e; // A vissprite_t is a thing that will be drawn during a refresh, @@ -141,7 +154,9 @@ typedef struct vissprite_s fixed_t gz, gzt; // global bottom/top for silhouette clipping and sorting with 3D floors fixed_t startfrac; // horizontal position of x1 - fixed_t scale, sortscale; // sortscale only differs from scale for paper sprites and MF2_LINKDRAW + fixed_t scale; + fixed_t sortscale; // sortscale only differs from scale for paper sprites, floor sprites, and MF2_LINKDRAW + fixed_t sortsplat; // the sortscale from behind the floor sprite fixed_t scalestep; // only for paper sprites, 0 otherwise fixed_t paperoffset, paperdistance; // for paper sprites, offset/dist relative to the angle fixed_t xiscale; // negative if flipped @@ -174,6 +189,13 @@ typedef struct vissprite_s INT16 sz, szt; spritecut_e cut; + UINT32 renderflags; + UINT8 rotateflags; + + fixed_t spritexscale, spriteyscale; + fixed_t spritexoffset, spriteyoffset; + + fixed_t shadowscale; INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; @@ -182,6 +204,12 @@ typedef struct vissprite_s extern UINT32 visspritecount; +void R_ClipSprites(drawseg_t* dsstart, portal_t* portal); +void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal); + +boolean R_SpriteIsFlashing(vissprite_t *vis); +UINT8 *R_GetSpriteTranslation(vissprite_t *vis); + // ---------- // DRAW NODES // ---------- diff --git a/src/s_sound.c b/src/s_sound.c index 793794aa7c70bcabbcd02e7fade906e108e39bb1..36bd454c104b02867c29d3f16f22f639ed06dc97 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -29,10 +29,7 @@ #include "fastcmp.h" #include "m_misc.h" // for tunes command #include "m_cond.h" // for conditionsets - -#ifdef HAVE_LUA_MUSICPLUS #include "lua_hook.h" // MusicChange hook -#endif #ifdef HW3SOUND // 3D Sound Interface @@ -2272,10 +2269,8 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32 return; strncpy(newmusic, mmusic, 7); -#ifdef HAVE_LUA_MUSICPLUS - if(LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) + if (LUAh_MusicChange(music_name, newmusic, &mflags, &looping, &position, &prefadems, &fadeinms)) return; -#endif newmusic[6] = 0; // No Music (empty string) diff --git a/src/screen.c b/src/screen.c index 048480fb27d8d6a54024cac0ff5664f72862e711..f14cf4bf6c3065790f0cad4ea413a3a5749606dd 100644 --- a/src/screen.c +++ b/src/screen.c @@ -28,6 +28,7 @@ #include "d_main.h" #include "d_clisrv.h" #include "f_finale.h" +#include "y_inter.h" // usebuffer #include "i_sound.h" // closed captions #include "s_sound.h" // ditto #include "g_game.h" // ditto @@ -63,15 +64,15 @@ consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); -static void SCR_ActuallyChangeRenderer(void); -static CV_PossibleValue_t cv_renderer_t[] = { +CV_PossibleValue_t cv_renderer_t[] = { {1, "Software"}, #ifdef HWRENDER {2, "OpenGL"}, #endif {0, NULL} }; -consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_ChangeRenderer); + +consvar_t cv_renderer = CVAR_INIT ("renderer", "Software", CV_SAVE|CV_NOLUA|CV_CALL, cv_renderer_t, SCR_SetTargetRenderer); static void SCR_ChangeFullscreen(void); @@ -121,34 +122,34 @@ void SCR_SetDrawFuncs(void) colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8; spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8; + spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8; + spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8; spanfuncs[SPANDRAWFUNC_SPLAT] = R_DrawSplat_8; spanfuncs[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_8; - spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; -#ifndef NOWATER + spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8; + spanfuncs[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8; + spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8; spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8; -#endif - spanfuncs[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_8; - spanfuncs[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_8; -#ifndef NOWATER spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_8; -#endif - spanfuncs[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_8; + spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; // Lactozilla: Non-powers-of-two spanfuncs_npo2[BASEDRAWFUNC] = R_DrawSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_SPLAT] = R_DrawSplat_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANSSPLAT] = R_DrawTranslucentSplat_NPO2_8; - spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed -#ifndef NOWATER + spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_SPRITE] = R_DrawFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8; -#endif - spanfuncs_npo2[SPANDRAWFUNC_TILTED] = R_DrawTiltedSpan_NPO2_8; - spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANS] = R_DrawTiltedTranslucentSpan_NPO2_8; -#ifndef NOWATER spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8; -#endif - spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPLAT] = R_DrawTiltedSplat_NPO2_8; + spanfuncs_npo2[SPANDRAWFUNC_FOG] = NULL; // Not needed #ifdef RUSEASM if (R_ASM) @@ -202,14 +203,15 @@ void SCR_SetMode(void) // Lactozilla: Renderer switching if (setrenderneeded) { - Z_PreparePatchFlush(); - needpatchflush = true; - needpatchrecache = true; + // stop recording movies (APNG only) + if (setrenderneeded && (moviemode == MM_APNG)) + M_StopMovie(); + VID_CheckRenderer(); - if (!setmodeneeded) - VID_SetMode(vid.modenum); + vid.recalc = 1; } + // Set the video mode in the video interface. if (setmodeneeded) VID_SetMode(--setmodeneeded); @@ -279,34 +281,9 @@ void SCR_Startup(void) vid.modenum = 0; - vid.dupx = vid.width / BASEVIDWIDTH; - vid.dupy = vid.height / BASEVIDHEIGHT; - vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); - vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - -#ifdef HWRENDER - if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl -#endif - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); - - vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; - vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif - - vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; - vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif - - vid.baseratio = FRACUNIT; - V_Init(); + V_Recalc(); + CV_RegisterVar(&cv_ticrate); CV_RegisterVar(&cv_constextsize); @@ -323,38 +300,7 @@ void SCR_Recalc(void) // bytes per pixel quick access scr_bpp = vid.bpp; - // scale 1,2,3 times in x and y the patches for the menus and overlays... - // calculated once and for all, used by routines in v_video.c - vid.dupx = vid.width / BASEVIDWIDTH; - vid.dupy = vid.height / BASEVIDHEIGHT; - vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); - vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); - vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); - -#ifdef HWRENDER - //if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl - // 13/11/18: - // The above is no longer necessary, since we want OpenGL to be just like software now - // -- Monster Iestyn -#endif - vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); - - //vid.baseratio = FixedDiv(vid.height << FRACBITS, BASEVIDHEIGHT << FRACBITS); - vid.baseratio = FRACUNIT; - - vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; - vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; -#ifdef HWRENDER - vid.fmeddupx = vid.meddupx*FRACUNIT; - vid.fmeddupy = vid.meddupy*FRACUNIT; -#endif - - vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; - vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; -#ifdef HWRENDER - vid.fsmalldupx = vid.smalldupx*FRACUNIT; - vid.fsmalldupy = vid.smalldupy*FRACUNIT; -#endif + V_Recalc(); // toggle off (then back on) the automap because some screensize-dependent values will // be calculated next time the automap is activated. @@ -374,6 +320,12 @@ void SCR_Recalc(void) // vid.recalc lasts only for the next refresh... con_recalc = true; am_recalc = true; + +#ifdef HWRENDER + // Shoot! The screen texture was flushed! + if ((rendermode == render_opengl) && (gamestate == GS_INTERMISSION)) + usebuffer = false; +#endif } // Check for screen cmd-line parms: to force a resolution. @@ -411,7 +363,16 @@ void SCR_CheckDefaultMode(void) setmodeneeded = VID_GetModeForSize(cv_scr_width.value, cv_scr_height.value) + 1; } - SCR_ActuallyChangeRenderer(); + if (cv_renderer.value != (signed)rendermode) + { + if (chosenrendermode == render_none) // nothing set at command line + SCR_ChangeRenderer(); + else + { + // Set cv_renderer to the current render mode + CV_StealthSetValue(&cv_renderer, rendermode); + } + } } // sets the modenum as the new default video mode to be saved in the config file @@ -441,64 +402,33 @@ void SCR_ChangeFullscreen(void) #endif } -static int target_renderer = 0; +void SCR_SetTargetRenderer(void) +{ + if (!con_refresh) + SCR_ChangeRenderer(); +} -void SCR_ActuallyChangeRenderer(void) +void SCR_ChangeRenderer(void) { - setrenderneeded = target_renderer; + if ((signed)rendermode == cv_renderer.value) + return; #ifdef HWRENDER - // Well, it didn't even load anyway. - if ((vid_opengl_state == -1) && (setrenderneeded == render_opengl)) + // Check if OpenGL loaded successfully (or wasn't disabled) before switching to it. + if ((vid.glstate == VID_GL_LIBRARY_ERROR) + && (cv_renderer.value == render_opengl)) { if (M_CheckParm("-nogl")) CONS_Alert(CONS_ERROR, "OpenGL rendering was disabled!\n"); else CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); - setrenderneeded = 0; return; } #endif - // setting the same renderer twice WILL crash your game, so let's not, please - if (rendermode == setrenderneeded) - setrenderneeded = 0; -} - -// Lactozilla: Renderer switching -void SCR_ChangeRenderer(void) -{ - setrenderneeded = 0; - - if (con_startup) - { - target_renderer = cv_renderer.value; -#ifdef HWRENDER - if (M_CheckParm("-opengl") && (vid_opengl_state == 1)) - target_renderer = rendermode = render_opengl; - else -#endif - if (M_CheckParm("-software")) - target_renderer = rendermode = render_soft; - // set cv_renderer back - SCR_ChangeRendererCVars(rendermode); - return; - } - - if (cv_renderer.value == 1) - target_renderer = render_soft; - else if (cv_renderer.value == 2) - target_renderer = render_opengl; - SCR_ActuallyChangeRenderer(); -} - -void SCR_ChangeRendererCVars(INT32 mode) -{ - // set cv_renderer back - if (mode == render_soft) - CV_StealthSetValue(&cv_renderer, 1); - else if (mode == render_opengl) - CV_StealthSetValue(&cv_renderer, 2); + // Set the new render mode + setrenderneeded = cv_renderer.value; + con_refresh = false; } boolean SCR_IsAspectCorrect(INT32 width, INT32 height) diff --git a/src/screen.h b/src/screen.h index 2cb2cf839160ab6e73e1544d6f7f6869ac4bdbb9..66452289cf360d1bbde5e182693043c22dabf1f8 100644 --- a/src/screen.h +++ b/src/screen.h @@ -72,10 +72,16 @@ typedef struct viddef_s #ifdef HWRENDER INT32/*fixed_t*/ fsmalldupx, fsmalldupy; INT32/*fixed_t*/ fmeddupx, fmeddupy; + INT32 glstate; #endif } viddef_t; -#define VIDWIDTH vid.width -#define VIDHEIGHT vid.height + +enum +{ + VID_GL_LIBRARY_NOTLOADED = 0, + VID_GL_LIBRARY_LOADED = 1, + VID_GL_LIBRARY_ERROR = -1, +}; // internal additional info for vesa modes only typedef struct @@ -134,18 +140,22 @@ enum { SPANDRAWFUNC_BASE = BASEDRAWFUNC, SPANDRAWFUNC_TRANS, - SPANDRAWFUNC_SPLAT, - SPANDRAWFUNC_TRANSSPLAT, - SPANDRAWFUNC_FOG, -#ifndef NOWATER - SPANDRAWFUNC_WATER, -#endif SPANDRAWFUNC_TILTED, SPANDRAWFUNC_TILTEDTRANS, + + SPANDRAWFUNC_SPLAT, + SPANDRAWFUNC_TRANSSPLAT, SPANDRAWFUNC_TILTEDSPLAT, -#ifndef NOWATER + + SPANDRAWFUNC_SPRITE, + SPANDRAWFUNC_TRANSSPRITE, + SPANDRAWFUNC_TILTEDSPRITE, + SPANDRAWFUNC_TILTEDTRANSSPRITE, + + SPANDRAWFUNC_WATER, SPANDRAWFUNC_TILTEDWATER, -#endif + + SPANDRAWFUNC_FOG, SPANDRAWFUNC_MAX }; @@ -170,10 +180,12 @@ extern boolean R_SSE2; // ---------------- extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 +extern UINT8 setrenderneeded; void SCR_ChangeRenderer(void); -void SCR_ChangeRendererCVars(INT32 mode); -extern UINT8 setrenderneeded; +void SCR_SetTargetRenderer(void); + +extern CV_PossibleValue_t cv_renderer_t[]; extern INT32 scr_bpp; extern UINT8 *scr_borderpatch; // patch used to fill the view borders @@ -182,17 +194,23 @@ extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_re // wait for page flipping to end or not extern consvar_t cv_vidwait; +// Initialize the screen +void SCR_Startup(void); + // Change video mode, only at the start of a refresh. void SCR_SetMode(void); + +// Set drawer functions for Software void SCR_SetDrawFuncs(void); + // Recalc screen size dependent stuff void SCR_Recalc(void); + // Check parms once at startup void SCR_CheckDefaultMode(void); -// Set the mode number which is saved in the config -void SCR_SetDefaultMode (void); -void SCR_Startup (void); +// Set the mode number which is saved in the config +void SCR_SetDefaultMode(void); FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index c2d6456e462bbf67bca399703e5b30b63d773d0a..22ac9fb8ff68228332cd142555f283be039ecfdc 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -283,6 +283,8 @@ <ClInclude Include="..\r_draw.h" /> <ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_main.h" /> + <ClInclude Include="..\r_patch.h" /> + <ClInclude Include="..\r_patchrotation.h" /> <ClInclude Include="..\r_picformats.h" /> <ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_portal.h" /> @@ -452,6 +454,8 @@ <ExcludedFromBuild>true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\r_main.c" /> + <ClCompile Include="..\r_patch.c" /> + <ClCompile Include="..\r_patchrotation.c" /> <ClCompile Include="..\r_picformats.c" /> <ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_portal.c" /> diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 438746ac7f02a01745f3785c9bf60b1e969e8de1..adae2f446dbde8267e375bb794eacc50bed9c663 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -477,12 +477,18 @@ <ClInclude Include="..\hardware\hw_clip.h"> <Filter>Hw_Hardware</Filter> </ClInclude> - <ClInclude Include="..\r_textures.h"> + <ClInclude Include="..\r_patch.h"> + <Filter>R_Rend</Filter> + </ClInclude> + <ClInclude Include="..\r_patchrotation.h"> <Filter>R_Rend</Filter> </ClInclude> <ClInclude Include="..\r_picformats.h"> <Filter>R_Rend</Filter> </ClInclude> + <ClInclude Include="..\r_textures.h"> + <Filter>R_Rend</Filter> + </ClInclude> <ClInclude Include="..\r_portal.h"> <Filter>R_Rend</Filter> </ClInclude> @@ -961,12 +967,18 @@ <Filter>Hw_Hardware</Filter> </ClCompile> <ClCompile Include="..\apng.c" /> - <ClCompile Include="..\r_textures.c"> + <ClCompile Include="..\r_patch.c"> + <Filter>R_Rend</Filter> + </ClCompile> + <ClCompile Include="..\r_patchrotation.c"> <Filter>R_Rend</Filter> </ClCompile> <ClCompile Include="..\r_picformats.c"> <Filter>R_Rend</Filter> </ClCompile> + <ClCompile Include="..\r_textures.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_portal.c"> <Filter>R_Rend</Filter> </ClCompile> diff --git a/src/sdl/hwsym_sdl.c b/src/sdl/hwsym_sdl.c index e545bbb6363a72210fdb25aeffb4de35a638b491..96e3d7d6926ef23771c8dcf489b4d8d2a16c0a1c 100644 --- a/src/sdl/hwsym_sdl.c +++ b/src/sdl/hwsym_sdl.c @@ -86,6 +86,7 @@ void *hwSym(const char *funcName,void *handle) GETFUNC(ClearBuffer); GETFUNC(SetTexture); GETFUNC(UpdateTexture); + GETFUNC(DeleteTexture); GETFUNC(ReadRect); GETFUNC(GClipRect); GETFUNC(ClearMipMapCache); diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index a49adb50866cb5fa9e096d599cabc8fd8af30421..b9423ac21a36fdaf5d7a7dbf8732f800552cf4f5 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -42,7 +42,7 @@ #ifdef HAVE_IMAGE #include "SDL_image.h" -#elif defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) // Windows doesn't need this, as SDL will do it for us. +#elif defined (__unix__) || (!defined(__APPLE__) && defined (UNIXCOMMON)) // Windows & Mac don't need this, as SDL will do it for us. #define LOAD_XPM //I want XPM! #include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so #define HAVE_IMAGE //I have SDL_Image, sortof @@ -95,7 +95,7 @@ static INT32 numVidModes = -1; static char vidModeName[33][32]; // allow 33 different modes rendermode_t rendermode = render_soft; -static rendermode_t chosenrendermode = render_soft; // set by command line arguments +rendermode_t chosenrendermode = render_none; // set by command line arguments boolean highcolor = false; @@ -105,7 +105,6 @@ static consvar_t cv_stretch = CVAR_INIT ("stretch", "Off", CV_SAVE|CV_NOSHOWHELP static consvar_t cv_alwaysgrabmouse = CVAR_INIT ("alwaysgrabmouse", "Off", CV_SAVE, CV_OnOff, NULL); UINT8 graphics_started = 0; // Is used in console.c and screen.c -INT32 vid_opengl_state = 0; // To disable fullscreen at startup; is set in VID_PrepareModeList boolean allow_fullscreen = false; @@ -1443,7 +1442,8 @@ static SDL_bool Impl_CreateContext(void) { // Renderer-specific stuff #ifdef HWRENDER - if ((rendermode == render_opengl) && (vid_opengl_state != -1)) + if ((rendermode == render_opengl) + && (vid.glstate != VID_GL_LIBRARY_ERROR)) { if (!sdlglcontext) sdlglcontext = SDL_GL_CreateContext(window); @@ -1480,7 +1480,7 @@ void VID_CheckGLLoaded(rendermode_t oldrender) { (void)oldrender; #ifdef HWRENDER - if (vid_opengl_state == -1) // Well, it didn't work the first time anyway. + if (vid.glstate == VID_GL_LIBRARY_ERROR) // Well, it didn't work the first time anyway. { CONS_Alert(CONS_ERROR, "OpenGL never loaded\n"); rendermode = oldrender; @@ -1495,14 +1495,16 @@ void VID_CheckGLLoaded(rendermode_t oldrender) #endif } -void VID_CheckRenderer(void) +boolean VID_CheckRenderer(void) { boolean rendererchanged = false; boolean contextcreated = false; +#ifdef HWRENDER rendermode_t oldrenderer = rendermode; +#endif if (dedicated) - return; + return false; if (setrenderneeded) { @@ -1516,11 +1518,12 @@ void VID_CheckRenderer(void) // Initialise OpenGL before calling SDLSetMode!!! // This is because SDLSetMode calls OglSdlSurface. - if (vid_opengl_state == 0) + if (vid.glstate == VID_GL_LIBRARY_NOTLOADED) { VID_StartupOpenGL(); + // Loaded successfully! - if (vid_opengl_state == 1) + if (vid.glstate == VID_GL_LIBRARY_LOADED) { // Destroy the current window, if it exists. if (window) @@ -1543,7 +1546,7 @@ void VID_CheckRenderer(void) contextcreated = true; } } - else if (vid_opengl_state == -1) + else if (vid.glstate == VID_GL_LIBRARY_ERROR) rendererchanged = false; } #endif @@ -1565,27 +1568,22 @@ void VID_CheckRenderer(void) bufSurface = NULL; } - if (rendererchanged) - { #ifdef HWRENDER - if (vid_opengl_state == 1) // Only if OpenGL ever loaded! - HWR_FreeTextureCache(); + if (rendererchanged && vid.glstate == VID_GL_LIBRARY_LOADED) // Only if OpenGL ever loaded! + HWR_ClearAllTextures(); #endif - SCR_SetDrawFuncs(); - } + + SCR_SetDrawFuncs(); } #ifdef HWRENDER - else if (rendermode == render_opengl) + else if (rendermode == render_opengl && rendererchanged) { - if (rendererchanged) - { - R_InitHardwareMode(); - V_SetPalette(0); - } + HWR_Switch(); + V_SetPalette(0); } -#else - (void)oldrenderer; #endif + + return rendererchanged; } INT32 VID_SetMode(INT32 modeNum) @@ -1626,7 +1624,7 @@ static SDL_bool Impl_CreateWindow(SDL_bool fullscreen) flags |= SDL_WINDOW_BORDERLESS; #ifdef HWRENDER - if (vid_opengl_state == 1) + if (vid.glstate == VID_GL_LIBRARY_LOADED) flags |= SDL_WINDOW_OPENGL; #endif @@ -1747,12 +1745,44 @@ void I_StartupGraphics(void) framebuffer = SDL_TRUE; } -#ifdef HWRENDER - if (M_CheckParm("-opengl")) - chosenrendermode = rendermode = render_opengl; + // Renderer choices + // Takes priority over the config. + if (M_CheckParm("-renderer")) + { + INT32 i = 0; + CV_PossibleValue_t *renderer_list = cv_renderer_t; + const char *modeparm = M_GetNextParm(); + while (renderer_list[i].strvalue) + { + if (!stricmp(modeparm, renderer_list[i].strvalue)) + { + chosenrendermode = renderer_list[i].value; + break; + } + i++; + } + } + + // Choose Software renderer else if (M_CheckParm("-software")) + chosenrendermode = render_soft; + +#ifdef HWRENDER + // Choose OpenGL renderer + else if (M_CheckParm("-opengl")) + chosenrendermode = render_opengl; + + // Don't startup OpenGL + if (M_CheckParm("-nogl")) + { + vid.glstate = VID_GL_LIBRARY_ERROR; + if (chosenrendermode == render_opengl) + chosenrendermode = render_none; + } #endif - chosenrendermode = rendermode = render_soft; + + if (chosenrendermode != render_none) + rendermode = chosenrendermode; usesdl2soft = M_CheckParm("-softblit"); borderlesswindow = M_CheckParm("-borderless"); @@ -1761,9 +1791,7 @@ void I_StartupGraphics(void) VID_Command_ModeList_f(); #ifdef HWRENDER - if (M_CheckParm("-nogl")) - vid_opengl_state = -1; // Don't startup OpenGL - else if (chosenrendermode == render_opengl) + if (rendermode == render_opengl) VID_StartupOpenGL(); #endif @@ -1836,6 +1864,7 @@ void VID_StartupOpenGL(void) HWD.pfnClearBuffer = hwSym("ClearBuffer",NULL); HWD.pfnSetTexture = hwSym("SetTexture",NULL); HWD.pfnUpdateTexture = hwSym("UpdateTexture",NULL); + HWD.pfnDeleteTexture = hwSym("DeleteTexture",NULL); HWD.pfnReadRect = hwSym("ReadRect",NULL); HWD.pfnGClipRect = hwSym("GClipRect",NULL); HWD.pfnClearMipMapCache = hwSym("ClearMipMapCache",NULL); @@ -1863,9 +1892,9 @@ void VID_StartupOpenGL(void) HWD.pfnSetShaderInfo = hwSym("SetShaderInfo",NULL); HWD.pfnLoadCustomShader = hwSym("LoadCustomShader",NULL); - vid_opengl_state = HWD.pfnInit() ? 1 : -1; // let load the OpenGL library + vid.glstate = HWD.pfnInit() ? VID_GL_LIBRARY_LOADED : VID_GL_LIBRARY_ERROR; // let load the OpenGL library - if (vid_opengl_state == -1) + if (vid.glstate == VID_GL_LIBRARY_ERROR) { rendermode = render_soft; setrenderneeded = 0; diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c index 04214ad03e3031f2f3de772b5c60aa46b02ebc10..52727c05600a5f33221e729d51263b08fcdde30b 100644 --- a/src/sdl/ogl_sdl.c +++ b/src/sdl/ogl_sdl.c @@ -189,7 +189,7 @@ boolean OglSdlSurface(INT32 w, INT32 h) SetupGLFunc4(); - granisotropicmode_cons_t[1].value = maximumAnisotropy; + glanisotropicmode_cons_t[1].value = maximumAnisotropy; SDL_GL_SetSwapInterval(cv_vidwait.value ? 1 : 0); diff --git a/src/st_stuff.c b/src/st_stuff.c index 86e0b37542224bc780017c44449ef0fb3e55d306..bd98c0a143a7da7bd7d8659b8ad0ca9559c6c9b2 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -203,9 +203,7 @@ void ST_doPaletteStuff(void) { INT32 palette; - if (paused || P_AutoPause()) - palette = 0; - else if (stplyr && stplyr->flashcount) + if (stplyr && stplyr->flashcount) palette = stplyr->flashpal; else palette = 0; @@ -215,8 +213,6 @@ void ST_doPaletteStuff(void) palette = 0; // No flashpals here in OpenGL #endif - palette = min(max(palette, 0), 13); - if (palette != st_palette) { st_palette = palette; @@ -232,7 +228,7 @@ void ST_doPaletteStuff(void) void ST_UnloadGraphics(void) { - Z_FreeTag(PU_HUDGFX); + Patch_FreeTag(PU_HUDGFX); } void ST_LoadGraphics(void) @@ -2080,21 +2076,21 @@ static void ST_drawNiGHTSHUD(void) if (stplyr->powers[pw_nights_superloop]) { pwr = stplyr->powers[pw_nights_superloop]; - V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_CACHE)); + V_DrawSmallScaledPatch(110, 44, 0, W_CachePatchName("NPRUA0",PU_SPRITE)); V_DrawThinString(106, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_helper]) { pwr = stplyr->powers[pw_nights_helper]; - V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_CACHE)); + V_DrawSmallScaledPatch(150, 44, 0, W_CachePatchName("NPRUC0",PU_SPRITE)); V_DrawThinString(146, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } if (stplyr->powers[pw_nights_linkfreeze]) { pwr = stplyr->powers[pw_nights_linkfreeze]; - V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_CACHE)); + V_DrawSmallScaledPatch(190, 44, 0, W_CachePatchName("NPRUE0",PU_SPRITE)); V_DrawThinString(186, 52, V_MONOSPACE, va("%2d.%02d", pwr/TICRATE, G_TicsToCentiseconds(pwr))); } } @@ -2755,9 +2751,6 @@ static void ST_overlayDrawer(void) void ST_Drawer(void) { - if (needpatchrecache) - R_ReloadHUDGraphics(); - #ifdef SEENAMES if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo) { diff --git a/src/taglist.c b/src/taglist.c new file mode 100644 index 0000000000000000000000000000000000000000..b11216b6cf7b3e7c709b73750c2d46e8e9155c40 --- /dev/null +++ b/src/taglist.c @@ -0,0 +1,366 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Nev3r. +// +// 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 taglist.c +/// \brief Ingame sector/line/mapthing tagging. + +#include "taglist.h" +#include "z_zone.h" +#include "r_data.h" + +// Taggroups are used to list elements of the same tag, for iteration. +// Since elements can now have multiple tags, it means an element may appear +// in several taggroups at the same time. These are built on level load. +taggroup_t* tags_sectors[MAXTAGS + 1]; +taggroup_t* tags_lines[MAXTAGS + 1]; +taggroup_t* tags_mapthings[MAXTAGS + 1]; + +/// Adds a tag to a given element's taglist. +/// \warning This does not rebuild the global taggroups, which are used for iteration. +void Tag_Add (taglist_t* list, const mtag_t tag) +{ + list->tags = Z_Realloc(list->tags, (list->count + 1) * sizeof(list->tags), PU_LEVEL, NULL); + list->tags[list->count++] = tag; +} + +/// Sets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. +void Tag_FSet (taglist_t* list, const mtag_t tag) +{ + if (!list->count) + { + Tag_Add(list, tag); + return; + } + + list->tags[0] = tag; +} + +/// Gets the first tag entry in a taglist. +/// Replicates the old way of accessing element->tag. +mtag_t Tag_FGet (const taglist_t* list) +{ + if (list->count) + return list->tags[0]; + + return 0; +} + +/// Returns true if the given tag exist inside the list. +boolean Tag_Find (const taglist_t* list, const mtag_t tag) +{ + size_t i; + for (i = 0; i < list->count; i++) + if (list->tags[i] == tag) + return true; + + return false; +} + +/// Returns true if at least one tag is shared between two given lists. +boolean Tag_Share (const taglist_t* list1, const taglist_t* list2) +{ + size_t i; + for (i = 0; i < list1->count; i++) + if (Tag_Find(list2, list1->tags[i])) + return true; + + return false; +} + +/// Returns true if both lists are identical. +boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2) +{ + size_t i; + + if (list1->count != list2->count) + return false; + + for (i = 0; i < list1->count; i++) + if (list1->tags[i] != list2->tags[i]) + return false; + + return true; +} + +/// Search for an element inside a global taggroup. +size_t Taggroup_Find (const taggroup_t *group, const size_t id) +{ + size_t i; + + if (!group) + return -1; + + for (i = 0; i < group->count; i++) + if (group->elements[i] == id) + return i; + + return -1; +} + +/// Add an element to a global taggroup. +void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id) +{ + taggroup_t *group; + size_t i; // Insert position. + + if (tag == MTAG_GLOBAL) + return; + + group = garray[(UINT16)tag]; + + // Don't add duplicate entries. + if (Taggroup_Find(group, id) != (size_t)-1) + return; + + // Create group if empty. + if (!group) + { + i = 0; + group = garray[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL); + } + else + { + // Keep the group element ids in an ascending order. + // Find the location to insert the element to. + for (i = 0; i < group->count; i++) + if (group->elements[i] > id) + break; + + group->elements = Z_Realloc(group->elements, (group->count + 1) * sizeof(size_t), PU_LEVEL, NULL); + + // Offset existing elements to make room for the new one. + if (i < group->count) + memmove(&group->elements[i + 1], &group->elements[i], group->count - i); + } + + group->count++; + group->elements = Z_Realloc(group->elements, group->count * sizeof(size_t), PU_LEVEL, NULL); + group->elements[i] = id; +} + +/// Remove an element from a global taggroup. +void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id) +{ + taggroup_t *group; + size_t rempos; + size_t newcount; + + if (tag == MTAG_GLOBAL) + return; + + group = garray[(UINT16)tag]; + + if ((rempos = Taggroup_Find(group, id)) == (size_t)-1) + return; + + // Strip away taggroup if no elements left. + if (!(newcount = --group->count)) + { + Z_Free(group->elements); + Z_Free(group); + garray[(UINT16)tag] = NULL; + } + else + { + size_t *newelements = Z_Malloc(newcount * sizeof(size_t), PU_LEVEL, NULL); + size_t i; + + // Copy the previous entries save for the one to remove. + for (i = 0; i < rempos; i++) + newelements[i] = group->elements[i]; + + for (i = rempos + 1; i < group->count; i++) + newelements[i - 1] = group->elements[i]; + + Z_Free(group->elements); + group->elements = newelements; + group->count = newcount; + } +} + +// Initialization. + +static void Taglist_AddToSectors (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_sectors, tag, itemid); +} + +static void Taglist_AddToLines (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_lines, tag, itemid); +} + +static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid) +{ + Taggroup_Add(tags_mapthings, tag, itemid); +} + +/// After all taglists have been built for each element (sectors, lines, things), +/// the global taggroups, made for iteration, are built here. +void Taglist_InitGlobalTables(void) +{ + size_t i, j; + + for (i = 0; i < MAXTAGS; i++) + { + tags_sectors[i] = NULL; + tags_lines[i] = NULL; + tags_mapthings[i] = NULL; + } + for (i = 0; i < numsectors; i++) + { + for (j = 0; j < sectors[i].tags.count; j++) + Taglist_AddToSectors(sectors[i].tags.tags[j], i); + } + for (i = 0; i < numlines; i++) + { + for (j = 0; j < lines[i].tags.count; j++) + Taglist_AddToLines(lines[i].tags.tags[j], i); + } + for (i = 0; i < nummapthings; i++) + { + for (j = 0; j < mapthings[i].tags.count; j++) + Taglist_AddToMapthings(mapthings[i].tags.tags[j], i); + } +} + +// Iteration, ingame search. + +INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p) +{ + if (tag == MTAG_GLOBAL) + { + if (p < numsectors) + return p; + return -1; + } + + if (tags_sectors[(UINT16)tag]) + { + if (p < tags_sectors[(UINT16)tag]->count) + return tags_sectors[(UINT16)tag]->elements[p]; + return -1; + } + return -1; +} + +INT32 Tag_Iterate_Lines (const mtag_t tag, const size_t p) +{ + if (tag == MTAG_GLOBAL) + { + if (p < numlines) + return p; + return -1; + } + + if (tags_lines[(UINT16)tag]) + { + if (p < tags_lines[(UINT16)tag]->count) + return tags_lines[(UINT16)tag]->elements[p]; + return -1; + } + return -1; +} + +INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p) +{ + if (tag == MTAG_GLOBAL) + { + if (p < nummapthings) + return p; + return -1; + } + + if (tags_mapthings[(UINT16)tag]) + { + if (p < tags_mapthings[(UINT16)tag]->count) + return tags_mapthings[(UINT16)tag]->elements[p]; + return -1; + } + return -1; +} + +INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag) +{ + size_t i; + + if (tag == MTAG_GLOBAL) + { + for (i = 0; i < numlines; i++) + if (lines[i].special == special) + return i; + } + else if (tags_lines[(UINT16)tag]) + { + taggroup_t *tagged = tags_lines[(UINT16)tag]; + for (i = 0; i < tagged->count; i++) + if (lines[tagged->elements[i]].special == special) + return tagged->elements[i]; + } + return -1; +} + +/// Backwards compatibility iteration function for Lua scripts. +INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start) +{ + if (tag == -1) + { + start++; + + if (start >= (INT32)numlines) + return -1; + + while (start < (INT32)numlines && lines[start].special != special) + start++; + + return start; + } + else + { + size_t p = 0; + INT32 id; + + // For backwards compatibility's sake, simulate the old linked taglist behavior: + // Iterate through the taglist and find the "start" line's position in the list, + // And start checking with the next one (if it exists). + if (start != -1) + { + for (; (id = Tag_Iterate_Lines(tag, p)) >= 0; p++) + if (id == start) + { + p++; + break; + } + } + + for (; (id = Tag_Iterate_Lines(tag, p)) >= 0; p++) + if (lines[id].special == special) + return id; + + return -1; + } +} + + +// Ingame list manipulation. + +/// Changes the first tag for a given sector, and updates the global taggroups. +void Tag_SectorFSet (const size_t id, const mtag_t tag) +{ + sector_t* sec = §ors[id]; + mtag_t curtag = Tag_FGet(&sec->tags); + if (curtag == tag) + return; + + Taggroup_Remove(tags_sectors, curtag, id); + Taggroup_Add(tags_sectors, tag, id); + Tag_FSet(&sec->tags, tag); +} diff --git a/src/taglist.h b/src/taglist.h new file mode 100644 index 0000000000000000000000000000000000000000..0e6d9f8422bbc150dbbabe3c6048d6e66c448f05 --- /dev/null +++ b/src/taglist.h @@ -0,0 +1,127 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// Copyright (C) 2020 by Nev3r. +// +// 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 taglist.h +/// \brief Tag iteration and reading functions and macros' declarations. + +#ifndef __R_TAGLIST__ +#define __R_TAGLIST__ + +#include "doomtype.h" + +typedef INT16 mtag_t; +#define MAXTAGS UINT16_MAX +#define MTAG_GLOBAL -1 + +/// Multitag list. Each taggable element will have its own taglist. +typedef struct +{ + mtag_t* tags; + UINT16 count; +} taglist_t; + +void Tag_Add (taglist_t* list, const mtag_t tag); +void Tag_FSet (taglist_t* list, const mtag_t tag); +mtag_t Tag_FGet (const taglist_t* list); +boolean Tag_Find (const taglist_t* list, const mtag_t tag); +boolean Tag_Share (const taglist_t* list1, const taglist_t* list2); +boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2); + +void Tag_SectorFSet (const size_t id, const mtag_t tag); + +/// Taggroup list. It is essentially just an element id list. +typedef struct +{ + size_t *elements; + size_t count; +} taggroup_t; + +extern taggroup_t* tags_sectors[]; +extern taggroup_t* tags_lines[]; +extern taggroup_t* tags_mapthings[]; + +void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id); +void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id); +size_t Taggroup_Find (const taggroup_t *group, const size_t id); + +void Taglist_InitGlobalTables(void); + +INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p); +INT32 Tag_Iterate_Lines (const mtag_t tag, const size_t p); +INT32 Tag_Iterate_Things (const mtag_t tag, const size_t p); + +INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag); +INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start); + +// Use this macro to declare an iterator position variable. +#define TAG_ITER_DECLARECOUNTER(level) size_t ICNT_##level + +#define TAG_ITER(level, fn, tag, return_varname) for(ICNT_##level = 0; (return_varname = fn(tag, ICNT_##level)) >= 0; ICNT_##level++) + +// Use these macros as wrappers for a taglist iteration. +#define TAG_ITER_SECTORS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Sectors, tag, return_varname) +#define TAG_ITER_LINES(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Lines, tag, return_varname) +#define TAG_ITER_THINGS(level, tag, return_varname) TAG_ITER(level, Tag_Iterate_Things, tag, return_varname) + +/* ITERATION MACROS +TAG_ITER_DECLARECOUNTER must be used before using the iterators. + +'level': +For each nested iteration, an additional TAG_ITER_DECLARECOUNTER +must be used with a different level number to avoid conflict with +the outer iterations. +Most cases don't have nested iterations and thus the level is just 0. + +'tag': +Pretty much the elements' tag to iterate through. + +'return_varname': +Target variable's name to return the iteration results to. + + +EXAMPLE: +{ + TAG_ITER_DECLARECOUNTER(0); + TAG_ITER_DECLARECOUNTER(1); // For the nested iteration. + + size_t li; + size_t sec; + + INT32 tag1 = 4; + + ... + + TAG_ITER_LINES(0, tag1, li) + { + line_t *line = lines + li; + + ... + + if (something) + { + mtag_t tag2 = 8; + + // Nested iteration; just make sure the level is higher + // and that it has its own counter declared in scope. + TAG_ITER_SECTORS(1, tag2, sec) + { + sector_t *sector = sectors + sec; + + ... + } + } + } +} + +Notes: +If no elements are found for a given tag, the loop inside won't be executed. +*/ + +#endif //__R_TAGLIST__ diff --git a/src/tmap.nas b/src/tmap.nas index 106f38e962b03fef0f0edc9e93dbd71112449ced..69282d0b471dd2c86802df544f4a346e4b96baa9 100644 --- a/src/tmap.nas +++ b/src/tmap.nas @@ -763,8 +763,8 @@ TX2 EQU 16 TY2 EQU 20 RASTERY_SIZEOF EQU 24 -cglobal rasterize_segment_tex -rasterize_segment_tex: +cglobal rasterize_segment_tex_asm +rasterize_segment_tex_asm: push ebp mov ebp,esp diff --git a/src/v_video.c b/src/v_video.c index 9c91261de6eb3247945e33eec33384145e99ea6a..522883475d255790e61fc457a4076d0a41efeea7 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -529,7 +529,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca //if (rendermode != render_soft && !con_startup) // Why? if (rendermode == render_opengl) { - HWR_DrawStretchyFixedPatch((GLPatch_t *)patch, x, y, pscale, vscale, scrn, colormap); + HWR_DrawStretchyFixedPatch(patch, x, y, pscale, vscale, scrn, colormap); return; } #endif @@ -551,7 +551,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (alphalevel) { - v_translevel = transtables + ((alphalevel-1)<<FF_TRANSSHIFT); + v_translevel = R_GetTranslucencyTable(alphalevel); patchdrawfunc = translucentpdraw; } } @@ -714,7 +714,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca // if it's meant to cover the whole screen, black out the rest (ONLY IF TOP LEFT ISN'T TRANSPARENT) if (x == 0 && SHORT(patch->width) == BASEVIDWIDTH && y == 0 && SHORT(patch->height) == BASEVIDHEIGHT) { - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[0])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[0])); if (!column->topdelta) { source = (const UINT8 *)(column) + 3; @@ -782,7 +782,7 @@ void V_DrawStretchyFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, fixed_t vsca if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; } - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); while (column->topdelta != 0xff) { @@ -829,7 +829,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ //if (rendermode != render_soft && !con_startup) // Not this again if (rendermode == render_opengl) { - HWR_DrawCroppedPatch((GLPatch_t*)patch,x,y,pscale,scrn,sx,sy,w,h); + HWR_DrawCroppedPatch(patch,x,y,pscale,scrn,sx,sy,w,h); return; } #endif @@ -851,7 +851,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ if (alphalevel) { - v_translevel = transtables + ((alphalevel-1)<<FF_TRANSSHIFT); + v_translevel = R_GetTranslucencyTable(alphalevel); patchdrawfunc = translucentpdraw; } } @@ -1005,7 +1005,7 @@ void V_DrawCroppedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_ continue; if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION) break; - column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS])); + column = (const column_t *)((const UINT8 *)(patch->columns) + (patch->columnofs[col>>FRACBITS])); while (column->topdelta != 0xff) { @@ -1500,7 +1500,7 @@ void V_DrawFillConsoleMap(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) // Jimita (12-04-2018) if (alphalevel) { - fadetable = ((UINT8 *)transtables + ((alphalevel-1)<<FF_TRANSSHIFT) + (c*256)); + fadetable = R_GetTranslucencyTable(alphalevel) + (c*256); for (;(--h >= 0) && dest < deststop; dest += vid.width) { u = 0; @@ -1683,7 +1683,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U fadetable = ((color & 0xFF00) // Color is not palette index? ? ((UINT8 *)colormaps + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade. + : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade. for (;(--h >= 0) && dest < deststop; dest += vid.width) { u = 0; @@ -1829,7 +1829,7 @@ void V_DrawFadeScreen(UINT16 color, UINT8 strength) ? ((UINT8 *)(((color & 0x0F00) == 0x0A00) ? fadecolormap // Do fadecolormap fade. : (((color & 0x0F00) == 0x0B00) ? fadecolormap + (256 * FADECOLORMAPROWS) // Do white fadecolormap fade. : colormaps)) + strength*256) // Do COLORMAP fade. - : ((UINT8 *)transtables + ((9-strength)<<FF_TRANSSHIFT) + color*256)); // Else, do TRANSMAP** fade. + : ((UINT8 *)R_GetTranslucencyTable((9-strength)+1) + color*256)); // Else, do TRANSMAP** fade. const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height; UINT8 *buf = screens[0]; @@ -3565,7 +3565,7 @@ void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param) angle_t disStart = (leveltime * 128) & FINEMASK; // in 0 to FINEANGLE INT32 newpix; INT32 sine; - //UINT8 *transme = transtables + ((tr_trans50-1)<<FF_TRANSSHIFT); + //UINT8 *transme = R_GetTranslucencyTable(tr_trans50); for (y = yoffset; y < yoffset+height; y++) { @@ -3622,7 +3622,7 @@ Unoptimized version INT32 x, y; // TODO: Add a postimg_param so that we can pick the translucency level... - UINT8 *transme = transtables + ((param-1)<<FF_TRANSSHIFT); + UINT8 *transme = R_GetTranslucencyTable(param); for (y = yoffset; y < yoffset+height; y++) { @@ -3770,3 +3770,36 @@ void V_Init(void) CONS_Debug(DBG_RENDER, " screens[%d] = %x\n", i, screens[i]); #endif } + +void V_Recalc(void) +{ + // scale 1,2,3 times in x and y the patches for the menus and overlays... + // calculated once and for all, used by routines in v_video.c and v_draw.c + vid.dupx = vid.width / BASEVIDWIDTH; + vid.dupy = vid.height / BASEVIDHEIGHT; + vid.dupx = vid.dupy = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy); + vid.fdupx = FixedDiv(vid.width*FRACUNIT, BASEVIDWIDTH*FRACUNIT); + vid.fdupy = FixedDiv(vid.height*FRACUNIT, BASEVIDHEIGHT*FRACUNIT); + +#ifdef HWRENDER + //if (rendermode != render_opengl && rendermode != render_none) // This was just placing it incorrectly at non aspect correct resolutions in opengl + // 13/11/18: + // The above is no longer necessary, since we want OpenGL to be just like software now + // -- Monster Iestyn +#endif + vid.fdupx = vid.fdupy = (vid.fdupx < vid.fdupy ? vid.fdupx : vid.fdupy); + + vid.meddupx = (UINT8)(vid.dupx >> 1) + 1; + vid.meddupy = (UINT8)(vid.dupy >> 1) + 1; +#ifdef HWRENDER + vid.fmeddupx = vid.meddupx*FRACUNIT; + vid.fmeddupy = vid.meddupy*FRACUNIT; +#endif + + vid.smalldupx = (UINT8)(vid.dupx / 3) + 1; + vid.smalldupy = (UINT8)(vid.dupy / 3) + 1; +#ifdef HWRENDER + vid.fsmalldupx = vid.smalldupx*FRACUNIT; + vid.fsmalldupy = vid.smalldupy*FRACUNIT; +#endif +} diff --git a/src/v_video.h b/src/v_video.h index 2af4fe29313055edab8478dfcb912ca28a8435aa..8a18f82ad7ab834988e672e3f5c21189764876b6 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -36,6 +36,9 @@ cv_rsaturation, cv_ysaturation, cv_gsaturation, cv_csaturation, cv_bsaturation, // Allocates buffer screens, call before R_Init. void V_Init(void); +// Recalculates the viddef (dupx, dupy, etc.) according to the current screen resolution. +void V_Recalc(void); + // Color look-up table #define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) diff --git a/src/w_wad.c b/src/w_wad.c index fd70f8ec33f1fe4e95cbf4fb9f9b3a5b6dc2be64..aca530fa518c7134636349b769f6760590cc79e3 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -57,6 +57,7 @@ #include "r_defs.h" #include "r_data.h" #include "r_textures.h" +#include "r_patch.h" #include "r_picformats.h" #include "i_system.h" #include "md5.h" @@ -833,11 +834,6 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); -#ifdef HWRENDER - // allocates GLPatch info structures and store them in a tree - wadfile->hwrcache = M_AATreeAlloc(AATREE_ZUSER); -#endif - // // add the wadfile // @@ -847,7 +843,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) #ifdef HWRENDER // Read shaders from file - if (rendermode == render_opengl && (vid_opengl_state == 1)) + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) { HWR_LoadCustomShadersFromFile(numwadfiles - 1, (type == RET_PK3)); HWR_CompileShaders(); @@ -1670,13 +1666,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (!lumpcache[lump]) { size_t len = W_LumpLengthPwad(wad, lump); - void *ptr, *lumpdata; -#ifndef NO_PNG_LUMPS - void *srcdata = NULL; -#endif - - ptr = Z_Malloc(len, tag, &lumpcache[lump]); - lumpdata = Z_Malloc(len, tag, NULL); + void *ptr, *dest, *lumpdata = Z_Malloc(len, PU_STATIC, NULL); // read the lump in full W_ReadLumpHeaderPwad(wad, lump, lumpdata, 0, 0); @@ -1686,14 +1676,25 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) { size_t newlen; - srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, NULL, NULL, NULL, NULL, len, &newlen, 0); - ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); - M_Memcpy(ptr, srcdata, newlen); - Z_Free(srcdata); + void *converted = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &newlen, 0); + ptr = Z_Malloc(newlen, PU_STATIC, NULL); + M_Memcpy(ptr, converted, newlen); + Z_Free(converted); + len = newlen; } else // just copy it into the patch cache #endif + { + ptr = Z_Malloc(len, PU_STATIC, NULL); M_Memcpy(ptr, lumpdata, len); + } + + Z_Free(lumpdata); + + dest = Z_Calloc(sizeof(patch_t), tag, &lumpcache[lump]); + Patch_Create(ptr, len, dest); + + Z_Free(ptr); } else Z_ChangeTag(lumpcache[lump], tag); @@ -1708,45 +1709,22 @@ void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag) void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) { -#ifdef HWRENDER - GLPatch_t *grPatch; -#endif + patch_t *patch; if (!TestValidLump(wad, lump)) return NULL; + patch = W_CacheSoftwarePatchNumPwad(wad, lump, tag); + #ifdef HWRENDER // Software-only compile cache the data without conversion if (rendermode == render_soft || rendermode == render_none) #endif - { - return W_CacheSoftwarePatchNumPwad(wad, lump, tag); - } -#ifdef HWRENDER - - grPatch = HWR_GetCachedGLPatchPwad(wad, lump); - - if (grPatch->mipmap->data) - { - if (tag == PU_CACHE) - tag = PU_HWRCACHE; - Z_ChangeTag(grPatch->mipmap->data, tag); - } - else - { - patch_t *ptr = NULL; - - // Only load the patch if we haven't initialised the grPatch yet - if (grPatch->mipmap->width == 0) - ptr = W_CacheLumpNumPwad(grPatch->wadnum, grPatch->lumpnum, PU_STATIC); + return (void *)patch; - // Run HWR_MakePatch in all cases, to recalculate some things - HWR_MakePatch(ptr, grPatch, grPatch->mipmap, false); - Z_Free(ptr); - } - - // return GLPatch_t, which can be casted to (patch_t) with valid patch header info - return (void *)grPatch; +#ifdef HWRENDER + Patch_CreateGL(patch); + return (void *)patch; #endif } @@ -1761,7 +1739,7 @@ void W_UnlockCachedPatch(void *patch) // have different lifetimes from software's. #ifdef HWRENDER if (rendermode == render_opengl) - HWR_UnlockCachedPatch((GLPatch_t*)patch); + HWR_UnlockCachedPatch((GLPatch_t *)((patch_t *)patch)->hardware); else #endif Z_Unlock(patch); @@ -2074,14 +2052,59 @@ int W_VerifyNMUSlumps(const char *filename) {"CLM", 3}, // Colormap changes {"TRANS", 5}, // Translucency map changes + {"CONSBACK", 8}, // Console Background graphic + + {"SAVE", 4}, // Save Select graphics here and below + {"BLACXLVL", 8}, + {"GAMEDONE", 8}, + {"CONT", 4}, // Continue icons on saves (probably not used anymore) + {"STNONEX", 7}, // "X" graphic + {"ULTIMATE", 8}, // Ultimate no-save + + {"CRFNT", 5}, // Sonic 1 font changes + {"NTFNT", 5}, // Character Select font changes + {"NTFNO", 5}, // Character Select font (outline) {"LTFNT", 5}, // Level title font changes {"TTL", 3}, // Act number changes {"STCFN", 5}, // Console font changes {"TNYFN", 5}, // Tiny console font changes + + {"STLIVE", 6}, // Life graphics, background and the "X" that shows under skin's HUDNAME + {"CROSHAI", 7}, // First person crosshairs + {"INTERSC", 7}, // Default intermission backgrounds (co-op) {"STT", 3}, // Acceptable HUD changes (Score Time Rings) {"YB_", 3}, // Intermission graphics, goes with the above - {"M_", 2}, // As does menu stuff + {"RESULT", 6}, // Used in intermission for competitive modes, above too :3 + {"RACE", 4}, // Race mode graphics, 321go + {"M_", 2}, // Menu stuff + {"LT", 2}, // Titlecard changes + + {"SLID", 4}, // Continue + {"CONT", 4}, + + {"MINICAPS", 8}, // NiGHTS graphics here and below + {"BLUESTAT", 8}, // Sphere status + {"BYELSTAT", 8}, + {"ORNGSTAT", 8}, + {"REDSTAT", 7}, + {"YELSTAT", 7}, + {"NBRACKET", 8}, + {"NGHTLINK", 8}, + {"NGT", 3}, // Link numbers + {"NARROW", 6}, + {"NREDAR", 6}, + {"NSS", 3}, + {"NBON", 4}, + {"NRNG", 4}, + {"NHUD", 4}, + {"CAPS", 4}, + {"DRILL", 5}, + {"GRADE", 5}, + {"MINUS5", 6}, + {"MUSICDEF", 8}, // Song definitions (thanks kart) + {"SHADERS", 7}, // OpenGL shader definitions + {"SH_", 3}, // GLSL shader {NULL, 0}, }; diff --git a/src/w_wad.h b/src/w_wad.h index 41232cba1c5f5e006c33ed8496462c98a1ccf2f4..1e86eea5a6b2ac991d26d47b98cf3416f4de5b2b 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -102,10 +102,6 @@ virtlump_t* vres_Find(const virtres_t*, const char*); #define lumpcache_t void * -#ifdef HWRENDER -#include "m_aatree.h" -#endif - // Resource type of the WAD. Yeah, I know this sounds dumb, but I'll leave it like this until I clean up the code further. typedef enum restype { @@ -123,9 +119,6 @@ typedef struct wadfile_s lumpinfo_t *lumpinfo; lumpcache_t *lumpcache; lumpcache_t *patchcache; -#ifdef HWRENDER - aatree_t *hwrcache; // patches are cached in renderer's native format -#endif UINT16 numlumps; // this wad's number of resources FILE *handle; UINT32 filesize; // for network diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 52617037b210f0eb913daf9a4e7eab6d1bee973f..3e8af3b0ed866b9039879abbc4b4e28b1d623ba4 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -298,6 +298,8 @@ <ExcludedFromBuild>true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\r_main.c" /> + <ClCompile Include="..\r_patch.c" /> + <ClCompile Include="..\r_patchrotation.c" /> <ClCompile Include="..\r_picformats.c" /> <ClCompile Include="..\r_plane.c" /> <ClCompile Include="..\r_portal.c" /> @@ -454,6 +456,8 @@ <ClInclude Include="..\r_draw.h" /> <ClInclude Include="..\r_local.h" /> <ClInclude Include="..\r_main.h" /> + <ClInclude Include="..\r_patch.h" /> + <ClInclude Include="..\r_patchrotation.h" /> <ClInclude Include="..\r_picformats.h" /> <ClInclude Include="..\r_plane.h" /> <ClInclude Include="..\r_portal.h" /> diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index 0689a4ac0893e10c660a72ed32c9bb0c3c054c82..7279368f1423f4a02e962395e8d4b451a30e44cd 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -469,9 +469,18 @@ <Filter>Hw_Hardware</Filter> </ClCompile> <ClCompile Include="..\apng.c" /> + <ClCompile Include="..\r_patch.c"> + <Filter>R_Rend</Filter> + </ClCompile> + <ClCompile Include="..\r_patchrotation.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_picformats.c"> <Filter>R_Rend</Filter> </ClCompile> + <ClCompile Include="..\r_textures.c"> + <Filter>R_Rend</Filter> + </ClCompile> <ClCompile Include="..\r_portal.c"> <Filter>R_Rend</Filter> </ClCompile> @@ -886,12 +895,18 @@ <Filter>Hw_Hardware</Filter> </ClInclude> <ClInclude Include="..\apng.h" /> - <ClInclude Include="..\r_textures.h"> + <ClInclude Include="..\r_patch.h"> + <Filter>R_Rend</Filter> + </ClInclude> + <ClInclude Include="..\r_patchrotation.h"> <Filter>R_Rend</Filter> </ClInclude> <ClInclude Include="..\r_picformats.h"> <Filter>R_Rend</Filter> </ClInclude> + <ClInclude Include="..\r_textures.h"> + <Filter>R_Rend</Filter> + </ClInclude> <ClInclude Include="..\r_portal.h"> <Filter>R_Rend</Filter> </ClInclude> diff --git a/src/win32/win_dll.c b/src/win32/win_dll.c index fa648a89c77d2f889799b5b31ebbba7507c1cf0b..4743cec34b2e6af738caeec60d7c179e58ec14d1 100644 --- a/src/win32/win_dll.c +++ b/src/win32/win_dll.c @@ -107,6 +107,7 @@ static loadfunc_t hwdFuncTable[] = { {"ClearBuffer@12", &hwdriver.pfnClearBuffer}, {"SetTexture@4", &hwdriver.pfnSetTexture}, {"UpdateTexture@4", &hwdriver.pfnUpdateTexture}, + {"DeleteTexture@4", &hwdriver.pfnDeleteTexture}, {"ReadRect@24", &hwdriver.pfnReadRect}, {"GClipRect@20", &hwdriver.pfnGClipRect}, {"ClearMipMapCache@0", &hwdriver.pfnClearMipMapCache}, @@ -139,6 +140,7 @@ static loadfunc_t hwdFuncTable[] = { {"ClearBuffer", &hwdriver.pfnClearBuffer}, {"SetTexture", &hwdriver.pfnSetTexture}, {"UpdateTexture", &hwdriver.pfnUpdateTexture}, + {"DeleteTexture", &hwdriver.pfnDeleteTexture}, {"ReadRect", &hwdriver.pfnReadRect}, {"GClipRect", &hwdriver.pfnGClipRect}, {"ClearMipMapCache", &hwdriver.pfnClearMipMapCache}, diff --git a/src/win32/win_vid.c b/src/win32/win_vid.c index 931e006eb35416dc251e5fbf7bd2ade432154f5c..7a33e19311f876fe595b72f7552fcf55f0af23fd 100644 --- a/src/win32/win_vid.c +++ b/src/win32/win_vid.c @@ -48,6 +48,7 @@ // this is the CURRENT rendermode!! very important: used by w_wad, and much other code rendermode_t rendermode = render_soft; +rendermode_t chosenrendermode = render_none; // set by command line arguments static void OnTop_OnChange(void); // synchronize page flipping with screen refresh static CV_PossibleValue_t CV_NeverOnOff[] = {{-1, "Never"}, {0, "Off"}, {1, "On"}, {0, NULL}}; @@ -56,7 +57,6 @@ static consvar_t cv_stretch = CVAR_INIT ("stretch", "On", CV_SAVE|CV_NOSHOWHELP, static consvar_t cv_ontop = CVAR_INIT ("ontop", "Never", 0, CV_NeverOnOff, NULL); boolean highcolor; -int vid_opengl_state = 0; static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces static LPBITMAPINFO bmiMain = NULL; @@ -952,7 +952,11 @@ INT32 VID_SetMode(INT32 modenum) return 1; } -void VID_CheckRenderer(void) {} +boolean VID_CheckRenderer(void) +{ + return false; +} + void VID_CheckGLLoaded(rendermode_t oldrender) { (void)oldrender; diff --git a/src/y_inter.c b/src/y_inter.c index d263bf6357c186e30c4d44612ec16c27ddb2d03c..acdf5f8d74c478d81348710e28669e474601634c 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -152,7 +152,6 @@ typedef struct boolean usebuffer = false; static boolean useinterpic; -static boolean safetorender = true; static y_buffer_t *y_buffer; static INT32 intertic; @@ -169,7 +168,6 @@ static void Y_CalculateCompetitionWinners(void); static void Y_CalculateTimeRaceWinners(void); static void Y_CalculateMatchWinners(void); static void Y_UnloadData(void); -static void Y_CleanupData(void); // Stuff copy+pasted from st_stuff.c #define ST_DrawNumFromHud(h,n) V_DrawTallNum(hudinfo[h].x, hudinfo[h].y, hudinfo[h].f, n) @@ -316,19 +314,6 @@ void Y_IntermissionDrawer(void) if (intertype == int_none || rendermode == render_none) return; - // Lactozilla: Renderer switching - if (needpatchrecache) - { - Y_CleanupData(); - safetorender = false; - } - - if (!safetorender) - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - if (!safetorender) - goto dontdrawbg; - if (useinterpic) V_DrawScaledPatch(0, 0, 0, interpic); else if (!usetile) @@ -366,7 +351,6 @@ void Y_IntermissionDrawer(void) if (!LUA_HudEnabled(hud_intermissiontally)) goto skiptallydrawer; -dontdrawbg: if (intertype == int_coop) { INT32 bonusy; @@ -416,17 +400,14 @@ dontdrawbg: bonusy = 150; // Total - if (safetorender) - { - V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); - V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); - } + V_DrawScaledPatch(152, bonusy, 0, data.coop.ptotal); + V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.total); bonusy -= (3*SHORT(tallnum[0]->height)/2) + 1; // Draw bonuses for (i = 3; i >= 0; --i) { - if (data.coop.bonuses[i].display && safetorender) + if (data.coop.bonuses[i].display) { V_DrawScaledPatch(152, bonusy, 0, data.coop.bonuspatches[i]); V_DrawTallNum(BASEVIDWIDTH - 68, bonusy + 1, 0, data.coop.bonuses[i].points); @@ -655,8 +636,7 @@ dontdrawbg: char strtime[10]; // draw the header - if (safetorender) - V_DrawScaledPatch(112, 2, 0, data.match.result); + V_DrawScaledPatch(112, 2, 0, data.match.result); // draw the level name V_DrawCenteredString(BASEVIDWIDTH/2, 20, 0, data.match.levelstring); @@ -1212,8 +1192,6 @@ void Y_StartIntermission(void) I_Error("endtic is dirty"); #endif - safetorender = true; - if (!multiplayer) { timer = 0; @@ -2060,19 +2038,13 @@ void Y_EndIntermission(void) usebuffer = false; } -#define UNLOAD(x) if (x) {Z_ChangeTag(x, PU_CACHE);} x = NULL; -#define CLEANUP(x) x = NULL; +#define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; // // Y_UnloadData // static void Y_UnloadData(void) { - // In hardware mode, don't Z_ChangeTag a pointer returned by W_CachePatchName(). - // It doesn't work and is unnecessary. - if (rendermode != render_soft) - return; - // unload the background patches UNLOAD(bgpatch); UNLOAD(bgtile); @@ -2112,45 +2084,3 @@ static void Y_UnloadData(void) break; } } - -static void Y_CleanupData(void) -{ - // unload the background patches - CLEANUP(bgpatch); - CLEANUP(bgtile); - CLEANUP(interpic); - - switch (intertype) - { - case int_coop: - // unload the coop and single player patches - CLEANUP(data.coop.bonuspatches[3]); - CLEANUP(data.coop.bonuspatches[2]); - CLEANUP(data.coop.bonuspatches[1]); - CLEANUP(data.coop.bonuspatches[0]); - CLEANUP(data.coop.ptotal); - break; - case int_spec: - // unload the special stage patches - //CLEANUP(data.spec.cemerald); - //CLEANUP(data.spec.nowsuper); - CLEANUP(data.spec.bonuspatches[1]); - CLEANUP(data.spec.bonuspatches[0]); - CLEANUP(data.spec.pscore); - CLEANUP(data.spec.pcontinues); - break; - case int_match: - case int_race: - CLEANUP(data.match.result); - break; - case int_ctf: - CLEANUP(data.match.blueflag); - CLEANUP(data.match.redflag); - break; - default: - //without this default, - //int_none, int_tag, int_chaos, and int_classicrace - //are not handled - break; - } -} diff --git a/src/z_zone.c b/src/z_zone.c index 2c7384c3da22fead194f365dc8fea0a4768949b9..ad64a3a07f04f01d40ac291cfa4e77f26bd37e88 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -27,6 +27,7 @@ #include "doomdef.h" #include "doomstat.h" +#include "r_patch.h" #include "r_picformats.h" #include "i_system.h" // I_GetFreeMem #include "i_video.h" // rendermode @@ -495,36 +496,37 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) } } -// ----------------- -// Utility functions -// ----------------- +/** Iterates through all memory for a given set of tags. + * + * \param lowtag The lowest tag to consider. + * \param hightag The highest tag to consider. + * \param iterfunc The iterator function. + */ +void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *)) +{ + memblock_t *block, *next; -// for renderer switching -boolean needpatchflush = false; -boolean needpatchrecache = false; + if (!iterfunc) + I_Error("Z_IterateTags: no iterator function was given"); -// flush all patches from memory -void Z_FlushCachedPatches(void) -{ - CONS_Debug(DBG_RENDER, "Z_FlushCachedPatches()...\n"); - Z_FreeTag(PU_PATCH); - Z_FreeTag(PU_HUDGFX); - Z_FreeTag(PU_HWRPATCHINFO); - Z_FreeTag(PU_HWRMODELTEXTURE); - Z_FreeTag(PU_HWRCACHE); - Z_FreeTag(PU_HWRCACHE_UNLOCKED); - Z_FreeTag(PU_HWRPATCHINFO_UNLOCKED); - Z_FreeTag(PU_HWRMODELTEXTURE_UNLOCKED); -} + for (block = head.next; block != &head; block = next) + { + next = block->next; // get link before possibly freeing -void Z_PreparePatchFlush(void) -{ - CONS_Debug(DBG_RENDER, "Z_PreparePatchFlush()...\n"); -#ifdef ROTSPRITE - R_FreeAllRotSprite(); -#endif + if (block->tag >= lowtag && block->tag <= hightag) + { + void *mem = (UINT8 *)block->hdr + sizeof *block->hdr; + boolean free = iterfunc(mem); + if (free) + Z_Free(mem); + } + } } +// ----------------- +// Utility functions +// ----------------- + // starting value of nextcleanup #define CLEANUPCOUNT 2000 @@ -793,14 +795,19 @@ static void Command_Memfree_f(void) Z_CheckHeap(-1); CONS_Printf("\x82%s", M_GetText("Memory Info\n")); - CONS_Printf(M_GetText("Total heap used : %7s KB\n"), sizeu1(Z_TotalUsage()>>10)); - CONS_Printf(M_GetText("Static : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC)>>10)); - CONS_Printf(M_GetText("Static (sound) : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND)>>10)); - CONS_Printf(M_GetText("Static (music) : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC)>>10)); - CONS_Printf(M_GetText("Locked cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_CACHE)>>10)); - CONS_Printf(M_GetText("Level : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVEL)>>10)); - CONS_Printf(M_GetText("Special thinker : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVSPEC)>>10)); - CONS_Printf(M_GetText("All purgable : %7s KB\n"), + CONS_Printf(M_GetText("Total heap used : %7s KB\n"), sizeu1(Z_TotalUsage()>>10)); + CONS_Printf(M_GetText("Static : %7s KB\n"), sizeu1(Z_TagUsage(PU_STATIC)>>10)); + CONS_Printf(M_GetText("Static (sound) : %7s KB\n"), sizeu1(Z_TagUsage(PU_SOUND)>>10)); + CONS_Printf(M_GetText("Static (music) : %7s KB\n"), sizeu1(Z_TagUsage(PU_MUSIC)>>10)); + CONS_Printf(M_GetText("Patches : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH)>>10)); + CONS_Printf(M_GetText("Patches (low priority) : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH_LOWPRIORITY)>>10)); + CONS_Printf(M_GetText("Patches (rotated) : %7s KB\n"), sizeu1(Z_TagUsage(PU_PATCH_ROTATED)>>10)); + CONS_Printf(M_GetText("Sprites : %7s KB\n"), sizeu1(Z_TagUsage(PU_SPRITE)>>10)); + CONS_Printf(M_GetText("HUD graphics : %7s KB\n"), sizeu1(Z_TagUsage(PU_HUDGFX)>>10)); + CONS_Printf(M_GetText("Locked cache : %7s KB\n"), sizeu1(Z_TagUsage(PU_CACHE)>>10)); + CONS_Printf(M_GetText("Level : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVEL)>>10)); + CONS_Printf(M_GetText("Special thinker : %7s KB\n"), sizeu1(Z_TagUsage(PU_LEVSPEC)>>10)); + CONS_Printf(M_GetText("All purgable : %7s KB\n"), sizeu1(Z_TagsUsage(PU_PURGELEVEL, INT32_MAX)>>10)); #ifdef HWRENDER diff --git a/src/z_zone.h b/src/z_zone.h index 5cbcc6655bc24eb2208627f4cf57e31b48c88a1a..e80a45e7fb4f2ed6223868fc78d18649e75ab4ad 100644 --- a/src/z_zone.h +++ b/src/z_zone.h @@ -42,8 +42,13 @@ enum PU_SOUND = 11, // static while playing PU_MUSIC = 12, // static while playing - PU_HUDGFX = 13, // static until WAD added - PU_PATCH = 14, // static until renderer change + + PU_PATCH = 14, // static entire execution time + PU_PATCH_LOWPRIORITY = 15, // lower priority patch, static until level exited + PU_PATCH_ROTATED = 16, // rotated patch, static until level exited or WAD added + PU_PATCH_DATA = 17, // patch data, lifetime depends on the patch that owns it + PU_SPRITE = 18, // sprite patch, static until WAD added + PU_HUDGFX = 19, // HUD patch, static until WAD added PU_HWRPATCHINFO = 21, // Hardware GLPatch_t struct for OpenGL texture cache PU_HWRPATCHCOLMIPMAP = 22, // Hardware GLMipmap_t struct colormap variation of patch @@ -63,7 +68,7 @@ enum PU_HWRCACHE_UNLOCKED = 102, // 'unlocked' PU_HWRCACHE memory: // 'second-level' cache for graphics // stored in hardware format and downloaded as needed - PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory + PU_HWRPATCHINFO_UNLOCKED = 103, // 'unlocked' PU_HWRPATCHINFO memory PU_HWRMODELTEXTURE_UNLOCKED = 104, // 'unlocked' PU_HWRMODELTEXTURE memory }; @@ -107,6 +112,10 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb #define Z_FreeTag(tagnum) Z_FreeTags(tagnum, tagnum) void Z_FreeTags(INT32 lowtag, INT32 hightag); +// Iterate memory by tag +#define Z_IterateTag(tagnum, func) Z_IterateTags(tagnum, tagnum, func) +void Z_IterateTags(INT32 lowtag, INT32 hightag, boolean (*iterfunc)(void *)); + // // Utility functions // @@ -144,10 +153,4 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag); char *Z_StrDup(const char *in); #define Z_Unlock(p) (void)p // TODO: remove this now that NDS code has been removed -// For renderer switching -extern boolean needpatchflush; -extern boolean needpatchrecache; -void Z_FlushCachedPatches(void); -void Z_PreparePatchFlush(void); - #endif