diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 56f5416cf..f282ca891 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -450,15 +450,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t texture = textures[texnum]; - mipmap->flags = TF_WRAPXY; - mipmap->width = (UINT16)texture->width; - mipmap->height = (UINT16)texture->height; - mipmap->format = textureformat; - blockwidth = texture->width; blockheight = texture->height; - blocksize = (blockwidth * blockheight); - block = MakeBlock(&grtex->mipmap); + blocksize = blockwidth * blockheight; + block = MakeBlock(mipmap); // Composite the columns together. for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) @@ -488,7 +483,7 @@ static void HWR_GenerateTexture(INT32 texnum, GLMapTexture_t *grtex, GLMipmap_t realpatch = W_CachePatchNumPwad(wadnum, lumpnum, PU_PATCH); } - HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, texture, patch, realpatch); + HWR_DrawTexturePatchInCache(mipmap, blockwidth, blockheight, texture, patch, realpatch); if (free_patch) Patch_Free(realpatch); @@ -680,25 +675,24 @@ void HWR_InitMapTextures(void) gl_maptexturesloaded = false; } -static void DeleteTextureMipmap(GLMipmap_t *grMipmap) +static void DeleteTextureMipmap(GLMipmap_t *grMipmap, boolean delete_mipmap) { HWD.pfnDeleteTexture(grMipmap); - // Chroma-keyed textures do not own their texture data, so do not free it - if (!(grMipmap->flags & TF_CHROMAKEYED)) + if (delete_mipmap) Z_Free(grMipmap->data); } -static void FreeMapTexture(GLMapTexture_t *tex) +static void FreeMapTexture(GLMapTexture_t *tex, boolean delete_chromakeys) { if (tex->mipmap.nextcolormap) { - DeleteTextureMipmap(tex->mipmap.nextcolormap); + DeleteTextureMipmap(tex->mipmap.nextcolormap, delete_chromakeys); free(tex->mipmap.nextcolormap); tex->mipmap.nextcolormap = NULL; } - DeleteTextureMipmap(&tex->mipmap); + DeleteTextureMipmap(&tex->mipmap, true); } void HWR_FreeMapTextures(void) @@ -707,8 +701,8 @@ void HWR_FreeMapTextures(void) for (i = 0; i < gl_numtextures; i++) { - FreeMapTexture(&gl_textures[i]); - FreeMapTexture(&gl_flats[i]); + FreeMapTexture(&gl_textures[i], true); + FreeMapTexture(&gl_flats[i], false); } // now the heap don't have any 'user' pointing to our @@ -741,22 +735,7 @@ void HWR_LoadMapTextures(size_t pnumtextures) // -------------------------------------------------------------------------- // Make sure texture is downloaded and set it as the source // -------------------------------------------------------------------------- -static void GetMapTexture(INT32 tex, GLMapTexture_t *grtex, GLMipmap_t *mipmap) -{ - // Generate texture if missing from the cache - if (!mipmap->data && !mipmap->downloaded) - HWR_GenerateTexture(tex, grtex, mipmap); - - // If hardware does not have the texture, then call pfnSetTexture to upload it - if (!mipmap->downloaded) - HWD.pfnSetTexture(mipmap); - HWR_SetCurrentTexture(mipmap); - - // The system-memory data can be purged now. - Z_ChangeTag(mipmap->data, PU_HWRCACHE_UNLOCKED); -} - -GLMapTexture_t *HWR_GetTexture(INT32 tex) +GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed) { if (tex < 0 || tex >= (signed)gl_numtextures) { @@ -769,7 +748,46 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex) GLMapTexture_t *grtex = &gl_textures[tex]; - GetMapTexture(tex, grtex, &grtex->mipmap); + GLMipmap_t *grMipmap = &grtex->mipmap; + GLMipmap_t *originalMipmap = grMipmap; + + if (!originalMipmap->downloaded) + { + originalMipmap->flags = TF_WRAPXY; + originalMipmap->width = (UINT16)textures[tex]->width; + originalMipmap->height = (UINT16)textures[tex]->height; + originalMipmap->format = textureformat; + } + + // If chroma-keyed, create or use a different mipmap for the variant + if (chromakeyed && !textures[tex]->transparency) + { + // Allocate it if it wasn't already + if (!originalMipmap->nextcolormap) + { + GLMipmap_t *newMipmap = calloc(1, sizeof (*grMipmap)); + if (newMipmap == NULL) + I_Error("%s: Out of memory", "HWR_GetTexture"); + + newMipmap->flags = originalMipmap->flags | TF_CHROMAKEYED; + newMipmap->width = originalMipmap->width; + newMipmap->height = originalMipmap->height; + newMipmap->format = originalMipmap->format; + originalMipmap->nextcolormap = newMipmap; + } + + // Generate, upload and bind the variant texture instead of the original one + grMipmap = originalMipmap->nextcolormap; + } + + if (!grMipmap->data) + HWR_GenerateTexture(tex, grtex, grMipmap); + + if (!grMipmap->downloaded) + HWD.pfnSetTexture(grMipmap); + HWR_SetCurrentTexture(grMipmap); + + Z_ChangeTag(grMipmap->data, PU_HWRCACHE_UNLOCKED); return grtex; } diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index 807c70989..5678cd593 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -120,7 +120,7 @@ void HWR_GetPatch(patch_t *patch); void HWR_GetMappedPatch(patch_t *patch, const UINT8 *colormap); void HWR_GetFadeMask(lumpnum_t fademasklumpnum); -GLMapTexture_t *HWR_GetTexture(INT32 tex); +GLMapTexture_t *HWR_GetTexture(INT32 tex, boolean chromakeyed); void HWR_GetLevelFlat(levelflat_t *levelflat, boolean chromakeyed); void HWR_GetRawFlat(lumpnum_t flatlumpnum); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4e651891d..a4b8b15ed 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -978,7 +978,7 @@ static void HWR_RenderMidtexture(INT32 gl_midtexture, float cliplow, float cliph else repeats = 1; - GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture); + GLMapTexture_t *grTex = HWR_GetTexture(gl_midtexture, true); float xscale = FixedToFloat(gl_sidedef->scalex_mid); float yscale = FixedToFloat(gl_sidedef->scaley_mid); @@ -1237,7 +1237,7 @@ static void HWR_ProcessSeg(void) // check TOP TEXTURE if ((worldhighslope < worldtopslope || worldhigh < worldtop) && gl_toptexture) { - grTex = HWR_GetTexture(gl_toptexture); + grTex = HWR_GetTexture(gl_toptexture, false); xscale = FixedToFloat(abs(gl_sidedef->scalex_top)); yscale = FixedToFloat(abs(gl_sidedef->scaley_top)); @@ -1327,7 +1327,7 @@ static void HWR_ProcessSeg(void) // check BOTTOM TEXTURE if ((worldlowslope > worldbottomslope || worldlow > worldbottom) && gl_bottomtexture) { - grTex = HWR_GetTexture(gl_bottomtexture); + grTex = HWR_GetTexture(gl_bottomtexture, false); xscale = FixedToFloat(abs(gl_sidedef->scalex_bottom)); yscale = FixedToFloat(abs(gl_sidedef->scaley_bottom)); @@ -1441,7 +1441,7 @@ static void HWR_ProcessSeg(void) // Single sided line... Deal only with the middletexture (if one exists) if (gl_midtexture && gl_linedef->special != SPECIAL_HORIZON_LINE) // (Ignore horizon line for OGL) { - grTex = HWR_GetTexture(gl_midtexture); + grTex = HWR_GetTexture(gl_midtexture, false); xscale = FixedToFloat(gl_sidedef->scalex_mid); yscale = FixedToFloat(gl_sidedef->scaley_mid); @@ -1615,7 +1615,7 @@ static void HWR_ProcessSeg(void) // -- Monster Iestyn 26/06/18 fixed_t texturevpeg = side->rowoffset + side->offsety_mid; - grTex = HWR_GetTexture(texnum); + grTex = HWR_GetTexture(texnum, true); xscale = FixedToFloat(side->scalex_mid); yscale = FixedToFloat(side->scaley_mid); @@ -1772,7 +1772,7 @@ static void HWR_ProcessSeg(void) // -- Monster Iestyn 26/06/18 fixed_t texturevpeg = side->rowoffset + side->offsety_mid; - grTex = HWR_GetTexture(texnum); + grTex = HWR_GetTexture(texnum, true); xscale = FixedToFloat(side->scalex_mid); yscale = FixedToFloat(side->scaley_mid); @@ -4113,7 +4113,7 @@ static void HWR_CreateDrawNodes(void) else if (sortnode[sortindex[i]].wall) { if (!(sortnode[sortindex[i]].wall->blend & PF_NoTexture)) - HWR_GetTexture(sortnode[sortindex[i]].wall->texnum); + HWR_GetTexture(sortnode[sortindex[i]].wall->texnum, true); HWR_RenderWall(sortnode[sortindex[i]].wall->wallVerts, &sortnode[sortindex[i]].wall->Surf, sortnode[sortindex[i]].wall->blend, sortnode[sortindex[i]].wall->fogwall, sortnode[sortindex[i]].wall->lightlevel, sortnode[sortindex[i]].wall->wallcolormap); } @@ -5093,6 +5093,8 @@ static void HWR_DrawSkyBackground(player_t *player) HWD.pfnSetBlend(PF_Translucent|PF_NoDepthTest|PF_Modulated); + HWR_GetTexture(texturetranslation[skytexture], false); + if (cv_glskydome.value) { FTransform dometransform; @@ -5108,8 +5110,6 @@ static void HWR_DrawSkyBackground(player_t *player) HWR_SetTransformAiming(&dometransform, player, false); dometransform.angley = (float)((viewangle-ANGLE_270)>>ANGLETOFINESHIFT)*(360.0f/(float)FINEANGLES); - HWR_GetTexture(texturetranslation[skytexture]); - if (gl_sky.texture != texturetranslation[skytexture]) { HWR_ClearSkyDome(); @@ -5129,7 +5129,6 @@ static void HWR_DrawSkyBackground(player_t *player) float aspectratio; float angleturn; - HWR_GetTexture(texturetranslation[skytexture]); aspectratio = (float)vid.width/(float)vid.height; //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 diff --git a/src/m_menu.c b/src/m_menu.c index 38165472e..c4fccb372 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -140,6 +140,7 @@ static char *char_notes = NULL; boolean menuactive = false; boolean fromlevelselect = false; +tic_t shieldprompt_timer = 0; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove typedef enum { @@ -3161,6 +3162,7 @@ static void Command_Manual_f(void) if (modeattacking) return; M_StartControlPanel(); + if (shieldprompt_timer) return; // TODO: 2.3: Delete this line currentMenu = &MISC_HelpDef; itemOn = 0; } @@ -3340,6 +3342,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); // Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically. //OP_SoundOptionsDef.lastOn = 0; @@ -3350,6 +3353,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); M_VideoModeMenu(0); return true; @@ -3361,6 +3365,7 @@ boolean M_Responder(event_t *ev) if (modeattacking) return true; M_StartControlPanel(); + if (shieldprompt_timer) return true; // TODO: 2.3: Delete this line M_Options(0); M_SetupNextMenu(&OP_MainDef); return true; @@ -3631,6 +3636,230 @@ void M_Drawer(void) } } +// Handle the "Do you want to assign Shield Ability now?" pop-up for old configs // TODO: 2.3: Remove this line... +static UINT8 shieldprompt_currentchoice = 0; // ...and this line... + +static void M_ShieldPromptUseDefaults(void) // ...and this function +{ + // With a default config from v2.2.10 to v2.2.13, the B button will be set to Custom 1, + // and Controls per Key defaults to "One", so it will override the default Shield button. + // A default config from v2.2.0 to v2.2.9 has Next Weapon on B, so it suffers from this too. + + // So for "Use default Shield Ability buttons", we should update old configs to mitigate gamepad conflicts + // (even with "Several" Controls per Key!), and show a message with the default bindings + + for (setupcontrols = gamecontrol; true; setupcontrols = gamecontrolbis) // Do stuff for both P1 and P2 + { + INT32 JOY1 = (setupcontrols == gamecontrol) ? KEY_JOY1 : KEY_2JOY1; // Is this for P1 or for P2? + + if ((setupcontrols[GC_CUSTOM1][0] == JOY1+1 || setupcontrols[GC_CUSTOM1][1] == JOY1+1) + && (setupcontrols[GC_CUSTOM2][0] == JOY1+3 || setupcontrols[GC_CUSTOM2][1] == JOY1+3) + && (setupcontrols[GC_CUSTOM3][0] == JOY1+8 || setupcontrols[GC_CUSTOM3][1] == JOY1+8)) + { + // If the player has v2.2.13's default gamepad Custom 1/2/3 buttons, + // shuffle Custom 1/2/3 around to make room for Shield Ability on B + UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1; + UINT8 custom1_slot = (setupcontrols[GC_CUSTOM1][0] == JOY1+1) ? 0 : 1; + UINT8 custom2_slot = (setupcontrols[GC_CUSTOM2][0] == JOY1+3) ? 0 : 1; + UINT8 custom3_slot = (setupcontrols[GC_CUSTOM3][0] == JOY1+8) ? 0 : 1; + + setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B + setupcontrols[GC_CUSTOM1][custom1_slot] = JOY1+3; // Move Custom 1 from B to Y + setupcontrols[GC_CUSTOM2][custom2_slot] = JOY1+8; // Move Custom 2 from Y to LS + setupcontrols[GC_CUSTOM3][custom3_slot] = KEY_NULL; // Unassign Custom 3 from LS... + // (The alternative would be to check and update the ENTIRE gamepad layout. + // That'd be nice, but it would mess with people that are used to the old defaults.) + } + else if ((setupcontrols[GC_WEAPONNEXT][0] == JOY1+1 || setupcontrols[GC_WEAPONNEXT][1] == JOY1+1) + && (setupcontrols[GC_WEAPONPREV][0] == JOY1+2 || setupcontrols[GC_WEAPONPREV][1] == JOY1+2)) + { + // Or if the user has a default config from v2.2.0 to v2.2.9, + // the B button will be Next Weapon, and X will be Previous Weapon. + // It's "safe" to discard one of them, you just have to press X multiple times to select in the other direction + UINT8 shield_slot = (setupcontrols[GC_SHIELD ][0] == KEY_NULL ) ? 0 : 1; + UINT8 nweapon_slot = (setupcontrols[GC_WEAPONNEXT][0] == JOY1+1) ? 0 : 1; + UINT8 pweapon_slot = (setupcontrols[GC_WEAPONPREV][0] == JOY1+2) ? 0 : 1; + + setupcontrols[GC_SHIELD ][shield_slot ] = JOY1+1; // Assign Shield Ability to B + setupcontrols[GC_WEAPONNEXT][nweapon_slot] = JOY1+3; // Move Next Weapon from B to X + setupcontrols[GC_WEAPONPREV][pweapon_slot] = KEY_NULL; // Unassign Previous Weapon from X + } + + if (setupcontrols == gamecontrolbis) // If we've already updated both players, break out + break; + } + + + // Now, show a message about the default Shield Ability bindings + if ((gamecontrol[GC_SHIELD][0] == KEY_LALT && gamecontrol[GC_SHIELD][1] == KEY_JOY1+1) + || (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 && gamecontrol[GC_SHIELD][1] == KEY_LALT)) + { + // Left Alt and the B button are both assigned + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard,\nand the \x85""B button\x80"" on gamepads." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 43; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 27; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_LALT || gamecontrol[GC_SHIELD][1] == KEY_LALT) + { + // Left Alt is assigned, but the B button isn't. + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x82""Left Alt\x80"" key on keyboard.\nThe \x85""B button\x80"" on gamepads was taken." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 24; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_JOY1+1 || gamecontrol[GC_SHIELD][1] == KEY_JOY1+1) + { + // The B button is assigned, but Left Alt isn't + M_StartMessage(M_GetText("Shield Ability defaults to\nthe \x85""B button\x80"" on gamepads.\nThe \x82""Left Alt\x80"" key on keyboard was taken." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 8; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 36; + } + else if (gamecontrol[GC_SHIELD][0] == KEY_NULL && gamecontrol[GC_SHIELD][1] == KEY_NULL) + { + // Neither Left Alt nor the B button are assigned + M_StartMessage(M_GetText("Shield Ability is unassigned!\nThe \x82""Left Alt\x80"" key on keyboard and\nthe \x85""B button\x80"" on gamepads were taken." + "\n\nYou should assign Shield Ability\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 19; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 33; + } + else + { + // Neither Left Alt nor the B button are assigned... but something else is??? + // (This can technically happen if you edit your config or use setcontrol in the console before opening the menu) + char keystr[16+16+2+7+1]; // Two 16-char keys + two colour codes + "' and '" + null + + if (gamecontrol[GC_SHIELD][0] != KEY_NULL && gamecontrol[GC_SHIELD][1] != KEY_NULL) + STRBUFCPY(keystr, va("%s\x80""' and '\x82""%s", + G_KeyNumToName(gamecontrol[GC_SHIELD][0]), + G_KeyNumToName(gamecontrol[GC_SHIELD][1]))); + else if (gamecontrol[GC_SHIELD][0] != KEY_NULL) + STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][0])); + else //if (gamecontrol[GC_SHIELD][1] != KEY_NULL) + STRBUFCPY(keystr, G_KeyNumToName(gamecontrol[GC_SHIELD][1])); + + M_StartMessage(va("Shield Ability is assigned to\n'\x82""%s\x80""'." + "\n\nYou can always reassign it\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n", + keystr), NULL, MM_NOTHING); + MessageDef.x = 23; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 32; + } +} + +static void M_HandleShieldPromptMenu(INT32 choice) // TODO: 2.3: Remove +{ + switch (choice) + { + case KEY_ESCAPE: + if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident! + break; + + S_StartSound(NULL, sfx_menu1); + noFurtherInput = true; + shieldprompt_timer = 0; + M_ShieldPromptUseDefaults(); + break; + + case KEY_ENTER: + if (I_GetTime() <= shieldprompt_timer) // Don't mash past the pop-up by accident! + break; + + S_StartSound(NULL, sfx_menu1); + noFurtherInput = true; + shieldprompt_timer = 0; + + if (shieldprompt_currentchoice == 0) + { + OP_ChangeControlsDef.lastOn = 8; // Highlight Shield Ability in the controls menu + M_Setup1PControlsMenu(0); // Set up P1's controls menu and call M_SetupNextMenu + } + else if (shieldprompt_currentchoice == 1) // Copy the Spin buttons to the Shield buttons + { + CV_SetValue(&cv_controlperkey, 2); // Make sure that Controls per Key is "Several" + + gamecontrol [GC_SHIELD][0] = gamecontrol [GC_SPIN][0]; + gamecontrol [GC_SHIELD][1] = gamecontrol [GC_SPIN][1]; + gamecontrolbis[GC_SHIELD][0] = gamecontrolbis[GC_SPIN][0]; + gamecontrolbis[GC_SHIELD][1] = gamecontrolbis[GC_SPIN][1]; + CV_SetValue(&cv_shieldaxis, cv_spinaxis.value); + CV_SetValue(&cv_shieldaxis2, cv_spinaxis2.value); + + M_StartMessage(M_GetText("Spin and Shield Ability are now\nthe same button." + "\n\nYou can always reassign them\nin the Options menu later." + "\n\n\nPress 'Enter' to continue\n"), + NULL, MM_NOTHING); + MessageDef.x = 36; // Change the pop-up message's background position/width + MessageDef.lastOn = (MessageDef.lastOn & ~0xFF) | 29; + } + else + M_ShieldPromptUseDefaults(); + break; + + case KEY_UPARROW: + S_StartSound(NULL, sfx_menu1); + shieldprompt_currentchoice = (shieldprompt_currentchoice+2)%3; + break; + + case KEY_DOWNARROW: + S_StartSound(NULL, sfx_menu1); + shieldprompt_currentchoice = (shieldprompt_currentchoice+1)%3; + break; + } + + MessageDef.prevMenu = &MainDef; +} + +static void M_DrawShieldPromptMenu(void) // TODO: 2.3: Remove +{ + INT16 cursorx = (BASEVIDWIDTH/2) - 24; + + V_DrawFill(10-3, 68-3, 300+6, 40+6, 159); + // V_DrawCenteredString doesn't centre newlines, so we have to draw each line separately + V_DrawCenteredString(BASEVIDWIDTH/2, 68, V_ALLOWLOWERCASE, "Welcome back! Since you last played,"); + V_DrawCenteredString(BASEVIDWIDTH/2, 76, V_ALLOWLOWERCASE, "Spin has been split into separate"); + V_DrawCenteredString(BASEVIDWIDTH/2, 84, V_ALLOWLOWERCASE, "\"Spin\" and \"Shield Ability\" controls."); + + V_DrawCenteredString(BASEVIDWIDTH/2, 98, V_ALLOWLOWERCASE, "Do you want to assign Shield Ability now?"); + + + V_DrawCenteredString(BASEVIDWIDTH/2, 164, + (shieldprompt_currentchoice == 0) ? V_YELLOWMAP : 0, "Open Control Setup"); + V_DrawCenteredString(BASEVIDWIDTH/2, 172, + (shieldprompt_currentchoice == 1) ? V_YELLOWMAP : 0, "Keep the old behaviour"); + V_DrawCenteredString(BASEVIDWIDTH/2, 180, + (shieldprompt_currentchoice == 2) ? V_YELLOWMAP : 0, "Use default Shield Ability buttons"); + + switch (shieldprompt_currentchoice) + { + case 0: cursorx -= V_StringWidth("Open Control Setup", 0)/2; break; + case 1: cursorx -= V_StringWidth("Keep the old behaviour", 0)/2; break; + default: cursorx -= V_StringWidth("Use default Shield Ability buttons", 0)/2; break; + } + V_DrawScaledPatch(cursorx, 164 + (shieldprompt_currentchoice*8), 0, W_CachePatchName("M_CURSOR", PU_PATCH)); +} + +static menuitem_t OP_ShieldPromptMenu[] = {{IT_KEYHANDLER | IT_NOTHING, NULL, "", M_HandleShieldPromptMenu, 0}}; // TODO: 2.3: Remove + +menu_t OP_ShieldPromptDef = { // TODO: 2.3: Remove + MN_SPECIAL, + NULL, + 1, + &MainDef, + OP_ShieldPromptMenu, + M_DrawShieldPromptMenu, + 0, 0, 0, NULL +}; + // // M_StartControlPanel // @@ -3662,6 +3891,15 @@ void M_StartControlPanel(void) currentMenu = &MainDef; itemOn = singleplr; M_UpdateItemOn(); + + if (shieldprompt_timer) // For old configs, show a pop-up about the new Shield button // TODO: 2.3: Remove + { + S_StartSound(NULL, sfx_strpst); + noFurtherInput = true; + shieldprompt_timer = I_GetTime() + TICRATE; // Don't mash past the pop-up by accident! + + M_SetupNextMenu(&OP_ShieldPromptDef); + } } else if (modeattacking) { diff --git a/src/m_menu.h b/src/m_menu.h index 99a5b6de4..55c0b4060 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -176,6 +176,7 @@ typedef struct extern menupres_t menupres[NUMMENUTYPES]; extern UINT32 prevMenuId; extern UINT32 activeMenuId; +extern tic_t shieldprompt_timer; // Show a prompt about the new Shield button for old configs // TODO: 2.3: Remove void M_InitMenuPresTables(void); UINT8 M_GetYoungestChildMenu(void); diff --git a/src/m_misc.c b/src/m_misc.c index a60bbea98..724717aa6 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -560,6 +560,11 @@ void M_FirstLoadConfig(void) COM_BufInsertText(va("exec \"%s\"\n", configfile)); // no COM_BufExecute() needed; that does it right away + // For configs loaded at startup only, check for pre-Shield-button configs // TODO: 2.3: Remove + if (GETMAJOREXECVERSION(cv_execversion.value) < 55 // Pre-v2.2.14 configs + && cv_execversion.value != 25) // Make sure that the config exists, too + shieldprompt_timer = 1; + // don't filter anymore vars and don't let this convsvar be changed COM_BufInsertText(va("%s \"%d\"\n", cv_execversion.name, EXECVERSION)); CV_ToggleExecVersion(false); diff --git a/src/m_vector.c b/src/m_vector.c index 3132a869d..1b04f8ae1 100644 --- a/src/m_vector.c +++ b/src/m_vector.c @@ -21,6 +21,32 @@ void DVector3_Load(dvector3_t *vec, double x, double y, double z) vec->z = z; } +void DVector3_Copy(dvector3_t *a_o, const dvector3_t *a_i) +{ + memcpy(a_o, a_i, sizeof(dvector3_t)); +} + +void DVector3_Add(const dvector3_t *a_i, const dvector3_t *a_c, dvector3_t *a_o) +{ + a_o->x = a_i->x + a_c->x; + a_o->y = a_i->y + a_c->y; + a_o->z = a_i->z + a_c->z; +} + +void DVector3_Subtract(const dvector3_t *a_i, const dvector3_t *a_c, dvector3_t *a_o) +{ + a_o->x = a_i->x - a_c->x; + a_o->y = a_i->y - a_c->y; + a_o->z = a_i->z - a_c->z; +} + +void DVector3_Multiply(const dvector3_t *a_i, double a_c, dvector3_t *a_o) +{ + a_o->x = a_i->x * a_c; + a_o->y = a_i->y * a_c; + a_o->z = a_i->z * a_c; +} + double DVector3_Magnitude(const dvector3_t *a_normal) { double xs = a_normal->x * a_normal->x; diff --git a/src/m_vector.h b/src/m_vector.h index 55669be03..1395744f2 100644 --- a/src/m_vector.h +++ b/src/m_vector.h @@ -19,6 +19,10 @@ typedef struct } dvector3_t; void DVector3_Load(dvector3_t *vec, double x, double y, double z); +void DVector3_Copy(dvector3_t *a_o, const dvector3_t *a_i); +void DVector3_Add(const dvector3_t *a_i, const dvector3_t *a_c, dvector3_t *a_o); +void DVector3_Subtract(const dvector3_t *a_i, const dvector3_t *a_c, dvector3_t *a_o); +void DVector3_Multiply(const dvector3_t *a_i, double a_c, dvector3_t *a_o); double DVector3_Magnitude(const dvector3_t *a_normal); double DVector3_Normalize(dvector3_t *a_normal); void DVector3_Negate(dvector3_t *a_o); diff --git a/src/r_defs.h b/src/r_defs.h index 17f94bc1b..51cc08646 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -60,6 +60,8 @@ typedef UINT8 lighttable_t; #define CMF_FADEFULLBRIGHTSPRITES 1 #define CMF_FOG 4 +#define TEXTURE_255_IS_TRANSPARENT + // ExtraColormap type. Use for extra_colormaps from now on. typedef struct extracolormap_s { diff --git a/src/r_draw.h b/src/r_draw.h index 77588d7de..6a6ab2db1 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -154,9 +154,11 @@ void R_VideoErase(size_t ofs, INT32 count); void R_DrawColumn_8(void); void R_DrawColumnClamped_8(void); +void R_Draw2sMultiPatchColumn_8(void); void R_DrawShadeColumn_8(void); void R_DrawTranslucentColumn_8(void); void R_DrawTranslucentColumnClamped_8(void); +void R_Draw2sMultiPatchTranslucentColumn_8(void); void R_DrawDropShadowColumn_8(void); void R_DrawTranslatedColumn_8(void); void R_DrawTranslatedTranslucentColumn_8(void); diff --git a/src/r_draw8.c b/src/r_draw8.c index 735127f88..2011e4640 100644 --- a/src/r_draw8.c +++ b/src/r_draw8.c @@ -192,6 +192,189 @@ void R_DrawColumnClamped_8(void) } } +void R_Draw2sMultiPatchColumn_8(void) +{ + INT32 count; + register UINT8 *dest; + register fixed_t frac; + fixed_t fracstep; + + count = dc_yh - dc_yl; + + if (count < 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) + return; +#endif + + // Framebuffer destination address. + dest = &topleft[dc_yl*vid.width + dc_x]; + + count++; + + // Determine scaling, which is the only mapping to be done. + fracstep = dc_iscale; + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); + + // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. + // This is as fast as it gets. + { + register const UINT8 *source = dc_source; + register const lighttable_t *colormap = dc_colormap; + register INT32 heightmask = dc_texheight-1; + register UINT8 val; + if (dc_texheight & heightmask) // not a power of 2 -- killough + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= heightmask) + frac -= heightmask; + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + // heightmask is the Tutti-Frutti fix + val = source[frac>>FRACBITS]; + + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + + dest += vid.width; + + // Avoid overflow. + if (fracstep > 0x7FFFFFFF - frac) + frac += fracstep - heightmask; + else + frac += fracstep; + + while (frac >= heightmask) + frac -= heightmask; + } while (--count); + } + else + { + while ((count -= 2) >= 0) // texture height is a power of 2 + { + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + dest += vid.width; + frac += fracstep; + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + dest += vid.width; + frac += fracstep; + } + if (count & 1) + { + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = colormap[val]; + } + } + } +} + +void R_Draw2sMultiPatchTranslucentColumn_8(void) +{ + INT32 count; + register UINT8 *dest; + register fixed_t frac; + fixed_t fracstep; + + count = dc_yh - dc_yl; + + if (count < 0) // Zero length, column does not exceed a pixel. + return; + +#ifdef RANGECHECK + if ((unsigned)dc_x >= (unsigned)vid.width || dc_yl < 0 || dc_yh >= vid.height) + return; +#endif + + // Framebuffer destination address. + dest = &topleft[dc_yl*vid.width + dc_x]; + + count++; + + // Determine scaling, which is the only mapping to be done. + fracstep = dc_iscale; + frac = dc_texturemid + FixedMul((dc_yl << FRACBITS) - centeryfrac, fracstep); + + // Inner loop that does the actual texture mapping, e.g. a DDA-like scaling. + // This is as fast as it gets. + { + register const UINT8 *source = dc_source; + register const UINT8 *transmap = dc_transmap; + register const lighttable_t *colormap = dc_colormap; + register INT32 heightmask = dc_texheight-1; + register UINT8 val; + if (dc_texheight & heightmask) // not a power of 2 -- killough + { + heightmask++; + heightmask <<= FRACBITS; + + if (frac < 0) + while ((frac += heightmask) < 0); + else + while (frac >= heightmask) + frac -= heightmask; + + do + { + // Re-map color indices from wall texture column + // using a lighting/special effects LUT. + // heightmask is the Tutti-Frutti fix + val = source[frac>>FRACBITS]; + + if (val != TRANSPARENTPIXEL) + *dest = *(transmap + (colormap[val]<<8) + (*dest)); + + dest += vid.width; + + // Avoid overflow. + if (fracstep > 0x7FFFFFFF - frac) + frac += fracstep - heightmask; + else + frac += fracstep; + + while (frac >= heightmask) + frac -= heightmask; + } while (--count); + } + else + { + while ((count -= 2) >= 0) // texture height is a power of 2 + { + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = *(transmap + (colormap[val]<<8) + (*dest)); + dest += vid.width; + frac += fracstep; + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = *(transmap + (colormap[val]<<8) + (*dest)); + dest += vid.width; + frac += fracstep; + } + if (count & 1) + { + val = source[(frac>>FRACBITS) & heightmask]; + if (val != TRANSPARENTPIXEL) + *dest = *(transmap + (colormap[val]<<8) + (*dest)); + } + } + } +} + /** \brief The R_DrawShadeColumn_8 function Experiment to make software go faster. Taken from the Boom source */ diff --git a/src/r_fps.c b/src/r_fps.c index 0773f228d..7f1f2bb30 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -120,6 +120,19 @@ static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixe return out; } +static double R_LerpDouble(double from, double to, double frac) +{ + return from + (frac * (to - from)); +} + +static dvector3_t *R_LerpDVector3(const dvector3_t *from, const dvector3_t *to, double frac, dvector3_t *out) +{ + DVector3_Subtract(to, from, out); + DVector3_Multiply(out, frac, out); + DVector3_Add(from, out, out); + return out; +} + // recalc necessary stuff for mouseaiming // slopes are already calculated for the full possible view (which is 4*viewheight). // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) @@ -497,6 +510,14 @@ void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope) FV2_Copy(&interp->dynslope.bakd, &slope->d); interp->dynslope.oldzdelta = interp->dynslope.bakzdelta = slope->zdelta; + + DVector3_Copy(&interp->dynslope.oldorigin, &slope->dorigin); + DVector3_Copy(&interp->dynslope.bakorigin, &slope->dorigin); + + DVector3_Copy(&interp->dynslope.oldnormdir, &slope->dnormdir); + DVector3_Copy(&interp->dynslope.baknormdir, &slope->dnormdir); + + interp->dynslope.olddzdelta = interp->dynslope.bakdzdelta = slope->dzdelta; } void R_InitializeLevelInterpolators(void) @@ -561,6 +582,21 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) FV3_Copy(&interp->dynslope.bako, &interp->dynslope.slope->o); FV2_Copy(&interp->dynslope.bakd, &interp->dynslope.slope->d); interp->dynslope.bakzdelta = interp->dynslope.slope->zdelta; + + DVector3_Copy(&interp->dynslope.oldorigin, &interp->dynslope.bakorigin); + DVector3_Copy(&interp->dynslope.oldnormdir, &interp->dynslope.baknormdir); + interp->dynslope.olddzdelta = interp->dynslope.bakdzdelta; + + if (interp->dynslope.slope->moved) + { + P_CalculateSlopeVectors(interp->dynslope.slope); + + interp->dynslope.slope->moved = false; + } + + DVector3_Copy(&interp->dynslope.bakorigin, &interp->dynslope.slope->dorigin); + DVector3_Copy(&interp->dynslope.baknormdir, &interp->dynslope.slope->dnormdir); + interp->dynslope.bakdzdelta = interp->dynslope.slope->dzdelta; break; } } @@ -646,7 +682,13 @@ void R_ApplyLevelInterpolators(fixed_t frac) R_LerpVector3(&interp->dynslope.oldo, &interp->dynslope.bako, frac, &interp->dynslope.slope->o); R_LerpVector2(&interp->dynslope.oldd, &interp->dynslope.bakd, frac, &interp->dynslope.slope->d); interp->dynslope.slope->zdelta = R_LerpFixed(interp->dynslope.oldzdelta, interp->dynslope.bakzdelta, frac); - interp->dynslope.slope->moved = true; + if (rendermode == render_soft) + { + double dfrac = FixedToDouble(frac); + R_LerpDVector3(&interp->dynslope.oldorigin, &interp->dynslope.bakorigin, dfrac, &interp->dynslope.slope->dorigin); + R_LerpDVector3(&interp->dynslope.oldnormdir, &interp->dynslope.baknormdir, dfrac, &interp->dynslope.slope->dnormdir); + interp->dynslope.slope->dzdelta = R_LerpDouble(interp->dynslope.olddzdelta, interp->dynslope.bakdzdelta, dfrac); + } break; } } @@ -704,6 +746,10 @@ void R_RestoreLevelInterpolators(void) FV3_Copy(&interp->dynslope.slope->o, &interp->dynslope.bako); FV2_Copy(&interp->dynslope.slope->d, &interp->dynslope.bakd); interp->dynslope.slope->zdelta = interp->dynslope.bakzdelta; + + DVector3_Copy(&interp->dynslope.slope->dorigin, &interp->dynslope.bakorigin); + DVector3_Copy(&interp->dynslope.slope->dnormdir, &interp->dynslope.baknormdir); + interp->dynslope.slope->dzdelta = interp->dynslope.bakdzdelta; break; } } diff --git a/src/r_fps.h b/src/r_fps.h index cd40b0a9a..33224a83a 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -115,6 +115,9 @@ typedef struct levelinterpolator_s { vector3_t oldo, bako; vector2_t oldd, bakd; fixed_t oldzdelta, bakzdelta; + dvector3_t oldorigin, bakorigin; + dvector3_t oldnormdir, baknormdir; + double olddzdelta, bakdzdelta; } dynslope; }; } levelinterpolator_t; diff --git a/src/r_segs.c b/src/r_segs.c index 51487d242..8e2a72ccc 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -120,6 +120,98 @@ static INT16 R_BottomLightLevel(side_t *side, UINT8 base_lightlevel) } */ +// If we have a multi-patch texture on a 2sided wall (rare) then we draw +// it using R_DrawColumn, else we draw it using R_DrawMaskedColumn, this +// way we don't have to store extra post_t info with each column for +// multi-patch textures. They are not normally needed as multi-patch +// textures don't have holes in it. At least not for now. +static void R_Render2sidedMultiPatchColumn(column_t *column, unsigned lengthcol) +{ + INT32 topscreen, bottomscreen; + + post_t *post = &column->posts[0]; + if (!post->length) + return; + + topscreen = sprtopscreen; + bottomscreen = topscreen + spryscale * lengthcol; + + dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS; + dc_yh = (bottomscreen-1)>>FRACBITS; + + if (windowtop != INT32_MAX && windowbottom != INT32_MAX) + { + dc_yl = ((windowtop + FRACUNIT)>>FRACBITS); + dc_yh = (windowbottom - 1)>>FRACBITS; + } + + if (dc_yh >= mfloorclip[dc_x]) + dc_yh = mfloorclip[dc_x] - 1; + if (dc_yl <= mceilingclip[dc_x]) + dc_yl = mceilingclip[dc_x] + 1; + + if (dc_yl >= vid.height || dc_yh < 0) + return; + + if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0) + { + dc_source = column->pixels + post->data_offset; + dc_postlength = post->length; + + if (colfunc == colfuncs[BASEDRAWFUNC]) + (colfuncs[COLDRAWFUNC_TWOSMULTIPATCH])(); + else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY]) + (colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS])(); + else + colfunc(); + } +} + +static void R_RenderFlipped2sidedMultiPatchColumn(column_t *column, unsigned lengthcol) +{ + INT32 topscreen, bottomscreen; + + void (*localcolfunc)(void); + + post_t *post = &column->posts[0]; + if (!post->length) + return; + + topscreen = sprtopscreen; + bottomscreen = topscreen + spryscale * lengthcol; + + dc_yl = (sprtopscreen+FRACUNIT-1)>>FRACBITS; + dc_yh = (bottomscreen-1)>>FRACBITS; + + if (windowtop != INT32_MAX && windowbottom != INT32_MAX) + { + dc_yl = ((windowtop + FRACUNIT)>>FRACBITS); + dc_yh = (windowbottom - 1)>>FRACBITS; + } + + if (dc_yh >= mfloorclip[dc_x]) + dc_yh = mfloorclip[dc_x] - 1; + if (dc_yl <= mceilingclip[dc_x]) + dc_yl = mceilingclip[dc_x] + 1; + + if (dc_yl >= vid.height || dc_yh < 0) + return; + + if (dc_yl <= dc_yh && dc_yh < vid.height && dc_yh > 0) + { + dc_postlength = post->length; + + if (colfunc == colfuncs[BASEDRAWFUNC]) + localcolfunc = colfuncs[COLDRAWFUNC_TWOSMULTIPATCH]; + else if (colfunc == colfuncs[COLDRAWFUNC_FUZZY]) + localcolfunc = colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS]; + else + localcolfunc = colfunc; + + R_DrawFlippedPost(column->pixels + post->data_offset, post->length, localcolfunc); + } +} + void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) { size_t pindex; @@ -207,7 +299,16 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) // Texture must be cached R_CheckTextureCache(texnum); - if (vertflip) // vertically flipped? + // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures + // are not stored per-column with post info in SRB2 + if (!textures[texnum]->transparency) + { + if (vertflip) // vertically flipped? + colfunc_2s = R_RenderFlipped2sidedMultiPatchColumn; + else + colfunc_2s = R_Render2sidedMultiPatchColumn; + } + else if (vertflip) // vertically flipped? colfunc_2s = R_DrawFlippedMaskedColumn; else colfunc_2s = R_DrawMaskedColumn; // render the usual 2sided single-patch packed texture @@ -836,7 +937,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) // Texture must be cached R_CheckTextureCache(texnum); - if (vertflip) // vertically flipped? + // handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures + // are not stored per-column with post info in SRB2 + if (!textures[texnum]->transparency) + { + if (vertflip) // vertically flipped? + colfunc_2s = R_RenderFlipped2sidedMultiPatchColumn; + else + colfunc_2s = R_Render2sidedMultiPatchColumn; + } + else if (vertflip) // vertically flipped? colfunc_2s = R_DrawRepeatFlippedMaskedColumn; else colfunc_2s = R_DrawRepeatMaskedColumn; @@ -919,21 +1029,25 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { dc_iscale = 0xffffffffu / (unsigned)spryscale; - // Column has a single post and it matches the texture height, use regular column drawers - if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight) + // Skip if texture is multipatch + if (textures[texnum]->transparency) { - if (fuzzy) - colfunc = colfuncs[COLDRAWFUNC_FUZZY]; + // Column has a single post and it matches the texture height, use regular column drawers + if (col->num_posts == 1 && col->posts[0].topdelta == 0 && col->posts[0].length == (unsigned)dc_texheight) + { + if (fuzzy) + colfunc = colfuncs[COLDRAWFUNC_FUZZY]; + else + colfunc = colfuncs[BASEDRAWFUNC]; + } else - colfunc = colfuncs[BASEDRAWFUNC]; - } - else - { - // Otherwise use column drawers with extra checks - if (fuzzy) - colfunc = R_DrawTranslucentColumnClamped_8; - else - colfunc = R_DrawColumnClamped_8; + { + // Otherwise use column drawers with extra checks + if (fuzzy) + colfunc = colfuncs[COLDRAWFUNC_CLAMPEDTRANS]; + else + colfunc = colfuncs[COLDRAWFUNC_CLAMPED]; + } } } diff --git a/src/r_textures.c b/src/r_textures.c index 5d3fe24db..6e01d5641 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -147,9 +147,9 @@ static void R_DrawFlippedColumnInCache(column_t *column, UINT8 *cache, texpatch_ if (count > 0) { - for (; dest < cache + position + count; --source, is_opaque++) + for (; dest < cache + position + count; --source, dest++, is_opaque++) { - *dest++ = *source; + *dest = *source; *is_opaque = true; } } @@ -295,7 +295,6 @@ UINT8 *R_GenerateTexture(size_t texnum) UINT16 lumpnum = patch->lump; UINT8 *pdata; softwarepatch_t *realpatch; - boolean holey = false; #ifndef NO_PNG_LUMPS UINT8 header[PNG_HEADER_SIZE]; @@ -310,9 +309,11 @@ UINT8 *R_GenerateTexture(size_t texnum) pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); realpatch = (softwarepatch_t *)pdata; + texture->transparency = false; + // Check the patch for holes. if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) - holey = true; + texture->transparency = true; else { UINT8 *colofs = (UINT8 *)realpatch->columnofs; @@ -332,12 +333,12 @@ UINT8 *R_GenerateTexture(size_t texnum) col = (doompost_t *)((UINT8 *)col + col->length + 4); } if (y < texture->height) - holey = true; // this texture is HOLEy! D: + texture->transparency = true; // this texture is HOLEy! D: } } // If the patch uses transparency, we have to save it this way. - if (holey) + if (texture->transparency) { texture->flip = patch->flip; @@ -378,6 +379,15 @@ UINT8 *R_GenerateTexture(size_t texnum) temp_columns = Z_Calloc(sizeof(column_t) * texture->width, PU_STATIC, NULL); temp_block = Z_Calloc(total_pixels, PU_STATIC, NULL); +#ifdef TEXTURE_255_IS_TRANSPARENT + texture->transparency = false; + + // Transparency hack + memset(temp_block, TRANSPARENTPIXEL, total_pixels); +#else + texture->transparency = true; +#endif + for (x = 0; x < texture->width; x++) { column_t *column = &temp_columns[x]; @@ -474,13 +484,27 @@ UINT8 *R_GenerateTexture(size_t texnum) // Now write the columns column_posts = Z_Calloc(sizeof(unsigned) * texture->width, PU_STATIC, NULL); +#ifdef TEXTURE_255_IS_TRANSPARENT + total_posts = texture->width; + temp_posts = Z_Realloc(temp_posts, sizeof(post_t) * total_posts, PU_CACHE, NULL); +#endif + for (x = 0; x < texture->width; x++) { post_t *post = NULL; - boolean was_opaque = false; column_t *column = &temp_columns[x]; +#ifdef TEXTURE_255_IS_TRANSPARENT + post = &temp_posts[x]; + post->topdelta = 0; + post->length = texture->height; + post->data_offset = 0; + column_posts[x] = x; + column->num_posts = 1; +#else + boolean was_opaque = false; + column_posts[x] = (unsigned)-1; for (INT32 y = 0; y < texture->height; y++) @@ -510,6 +534,7 @@ UINT8 *R_GenerateTexture(size_t texnum) post->length++; } +#endif } blocksize = (sizeof(column_t) * texture->width) + (sizeof(post_t) * total_posts) + (sizeof(UINT8) * total_pixels); diff --git a/src/r_textures.h b/src/r_textures.h index eb68ec09f..7e1588851 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -54,6 +54,7 @@ typedef struct char name[8]; UINT32 hash; UINT8 type; // TEXTURETYPE_* + boolean transparency; INT16 width, height; UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both void *flat; // The texture, as a flat. diff --git a/src/screen.c b/src/screen.c index 9a82a1561..014a20117 100644 --- a/src/screen.c +++ b/src/screen.c @@ -112,6 +112,10 @@ void SCR_SetDrawFuncs(void) colfuncs[COLDRAWFUNC_SHADE] = R_DrawShadeColumn_8; colfuncs[COLDRAWFUNC_SHADOWED] = R_DrawColumnShadowed_8; colfuncs[COLDRAWFUNC_TRANSTRANS] = R_DrawTranslatedTranslucentColumn_8; + colfuncs[COLDRAWFUNC_CLAMPED] = R_DrawColumnClamped_8; + colfuncs[COLDRAWFUNC_CLAMPEDTRANS] = R_DrawTranslucentColumnClamped_8; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCH] = R_Draw2sMultiPatchColumn_8; + colfuncs[COLDRAWFUNC_TWOSMULTIPATCHTRANS] = R_Draw2sMultiPatchTranslucentColumn_8; colfuncs[COLDRAWFUNC_FOG] = R_DrawFogColumn_8; spanfuncs[SPANDRAWFUNC_TRANS] = R_DrawTranslucentSpan_8; diff --git a/src/screen.h b/src/screen.h index 8b952e553..e23e8cbd6 100644 --- a/src/screen.h +++ b/src/screen.h @@ -97,6 +97,10 @@ enum COLDRAWFUNC_SHADE, COLDRAWFUNC_SHADOWED, COLDRAWFUNC_TRANSTRANS, + COLDRAWFUNC_CLAMPED, + COLDRAWFUNC_CLAMPEDTRANS, + COLDRAWFUNC_TWOSMULTIPATCH, + COLDRAWFUNC_TWOSMULTIPATCHTRANS, COLDRAWFUNC_FOG, COLDRAWFUNC_MAX diff --git a/src/snake.c b/src/snake.c index 2349d5fdb..4219d5b8f 100644 --- a/src/snake.c +++ b/src/snake.c @@ -582,7 +582,7 @@ boolean Snake_JoyGrabber(void *opaque, event_t *ev) { snake_t *snake = opaque; - if (ev->type == ev_joystick && ev->key == 0) + if (snake != NULL && ev->type == ev_joystick && ev->key == 0) { snake->joyevents[snake->joyeventcount] = ev; snake->joyeventcount++;