diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ec18032e..2f3a94d49 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -681,6 +681,7 @@ file( GLOB HEADER_FILES sound/wildmidi/*.h xlat/*.h swrenderer/*.h + swrenderer/textures/*.h swrenderer/drawers/*.h swrenderer/scene/*.h swrenderer/segments/*.h @@ -1097,7 +1098,10 @@ set (PCH_SOURCES textures/anim_switches.cpp textures/bitmap.cpp textures/texture.cpp + textures/image.cpp + textures/imagetexture.cpp textures/texturemanager.cpp + textures/multipatchtexturebuilder.cpp textures/skyboxtexture.cpp textures/formats/automaptexture.cpp textures/formats/brightmaptexture.cpp @@ -1105,6 +1109,7 @@ set (PCH_SOURCES textures/formats/canvastexture.cpp textures/formats/ddstexture.cpp textures/formats/flattexture.cpp + textures/formats/fontchars.cpp textures/formats/imgztexture.cpp textures/formats/jpegtexture.cpp textures/formats/md5check.cpp @@ -1116,8 +1121,6 @@ set (PCH_SOURCES textures/formats/emptytexture.cpp textures/formats/shadertexture.cpp textures/formats/tgatexture.cpp - textures/formats/worldtexture.cpp - textures/formats/warptexture.cpp textures/hires/hqresize.cpp textures/hires/hirestex.cpp xlat/parse_xlat.cpp @@ -1141,6 +1144,7 @@ set (PCH_SOURCES r_data/voxels.cpp r_data/renderinfo.cpp r_data/renderstyle.cpp + r_data/r_canvastexture.cpp r_data/r_interpolate.cpp r_data/r_vanillatrans.cpp r_data/r_sections.cpp @@ -1244,6 +1248,9 @@ set (PCH_SOURCES sound/wildmidi/reverb.cpp sound/wildmidi/wildmidi_lib.cpp sound/wildmidi/wm_error.cpp + swrenderer/textures/r_swtexture.cpp + swrenderer/textures/warptexture.cpp + swrenderer/textures/swcanvastexture.cpp events.cpp ) diff --git a/src/am_map.cpp b/src/am_map.cpp index 505e3561f..4357136eb 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -1194,12 +1194,12 @@ static void AM_ScrollParchment (double dmapx, double dmapy) if (mapback.isValid()) { - FTexture *backtex = TexMan[mapback]; + FTexture *backtex = TexMan.GetTexture(mapback); if (backtex != NULL) { - int pwidth = backtex->GetWidth(); - int pheight = backtex->GetHeight(); + int pwidth = backtex->GetDisplayWidth(); + int pheight = backtex->GetDisplayHeight(); while(mapxstart > 0) mapxstart -= pwidth; @@ -1689,11 +1689,11 @@ void AM_clearFB (const AMColor &color) } else { - FTexture *backtex = TexMan[mapback]; + FTexture *backtex = TexMan.GetTexture(mapback); if (backtex != NULL) { - int pwidth = backtex->GetWidth(); - int pheight = backtex->GetHeight(); + int pwidth = backtex->GetDisplayWidth(); + int pheight = backtex->GetDisplayHeight(); int x, y; //blit the automap background to the screen. @@ -2212,8 +2212,7 @@ void AM_drawSubsectors() } // Draw the polygon. - FTexture *pic = TexMan(maptex); - if (pic != nullptr && pic->UseType != ETextureType::Null) + if (maptex.isValid()) { // Hole filling "subsectors" are not necessarily convex so they require real triangulation. // These things are extremely rare so performance is secondary here. @@ -2235,7 +2234,7 @@ void AM_drawSubsectors() } else indices.clear(); - screen->FillSimplePoly(TexMan(maptex), + screen->FillSimplePoly(TexMan.GetTexture(maptex, true), &points[0], points.Size(), originx, originy, scale / scalex, @@ -3020,7 +3019,7 @@ void AM_drawThings () rotation = int((angle.Normalized360() * (16. / 360.)).Degrees); const FTextureID textureID = frame->Texture[show > 2 ? rotation : 0]; - texture = TexMan(textureID); + texture = TexMan.GetTexture(textureID, true); } if (texture == NULL) goto drawTriangle; // fall back to standard display if no sprite can be found. @@ -3116,7 +3115,7 @@ void AM_drawThings () static void DrawMarker (FTexture *tex, double x, double y, int yadjust, INTBOOL flip, double xscale, double yscale, int translation, double alpha, uint32_t fillcolor, FRenderStyle renderstyle) { - if (tex == NULL || tex->UseType == ETextureType::Null) + if (tex == NULL || !tex->isValid()) { return; } @@ -3125,8 +3124,8 @@ static void DrawMarker (FTexture *tex, double x, double y, int yadjust, AM_rotatePoint (&x, &y); } screen->DrawTexture (tex, CXMTOF(x) + f_x, CYMTOF(y) + yadjust + f_y, - DTA_DestWidthF, tex->GetScaledWidthDouble() * CleanXfac * xscale, - DTA_DestHeightF, tex->GetScaledHeightDouble() * CleanYfac * yscale, + DTA_DestWidthF, tex->GetDisplayWidthDouble() * CleanXfac * xscale, + DTA_DestHeightF, tex->GetDisplayHeightDouble() * CleanYfac * yscale, DTA_ClipTop, f_y, DTA_ClipBottom, f_y + f_h, DTA_ClipLeft, f_x, @@ -3151,7 +3150,7 @@ void AM_drawMarks () { if (markpoints[i].x != -1) { - DrawMarker (TexMan(marknums[i]), markpoints[i].x, markpoints[i].y, -3, 0, + DrawMarker (TexMan.GetTexture(marknums[i], true), markpoints[i].x, markpoints[i].y, -3, 0, 1, 1, 0, 1, 0, LegacyRenderStyles[STYLE_Normal]); } } @@ -3184,13 +3183,13 @@ void AM_drawAuthorMarkers () if (mark->picnum.isValid()) { - tex = TexMan(mark->picnum); - if (tex->Rotations != 0xFFFF) + tex = TexMan.GetTexture(mark->picnum, true); + if (tex->GetRotations() != 0xFFFF) { - spriteframe_t *sprframe = &SpriteFrames[tex->Rotations]; + spriteframe_t *sprframe = &SpriteFrames[tex->GetRotations()]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan[picnum]; + tex = TexMan.GetTexture(picnum); } } else @@ -3205,7 +3204,7 @@ void AM_drawAuthorMarkers () spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + mark->frame]; picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan[picnum]; + tex = TexMan.GetTexture(picnum); } } FActorIterator it (mark->args[0]); diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index f43e77473..2aa941913 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1052,7 +1052,7 @@ CCMD(changesky) sky1name = argv[1]; if (sky1name[0] != 0) { - FTextureID newsky = TexMan.GetTexture(sky1name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + FTextureID newsky = TexMan.GetTextureID(sky1name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); if (newsky.Exists()) { sky1texture = level.skytexture1 = newsky; diff --git a/src/c_console.cpp b/src/c_console.cpp index 9a38ae1cf..caea2a741 100644 --- a/src/c_console.cpp +++ b/src/c_console.cpp @@ -555,7 +555,7 @@ void C_InitConback() if (!conback.isValid()) { - conback = TexMan.GetTexture (gameinfo.TitlePage, ETextureType::MiscPatch); + conback = TexMan.GetTextureID (gameinfo.TitlePage, ETextureType::MiscPatch); conshade = MAKEARGB(175,0,0,0); conline = true; } @@ -1083,7 +1083,7 @@ void C_DrawConsole () else if (ConBottom) { int visheight; - FTexture *conpic = TexMan[conback]; + FTexture *conpic = TexMan.GetTexture(conback); visheight = ConBottom; diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 2fa68208a..dccebef11 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -223,8 +223,7 @@ DEFINE_FIELD_X(DehInfo, DehInfo, BlueAC) TArray TouchedActors; -char *UnchangedSpriteNames; -int NumUnchangedSprites; +TArray UnchangedSpriteNames; bool changedStates; // Sprite<->Class map for DehackedPickup::DetermineType @@ -395,17 +394,10 @@ static bool HandleKey (const struct Key *keys, void *structure, const char *key, static int FindSprite (const char *sprname) { - int i; - uint32_t nameint = *((uint32_t *)sprname); - - for (i = 0; i < NumUnchangedSprites; ++i) - { - if (*((uint32_t *)&UnchangedSpriteNames[i*4]) == nameint) - { - return i; - } - } - return -1; + uint32_t nameint; + memcpy(&nameint, sprname, 4); + auto f = UnchangedSpriteNames.Find(nameint); + return f == UnchangedSpriteNames.Size() ? -1 : f; } static FState *FindState (int statenum) @@ -2662,31 +2654,16 @@ static void UnloadDehSupp () // that was altered by the first. So we need to keep the // StateMap around until all patches have been applied. DehUseCount = 0; - Actions.Clear(); - Actions.ShrinkToFit(); - OrgHeights.Clear(); - OrgHeights.ShrinkToFit(); - CodePConv.Clear(); - CodePConv.ShrinkToFit(); - OrgSprNames.Clear(); - OrgSprNames.ShrinkToFit(); - SoundMap.Clear(); - SoundMap.ShrinkToFit(); - InfoNames.Clear(); - InfoNames.ShrinkToFit(); - BitNames.Clear(); - BitNames.ShrinkToFit(); - StyleNames.Clear(); - StyleNames.ShrinkToFit(); - AmmoNames.Clear(); - AmmoNames.ShrinkToFit(); - - if (UnchangedSpriteNames != NULL) - { - delete[] UnchangedSpriteNames; - UnchangedSpriteNames = NULL; - NumUnchangedSprites = 0; - } + Actions.Reset(); + OrgHeights.Reset(); + CodePConv.Reset(); + OrgSprNames.Reset(); + SoundMap.Reset(); + InfoNames.Reset(); + BitNames.Reset(); + StyleNames.Reset(); + AmmoNames.Reset(); + UnchangedSpriteNames.Reset(); if (EnglishStrings != NULL) { delete EnglishStrings; @@ -2714,7 +2691,6 @@ static bool LoadDehSupp () return false; } bool gotnames = false; - int i; if (++DehUseCount > 1) @@ -2728,14 +2704,11 @@ static bool LoadDehSupp () EnglishStrings->LoadStrings (true); } - if (UnchangedSpriteNames == NULL) + + UnchangedSpriteNames.Resize(sprites.Size()); + for (unsigned i = 0; i < UnchangedSpriteNames.Size(); ++i) { - UnchangedSpriteNames = new char[sprites.Size()*4]; - NumUnchangedSprites = sprites.Size(); - for (i = 0; i < NumUnchangedSprites; ++i) - { - memcpy (UnchangedSpriteNames+i*4, &sprites[i].name, 4); - } + memcpy (&UnchangedSpriteNames[i], &sprites[i].name, 4); } FScanner sc; diff --git a/src/d_main.cpp b/src/d_main.cpp index 7827bffd2..a7a0ef46a 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -184,18 +184,19 @@ CVAR (Int, snd_drawoutput, 0, 0); CUSTOM_CVAR (String, vid_cursor, "None", CVAR_ARCHIVE | CVAR_NOINITCALL) { bool res = false; + if (!stricmp(self, "None" ) && gameinfo.CursorPic.IsNotEmpty()) { - res = I_SetCursor(TexMan[gameinfo.CursorPic]); + res = I_SetCursor(TexMan.GetTextureByName(gameinfo.CursorPic)); } else { - res = I_SetCursor(TexMan[self]); + res = I_SetCursor(TexMan.GetTextureByName(self)); } if (!res) { - I_SetCursor(TexMan["cursor"]); + I_SetCursor(TexMan.GetTextureByName("cursor")); } } @@ -834,16 +835,16 @@ void D_Display () int x; FString pstring = "By "; - tex = TexMan(gameinfo.PauseSign); - x = (SCREENWIDTH - tex->GetScaledWidth() * CleanXfac)/2 + - tex->GetScaledLeftOffset(0) * CleanXfac; + tex = TexMan.GetTextureByName(gameinfo.PauseSign, true); + x = (SCREENWIDTH - tex->GetDisplayWidth() * CleanXfac)/2 + + tex->GetDisplayLeftOffset() * CleanXfac; screen->DrawTexture (tex, x, 4, DTA_CleanNoMove, true, TAG_DONE); if (paused && multiplayer) { pstring += players[paused - 1].userinfo.GetName(); screen->DrawText(SmallFont, CR_RED, (screen->GetWidth() - SmallFont->StringWidth(pstring)*CleanXfac) / 2, - (tex->GetScaledHeight() * CleanYfac) + 4, pstring, DTA_CleanNoMove, true, TAG_DONE); + (tex->GetDisplayHeight() * CleanYfac) + 4, pstring, DTA_CleanNoMove, true, TAG_DONE); } } @@ -855,8 +856,8 @@ void D_Display () D_DrawIcon = NULL; if (picnum.isValid()) { - FTexture *tex = TexMan[picnum]; - screen->DrawTexture (tex, 160 - tex->GetScaledWidth()/2, 100 - tex->GetScaledHeight()/2, + FTexture *tex = TexMan.GetTexture(picnum); + screen->DrawTexture (tex, 160 - tex->GetDisplayWidth()/2, 100 - tex->GetDisplayHeight()/2, DTA_320x200, true, TAG_DONE); } NoWipe = 10; @@ -1051,7 +1052,7 @@ void D_PageDrawer (void) screen->Clear(0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); if (Page.Exists()) { - screen->DrawTexture (TexMan(Page), 0, 0, + screen->DrawTexture (TexMan.GetTexture(Page, true), 0, 0, DTA_Fullscreen, true, DTA_Masked, false, DTA_BilinearFilter, true, @@ -1241,7 +1242,7 @@ void D_DoAdvanceDemo (void) case 3: if (gameinfo.advisoryTime) { - Advisory = TexMan["ADVISOR"]; + Advisory = TexMan.GetTextureByName("ADVISOR"); demosequence = 1; pagetic = (int)(gameinfo.advisoryTime * TICRATE); break; @@ -2708,7 +2709,7 @@ void D_DoomMain (void) DestroyCVarsFlagged(CVAR_MOD); // Delete any cvar left by mods FS_Close(); // destroy the global FraggleScript. DeinitMenus(); - LightDefaults.Clear(); // this can leak heap memory if it isn't cleared. + LightDefaults.DeleteAndClear(); // this can leak heap memory if it isn't cleared. // delete DoomStartupInfo data DoomStartupInfo.Name = (const char*)0; diff --git a/src/d_player.h b/src/d_player.h index 4eb207fa9..4acae8ac8 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -453,7 +453,7 @@ public: TObjPtr MUSINFOactor = nullptr; // For MUSINFO purposes int8_t MUSINFOtics = 0; - bool settings_controller = true; // Player can control game settings. + bool settings_controller = false; // Player can control game settings. int8_t crouching = 0; int8_t crouchdir = 0; diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index cd1b49a10..51e95313d 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -322,7 +322,6 @@ static void MarkRoot() M_MarkMenus(); Mark(DIntermissionController::CurrentIntermission); DThinker::MarkRoots(); - FCanvasTextureInfo::Mark(); Mark(E_FirstEventHandler); Mark(E_LastEventHandler); level.Mark(); diff --git a/src/f_wipe.cpp b/src/f_wipe.cpp index 25c283038..80e576100 100644 --- a/src/f_wipe.cpp +++ b/src/f_wipe.cpp @@ -41,10 +41,13 @@ public: Height = h; } - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override + FBitmap GetBgraBitmap(PalEntry*, int *trans) override { - bmp->CopyPixelDataRGB(x, y, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, rotate, CF_RGBA, inf); - return 0; + FBitmap bmp; + bmp.Create(Width, Height); + bmp.CopyPixelDataRGB(0, 0, (uint8_t*)WorkBuffer.Data(), Width, Height, 4, Width*4, 0, CF_RGBA, nullptr); + if (trans) *trans = 0; + return bmp; } uint32_t *GetBuffer() @@ -304,8 +307,8 @@ bool Wiper_Melt::Run(int ticks) // Only draw for the final tick. // No need for optimization. Wipes won't ever be drawn with anything else. - int w = startScreen->GetWidth(); - int h = startScreen->GetHeight(); + int w = startScreen->GetDisplayWidth(); + int h = startScreen->GetDisplayHeight(); dpt.x = i * w / WIDTH; dpt.y = MAX(0, y[i] * h / HEIGHT); rect.left = dpt.x; @@ -369,9 +372,8 @@ bool Wiper_Burn::Run(int ticks) Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); done = (Density < 0); } - - auto mat = FMaterial::ValidateTexture(BurnTexture, false); - mat->Clean(true); + + BurnTexture->SystemTextures.Clean(true, true); const uint8_t *src = BurnArray; uint32_t *dest = (uint32_t *)BurnTexture->GetBuffer(); for (int y = HEIGHT; y != 0; --y) diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 6c475c0f8..fe1559991 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -1892,7 +1892,7 @@ void FParser::SF_FloorTexture(void) if(t_argc > 1) { int i = -1; - FTextureID picnum = TexMan.GetTexture(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // set all sectors with tag FSSectorTagIterator itr(tagnum); @@ -1903,8 +1903,8 @@ void FParser::SF_FloorTexture(void) } t_return.type = svt_string; - FTexture * tex = TexMan[sector->GetTexture(sector_t::floor)]; - t_return.string = tex? tex->Name : ""; + FTexture * tex = TexMan.GetTexture(sector->GetTexture(sector_t::floor)); + t_return.string = tex? tex->GetName() : ""; } } @@ -1982,7 +1982,7 @@ void FParser::SF_CeilingTexture(void) if(t_argc > 1) { int i = -1; - FTextureID picnum = TexMan.GetTexture(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // set all sectors with tag FSSectorTagIterator itr(tagnum); @@ -1993,8 +1993,8 @@ void FParser::SF_CeilingTexture(void) } t_return.type = svt_string; - FTexture * tex = TexMan[sector->GetTexture(sector_t::ceiling)]; - t_return.string = tex? tex->Name : ""; + FTexture * tex = TexMan.GetTexture(sector->GetTexture(sector_t::ceiling)); + t_return.string = tex? tex->GetName() : ""; } } @@ -2235,7 +2235,7 @@ void FParser::SF_SetLineTexture(void) position=3-position; texture = stringvalue(t_argv[3]); - texturenum = TexMan.GetTexture(texture, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + texturenum = TexMan.GetTextureID(texture, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); FLineIdIterator itr(tag); while ((i = itr.Next()) >= 0) @@ -2252,7 +2252,7 @@ void FParser::SF_SetLineTexture(void) } else // and an improved legacy version { - FTextureID picnum = TexMan.GetTexture(t_argv[1].string, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + FTextureID picnum = TexMan.GetTextureID(t_argv[1].string, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); side = !!intvalue(t_argv[2]); int sections = intvalue(t_argv[3]); @@ -2453,7 +2453,7 @@ void FParser::SF_PlayerKeys(void) else { givetake = intvalue(t_argv[2]); - ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, players[playernum].mo, keyname.GetIndex(), 1); + ScriptUtil::Exec(givetake?NAME_GiveInventory : NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, keyname.GetIndex(), ScriptUtil::Int, 1, ScriptUtil::End); t_return.type = svt_int; t_return.value.i = 0; } @@ -2648,7 +2648,7 @@ void FParser::SF_GiveInventory(void) if(t_argc == 2) count=1; else count=intvalue(t_argv[2]); - ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, players[playernum].mo, FName(stringvalue(t_argv[1])).GetIndex(), count); + ScriptUtil::Exec(NAME_GiveInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End); t_return.type = svt_int; t_return.value.i = 0; } @@ -2671,7 +2671,7 @@ void FParser::SF_TakeInventory(void) if(t_argc == 2) count=32767; else count=intvalue(t_argv[2]); - ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, FName(stringvalue(t_argv[1])).GetIndex(), count); + ScriptUtil::Exec(NAME_TakeInventory, ScriptUtil::Pointer, players[playernum].mo, ScriptUtil::Int, FName(stringvalue(t_argv[1])).GetIndex(), ScriptUtil::Int, count, ScriptUtil::End); t_return.type = svt_int; t_return.value.i = 0; } diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp index 1d13118a8..1d5b86ce0 100644 --- a/src/fragglescript/t_load.cpp +++ b/src/fragglescript/t_load.cpp @@ -189,7 +189,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc) sc.MustGetStringName("="); sc.MustGetString(); - sky2texture = sky1texture = level.skytexture1 = level.skytexture2 = TexMan.GetTexture (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); + sky2texture = sky1texture = level.skytexture1 = level.skytexture2 = TexMan.GetTextureID (sc.String, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); R_InitSkyMap (); } else if (sc.Compare("interpic")) diff --git a/src/g_game.cpp b/src/g_game.cpp index b0c09d993..56ccd46b2 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1285,6 +1285,7 @@ void G_PlayerReborn (int player) log = p->LogText; chasecam = p->cheats & CF_CHASECAM; Bot = p->Bot; //Added by MC: + const bool settings_controller = p->settings_controller; // Reset player structure to its defaults p->~player_t(); @@ -1303,6 +1304,7 @@ void G_PlayerReborn (int player) p->LogText = log; p->cheats |= chasecam; p->Bot = Bot; //Added by MC: + p->settings_controller = settings_controller; p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately p->original_oldbuttons = ~0; diff --git a/src/g_level.cpp b/src/g_level.cpp index fe5477bf6..928c9ab13 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -123,10 +123,11 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, CVAR_NOINITCALL) CUSTOM_CVAR(Int, gl_lightmode, 3, CVAR_ARCHIVE | CVAR_NOINITCALL) { int newself = self; - if (newself > 4) newself = 8; // use 8 for software lighting to avoid conflicts with the bit mask - if (newself < 0) newself = 0; + if (newself > 8) newself = 16; // use 8 and 16 for software lighting to avoid conflicts with the bit mask + else if (newself > 4) newself = 8; + else if (newself < 0) newself = 0; if (self != newself) self = newself; - else if ((level.info == nullptr || level.info->lightmode == -1)) level.lightmode = self; + else if ((level.info == nullptr || level.info->lightmode == ELightMode::NotSet)) level.lightmode = (ELightMode)*self; } @@ -968,7 +969,7 @@ void G_DoLoadLevel (int position, bool autosave, bool newGame) // a flat. The data is in the WAD only because // we look for an actual index, instead of simply // setting one. - skyflatnum = TexMan.GetTexture (gameinfo.SkyFlatName, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + skyflatnum = TexMan.GetTextureID (gameinfo.SkyFlatName, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); // DOOM determines the sky texture to be used // depending on the current episode and the game version. @@ -1455,8 +1456,8 @@ void G_InitLevelLocals () level.info = info; level.skyspeed1 = info->skyspeed1; level.skyspeed2 = info->skyspeed2; - level.skytexture1 = TexMan.GetTexture(info->SkyPic1, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); - level.skytexture2 = TexMan.GetTexture(info->SkyPic2, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + level.skytexture1 = TexMan.GetTextureID(info->SkyPic1, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + level.skytexture2 = TexMan.GetTextureID(info->SkyPic2, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); level.fadeto = info->fadeto; level.cdtrack = info->cdtrack; level.cdid = info->cdid; @@ -1522,7 +1523,7 @@ void G_InitLevelLocals () level.DefaultEnvironment = info->DefaultEnvironment; - level.lightmode = info->lightmode < 0? gl_lightmode : info->lightmode; + level.lightmode = info->lightmode == ELightMode::NotSet? (ELightMode)*gl_lightmode : info->lightmode; level.brightfog = info->brightfog < 0? gl_brightfog : !!info->brightfog; level.lightadditivesurfaces = info->lightadditivesurfaces < 0 ? gl_lightadditivesurfaces : !!info->lightadditivesurfaces; level.notexturefill = info->notexturefill < 0 ? gl_notexturefill : !!info->notexturefill; @@ -1959,6 +1960,7 @@ void FLevelLocals::Tick () void FLevelLocals::Mark() { + canvasTextureInfo.Mark(); for (auto &s : sectorPortals) { GC::Mark(s.mSkybox); diff --git a/src/g_level.h b/src/g_level.h index a98a8d415..46ffbf795 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -247,6 +247,7 @@ enum ELevelFlags : unsigned int LEVEL3_NOCOLOREDSPRITELIGHTING = 0x00000010, // draw sprites only with color-less light LEVEL3_EXITNORMALUSED = 0x00000020, LEVEL3_EXITSECRETUSED = 0x00000040, + LEVEL3_FORCEWORLDPANNING = 0x00000080, // Forces the world panning flag for all textures, even those without it explicitly set. }; @@ -314,6 +315,19 @@ struct FExitText } }; +enum class ELightMode : int8_t +{ + NotSet = -1, + LinearStandard = 0, + DoomBright = 1, + Doom = 2, + DoomDark = 3, + DoomLegacy = 4, + ZDoomSoftware = 8, + DoomSoftware = 16 +}; + + struct level_info_t { int levelnum; @@ -395,7 +409,7 @@ struct level_info_t TArray EventHandlers; - int8_t lightmode; + ELightMode lightmode; int8_t brightfog; int8_t lightadditivesurfaces; int8_t notexturefill; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index c39da9250..c9eceabb6 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -44,12 +44,13 @@ #include "p_local.h" #include "p_destructible.h" #include "r_data/r_sections.h" +#include "r_data/r_canvastexture.h" struct FLevelLocals { - void Tick (); + void Tick(); void Mark(); - void AddScroller (int secnum); + void AddScroller(int secnum); void SetInterMusic(const char *nextmap); void SetMusicVolume(float v); @@ -87,7 +88,7 @@ struct FLevelLocals TArray gamenodes; node_t *headgamenode; TArray rejectmatrix; - + static const int BODYQUESIZE = 32; TObjPtr bodyque[BODYQUESIZE]; int bodyqueslot; @@ -100,9 +101,10 @@ struct FLevelLocals FDisplacementTable Displacements; FPortalBlockmap PortalBlockmap; TArray linkedPortals; // only the linked portals, this is used to speed up looking for them in P_CollectConnectedGroups. - TArray portalGroups; + TArray portalGroups; TArray linePortalSpans; FSectionContainer sections; + FCanvasTextureInfo canvasTextureInfo; int NumMapSections; @@ -181,7 +183,7 @@ struct FLevelLocals float MusicVolume; // Hardware render stuff that can either be set via CVAR or MAPINFO - int lightmode; + ELightMode lightmode; bool brightfog; bool lightadditivesurfaces; bool notexturefill; @@ -192,7 +194,7 @@ struct FLevelLocals node_t *HeadNode() const { - return nodes.Size() == 0? nullptr : &nodes[nodes.Size() - 1]; + return nodes.Size() == 0 ? nullptr : &nodes[nodes.Size() - 1]; } node_t *HeadGamenode() const { @@ -202,9 +204,24 @@ struct FLevelLocals // Returns true if level is loaded from saved game or is being revisited as a part of a hub bool IsReentering() const { - return savegamerestore + return savegamerestore || (info != nullptr && info->Snapshot.mBuffer != nullptr && info->isValid()); } + + bool isSoftwareLighting() const + { + return lightmode >= ELightMode::ZDoomSoftware; + } + + bool isDarkLightMode() const + { + return !!((int)lightmode & (int)ELightMode::Doom); + } + + void SetFallbackLightMode() + { + lightmode = ELightMode::Doom; + } }; extern FLevelLocals level; diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index d621b231c..4595afff0 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -284,7 +284,7 @@ void level_info_t::Reset() PrecacheSounds.Clear(); brightfog = -1; - lightmode = -1; + lightmode = ELightMode::NotSet; notexturefill = -1; lightadditivesurfaces = -1; skyrotatevector = FVector3(0, 0, 1); @@ -1381,9 +1381,9 @@ DEFINE_MAP_OPTION(lightmode, false) parse.ParseAssign(); parse.sc.MustGetNumber(); - if ((parse.sc.Number >= 0 && parse.sc.Number <= 4) || parse.sc.Number == 8) + if ((parse.sc.Number >= 0 && parse.sc.Number <= 4) || parse.sc.Number == 8 || parse.sc.Number == 16) { - info->lightmode = uint8_t(parse.sc.Number); + info->lightmode = ELightMode(parse.sc.Number); } else { @@ -1553,6 +1553,7 @@ MapFlagHandlers[] = { "forcefakecontrast", MITYPE_SETFLAG3, LEVEL3_FORCEFAKECONTRAST, 0 }, { "nolightfade", MITYPE_SETFLAG3, LEVEL3_NOLIGHTFADE, 0 }, { "nocoloredspritelighting", MITYPE_SETFLAG3, LEVEL3_NOCOLOREDSPRITELIGHTING, 0 }, + { "forceworldpanning", MITYPE_SETFLAG3, LEVEL3_FORCEWORLDPANNING, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 }, { "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 }, diff --git a/src/g_shared/a_decals.cpp b/src/g_shared/a_decals.cpp index bb503fec0..09110bf75 100644 --- a/src/g_shared/a_decals.cpp +++ b/src/g_shared/a_decals.cpp @@ -262,9 +262,9 @@ FTextureID DBaseDecal::StickToWall (side_t *wall, double x, double y, F3DFloor * else return FNullTextureID(); CalcFracPos (wall, x, y); - FTexture *texture = TexMan[tex]; + FTexture *texture = TexMan.GetTexture(tex); - if (texture == NULL || texture->bNoDecals) + if (texture == NULL || texture->allowNoDecals()) { return FNullTextureID(); } @@ -492,15 +492,15 @@ void DBaseDecal::Spread (const FDecalTemplate *tpl, side_t *wall, double x, doub GetWallStuff (wall, v1, ldx, ldy); rorg = Length (x - v1->fX(), y - v1->fY()); - if ((tex = TexMan[PicNum]) == NULL) + if ((tex = TexMan.GetTexture(PicNum)) == NULL) { return; } - int dwidth = tex->GetWidth (); + int dwidth = tex->GetDisplayWidth (); DecalWidth = dwidth * ScaleX; - DecalLeft = tex->GetLeftOffset(0) * ScaleX; + DecalLeft = tex->GetDisplayLeftOffset() * ScaleX; DecalRight = DecalWidth - DecalLeft; SpreadSource = this; SpreadTemplate = tpl; diff --git a/src/g_shared/a_dynlight.cpp b/src/g_shared/a_dynlight.cpp index 13ce1f9c1..64d294aab 100644 --- a/src/g_shared/a_dynlight.cpp +++ b/src/g_shared/a_dynlight.cpp @@ -937,7 +937,7 @@ CCMD(listlights) if (dl->target) { FTextureID spr = sprites[dl->target->sprite].GetSpriteFrame(dl->target->frame, 0, 0., nullptr); - Printf(", frame = %s ", TexMan[spr]->Name.GetChars()); + Printf(", frame = %s ", TexMan.GetTexture(spr)->GetName().GetChars()); } diff --git a/src/g_shared/a_dynlight.h b/src/g_shared/a_dynlight.h index 369b826e3..685c3a39c 100644 --- a/src/g_shared/a_dynlight.h +++ b/src/g_shared/a_dynlight.h @@ -85,7 +85,7 @@ public: } protected: - FName m_Name; + FName m_Name = NAME_None; int m_Args[5] = { 0,0,0,0,0 }; double m_Param = 0; DVector3 m_Pos = { 0,0,0 }; diff --git a/src/g_statusbar/sbar_mugshot.cpp b/src/g_statusbar/sbar_mugshot.cpp index 950438f21..cf3c1f009 100644 --- a/src/g_statusbar/sbar_mugshot.cpp +++ b/src/g_statusbar/sbar_mugshot.cpp @@ -96,7 +96,7 @@ FTexture *FMugShotFrame::GetTexture(const char *default_face, const char *skin_f } sprite.UnlockBuffer(); } - return TexMan[TexMan.CheckForTexture(sprite, ETextureType::Any, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_AllowSkins)]; + return TexMan.GetTexture(TexMan.CheckForTexture(sprite, ETextureType::Any, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_AllowSkins)); } //=========================================================================== diff --git a/src/g_statusbar/sbarinfo.cpp b/src/g_statusbar/sbarinfo.cpp index c4941713b..7b1184cec 100644 --- a/src/g_statusbar/sbarinfo.cpp +++ b/src/g_statusbar/sbarinfo.cpp @@ -1188,12 +1188,11 @@ public: if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - if (forceWidth < 0) dx -= (texture->GetScaledWidthDouble()/2.0)-texture->GetScaledLeftOffsetDouble(0); - else dx -= forceWidth*(0.5-(texture->GetScaledLeftOffsetDouble(0)/texture->GetScaledWidthDouble())); - //Unoptimalized ^^formula is dx -= forceWidth/2.0-(texture->GetScaledLeftOffsetDouble()*forceWidth/texture->GetScaledWidthDouble()); + if (forceWidth < 0) dx -= (texture->GetDisplayWidthDouble()/2.0)-texture->GetDisplayLeftOffsetDouble(); + else dx -= forceWidth*(0.5-(texture->GetDisplayLeftOffsetDouble()/texture->GetDisplayWidthDouble())); - if (forceHeight < 0) dy -= (texture->GetScaledHeightDouble()/2.0)-texture->GetScaledTopOffsetDouble(0); - else dy -= forceHeight*(0.5-(texture->GetScaledTopOffsetDouble(0)/texture->GetScaledHeightDouble())); + if (forceHeight < 0) dy -= (texture->GetDisplayHeightDouble()/2.0)-texture->GetDisplayTopOffsetDouble(); + else dy -= forceHeight*(0.5-(texture->GetDisplayTopOffsetDouble()/texture->GetDisplayHeightDouble())); } dx += xOffset; @@ -1202,12 +1201,12 @@ public: if(!fullScreenOffsets) { double tmp = 0; - w = forceWidth < 0 ? texture->GetScaledWidthDouble() : forceWidth; - h = forceHeight < 0 ? texture->GetScaledHeightDouble() : forceHeight; - double dcx = clip[0] == 0 ? 0 : dx + clip[0] - texture->GetScaledLeftOffsetDouble(0); - double dcy = clip[1] == 0 ? 0 : dy + clip[1] - texture->GetScaledTopOffsetDouble(0); - double dcr = clip[2] == 0 ? INT_MAX : dx + w - clip[2] - texture->GetScaledLeftOffsetDouble(0); - double dcb = clip[3] == 0 ? INT_MAX : dy + h - clip[3] - texture->GetScaledTopOffsetDouble(0); + w = forceWidth < 0 ? texture->GetDisplayWidthDouble() : forceWidth; + h = forceHeight < 0 ? texture->GetDisplayHeightDouble() : forceHeight; + double dcx = clip[0] == 0 ? 0 : dx + clip[0] - texture->GetDisplayLeftOffsetDouble(); + double dcy = clip[1] == 0 ? 0 : dy + clip[1] - texture->GetDisplayTopOffsetDouble(); + double dcr = clip[2] == 0 ? INT_MAX : dx + w - clip[2] - texture->GetDisplayLeftOffsetDouble(); + double dcb = clip[3] == 0 ? INT_MAX : dy + h - clip[3] - texture->GetDisplayTopOffsetDouble(); if(clip[0] != 0 || clip[1] != 0) { @@ -1271,8 +1270,8 @@ public: bool xright = *x < 0 && !x.RelCenter(); bool ybot = *y < 0 && !y.RelCenter(); - w = (forceWidth < 0 ? texture->GetScaledWidthDouble() : forceWidth); - h = (forceHeight < 0 ? texture->GetScaledHeightDouble() : forceHeight); + w = (forceWidth < 0 ? texture->GetDisplayWidthDouble() : forceWidth); + h = (forceHeight < 0 ? texture->GetDisplayHeightDouble() : forceHeight); if(vid_fps && rx < 0 && ry >= 0) ry += 10; @@ -1289,10 +1288,10 @@ public: // Check for clipping if(clip[0] != 0 || clip[1] != 0 || clip[2] != 0 || clip[3] != 0) { - rcx = clip[0] == 0 ? 0 : rx+((clip[0] - texture->GetScaledLeftOffsetDouble(0))*Scale.X); - rcy = clip[1] == 0 ? 0 : ry+((clip[1] - texture->GetScaledTopOffsetDouble(0))*Scale.Y); - rcr = clip[2] == 0 ? INT_MAX : rx+w-((clip[2] + texture->GetScaledLeftOffsetDouble(0))*Scale.X); - rcb = clip[3] == 0 ? INT_MAX : ry+h-((clip[3] + texture->GetScaledTopOffsetDouble(0))*Scale.Y); + rcx = clip[0] == 0 ? 0 : rx+((clip[0] - texture->GetDisplayLeftOffsetDouble())*Scale.X); + rcy = clip[1] == 0 ? 0 : ry+((clip[1] - texture->GetDisplayTopOffsetDouble())*Scale.Y); + rcr = clip[2] == 0 ? INT_MAX : rx+w-((clip[2] + texture->GetDisplayLeftOffsetDouble())*Scale.X); + rcb = clip[3] == 0 ? INT_MAX : ry+h-((clip[3] + texture->GetDisplayTopOffsetDouble())*Scale.Y); } if(clearDontDraw) @@ -1380,7 +1379,8 @@ public: width = font->GetCharWidth((unsigned char) *str); else width = font->GetCharWidth((unsigned char) script->spacingCharacter); - FTexture* c = font->GetChar((unsigned char) *str, &width); + bool redirected = false; + FTexture* c = font->GetChar((unsigned char) *str, fontcolor, &width); if(c == NULL) //missing character. { str++; @@ -1389,13 +1389,13 @@ public: int character = (unsigned char)*str; if (script->spacingCharacter == '\0') //If we are monospaced lets use the offset - ax += (c->GetLeftOffset(0) + 1); //ignore x offsets since we adapt to character size + ax += (c->GetDisplayLeftOffset() + 1); //ignore x offsets since we adapt to character size double rx, ry, rw, rh; rx = ax + xOffset; ry = ay + yOffset; - rw = c->GetScaledWidthDouble(); - rh = c->GetScaledHeightDouble(); + rw = c->GetDisplayWidthDouble(); + rh = c->GetDisplayHeightDouble(); if(script->spacingCharacter != '\0') { @@ -1453,7 +1453,7 @@ public: DTA_Alpha, Alpha, TAG_DONE); if (script->spacingCharacter == '\0') - ax += width + spacing - (c->GetLeftOffset(0) + 1); + ax += width + spacing - (c->GetDisplayLeftOffsetDouble() + 1); else //width gets changed at the call to GetChar() ax += font->GetCharWidth((unsigned char) script->spacingCharacter) + spacing; str++; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index fa321660a..6094f82ea 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -69,8 +69,8 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { double scale1, scale2; scale1 = scale2 = 1.0f; - double texwidth = (int) (texture->GetScaledWidthDouble()*spawnScaleX); - double texheight = (int) (texture->GetScaledHeightDouble()*spawnScaleY); + double texwidth = (int) (texture->GetDisplayWidthDouble()*spawnScaleX); + double texheight = (int) (texture->GetDisplayHeightDouble()*spawnScaleY); if (w != -1 && (wGetScaledWidthDouble()*spawnScaleX); - h=(int) (texture->GetScaledHeightDouble()*spawnScaleY); + w=(int) (texture->GetDisplayWidthDouble()*spawnScaleX); + h=(int) (texture->GetDisplayHeightDouble()*spawnScaleY); } statusBar->DrawGraphic(texture, imgx, imgy, block->XOffset(), block->YOffset(), frameAlpha, block->FullScreenOffsets(), translatable, false, offset, false, w, h); @@ -241,7 +241,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl applyscale = false; } if(type == PLAYERICON) - texture = TexMan(statusBar->CPlayer->mo->ScoreIcon); + texture = TexMan.GetTexture(statusBar->CPlayer->mo->ScoreIcon, true); else if(type == AMMO1) { auto ammo = statusBar->ammo1; @@ -270,7 +270,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl { auto item = statusBar->CPlayer->mo->FindInventory(NAME_Sigil); if (item != NULL) - texture = TexMan(item->TextureIDVar(NAME_Icon)); + texture = TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true); } else if(type == HEXENARMOR_ARMOR || type == HEXENARMOR_SHIELD || type == HEXENARMOR_HELM || type == HEXENARMOR_AMULET) { @@ -292,15 +292,15 @@ class CommandDrawImage : public SBarInfoCommandFlowControl } } else if(type == INVENTORYICON) - texture = TexMan(sprite); + texture = TexMan.GetTexture(sprite, true); else if(type == SELECTEDINVENTORYICON && statusBar->CPlayer->mo->InvSel != NULL) - texture = TexMan(statusBar->CPlayer->mo->InvSel->TextureIDVar(NAME_Icon)); + texture = TexMan.GetTexture(statusBar->CPlayer->mo->InvSel->TextureIDVar(NAME_Icon), true); else if(image >= 0) texture = statusBar->Images[image]; if (flags & DI_ALTERNATEONFAIL) { - SetTruth(texture == NULL || texture->UseType == ETextureType::Null, block, statusBar); + SetTruth(texture == NULL || !texture->isValid(), block, statusBar); } } protected: @@ -316,7 +316,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl spawnScaleY = item->Scale.Y; } - texture = TexMan(icon); + texture = TexMan.GetTexture(icon, true); } enum ImageType @@ -2131,7 +2131,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgARTIBOX], rx, ry, block->XOffset(), block->YOffset(), bgalpha, block->FullScreenOffsets()); if(style != STYLE_Strife) //Strife draws the cursor before the icons - statusBar->DrawGraphic(TexMan(item->TextureIDVar(NAME_Icon)), rx - (style == STYLE_HexenStrict ? 2 : 0), ry - (style == STYLE_HexenStrict ? 1 : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); + statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), rx - (style == STYLE_HexenStrict ? 2 : 0), ry - (style == STYLE_HexenStrict ? 1 : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); if(item == statusBar->CPlayer->mo->InvSel) { if(style == STYLE_Heretic) @@ -2146,7 +2146,7 @@ class CommandDrawInventoryBar : public SBarInfoCommand statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); } if(style == STYLE_Strife) - statusBar->DrawGraphic(TexMan(item->TextureIDVar(NAME_Icon)), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); + statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->IntVar(NAME_Amount) <= 0); if(counters != NULL && (alwaysShowCounter || item->IntVar(NAME_Amount) != 1)) { counters[i]->valueArgument = item->IntVar(NAME_Amount); @@ -2266,11 +2266,11 @@ class CommandDrawInventoryBar : public SBarInfoCommand int spacing; if (!vertical) { - spacing = box->GetScaledWidth(); + spacing = box->GetDisplayWidth(); } else { - spacing = box->GetScaledHeight(); + spacing = box->GetDisplayHeight(); } return spacing + ((style != STYLE_Strife) ? 1 : -1); } @@ -2369,22 +2369,22 @@ class CommandDrawKeyBar : public SBarInfoCommand { if(!vertical) { - statusBar->DrawGraphic(TexMan(item->TextureIDVar(NAME_Icon)), x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan(item->TextureIDVar(NAME_Icon))->GetScaledHeight()+2 : rowIconSize; + statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayHeight()+2 : rowIconSize; } else { - statusBar->DrawGraphic(TexMan(item->TextureIDVar(NAME_Icon)), x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); - rowWidth = rowIconSize == -1 ? TexMan(item->TextureIDVar(NAME_Icon))->GetScaledWidth()+2 : rowIconSize; + statusBar->DrawGraphic(TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true), x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayWidth()+2 : rowIconSize; } // If cmd.special is -1 then the slot size is auto detected if(iconSize == -1) { if(!vertical) - slotOffset += (reverse ? -1 : 1) * (TexMan(item->TextureIDVar(NAME_Icon))->GetScaledWidth() + 2); + slotOffset += (reverse ? -1 : 1) * (TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayWidth() + 2); else - slotOffset += (reverse ? -1 : 1) * (TexMan(item->TextureIDVar(NAME_Icon))->GetScaledHeight() + 2); + slotOffset += (reverse ? -1 : 1) * (TexMan.GetTexture(item->TextureIDVar(NAME_Icon), true)->GetDisplayHeight() + 2); } else slotOffset += (reverse ? -iconSize : iconSize); @@ -2504,7 +2504,7 @@ class CommandDrawBar : public SBarInfoCommand else { // Draw background - if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + if (bg != NULL && bg->GetDisplayWidth() == fg->GetDisplayWidth() && bg->GetDisplayHeight() == fg->GetDisplayHeight()) statusBar->DrawGraphic(bg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); else statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, nulclip, true); @@ -2513,7 +2513,7 @@ class CommandDrawBar : public SBarInfoCommand // {cx, cy, cr, cb} double Clip[4] = {0, 0, 0, 0}; - int sizeOfImage = (horizontal ? fg->GetScaledWidth()-border*2 : fg->GetScaledHeight()-border*2); + int sizeOfImage = (horizontal ? fg->GetDisplayWidth()-border*2 : fg->GetDisplayHeight()-border*2); Clip[(!horizontal)|((horizontal ? !reverse : reverse)<<1)] = sizeOfImage - sizeOfImage *value; // Draw background if(border != 0) @@ -2521,7 +2521,7 @@ class CommandDrawBar : public SBarInfoCommand for(unsigned int i = 0;i < 4;i++) Clip[i] += border; - if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + if (bg != NULL && bg->GetDisplayWidth() == fg->GetDisplayWidth() && bg->GetDisplayHeight() == fg->GetDisplayHeight()) statusBar->DrawGraphic(bg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, Clip); else statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, Clip, true); @@ -2802,7 +2802,7 @@ class CommandDrawBar : public SBarInfoCommand // [BL] Since we used a percentage (in order to get the most fluid animation) // we need to establish a cut off point so the last pixel won't hang as the animation slows if(pixel == -1 && statusBar->Images[foreground]) - pixel = MAX(1 / 65536., 1./statusBar->Images[foreground]->GetWidth()); + pixel = MAX(1 / 65536., 1./statusBar->Images[foreground]->GetDisplayWidth()); if(fabs(drawValue - value) < pixel) drawValue = value; @@ -3115,7 +3115,7 @@ class CommandDrawGem : public SBarInfoCommand SBarInfoCoordinate drawY = y; if(wiggle && drawValue != goalValue) // Should only wiggle when the value doesn't equal what is being drawn. drawY += chainWiggle; - int chainWidth = chainImg->GetScaledWidth(); + int chainWidth = chainImg->GetDisplayWidth(); int offset = (int) (((double) (chainWidth-leftPadding-rightPadding)/100)*drawValue); statusBar->DrawGraphic(chainImg, x+(offset%chainSize), drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); if(gemImg != NULL) diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 766e18d6a..12b66bf88 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -203,7 +203,7 @@ void ST_LoadCrosshair(bool alwaysload) } } CrosshairNum = num; - CrosshairImage = TexMan[texid]; + CrosshairImage = TexMan.GetTexture(texid); } //--------------------------------------------------------------------------- @@ -817,11 +817,11 @@ void DBaseStatusBar::RefreshBackground () const if (setblocks >= 10) { - FTexture *p = TexMan[gameinfo.Border.b]; + FTexture *p = TexMan.GetTextureByName(gameinfo.Border.b); if (p != NULL) { - screen->FlatFill(0, y, x, y + p->GetHeight(), p, true); - screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetHeight(), p, true); + screen->FlatFill(0, y, x, y + p->GetDisplayHeight(), p, true); + screen->FlatFill(x2, y, SCREENWIDTH, y + p->GetDisplayHeight(), p, true); } } } @@ -864,8 +864,8 @@ void DBaseStatusBar::DrawCrosshair () { size *= CrosshairSize; } - w = int(CrosshairImage->GetWidth() * size); - h = int(CrosshairImage->GetHeight() * size); + w = int(CrosshairImage->GetDisplayWidth() * size); + h = int(CrosshairImage->GetDisplayHeight() * size); if (crosshairhealth) { @@ -1323,10 +1323,10 @@ void DBaseStatusBar::DrawGraphic(FTextureID texture, double x, double y, int fla if (!texture.isValid()) return; - FTexture *tex = (flags & DI_DONTANIMATE)? TexMan[texture] : TexMan(texture); + FTexture *tex = TexMan.GetTexture(texture, !(flags & DI_DONTANIMATE)); - double texwidth = tex->GetScaledWidthDouble() * scaleX; - double texheight = tex->GetScaledHeightDouble() * scaleY; + double texwidth = tex->GetDisplayWidthDouble() * scaleX; + double texheight = tex->GetDisplayHeightDouble() * scaleY; if (boxwidth > 0 || boxheight > 0) { @@ -1378,14 +1378,14 @@ void DBaseStatusBar::DrawGraphic(FTextureID texture, double x, double y, int fla { case DI_ITEM_HCENTER: x -= boxwidth / 2; break; case DI_ITEM_RIGHT: x -= boxwidth; break; - case DI_ITEM_HOFFSET: x -= tex->GetScaledLeftOffsetDouble(0) * boxwidth / texwidth; break; + case DI_ITEM_HOFFSET: x -= tex->GetDisplayLeftOffsetDouble() * boxwidth / texwidth; break; } switch (flags & DI_ITEM_VMASK) { case DI_ITEM_VCENTER: y -= boxheight / 2; break; case DI_ITEM_BOTTOM: y -= boxheight; break; - case DI_ITEM_VOFFSET: y -= tex->GetScaledTopOffsetDouble(0) * boxheight / texheight; break; + case DI_ITEM_VOFFSET: y -= tex->GetDisplayTopOffsetDouble() * boxheight / texheight; break; } if (!fullscreenOffsets) @@ -1513,20 +1513,20 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d } int width; - FTexture* c = font->GetChar((unsigned char)ch, &width); + FTexture* c = font->GetChar((unsigned char)ch, fontcolor, &width); if (c == NULL) //missing character. { continue; } if (!monospaced) //If we are monospaced lets use the offset - x += (c->GetLeftOffset(0) + 1); //ignore x offsets since we adapt to character size + x += (c->GetDisplayLeftOffsetDouble() + 1); //ignore x offsets since we adapt to character size double rx, ry, rw, rh; rx = x + drawOffset.X; ry = y + drawOffset.Y; - rw = c->GetScaledWidthDouble(); - rh = c->GetScaledHeightDouble(); + rw = c->GetDisplayWidthDouble(); + rh = c->GetDisplayHeightDouble(); if (!fullscreenOffsets) { @@ -1560,7 +1560,7 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d TAG_DONE); if (!monospaced) - x += width + spacing - (c->GetLeftOffset(0) + 1); + x += width + spacing - (c->GetDisplayLeftOffsetDouble() + 1); else x += spacing; } diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 2979420f9..3bd34fd15 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -60,6 +60,8 @@ EXTERN_CVAR (Color, am_fdwallcolor) EXTERN_CVAR (Color, am_cdwallcolor) EXTERN_CVAR (Float, spc_amp) EXTERN_CVAR (Bool, wi_percents) +EXTERN_CVAR (Int, gl_texture_hqresizemode) +EXTERN_CVAR (Int, gl_texture_hqresizemult) FGameConfigFile::FGameConfigFile () { @@ -395,6 +397,93 @@ void FGameConfigFile::DoGlobalSetup () FBaseCVar *var = FindCVar("snd_hrtf", NULL); if (var != NULL) var->ResetToDefault(); } + if (last < 216) + { + FBaseCVar *var = FindCVar("gl_texture_hqresize", NULL); + if (var != NULL) + { + auto v = var->GetGenericRep(CVAR_Int); + switch (v.Int) + { + case 1: + gl_texture_hqresizemode = 1; gl_texture_hqresizemult = 2; + break; + case 2: + gl_texture_hqresizemode = 1; gl_texture_hqresizemult = 3; + break; + case 3: + gl_texture_hqresizemode = 1; gl_texture_hqresizemult = 4; + break; + case 4: + gl_texture_hqresizemode = 2; gl_texture_hqresizemult = 2; + break; + case 5: + gl_texture_hqresizemode = 2; gl_texture_hqresizemult = 3; + break; + case 6: + gl_texture_hqresizemode = 2; gl_texture_hqresizemult = 4; + break; + case 7: + gl_texture_hqresizemode = 3; gl_texture_hqresizemult = 2; + break; + case 8: + gl_texture_hqresizemode = 3; gl_texture_hqresizemult = 3; + break; + case 9: + gl_texture_hqresizemode = 3; gl_texture_hqresizemult = 4; + break; + case 10: + gl_texture_hqresizemode = 4; gl_texture_hqresizemult = 2; + break; + case 11: + gl_texture_hqresizemode = 4; gl_texture_hqresizemult = 3; + break; + case 12: + gl_texture_hqresizemode = 4; gl_texture_hqresizemult = 4; + break; + case 18: + gl_texture_hqresizemode = 4; gl_texture_hqresizemult = 5; + break; + case 19: + gl_texture_hqresizemode = 4; gl_texture_hqresizemult = 6; + break; + case 13: + gl_texture_hqresizemode = 5; gl_texture_hqresizemult = 2; + break; + case 14: + gl_texture_hqresizemode = 5; gl_texture_hqresizemult = 3; + break; + case 15: + gl_texture_hqresizemode = 5; gl_texture_hqresizemult = 4; + break; + case 16: + gl_texture_hqresizemode = 5; gl_texture_hqresizemult = 5; + break; + case 17: + gl_texture_hqresizemode = 5; gl_texture_hqresizemult = 6; + break; + case 20: + gl_texture_hqresizemode = 6; gl_texture_hqresizemult = 2; + break; + case 21: + gl_texture_hqresizemode = 6; gl_texture_hqresizemult = 3; + break; + case 22: + gl_texture_hqresizemode = 6; gl_texture_hqresizemult = 4; + break; + case 23: + gl_texture_hqresizemode = 6; gl_texture_hqresizemult = 5; + break; + case 24: + gl_texture_hqresizemode = 6; gl_texture_hqresizemult = 6; + break; + case 0: + default: + gl_texture_hqresizemode = 0; gl_texture_hqresizemult = 1; + break; + } + } + } } } } diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index d5c78f116..67d083a31 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -966,11 +966,11 @@ void FGLRenderBuffers::RenderEffect(const FString &name) auto &shader = GLShaders[step.ShaderName]; // Set uniforms - if (step.Uniforms.Size > 0) + if (step.Uniforms.Data.Size() > 0) { if (!shader->Uniforms) shader->Uniforms.reset(screen->CreateDataBuffer(POSTPROCESS_BINDINGPOINT, false)); - shader->Uniforms->SetData(step.Uniforms.Size, step.Uniforms.Data); + shader->Uniforms->SetData(step.Uniforms.Data.Size(), step.Uniforms.Data.Data()); shader->Uniforms->BindBase(); } diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index af6a3acac..44422ad2d 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -117,7 +117,7 @@ FGLRenderer::~FGLRenderer() { FlushModels(); AActor::DeleteAllAttachedLights(); - FMaterial::FlushAll(); + TexMan.FlushAll(); if (mShaderManager != nullptr) delete mShaderManager; if (mSamplerManager != nullptr) delete mSamplerManager; if (mFBID != 0) glDeleteFramebuffers(1, &mFBID); @@ -254,7 +254,10 @@ sector_t *FGLRenderer::RenderView(player_t* player) bool saved_niv = NoInterpolateView; NoInterpolateView = false; // prepare all camera textures that have been used in the last frame - FCanvasTextureInfo::UpdateAll(); + level.canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) + { + RenderTextureView(camtex, camera, fov); + }); NoInterpolateView = saved_niv; @@ -285,7 +288,7 @@ sector_t *FGLRenderer::RenderView(player_t* player) void FGLRenderer::BindToFrameBuffer(FMaterial *mat) { - auto BaseLayer = static_cast(mat->GetLayer(0)); + auto BaseLayer = static_cast(mat->GetLayer(0, 0)); if (BaseLayer == nullptr) { @@ -324,7 +327,8 @@ void FGLRenderer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, doub EndOffscreen(); - tex->SetUpdated(); + tex->SetUpdated(true); + static_cast(screen)->camtexcount++; } //=========================================================================== diff --git a/src/gl/renderer/gl_renderstate.cpp b/src/gl/renderer/gl_renderstate.cpp index 883231bc4..0cc80d073 100644 --- a/src/gl/renderer/gl_renderstate.cpp +++ b/src/gl/renderer/gl_renderstate.cpp @@ -303,7 +303,7 @@ void FGLRenderState::Apply() void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translation, int overrideshader) { - if (mat->tex->bHasCanvas) + if (mat->tex->isHardwareCanvas()) { mTempTM = TM_OPAQUE; } @@ -317,8 +317,8 @@ void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translatio auto tex = mat->tex; if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; - if (tex->bHasCanvas) clampmode = CLAMP_CAMTEX; - else if ((tex->bWarped || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; + if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; + else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; // avoid rebinding the same texture multiple times. if (mat == lastMaterial && lastClamp == clampmode && translation == lastTranslation) return; @@ -330,16 +330,16 @@ void FGLRenderState::ApplyMaterial(FMaterial *mat, int clampmode, int translatio int maxbound = 0; // Textures that are already scaled in the texture lump will not get replaced by hires textures. - int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && tex->Scale.X == 1 && tex->Scale.Y == 1 && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0; + int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled() && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0; int numLayers = mat->GetLayers(); - auto base = static_cast(mat->GetLayer(0)); + auto base = static_cast(mat->GetLayer(0, translation)); if (base->BindOrCreate(tex, 0, clampmode, translation, flags)) { for (int i = 1; i(mat->GetLayer(i, &layer)); + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); systex->BindOrCreate(layer, i, clampmode, 0, mat->isExpanded() ? CTF_Expand : 0); maxbound = i; } @@ -595,4 +595,4 @@ bool FGLRenderState::SetDepthClamp(bool on) return res; } -} \ No newline at end of file +} diff --git a/src/gl/shaders/gl_postprocessshader.cpp b/src/gl/shaders/gl_postprocessshader.cpp index 9c33cfdc1..0e87275e0 100644 --- a/src/gl/shaders/gl_postprocessshader.cpp +++ b/src/gl/shaders/gl_postprocessshader.cpp @@ -216,8 +216,8 @@ void PostProcessShaderInstance::BindTextures() continue; FString name = pair->Value; - FTexture *tex = TexMan(TexMan.CheckForTexture(name, ETextureType::Any)); - if (tex && tex->UseType != ETextureType::Null) + FTexture *tex = TexMan.GetTexture(TexMan.CheckForTexture(name, ETextureType::Any), true); + if (tex && tex->isValid()) { glUniform1i(location, textureUnit); @@ -225,14 +225,14 @@ void PostProcessShaderInstance::BindTextures() auto it = mTextureHandles.find(tex); if (it == mTextureHandles.end()) { - FBitmap bitmap; - bitmap.Create(tex->GetWidth(), tex->GetHeight()); - tex->CopyTrueColorPixels(&bitmap, 0, 0); + // Why does this completely circumvent the normal way of handling textures? + // This absolutely needs fixing because it will also circumvent any potential caching system that may get implemented. + auto buffer = tex->CreateTexBuffer(0); GLuint handle = 0; glGenTextures(1, &handle); glBindTexture(GL_TEXTURE_2D, handle); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex->GetWidth(), tex->GetHeight(), 0, GL_BGRA, GL_UNSIGNED_BYTE, bitmap.GetPixels()); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, buffer.mWidth, buffer.mHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer.mBuffer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); mTextureHandles[tex] = handle; @@ -247,4 +247,4 @@ void PostProcessShaderInstance::BindTextures() } } -} \ No newline at end of file +} diff --git a/src/gl/system/gl_framebuffer.cpp b/src/gl/system/gl_framebuffer.cpp index d3d242cd4..08a9cc030 100644 --- a/src/gl/system/gl_framebuffer.cpp +++ b/src/gl/system/gl_framebuffer.cpp @@ -186,25 +186,6 @@ void OpenGLFrameBuffer::Update() Super::Update(); } -//=========================================================================== -// -// -// -//=========================================================================== - -void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - if (!V_IsHardwareRenderer()) - { - Super::RenderTextureView(tex, Viewpoint, FOV); - } - else if (GLRenderer != nullptr) - { - GLRenderer->RenderTextureView(tex, Viewpoint, FOV); - camtexcount++; - } -} - //=========================================================================== // // Render the view to a savegame picture @@ -345,27 +326,27 @@ void OpenGLFrameBuffer::SetTextureFilterMode() if (GLRenderer != nullptr && GLRenderer->mSamplerManager != nullptr) GLRenderer->mSamplerManager->SetTextureFilterMode(); } -IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture(FTexture *tex) +IHardwareTexture *OpenGLFrameBuffer::CreateHardwareTexture() { - return new FHardwareTexture(tex->bNoCompress); + return new FHardwareTexture(true/*tex->bNoCompress*/); } void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) { auto tex = mat->tex; - if (tex->UseType == ETextureType::SWCanvas) return; + if (tex->isSWCanvas()) return; // Textures that are already scaled in the texture lump will not get replaced by hires textures. - int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && tex->Scale.X == 1 && tex->Scale.Y == 1) ? CTF_CheckHires : 0; + int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled()) ? CTF_CheckHires : 0; int numLayers = mat->GetLayers(); - auto base = static_cast(mat->GetLayer(0)); + auto base = static_cast(mat->GetLayer(0, translation)); if (base->BindOrCreate(tex, 0, CLAMP_NONE, translation, flags)) { for (int i = 1; i < numLayers; i++) { FTexture *layer; - auto systex = static_cast(mat->GetLayer(i, &layer)); + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); systex->BindOrCreate(layer, i, CLAMP_NONE, 0, mat->isExpanded() ? CTF_Expand : 0); } } @@ -373,7 +354,7 @@ void OpenGLFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) FHardwareTexture::UnbindAll(); } -FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) +FModelRenderer *OpenGLFrameBuffer::CreateModelRenderer(int mli) { return new FGLModelRenderer(nullptr, gl_RenderState, mli); } @@ -527,9 +508,9 @@ FTexture *OpenGLFrameBuffer::WipeStartScreen() const auto &viewport = screen->mScreenViewport; auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->SystemTexture[0]->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); + tex->GetSystemTexture()->CreateTexture(nullptr, viewport.width, viewport.height, 0, false, 0, "WipeStartScreen"); glFinish(); - static_cast(tex->SystemTexture[0])->Bind(0, false, false); + static_cast(tex->GetSystemTexture())->Bind(0, false); GLRenderer->mBuffers->BindCurrentFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); @@ -549,12 +530,12 @@ FTexture *OpenGLFrameBuffer::WipeEndScreen() GLRenderer->Flush(); const auto &viewport = screen->mScreenViewport; auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); - tex->SystemTexture[0]->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); + tex->GetSystemTexture()->CreateTexture(NULL, viewport.width, viewport.height, 0, false, 0, "WipeEndScreen"); glFinish(); - static_cast(tex->SystemTexture[0])->Bind(0, false, false); + static_cast(tex->GetSystemTexture())->Bind(0, false); GLRenderer->mBuffers->BindCurrentFB(); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, viewport.left, viewport.top, viewport.width, viewport.height); return tex; } -} \ No newline at end of file +} diff --git a/src/gl/system/gl_framebuffer.h b/src/gl/system/gl_framebuffer.h index c2a26650f..c77b3af67 100644 --- a/src/gl/system/gl_framebuffer.h +++ b/src/gl/system/gl_framebuffer.h @@ -30,11 +30,10 @@ public: void CleanForRestart() override; void UpdatePalette() override; uint32_t GetCaps() override; - void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) override; void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; sector_t *RenderView(player_t *player) override; void SetTextureFilterMode() override; - IHardwareTexture *CreateHardwareTexture(FTexture *tex) override; + IHardwareTexture *CreateHardwareTexture() override; void PrecacheMaterial(FMaterial *mat, int translation) override; FModelRenderer *CreateModelRenderer(int mli) override; void TextureFilterChanged() override; @@ -64,7 +63,7 @@ public: FTexture *WipeStartScreen() override; FTexture *WipeEndScreen() override; -private: + int camtexcount = 0; }; diff --git a/src/gl/textures/gl_hwtexture.cpp b/src/gl/textures/gl_hwtexture.cpp index 568c05be1..9c5f7b894 100644 --- a/src/gl/textures/gl_hwtexture.cpp +++ b/src/gl/textures/gl_hwtexture.cpp @@ -96,13 +96,16 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int texformat = GL_RGBA8; } */ - TranslatedTexture * glTex=GetTexID(translation); - bool firstCall = glTex->glTexID == 0; - if (firstCall) glGenTextures(1,&glTex->glTexID); - if (texunit != 0) glActiveTexture(GL_TEXTURE0+texunit); - glBindTexture(GL_TEXTURE_2D, glTex->glTexID); - FGLDebug::LabelObject(GL_TEXTURE, glTex->glTexID, name); - lastbound[texunit] = glTex->glTexID; + bool firstCall = glTexID == 0; + if (firstCall) glGenTextures(1,&glTexID); + + int textureBinding = UINT_MAX; + if (texunit == -1) glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); + if (texunit > 0) glActiveTexture(GL_TEXTURE0+texunit); + if (texunit >= 0) lastbound[texunit] = glTexID; + glBindTexture(GL_TEXTURE_2D, glTexID); + + FGLDebug::LabelObject(GL_TEXTURE, glTexID, name); rw = GetTexDimension(w); rh = GetTexDimension(h); @@ -114,7 +117,7 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int else if (!buffer) { // The texture must at least be initialized if no data is present. - glTex->mipmapped = false; + mipmapped = false; buffer=(unsigned char *)calloc(4,rw * (rh+1)); deletebuffer=true; //texheight=-h; @@ -165,11 +168,12 @@ unsigned int FHardwareTexture::CreateTexture(unsigned char * buffer, int w, int if (mipmap && TexFilter[gl_texture_filter].mipmapping) { glGenerateMipmap(GL_TEXTURE_2D); - glTex->mipmapped = true; + mipmapped = true; } - if (texunit != 0) glActiveTexture(GL_TEXTURE0); - return glTex->glTexID; + if (texunit > 0) glActiveTexture(GL_TEXTURE0); + else if (texunit == -1) glBindTexture(GL_TEXTURE_2D, textureBinding); + return glTexID; } @@ -200,89 +204,6 @@ uint8_t *FHardwareTexture::MapBuffer() return (uint8_t*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); } -//=========================================================================== -// -// Creates a texture -// -//=========================================================================== -FHardwareTexture::FHardwareTexture(bool nocompression) -{ - forcenocompression = nocompression; - - glDefTex.glTexID = 0; - glDefTex.translation = 0; - glDefTex.mipmapped = false; - glDepthID = 0; -} - - -//=========================================================================== -// -// Deletes a texture id and unbinds it from the texture units -// -//=========================================================================== -void FHardwareTexture::TranslatedTexture::Delete() -{ - if (glTexID != 0) - { - for(int i = 0; i < MAX_TEXTURES; i++) - { - if (lastbound[i] == glTexID) - { - lastbound[i] = 0; - } - } - glDeleteTextures(1, &glTexID); - glTexID = 0; - mipmapped = false; - } -} - -//=========================================================================== -// -// Frees all associated resources -// -//=========================================================================== -void FHardwareTexture::Clean(bool all) -{ - int cm_arraysize = CM_FIRSTSPECIALCOLORMAP + SpecialColormaps.Size(); - - if (all) - { - glDefTex.Delete(); - } - for(unsigned int i=0;i= 0; i--) - { - if (usedtranslations.CheckKey(glTex_Translated[i].translation) == nullptr) - { - glTex_Translated[i].Delete(); - glTex_Translated.Delete(i); - } - } -} - //=========================================================================== // // Destroys the texture @@ -290,72 +211,38 @@ void FHardwareTexture::CleanUnused(SpriteHits &usedtranslations) //=========================================================================== FHardwareTexture::~FHardwareTexture() { - Clean(true); glDeleteBuffers(1, &glBufferID); } -//=========================================================================== -// -// Gets a texture ID address and validates all required data -// -//=========================================================================== - -FHardwareTexture::TranslatedTexture *FHardwareTexture::GetTexID(int translation) -{ - if (translation == 0) - { - return &glDefTex; - } - - // normally there aren't more than very few different - // translations here so this isn't performance critical. - for (unsigned int i = 0; i < glTex_Translated.Size(); i++) - { - if (glTex_Translated[i].translation == translation) - { - return &glTex_Translated[i]; - } - } - - int add = glTex_Translated.Reserve(1); - glTex_Translated[add].translation = translation; - glTex_Translated[add].glTexID = 0; - glTex_Translated[add].mipmapped = false; - return &glTex_Translated[add]; -} - //=========================================================================== // // Binds this patch // //=========================================================================== -unsigned int FHardwareTexture::Bind(int texunit, int translation, bool needmipmap) +unsigned int FHardwareTexture::Bind(int texunit, bool needmipmap) { - TranslatedTexture *pTex = GetTexID(translation); - - if (pTex->glTexID != 0) + if (glTexID != 0) { - if (lastbound[texunit] == pTex->glTexID) return pTex->glTexID; - lastbound[texunit] = pTex->glTexID; + if (lastbound[texunit] == glTexID) return glTexID; + lastbound[texunit] = glTexID; if (texunit != 0) glActiveTexture(GL_TEXTURE0 + texunit); - glBindTexture(GL_TEXTURE_2D, pTex->glTexID); + glBindTexture(GL_TEXTURE_2D, glTexID); // Check if we need mipmaps on a texture that was creted without them. - if (needmipmap && !pTex->mipmapped && TexFilter[gl_texture_filter].mipmapping) + if (needmipmap && !mipmapped && TexFilter[gl_texture_filter].mipmapping) { glGenerateMipmap(GL_TEXTURE_2D); - pTex->mipmapped = true; + mipmapped = true; } if (texunit != 0) glActiveTexture(GL_TEXTURE0); - return pTex->glTexID; + return glTexID; } return 0; } unsigned int FHardwareTexture::GetTextureHandle(int translation) { - TranslatedTexture *pTex = GetTexID(translation); - return pTex->glTexID; + return glTexID; } void FHardwareTexture::Unbind(int texunit) @@ -408,7 +295,7 @@ void FHardwareTexture::BindToFrameBuffer(int width, int height) { width = GetTexDimension(width); height = GetTexDimension(height); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glDefTex.glTexID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glTexID, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height)); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, GetDepthBuffer(width, height)); } @@ -437,34 +324,35 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i bool needmipmap = (clampmode <= CLAMP_XY); // Bind it to the system. - if (!Bind(texunit, translation, needmipmap)) + if (!Bind(texunit, needmipmap)) { int w = 0, h = 0; // Create this texture - unsigned char * buffer = nullptr; + + FTextureBuffer texbuffer; - if (!tex->bHasCanvas) + if (!tex->isHardwareCanvas()) { - buffer = tex->CreateTexBuffer(translation, w, h, flags | CTF_ProcessData); + texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); + w = texbuffer.mWidth; + h = texbuffer.mHeight; } else { w = tex->GetWidth(); h = tex->GetHeight(); } - if (!CreateTexture(buffer, w, h, texunit, needmipmap, translation, "FHardwareTexture.BindOrCreate")) + if (!CreateTexture(texbuffer.mBuffer, w, h, texunit, needmipmap, translation, "FHardwareTexture.BindOrCreate")) { // could not create texture - delete[] buffer; return false; } - delete[] buffer; } - if (tex->bHasCanvas) static_cast(tex)->NeedUpdate(); + if (tex->isHardwareCanvas()) static_cast(tex)->NeedUpdate(); GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255); return true; } -} \ No newline at end of file +} diff --git a/src/gl/textures/gl_hwtexture.h b/src/gl/textures/gl_hwtexture.h index 6c693a998..db01f3637 100644 --- a/src/gl/textures/gl_hwtexture.h +++ b/src/gl/textures/gl_hwtexture.h @@ -19,31 +19,8 @@ class AActor; namespace OpenGLRenderer { - -// For error catching while changing parameters. -enum EInvalid -{ - Invalid = 0 -}; - class FHardwareTexture : public IHardwareTexture { -public: - enum - { - MAX_TEXTURES = 16 - }; - -private: - struct TranslatedTexture - { - unsigned int glTexID; - int translation; - bool mipmapped; - - void Delete(); - }; - public: static unsigned int lastbound[MAX_TEXTURES]; @@ -60,18 +37,20 @@ private: bool forcenocompression; - TranslatedTexture glDefTex; - TArray glTex_Translated; - unsigned int glDepthID; // only used by camera textures + unsigned int glTexID = 0; + unsigned int glDepthID = 0; // only used by camera textures unsigned int glBufferID = 0; int glTextureBytes = 4; - - TranslatedTexture * GetTexID(int translation); + bool mipmapped = false; int GetDepthBuffer(int w, int h); public: - FHardwareTexture(bool nocompress); + FHardwareTexture(bool nocompress) + { + forcenocompression = nocompress; + } + ~FHardwareTexture(); static void Unbind(int texunit); @@ -79,18 +58,14 @@ public: void BindToFrameBuffer(int w, int h); - unsigned int Bind(int texunit, int translation, bool needmipmap); + unsigned int Bind(int texunit, bool needmipmap); bool BindOrCreate(FTexture *tex, int texunit, int clampmode, int translation, int flags); void AllocateBuffer(int w, int h, int texelsize); uint8_t *MapBuffer(); - unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const FString &name) = delete; unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name); unsigned int GetTextureHandle(int translation); - - void Clean(bool all); - void CleanUnused(SpriteHits &usedtranslations); }; } diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index fd4c4123b..c9ed444af 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -209,15 +209,15 @@ void HU_GetPlayerWidths(int &maxnamewidth, int &maxscorewidth, int &maxiconheigh } if (players[i].mo->ScoreIcon.isValid()) { - FTexture *pic = TexMan[players[i].mo->ScoreIcon]; - width = pic->GetScaledWidth() - pic->GetScaledLeftOffset(0) + 2; + FTexture *pic = TexMan.GetTexture(players[i].mo->ScoreIcon); + width = pic->GetDisplayWidth() - pic->GetDisplayLeftOffset() + 2; if (width > maxscorewidth) { maxscorewidth = width; } // The icon's top offset does not count toward its height, because // zdoom.pk3's standard Hexen class icons are designed that way. - int height = pic->GetScaledHeight() - pic->GetScaledTopOffset(0); + int height = pic->GetDisplayHeight() - pic->GetDisplayTopOffset(); if (height > maxiconheight) { maxiconheight = height; @@ -422,7 +422,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, if (player->mo->ScoreIcon.isValid()) { - FTexture *pic = TexMan[player->mo->ScoreIcon]; + FTexture *pic = TexMan.GetTexture(player->mo->ScoreIcon); screen->DrawTexture (pic, col3, y, DTA_CleanNoMove, true, TAG_DONE); @@ -445,8 +445,8 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, if (teamplay && Teams[player->userinfo.GetTeam()].GetLogo().IsNotEmpty ()) { - FTexture *pic = TexMan[Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()]; - screen->DrawTexture (pic, col1 - (pic->GetScaledWidth() + 2) * CleanXfac, y, + FTexture *pic = TexMan.GetTextureByName(Teams[player->userinfo.GetTeam()].GetLogo().GetChars ()); + screen->DrawTexture (pic, col1 - (pic->GetDisplayWidth() + 2) * CleanXfac, y, DTA_CleanNoMove, true, TAG_DONE); } } diff --git a/src/hwrenderer/dynlights/hw_lightbuffer.cpp b/src/hwrenderer/dynlights/hw_lightbuffer.cpp index a9e24353c..bb7c78e9b 100644 --- a/src/hwrenderer/dynlights/hw_lightbuffer.cpp +++ b/src/hwrenderer/dynlights/hw_lightbuffer.cpp @@ -64,7 +64,6 @@ FLightBuffer::FLightBuffer() mBuffer->SetData(mByteSize, nullptr, false); Clear(); - mLastMappedIndex = UINT_MAX; } FLightBuffer::~FLightBuffer() @@ -75,6 +74,7 @@ FLightBuffer::~FLightBuffer() void FLightBuffer::Clear() { mIndex = 0; + mLastMappedIndex = UINT_MAX; } int FLightBuffer::UploadLights(FDynLightData &data) diff --git a/src/hwrenderer/postprocessing/hw_postprocess.h b/src/hwrenderer/postprocessing/hw_postprocess.h index c94a89b81..0b11ec124 100644 --- a/src/hwrenderer/postprocessing/hw_postprocess.h +++ b/src/hwrenderer/postprocessing/hw_postprocess.h @@ -38,12 +38,7 @@ public: PPUniforms(const PPUniforms &src) { - if (src.Size > 0) - { - Data = new uint8_t[src.Size]; - Size = src.Size; - memcpy(Data, src.Data, Size); - } + Data = src.Data; } ~PPUniforms() @@ -53,49 +48,26 @@ public: PPUniforms &operator=(const PPUniforms &src) { - if (this != &src) - { - if (src.Size > 0) - { - Data = new uint8_t[src.Size]; - Size = src.Size; - memcpy(Data, src.Data, Size); - } - else - { - delete[] Data; - Data = nullptr; - Size = 0; - } - } - + Data = src.Data; return *this; } void Clear() { - delete[] Data; - Data = nullptr; - Size = 0; + Data.Clear(); } template void Set(const T &v) { - if (Size != (int)sizeof(T)) + if (Data.Size() != (int)sizeof(T)) { - delete[] Data; - Data = nullptr; - Size = 0; - - Data = new uint8_t[sizeof(T)]; - Size = sizeof(T); - memcpy(Data, &v, Size); + Data.Resize(sizeof(T)); + memcpy(Data.Data(), &v, Data.Size()); } } - uint8_t *Data = nullptr; - int Size = 0; + TArray Data; }; class PPStep diff --git a/src/hwrenderer/scene/hw_bsp.cpp b/src/hwrenderer/scene/hw_bsp.cpp index 39d4145f3..6dab92cc8 100644 --- a/src/hwrenderer/scene/hw_bsp.cpp +++ b/src/hwrenderer/scene/hw_bsp.cpp @@ -56,6 +56,7 @@ struct RenderJob WallJob, SpriteJob, ParticleJob, + PortalJob, TerminateJob // inserted when all work is done so that the worker can return. }; @@ -177,7 +178,12 @@ void HWDrawInfo::WorkerThread() RenderParticles(job->sub, front); SetupSprite.Unclock(); break; + + case RenderJob::PortalJob: + AddSubsectorToPortal((FSectorPortalGroup *)job->seg, job->sub); + break; } + } } @@ -277,8 +283,8 @@ void HWDrawInfo::AddLine (seg_t *seg, bool portalclip) { if (!seg->linedef->isVisualPortal()) { - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); - if (!tex || tex->UseType==ETextureType::Null) + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); + if (!tex || !tex->isValid()) { // nothing to do here! seg->linedef->validcount=validcount; @@ -646,7 +652,7 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) sector->validcount = validcount; sector->MoreFlags |= SECMF_DRAWN; - if (gl_render_things && sector->touching_renderthings) + if (gl_render_things && (sector->touching_renderthings || sector->sectorportal_thinglist)) { if (multithread) { @@ -706,16 +712,35 @@ void HWDrawInfo::DoSubsector(subsector_t * sub) // This is for portal coverage. FSectorPortalGroup *portal; + // AddSubsectorToPortal cannot be called here when using multithreaded processing, + // because the wall processing code in the worker can also modify the portal state. + // To avoid costly synchronization for every access to the portal list, + // the call to AddSubsectorToPortal will be deferred to the worker. + // (GetPortalGruop only accesses static sector data so this check can be done here, restricting the new job to the minimum possible extent.) portal = fakesector->GetPortalGroup(sector_t::ceiling); if (portal != nullptr) { - AddSubsectorToPortal(portal, sub); + if (multithread) + { + jobQueue.AddJob(RenderJob::PortalJob, sub, (seg_t *)portal); + } + else + { + AddSubsectorToPortal(portal, sub); + } } portal = fakesector->GetPortalGroup(sector_t::floor); if (portal != nullptr) { - AddSubsectorToPortal(portal, sub); + if (multithread) + { + jobQueue.AddJob(RenderJob::PortalJob, sub, (seg_t *)portal); + } + else + { + AddSubsectorToPortal(portal, sub); + } } } } diff --git a/src/hwrenderer/scene/hw_decal.cpp b/src/hwrenderer/scene/hw_decal.cpp index 815032314..9bce744c4 100644 --- a/src/hwrenderer/scene/hw_decal.cpp +++ b/src/hwrenderer/scene/hw_decal.cpp @@ -208,7 +208,7 @@ void GLWall::ProcessDecal(HWDrawInfo *di, DBaseDecal *decal, const FVector3 &nor flipy = !!(decal->RenderFlags & RF_YFLIP); - FTexture *texture = TexMan[decalTile]; + FTexture *texture = TexMan.GetTexture(decalTile); if (texture == NULL) return; diff --git a/src/hwrenderer/scene/hw_drawinfo.cpp b/src/hwrenderer/scene/hw_drawinfo.cpp index 35b1836e0..06e962fff 100644 --- a/src/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/hwrenderer/scene/hw_drawinfo.cpp @@ -388,7 +388,7 @@ void HWViewpointUniforms::SetDefaults() mNormalViewMatrix.loadIdentity(); mViewHeight = viewheight; mGlobVis = (float)R_GetGlobVis(r_viewwindow, r_visibility) / 32.f; - mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8); + mPalLightLevels = static_cast(gl_bandedswlight) | (static_cast(gl_fogmode) << 8) | (static_cast(gl_lightmode) << 16); mClipLine.X = -10000000.0f; mShadowmapFilter = gl_shadowmap_filter; diff --git a/src/hwrenderer/scene/hw_drawlist.cpp b/src/hwrenderer/scene/hw_drawlist.cpp index 067c5dee5..0cf6a8010 100644 --- a/src/hwrenderer/scene/hw_drawlist.cpp +++ b/src/hwrenderer/scene/hw_drawlist.cpp @@ -483,7 +483,7 @@ inline double CalcIntersectionVertex(GLSprite *s, GLWall * w2) return ((ay - cy)*(dx - cx) - (ax - cx)*(dy - cy)) / ((bx - ax)*(dy - cy) - (by - ay)*(dx - cx)); } -void HWDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort) +void HWDrawList::SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort) { GLWall *wh= walls[drawitems[head->itemindex].index]; GLSprite * ss= sprites[drawitems[sort->itemindex].index]; @@ -560,6 +560,16 @@ void HWDrawList::SortSpriteIntoWall(SortNode * head,SortNode * sort) head->AddToLeft(sort); head->AddToRight(sort2); } + if (screen->BuffersArePersistent()) + { + s->vertexindex = ss->vertexindex = -1; + } + else + { + s->CreateVertices(di); + ss->CreateVertices(di); + } + } } @@ -667,7 +677,7 @@ SortNode * HWDrawList::DoSort(HWDrawInfo *di, SortNode * head) break; case GLDIT_SPRITE: - SortSpriteIntoWall(head,node); + SortSpriteIntoWall(di, head, node); break; case GLDIT_FLAT: break; diff --git a/src/hwrenderer/scene/hw_drawlist.h b/src/hwrenderer/scene/hw_drawlist.h index 303da06fb..66ae468ed 100644 --- a/src/hwrenderer/scene/hw_drawlist.h +++ b/src/hwrenderer/scene/hw_drawlist.h @@ -101,7 +101,7 @@ public: void SortWallIntoPlane(SortNode * head,SortNode * sort); void SortSpriteIntoPlane(SortNode * head,SortNode * sort); void SortWallIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); - void SortSpriteIntoWall(SortNode * head,SortNode * sort); + void SortSpriteIntoWall(HWDrawInfo *di, SortNode * head,SortNode * sort); int CompareSprites(SortNode * a,SortNode * b); SortNode * SortSpriteList(SortNode * head); SortNode * DoSort(HWDrawInfo *di, SortNode * head); diff --git a/src/hwrenderer/scene/hw_fakeflat.cpp b/src/hwrenderer/scene/hw_fakeflat.cpp index 38cfaeefc..510e7d48a 100644 --- a/src/hwrenderer/scene/hw_fakeflat.cpp +++ b/src/hwrenderer/scene/hw_fakeflat.cpp @@ -117,8 +117,8 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto // now check for closed sectors! if (bs_ceilingheight1 <= fs_floorheight1 && bs_ceilingheight2 <= fs_floorheight2) { - FTexture * tex = TexMan(sidedef->GetTexture(side_t::top)); - if (!tex || tex->UseType == ETextureType::Null) return false; + FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::top), true); + if (!tex || !tex->isValid()) return false; if (backsector->GetTexture(sector_t::ceiling) == skyflatnum && frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false; return true; @@ -126,8 +126,8 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto if (fs_ceilingheight1 <= bs_floorheight1 && fs_ceilingheight2 <= bs_floorheight2) { - FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom)); - if (!tex || tex->UseType == ETextureType::Null) return false; + FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::bottom), true); + if (!tex || !tex->isValid()) return false; // properly render skies (consider door "open" if both floors are sky): if (backsector->GetTexture(sector_t::ceiling) == skyflatnum && @@ -140,13 +140,13 @@ bool hw_CheckClip(side_t * sidedef, sector_t * frontsector, sector_t * backsecto // preserve a kind of transparent door/lift special effect: if (bs_ceilingheight1 < fs_ceilingheight1 || bs_ceilingheight2 < fs_ceilingheight2) { - FTexture * tex = TexMan(sidedef->GetTexture(side_t::top)); - if (!tex || tex->UseType == ETextureType::Null) return false; + FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::top), true); + if (!tex || !tex->isValid()) return false; } if (bs_floorheight1 > fs_floorheight1 || bs_floorheight2 > fs_floorheight2) { - FTexture * tex = TexMan(sidedef->GetTexture(side_t::bottom)); - if (!tex || tex->UseType == ETextureType::Null) return false; + FTexture * tex = TexMan.GetTexture(sidedef->GetTexture(side_t::bottom), true); + if (!tex || !tex->isValid()) return false; } if (backsector->GetTexture(sector_t::ceiling) == skyflatnum && frontsector->GetTexture(sector_t::ceiling) == skyflatnum) return false; diff --git a/src/hwrenderer/scene/hw_flats.cpp b/src/hwrenderer/scene/hw_flats.cpp index 4e53635b7..b63987fd0 100644 --- a/src/hwrenderer/scene/hw_flats.cpp +++ b/src/hwrenderer/scene/hw_flats.cpp @@ -70,7 +70,7 @@ bool hw_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * glte float xscale1 = secplane->Scale.X; float yscale1 = secplane->Scale.Y; - if (gltexture->tex->bHasCanvas) + if (gltexture->hasCanvas()) { yscale1 = 0 - yscale1; } diff --git a/src/hwrenderer/scene/hw_renderhacks.cpp b/src/hwrenderer/scene/hw_renderhacks.cpp index 6814fd5f5..59d71231d 100644 --- a/src/hwrenderer/scene/hw_renderhacks.cpp +++ b/src/hwrenderer/scene/hw_renderhacks.cpp @@ -350,8 +350,8 @@ bool HWDrawInfo::DoOneSectorUpper(subsector_t * subsec, float Planez, area_t in_ if (sec->GetPlaneTexZ(sector_t::ceiling) == Planez) { // If there's a texture abort - FTexture * tex = TexMan[seg->sidedef->GetTexture(side_t::top)]; - if (!tex || tex->UseType == ETextureType::Null) continue; + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top)); + if (!tex || !tex->isValid()) continue; else return false; } } @@ -408,8 +408,8 @@ bool HWDrawInfo::DoOneSectorLower(subsector_t * subsec, float Planez, area_t in_ if (sec->GetPlaneTexZ(sector_t::floor) == Planez) { // If there's a texture abort - FTexture * tex = TexMan[seg->sidedef->GetTexture(side_t::bottom)]; - if (!tex || tex->UseType == ETextureType::Null) continue; + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom)); + if (!tex || !tex->isValid()) continue; else return false; } } diff --git a/src/hwrenderer/scene/hw_renderstate.cpp b/src/hwrenderer/scene/hw_renderstate.cpp index 5aa8d9c3c..721b87fd5 100644 --- a/src/hwrenderer/scene/hw_renderstate.cpp +++ b/src/hwrenderer/scene/hw_renderstate.cpp @@ -127,7 +127,7 @@ void FRenderState::SetFog(int lightlevel, int rellight, bool fullbright, const F } else { - if ((level.lightmode == 2 || (level.lightmode == 8 && cmap->BlendFactor > 0)) && fogcolor == 0) + if ((level.lightmode == ELightMode::Doom || (level.isSoftwareLighting() && cmap->BlendFactor > 0)) && fogcolor == 0) { float light = (float)hw_CalcLightLevel(lightlevel, rellight, false, cmap->BlendFactor); SetShaderLight(light, lightlevel); @@ -148,7 +148,7 @@ void FRenderState::SetFog(int lightlevel, int rellight, bool fullbright, const F SetFog(fogcolor, fogdensity); // Korshun: fullbright fog like in software renderer. - if (level.lightmode == 8 && cmap->BlendFactor == 0 && level.brightfog && fogdensity != 0 && fogcolor != 0) + if (level.isSoftwareLighting() && cmap->BlendFactor == 0 && level.brightfog && fogdensity != 0 && fogcolor != 0) { SetSoftLightLevel(255); } diff --git a/src/hwrenderer/scene/hw_renderstate.h b/src/hwrenderer/scene/hw_renderstate.h index f494df34a..d820c07ec 100644 --- a/src/hwrenderer/scene/hw_renderstate.h +++ b/src/hwrenderer/scene/hw_renderstate.h @@ -326,7 +326,7 @@ public: void SetSoftLightLevel(int llevel, int blendfactor = 0) { - if (level.lightmode == 8 && blendfactor == 0) mLightParms[3] = llevel / 255.f; + if (level.isSoftwareLighting() && blendfactor == 0) mLightParms[3] = llevel / 255.f; else mLightParms[3] = -1.f; } diff --git a/src/hwrenderer/scene/hw_sky.cpp b/src/hwrenderer/scene/hw_sky.cpp index 695321312..c2c6b8189 100644 --- a/src/hwrenderer/scene/hw_sky.cpp +++ b/src/hwrenderer/scene/hw_sky.cpp @@ -61,7 +61,7 @@ void GLSkyInfo::init(int sky1, PalEntry FadeColor) FTextureID texno = s->GetTexture(pos); texture[0] = FMaterial::ValidateTexture(texno, false, true); - if (!texture[0] || texture[0]->tex->UseType == ETextureType::Null) goto normalsky; + if (!texture[0] || !texture[0]->tex->isValid()) goto normalsky; skytexno1 = texno; x_offset[0] = s->GetTextureXOffset(pos) * (360.f/65536.f); y_offset = s->GetTextureYOffset(pos); @@ -243,13 +243,13 @@ void GLWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vert { if (bs->GetPlaneTexZ(sector_t::floor)==fs->GetPlaneTexZ(sector_t::floor)+1.) { - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom)); - if (!tex || tex->UseType==ETextureType::Null) return; + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); + if (!tex || !tex->isValid()) return; // very, very, very ugly special case (See Icarus MAP14) // It is VERY important that this is only done for a floor height difference of 1 // or it will cause glitches elsewhere. - tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); + tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); if (tex != NULL && !(seg->linedef->flags & ML_DONTPEGTOP) && seg->sidedef->GetTextureYOffset(side_t::mid) > 0) { @@ -265,7 +265,7 @@ void GLWall::SkyTop(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,vert ztop[0]=ztop[1]=32768.0f; - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top)); + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top), true); if (bs->GetTexture(sector_t::ceiling) != skyflatnum) { @@ -325,10 +325,10 @@ void GLWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,v if (fs->GetTexture(sector_t::floor)==skyflatnum) { if (bs->special == GLSector_NoSkyDraw) return; - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::bottom)); + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); - // For lower skies the normal logic only applies to walls with no lower texture! - if (tex->UseType==ETextureType::Null) + // For lower skies the normal logic only applies to walls with no lower texture. + if (!tex->isValid()) { if (bs->GetTexture(sector_t::floor)==skyflatnum) { @@ -346,7 +346,7 @@ void GLWall::SkyBottom(HWDrawInfo *di, seg_t * seg,sector_t * fs,sector_t * bs,v } zbottom[0]=zbottom[1]=-32768.0f; - if ((tex && tex->UseType!=ETextureType::Null) || bs->GetTexture(sector_t::floor)!=skyflatnum) + if ((tex && !tex->isValid()) || bs->GetTexture(sector_t::floor)!=skyflatnum) { ztop[0]=zfloor[0]; ztop[1]=zfloor[1]; diff --git a/src/hwrenderer/scene/hw_skydome.cpp b/src/hwrenderer/scene/hw_skydome.cpp index 27342cf7d..f0436ca53 100644 --- a/src/hwrenderer/scene/hw_skydome.cpp +++ b/src/hwrenderer/scene/hw_skydome.cpp @@ -293,7 +293,7 @@ void FSkyVertexBuffer::SetupMatrices(FMaterial *tex, float x_offset, float y_off float yscale = 1.f; if (texh <= 128 && (level.flags & LEVEL_FORCETILEDSKY)) { - modelMatrix.translate(0.f, (-40 + tex->tex->SkyOffset + skyoffset)*skyoffsetfactor, 0.f); + modelMatrix.translate(0.f, (-40 + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); yscale = 240.f / texh; } @@ -311,12 +311,12 @@ void FSkyVertexBuffer::SetupMatrices(FMaterial *tex, float x_offset, float y_off } else if (texh <= 240) { - modelMatrix.translate(0.f, (200 - texh + tex->tex->SkyOffset + skyoffset)*skyoffsetfactor, 0.f); + modelMatrix.translate(0.f, (200 - texh + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); modelMatrix.scale(1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f, 1.f); } else { - modelMatrix.translate(0.f, (-40 + tex->tex->SkyOffset + skyoffset)*skyoffsetfactor, 0.f); + modelMatrix.translate(0.f, (-40 + tex->tex->GetSkyOffset() + skyoffset)*skyoffsetfactor, 0.f); modelMatrix.scale(1.f, 1.2f * 1.17f, 1.f); yscale = 240.f / texh; } diff --git a/src/hwrenderer/scene/hw_skyportal.cpp b/src/hwrenderer/scene/hw_skyportal.cpp index cb04c1e86..05b70e7fd 100644 --- a/src/hwrenderer/scene/hw_skyportal.cpp +++ b/src/hwrenderer/scene/hw_skyportal.cpp @@ -164,10 +164,10 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) auto &vp = di->Viewpoint; // We have no use for Doom lighting special handling here, so disable it for this function. - int oldlightmode = ::level.lightmode; - if (::level.lightmode == 8) + auto oldlightmode = ::level.lightmode; + if (::level.isSoftwareLighting()) { - ::level.lightmode = 2; + ::level.SetFallbackLightMode(); state.SetSoftLightLevel(-1); } @@ -181,7 +181,7 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) di->SetupView(state, 0, 0, 0, !!(mState->MirrorFlag & 1), !!(mState->PlaneMirrorFlag & 1)); state.SetVertexBuffer(vertexBuffer); - if (origin->texture[0] && origin->texture[0]->tex->bSkybox) + if (origin->texture[0] && origin->texture[0]->tex->isSkybox()) { RenderBox(di, state, origin->skytexno1, origin->texture[0], origin->x_offset[0], origin->sky2); } diff --git a/src/hwrenderer/scene/hw_sprites.cpp b/src/hwrenderer/scene/hw_sprites.cpp index 84a91a307..f8c716686 100644 --- a/src/hwrenderer/scene/hw_sprites.cpp +++ b/src/hwrenderer/scene/hw_sprites.cpp @@ -244,6 +244,7 @@ void GLSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) { state.SetNormal(0, 0, 0); + if (screen->BuffersArePersistent()) { CreateVertices(di); @@ -789,9 +790,9 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (isPicnumOverride) { // Animate picnum overrides. - auto tex = TexMan(thing->picnum); + auto tex = TexMan.GetTexture(thing->picnum, true); if (tex == nullptr) return; - patch = tex->id; + patch = tex->GetID(); mirror = false; } else @@ -910,7 +911,7 @@ void GLSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t // allow disabling of the fullbright flag by a brightmap definition // (e.g. to do the gun flashes of Doom's zombies correctly. fullbright = (thing->flags5 & MF5_BRIGHT) || - ((thing->renderflags & RF_FULLBRIGHT) && (!gltexture || !gltexture->tex->bDisableFullbright)); + ((thing->renderflags & RF_FULLBRIGHT) && (!gltexture || !gltexture->tex->isFullbrightDisabled())); lightlevel = fullbright ? 255 : hw_ClampLight(rendersector->GetTexture(sector_t::ceiling) == skyflatnum ? diff --git a/src/hwrenderer/scene/hw_walls.cpp b/src/hwrenderer/scene/hw_walls.cpp index 70ca0f633..f0022a109 100644 --- a/src/hwrenderer/scene/hw_walls.cpp +++ b/src/hwrenderer/scene/hw_walls.cpp @@ -165,7 +165,7 @@ void GLWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) } state.SetFog(255, 0, di->isFullbrightScene(), nullptr, false); } - if (type != RENDERWALL_COLOR) + if (type != RENDERWALL_COLOR && seg->sidedef != nullptr) { auto side = seg->sidedef; auto tierndx = renderwalltotier[type]; @@ -1000,7 +1000,7 @@ bool GLWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto if (gltexture != NULL) { bool normalize = false; - if (gltexture->tex->bHasCanvas) normalize = true; + if (gltexture->tex->isHardwareCanvas()) normalize = true; else if (flags & GLWF_CLAMPY) { // for negative scales we can get negative coordinates here. @@ -1029,7 +1029,7 @@ void GLWall::CheckTexturePosition(FTexCoordInfo *tci) { float sub; - if (gltexture->tex->bHasCanvas) return; + if (gltexture->tex->isHardwareCanvas()) return; // clamp texture coordinates to a reasonable range. // Extremely large values can cause visual problems @@ -1222,8 +1222,8 @@ void GLWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // Set up the top // // - FTexture * tex = TexMan(seg->sidedef->GetTexture(side_t::top)); - if (!tex || tex->UseType==ETextureType::Null) + FTexture * tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::top), true); + if (!tex || !tex->isValid()) { if (front->GetTexture(sector_t::ceiling) == skyflatnum && back->GetTexture(sector_t::ceiling) == skyflatnum && !wrap) @@ -1258,8 +1258,8 @@ void GLWall::DoMidTexture(HWDrawInfo *di, seg_t * seg, bool drawfogboundary, // Set up the bottom // // - tex = TexMan(seg->sidedef->GetTexture(side_t::bottom)); - if (!tex || tex->UseType==ETextureType::Null) + tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::bottom), true); + if (!tex || !tex->isValid()) { // texture is missing - use the lower plane bottomleft = MIN(bfh1,ffh1); @@ -2057,7 +2057,7 @@ void GLWall::Process(HWDrawInfo *di, seg_t *seg, sector_t * frontsector, sector_ sector_t *backsec = isportal? seg->linedef->getPortalDestination()->frontsector : backsector; bool drawfogboundary = !di->isFullbrightScene() && hw_CheckFog(frontsector, backsec); - FTexture *tex = TexMan(seg->sidedef->GetTexture(side_t::mid)); + FTexture *tex = TexMan.GetTexture(seg->sidedef->GetTexture(side_t::mid), true); if (tex != NULL) { if (i_compatflags & COMPATF_MASKEDMIDTEX) diff --git a/src/hwrenderer/scene/hw_weapon.cpp b/src/hwrenderer/scene/hw_weapon.cpp index 171c28647..8ec59a281 100644 --- a/src/hwrenderer/scene/hw_weapon.cpp +++ b/src/hwrenderer/scene/hw_weapon.cpp @@ -106,8 +106,8 @@ void HWDrawInfo::DrawPSprite(HUDSprite *huds, FRenderState &state) void HWDrawInfo::DrawPlayerSprites(bool hudModelStep, FRenderState &state) { - int oldlightmode = level.lightmode; - if (!hudModelStep && level.lightmode == 8) level.lightmode = 2; // Software lighting cannot handle 2D content so revert to lightmode 2 for that. + auto oldlightmode = level.lightmode; + if (!hudModelStep && level.isSoftwareLighting()) level.SetFallbackLightMode(); // Software lighting cannot handle 2D content. for (auto &hudsprite : hudsprites) { if ((!!hudsprite.mframe) == hudModelStep) @@ -131,8 +131,8 @@ static bool isBright(DPSprite *psp) FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); if (lump.isValid()) { - FTexture * tex = TexMan(lump); - if (tex) disablefullbright = tex->bDisableFullbright; + FTexture * tex = TexMan.GetTexture(lump, true); + if (tex) disablefullbright = tex->isFullbrightDisabled(); } return psp->GetState()->GetFullbright() && !disablefullbright; } @@ -260,7 +260,7 @@ static WeaponLighting GetWeaponLighting(sector_t *viewsector, const DVector3 &po l.lightlevel = hw_CalcLightLevel(l.lightlevel, getExtraLight(), true, 0); - if (level.lightmode == 8 || l.lightlevel < 92) + if (level.isSoftwareLighting() || l.lightlevel < 92) { // Korshun: the way based on max possible light level for sector like in software renderer. double min_L = 36.0 / 31.0 - ((l.lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63 @@ -498,8 +498,8 @@ void HWDrawInfo::PreparePlayerSprites(sector_t * viewsector, area_t in_area) // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change // light mode here to draw the weapon sprite. - int oldlightmode = level.lightmode; - if (level.lightmode == 8) level.lightmode = 2; + auto oldlightmode = level.lightmode; + if (level.isSoftwareLighting()) level.SetFallbackLightMode(); for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) { diff --git a/src/hwrenderer/textures/hw_ihwtexture.h b/src/hwrenderer/textures/hw_ihwtexture.h index 10447e5b1..f05baf47d 100644 --- a/src/hwrenderer/textures/hw_ihwtexture.h +++ b/src/hwrenderer/textures/hw_ihwtexture.h @@ -25,9 +25,6 @@ public: virtual uint8_t *MapBuffer() = 0; virtual unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) = 0; - virtual void Clean(bool all) = 0; - virtual void CleanUnused(SpriteHits &usedtranslations) = 0; - void Resize(int swidth, int sheight, int width, int height, unsigned char *src_data, unsigned char *dst_data); }; diff --git a/src/hwrenderer/textures/hw_material.cpp b/src/hwrenderer/textures/hw_material.cpp index 303c3e83a..d24f0d69a 100644 --- a/src/hwrenderer/textures/hw_material.cpp +++ b/src/hwrenderer/textures/hw_material.cpp @@ -128,25 +128,6 @@ void IHardwareTexture::Resize(int swidth, int sheight, int width, int height, un } } -//=========================================================================== -// -// -// -//=========================================================================== -IHardwareTexture * FMaterial::ValidateSysTexture(FTexture * tex, bool expand) -{ - if (tex && tex->UseType!=ETextureType::Null) - { - IHardwareTexture *gltex = tex->SystemTexture[expand]; - if (gltex == nullptr) - { - gltex = tex->SystemTexture[expand] = screen->CreateHardwareTexture(tex); - } - return gltex; - } - return nullptr; -} - //=========================================================================== // // Constructor @@ -160,16 +141,15 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) mShaderIndex = SHADER_Default; sourcetex = tex = tx; - if (tx->UseType == ETextureType::SWCanvas && tx->WidthBits == 0) + if (tx->UseType == ETextureType::SWCanvas && static_cast(tx)->GetColorFormat() == 0) { mShaderIndex = SHADER_Paletted; } - else if (tx->bWarped) + else if (tx->isWarped()) { - mShaderIndex = tx->bWarped; // This picks SHADER_Warp1 or SHADER_Warp2 - tx->shaderspeed = static_cast(tx)->GetSpeed(); + mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 } - else if (tx->bHasCanvas) + else if (tx->isHardwareCanvas()) { if (tx->shaderindex >= FIRST_USER_SHADER) { @@ -183,7 +163,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) { for (auto &texture : { tx->Normal, tx->Specular }) { - ValidateSysTexture(texture, expanded); mTextureLayers.Push(texture); } mShaderIndex = SHADER_Specular; @@ -192,7 +171,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) { for (auto &texture : { tx->Normal, tx->Metallic, tx->Roughness, tx->AmbientOcclusion }) { - ValidateSysTexture(texture, expanded); mTextureLayers.Push(texture); } mShaderIndex = SHADER_PBR; @@ -201,7 +179,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) tx->CreateDefaultBrightmap(); if (tx->Brightmap) { - ValidateSysTexture(tx->Brightmap, expanded); mTextureLayers.Push(tx->Brightmap); if (mShaderIndex == SHADER_Specular) mShaderIndex = SHADER_SpecularBrightmap; @@ -219,16 +196,12 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) for (auto &texture : tx->CustomShaderTextures) { if (texture == nullptr) continue; - ValidateSysTexture(texture, expanded); mTextureLayers.Push(texture); } mShaderIndex = tx->shaderindex; } } } - mBaseLayer = ValidateSysTexture(tx, expanded); - - mWidth = tx->GetWidth(); mHeight = tx->GetHeight(); mLeftOffset = tx->GetLeftOffset(0); // These only get used by decals and decals should not use renderer-specific offsets. @@ -238,14 +211,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) mSpriteU[0] = mSpriteV[0] = 0.f; mSpriteU[1] = mSpriteV[1] = 1.f; - FTexture *basetex = tx->GetRedirect(); - // allow the redirect only if the texture is not expanded or the scale matches. - if (!expanded || (tx->Scale.X == basetex->Scale.X && tx->Scale.Y == basetex->Scale.Y)) - { - sourcetex = basetex; - mBaseLayer = ValidateSysTexture(basetex, expanded); - } - mExpanded = expanded; if (expanded) { @@ -265,7 +230,7 @@ FMaterial::FMaterial(FTexture * tx, bool expanded) mMaxBound = -1; mMaterials.Push(this); tx->Material[expanded] = this; - if (tx->bHasCanvas) tx->bTranslucent = 0; + if (tx->isHardwareCanvas()) tx->bTranslucent = 0; } //=========================================================================== @@ -350,19 +315,19 @@ void FMaterial::SetSpriteRect() bool FMaterial::TrimBorders(uint16_t *rect) { - int w; - int h; - unsigned char *buffer = sourcetex->CreateTexBuffer(0, w, h); + auto texbuffer = sourcetex->CreateTexBuffer(0); + int w = texbuffer.mWidth; + int h = texbuffer.mHeight; + auto Buffer = texbuffer.mBuffer; - if (buffer == NULL) + if (texbuffer.mBuffer == nullptr) { return false; } if (w != mWidth || h != mHeight) { // external Hires replacements cannot be trimmed. - delete [] buffer; return false; } @@ -374,14 +339,13 @@ bool FMaterial::TrimBorders(uint16_t *rect) rect[1] = 0; rect[2] = 1; rect[3] = 1; - delete[] buffer; return true; } int first, last; for(first = 0; first < size; first++) { - if (buffer[first*4+3] != 0) break; + if (Buffer[first*4+3] != 0) break; } if (first >= size) { @@ -390,13 +354,12 @@ bool FMaterial::TrimBorders(uint16_t *rect) rect[1] = 0; rect[2] = 1; rect[3] = 1; - delete [] buffer; return true; } for(last = size-1; last >= first; last--) { - if (buffer[last*4+3] != 0) break; + if (Buffer[last*4+3] != 0) break; } rect[1] = first / w; @@ -405,7 +368,7 @@ bool FMaterial::TrimBorders(uint16_t *rect) rect[0] = 0; rect[2] = w; - unsigned char *bufferoff = buffer + (rect[1] * w * 4); + unsigned char *bufferoff = Buffer + (rect[1] * w * 4); h = rect[3]; for(int x = 0; x < w; x++) @@ -425,16 +388,38 @@ outl: { if (bufferoff[(x+y*w)*4+3] != 0) { - delete [] buffer; return true; } } rect[2]--; } - delete [] buffer; return true; } +//=========================================================================== +// +// +// +//=========================================================================== + +IHardwareTexture *FMaterial::GetLayer(int i, int translation, FTexture **pLayer) +{ + FTexture *layer = i == 0 ? tex : mTextureLayers[i - 1]; + if (pLayer) *pLayer = layer; + + if (layer && layer->UseType!=ETextureType::Null) + { + IHardwareTexture *hwtex = layer->SystemTextures.GetHardwareTexture(translation, mExpanded); + if (hwtex == nullptr) + { + hwtex = screen->CreateHardwareTexture(); + layer->SystemTextures.AddHardwareTexture(translation, mExpanded, hwtex); + } + return hwtex; + } + return nullptr; +} + //=========================================================================== // // @@ -452,7 +437,7 @@ void FMaterial::Precache() //=========================================================================== void FMaterial::PrecacheList(SpriteHits &translations) { - if (mBaseLayer != nullptr) mBaseLayer->CleanUnused(translations); + tex->SystemTextures.CleanUnused(translations, mExpanded); SpriteHits::Iterator it(translations); SpriteHits::Pair *pair; while(it.NextPair(pair)) screen->PrecacheMaterial(this, pair->Key); @@ -484,19 +469,19 @@ int FMaterial::GetAreas(FloatRect **pAreas) const // //========================================================================== -FMaterial * FMaterial::ValidateTexture(FTexture * tex, bool expand) +FMaterial * FMaterial::ValidateTexture(FTexture * tex, bool expand, bool create) { again: - if (tex && tex->UseType!=ETextureType::Null) + if (tex && tex->isValid()) { if (tex->bNoExpand) expand = false; - FMaterial *gltex = tex->Material[expand]; - if (gltex == NULL) + FMaterial *hwtex = tex->Material[expand]; + if (hwtex == NULL && create) { if (expand) { - if (tex->bWarped || tex->bHasCanvas || tex->shaderindex >= FIRST_USER_SHADER || (tex->shaderindex >= SHADER_Specular && tex->shaderindex <= SHADER_PBRBrightmap)) + if (tex->isWarped() || tex->isHardwareCanvas() || tex->shaderindex >= FIRST_USER_SHADER || (tex->shaderindex >= SHADER_Specular && tex->shaderindex <= SHADER_PBRBrightmap)) { tex->bNoExpand = true; goto again; @@ -511,84 +496,14 @@ again: goto again; } } - gltex = new FMaterial(tex, expand); + hwtex = new FMaterial(tex, expand); } - return gltex; + return hwtex; } return NULL; } -FMaterial * FMaterial::ValidateTexture(FTextureID no, bool expand, bool translate) +FMaterial * FMaterial::ValidateTexture(FTextureID no, bool expand, bool translate, bool create) { - return ValidateTexture(translate? TexMan(no) : TexMan[no], expand); + return ValidateTexture(TexMan.GetTexture(no, translate), expand, create); } - - -//========================================================================== -// -// Flushes all hardware dependent data -// -//========================================================================== - -void FMaterial::FlushAll() -{ - for(int i=mMaterials.Size()-1;i>=0;i--) - { - mMaterials[i]->mBaseLayer->Clean(true); - } - // This is for shader layers. All shader layers must be managed by the texture manager - // so this will catch everything. - for(int i=TexMan.NumTextures()-1;i>=0;i--) - { - for (int j = 0; j < 2; j++) - { - auto gltex = TexMan.ByIndex(i)->SystemTexture[j]; - if (gltex != nullptr) gltex->Clean(true); - } - } -} - -void FMaterial::Clean(bool f) -{ - // This somehow needs to deal with the other layers as well, but they probably need some form of reference counting to work properly... - mBaseLayer->Clean(f); -} - -//========================================================================== -// -// Prints some texture info -// -//========================================================================== - -CCMD(textureinfo) -{ - int cntt = 0; - for (int i = 0; i < TexMan.NumTextures(); i++) - { - FTexture *tex = TexMan.ByIndex(i); - if (tex->SystemTexture[0] || tex->SystemTexture[1] || tex->Material[0] || tex->Material[1]) - { - int lump = tex->GetSourceLump(); - Printf(PRINT_LOG, "Texture '%s' (Index %d, Lump %d, Name '%s'):\n", tex->Name.GetChars(), i, lump, Wads.GetLumpFullName(lump)); - if (tex->Material[0]) - { - Printf(PRINT_LOG, "in use (normal)\n"); - } - else if (tex->SystemTexture[0]) - { - Printf(PRINT_LOG, "referenced (normal)\n"); - } - if (tex->Material[1]) - { - Printf(PRINT_LOG, "in use (expanded)\n"); - } - else if (tex->SystemTexture[1]) - { - Printf(PRINT_LOG, "referenced (normal)\n"); - } - cntt++; - } - } - Printf(PRINT_LOG, "%d system textures\n", cntt); -} - diff --git a/src/hwrenderer/textures/hw_material.h b/src/hwrenderer/textures/hw_material.h index c35b23c08..33bf0f9d3 100644 --- a/src/hwrenderer/textures/hw_material.h +++ b/src/hwrenderer/textures/hw_material.h @@ -39,7 +39,6 @@ class FMaterial static TArray mMaterials; static int mMaxBound; - IHardwareTexture *mBaseLayer; TArray mTextureLayers; int mShaderIndex; @@ -68,7 +67,6 @@ public: void Precache(); void PrecacheList(SpriteHits &translations); int GetShaderIndex() const { return mShaderIndex; } - IHardwareTexture * ValidateSysTexture(FTexture * tex, bool expand); void AddTextureLayer(FTexture *tex) { ValidateTexture(tex, false); @@ -87,24 +85,13 @@ public: { return mTextureLayers.Size() + 1; } - - IHardwareTexture *GetLayer(int i, FTexture **pLayer = nullptr) + + bool hasCanvas() { - if (i == 0) - { - if (pLayer) *pLayer = tex; - return mBaseLayer; - } - else - { - i--; - FTexture *layer = mTextureLayers[i]; - if (pLayer) *pLayer = layer; - return ValidateSysTexture(layer, isExpanded()); - } + return tex->isHardwareCanvas(); } - void Clean(bool f); + IHardwareTexture *GetLayer(int i, int translation, FTexture **pLayer = nullptr); // Patch drawing utilities @@ -163,10 +150,8 @@ public: float GetSpriteVB() const { return mSpriteV[1]; } - static void DeleteAll(); - static void FlushAll(); - static FMaterial *ValidateTexture(FTexture * tex, bool expand); - static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans); + static FMaterial *ValidateTexture(FTexture * tex, bool expand, bool create = true); + static FMaterial *ValidateTexture(FTextureID no, bool expand, bool trans, bool create = true); }; #endif diff --git a/src/hwrenderer/textures/hw_precache.cpp b/src/hwrenderer/textures/hw_precache.cpp index a6342d2fb..dc6829dd6 100644 --- a/src/hwrenderer/textures/hw_precache.cpp +++ b/src/hwrenderer/textures/hw_precache.cpp @@ -33,6 +33,7 @@ #include "r_data/models/models.h" #include "textures/skyboxtexture.h" #include "hwrenderer/textures/hw_material.h" +#include "image.h" //========================================================================== @@ -48,11 +49,6 @@ static void PrecacheTexture(FTexture *tex, int cache) FMaterial * gltex = FMaterial::ValidateTexture(tex, false); if (gltex) gltex->Precache(); } - else - { - // make sure that software pixel buffers do not stick around for unneeded textures. - tex->Unload(); - } } //========================================================================== @@ -91,14 +87,14 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl if (texhitlist[i] & (FTextureManager::HIT_Sky | FTextureManager::HIT_Wall)) { FTexture *tex = TexMan.ByIndex(i); - if (tex->bSkybox) + if (tex->isSkybox()) { FSkyBox *sb = static_cast(tex); for (int i = 0; i<6; i++) { if (sb->faces[i]) { - int index = sb->faces[i]->id.GetIndex(); + int index = sb->faces[i]->GetID().GetIndex(); texhitlist[index] |= FTextureManager::HIT_Flat; } } @@ -181,17 +177,41 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl { if (!texhitlist[i]) { - if (tex->Material[0]) tex->Material[0]->Clean(true); + tex->SystemTextures.Clean(true, false); } if (spritehitlist[i] == nullptr || (*spritehitlist[i]).CountUsed() == 0) { - if (tex->Material[1]) tex->Material[1]->Clean(true); + tex->SystemTextures.Clean(false, true); } } } if (gl_precache) { + FImageSource::BeginPrecaching(); + + // cache all used textures + for (int i = cnt - 1; i >= 0; i--) + { + FTexture *tex = TexMan.ByIndex(i); + if (tex != nullptr && tex->GetImage() != nullptr) + { + if (texhitlist[i] & (FTextureManager::HIT_Wall | FTextureManager::HIT_Flat | FTextureManager::HIT_Sky)) + { + if (tex->GetImage() && tex->SystemTextures.GetHardwareTexture(0, false) == nullptr) + { + FImageSource::RegisterForPrecache(tex->GetImage()); + } + } + + // Only register untranslated sprites. Translated ones are very unlikely to require data that can be reused. + if (spritehitlist[i] != nullptr && (*spritehitlist[i]).CheckKey(0)) + { + FImageSource::RegisterForPrecache(tex->GetImage()); + } + } + } + // cache all used textures for (int i = cnt - 1; i >= 0; i--) { @@ -206,6 +226,9 @@ void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitl } } + + FImageSource::EndPrecaching(); + // cache all used models FModelRenderer *renderer = screen->CreateModelRenderer(-1); for (unsigned i = 0; i < Models.Size(); i++) diff --git a/src/hwrenderer/textures/hw_texcontainer.h b/src/hwrenderer/textures/hw_texcontainer.h new file mode 100644 index 000000000..65f356115 --- /dev/null +++ b/src/hwrenderer/textures/hw_texcontainer.h @@ -0,0 +1,130 @@ +#pragma once + +#include "tarray.h" +#include "hwrenderer/textures/hw_ihwtexture.h" + +struct FTextureBuffer; +class IHardwareTexture; + +class FHardwareTextureContainer +{ +public: + enum + { + MAX_TEXTURES = 16 + }; + +private: + struct TranslatedTexture + { + IHardwareTexture *hwTexture = nullptr; + int translation = 0; + + void Delete() + { + if (hwTexture) delete hwTexture; + hwTexture = nullptr; + } + + ~TranslatedTexture() + { + Delete(); + } + }; + +private: + + TranslatedTexture hwDefTex[2]; + TArray hwTex_Translated; + + TranslatedTexture * GetTexID(int translation, bool expanded) + { + translation = TranslationToIndex(translation); + if (translation == 0) + { + return &hwDefTex[expanded]; + } + + if (expanded) translation = -translation; + // normally there aren't more than very few different + // translations here so this isn't performance critical. + unsigned index = hwTex_Translated.FindEx([=](auto &element) + { + return element.translation == translation; + }); + if (index < hwTex_Translated.Size()) + { + return &hwTex_Translated[index]; + } + + int add = hwTex_Translated.Reserve(1); + auto item = &hwTex_Translated[add]; + item->translation = translation; + return item; + } + +public: + + void Clean(bool cleannormal, bool cleanexpanded) + { + if (cleannormal) hwDefTex[0].Delete(); + if (cleanexpanded) hwDefTex[1].Delete(); + for (int i = hwTex_Translated.Size() - 1; i >= 0; i--) + { + if (cleannormal && hwTex_Translated[i].translation > 0) hwTex_Translated.Delete(i); + else if (cleanexpanded && hwTex_Translated[i].translation < 0) hwTex_Translated.Delete(i); + } + } + + IHardwareTexture * GetHardwareTexture(int translation, bool expanded) + { + auto tt = GetTexID(translation, expanded); + return tt->hwTexture; + } + + void AddHardwareTexture(int translation, bool expanded, IHardwareTexture *tex) + { + auto tt = GetTexID(translation, expanded); + tt->Delete(); + tt->hwTexture =tex; + } + + //=========================================================================== + // + // Deletes all allocated resources and considers translations + // This will only be called for sprites + // + //=========================================================================== + + void CleanUnused(SpriteHits &usedtranslations, bool expanded) + { + if (usedtranslations.CheckKey(0) == nullptr) + { + hwDefTex[expanded].Delete(); + } + int fac = expanded ? -1 : 1; + for (int i = hwTex_Translated.Size()-1; i>= 0; i--) + { + if (usedtranslations.CheckKey(hwTex_Translated[i].translation * fac) == nullptr) + { + hwTex_Translated.Delete(i); + } + } + } + + static int TranslationToIndex(int translation) + { + if (translation <= 0) + { + return -translation; + } + else + { + auto remap = TranslationToTable(translation); + return remap == nullptr ? 0 : remap->GetUniqueIndex(); + } + } + + +}; + diff --git a/src/hwrenderer/utility/hw_cvars.cpp b/src/hwrenderer/utility/hw_cvars.cpp index f0a0f8c83..1d11e24b1 100644 --- a/src/hwrenderer/utility/hw_cvars.cpp +++ b/src/hwrenderer/utility/hw_cvars.cpp @@ -92,7 +92,7 @@ CUSTOM_CVAR(Float,gl_texture_filter_anisotropic,8.0f,CVAR_ARCHIVE|CVAR_GLOBALCON CCMD(gl_flush) { - FMaterial::FlushAll(); + TexMan.FlushAll(); } CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL) @@ -103,7 +103,7 @@ CUSTOM_CVAR(Int, gl_texture_filter, 4, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINI CUSTOM_CVAR(Bool, gl_texture_usehires, true, CVAR_ARCHIVE|CVAR_NOINITCALL) { - FMaterial::FlushAll(); + TexMan.FlushAll(); } CVAR(Bool, gl_precache, false, CVAR_ARCHIVE) diff --git a/src/hwrenderer/utility/hw_draw2d.cpp b/src/hwrenderer/utility/hw_draw2d.cpp index f15ddc2c4..0e224b26d 100644 --- a/src/hwrenderer/utility/hw_draw2d.cpp +++ b/src/hwrenderer/utility/hw_draw2d.cpp @@ -169,7 +169,7 @@ void Draw2D(F2DDrawer *drawer, FRenderState &state) state.EnableTexture(true); // Canvas textures are stored upside down - if (cmd.mTexture->bHasCanvas) + if (cmd.mTexture->isHardwareCanvas()) { state.mTextureMatrix.loadIdentity(); state.mTextureMatrix.scale(1.f, -1.f, 1.f); diff --git a/src/hwrenderer/utility/hw_lighting.cpp b/src/hwrenderer/utility/hw_lighting.cpp index 83e2acd7d..8d7298b9f 100644 --- a/src/hwrenderer/utility/hw_lighting.cpp +++ b/src/hwrenderer/utility/hw_lighting.cpp @@ -88,7 +88,7 @@ int hw_CalcLightLevel(int lightlevel, int rellight, bool weapon, int blendfactor if (lightlevel == 0) return 0; - bool darklightmode = (level.lightmode & 2) || (level.lightmode == 8 && blendfactor > 0); + bool darklightmode = (level.isDarkLightMode()) || (level.isSoftwareLighting() && blendfactor > 0); if (darklightmode && lightlevel < 192 && !weapon) { @@ -130,7 +130,7 @@ PalEntry hw_CalcLightColor(int light, PalEntry pe, int blendfactor) if (blendfactor == 0) { - if (level.lightmode == 8) + if (level.isSoftwareLighting()) { return pe; } @@ -174,10 +174,10 @@ float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, { float density; - int lightmode = level.lightmode; - if (lightmode == 8 && blendfactor > 0) lightmode = 2; // The blendfactor feature does not work with software-style lighting. + auto lightmode = level.lightmode; + if (level.isSoftwareLighting() && blendfactor > 0) lightmode = ELightMode::Doom; // The blendfactor feature does not work with software-style lighting. - if (lightmode & 4) + if (lightmode == ELightMode::DoomLegacy) { // uses approximations of Legacy's default settings. density = level.fogdensity ? (float)level.fogdensity : 18; @@ -190,9 +190,9 @@ float hw_GetFogDensity(int lightlevel, PalEntry fogcolor, int sectorfogdensity, else if ((fogcolor.d & 0xffffff) == 0) { // case 2: black fog - if ((lightmode != 8 || blendfactor > 0) && !(level.flags3 & LEVEL3_NOLIGHTFADE)) + if ((!level.isSoftwareLighting() || blendfactor > 0) && !(level.flags3 & LEVEL3_NOLIGHTFADE)) { - density = distfogtable[level.lightmode != 0][hw_ClampLight(lightlevel)]; + density = distfogtable[level.lightmode != ELightMode::LinearStandard][hw_ClampLight(lightlevel)]; } else { @@ -250,7 +250,7 @@ bool hw_CheckFog(sector_t *frontsector, sector_t *backsector) else if (level.outsidefogdensity != 0 && APART(level.info->outsidefog) != 0xff && (fogcolor.d & 0xffffff) == (level.info->outsidefog & 0xffffff)) { } - else if (level.fogdensity!=0 || (level.lightmode & 4)) + else if (level.fogdensity!=0 || level.lightmode == ELightMode::DoomLegacy) { // case 3: level has fog density set } @@ -269,7 +269,7 @@ bool hw_CheckFog(sector_t *frontsector, sector_t *backsector) { return false; } - else if (level.fogdensity!=0 || (level.lightmode & 4)) + else if (level.fogdensity!=0 || level.lightmode == ELightMode::DoomLegacy) { // case 3: level has fog density set return false; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 65f31910e..4b3826261 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -162,11 +162,11 @@ void DIntermissionScreen::Drawer () { if (!mFlatfill) { - screen->DrawTexture (TexMan[mBackground], 0, 0, DTA_Fullscreen, true, TAG_DONE); + screen->DrawTexture (TexMan.GetTexture(mBackground), 0, 0, DTA_Fullscreen, true, TAG_DONE); } else { - screen->FlatFill (0,0, SCREENWIDTH, SCREENHEIGHT, TexMan[mBackground]); + screen->FlatFill (0,0, SCREENWIDTH, SCREENHEIGHT, TexMan.GetTexture(mBackground)); } } else @@ -176,7 +176,7 @@ void DIntermissionScreen::Drawer () for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - screen->DrawTexture (TexMan[mOverlays[i].mPic], mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); + screen->DrawTexture (TexMan.GetTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); } if (!mFlatfill) screen->FillBorder (NULL); } @@ -229,11 +229,11 @@ void DIntermissionScreenFader::Drawer () if (mType == FADE_In) factor = 1.0 - factor; int color = MAKEARGB(int(factor*255), 0,0,0); - screen->DrawTexture (TexMan[mBackground], 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); + screen->DrawTexture (TexMan.GetTexture(mBackground), 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - screen->DrawTexture (TexMan[mOverlays[i].mPic], mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); + screen->DrawTexture (TexMan.GetTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); } screen->FillBorder (NULL); } @@ -337,7 +337,7 @@ void DIntermissionScreenText::Drawer () continue; } - pic = SmallFont->GetChar (c, &w); + pic = SmallFont->GetChar (c, mTextColor, &w); w += kerning; w *= CleanXfac; if (cx + w > SCREENWIDTH) @@ -568,13 +568,13 @@ void DIntermissionScreenCast::Drawer () } sprframe = &SpriteFrames[sprites[castsprite].spriteframes + caststate->GetFrame()]; - pic = TexMan(sprframe->Texture[0]); + pic = TexMan.GetTexture(sprframe->Texture[0], true); screen->DrawTexture (pic, 160, 170, DTA_320x200, true, DTA_FlipX, sprframe->Flip & 1, - DTA_DestHeightF, pic->GetScaledHeightDouble() * castscale.Y, - DTA_DestWidthF, pic->GetScaledWidthDouble() * castscale.X, + DTA_DestHeightF, pic->GetDisplayHeightDouble() * castscale.Y, + DTA_DestWidthF, pic->GetDisplayWidthDouble() * castscale.X, DTA_RenderStyle, mDefaults->RenderStyle, DTA_Alpha, mDefaults->Alpha, DTA_TranslationIndex, casttranslation, @@ -611,13 +611,13 @@ int DIntermissionScreenScroller::Responder (event_t *ev) void DIntermissionScreenScroller::Drawer () { - FTexture *tex = TexMan[mFirstPic]; - FTexture *tex2 = TexMan[mSecondPic]; + FTexture *tex = TexMan.GetTexture(mFirstPic); + FTexture *tex2 = TexMan.GetTexture(mSecondPic); if (mTicker >= mScrollDelay && mTicker < mScrollDelay + mScrollTime && tex != NULL && tex2 != NULL) { - int fwidth = tex->GetScaledWidth(); - int fheight = tex->GetScaledHeight(); + int fwidth = tex->GetDisplayWidth(); + int fheight = tex->GetDisplayHeight(); double xpos1 = 0, ypos1 = 0, xpos2 = 0, ypos2 = 0; diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 8211cc57f..6361e8e4f 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -502,7 +502,7 @@ unsigned FSavegameManager::ExtractSaveData(int index) { SavePic = PNGTexture_CreateFromFile(png, node->Filename); delete png; - if (SavePic->GetWidth() == 1 && SavePic->GetHeight() == 1) + if (SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1) { delete SavePic; SavePic = nullptr; diff --git a/src/p_3dmidtex.cpp b/src/p_3dmidtex.cpp index 7a2363be6..6b54d6558 100644 --- a/src/p_3dmidtex.cpp +++ b/src/p_3dmidtex.cpp @@ -229,7 +229,7 @@ bool P_GetMidTexturePosition(const line_t *line, int sideno, double *ptextop, do side_t *side = line->sidedef[sideno]; FTextureID texnum = side->GetTexture(side_t::mid); if (!texnum.isValid()) return false; - FTexture * tex= TexMan(texnum); + FTexture * tex= TexMan.GetTexture(texnum, true); if (!tex) return false; FTexCoordInfo tci; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 44038184d..ab7ca86b8 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3747,7 +3747,7 @@ void DLevelScript::ChangeFlat (int tag, int name, bool floorOrCeiling) if (flatname == NULL) return; - flat = TexMan.GetTexture (flatname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + flat = TexMan.GetTextureID(flatname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); FSectorTagIterator it(tag); while ((secnum = it.Next()) >= 0) @@ -3779,7 +3779,7 @@ void DLevelScript::SetLineTexture (int lineid, int side, int position, int name) side = !!side; - texture = TexMan.GetTexture (texname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + texture = TexMan.GetTextureID(texname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); FLineIdIterator itr(lineid); while ((linenum = itr.Next()) >= 0) @@ -4574,10 +4574,10 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b { return 0; } - FTexture *tex = TexMan.FindTexture(FBehavior::StaticLookupString(string), ETextureType::Flat, + FTextureID tex = TexMan.CheckForTexture(FBehavior::StaticLookupString(string), ETextureType::Flat, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_DontCreate); - if (tex == NULL) + if (!tex.Exists()) { // If the texture we want to check against doesn't exist, then // they're obviously not the same. return 0; @@ -4596,7 +4596,7 @@ bool DLevelScript::DoCheckActorTexture(int tid, AActor *activator, int string, b NextHighestCeilingAt(actor->Sector, actor->X(), actor->Y(), actor->Z(), actor->Top(), 0, &resultsec, &resffloor); secpic = resffloor ? *resffloor->bottom.texture : resultsec->planes[sector_t::ceiling].Texture; } - return tex == TexMan[secpic]; + return tex == secpic; } @@ -6690,7 +6690,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) auto a = SingleActorFromTID(args[0], activator); if (a != nullptr) { - return GlobalACSStrings.AddString(TexMan[a->floorpic]->Name); + return GlobalACSStrings.AddString(TexMan.GetTexture(a->floorpic)->GetName()); } else { @@ -9865,11 +9865,11 @@ scriptwait: sky2name = FBehavior::StaticLookupString (STACK(1)); if (sky1name[0] != 0) { - sky1texture = level.skytexture1 = TexMan.GetTexture (sky1name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); + sky1texture = level.skytexture1 = TexMan.GetTextureID(sky1name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); } if (sky2name[0] != 0) { - sky2texture = level.skytexture2 = TexMan.GetTexture (sky2name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); + sky2texture = level.skytexture2 = TexMan.GetTextureID(sky2name, ETextureType::Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_ReturnFirst); } R_InitSkyMap (); sp -= 2; @@ -9900,7 +9900,7 @@ scriptwait: } else { - FCanvasTextureInfo::Add (camera, picnum, STACK(1)); + level.canvasTextureInfo.Add(camera, picnum, STACK(1)); } } sp -= 3; diff --git a/src/p_doors.cpp b/src/p_doors.cpp index fa08f3259..da7d1336e 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -293,8 +293,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const if (line->backsector == NULL) continue; - FTexture *tex = TexMan[line->sidedef[0]->GetTexture(side_t::top)]; - texname = tex ? tex->Name.GetChars() : NULL; + FTexture *tex = TexMan.GetTexture(line->sidedef[0]->GetTexture(side_t::top)); + texname = tex ? tex->GetName().GetChars() : NULL; if (texname != NULL && texname[0] == 'D' && texname[1] == 'O' && texname[2] == 'R') { switch (texname[3]) @@ -715,9 +715,8 @@ DAnimatedDoor::DAnimatedDoor (sector_t *sec, line_t *line, int speed, int delay, picnum = tex1[side_t::top].texture; - // don't forget texture scaling here! - FTexture *tex = TexMan[picnum]; - topdist = tex ? tex->GetScaledHeight() : 64; + FTexture *tex = TexMan.GetTexture(picnum); + topdist = tex ? tex->GetDisplayHeight() : 64; topdist = m_Sector->ceilingplane.fD() - topdist * m_Sector->ceilingplane.fC(); diff --git a/src/p_effect.cpp b/src/p_effect.cpp index aeb5b0ec8..da43890c5 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -59,10 +59,9 @@ FRandom pr_railtrail("RailTrail"); #define FADEFROMTTL(a) (1.f/(a)) // [RH] particle globals -uint16_t NumParticles; -uint16_t ActiveParticles; -uint16_t InactiveParticles; -particle_t *Particles; +uint32_t ActiveParticles; +uint32_t InactiveParticles; +TArray Particles; TArray ParticlesInSubsec; static int grey1, grey2, grey3, grey4, red, green, blue, yellow, black, @@ -105,13 +104,13 @@ static const struct ColorList { inline particle_t *NewParticle (void) { - particle_t *result = NULL; + particle_t *result = nullptr; if (InactiveParticles != NO_PARTICLE) { - result = Particles + InactiveParticles; + result = &Particles[InactiveParticles]; InactiveParticles = result->tnext; result->tnext = ActiveParticles; - ActiveParticles = uint16_t(result - Particles); + ActiveParticles = uint32_t(result - Particles.Data()); } return result; } @@ -120,7 +119,6 @@ inline particle_t *NewParticle (void) // [RH] Particle functions // void P_InitParticles (); -void P_DeinitParticles (); // [BC] Allow the maximum number of particles to be specified by a cvar (so people // with lots of nice hardware can have lots of particles!). @@ -135,7 +133,6 @@ CUSTOM_CVAR( Int, r_maxparticles, 4000, CVAR_ARCHIVE ) if ( gamestate != GS_STARTUP ) { - P_DeinitParticles( ); P_InitParticles( ); } } @@ -152,33 +149,21 @@ void P_InitParticles () num = r_maxparticles; // This should be good, but eh... - NumParticles = (uint16_t)clamp(num, 100, 65535); + int NumParticles = clamp(num, 100, 65535); - P_DeinitParticles(); - Particles = new particle_t[NumParticles]; + Particles.Resize(NumParticles); P_ClearParticles (); - atterm (P_DeinitParticles); -} - -void P_DeinitParticles() -{ - if (Particles != NULL) - { - delete[] Particles; - Particles = NULL; - } } void P_ClearParticles () { - int i; - - memset (Particles, 0, NumParticles * sizeof(particle_t)); + int i = 0; + memset (Particles.Data(), 0, Particles.Size() * sizeof(particle_t)); ActiveParticles = NO_PARTICLE; InactiveParticles = 0; - for (i = 0; i < NumParticles-1; i++) - Particles[i].tnext = i + 1; - Particles[i].tnext = NO_PARTICLE; + for (auto &p : Particles) + p.tnext = ++i; + Particles.Last().tnext = NO_PARTICLE; } // Group particles by subsectors. Because particles are always @@ -255,7 +240,7 @@ void P_ThinkParticles () prev = NULL; while (i != NO_PARTICLE) { - particle = Particles + i; + particle = &Particles[i]; i = particle->tnext; if (!particle->notimefreeze && ((bglobal.freeze) || (level.flags2 & LEVEL2_FROZEN))) { @@ -274,7 +259,7 @@ void P_ThinkParticles () else ActiveParticles = i; particle->tnext = InactiveParticles; - InactiveParticles = (int)(particle - Particles); + InactiveParticles = (int)(particle - Particles.Data()); continue; } diff --git a/src/p_effect.h b/src/p_effect.h index 4620bfa5a..00689118a 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -62,7 +62,7 @@ struct particle_t uint16_t snext; }; -extern particle_t *Particles; +extern TArray Particles; extern TArray ParticlesInSubsec; const uint16_t NO_PARTICLE = 0xffff; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 5436cfbe7..68f642c78 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -1012,7 +1012,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) StatusBar->SerializeMessages(arc); AM_SerializeMarkers(arc); FRemapTable::StaticSerializeTranslations(arc); - FCanvasTextureInfo::Serialize(arc); + level.canvasTextureInfo.Serialize(arc); P_SerializePlayers(arc, hubload); P_SerializeSounds(arc); diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 0f8285e93..d716fd8bf 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -477,10 +477,10 @@ static inline void CheckShortestTex (FTextureID texnum, double &minsize) { if (texnum.isValid() || (texnum.isNull() && (i_compatflags & COMPATF_SHORTTEX))) { - FTexture *tex = TexMan[texnum]; + FTexture *tex = TexMan.GetTexture(texnum); if (tex != NULL) { - double h = tex->GetScaledHeight(); + double h = tex->GetDisplayHeight(); if (h < minsize) { minsize = h; @@ -501,7 +501,7 @@ double FindShortestTextureAround (sector_t *sec) CheckShortestTex (check->sidedef[1]->GetTexture(side_t::bottom), minsize); } } - return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight(); + return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight(); } // @@ -526,7 +526,7 @@ double FindShortestUpperAround (sector_t *sec) CheckShortestTex (check->sidedef[1]->GetTexture(side_t::top), minsize); } } - return minsize < FLT_MAX ? minsize : TexMan[0]->GetHeight(); + return minsize < FLT_MAX ? minsize : TexMan.ByIndex(0)->GetDisplayHeight(); } // @@ -1144,14 +1144,14 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) auto c = planes[sector_t::floor].GlowColor; if (c == 0) { - FTexture *tex = TexMan[GetTexture(sector_t::floor)]; + FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::floor)); if (tex != NULL && tex->isGlowing()) { - if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::floor)); + if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::floor), true); if (tex->isGlowing()) // recheck the current animation frame. { tex->GetGlowColor(bottomglowcolor); - bottomglowcolor[3] = (float)tex->GlowHeight; + bottomglowcolor[3] = (float)tex->GetGlowHeight(); } } } @@ -1189,15 +1189,15 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) auto c = planes[sector_t::ceiling].GlowColor; if (c == 0) { - FTexture *tex = TexMan[GetTexture(sector_t::ceiling)]; + FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::ceiling)); if (tex != NULL && tex->isGlowing()) { - if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::ceiling)); + if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::ceiling), true); if (tex->isGlowing()) // recheck the current animation frame. { ret = true; tex->GetGlowColor(topglowcolor); - topglowcolor[3] = (float)tex->GlowHeight; + topglowcolor[3] = (float)tex->GetGlowHeight(); } } } @@ -1213,15 +1213,15 @@ double GetFriction(const sector_t *self, int plane, double *pMoveFac) c = planes[sector_t::floor].GlowColor; if (c == 0) { - FTexture *tex = TexMan[GetTexture(sector_t::floor)]; + FTexture *tex = TexMan.GetTexture(GetTexture(sector_t::floor)); if (tex != NULL && tex->isGlowing()) { - if (!tex->bAutoGlowing) tex = TexMan(GetTexture(sector_t::floor)); + if (!tex->isAutoGlowing()) tex = TexMan.GetTexture(GetTexture(sector_t::floor), true); if (tex->isGlowing()) // recheck the current animation frame. { ret = true; tex->GetGlowColor(bottomglowcolor); - bottomglowcolor[3] = (float)tex->GlowHeight; + bottomglowcolor[3] = (float)tex->GetGlowHeight(); } } } @@ -1397,8 +1397,8 @@ void P_ReplaceTextures(const char *fromname, const char *toname, int flags) if ((flags ^ (NOT_BOTTOM | NOT_MIDDLE | NOT_TOP)) != 0) { - picnum1 = TexMan.GetTexture(fromname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture(toname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + picnum1 = TexMan.GetTextureID(fromname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTextureID(toname, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); for (auto &side : level.sides) { @@ -1414,8 +1414,8 @@ void P_ReplaceTextures(const char *fromname, const char *toname, int flags) } if ((flags ^ (NOT_FLOOR | NOT_CEILING)) != 0) { - picnum1 = TexMan.GetTexture(fromname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); - picnum2 = TexMan.GetTexture(toname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + picnum1 = TexMan.GetTextureID(fromname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); + picnum2 = TexMan.GetTextureID(toname, ETextureType::Flat, FTextureManager::TEXMAN_Overridable); for (auto &sec : level.sectors) { diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b7489bf92..16f609152 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -3408,6 +3408,45 @@ void P_GetPolySpots (MapData * map, TArray &spots, TAr //=========================================================================== void hw_PrecacheTexture(uint8_t *texhitlist, TMap &actorhitlist); +static void AddToList(uint8_t *hitlist, FTextureID texid, int bitmask) +{ + if (hitlist[texid.GetIndex()] & bitmask) return; // already done, no need to process everything again. + hitlist[texid.GetIndex()] |= (uint8_t)bitmask; + + for (auto anim : TexMan.mAnimations) + { + if (texid == anim->BasePic || (!anim->bDiscrete && anim->BasePic < texid && texid < anim->BasePic + anim->NumFrames)) + { + for (int i = anim->BasePic.GetIndex(); i < anim->BasePic.GetIndex() + anim->NumFrames; i++) + { + hitlist[i] |= (uint8_t)bitmask; + } + } + } + + auto switchdef = TexMan.FindSwitch(texid); + if (switchdef) + { + for (int i = 0; i < switchdef->NumFrames; i++) + { + hitlist[switchdef->frames[i].Texture.GetIndex()] |= (uint8_t)bitmask; + } + for (int i = 0; i < switchdef->PairDef->NumFrames; i++) + { + hitlist[switchdef->frames[i].Texture.GetIndex()] |= (uint8_t)bitmask; + } + } + + auto adoor = TexMan.FindAnimatedDoor(texid); + if (adoor) + { + for (int i = 0; i < adoor->NumTextureFrames; i++) + { + hitlist[adoor->TextureFrames[i].GetIndex()] |= (uint8_t)bitmask; + } + } +} + static void P_PrecacheLevel() { int i; @@ -3443,15 +3482,15 @@ static void P_PrecacheLevel() for (i = level.sectors.Size() - 1; i >= 0; i--) { - hitlist[level.sectors[i].GetTexture(sector_t::floor).GetIndex()] |= FTextureManager::HIT_Flat; - hitlist[level.sectors[i].GetTexture(sector_t::ceiling).GetIndex()] |= FTextureManager::HIT_Flat; + AddToList(hitlist, level.sectors[i].GetTexture(sector_t::floor), FTextureManager::HIT_Flat); + AddToList(hitlist, level.sectors[i].GetTexture(sector_t::ceiling), FTextureManager::HIT_Flat); } for (i = level.sides.Size() - 1; i >= 0; i--) { - hitlist[level.sides[i].GetTexture(side_t::top).GetIndex()] |= FTextureManager::HIT_Wall; - hitlist[level.sides[i].GetTexture(side_t::mid).GetIndex()] |= FTextureManager::HIT_Wall; - hitlist[level.sides[i].GetTexture(side_t::bottom).GetIndex()] |= FTextureManager::HIT_Wall; + AddToList(hitlist, level.sides[i].GetTexture(side_t::top), FTextureManager::HIT_Wall); + AddToList(hitlist, level.sides[i].GetTexture(side_t::mid), FTextureManager::HIT_Wall); + AddToList(hitlist, level.sides[i].GetTexture(side_t::bottom), FTextureManager::HIT_Wall); } // Sky texture is always present. @@ -3463,22 +3502,22 @@ static void P_PrecacheLevel() if (sky1texture.isValid()) { - hitlist[sky1texture.GetIndex()] |= FTextureManager::HIT_Sky; + AddToList(hitlist, sky1texture, FTextureManager::HIT_Sky); } if (sky2texture.isValid()) { - hitlist[sky2texture.GetIndex()] |= FTextureManager::HIT_Sky; + AddToList(hitlist, sky2texture, FTextureManager::HIT_Sky); } for (auto n : gameinfo.PrecachedTextures) { FTextureID tex = TexMan.CheckForTexture(n, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); - if (tex.Exists()) hitlist[tex.GetIndex()] |= FTextureManager::HIT_Wall; + if (tex.Exists()) AddToList(hitlist, tex, FTextureManager::HIT_Wall); } for (unsigned i = 0; i < level.info->PrecacheTextures.Size(); i++) { FTextureID tex = TexMan.CheckForTexture(level.info->PrecacheTextures[i], ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst); - if (tex.Exists()) hitlist[tex.GetIndex()] |= FTextureManager::HIT_Wall; + if (tex.Exists()) AddToList(hitlist, tex, FTextureManager::HIT_Wall); } // This is just a temporary solution, until the hardware renderer's texture manager is in a better state. @@ -3516,7 +3555,6 @@ void P_FreeLevelData () MapThingsUserDataIndex.Clear(); MapThingsUserData.Clear(); linemap.Clear(); - FCanvasTextureInfo::EmptyList(); R_FreePastViewers(); P_ClearUDMFKeys(); @@ -3555,6 +3593,7 @@ void P_FreeLevelData () FBehavior::StaticUnloadModules (); + level.canvasTextureInfo.EmptyList(); level.sections.Clear(); level.segs.Clear(); level.sectors.Clear(); diff --git a/src/p_things.cpp b/src/p_things.cpp index f6d5139f6..9728c691e 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -572,23 +572,22 @@ static int SpawnableSort(const void *a, const void *b) static void DumpClassMap(FClassMap &themap) { FClassMap::Iterator it(themap); - FClassMap::Pair *pair, **allpairs; + FClassMap::Pair *pair; + TArray allpairs(themap.CountUsed(), true); int i = 0; // Sort into numerical order, since their arrangement in the map can // be in an unspecified order. - allpairs = new FClassMap::Pair *[themap.CountUsed()]; while (it.NextPair(pair)) { allpairs[i++] = pair; } - qsort(allpairs, i, sizeof(*allpairs), SpawnableSort); + qsort(allpairs.Data(), i, sizeof(allpairs[0]), SpawnableSort); for (int j = 0; j < i; ++j) { pair = allpairs[j]; Printf ("%d %s\n", pair->Key, pair->Value->TypeName.GetChars()); } - delete[] allpairs; } CCMD(dumpspawnables) diff --git a/src/p_user.cpp b/src/p_user.cpp index 4bae6ee5e..6077d597c 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -429,12 +429,8 @@ void player_t::SetLogNumber (int num) } else { - int length=Wads.LumpLength(lumpnum); - char *data= new char[length+1]; - Wads.ReadLump (lumpnum, data); - data[length]=0; - SetLogText (data); - delete[] data; + auto lump = Wads.ReadLump(lumpnum); + SetLogText (lump.GetString()); } } diff --git a/src/polyrenderer/drawers/poly_draw_args.cpp b/src/polyrenderer/drawers/poly_draw_args.cpp index 158c24dcf..bb31c1515 100644 --- a/src/polyrenderer/drawers/poly_draw_args.cpp +++ b/src/polyrenderer/drawers/poly_draw_args.cpp @@ -47,11 +47,11 @@ void PolyDrawArgs::SetTexture(const uint8_t *texels, int width, int height) mTranslation = nullptr; } -void PolyDrawArgs::SetTexture(FTexture *texture, FRenderStyle style) +void PolyDrawArgs::SetTexture(FSoftwareTexture *texture, FRenderStyle style) { mTexture = texture; - mTextureWidth = texture->GetWidth(); - mTextureHeight = texture->GetHeight(); + mTextureWidth = texture->GetPhysicalWidth(); + mTextureHeight = texture->GetPhysicalHeight(); if (PolyTriangleDrawer::IsBgra()) mTexturePixels = (const uint8_t *)texture->GetPixelsBgra(); else @@ -59,7 +59,7 @@ void PolyDrawArgs::SetTexture(FTexture *texture, FRenderStyle style) mTranslation = nullptr; } -void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, FRenderStyle style) +void PolyDrawArgs::SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style) { // Alphatexture overrides translations. if (translationID != 0xffffffff && translationID != 0 && !(style.Flags & STYLEF_RedIsAlpha)) @@ -73,8 +73,8 @@ void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, FRender mTranslation = table->Remap; mTexture = texture; - mTextureWidth = texture->GetWidth(); - mTextureHeight = texture->GetHeight(); + mTextureWidth = texture->GetPhysicalWidth(); + mTextureHeight = texture->GetPhysicalHeight(); mTexturePixels = texture->GetPixels(style); return; } @@ -83,8 +83,8 @@ void PolyDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, FRender if (style.Flags & STYLEF_RedIsAlpha) { mTexture = texture; - mTextureWidth = texture->GetWidth(); - mTextureHeight = texture->GetHeight(); + mTextureWidth = texture->GetPhysicalWidth(); + mTextureHeight = texture->GetPhysicalHeight(); mTexturePixels = texture->GetPixels(style); } else @@ -140,7 +140,7 @@ void PolyDrawArgs::SetColor(uint32_t bgra, uint8_t palindex) } } -void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright) +void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *tex, bool fullbright) { SetTexture(tex, translationID, renderstyle); SetColor(0xff000000 | fillcolor, fillcolor >> 24); @@ -203,7 +203,7 @@ void PolyDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint3 ///////////////////////////////////////////////////////////////////////////// -void RectDrawArgs::SetTexture(FTexture *texture, FRenderStyle style) +void RectDrawArgs::SetTexture(FSoftwareTexture *texture, FRenderStyle style) { mTexture = texture; mTextureWidth = texture->GetWidth(); @@ -215,7 +215,7 @@ void RectDrawArgs::SetTexture(FTexture *texture, FRenderStyle style) mTranslation = nullptr; } -void RectDrawArgs::SetTexture(FTexture *texture, uint32_t translationID, FRenderStyle style) +void RectDrawArgs::SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style) { // Alphatexture overrides translations. if (translationID != 0xffffffff && translationID != 0 && !(style.Flags & STYLEF_RedIsAlpha)) @@ -291,7 +291,7 @@ void RectDrawArgs::Draw(PolyRenderThread *thread, double x0, double x1, double y thread->DrawQueue->Push(*this); } -void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *tex, bool fullbright) +void RectDrawArgs::SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *tex, bool fullbright) { SetTexture(tex, translationID, renderstyle); SetColor(0xff000000 | fillcolor, fillcolor >> 24); diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index 8450bd655..b40e209a2 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -27,7 +27,7 @@ #include "screen_triangle.h" class PolyRenderThread; -class FTexture; +class FSoftwareTexture; class Mat4f; enum class PolyDrawMode @@ -67,8 +67,8 @@ class PolyDrawArgs public: void SetClipPlane(int index, const PolyClipPlane &plane) { mClipPlane[index] = plane; } void SetTexture(const uint8_t *texels, int width, int height); - void SetTexture(FTexture *texture, FRenderStyle style); - void SetTexture(FTexture *texture, uint32_t translationID, FRenderStyle style); + void SetTexture(FSoftwareTexture *texture, FRenderStyle style); + void SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style); void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed); void SetDepthTest(bool enable) { mDepthTest = enable; } void SetStencilTestValue(uint8_t stencilTestValue) { mStencilTestValue = stencilTestValue; } @@ -76,7 +76,7 @@ public: void SetWriteStencil(bool enable, uint8_t stencilWriteValue = 0) { mWriteStencil = enable; mStencilWriteValue = stencilWriteValue; } void SetWriteDepth(bool enable) { mWriteDepth = enable; } void SetStyle(TriBlendMode blendmode, double alpha = 1.0) { mBlendMode = blendmode; mAlpha = (uint32_t)(alpha * 256.0 + 0.5); } - void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright); + void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *texture, bool fullbright); void SetColor(uint32_t bgra, uint8_t palindex); void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; } void SetDynLightColor(uint32_t color) { mDynLightColor = color; } @@ -85,7 +85,7 @@ public: bool WriteColor() const { return mWriteColor; } - FTexture *Texture() const { return mTexture; } + FSoftwareTexture *Texture() const { return mTexture; } const uint8_t *TexturePixels() const { return mTexturePixels; } int TextureWidth() const { return mTextureWidth; } int TextureHeight() const { return mTextureHeight; } @@ -131,7 +131,7 @@ private: bool mWriteStencil = true; bool mWriteColor = true; bool mWriteDepth = true; - FTexture *mTexture = nullptr; + FSoftwareTexture *mTexture = nullptr; const uint8_t *mTexturePixels = nullptr; int mTextureWidth = 0; int mTextureHeight = 0; @@ -166,15 +166,15 @@ private: class RectDrawArgs { public: - void SetTexture(FTexture *texture, FRenderStyle style); - void SetTexture(FTexture *texture, uint32_t translationID, FRenderStyle style); + void SetTexture(FSoftwareTexture *texture, FRenderStyle style); + void SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style); void SetLight(FSWColormap *basecolormap, uint32_t lightlevel); void SetStyle(TriBlendMode blendmode, double alpha = 1.0) { mBlendMode = blendmode; mAlpha = (uint32_t)(alpha * 256.0 + 0.5); } - void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright); + void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FSoftwareTexture *texture, bool fullbright); void SetColor(uint32_t bgra, uint8_t palindex); void Draw(PolyRenderThread *thread, double x0, double x1, double y0, double y1, double u0, double u1, double v0, double v1); - FTexture *Texture() const { return mTexture; } + FSoftwareTexture *Texture() const { return mTexture; } const uint8_t *TexturePixels() const { return mTexturePixels; } int TextureWidth() const { return mTextureWidth; } int TextureHeight() const { return mTextureHeight; } @@ -207,7 +207,7 @@ public: float V1() const { return mV1; } private: - FTexture *mTexture = nullptr; + FSoftwareTexture *mTexture = nullptr; const uint8_t *mTexturePixels = nullptr; int mTextureWidth = 0; int mTextureHeight = 0; diff --git a/src/polyrenderer/poly_all.cpp b/src/polyrenderer/poly_all.cpp index 1a777fbb1..29b3c7fe1 100644 --- a/src/polyrenderer/poly_all.cpp +++ b/src/polyrenderer/poly_all.cpp @@ -1,3 +1,4 @@ +#include "../swrenderer/textures/r_swtexture.h" #include "poly_renderer.cpp" #include "poly_renderthread.cpp" #include "drawers/poly_buffer.cpp" diff --git a/src/polyrenderer/poly_renderthread.cpp b/src/polyrenderer/poly_renderthread.cpp index 22900c17a..3293014f4 100644 --- a/src/polyrenderer/poly_renderthread.cpp +++ b/src/polyrenderer/poly_renderthread.cpp @@ -75,7 +75,7 @@ void PolyRenderThread::FlushDrawQueue() } static std::mutex loadmutex; -void PolyRenderThread::PrepareTexture(FTexture *texture, FRenderStyle style) +void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) { if (texture == nullptr) return; @@ -90,14 +90,18 @@ void PolyRenderThread::PrepareTexture(FTexture *texture, FRenderStyle style) std::unique_lock lock(loadmutex); - texture->GetPixels(style); - const FTexture::Span *spans; - texture->GetColumn(style, 0, &spans); + const FSoftwareTextureSpan *spans; if (PolyRenderer::Instance()->RenderTarget->IsBgra()) { texture->GetPixelsBgra(); texture->GetColumnBgra(0, &spans); } + else + { + bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); + texture->GetPixels(alpha); + texture->GetColumn(alpha, 0, &spans); + } } static std::mutex polyobjmutex; diff --git a/src/polyrenderer/poly_renderthread.h b/src/polyrenderer/poly_renderthread.h index b9a6b32db..69e2e67e8 100644 --- a/src/polyrenderer/poly_renderthread.h +++ b/src/polyrenderer/poly_renderthread.h @@ -57,7 +57,7 @@ public: TArray AddedLightsArray; // Make sure texture can accessed safely - void PrepareTexture(FTexture *texture, FRenderStyle style); + void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style); // Setup poly object in a threadsafe manner void PreparePolyObject(subsector_t *sub); diff --git a/src/polyrenderer/scene/poly_decal.cpp b/src/polyrenderer/scene/poly_decal.cpp index f15c15ba3..54ba76955 100644 --- a/src/polyrenderer/scene/poly_decal.cpp +++ b/src/polyrenderer/scene/poly_decal.cpp @@ -49,9 +49,11 @@ void RenderPolyDecal::Render(PolyRenderThread *thread, DBaseDecal *decal, const if (decal->RenderFlags & RF_INVISIBLE || !viewactive || !decal->PicNum.isValid()) return; - FTexture *tex = TexMan(decal->PicNum, true); - if (tex == nullptr || tex->UseType == ETextureType::Null) + FTexture *ttex = TexMan.GetPalettedTexture(decal->PicNum, true); + if (ttex == nullptr || !ttex->isValid()) return; + + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); sector_t *front, *back; GetDecalSectors(decal, line, &front, &back); @@ -73,16 +75,16 @@ void RenderPolyDecal::Render(PolyRenderThread *thread, DBaseDecal *decal, const bool flipTextureX = (decal->RenderFlags & RF_XFLIP) == RF_XFLIP; double u_left = flipTextureX ? 1.0 : 0.0; - double u_right = flipTextureX ? 1.0 - tex->Scale.X : tex->Scale.X; + double u_right = flipTextureX ? 1.0 - tex->GetScale().X : tex->GetScale().X; double u_unit = (u_right - u_left) / (edge_left + edge_right); double zpos = GetDecalZ(decal, line, front, back); - double spriteHeight = decal->ScaleY / tex->Scale.Y * tex->GetHeight(); + double spriteHeight = decal->ScaleY / tex->GetScale().Y * tex->GetHeight(); double ztop = zpos + spriteHeight - spriteHeight * 0.5; double zbottom = zpos - spriteHeight * 0.5; double v_top = 0.0; - double v_bottom = tex->Scale.Y; + double v_bottom = tex->GetScale().Y; double v_unit = (v_bottom - v_top) / (zbottom - ztop); // Clip decal to wall part @@ -156,25 +158,25 @@ void RenderPolyDecal::Render(PolyRenderThread *thread, DBaseDecal *decal, const vertices[0].z = (float)ztop; vertices[0].w = 1.0f; vertices[0].u = (float)u_left; - vertices[0].v = (float)v_top; + vertices[0].v = 1.0f - (float)v_top; vertices[1].x = (float)decal_right.X; vertices[1].y = (float)decal_right.Y; vertices[1].z = (float)ztop; vertices[1].w = 1.0f; vertices[1].u = (float)u_right; - vertices[1].v = (float)v_top; + vertices[1].v = 1.0f - (float)v_top; vertices[2].x = (float)decal_right.X; vertices[2].y = (float)decal_right.Y; vertices[2].z = (float)zbottom; vertices[2].w = 1.0f; vertices[2].u = (float)u_right; - vertices[2].v = (float)v_bottom; + vertices[2].v = 1.0f - (float)v_bottom; vertices[3].x = (float)decal_left.X; vertices[3].y = (float)decal_left.Y; vertices[3].z = (float)zbottom; vertices[3].w = 1.0f; vertices[3].u = (float)u_left; - vertices[3].v = (float)v_bottom; + vertices[3].v = 1.0f - (float)v_bottom; // Light calculations diff --git a/src/polyrenderer/scene/poly_model.cpp b/src/polyrenderer/scene/poly_model.cpp index cba1c991b..a2f7875cb 100644 --- a/src/polyrenderer/scene/poly_model.cpp +++ b/src/polyrenderer/scene/poly_model.cpp @@ -66,8 +66,8 @@ static bool isBright(DPSprite *psp) FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); if (lump.isValid()) { - FTexture * tex = TexMan(lump); - if (tex) disablefullbright = tex->bDisableFullbright; + FTexture * tex = TexMan.GetPalettedTexture(lump, true); + if (tex) disablefullbright = tex->isFullbrightDisabled(); } return psp->GetState()->GetFullbright() && !disablefullbright; } @@ -238,7 +238,7 @@ void PolyModelRenderer::SetInterpolation(double interpolation) void PolyModelRenderer::SetMaterial(FTexture *skin, bool clampNoFilter, int translation) { - SkinTexture = skin; + SkinTexture = skin? skin->GetSoftwareTexture() : nullptr; } void PolyModelRenderer::SetTransform() diff --git a/src/polyrenderer/scene/poly_model.h b/src/polyrenderer/scene/poly_model.h index ff7269e18..bdf6c9423 100644 --- a/src/polyrenderer/scene/poly_model.h +++ b/src/polyrenderer/scene/poly_model.h @@ -65,7 +65,7 @@ public: uint32_t Translation; Mat4f ObjectToWorld; - FTexture *SkinTexture = nullptr; + FSoftwareTexture *SkinTexture = nullptr; unsigned int *IndexBuffer = nullptr; FModelVertex *VertexBuffer = nullptr; float InterpolationFactor = 0.0; diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index 18d24cfd7..926092f5c 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -66,11 +66,11 @@ void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const PolyTransferH FTextureID picnum = fakeflat.FrontSector->GetTexture(ceiling ? sector_t::ceiling : sector_t::floor); if (picnum != skyflatnum) { - FTexture *tex = TexMan(picnum); - if (!tex || tex->UseType == ETextureType::Null) + FTexture *tex = TexMan.GetPalettedTexture(picnum, true); + if (!tex || !tex->isValid()) return; - PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex); + PolyPlaneUVTransform transform = PolyPlaneUVTransform(ceiling ? fakeflat.FrontSector->planes[sector_t::ceiling].xform : fakeflat.FrontSector->planes[sector_t::floor].xform, tex->GetSoftwareTexture()); TriVertex *vertices = CreatePlaneVertices(thread, fakeflat.Subsector, transform, ceiling ? fakeflat.FrontSector->ceilingplane : fakeflat.FrontSector->floorplane); PolyDrawArgs args; @@ -78,7 +78,7 @@ void RenderPolyPlane::RenderNormal(PolyRenderThread *thread, const PolyTransferH SetDynLights(thread, args, fakeflat.Subsector, ceiling); args.SetStencilTestValue(stencilValue); args.SetWriteStencil(true, stencilValue + 1); - args.SetTexture(tex, DefaultRenderStyle()); + args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle()); args.SetStyle(TriBlendMode::Opaque); PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, fakeflat.Subsector->numlines, PolyDrawMode::TriangleFan); } @@ -389,12 +389,12 @@ TriVertex *RenderPolyPlane::CreateSkyPlaneVertices(PolyRenderThread *thread, sub ///////////////////////////////////////////////////////////////////////////// -PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FTexture *tex) +PolyPlaneUVTransform::PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex) { if (tex) { - xscale = (float)(transform.xScale * tex->Scale.X / tex->GetWidth()); - yscale = (float)(transform.yScale * tex->Scale.Y / tex->GetHeight()); + xscale = (float)(transform.xScale * tex->GetScale().X / tex->GetWidth()); + yscale = (float)(transform.yScale * tex->GetScale().Y / tex->GetHeight()); double planeang = (transform.Angle + transform.baseAngle).Radians(); cosine = (float)cos(planeang); @@ -510,8 +510,8 @@ void Render3DFloorPlane::RenderPlanes(PolyRenderThread *thread, subsector_t *sub void Render3DFloorPlane::Render(PolyRenderThread *thread) { FTextureID picnum = ceiling ? *fakeFloor->bottom.texture : *fakeFloor->top.texture; - FTexture *tex = TexMan(picnum); - if (tex->UseType == ETextureType::Null) + auto tex = TexMan.GetPalettedTexture(picnum, true); + if (!tex->isValid()) return; PolyCameraLight *cameraLight = PolyCameraLight::Instance(); @@ -528,7 +528,7 @@ void Render3DFloorPlane::Render(PolyRenderThread *thread) int actualextralight = foggy ? 0 : PolyRenderer::Instance()->Viewpoint.extralight << 4; lightlevel = clamp(lightlevel + actualextralight, 0, 255); - PolyPlaneUVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex); + PolyPlaneUVTransform xform(ceiling ? fakeFloor->top.model->planes[sector_t::ceiling].xform : fakeFloor->top.model->planes[sector_t::floor].xform, tex->GetSoftwareTexture()); TriVertex *vertices = thread->FrameMemory->AllocMemory(sub->numlines); if (ceiling) @@ -562,6 +562,6 @@ void Render3DFloorPlane::Render(PolyRenderThread *thread) } args.SetStencilTestValue(stencilValue); args.SetWriteStencil(true, stencilValue + 1); - args.SetTexture(tex, DefaultRenderStyle()); + args.SetTexture(tex->GetSoftwareTexture(), DefaultRenderStyle()); PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, vertices, sub->numlines, PolyDrawMode::TriangleFan); } diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h index 96c115c19..74c6c7956 100644 --- a/src/polyrenderer/scene/poly_plane.h +++ b/src/polyrenderer/scene/poly_plane.h @@ -29,7 +29,7 @@ class PolyDrawSectorPortal; class PolyPlaneUVTransform { public: - PolyPlaneUVTransform(const FTransform &transform, FTexture *tex); + PolyPlaneUVTransform(const FTransform &transform, FSoftwareTexture *tex); TriVertex GetVertex(vertex_t *v1, double height) const { diff --git a/src/polyrenderer/scene/poly_playersprite.cpp b/src/polyrenderer/scene/poly_playersprite.cpp index ada83a747..93cfca926 100644 --- a/src/polyrenderer/scene/poly_playersprite.cpp +++ b/src/polyrenderer/scene/poly_playersprite.cpp @@ -162,7 +162,7 @@ void RenderPolyPlayerSprites::RenderRemainingSprites() { for (const PolyHWAccelPlayerSprite &sprite : AcceleratedSprites) { - screen->DrawTexture(sprite.pic, + screen->DrawTexture(sprite.pic->GetTexture(), viewwindowx + sprite.x1, viewwindowy + viewheight / 2 - sprite.texturemid * sprite.yscale - 0.5, DTA_DestWidthF, FIXED2DBL(sprite.pic->GetWidth() * sprite.xscale), @@ -198,7 +198,8 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p spriteframe_t* sprframe; FTextureID picnum; uint16_t flip; - FTexture* tex; + FTexture* ttex; + FSoftwareTexture* tex; bool noaccel; double alpha = owner->Alpha; @@ -226,10 +227,12 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan(picnum); + ttex = TexMan.GetTexture(picnum); - if (tex->UseType == ETextureType::Null) + if (!ttex->isValid()) return; + + tex = ttex->GetSoftwareTexture(); if (pspr->firstTic) { // Can't interpolate the first tic. @@ -290,7 +293,7 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p vis.renderflags = owner->renderflags; - vis.texturemid = (BASEYCENTER - sy) * tex->Scale.Y + tex->GetTopOffsetPo(); + vis.texturemid = (BASEYCENTER - sy) * tex->GetScale().Y + tex->GetTopOffsetPo(); if (viewpoint.camera->player && (renderToCanvas || viewheight == renderTarget->GetHeight() || @@ -304,20 +307,20 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p } vis.x1 = x1 < 0 ? 0 : x1; vis.x2 = x2 >= viewwidth ? viewwidth : x2; - vis.xscale = FLOAT2FIXED(pspritexscale / tex->Scale.X); - vis.yscale = float(pspriteyscale / tex->Scale.Y); + vis.xscale = FLOAT2FIXED(pspritexscale / tex->GetScale().X); + vis.yscale = float(pspriteyscale / tex->GetScale().Y); vis.pic = tex; // If flip is used, provided that it's not already flipped (that would just invert itself) // (It's an XOR...) if (!(flip) != !(pspr->Flags & PSPF_FLIP)) { - vis.xiscale = -FLOAT2FIXED(pspritexiscale * tex->Scale.X); + vis.xiscale = -FLOAT2FIXED(pspritexiscale * tex->GetScale().X); vis.startfrac = (tex->GetWidth() << FRACBITS) - 1; } else { - vis.xiscale = FLOAT2FIXED(pspritexiscale * tex->Scale.X); + vis.xiscale = FLOAT2FIXED(pspritexiscale * tex->GetScale().X); vis.startfrac = 0; } @@ -383,6 +386,8 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p { noaccel = true; } +#if 0 + // The HW 2D drawer should be able to handle this without problems // If the main colormap has fixed lights, and this sprite is being drawn with that // colormap, disable acceleration so that the lights can remain fixed. PolyCameraLight *cameraLight = PolyCameraLight::Instance(); @@ -392,6 +397,7 @@ void RenderPolyPlayerSprites::RenderSprite(PolyRenderThread *thread, DPSprite *p { noaccel = true; } +#endif } else { diff --git a/src/polyrenderer/scene/poly_playersprite.h b/src/polyrenderer/scene/poly_playersprite.h index 010c1c7be..cba6cda52 100644 --- a/src/polyrenderer/scene/poly_playersprite.h +++ b/src/polyrenderer/scene/poly_playersprite.h @@ -47,7 +47,7 @@ public: fixed_t xscale = 0; float yscale = 0.0f; - FTexture *pic = nullptr; + FSoftwareTexture *pic = nullptr; fixed_t xiscale = 0; fixed_t startfrac = 0; @@ -67,7 +67,7 @@ public: class PolyHWAccelPlayerSprite { public: - FTexture *pic = nullptr; + FSoftwareTexture *pic = nullptr; double texturemid = 0.0; float yscale = 0.0f; fixed_t xscale = 0; diff --git a/src/polyrenderer/scene/poly_scene.cpp b/src/polyrenderer/scene/poly_scene.cpp index 2f5e36702..f92c73762 100644 --- a/src/polyrenderer/scene/poly_scene.cpp +++ b/src/polyrenderer/scene/poly_scene.cpp @@ -189,7 +189,7 @@ void RenderPolyScene::RenderSubsector(PolyRenderThread *thread, subsector_t *sub int subsectorIndex = sub->Index(); for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext) { - particle_t *particle = Particles + i; + particle_t *particle = &Particles[i]; thread->TranslucentObjects.push_back(thread->FrameMemory->NewObject(particle, sub, subsectorDepth, CurrentViewpoint->StencilValue)); } } diff --git a/src/polyrenderer/scene/poly_sky.cpp b/src/polyrenderer/scene/poly_sky.cpp index 59157bf7b..3e7cd072c 100644 --- a/src/polyrenderer/scene/poly_sky.cpp +++ b/src/polyrenderer/scene/poly_sky.cpp @@ -32,6 +32,11 @@ EXTERN_CVAR(Float, skyoffset) +extern double skytexturemid; +extern float skyiscale; +extern double skyscale; +extern fixed_t sky1cyl, sky2cyl; + PolySkyDome::PolySkyDome() { @@ -63,7 +68,7 @@ void PolySkyDome::Render(PolyRenderThread *thread, const Mat4f &worldToView, con float offsetBaseV = 0.25f; float scaleFrontU = frameSetup.frontcyl / (float)frameSetup.frontskytex->GetWidth(); - float scaleFrontV = (float)frameSetup.frontskytex->Scale.Y * scaleBaseV; + float scaleFrontV = (float)frameSetup.frontskytex->GetScale().Y * scaleBaseV; float offsetFrontU = (float)((frameSetup.frontpos / 65536.0 + frameSetup.frontcyl / 2) / frameSetup.frontskytex->GetWidth()); float offsetFrontV = (float)((frameSetup.skymid / frameSetup.frontskytex->GetHeight() + offsetBaseV) * scaleBaseV); @@ -115,7 +120,7 @@ void PolySkyDome::RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int ro PolyTriangleDrawer::DrawArray(thread->DrawQueue, args, &mVertices[mPrimStart[row]], mPrimStart[row + 1] - mPrimStart[row], PolyDrawMode::TriangleStrip); } -void PolySkyDome::RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap) +void PolySkyDome::RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap) { uint32_t solid = skytex->GetSkyCapColor(bottomCap); uint8_t palsolid = RGB32k.RGB[(RPART(solid) >> 3)][(GPART(solid) >> 3)][(BPART(solid) >> 3)]; @@ -214,7 +219,7 @@ Mat4f PolySkyDome::GLSkyMath() float x_offset = 0.0f; float y_offset = 0.0f; bool mirror = false; - FTexture *tex = mCurrentSetup.frontskytex; + FSoftwareTexture *tex = mCurrentSetup.frontskytex; int texh = 0; int texw = 0; @@ -231,7 +236,7 @@ Mat4f PolySkyDome::GLSkyMath() float yscale = 1.f; if (texh <= 128 && (level.flags & LEVEL_FORCETILEDSKY)) { - modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->SkyOffset + skyoffset)*skyoffsetfactor); + modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor); modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f); yscale = 240.f / texh; } @@ -249,12 +254,12 @@ Mat4f PolySkyDome::GLSkyMath() } else if (texh <= 240) { - modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (200 - texh + tex->SkyOffset + skyoffset)*skyoffsetfactor); + modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (200 - texh + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor); modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.f + ((texh - 200.f) / 200.f) * 1.17f); } else { - modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->SkyOffset + skyoffset)*skyoffsetfactor); + modelMatrix = modelMatrix * Mat4f::Translate(0.f, 0.f, (-40 + tex->GetSkyOffset() + skyoffset)*skyoffsetfactor); modelMatrix = modelMatrix * Mat4f::Scale(1.f, 1.f, 1.2f * 1.17f); yscale = 240.f / texh; } @@ -277,6 +282,14 @@ Mat4f PolySkyDome::GLSkyMath() ///////////////////////////////////////////////////////////////////////////// +static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true) +{ + auto tex = TexMan.GetPalettedTexture(texid, true); + if (tex == nullptr) return nullptr; + if (!allownull && !tex->isValid()) return nullptr; + return tex->GetSoftwareTexture(); +} + void PolySkySetup::Update() { FTextureID sky1tex, sky2tex; @@ -299,9 +312,9 @@ void PolySkySetup::Update() if (!(sectorSky & PL_SKYFLAT)) { // use sky1 sky1: - frontskytex = TexMan(sky1tex, true); + frontskytex = GetSWTex(sky1tex); if (level.flags & LEVEL_DOUBLESKY) - backskytex = TexMan(sky2tex, true); + backskytex = GetSWTex(sky2tex); else backskytex = nullptr; skyflip = false; @@ -312,7 +325,7 @@ void PolySkySetup::Update() } else if (sectorSky == PL_SKYFLAT) { // use sky2 - frontskytex = TexMan(sky2tex, true); + frontskytex = GetSWTex(sky2tex); backskytex = nullptr; frontcyl = sky2cyl; skyflip = false; @@ -338,8 +351,8 @@ void PolySkySetup::Update() pos = side_t::top; } - frontskytex = TexMan(s->GetTexture(pos), true); - if (frontskytex == nullptr || frontskytex->UseType == ETextureType::Null) + frontskytex = GetSWTex(s->GetTexture(pos), false); + if (frontskytex == nullptr) { // [RH] The blank texture: Use normal sky instead. goto sky1; } @@ -361,7 +374,7 @@ void PolySkySetup::Update() // allow old sky textures to be used. skyflip = l->args[2] ? false : true; - int frontxscale = int(frontskytex->Scale.X * 1024); + int frontxscale = int(frontskytex->GetScale().X * 1024); frontcyl = MAX(frontskytex->GetWidth(), frontxscale); } diff --git a/src/polyrenderer/scene/poly_sky.h b/src/polyrenderer/scene/poly_sky.h index 6c70edbb0..441086511 100644 --- a/src/polyrenderer/scene/poly_sky.h +++ b/src/polyrenderer/scene/poly_sky.h @@ -31,8 +31,8 @@ public: bool operator==(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) == 0; } bool operator!=(const PolySkySetup &that) const { return memcmp(this, &that, sizeof(PolySkySetup)) != 0; } - FTexture *frontskytex = nullptr; - FTexture *backskytex = nullptr; + FSoftwareTexture *frontskytex = nullptr; + FSoftwareTexture *backskytex = nullptr; bool skyflip = 0; int frontpos = 0; int backpos = 0; @@ -58,7 +58,7 @@ private: void CreateSkyHemisphere(bool zflip); void CreateDome(); void RenderRow(PolyRenderThread *thread, PolyDrawArgs &args, int row, uint32_t capcolor, uint8_t capcolorindex); - void RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FTexture *skytex, int row, bool bottomCap); + void RenderCapColorRow(PolyRenderThread *thread, PolyDrawArgs &args, FSoftwareTexture *skytex, int row, bool bottomCap); TriVertex SetVertexXYZ(float xx, float yy, float zz, float uu = 0, float vv = 0); diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index 086d9485f..be5b85f00 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -49,13 +49,13 @@ bool RenderPolySprite::GetLine(AActor *thing, DVector2 &left, DVector2 &right) DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); bool flipTextureX = false; - FTexture *tex = GetSpriteTexture(thing, flipTextureX); + FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX); if (tex == nullptr) return false; DVector2 spriteScale = thing->Scale; - double thingxscalemul = spriteScale.X / tex->Scale.X; - double thingyscalemul = spriteScale.Y / tex->Scale.Y; + double thingxscalemul = spriteScale.X / tex->GetScale().X; + double thingyscalemul = spriteScale.Y / tex->GetScale().Y; double spriteWidth = thingxscalemul * tex->GetWidth(); double spriteHeight = thingyscalemul * tex->GetHeight(); @@ -105,11 +105,11 @@ void RenderPolySprite::Render(PolyRenderThread *thread, AActor *thing, subsector posZ += thing->GetBobOffset(viewpoint.TicFrac); bool flipTextureX = false; - FTexture *tex = GetSpriteTexture(thing, flipTextureX); - if (tex == nullptr || tex->UseType == ETextureType::Null) + FSoftwareTexture *tex = GetSpriteTexture(thing, flipTextureX); + if (tex == nullptr) return; - double thingyscalemul = thing->Scale.Y / tex->Scale.Y; + double thingyscalemul = thing->Scale.Y / tex->GetScale().Y; double spriteHeight = thingyscalemul * tex->GetHeight(); posZ -= (tex->GetHeight() - tex->GetTopOffsetPo()) * thingyscalemul; @@ -302,7 +302,7 @@ bool RenderPolySprite::IsThingCulled(AActor *thing) return false; } -FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) +FSoftwareTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) { const auto &viewpoint = PolyRenderer::Instance()->Viewpoint; flipX = false; @@ -312,16 +312,17 @@ FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) if (thing->picnum.isValid()) { - FTexture *tex = TexMan(thing->picnum); - if (tex->UseType == ETextureType::Null) + FTexture *ttex = TexMan.GetPalettedTexture(thing->picnum, true); + if (!ttex || !ttex->isValid()) { return nullptr; } + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); - if (tex->Rotations != 0xFFFF) + if (ttex->GetRotations() != 0xFFFF) { // choose a different rotation based on player view - spriteframe_t *sprframe = &SpriteFrames[tex->Rotations]; + spriteframe_t *sprframe = &SpriteFrames[ttex->GetRotations()]; DVector3 pos = thing->InterpolatedPosition(viewpoint.TicFrac); pos.Z += thing->GetBobOffset(viewpoint.TicFrac); DAngle ang = (pos - viewpoint.Pos).Angle(); @@ -335,7 +336,13 @@ FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) rot = (ang - thing->Angles.Yaw + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28; } flipX = (sprframe->Flip & (1 << rot)) != 0; - tex = TexMan[sprframe->Texture[rot]]; // Do not animate the rotation + ttex = TexMan.GetPalettedTexture(sprframe->Texture[rot], false); // Do not animate the rotation + tex = ttex->GetSoftwareTexture(); + if (!ttex || !ttex->isValid()) + { + return nullptr; + } + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); } return tex; } @@ -364,7 +371,7 @@ FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) DAngle sprangle = thing->GetSpriteAngle((pos - viewpoint.Pos).Angle(), viewpoint.TicFrac); FTextureID tex = sprdef->GetSpriteFrame(thing->frame, -1, sprangle, &flipX); if (!tex.isValid()) return nullptr; - return TexMan[tex]; + return TexMan.GetPalettedTexture(tex, false)->GetSoftwareTexture(); } } } diff --git a/src/polyrenderer/scene/poly_sprite.h b/src/polyrenderer/scene/poly_sprite.h index d036176d3..7997228d6 100644 --- a/src/polyrenderer/scene/poly_sprite.h +++ b/src/polyrenderer/scene/poly_sprite.h @@ -31,7 +31,7 @@ public: static bool GetLine(AActor *thing, DVector2 &left, DVector2 &right); static bool IsThingCulled(AActor *thing); - static FTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX); + static FSoftwareTexture *GetSpriteTexture(AActor *thing, /*out*/ bool &flipX); private: static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z); diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 3ba2e9f56..70472eef7 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -171,8 +171,8 @@ bool RenderPolyWall::RenderLine(PolyRenderThread *thread, seg_t *line, sector_t wall.Alpha = wall.Line->alpha; wall.FogBoundary = IsFogBoundary(frontsector, backsector); - FTexture *midtex = TexMan(line->sidedef->GetTexture(side_t::mid), true); - if ((midtex && midtex->UseType != ETextureType::Null) || wall.FogBoundary) + FTexture *midtex = TexMan.GetPalettedTexture(line->sidedef->GetTexture(side_t::mid), true); + if ((midtex && midtex->isValid()) || wall.FogBoundary) translucentWallsOutput.push_back(thread->FrameMemory->NewObject(wall)); if (polyportal) @@ -526,10 +526,10 @@ void RenderPolyWall::ClampHeight(TriVertex &v1, TriVertex &v2) v2.v = texv1 * inv_t2 + texv2 * t2; } -FTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, side_t::ETexpart texpart) +FSoftwareTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, side_t::ETexpart texpart) { - FTexture *tex = TexMan(side->GetTexture(texpart), true); - if (tex == nullptr || tex->UseType == ETextureType::Null) + FTexture *tex = TexMan.GetPalettedTexture(side->GetTexture(texpart), true); + if (tex == nullptr || !tex->isValid()) { // Mapping error. Doom floodfills this with a plane. // This code doesn't do that, but at least it uses the "right" texture.. @@ -537,22 +537,22 @@ FTexture *RenderPolyWall::GetTexture(const line_t *line, const side_t *side, sid if (line && line->backsector && line->sidedef[0] == side) { if (texpart == side_t::top) - tex = TexMan(line->backsector->GetTexture(sector_t::ceiling), true); + tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::ceiling), true); else if (texpart == side_t::bottom) - tex = TexMan(line->backsector->GetTexture(sector_t::floor), true); + tex = TexMan.GetPalettedTexture(line->backsector->GetTexture(sector_t::floor), true); } if (line && line->backsector && line->sidedef[1] == side) { if (texpart == side_t::top) - tex = TexMan(line->frontsector->GetTexture(sector_t::ceiling), true); + tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::ceiling), true); else if (texpart == side_t::bottom) - tex = TexMan(line->frontsector->GetTexture(sector_t::floor), true); + tex = TexMan.GetPalettedTexture(line->frontsector->GetTexture(sector_t::floor), true); } - if (tex == nullptr || tex->UseType == ETextureType::Null) + if (tex == nullptr || !tex->isValid()) return nullptr; } - return tex; + return tex? tex->GetSoftwareTexture() : nullptr; } int RenderPolyWall::GetLightLevel() @@ -572,13 +572,13 @@ int RenderPolyWall::GetLightLevel() ///////////////////////////////////////////////////////////////////////////// -PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart wallpart) +PolyWallTextureCoordsU::PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *line, const side_t *side, side_t::ETexpart wallpart) { // Calculate the U texture coordinate for the line double lineu1 = side->GetTextureXOffset(wallpart); double lineu2 = side->GetTextureXOffset(wallpart) + line->sidedef[0]->TexelLength * side->GetTextureXScale(wallpart); - lineu1 *= tex->Scale.X / tex->GetWidth(); - lineu2 *= tex->Scale.X / tex->GetWidth(); + lineu1 *= tex->GetScale().X / tex->GetWidth(); + lineu2 *= tex->GetScale().X / tex->GetWidth(); // Calculate where we are on the lineseg double t1, t2; @@ -606,11 +606,11 @@ PolyWallTextureCoordsU::PolyWallTextureCoordsU(FTexture *tex, const seg_t *lines ///////////////////////////////////////////////////////////////////////////// -PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ) +PolyWallTextureCoordsV::PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ) { double yoffset = side->GetTextureYOffset(wallpart); - if (tex->bWorldPanning) - yoffset *= side->GetTextureYScale(wallpart) * tex->Scale.Y; + if (tex->useWorldPanning()) + yoffset *= side->GetTextureYScale(wallpart) * tex->GetScale().Y; switch (wallpart) { @@ -626,8 +626,8 @@ PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line break; } - v1 *= tex->Scale.Y / tex->GetHeight(); - v2 *= tex->Scale.Y / tex->GetHeight(); + v1 *= tex->GetScale().Y / tex->GetHeight(); + v2 *= tex->GetScale().Y / tex->GetHeight(); double texZHeight = (bottomTexZ - topTexZ); if (texZHeight > 0.0f || texZHeight < -0.0f) @@ -641,12 +641,12 @@ PolyWallTextureCoordsV::PolyWallTextureCoordsV(FTexture *tex, const line_t *line } } -void PolyWallTextureCoordsV::CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset) +void PolyWallTextureCoordsV::CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset) { bool pegged = (line->flags & ML_DONTPEGTOP) == 0; if (pegged) // bottom to top { - double texHeight = tex->GetHeight() / tex->Scale.Y; + double texHeight = tex->GetHeight() / tex->GetScale().Y; v1 = (topz - bottomz) * side->GetTextureYScale(side_t::top) - yoffset; v2 = -yoffset; v1 = texHeight - v1; @@ -659,7 +659,7 @@ void PolyWallTextureCoordsV::CalcVTopPart(FTexture *tex, const line_t *line, con } } -void PolyWallTextureCoordsV::CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset) +void PolyWallTextureCoordsV::CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset) { bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0; if (pegged) // top to bottom @@ -669,7 +669,7 @@ void PolyWallTextureCoordsV::CalcVMidPart(FTexture *tex, const line_t *line, con } else // bottom to top { - double texHeight = tex->GetHeight() / tex->Scale.Y; + double texHeight = tex->GetHeight() / tex->GetScale().Y; v1 = yoffset - (topz - bottomz) * side->GetTextureYScale(side_t::mid); v2 = yoffset; v1 = texHeight + v1; @@ -677,7 +677,7 @@ void PolyWallTextureCoordsV::CalcVMidPart(FTexture *tex, const line_t *line, con } } -void PolyWallTextureCoordsV::CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset) +void PolyWallTextureCoordsV::CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset) { bool pegged = (line->flags & ML_DONTPEGBOTTOM) == 0; if (pegged) // top to bottom diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h index 4bd5d6617..03850b0fc 100644 --- a/src/polyrenderer/scene/poly_wall.h +++ b/src/polyrenderer/scene/poly_wall.h @@ -48,7 +48,7 @@ public: const line_t *LineSegLine = nullptr; const line_t *Line = nullptr; const side_t *Side = nullptr; - FTexture *Texture = nullptr; + FSoftwareTexture *Texture = nullptr; side_t::ETexpart Wallpart = side_t::mid; double TopTexZ = 0.0; double BottomTexZ = 0.0; @@ -72,13 +72,13 @@ private: void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args); static bool IsFogBoundary(sector_t *front, sector_t *back); - static FTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart); + static FSoftwareTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart); }; class PolyWallTextureCoordsU { public: - PolyWallTextureCoordsU(FTexture *tex, const seg_t *lineseg, const line_t *linesegline, const side_t *side, side_t::ETexpart wallpart); + PolyWallTextureCoordsU(FSoftwareTexture *tex, const seg_t *lineseg, const line_t *linesegline, const side_t *side, side_t::ETexpart wallpart); double u1, u2; }; @@ -86,14 +86,14 @@ public: class PolyWallTextureCoordsV { public: - PolyWallTextureCoordsV(FTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ); + PolyWallTextureCoordsV(FSoftwareTexture *tex, const line_t *line, const side_t *side, side_t::ETexpart wallpart, double topz, double bottomz, double unpeggedceil, double topTexZ, double bottomTexZ); double v1, v2; private: - void CalcVTopPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset); - void CalcVMidPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset); - void CalcVBottomPart(FTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset); + void CalcVTopPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset); + void CalcVMidPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double yoffset); + void CalcVBottomPart(FSoftwareTexture *tex, const line_t *line, const side_t *side, double topz, double bottomz, double unpeggedceil, double yoffset); }; class PolyTranslucentWall : public PolyTranslucentObject diff --git a/src/polyrenderer/scene/poly_wallsprite.cpp b/src/polyrenderer/scene/poly_wallsprite.cpp index 7702dbd3d..4313b6863 100644 --- a/src/polyrenderer/scene/poly_wallsprite.cpp +++ b/src/polyrenderer/scene/poly_wallsprite.cpp @@ -40,13 +40,13 @@ void RenderPolyWallSprite::Render(PolyRenderThread *thread, AActor *thing, subse pos.Z += thing->GetBobOffset(viewpoint.TicFrac); bool flipTextureX = false; - FTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); - if (tex == nullptr || tex->UseType == ETextureType::Null) + FSoftwareTexture *tex = RenderPolySprite::GetSpriteTexture(thing, flipTextureX); + if (tex == nullptr) return; DVector2 spriteScale = thing->Scale; - double thingxscalemul = spriteScale.X / tex->Scale.X; - double thingyscalemul = spriteScale.Y / tex->Scale.Y; + double thingxscalemul = spriteScale.X / tex->GetScale().X; + double thingyscalemul = spriteScale.Y / tex->GetScale().Y; double spriteHeight = thingyscalemul * tex->GetHeight(); DAngle ang = thing->Angles.Yaw + 90; @@ -91,8 +91,8 @@ void RenderPolyWallSprite::Render(PolyRenderThread *thread, AActor *thing, subse vertices[i].y = (float)p.Y; vertices[i].z = (float)(pos.Z + spriteHeight * offsets[i].second); vertices[i].w = 1.0f; - vertices[i].u = (float)(offsets[i].first * tex->Scale.X); - vertices[i].v = (float)((1.0f - offsets[i].second) * tex->Scale.Y); + vertices[i].u = (float)(offsets[i].first * tex->GetScale().X); + vertices[i].v = (float)((1.0f - offsets[i].second) * tex->GetScale().Y); if (flipTextureX) vertices[i].u = 1.0f - vertices[i].u; } diff --git a/src/posix/cocoa/i_main_except.cpp b/src/posix/cocoa/i_main_except.cpp index a61eca2cc..afb0ba7e4 100644 --- a/src/posix/cocoa/i_main_except.cpp +++ b/src/posix/cocoa/i_main_except.cpp @@ -32,9 +32,11 @@ */ // Workaround for GCC Objective-C++ with C++ exceptions bug. -#include "doomerrors.h" #include +#include "doomerrors.h" +#include "vm.h" + // Import some functions from i_main.mm void call_terms(); void Mac_I_FatalError(const char* const message); @@ -50,10 +52,21 @@ void OriginalMainExcept(int argc, char** argv) { const char* const message = error.what(); - if (NULL != message) + if (strcmp(message, "NoRunExit")) { - if (strcmp(message, "NoRunExit")) fprintf(stderr, "%s\n", message); - Mac_I_FatalError(message); + if (CVMAbortException::stacktrace.IsNotEmpty()) + { + Printf("%s", CVMAbortException::stacktrace.GetChars()); + } + + if (batchrun) + { + Printf("%s\n", message); + } + else + { + Mac_I_FatalError(message); + } } exit(-1); diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index cb54f76c9..f5fd5b00b 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -647,18 +647,20 @@ CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINI // --------------------------------------------------------------------------- -bool I_SetCursor(FTexture* cursorpic) +bool I_SetCursor(FTexture *cursorpic) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSCursor* cursor = nil; - if (NULL != cursorpic && ETextureType::Null != cursorpic->UseType) + if (NULL != cursorpic && cursorpic->isValid()) { // Create bitmap image representation + + auto sbuffer = cursorpic->CreateTexBuffer(0); - const NSInteger imageWidth = cursorpic->GetWidth(); - const NSInteger imageHeight = cursorpic->GetHeight(); - const NSInteger imagePitch = imageWidth * 4; + const NSInteger imageWidth = sbuffer.mWidth; + const NSInteger imageHeight = sbuffer.mHeight; + const NSInteger imagePitch = sbuffer.mWidth * 4; NSBitmapImageRep* bitmapImageRep = [NSBitmapImageRep alloc]; [bitmapImageRep initWithBitmapDataPlanes:NULL @@ -675,20 +677,14 @@ bool I_SetCursor(FTexture* cursorpic) // Load bitmap data to representation uint8_t* buffer = [bitmapImageRep bitmapData]; - memset(buffer, 0, imagePitch * imageHeight); - - FBitmap bitmap(buffer, imagePitch, imageWidth, imageHeight); - cursorpic->CopyTrueColorPixels(&bitmap, 0, 0); + memcpy(buffer, sbuffer.mBuffer, imagePitch * imageHeight); // Swap red and blue components in each pixel for (size_t i = 0; i < size_t(imageWidth * imageHeight); ++i) { const size_t offset = i * 4; - - const uint8_t temp = buffer[offset ]; - buffer[offset ] = buffer[offset + 2]; - buffer[offset + 2] = temp; + std::swap(buffer[offset ], buffer[offset + 2]); } // Create image from representation and set it as cursor diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp index 1a895a676..8ad9c8b92 100644 --- a/src/posix/sdl/i_gui.cpp +++ b/src/posix/sdl/i_gui.cpp @@ -44,10 +44,11 @@ bool I_SetCursor(FTexture *cursorpic) static SDL_Cursor *cursor; static SDL_Surface *cursorSurface; - if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null) + if (cursorpic != NULL && cursorpic->isValid()) { + auto src = cursorpic->GetBgraBitmap(nullptr); // Must be no larger than 32x32. - if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32) + if (src.GetWidth() > 32 || src.GetHeight() > 32) { return false; } @@ -59,7 +60,7 @@ bool I_SetCursor(FTexture *cursorpic) uint8_t buffer[32*32*4]; memset(buffer, 0, 32*32*4); FBitmap bmp(buffer, 32*4, 32, 32); - cursorpic->CopyTrueColorPixels(&bmp, 0, 0); + bmp.Blit(0, 0, src); // expand to 32*32 memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4); SDL_UnlockSurface(cursorSurface); diff --git a/src/posix/sdl/i_main.cpp b/src/posix/sdl/i_main.cpp index 0c2389294..3d7912fc8 100644 --- a/src/posix/sdl/i_main.cpp +++ b/src/posix/sdl/i_main.cpp @@ -52,6 +52,7 @@ #include "cmdlib.h" #include "r_utility.h" #include "doomstat.h" +#include "vm.h" // MACROS ------------------------------------------------------------------ @@ -261,16 +262,31 @@ int main (int argc, char **argv) catch (std::exception &error) { I_ShutdownJoysticks(); - if (error.what () && strcmp(error.what(), "NoRunExit")) - fprintf (stderr, "%s\n", error.what ()); + const char *const message = error.what(); + + if (strcmp(message, "NoRunExit")) + { + if (CVMAbortException::stacktrace.IsNotEmpty()) + { + Printf("%s", CVMAbortException::stacktrace.GetChars()); + } + + if (batchrun) + { + Printf("%s\n", message); + } + else + { #ifdef __APPLE__ - Mac_I_FatalError(error.what()); + Mac_I_FatalError(message); #endif // __APPLE__ #ifdef __linux__ - Linux_I_FatalError(error.what()); + Linux_I_FatalError(message); #endif // __linux__ + } + } exit (-1); } diff --git a/src/posix/sdl/i_system.cpp b/src/posix/sdl/i_system.cpp index 9f4797926..8b73d2f14 100644 --- a/src/posix/sdl/i_system.cpp +++ b/src/posix/sdl/i_system.cpp @@ -240,30 +240,29 @@ void I_DebugPrint(const char *cp) { } -void I_PrintStr (const char *cp) +void I_PrintStr(const char *cp) { - // Strip out any color escape sequences before writing to the log file - char * copy = new char[strlen(cp)+1]; + // Strip out any color escape sequences before writing to debug output + TArray copy(strlen(cp) + 1, true); const char * srcp = cp; - char * dstp = copy; + char * dstp = copy.Data(); while (*srcp != 0) { - if (*srcp!=0x1c && *srcp!=0x1d && *srcp!=0x1e && *srcp!=0x1f) + if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f) { - *dstp++=*srcp++; + *dstp++ = *srcp++; } else { - if (srcp[1]!=0) srcp+=2; + if (srcp[1] != 0) srcp += 2; else break; } } - *dstp=0; + *dstp = 0; - fputs (copy, stdout); - delete [] copy; - fflush (stdout); + fputs(copy.Data(), stdout); + fflush(stdout); } int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad) diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index 0861a9773..8552ad77d 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -73,9 +73,7 @@ static void ParseVavoomSkybox() int facecount=0; int maplump = -1; bool error = false; - FSkyBox * sb = new FSkyBox; - sb->Name = sc.String; - sb->Name.ToUpper(); + FSkyBox * sb = new FSkyBox(sc.String); sb->fliptop = true; sc.MustGetStringName("{"); while (!sc.CheckString("}")) @@ -91,7 +89,7 @@ static void ParseVavoomSkybox() FTexture *tex = TexMan.FindTexture(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny); if (tex == NULL) { - sc.ScriptMessage("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, sb->Name.GetChars()); + sc.ScriptMessage("Texture '%s' not found in Vavoom skybox '%s'\n", sc.String, sb->GetName().GetChars()); error = true; } sb->faces[facecount] = tex; @@ -101,10 +99,13 @@ static void ParseVavoomSkybox() } if (facecount != 6) { - sc.ScriptError("%s: Skybox definition requires 6 faces", sb->Name.GetChars()); + sc.ScriptError("%s: Skybox definition requires 6 faces", sb->GetName().GetChars()); } sb->SetSize(); - if (!error) TexMan.AddTexture(sb); + if (!error) + { + TexMan.AddTexture(sb); + } } } @@ -966,8 +967,7 @@ class GLDefsParser sc.MustGetString(); - FSkyBox * sb = new FSkyBox; - sb->Name = sc.String; + FSkyBox * sb = new FSkyBox(sc.String); sb->Name.ToUpper(); if (sc.CheckString("fliptop")) { @@ -979,7 +979,7 @@ class GLDefsParser sc.MustGetString(); if (facecount<6) { - sb->faces[facecount] = TexMan[TexMan.GetTexture(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_Overridable)]; + sb->faces[facecount] = TexMan.GetTexture(TexMan.GetTextureID(sc.String, ETextureType::Wall, FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_Overridable)); } facecount++; } @@ -1010,7 +1010,7 @@ class GLDefsParser { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan[flump]; + FTexture *tex = TexMan.GetTexture(flump); if (tex) tex->bAutoGlowing = tex->bGlowing = tex->bFullbright = true; } } @@ -1021,7 +1021,7 @@ class GLDefsParser { sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Wall,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan[flump]; + FTexture *tex = TexMan.GetTexture(flump); if (tex) tex->bAutoGlowing = tex->bGlowing = tex->bFullbright = true; } } @@ -1030,7 +1030,7 @@ class GLDefsParser sc.SetCMode(true); sc.MustGetString(); FTextureID flump=TexMan.CheckForTexture(sc.String, ETextureType::Flat,FTextureManager::TEXMAN_TryAny); - FTexture *tex = TexMan[flump]; + FTexture *tex = TexMan.GetTexture(flump); sc.MustGetStringName(","); sc.MustGetString(); PalEntry color = V_GetColor(NULL, sc.String); @@ -1083,7 +1083,7 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); - FTexture *tex = TexMan[no]; + FTexture *tex = TexMan.GetTexture(no); sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1140,14 +1140,6 @@ class GLDefsParser if (bmtex != NULL) { - /* I do not think this is needed any longer - if (tex->bWarped != 0) - { - Printf("Cannot combine warping with brightmap on texture '%s'\n", tex->Name.GetChars()); - return; - } - */ - bmtex->bMasked = false; tex->Brightmap = bmtex; } @@ -1196,7 +1188,7 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable); - FTexture *tex = TexMan[no]; + FTexture *tex = TexMan.GetTexture(no); sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1367,7 +1359,7 @@ class GLDefsParser usershader.defines.AppendFormat("#define %s texture%d\n", texNameList[i].GetChars(), texNameIndex[i] + firstUserTexture); } - if (tex->bWarped != 0) + if (tex->isWarped() != 0) { Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars()); return; @@ -1499,7 +1491,7 @@ class GLDefsParser sc.MustGetString(); FTextureID no = TexMan.CheckForTexture(sc.String, type); - FTexture *tex = TexMan[no]; + FTexture *tex = TexMan.GetTexture(no); sc.MustGetToken('{'); while (!sc.CheckToken('}')) @@ -1608,7 +1600,7 @@ class GLDefsParser if (desc.shader.IsNotEmpty()) { - if (tex->bWarped != 0) + if (tex->isWarped() != 0) { Printf("Cannot combine warping with hardware shader on texture '%s'\n", tex->Name.GetChars()); return; @@ -1766,7 +1758,7 @@ void ParseGLDefs() { const char *defsLump = NULL; - LightDefaults.Clear(); + LightDefaults.DeleteAndClear(); //gl_DestroyUserShaders(); function says 'todo' switch (gameinfo.gametype) { diff --git a/src/r_data/models/models.cpp b/src/r_data/models/models.cpp index e8cb52678..6516ac5fd 100644 --- a/src/r_data/models/models.cpp +++ b/src/r_data/models/models.cpp @@ -268,7 +268,7 @@ void FModelRenderer::RenderFrameModels(const FSpriteModelFrame *smf, const FStat if (smf->modelIDs[i] != -1) { FModel * mdl = Models[smf->modelIDs[i]]; - FTexture *tex = smf->skinIDs[i].isValid() ? TexMan(smf->skinIDs[i]) : nullptr; + FTexture *tex = smf->skinIDs[i].isValid() ? TexMan.GetTexture(smf->skinIDs[i], true) : nullptr; mdl->BuildVertexBuffer(this); mdl->PushSpriteMDLFrame(smf, i); diff --git a/src/r_data/models/models.h b/src/r_data/models/models.h index a6b8bf65b..2f917e228 100644 --- a/src/r_data/models/models.h +++ b/src/r_data/models/models.h @@ -309,40 +309,23 @@ class FMD3Model : public FModel struct MD3Surface { - int numVertices; - int numTriangles; - int numSkins; + unsigned numVertices; + unsigned numTriangles; + unsigned numSkins; - FTextureID * skins; - MD3Triangle * tris; - MD3TexCoord * texcoords; - MD3Vertex * vertices; + TArray Skins; + TArray Tris; + TArray Texcoords; + TArray Vertices; - unsigned int vindex; // contains numframes arrays of vertices - unsigned int iindex; - - MD3Surface() - { - tris=NULL; - vertices=NULL; - texcoords=NULL; - vindex = iindex = UINT_MAX; - } - - ~MD3Surface() - { - if (skins) delete [] skins; - UnloadGeometry(); - } + unsigned int vindex = UINT_MAX; // contains numframes arrays of vertices + unsigned int iindex = UINT_MAX; void UnloadGeometry() { - if (tris) delete [] tris; - if (vertices) delete [] vertices; - if (texcoords) delete [] texcoords; - tris = NULL; - vertices = NULL; - texcoords = NULL; + Tris.Reset(); + Vertices.Reset(); + Texcoords.Reset(); } }; @@ -354,17 +337,14 @@ class FMD3Model : public FModel float origin[3]; }; - int numFrames; int numTags; - int numSurfaces; int mLumpNum; - MD3Frame * frames; - MD3Surface * surfaces; + TArray Frames; + TArray Surfaces; public: - FMD3Model() { } - virtual ~FMD3Model(); + FMD3Model() = default; virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length); virtual int FindFrame(const char * name); diff --git a/src/r_data/models/models_md2.cpp b/src/r_data/models/models_md2.cpp index ce9566a8f..d203bf15a 100644 --- a/src/r_data/models/models_md2.cpp +++ b/src/r_data/models/models_md2.cpp @@ -364,7 +364,7 @@ void FDMDModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame if (!skin) { if (info.numSkins == 0 || !skins[0].isValid()) return; - skin = TexMan(skins[0]); + skin = TexMan.GetTexture(skins[0], true); if (!skin) return; } diff --git a/src/r_data/models/models_md3.cpp b/src/r_data/models/models_md3.cpp index b3f12b853..49efceb4f 100644 --- a/src/r_data/models/models_md3.cpp +++ b/src/r_data/models/models_md3.cpp @@ -129,26 +129,27 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le { md3_header_t * hdr = (md3_header_t *)buffer; - numFrames = LittleLong(hdr->Num_Frames); + auto numFrames = LittleLong(hdr->Num_Frames); + auto numSurfaces = LittleLong(hdr->Num_Surfaces); + numTags = LittleLong(hdr->Num_Tags); - numSurfaces = LittleLong(hdr->Num_Surfaces); md3_frame_t * frm = (md3_frame_t*)(buffer + LittleLong(hdr->Ofs_Frames)); - frames = new MD3Frame[numFrames]; - for (int i = 0; i < numFrames; i++) + Frames.Resize(numFrames); + for (unsigned i = 0; i < numFrames; i++) { - strncpy(frames[i].Name, frm[i].Name, 16); - for (int j = 0; j < 3; j++) frames[i].origin[j] = frm[i].localorigin[j]; + strncpy(Frames[i].Name, frm[i].Name, 16); + for (int j = 0; j < 3; j++) Frames[i].origin[j] = frm[i].localorigin[j]; } md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces)); - surfaces = new MD3Surface[numSurfaces]; + Surfaces.Resize(numSurfaces); - for (int i = 0; i < numSurfaces; i++) + for (unsigned i = 0; i < numSurfaces; i++) { - MD3Surface * s = &surfaces[i]; + MD3Surface * s = &Surfaces[i]; md3_surface_t * ss = surf; surf = (md3_surface_t *)(((char*)surf) + LittleLong(surf->Ofs_End)); @@ -159,17 +160,17 @@ bool FMD3Model::Load(const char * path, int lumpnum, const char * buffer, int le // copy shaders (skins) md3_shader_t * shader = (md3_shader_t*)(((char*)ss) + LittleLong(ss->Ofs_Shaders)); - s->skins = new FTextureID[s->numSkins]; + s->Skins.Resize(s->numSkins); - for (int i = 0; i < s->numSkins; i++) + for (unsigned i = 0; i < s->numSkins; i++) { // [BB] According to the MD3 spec, Name is supposed to include the full path. // ... and since some tools seem to output backslashes, these need to be replaced with forward slashes to work. FixPathSeperator(shader[i].Name); - s->skins[i] = LoadSkin("", shader[i].Name); + s->Skins[i] = LoadSkin("", shader[i].Name); // [BB] Fall back and check if Name is relative. - if (!s->skins[i].isValid()) - s->skins[i] = LoadSkin(path, shader[i].Name); + if (!s->Skins[i].isValid()) + s->Skins[i] = LoadSkin(path, shader[i].Name); } } mLumpNum = lumpnum; @@ -189,42 +190,42 @@ void FMD3Model::LoadGeometry() md3_header_t * hdr = (md3_header_t *)buffer; md3_surface_t * surf = (md3_surface_t*)(buffer + LittleLong(hdr->Ofs_Surfaces)); - for(int i=0;iOfs_End)); // copy triangle indices - md3_triangle_t * tris = (md3_triangle_t*)(((char*)ss)+LittleLong(ss->Ofs_Triangles)); - s->tris = new MD3Triangle[s->numTriangles]; + md3_triangle_t * tris = (md3_triangle_t*)(((char*)ss) + LittleLong(ss->Ofs_Triangles)); + s->Tris.Resize(s->numTriangles); - for(int i=0;inumTriangles;i++) for (int j=0;j<3;j++) + for (unsigned i = 0; i < s->numTriangles; i++) for (int j = 0; j < 3; j++) { - s->tris[i].VertIndex[j]=LittleLong(tris[i].vt_index[j]); + s->Tris[i].VertIndex[j] = LittleLong(tris[i].vt_index[j]); } // Load texture coordinates - md3_texcoord_t * tc = (md3_texcoord_t*)(((char*)ss)+LittleLong(ss->Ofs_Texcoord)); - s->texcoords = new MD3TexCoord[s->numVertices]; + md3_texcoord_t * tc = (md3_texcoord_t*)(((char*)ss) + LittleLong(ss->Ofs_Texcoord)); + s->Texcoords.Resize(s->numVertices); - for(int i=0;inumVertices;i++) + for (unsigned i = 0; i < s->numVertices; i++) { - s->texcoords[i].s = tc[i].s; - s->texcoords[i].t = tc[i].t; + s->Texcoords[i].s = tc[i].s; + s->Texcoords[i].t = tc[i].t; } // Load vertices and texture coordinates - md3_vertex_t * vt = (md3_vertex_t*)(((char*)ss)+LittleLong(ss->Ofs_XYZNormal)); - s->vertices = new MD3Vertex[s->numVertices * numFrames]; + md3_vertex_t * vt = (md3_vertex_t*)(((char*)ss) + LittleLong(ss->Ofs_XYZNormal)); + s->Vertices.Resize(s->numVertices * Frames.Size()); - for(int i=0;inumVertices * numFrames;i++) + for (unsigned i = 0; i < s->numVertices * Frames.Size(); i++) { - s->vertices[i].x = LittleShort(vt[i].x)/64.f; - s->vertices[i].y = LittleShort(vt[i].y)/64.f; - s->vertices[i].z = LittleShort(vt[i].z)/64.f; - UnpackVector( LittleShort(vt[i].n), s->vertices[i].nx, s->vertices[i].ny, s->vertices[i].nz); + s->Vertices[i].x = LittleShort(vt[i].x) / 64.f; + s->Vertices[i].y = LittleShort(vt[i].y) / 64.f; + s->Vertices[i].z = LittleShort(vt[i].z) / 64.f; + UnpackVector(LittleShort(vt[i].n), s->Vertices[i].nx, s->Vertices[i].ny, s->Vertices[i].nz); } } } @@ -244,14 +245,14 @@ void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) unsigned int vbufsize = 0; unsigned int ibufsize = 0; - for (int i = 0; i < numSurfaces; i++) + for (unsigned i = 0; i < Surfaces.Size(); i++) { - MD3Surface * surf = &surfaces[i]; - vbufsize += numFrames * surf->numVertices; + MD3Surface * surf = &Surfaces[i]; + vbufsize += Frames.Size() * surf->numVertices; ibufsize += 3 * surf->numTriangles; } - auto vbuf = renderer->CreateVertexBuffer(true, numFrames == 1); + auto vbuf = renderer->CreateVertexBuffer(true, Frames.Size() == 1); SetVertexBuffer(renderer, vbuf); FModelVertex *vertptr = vbuf->LockVertexBuffer(vbufsize); @@ -261,28 +262,28 @@ void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) unsigned int vindex = 0, iindex = 0; - for (int i = 0; i < numSurfaces; i++) + for (unsigned i = 0; i < Surfaces.Size(); i++) { - MD3Surface * surf = &surfaces[i]; + MD3Surface * surf = &Surfaces[i]; surf->vindex = vindex; surf->iindex = iindex; - for (int j = 0; j < numFrames * surf->numVertices; j++) + for (unsigned j = 0; j < Frames.Size() * surf->numVertices; j++) { - MD3Vertex* vert = surf->vertices + j; + MD3Vertex* vert = &surf->Vertices[j]; FModelVertex *bvert = &vertptr[vindex++]; int tc = j % surf->numVertices; - bvert->Set(vert->x, vert->z, vert->y, surf->texcoords[tc].s, surf->texcoords[tc].t); + bvert->Set(vert->x, vert->z, vert->y, surf->Texcoords[tc].s, surf->Texcoords[tc].t); bvert->SetNormal(vert->nx, vert->nz, vert->ny); } - for (int k = 0; k < surf->numTriangles; k++) + for (unsigned k = 0; k < surf->numTriangles; k++) { for (int l = 0; l < 3; l++) { - indxptr[iindex++] = surf->tris[k].VertIndex[l]; + indxptr[iindex++] = surf->Tris[k].VertIndex[l]; } } surf->UnloadGeometry(); @@ -301,19 +302,19 @@ void FMD3Model::BuildVertexBuffer(FModelRenderer *renderer) void FMD3Model::AddSkins(uint8_t *hitlist) { - for (int i = 0; i < numSurfaces; i++) + for (unsigned i = 0; i < Surfaces.Size(); i++) { if (curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) { hitlist[curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].GetIndex()] |= FTextureManager::HIT_Flat; } - MD3Surface * surf = &surfaces[i]; - for (int j = 0; j < surf->numSkins; j++) + MD3Surface * surf = &Surfaces[i]; + for (unsigned j = 0; j < surf->numSkins; j++) { - if (surf->skins[j].isValid()) + if (surf->Skins[j].isValid()) { - hitlist[surf->skins[j].GetIndex()] |= FTextureManager::HIT_Flat; + hitlist[surf->Skins[j].GetIndex()] |= FTextureManager::HIT_Flat; } } } @@ -327,9 +328,9 @@ void FMD3Model::AddSkins(uint8_t *hitlist) int FMD3Model::FindFrame(const char * name) { - for (int i=0;i=numFrames || frameno2>=numFrames) return; + if ((unsigned)frameno >= Frames.Size() || (unsigned)frameno2 >= Frames.Size()) return; renderer->SetInterpolation(inter); - for(int i=0;isurfaceskinIDs[curMDLIndex][i].isValid()) { - surfaceSkin = TexMan(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i]); + surfaceSkin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); } - else if(surf->numSkins > 0 && surf->skins[0].isValid()) + else if (surf->numSkins > 0 && surf->Skins[0].isValid()) { - surfaceSkin = TexMan(surf->skins[0]); + surfaceSkin = TexMan.GetTexture(surf->Skins[0], true); } if (!surfaceSkin) @@ -376,16 +377,3 @@ void FMD3Model::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame renderer->SetInterpolation(0.f); } -//=========================================================================== -// -// -// -//=========================================================================== - -FMD3Model::~FMD3Model() -{ - if (frames) delete [] frames; - if (surfaces) delete [] surfaces; - frames = nullptr; - surfaces = nullptr; -} diff --git a/src/r_data/models/models_obj.cpp b/src/r_data/models/models_obj.cpp index b6adb29cf..bbf8e3b5b 100644 --- a/src/r_data/models/models_obj.cpp +++ b/src/r_data/models/models_obj.cpp @@ -636,11 +636,11 @@ void FOBJModel::RenderFrame(FModelRenderer *renderer, FTexture * skin, int frame { if (i < MD3_MAX_SURFACES && curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i].isValid()) { - userSkin = TexMan(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i]); + userSkin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][i], true); } else if (surf->skin.isValid()) { - userSkin = TexMan(surf->skin); + userSkin = TexMan.GetTexture(surf->skin, true); } } diff --git a/src/r_data/models/models_ue1.cpp b/src/r_data/models/models_ue1.cpp index bd4f54e3d..c51dbc7fb 100644 --- a/src/r_data/models/models_ue1.cpp +++ b/src/r_data/models/models_ue1.cpp @@ -235,7 +235,7 @@ void FUE1Model::RenderFrame( FModelRenderer *renderer, FTexture *skin, int frame if ( !sskin ) { if ( curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum].isValid() ) - sskin = TexMan(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum]); + sskin = TexMan.GetTexture(curSpriteMDLFrame->surfaceskinIDs[curMDLIndex][groups[i].texNum], true); if ( !sskin ) { vofs += vsize; diff --git a/src/r_data/models/models_voxel.cpp b/src/r_data/models/models_voxel.cpp index e25a72613..9a01b6487 100644 --- a/src/r_data/models/models_voxel.cpp +++ b/src/r_data/models/models_voxel.cpp @@ -32,6 +32,7 @@ #include "textures/bitmap.h" #include "g_levellocals.h" #include "models.h" +#include "image.h" #ifdef _MSC_VER #pragma warning(disable:4244) // warning C4244: conversion from 'double' to 'float', possible loss of data @@ -46,14 +47,13 @@ // //=========================================================================== -class FVoxelTexture : public FWorldTexture +class FVoxelTexture : public FImageSource { public: FVoxelTexture(FVoxel *voxel); - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; - bool UseBasePalette() override { return false; } - uint8_t *MakeTexture(FRenderStyle style) override; + int CopyPixels(FBitmap *bmp, int conversion) override; + TArray CreatePalettedPixels(int conversion) override; protected: FVoxel *SourceVox; @@ -70,10 +70,7 @@ FVoxelTexture::FVoxelTexture(FVoxel *vox) SourceVox = vox; Width = 16; Height = 16; - WidthBits = 4; - HeightBits = 4; - WidthMask = 15; - bNoCompress = true; + //bNoCompress = true; } //=========================================================================== @@ -82,11 +79,11 @@ FVoxelTexture::FVoxelTexture(FVoxel *vox) // //=========================================================================== -uint8_t *FVoxelTexture::MakeTexture (FRenderStyle style) +TArray FVoxelTexture::CreatePalettedPixels(int conversion) { // GetPixels gets called when a translated palette is used so we still need to implement it here. - auto Pixels = new uint8_t[256]; - uint8_t *pp = SourceVox->Palette; + TArray Pixels(256, true); + uint8_t *pp = SourceVox->Palette.Data(); if(pp != NULL) { @@ -97,7 +94,7 @@ uint8_t *FVoxelTexture::MakeTexture (FRenderStyle style) pe.g = (pp[1] << 2) | (pp[1] >> 4); pe.b = (pp[2] << 2) | (pp[2] >> 4); // Alphatexture handling is just for completeness, but rather unlikely to be used ever. - Pixels[i] = (style.Flags & STYLEF_RedIsAlpha)? pe.r : ColorMatcher.Pick(pe); + Pixels[i] = conversion == luminance ? pe.r : ColorMatcher.Pick(pe); } } else @@ -112,20 +109,20 @@ uint8_t *FVoxelTexture::MakeTexture (FRenderStyle style) //=========================================================================== // -// FVoxelTexture::CopyTrueColorPixels +// FVoxelTexture::CopyPixels // // This creates a dummy 16x16 paletted bitmap and converts that using the // voxel palette // //=========================================================================== -int FVoxelTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FVoxelTexture::CopyPixels(FBitmap *bmp, int conversion) { PalEntry pe[256]; uint8_t bitmap[256]; - uint8_t *pp = SourceVox->Palette; + uint8_t *pp = SourceVox->Palette.Data(); - if(pp != NULL) + if(pp != nullptr) { for(int i=0;i<256;i++, pp+=3) { @@ -145,7 +142,7 @@ int FVoxelTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, F pe[i].a = 255; } } - bmp->CopyPixelData(x, y, bitmap, Width, Height, 1, 16, rotate, pe, inf); + bmp->CopyPixelData(0, 0, bitmap, Width, Height, 1, 16, 0, pe); return 0; } @@ -159,7 +156,7 @@ FVoxelModel::FVoxelModel(FVoxel *voxel, bool owned) { mVoxel = voxel; mOwningVoxel = owned; - mPalette = TexMan.AddTexture(new FVoxelTexture(voxel)); + mPalette = TexMan.AddTexture(new FImageTexture(new FVoxelTexture(voxel))); } //=========================================================================== diff --git a/src/r_data/r_canvastexture.cpp b/src/r_data/r_canvastexture.cpp new file mode 100644 index 000000000..a64f50b87 --- /dev/null +++ b/src/r_data/r_canvastexture.cpp @@ -0,0 +1,210 @@ +/* +** r_canvastexture.cpp +** Maintenance data for camera textures +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "actor.h" +#include "r_canvastexture.h" +#include "g_levellocals.h" +#include "serializer.h" + +//========================================================================== +// +// FCanvasTextureInfo :: Add +// +// Assigns a camera to a canvas texture. +// +//========================================================================== + +void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) +{ + FCanvasTexture *texture; + + if (!picnum.isValid()) + { + return; + } + texture = static_cast(TexMan.GetTexture(picnum)); + if (!texture->bHasCanvas) + { + Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); + return; + } + + // Is this texture already assigned to a camera? + unsigned index = List.FindEx([=](auto &entry) { return entry.Texture == texture; }); + if (index < List.Size()) + { + auto probe = &List[index]; + // Yes, change its assignment to this new camera + if (probe->Viewpoint != viewpoint || probe->FOV != fov) + { + texture->bFirstUpdate = true; + } + probe->Viewpoint = viewpoint; + probe->FOV = fov; + return; + } + // No, create a new assignment + auto probe = &List[List.Reserve(1)]; + probe->Viewpoint = viewpoint; + probe->Texture = texture; + probe->PicNum = picnum; + probe->FOV = fov; + texture->bFirstUpdate = true; +} + +//========================================================================== +// +// SetCameraToTexture +// +// [ZZ] expose this to ZScript +// +//========================================================================== + +void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov) +{ + FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); + if (textureid.isValid()) + { + // Only proceed if the texture actually has a canvas. + FTexture *tex = TexMan.GetTexture(textureid); + if (tex && tex->isCanvas()) + { + level.canvasTextureInfo.Add(viewpoint, textureid, fov); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: UpdateAll +// +// Updates all canvas textures that were visible in the last frame. +// +//========================================================================== + +void FCanvasTextureInfo::UpdateAll(std::function callback) +{ + for (auto &probe : List) + { + if (probe.Viewpoint != nullptr && probe.Texture->bNeedsUpdate) + { + callback(probe.Viewpoint, probe.Texture, probe.FOV); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: EmptyList +// +// Removes all camera->texture assignments. +// +//========================================================================== + +void FCanvasTextureInfo::EmptyList () +{ + List.Clear(); +} + +//========================================================================== +// +// FCanvasTextureInfo :: Serialize +// +// Reads or writes the current set of mappings in an archive. +// +//========================================================================== + +void FCanvasTextureInfo::Serialize(FSerializer &arc) +{ + if (arc.isWriting()) + { + if (List.Size() > 0) + { + if (arc.BeginArray("canvastextures")) + { + for (auto &probe : List) + { + if (probe.Texture != nullptr && probe.Viewpoint != nullptr) + { + if (arc.BeginObject(nullptr)) + { + arc("viewpoint", probe.Viewpoint) + ("fov", probe.FOV) + ("texture", probe.PicNum) + .EndObject(); + } + } + } + arc.EndArray(); + } + } + } + else + { + if (arc.BeginArray("canvastextures")) + { + AActor *viewpoint = nullptr; + double fov; + FTextureID picnum; + while (arc.BeginObject(nullptr)) + { + arc("viewpoint", viewpoint) + ("fov", fov) + ("texture", picnum) + .EndObject(); + Add(viewpoint, picnum, fov); + } + arc.EndArray(); + } + } +} + +//========================================================================== +// +// FCanvasTextureInfo :: Mark +// +// Marks all viewpoints in the list for the collector. +// +//========================================================================== + +void FCanvasTextureInfo::Mark() +{ + for (auto & info : List) + { + GC::Mark(info.Viewpoint); + } +} + diff --git a/src/r_data/r_canvastexture.h b/src/r_data/r_canvastexture.h new file mode 100644 index 000000000..b69c46687 --- /dev/null +++ b/src/r_data/r_canvastexture.h @@ -0,0 +1,24 @@ +#pragma once + +class FCanvasTexture; +// This list keeps track of the cameras that draw into canvas textures. +struct FCanvasTextureEntry +{ + TObjPtr Viewpoint; + FCanvasTexture *Texture; + FTextureID PicNum; + double FOV; +}; + + +struct FCanvasTextureInfo +{ + TArray List; + + void Add (AActor *viewpoint, FTextureID picnum, double fov); + void UpdateAll (std::function callback); + void EmptyList (); + void Serialize(FSerializer &arc); + void Mark(); + +}; diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index c11f9be94..5264095e7 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -633,148 +633,140 @@ bool FRemapTable::AddToTranslation(const char *range) sc.OpenMem("translation", range, int(strlen(range))); sc.SetCMode(true); - try + sc.MustGetToken(TK_IntConst); + start = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + end = sc.Number; + sc.MustGetToken('='); + if (start < 0 || start > 255 || end < 0 || end > 255) { + sc.ScriptError("Palette index out of range"); + return false; + } + + sc.MustGetAnyToken(); + + if (sc.TokenType == '[') + { + // translation using RGB values + int r1,g1,b1,r2,g2,b2; + sc.MustGetToken(TK_IntConst); - start = sc.Number; + r1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g1 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b1 = sc.Number; + sc.MustGetToken(']'); sc.MustGetToken(':'); + sc.MustGetToken('['); + sc.MustGetToken(TK_IntConst); - end = sc.Number; - sc.MustGetToken('='); - if (start < 0 || start > 255 || end < 0 || end > 255) - { - sc.ScriptError("Palette index out of range"); - return false; - } + r2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + g2 = sc.Number; + sc.MustGetToken(','); + + sc.MustGetToken(TK_IntConst); + b2 = sc.Number; + sc.MustGetToken(']'); + + return AddColorRange(start, end, r1, g1, b1, r2, g2, b2); + } + else if (sc.TokenType == '%') + { + // translation using RGB values + double r1,g1,b1,r2,g2,b2; + + sc.MustGetToken('['); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + r1 = sc.Float; + sc.MustGetToken(','); sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + g1 = sc.Float; + sc.MustGetToken(','); - if (sc.TokenType == '[') - { - // translation using RGB values - int r1,g1,b1,r2,g2,b2; + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + b1 = sc.Float; + sc.MustGetToken(']'); + sc.MustGetToken(':'); + sc.MustGetToken('['); - sc.MustGetToken(TK_IntConst); - r1 = sc.Number; - sc.MustGetToken(','); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + r2 = sc.Float; + sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - g1 = sc.Number; - sc.MustGetToken(','); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + g2 = sc.Float; + sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - b1 = sc.Number; - sc.MustGetToken(']'); - sc.MustGetToken(':'); - sc.MustGetToken('['); + sc.MustGetAnyToken(); + if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); + b2 = sc.Float; + sc.MustGetToken(']'); - sc.MustGetToken(TK_IntConst); - r2 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - g2 = sc.Number; - sc.MustGetToken(','); - - sc.MustGetToken(TK_IntConst); - b2 = sc.Number; - sc.MustGetToken(']'); - - return AddColorRange(start, end, r1, g1, b1, r2, g2, b2); - } - else if (sc.TokenType == '%') - { - // translation using RGB values - double r1,g1,b1,r2,g2,b2; - - sc.MustGetToken('['); - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r1 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g1 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b1 = sc.Float; - sc.MustGetToken(']'); - sc.MustGetToken(':'); - sc.MustGetToken('['); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - r2 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - g2 = sc.Float; - sc.MustGetToken(','); - - sc.MustGetAnyToken(); - if (sc.TokenType != TK_IntConst) sc.TokenMustBe(TK_FloatConst); - b2 = sc.Float; - sc.MustGetToken(']'); - - return AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); - } - else if (sc.TokenType == '#') - { - // Colourise translation - int r, g, b; - sc.MustGetToken('['); - sc.MustGetToken(TK_IntConst); - r = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - g = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - b = sc.Number; - sc.MustGetToken(']'); - - return AddColourisation(start, end, r, g, b); - } - else if (sc.TokenType == '@') - { - // Tint translation - int a, r, g, b; - - sc.MustGetToken(TK_IntConst); - a = sc.Number; - sc.MustGetToken('['); - sc.MustGetToken(TK_IntConst); - r = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - g = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - b = sc.Number; - sc.MustGetToken(']'); - - return AddTint(start, end, r, g, b, a); - } - else - { - int pal1, pal2; - - sc.TokenMustBe(TK_IntConst); - pal1 = sc.Number; - sc.MustGetToken(':'); - sc.MustGetToken(TK_IntConst); - pal2 = sc.Number; - return AddIndexRange(start, end, pal1, pal2); - } + return AddDesaturation(start, end, r1, g1, b1, r2, g2, b2); } - catch (CRecoverableError &err) + else if (sc.TokenType == '#') { - Printf("Error in translation '%s':\n%s\n", range, err.GetMessage()); - return false; + // Colourise translation + int r, g, b; + sc.MustGetToken('['); + sc.MustGetToken(TK_IntConst); + r = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + g = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + b = sc.Number; + sc.MustGetToken(']'); + + return AddColourisation(start, end, r, g, b); + } + else if (sc.TokenType == '@') + { + // Tint translation + int a, r, g, b; + + sc.MustGetToken(TK_IntConst); + a = sc.Number; + sc.MustGetToken('['); + sc.MustGetToken(TK_IntConst); + r = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + g = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + b = sc.Number; + sc.MustGetToken(']'); + + return AddTint(start, end, r, g, b, a); + } + else + { + int pal1, pal2; + + sc.TokenMustBe(TK_IntConst); + pal1 = sc.Number; + sc.MustGetToken(':'); + sc.MustGetToken(TK_IntConst); + pal2 = sc.Number; + return AddIndexRange(start, end, pal1, pal2); } } @@ -1529,7 +1521,16 @@ void R_ParseTrnslate() do { sc.MustGetToken(TK_StringConst); - NewTranslation.AddToTranslation(sc.String); + + try + { + NewTranslation.AddToTranslation(sc.String); + } + catch (CRecoverableError &err) + { + sc.ScriptMessage("Error in translation '%s':\n" TEXTCOLOR_YELLOW "%s\n", sc.String, err.GetMessage()); + } + } while (sc.CheckToken(',')); int trans = NewTranslation.StoreTranslation(TRANSLATION_Custom); diff --git a/src/r_data/renderinfo.cpp b/src/r_data/renderinfo.cpp index 88526d824..7edeef789 100644 --- a/src/r_data/renderinfo.cpp +++ b/src/r_data/renderinfo.cpp @@ -392,7 +392,7 @@ static void AddToVertex(const sector_t * sec, TArray & list) static void InitVertexData() { - auto vt_sectorlists = new TArray[level.vertexes.Size()]; + TArray> vt_sectorlists(level.vertexes.Size(), true); for(auto &line : level.lines) { @@ -437,8 +437,6 @@ static void InitVertexData() vert.numsectors=0; } } - - delete [] vt_sectorlists; } //========================================================================== @@ -478,15 +476,15 @@ static int segcmp(const void *a, const void *b) static void PrepareSegs() { auto numsides = level.sides.Size(); - int *segcount = new int[numsides]; + TArray segcount(numsides, true); int realsegs = 0; // count the segs - memset(segcount, 0, numsides * sizeof(int)); + memset(segcount.Data(), 0, numsides * sizeof(int)); for(auto &seg : level.segs) { - if (seg.sidedef == NULL) continue; // miniseg + if (seg.sidedef == nullptr) continue; // miniseg int sidenum = seg.sidedef->Index(); realsegs++; @@ -509,7 +507,6 @@ static void PrepareSegs() level.sides[i].segs = level.sides[i-1].segs + segcount[i-1]; level.sides[i].numsegs = 0; } - delete [] segcount; // assign the segs for (auto &seg : level.segs) diff --git a/src/r_data/sprites.cpp b/src/r_data/sprites.cpp index c1f1f3e02..f8a53cf7d 100644 --- a/src/r_data/sprites.cpp +++ b/src/r_data/sprites.cpp @@ -122,7 +122,7 @@ static bool R_InstallSpriteLump (FTextureID lump, unsigned frame, char rot, bool if (frame >= MAX_SPRITE_FRAMES || rotation > 16) { - Printf (TEXTCOLOR_RED "R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan[lump]->Name.GetChars()); + Printf (TEXTCOLOR_RED "R_InstallSpriteLump: Bad frame characters in lump %s\n", TexMan.GetTexture(lump)->GetName().GetChars()); return false; } @@ -176,7 +176,7 @@ static bool R_InstallSpriteLump (FTextureID lump, unsigned frame, char rot, bool // [RH] Seperated out of R_InitSpriteDefs() -static void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe) +void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe) { int frame; int framestart; @@ -286,7 +286,7 @@ static void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxfr { for (int rot = 0; rot < 16; ++rot) { - TexMan[sprtemp[frame].Texture[rot]]->Rotations = framestart + frame; + TexMan.GetTexture(sprtemp[frame].Texture[rot])->Rotations = framestart + frame; } } } @@ -414,7 +414,7 @@ void R_InitSpriteDefs () int hash = hashes[intname % smax].Head; while (hash != -1) { - FTexture *tex = TexMan[hash]; + FTexture *tex = TexMan.GetTexture(hash); if (TEX_DWNAME(tex) == intname) { bool res = R_InstallSpriteLump (FTextureID(hash), tex->Name[4] - 'A', tex->Name[5], false, sprtemp, maxframe); diff --git a/src/r_data/voxels.cpp b/src/r_data/voxels.cpp index 9dc0b7006..a9eb9eb68 100644 --- a/src/r_data/voxels.cpp +++ b/src/r_data/voxels.cpp @@ -303,8 +303,8 @@ FVoxel *R_LoadKVX(int lumpnum) } voxel->LumpNum = lumpnum; - voxel->Palette = new uint8_t[768]; - memcpy(voxel->Palette, rawvoxel + voxelsize - 768, 768); + voxel->Palette.Resize(768); + memcpy(voxel->Palette.Data(), rawvoxel + voxelsize - 768, 768); return voxel; } @@ -382,22 +382,6 @@ uint8_t *FVoxelMipLevel::GetSlabData(bool wantremapped) const return SlabData; } -//========================================================================== -// -// FVoxel Constructor -// -//========================================================================== - -FVoxel::FVoxel() -{ - Palette = NULL; -} - -FVoxel::~FVoxel() -{ - if (Palette != NULL) delete [] Palette; -} - //========================================================================== // // Create true color version of the slab data @@ -430,7 +414,7 @@ void FVoxel::CreateBgraSlabData() int colorIndex = src->col[j]; uint32_t red, green, blue; - if (Palette) + if (Palette.Size()) { red = (Palette[colorIndex * 3 + 0] << 2) | (Palette[colorIndex * 3 + 0] >> 4); green = (Palette[colorIndex * 3 + 1] << 2) | (Palette[colorIndex * 3 + 1] >> 4); @@ -464,9 +448,9 @@ void FVoxel::Remap() { if (Remapped) return; Remapped = true; - if (Palette != NULL) + if (Palette.Size()) { - uint8_t *remap = GetVoxelRemap(Palette); + uint8_t *remap = GetVoxelRemap(Palette.Data()); for (int i = 0; i < NumMips; ++i) { int size = Mips[i].OffsetX[Mips[i].SizeX]; @@ -487,11 +471,7 @@ void FVoxel::Remap() void FVoxel::RemovePalette() { - if (Palette != NULL) - { - delete [] Palette; - Palette = NULL; - } + Palette.Reset(); } diff --git a/src/r_data/voxels.h b/src/r_data/voxels.h index eac1b39ee..60a149be9 100644 --- a/src/r_data/voxels.h +++ b/src/r_data/voxels.h @@ -50,16 +50,14 @@ public: struct FVoxel { + TArray Palette; int LumpNum; int NumMips; int VoxelIndex; - uint8_t *Palette; FVoxelMipLevel Mips[MAXVOXMIPS]; bool Remapped = false; bool Bgramade = false; - FVoxel(); - ~FVoxel(); void CreateBgraSlabData(); void Remap(); void RemovePalette(); diff --git a/src/r_renderer.h b/src/r_renderer.h index 225d57740..46fd9a430 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -28,9 +28,6 @@ struct FRenderer // renders view to a savegame picture virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height) = 0; - // render to a camera texture - virtual void RenderTextureView(FCanvasTexture *tex, AActor *viewpoint, double fov) = 0; - // draws player sprites with hardware acceleration (only useful for software rendering) virtual void DrawRemainingPlayerSprites() = 0; diff --git a/src/r_sky.cpp b/src/r_sky.cpp index 13d130adb..94fb65644 100644 --- a/src/r_sky.cpp +++ b/src/r_sky.cpp @@ -44,19 +44,9 @@ // FTextureID skyflatnum; FTextureID sky1texture, sky2texture; -double skytexturemid; -double skyscale; -float skyiscale; -bool skystretch; - -fixed_t sky1cyl, sky2cyl; double sky1pos, sky2pos; float hw_sky1pos, hw_sky2pos; - -CUSTOM_CVAR(Int, testskyoffset, 0, 0) -{ - R_InitSkyMap(); -} +bool skystretch; // [RH] Stretch sky texture if not taller than 128 pixels? // Also now controls capped skies. 0 = normal, 1 = stretched, 2 = capped @@ -67,10 +57,6 @@ CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE) CVAR(Float, skyoffset, 0, 0) // for testing - - -int freelookviewheight; - //========================================================================== // // R_InitSkyMap @@ -79,7 +65,7 @@ int freelookviewheight; // //========================================================================== -void R_InitSkyMap () +void R_InitSkyMap() { int skyheight; FTexture *skytex1, *skytex2; @@ -94,15 +80,15 @@ void R_InitSkyMap () sky2texture = TexMan.CheckForTexture("-noflat-", ETextureType::Any); } - skytex1 = TexMan(sky1texture, true); - skytex2 = TexMan(sky2texture, true); + skytex1 = TexMan.GetTexture(sky1texture, false); + skytex2 = TexMan.GetTexture(sky2texture, false); if (skytex1 == nullptr) return; - if ((level.flags & LEVEL_DOUBLESKY) && skytex1->GetHeight() != skytex2->GetHeight()) + if ((level.flags & LEVEL_DOUBLESKY) && skytex1->GetDisplayHeight() != skytex2->GetDisplayHeight()) { - Printf (TEXTCOLOR_BOLD "Both sky textures must be the same height." TEXTCOLOR_NORMAL "\n"); + Printf(TEXTCOLOR_BOLD "Both sky textures must be the same height." TEXTCOLOR_NORMAL "\n"); sky2texture = sky1texture; } @@ -119,47 +105,18 @@ void R_InitSkyMap () // the screen when looking fully up. // h > 200: Unstretched, but the baseline is shifted down so that the top // of the texture is at the top of the screen when looking fully up. - skyheight = skytex1->GetScaledHeight(); - skystretch = false; - skytexturemid = 0; + skyheight = skytex1->GetDisplayHeight(); + if (skyheight >= 128 && skyheight < 200) { skystretch = (r_skymode == 1 - && skyheight >= 128 - && level.IsFreelookAllowed() - && !(level.flags & LEVEL_FORCETILEDSKY)) ? 1 : 0; - skytexturemid = -28; + && skyheight >= 128 + && level.IsFreelookAllowed() + && !(level.flags & LEVEL_FORCETILEDSKY)) ? 1 : 0; } - else if (skyheight > 200) - { - skytexturemid = (200 - skyheight) * skytex1->Scale.Y +((r_skymode == 2 && !(level.flags & LEVEL_FORCETILEDSKY)) ? skytex1->SkyOffset + testskyoffset : 0); - } - - if (viewwidth != 0 && viewheight != 0) - { - skyiscale = float(r_Yaspect / freelookviewheight); - skyscale = freelookviewheight / r_Yaspect; - - skyiscale *= float(r_viewpoint.FieldOfView.Degrees / 90.); - skyscale *= float(90. / r_viewpoint.FieldOfView.Degrees); - } - - if (skystretch) - { - skyscale *= (double)SKYSTRETCH_HEIGHT / skyheight; - skyiscale *= skyheight / (float)SKYSTRETCH_HEIGHT; - skytexturemid *= skyheight / (double)SKYSTRETCH_HEIGHT; - } - - // The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees, - // giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024, - // we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of - // the texture as the cylinder's circumfrence. - sky1cyl = MAX(skytex1->GetWidth(), fixed_t(skytex1->Scale.X * 1024)); - sky2cyl = MAX(skytex2->GetWidth(), fixed_t(skytex2->Scale.Y * 1024)); + else skystretch = false; } - //========================================================================== // // R_UpdateSky diff --git a/src/r_sky.h b/src/r_sky.h index d9963d96c..05154e2fd 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -31,13 +31,9 @@ #include "textures/textures.h" extern FTextureID skyflatnum; -extern fixed_t sky1cyl, sky2cyl; extern FTextureID sky1texture, sky2texture; extern double sky1pos, sky2pos; extern float hw_sky1pos, hw_sky2pos; -extern double skytexturemid; -extern float skyiscale; -extern double skyscale; extern bool skystretch; extern int freelookviewheight; diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 52d9a4bd4..9117fc01f 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -144,7 +144,7 @@ bool setsizeneeded; unsigned int R_OldBlend = ~0; int validcount = 1; // increment every time a check is made int dl_validcount = 1; // increment every time a check is made -FCanvasTextureInfo *FCanvasTextureInfo::List; +int freelookviewheight; DVector3a view; DAngle viewpitch; @@ -431,7 +431,6 @@ static void R_Shutdown () SWRenderer = nullptr; R_DeinitTranslationTables(); R_DeinitColormaps (); - FCanvasTextureInfo::EmptyList(); } //========================================================================== @@ -1050,195 +1049,6 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor } -//========================================================================== -// -// FCanvasTextureInfo :: Add -// -// Assigns a camera to a canvas texture. -// -//========================================================================== - -void FCanvasTextureInfo::Add (AActor *viewpoint, FTextureID picnum, double fov) -{ - FCanvasTextureInfo *probe; - FCanvasTexture *texture; - - if (!picnum.isValid()) - { - return; - } - texture = static_cast(TexMan[picnum]); - if (!texture->bHasCanvas) - { - Printf ("%s is not a valid target for a camera\n", texture->Name.GetChars()); - return; - } - - // Is this texture already assigned to a camera? - for (probe = List; probe != NULL; probe = probe->Next) - { - if (probe->Texture == texture) - { - // Yes, change its assignment to this new camera - if (probe->Viewpoint != viewpoint || probe->FOV != fov) - { - texture->bFirstUpdate = true; - } - probe->Viewpoint = viewpoint; - probe->FOV = fov; - return; - } - } - // No, create a new assignment - probe = new FCanvasTextureInfo; - probe->Viewpoint = viewpoint; - probe->Texture = texture; - probe->PicNum = picnum; - probe->FOV = fov; - probe->Next = List; - texture->bFirstUpdate = true; - List = probe; -} - -// [ZZ] expose this to ZScript -void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov) -{ - FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable); - if (textureid.isValid()) - { - // Only proceed if the texture actually has a canvas. - FTexture *tex = TexMan[textureid]; - if (tex && tex->bHasCanvas) - { - FCanvasTextureInfo::Add(viewpoint, textureid, fov); - } - } -} - -DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(viewpoint, AActor); - PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. - PARAM_FLOAT(fov); - SetCameraToTexture(viewpoint, texturename, fov); - return 0; -} - -//========================================================================== -// -// FCanvasTextureInfo :: UpdateAll -// -// Updates all canvas textures that were visible in the last frame. -// -//========================================================================== - -void FCanvasTextureInfo::UpdateAll () -{ - FCanvasTextureInfo *probe; - - for (probe = List; probe != NULL; probe = probe->Next) - { - if (probe->Viewpoint != NULL && probe->Texture->bNeedsUpdate) - { - screen->RenderTextureView(probe->Texture, probe->Viewpoint, probe->FOV); - } - } -} - -//========================================================================== -// -// FCanvasTextureInfo :: EmptyList -// -// Removes all camera->texture assignments. -// -//========================================================================== - -void FCanvasTextureInfo::EmptyList () -{ - FCanvasTextureInfo *probe, *next; - - for (probe = List; probe != NULL; probe = next) - { - next = probe->Next; - probe->Texture->Unload(); - delete probe; - } - List = NULL; -} - -//========================================================================== -// -// FCanvasTextureInfo :: Serialize -// -// Reads or writes the current set of mappings in an archive. -// -//========================================================================== - -void FCanvasTextureInfo::Serialize(FSerializer &arc) -{ - if (arc.isWriting()) - { - if (List != nullptr) - { - if (arc.BeginArray("canvastextures")) - { - FCanvasTextureInfo *probe; - - for (probe = List; probe != nullptr; probe = probe->Next) - { - if (probe->Texture != nullptr && probe->Viewpoint != nullptr) - { - if (arc.BeginObject(nullptr)) - { - arc("viewpoint", probe->Viewpoint) - ("fov", probe->FOV) - ("texture", probe->PicNum) - .EndObject(); - } - } - } - arc.EndArray(); - } - } - } - else - { - if (arc.BeginArray("canvastextures")) - { - AActor *viewpoint = nullptr; - double fov; - FTextureID picnum; - while (arc.BeginObject(nullptr)) - { - arc("viewpoint", viewpoint) - ("fov", fov) - ("texture", picnum) - .EndObject(); - Add(viewpoint, picnum, fov); - } - arc.EndArray(); - } - } -} - -//========================================================================== -// -// FCanvasTextureInfo :: Mark -// -// Marks all viewpoints in the list for the collector. -// -//========================================================================== - -void FCanvasTextureInfo::Mark() -{ - for (FCanvasTextureInfo *probe = List; probe != NULL; probe = probe->Next) - { - GC::Mark(probe->Viewpoint); - } -} - - //========================================================================== // // CVAR transsouls diff --git a/src/r_utility.h b/src/r_utility.h index e5ac4a2b8..1eb93096a 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -138,25 +138,5 @@ double R_ClampVisibility(double vis); extern void R_FreePastViewers (); extern void R_ClearPastViewer (AActor *actor); -class FCanvasTexture; -// This list keeps track of the cameras that draw into canvas textures. -struct FCanvasTextureInfo -{ - FCanvasTextureInfo *Next; - TObjPtr Viewpoint; - FCanvasTexture *Texture; - FTextureID PicNum; - double FOV; - - static void Add (AActor *viewpoint, FTextureID picnum, double fov); - static void UpdateAll (); - static void EmptyList (); - static void Serialize(FSerializer &arc); - static void Mark(); - -private: - static FCanvasTextureInfo *List; -}; - #endif diff --git a/src/r_videoscale.cpp b/src/r_videoscale.cpp index 9918def62..95f788135 100644 --- a/src/r_videoscale.cpp +++ b/src/r_videoscale.cpp @@ -78,7 +78,7 @@ namespace } void R_ShowCurrentScaling(); -CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { setsizeneeded = true; if (self < 0.05 || self > 2.0) diff --git a/src/resourcefiles/file_pak.cpp b/src/resourcefiles/file_pak.cpp index d7f091c02..f679a0564 100644 --- a/src/resourcefiles/file_pak.cpp +++ b/src/resourcefiles/file_pak.cpp @@ -96,9 +96,9 @@ bool FPakFile::Open(bool quiet) NumLumps = LittleLong(header.dirlen) / sizeof(dpackfile_t); header.dirofs = LittleLong(header.dirofs); - dpackfile_t *fileinfo = new dpackfile_t[NumLumps]; + TArray fileinfo(NumLumps, true); Reader.Seek (header.dirofs, FileReader::SeekSet); - Reader.Read (fileinfo, NumLumps * sizeof(dpackfile_t)); + Reader.Read (fileinfo.Data(), NumLumps * sizeof(dpackfile_t)); Lumps.Resize(NumLumps); @@ -113,7 +113,6 @@ bool FPakFile::Open(bool quiet) Lumps[i].CheckEmbedded(); } - delete [] fileinfo; return true; } diff --git a/src/sc_man.cpp b/src/sc_man.cpp index 7eb6b3c3a..f1b9b9267 100644 --- a/src/sc_man.cpp +++ b/src/sc_man.cpp @@ -1120,7 +1120,7 @@ void FScanner::ScriptMessage (const char *message, ...) va_end (arglist); } - Printf (TEXTCOLOR_RED "Script error, \"%s\" line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + Printf (TEXTCOLOR_RED "Script error, \"%s\"" TEXTCOLOR_RED "line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); } diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 0eecab9a9..db87134dd 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -7600,7 +7600,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx) if (ctx.Class != nullptr) { - PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error); + PFunction *afd = FindClassMemberFunction(ctx.Class, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version); if (afd != nullptr) { @@ -8002,7 +8002,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) if (novirtual) { bool error; - PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error); + PFunction *afd = FindClassMemberFunction(ccls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version); if ((nullptr != afd) && (afd->Variants[0].Flags & VARF_Method) && (afd->Variants[0].Flags & VARF_Virtual)) { staticonly = false; @@ -8309,7 +8309,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) isresolved: bool error = false; - PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error); + PFunction *afd = FindClassMemberFunction(cls, ctx.Class, MethodName, ScriptPosition, &error, ctx.Version); if (error) { delete this; diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index 3876f9626..4140b9d9b 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -2104,6 +2104,7 @@ public: : FxExpression(EFX_Nop, p) { isresolved = true; + ValueType = TypeError; } ExpEmit Emit(VMFunctionBuilder *build) { diff --git a/src/scripting/backend/dynarrays.cpp b/src/scripting/backend/dynarrays.cpp index 15b016166..147ab89f8 100644 --- a/src/scripting/backend/dynarrays.cpp +++ b/src/scripting/backend/dynarrays.cpp @@ -121,9 +121,9 @@ template void ArrayResize(T *self, int amount) } } -template void ArrayReserve(T *self, int amount) +template unsigned int ArrayReserve(T *self, int amount) { - self->Reserve(amount); + return self->Reserve(amount); } template int ArrayMax(T *self) diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index 928f645a8..439bf8ce8 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -236,7 +236,7 @@ PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *retur // //========================================================================== -PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error) +PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error, const VersionInfo &version) { // Skip ACS_NamedExecuteWithResult. Anything calling this should use the builtin instead. if (name == NAME_ACS_NamedExecuteWithResult) return nullptr; @@ -263,7 +263,7 @@ PFunction *FindClassMemberFunction(PContainerType *selfcls, PContainerType *func { sc.Message(MSG_ERROR, "%s is declared protected and not accessible", symbol->SymbolName.GetChars()); } - else if (funcsym->Variants[0].Flags & VARF_Deprecated) + else if ((funcsym->Variants[0].Flags & VARF_Deprecated) && funcsym->mVersion <= version) { sc.Message(MSG_WARNING, "Call to deprecated function %s", symbol->SymbolName.GetChars()); } diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 844e38957..6e6737282 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -204,7 +204,7 @@ class FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestr FName CheckCastKludges(FName in); void SetImplicitArgs(TArray *args, TArray *argflags, TArray *argnames, PContainerType *cls, uint32_t funcflags, int useflags); PFunction *CreateAnonymousFunction(PContainerType *containingclass, PType *returntype, int flags); -PFunction *FindClassMemberFunction(PContainerType *cls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error); +PFunction *FindClassMemberFunction(PContainerType *cls, PContainerType *funccls, FName name, FScriptPosition &sc, bool *error, const VersionInfo &version); void CreateDamageFunction(PNamespace *ns, const VersionInfo &ver, PClassActor *info, AActor *defaults, FxExpression *id, bool fromDecorate, int lumpnum); //========================================================================== diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index f62ad91b7..d54684a48 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -729,7 +729,6 @@ DEFINE_PROPERTY(translation, L, Actor) else { FRemapTable CurrentTranslation; - bool success = true; CurrentTranslation.MakeIdentity(); for(int i = 1; i < PROP_PARM_COUNT; i++) @@ -744,14 +743,17 @@ DEFINE_PROPERTY(translation, L, Actor) else { // parse all ranges to get a complete list of errors, if more than one range fails. - success |= CurrentTranslation.AddToTranslation(str); + try + { + CurrentTranslation.AddToTranslation(str); + } + catch (CRecoverableError &err) + { + bag.ScriptPosition.Message(MSG_WARNING, "Error in translation '%s':\n" TEXTCOLOR_CYAN "%s\n", str, err.GetMessage()); + } } } defaults->Translation = CurrentTranslation.StoreTranslation (TRANSLATION_Decorate); - if (!success) - { - bag.ScriptPosition.Message(MSG_WARNING, "Failed to parse translation"); - } } } diff --git a/src/scripting/vm/jit.cpp b/src/scripting/vm/jit.cpp index 6aacc4bf1..319130aa4 100644 --- a/src/scripting/vm/jit.cpp +++ b/src/scripting/vm/jit.cpp @@ -268,7 +268,7 @@ void JitCompiler::SetupSimpleFrame() for (unsigned int i = 0; i < sfunc->Proto->ArgumentTypes.Size(); i++) { const PType *type = sfunc->Proto->ArgumentTypes[i]; - if (sfunc->ArgFlags[i] & (VARF_Out | VARF_Ref)) + if (sfunc->ArgFlags.Size() && sfunc->ArgFlags[i] & (VARF_Out | VARF_Ref)) { cc.mov(regA[rega++], x86::ptr(args, argsPos++ * sizeof(VMValue) + offsetof(VMValue, a))); } diff --git a/src/scripting/vm/jit_flow.cpp b/src/scripting/vm/jit_flow.cpp index 08e7b0660..0ca8bf437 100644 --- a/src/scripting/vm/jit_flow.cpp +++ b/src/scripting/vm/jit_flow.cpp @@ -169,16 +169,28 @@ void JitCompiler::EmitRET() if (cc.is64Bit()) { if (regtype & REGT_KONST) - cc.mov(x86::qword_ptr(location), asmjit::imm_ptr(konsta[regnum].v)); + { + auto ptr = newTempIntPtr(); + cc.mov(ptr, asmjit::imm_ptr(konsta[regnum].v)); + cc.mov(x86::qword_ptr(location), ptr); + } else + { cc.mov(x86::qword_ptr(location), regA[regnum]); + } } else { if (regtype & REGT_KONST) - cc.mov(x86::dword_ptr(location), asmjit::imm_ptr(konsta[regnum].v)); + { + auto ptr = newTempIntPtr(); + cc.mov(ptr, asmjit::imm_ptr(konsta[regnum].v)); + cc.mov(x86::dword_ptr(location), ptr); + } else + { cc.mov(x86::dword_ptr(location), regA[regnum]); + } } break; } diff --git a/src/scripting/vm/jit_move.cpp b/src/scripting/vm/jit_move.cpp index b8953b2aa..54c055cb2 100644 --- a/src/scripting/vm/jit_move.cpp +++ b/src/scripting/vm/jit_move.cpp @@ -53,7 +53,7 @@ static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %0 static int CastS2So(FString *b) { return FSoundID(*b); } static void CastSo2S(FString *a, int b) { *a = S_sfx[b].name; } static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; } -static void CastTID2S(FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); } +static void CastTID2S(FString *a, int b) { auto tex = TexMan.GetTexture(*(FTextureID*)&b); *a = (tex == nullptr) ? "(null)" : tex->GetName().GetChars(); } void JitCompiler::EmitCAST() { diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 59fbc7afc..97996376d 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -1874,8 +1874,8 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c case CAST_TID2S: { ASSERTS(a); ASSERTD(b); - auto tex = TexMan[*(FTextureID*)&(reg.d[b])]; - reg.s[a] = tex == nullptr ? "(null)" : tex->Name.GetChars(); + auto tex = TexMan.GetTexture(*(FTextureID*)&(reg.d[b])); + reg.s[a] = tex == nullptr ? "(null)" : tex->GetName().GetChars(); break; } diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 1bafaf84a..ad44203b1 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -1584,6 +1584,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, ReplaceTextures, ReplaceTextures) return 0; } +void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fov); + +DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraToTexture, SetCameraToTexture) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(viewpoint, AActor); + PARAM_STRING(texturename); // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it. + PARAM_FLOAT(fov); + SetCameraToTexture(viewpoint, texturename, fov); + return 0; +} + + //===================================================================================== // // secplane_t exports @@ -2372,7 +2385,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, ReceivedWeapon, ReceivedWeapon) static int GetMugshot(DBaseStatusBar *self, int accuracy, int stateflags, const FString &def_face) { auto tex = self->mugshot.GetFace(self->CPlayer, def_face, accuracy, (FMugShot::StateFlags)stateflags); - return (tex ? tex->id.GetIndex() : -1); + return (tex ? tex->GetID().GetIndex() : -1); } DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetMugshot, GetMugshot) diff --git a/src/serializer.cpp b/src/serializer.cpp index e0f74420f..535c739e7 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -1515,7 +1515,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe } FTextureID chk = value; if (chk.GetIndex() >= TexMan.NumTextures()) chk.SetNull(); - FTexture *pic = TexMan[chk]; + FTexture *pic = TexMan.GetTexture(chk); const char *name; if (Wads.GetLinkedTexture(pic->SourceLump) == pic) @@ -1545,7 +1545,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe assert(nameval.IsString() && typeval.IsInt()); if (nameval.IsString() && typeval.IsInt()) { - value = TexMan.GetTexture(UnicodeToString(nameval.GetString()), static_cast(typeval.GetInt())); + value = TexMan.GetTextureID(UnicodeToString(nameval.GetString()), static_cast(typeval.GetInt())); } else { diff --git a/src/sound/mididevices/music_win_mididevice.cpp b/src/sound/mididevices/music_win_mididevice.cpp index f9820033f..b6ddd46a2 100644 --- a/src/sound/mididevices/music_win_mididevice.cpp +++ b/src/sound/mididevices/music_win_mididevice.cpp @@ -198,6 +198,10 @@ int WinMIDIDevice::Open(MidiCallback callback, void *userdata) } } } + else + { + return 1; + } } return 0; } diff --git a/src/swrenderer/drawers/r_draw_pal.cpp b/src/swrenderer/drawers/r_draw_pal.cpp index b9501d157..9af01cffb 100644 --- a/src/swrenderer/drawers/r_draw_pal.cpp +++ b/src/swrenderer/drawers/r_draw_pal.cpp @@ -551,7 +551,6 @@ namespace swrenderer void DrawSingleSky1PalCommand::Execute(DrawerThread *thread) { uint8_t *dest = args.Dest(); - int count = args.Count(); int pitch = args.Viewport()->RenderTarget->GetPitch(); const uint8_t *source0 = args.FrontTexturePixels(); int textureheight0 = args.FrontTextureHeight(); @@ -559,6 +558,25 @@ namespace swrenderer int32_t frac = args.TextureVPos(); int32_t fracstep = args.TextureVStep(); + if (!args.FadeSky()) + { + int count = thread->count_for_thread(args.DestY(), args.Count()); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + *dest = source0[sample_index]; + dest += pitch; + frac += fracstep; + } + + return; + } + + int num_cores = thread->num_cores; + int skipped = thread->skipped_by_thread(args.DestY()); + int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out int fade_length = (1 << (24 - start_fade)); @@ -571,28 +589,11 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); dest = thread->dest_for_thread(args.DestY(), pitch, dest); frac += fracstep * skipped; fracstep *= num_cores; pitch *= num_cores; - if (!args.FadeSky()) - { - count = thread->count_for_thread(args.DestY(), count); - - for (int index = 0; index < count; index++) - { - uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; - *dest = source0[sample_index]; - dest += pitch; - frac += fracstep; - } - - return; - } - uint32_t solid_top = args.SolidTopColor(); uint32_t solid_bottom = args.SolidBottomColor(); diff --git a/src/swrenderer/drawers/r_draw_sky32.h b/src/swrenderer/drawers/r_draw_sky32.h index 59c8826fa..864002446 100644 --- a/src/swrenderer/drawers/r_draw_sky32.h +++ b/src/swrenderer/drawers/r_draw_sky32.h @@ -39,7 +39,6 @@ namespace swrenderer void Execute(DrawerThread *thread) override { uint32_t *dest = (uint32_t *)args.Dest(); - int count = args.Count(); int pitch = args.Viewport()->RenderTarget->GetPitch(); const uint32_t *source0 = (const uint32_t *)args.FrontTexturePixels(); int textureheight0 = args.FrontTextureHeight(); @@ -51,6 +50,25 @@ namespace swrenderer uint32_t solid_bottom = args.SolidBottomColor(); bool fadeSky = args.FadeSky(); + if (!fadeSky) + { + int count = thread->count_for_thread(args.DestY(), args.Count()); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + *dest = source0[sample_index]; + dest += pitch; + frac += fracstep; + } + + return; + } + + int num_cores = thread->num_cores; + int skipped = thread->skipped_by_thread(args.DestY()); + int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out int fade_length = (1 << (24 - start_fade)); @@ -63,28 +81,11 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); dest = thread->dest_for_thread(args.DestY(), pitch, dest); frac += fracstep * skipped; fracstep *= num_cores; pitch *= num_cores; - if (!fadeSky) - { - count = thread->count_for_thread(args.DestY(), count); - - for (int index = 0; index < count; index++) - { - uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; - *dest = source0[sample_index]; - dest += pitch; - frac += fracstep; - } - - return; - } - BgraColor solid_top_fill = solid_top; BgraColor solid_bottom_fill = solid_bottom; diff --git a/src/swrenderer/drawers/r_draw_sky32_sse2.h b/src/swrenderer/drawers/r_draw_sky32_sse2.h index 401d5bad1..56fd50300 100644 --- a/src/swrenderer/drawers/r_draw_sky32_sse2.h +++ b/src/swrenderer/drawers/r_draw_sky32_sse2.h @@ -38,7 +38,6 @@ namespace swrenderer void Execute(DrawerThread *thread) override { uint32_t *dest = (uint32_t *)args.Dest(); - int count = args.Count(); int pitch = args.Viewport()->RenderTarget->GetPitch(); const uint32_t *source0 = (const uint32_t *)args.FrontTexturePixels(); int textureheight0 = args.FrontTextureHeight(); @@ -50,6 +49,25 @@ namespace swrenderer uint32_t solid_bottom = args.SolidBottomColor(); bool fadeSky = args.FadeSky(); + if (!fadeSky) + { + int count = thread->count_for_thread(args.DestY(), args.Count()); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + *dest = source0[sample_index]; + dest += pitch; + frac += fracstep; + } + + return; + } + + int num_cores = thread->num_cores; + int skipped = thread->skipped_by_thread(args.DestY()); + int count = skipped + thread->count_for_thread(args.DestY(), args.Count()) * num_cores; + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out int fade_length = (1 << (24 - start_fade)); @@ -62,28 +80,11 @@ namespace swrenderer start_fadebottom_y = clamp(start_fadebottom_y, 0, count); end_fadebottom_y = clamp(end_fadebottom_y, 0, count); - int num_cores = thread->num_cores; - int skipped = thread->skipped_by_thread(args.DestY()); dest = thread->dest_for_thread(args.DestY(), pitch, dest); frac += fracstep * skipped; fracstep *= num_cores; pitch *= num_cores; - if (!fadeSky) - { - count = thread->count_for_thread(args.DestY(), count); - - for (int index = 0; index < count; index++) - { - uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; - *dest = source0[sample_index]; - dest += pitch; - frac += fracstep; - } - - return; - } - __m128i solid_top_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_top), _mm_setzero_si128()); __m128i solid_bottom_fill = _mm_unpacklo_epi8(_mm_cvtsi32_si128(solid_bottom), _mm_setzero_si128()); diff --git a/src/swrenderer/drawers/r_thread.cpp b/src/swrenderer/drawers/r_thread.cpp index 31a6f1915..5aa157f27 100644 --- a/src/swrenderer/drawers/r_thread.cpp +++ b/src/swrenderer/drawers/r_thread.cpp @@ -140,6 +140,8 @@ void DrawerThreads::WorkerMain(DrawerThread *thread) // Grab the commands DrawerCommandQueuePtr list = active_commands[thread->current_queue]; thread->current_queue++; + thread->numa_start_y = thread->numa_node * viewheight / thread->num_numa_nodes; + thread->numa_end_y = (thread->numa_node + 1) * viewheight / thread->num_numa_nodes; start_lock.unlock(); // Do the work: @@ -206,8 +208,6 @@ void DrawerThreads::StartThreads() thread->num_cores = I_GetNumaNodeThreadCount(numaNode); thread->numa_node = numaNode; thread->num_numa_nodes = I_GetNumaNodeCount(); - thread->numa_start_y = numaNode * viewheight / I_GetNumaNodeCount(); - thread->numa_end_y = (numaNode + 1) * viewheight / I_GetNumaNodeCount(); thread->thread = std::thread([=]() { queue->WorkerMain(thread); }); I_SetThreadNumaNode(thread->thread, numaNode); } @@ -223,8 +223,6 @@ void DrawerThreads::StartThreads() thread->num_cores = num_threads; thread->numa_node = 0; thread->num_numa_nodes = 1; - thread->numa_start_y = 0; - thread->numa_end_y = viewheight; thread->thread = std::thread([=]() { queue->WorkerMain(thread); }); I_SetThreadNumaNode(thread->thread, 0); } @@ -288,7 +286,4 @@ void MemcpyCommand::Execute(DrawerThread *thread) d += dstep; s += sstep; } - - thread->numa_start_y = thread->numa_node * viewheight / thread->num_numa_nodes; - thread->numa_end_y = (thread->numa_node + 1) * viewheight / thread->num_numa_nodes; } diff --git a/src/swrenderer/line/r_fogboundary.cpp b/src/swrenderer/line/r_fogboundary.cpp index 1b8f1c99d..ae222200c 100644 --- a/src/swrenderer/line/r_fogboundary.cpp +++ b/src/swrenderer/line/r_fogboundary.cpp @@ -54,12 +54,13 @@ namespace swrenderer { - void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int wallshade, float lightleft, float lightstep, FDynamicColormap *basecolormap) + void RenderFogBoundary::Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int lightlevel, bool foggy, float lightleft, float lightstep, FDynamicColormap *basecolormap) { // This is essentially the same as R_MapVisPlane but with an extra step // to create new horizontal spans whenever the light changes enough that // we need to use a new colormap. + int wallshade = LightVisibility::LightLevelToShade(lightlevel, foggy, thread->Viewport.get()); float light = lightleft + lightstep*(x2 - x1 - 1); int x = x2 - 1; int t2 = uclip[x]; @@ -73,7 +74,7 @@ namespace swrenderer fillshort(spanend + t2, b2 - t2, x); } - drawerargs.SetLight(basecolormap, (float)light, wallshade); + drawerargs.SetLight(basecolormap, (float)light, lightlevel, foggy, thread->Viewport.get()); uint8_t *fake_dc_colormap = basecolormap->Maps + (GETPALOOKUP(light, wallshade) << COLORMAPSHIFT); diff --git a/src/swrenderer/line/r_fogboundary.h b/src/swrenderer/line/r_fogboundary.h index b506ec7f8..3da57d583 100644 --- a/src/swrenderer/line/r_fogboundary.h +++ b/src/swrenderer/line/r_fogboundary.h @@ -31,7 +31,7 @@ namespace swrenderer class RenderFogBoundary { public: - void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int wallshade, float lightleft, float lightstep, FDynamicColormap *basecolormap); + void Render(RenderThread *thread, int x1, int x2, const short *uclip, const short *dclip, int lightlevel, bool foggy, float lightleft, float lightstep, FDynamicColormap *basecolormap); private: void RenderSection(RenderThread *thread, int y, int y2, int x1); diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp index 77ac90f5b..a3af39bb6 100644 --- a/src/swrenderer/line/r_line.cpp +++ b/src/swrenderer/line/r_line.cpp @@ -425,7 +425,7 @@ namespace swrenderer if (!onlyUpdatePlaneClip) // allocate space for masked texture tables, if needed // [RH] Don't just allocate the space; fill it in too. - if ((TexMan(sidedef->GetTexture(side_t::mid), true)->UseType != ETextureType::Null || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) && + if ((sidedef->GetTexture(side_t::mid).isValid() || draw_segment->Has3DFloorWalls() || IsFogBoundary(mFrontSector, mBackSector)) && (mCeilingClipped != ProjectedWallCull::OutsideBelow || !sidedef->GetTexture(side_t::top).isValid()) && (mFloorClipped != ProjectedWallCull::OutsideAbove || !sidedef->GetTexture(side_t::bottom).isValid()) && (WallC.sz1 >= TOO_CLOSE_Z && WallC.sz2 >= TOO_CLOSE_Z)) @@ -451,11 +451,12 @@ namespace swrenderer lwal = draw_segment->maskedtexturecol; swal = draw_segment->swall; - FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true); - double yscale = pic->Scale.Y * sidedef->GetTextureYScale(side_t::mid); + FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); + FSoftwareTexture *pic = tex && tex->isValid()? tex->GetSoftwareTexture() : nullptr; + double yscale = (pic? pic->GetScale().Y : 1.0) * sidedef->GetTextureYScale(side_t::mid); fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); - if (pic->bWorldPanning) + if (pic && pic->useWorldPanning()) { xoffset = xs_RoundToInt(xoffset * lwallscale); } @@ -493,16 +494,16 @@ namespace swrenderer draw_segment->lightstep = rw_lightstep; // Masked mMiddlePart.Textures should get the light level from the sector they reference, - // not from the current subsector, which is what the current wallshade value + // not from the current subsector, which is what the current lightlevel value // comes from. We make an exeption for polyobjects, however, since their "home" // sector should be whichever one they move into. if (mLineSegment->sidedef->Flags & WALLF_POLYOBJ) { - draw_segment->shade = wallshade; + draw_segment->lightlevel = lightlevel; } else { - draw_segment->shade = LightVisibility::LightLevelToShade(mLineSegment->sidedef->GetLightLevel(foggy, mLineSegment->frontsector->lightlevel) + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); + draw_segment->lightlevel = mLineSegment->sidedef->GetLightLevel(foggy, mLineSegment->frontsector->lightlevel); } if (draw_segment->bFogBoundary || draw_segment->maskedtexturecol != nullptr) @@ -551,7 +552,7 @@ namespace swrenderer // [ZZ] Only if not an active mirror if (!markportal) { - RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, wallshade, rw_lightleft, rw_lightstep, mLineSegment, WallC, foggy, basecolormap, walltop.ScreenY, wallbottom.ScreenY, false); + RenderDecal::RenderDecals(Thread, mLineSegment->sidedef, draw_segment, lightlevel, rw_lightleft, rw_lightstep, mLineSegment, WallC, foggy, basecolormap, walltop.ScreenY, wallbottom.ScreenY, false); } if (markportal) @@ -769,17 +770,18 @@ namespace swrenderer } } - FTexture *midtex = TexMan(sidedef->GetTexture(side_t::mid), true); + FTexture *ftex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); + FSoftwareTexture *midtex = ftex && ftex->isValid() ? ftex->GetSoftwareTexture() : nullptr; - bool segtextured = midtex != NULL || mTopPart.Texture != NULL || mBottomPart.Texture != NULL; + bool segtextured = ftex != NULL || mTopPart.Texture != NULL || mBottomPart.Texture != NULL; // calculate light table if (needlights && (segtextured || (mBackSector && IsFogBoundary(mFrontSector, mBackSector)))) { lwallscale = - midtex ? (midtex->Scale.X * sidedef->GetTextureXScale(side_t::mid)) : - mTopPart.Texture ? (mTopPart.Texture->Scale.X * sidedef->GetTextureXScale(side_t::top)) : - mBottomPart.Texture ? (mBottomPart.Texture->Scale.X * sidedef->GetTextureXScale(side_t::bottom)) : + ftex ? ((midtex? midtex->GetScale().X : 1.0) * sidedef->GetTextureXScale(side_t::mid)) : + mTopPart.Texture ? (mTopPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::top)) : + mBottomPart.Texture ? (mBottomPart.Texture->GetScale().X * sidedef->GetTextureXScale(side_t::bottom)) : 1.; walltexcoords.Project(Thread->Viewport.get(), sidedef->TexelLength * lwallscale, WallC.sx1, WallC.sx2, WallT); @@ -787,10 +789,9 @@ namespace swrenderer CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0) { - wallshade = LightVisibility::LightLevelToShade(mLineSegment->sidedef->GetLightLevel(foggy, mFrontSector->lightlevel) + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); - double GlobVis = Thread->Light->WallGlobVis(foggy); - rw_lightleft = float(GlobVis / WallC.sz1); - rw_lightstep = float((GlobVis / WallC.sz2 - rw_lightleft) / (WallC.sx2 - WallC.sx1)); + lightlevel = mLineSegment->sidedef->GetLightLevel(foggy, mFrontSector->lightlevel); + rw_lightleft = float(Thread->Light->WallVis(WallC.sz1, foggy)); + rw_lightstep = float((Thread->Light->WallVis(WallC.sz2, foggy) - rw_lightleft) / (WallC.sx2 - WallC.sx1)); } else { @@ -814,13 +815,15 @@ namespace swrenderer // No top texture for skyhack lines if (mFrontSector->GetTexture(sector_t::ceiling) == skyflatnum && mBackSector->GetTexture(sector_t::ceiling) == skyflatnum) return; - mTopPart.Texture = TexMan(sidedef->GetTexture(side_t::top), true); + FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::top), true); + mTopPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + if (mTopPart.Texture == nullptr) return; mTopPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::top)); double rowoffset = sidedef->GetTextureYOffset(side_t::top); mTopPart.TextureScaleU = sidedef->GetTextureXScale(side_t::top); mTopPart.TextureScaleV = sidedef->GetTextureYScale(side_t::top); - double yrepeat = mTopPart.Texture->Scale.Y * mTopPart.TextureScaleV; + double yrepeat = mTopPart.Texture->GetScale().Y * mTopPart.TextureScaleV; if (yrepeat >= 0) { // normal orientation if (linedef->flags & ML_DONTPEGTOP) @@ -848,7 +851,7 @@ namespace swrenderer mTopPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat; } } - if (mTopPart.Texture->bWorldPanning) + if (mTopPart.Texture->useWorldPanning()) { mTopPart.TextureMid += rowoffset * yrepeat; } @@ -871,12 +874,14 @@ namespace swrenderer if (linedef->isVisualPortal()) return; if (linedef->special == Line_Horizon) return; - mMiddlePart.Texture = TexMan(sidedef->GetTexture(side_t::mid), true); + auto tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::mid), true); + mMiddlePart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + if (mMiddlePart.Texture == nullptr) return; mMiddlePart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); double rowoffset = sidedef->GetTextureYOffset(side_t::mid); mMiddlePart.TextureScaleU = sidedef->GetTextureXScale(side_t::mid); mMiddlePart.TextureScaleV = sidedef->GetTextureYScale(side_t::mid); - double yrepeat = mMiddlePart.Texture->Scale.Y * mMiddlePart.TextureScaleV; + double yrepeat = mMiddlePart.Texture->GetScale().Y * mMiddlePart.TextureScaleV; if (yrepeat >= 0) { // normal orientation if (linedef->flags & ML_DONTPEGBOTTOM) @@ -904,7 +909,7 @@ namespace swrenderer mMiddlePart.TextureMid = (mFrontSector->GetPlaneTexZ(sector_t::ceiling) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mMiddlePart.Texture->GetHeight(); } } - if (mMiddlePart.Texture->bWorldPanning) + if (mMiddlePart.Texture->useWorldPanning()) { mMiddlePart.TextureMid += rowoffset * yrepeat; } @@ -935,13 +940,15 @@ namespace swrenderer frontlowertop = mBackSector->GetPlaneTexZ(sector_t::ceiling); } - mBottomPart.Texture = TexMan(sidedef->GetTexture(side_t::bottom), true); + FTexture *tex = TexMan.GetPalettedTexture(sidedef->GetTexture(side_t::bottom), true); + mBottomPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr; + if (!mBottomPart.Texture) return; mBottomPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::bottom)); double rowoffset = sidedef->GetTextureYOffset(side_t::bottom); mBottomPart.TextureScaleU = sidedef->GetTextureXScale(side_t::bottom); mBottomPart.TextureScaleV = sidedef->GetTextureYScale(side_t::bottom); - double yrepeat = mBottomPart.Texture->Scale.Y * mBottomPart.TextureScaleV; + double yrepeat = mBottomPart.Texture->GetScale().Y * mBottomPart.TextureScaleV; if (yrepeat >= 0) { // normal orientation if (linedef->flags & ML_DONTPEGBOTTOM) @@ -969,7 +976,7 @@ namespace swrenderer mBottomPart.TextureMid = (mBackSector->GetPlaneTexZ(sector_t::floor) - Thread->Viewport->viewpoint.Pos.Z) * yrepeat + mBottomPart.Texture->GetHeight(); } } - if (mBottomPart.Texture->bWorldPanning) + if (mBottomPart.Texture->useWorldPanning()) { mBottomPart.TextureMid += rowoffset * yrepeat; } @@ -1101,7 +1108,7 @@ namespace swrenderer } else { // two sided line - if (mTopPart.Texture != NULL && mTopPart.Texture->UseType != ETextureType::Null) + if (mTopPart.Texture != nullptr) { // top wall for (int x = x1; x < x2; ++x) { @@ -1114,7 +1121,7 @@ namespace swrenderer memcpy(ceilingclip + x1, walltop.ScreenY + x1, (x2 - x1) * sizeof(short)); } - if (mBottomPart.Texture != NULL && mBottomPart.Texture->UseType != ETextureType::Null) + if (mBottomPart.Texture != nullptr) { // bottom wall for (int x = x1; x < x2; ++x) { @@ -1132,19 +1139,19 @@ namespace swrenderer void SWRenderLine::RenderTopTexture(int x1, int x2) { if (mMiddlePart.Texture) return; - if (!mTopPart.Texture || mTopPart.Texture->UseType == ETextureType::Null) return; + if (!mTopPart.Texture) return; if (!viewactive) return; - FTexture *rw_pic = mTopPart.Texture; - double xscale = rw_pic->Scale.X * mTopPart.TextureScaleU; - double yscale = rw_pic->Scale.Y * mTopPart.TextureScaleV; + auto rw_pic = mTopPart.Texture; + double xscale = rw_pic->GetScale().X * mTopPart.TextureScaleU; + double yscale = rw_pic->GetScale().Y * mTopPart.TextureScaleV; if (xscale != lwallscale) { walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT); lwallscale = xscale; } fixed_t offset; - if (mTopPart.Texture->bWorldPanning) + if (mTopPart.Texture->useWorldPanning()) { offset = xs_RoundToInt(mTopPart.TextureOffsetU * xscale); } @@ -1174,24 +1181,24 @@ namespace swrenderer light_list = nullptr; // [SP] Don't draw dynlights if invul/lightamp active RenderWallPart renderWallpart(Thread); - renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallupper.ScreenY, mTopPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, wallshade, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); + renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallupper.ScreenY, mTopPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mBackCeilingZ1, mBackCeilingZ2), false, lightlevel, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); } void SWRenderLine::RenderMiddleTexture(int x1, int x2) { - if (!mMiddlePart.Texture || mMiddlePart.Texture->UseType == ETextureType::Null) return; + if (!mMiddlePart.Texture) return; if (!viewactive) return; - FTexture *rw_pic = mMiddlePart.Texture; - double xscale = rw_pic->Scale.X * mMiddlePart.TextureScaleU; - double yscale = rw_pic->Scale.Y * mMiddlePart.TextureScaleV; + auto rw_pic = mMiddlePart.Texture; + double xscale = rw_pic->GetScale().X * mMiddlePart.TextureScaleU; + double yscale = rw_pic->GetScale().Y * mMiddlePart.TextureScaleV; if (xscale != lwallscale) { walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT); lwallscale = xscale; } fixed_t offset; - if (mMiddlePart.Texture->bWorldPanning) + if (mMiddlePart.Texture->useWorldPanning()) { offset = xs_RoundToInt(mMiddlePart.TextureOffsetU * xscale); } @@ -1221,25 +1228,25 @@ namespace swrenderer light_list = nullptr; // [SP] Don't draw dynlights if invul/lightamp active RenderWallPart renderWallpart(Thread); - renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallbottom.ScreenY, mMiddlePart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, wallshade, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); + renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walltop.ScreenY, wallbottom.ScreenY, mMiddlePart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mFrontCeilingZ1, mFrontCeilingZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, lightlevel, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); } void SWRenderLine::RenderBottomTexture(int x1, int x2) { if (mMiddlePart.Texture) return; - if (!mBottomPart.Texture || mBottomPart.Texture->UseType == ETextureType::Null) return; + if (!mBottomPart.Texture) return; if (!viewactive) return; - FTexture *rw_pic = mBottomPart.Texture; - double xscale = rw_pic->Scale.X * mBottomPart.TextureScaleU; - double yscale = rw_pic->Scale.Y * mBottomPart.TextureScaleV; + auto rw_pic = mBottomPart.Texture; + double xscale = rw_pic->GetScale().X * mBottomPart.TextureScaleU; + double yscale = rw_pic->GetScale().Y * mBottomPart.TextureScaleV; if (xscale != lwallscale) { walltexcoords.ProjectPos(Thread->Viewport.get(), mLineSegment->sidedef->TexelLength*xscale, WallC.sx1, WallC.sx2, WallT); lwallscale = xscale; } fixed_t offset; - if (mBottomPart.Texture->bWorldPanning) + if (mBottomPart.Texture->useWorldPanning()) { offset = xs_RoundToInt(mBottomPart.TextureOffsetU * xscale); } @@ -1269,7 +1276,7 @@ namespace swrenderer light_list = nullptr; // [SP] Don't draw dynlights if invul/lightamp active RenderWallPart renderWallpart(Thread); - renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walllower.ScreenY, wallbottom.ScreenY, mBottomPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, wallshade, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); + renderWallpart.Render(drawerargs, mFrontSector, mLineSegment, WallC, rw_pic, x1, x2, walllower.ScreenY, wallbottom.ScreenY, mBottomPart.TextureMid, walltexcoords.VStep, walltexcoords.UPos, yscale, MAX(mBackFloorZ1, mBackFloorZ2), MIN(mFrontFloorZ1, mFrontFloorZ2), false, lightlevel, offset, rw_light, rw_lightstep, light_list, foggy, basecolormap); } //////////////////////////////////////////////////////////////////////////// diff --git a/src/swrenderer/line/r_line.h b/src/swrenderer/line/r_line.h index a76f4dc7c..0b7283fc0 100644 --- a/src/swrenderer/line/r_line.h +++ b/src/swrenderer/line/r_line.h @@ -65,7 +65,7 @@ namespace swrenderer double TextureMid; double TextureScaleU; double TextureScaleV; - FTexture *Texture; + FSoftwareTexture *Texture; }; class SWRenderLine : VisibleSegmentRenderer @@ -133,7 +133,7 @@ namespace swrenderer bool rw_prepped; - int wallshade; + int lightlevel; float rw_lightstep; float rw_lightleft; diff --git a/src/swrenderer/line/r_renderdrawsegment.cpp b/src/swrenderer/line/r_renderdrawsegment.cpp index fbc18b0c6..f1a11c454 100644 --- a/src/swrenderer/line/r_renderdrawsegment.cpp +++ b/src/swrenderer/line/r_renderdrawsegment.cpp @@ -97,7 +97,7 @@ namespace swrenderer FDynamicColormap *basecolormap = GetColorTable(sec->Colormap, sec->SpecialColors[sector_t::walltop]); // [RH] Set basecolormap - int wallshade = ds->shade; + int lightlevel = ds->lightlevel; rw_lightstep = ds->lightstep; rw_light = ds->light + (x1 - ds->x1) * rw_lightstep; @@ -113,8 +113,8 @@ namespace swrenderer { lightlist_t *lit = &frontsector->e->XFloor.lightlist[i]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); - bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr) + LightVisibility::ActualExtraLight(ds->foggy, viewport), foggy); + //bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag + lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr); break; } } @@ -129,7 +129,7 @@ namespace swrenderer const short *mceilingclip = ds->sprtopclip - ds->x1; RenderFogBoundary renderfog; - renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, wallshade, rw_light, rw_lightstep, basecolormap); + renderfog.Render(Thread, x1, x2, mceilingclip, mfloorclip, lightlevel, ds->foggy, rw_light, rw_lightstep, basecolormap); if (ds->maskedtexturecol == nullptr) renderwall = false; @@ -140,11 +140,11 @@ namespace swrenderer } if (renderwall) - notrelevant = RenderWall(ds, x1, x2, walldrawerargs, columndrawerargs, visible, basecolormap, wallshade); + notrelevant = RenderWall(ds, x1, x2, walldrawerargs, columndrawerargs, visible, basecolormap, lightlevel); if (ds->Has3DFloorFrontSectorWalls() || ds->Has3DFloorBackSectorWalls()) { - RenderFakeWallRange(ds, x1, x2, wallshade); + RenderFakeWallRange(ds, x1, x2); } if (!notrelevant) { @@ -153,7 +153,7 @@ namespace swrenderer } } - bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, WallDrawerArgs &walldrawerargs, SpriteDrawerArgs &columndrawerargs, bool visible, FDynamicColormap *basecolormap, int wallshade) + bool RenderDrawSegment::RenderWall(DrawSegment *ds, int x1, int x2, WallDrawerArgs &walldrawerargs, SpriteDrawerArgs &columndrawerargs, bool visible, FDynamicColormap *basecolormap, int lightlevel) { auto renderstyle = DefaultRenderStyle(); auto viewport = Thread->Viewport.get(); @@ -162,11 +162,12 @@ namespace swrenderer if (curline->sidedef->GetTexture(side_t::mid).isNull()) return false; - FTexture *tex = TexMan(curline->sidedef->GetTexture(side_t::mid), true); + FTexture *ttex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::mid), true); if (i_compatflags & COMPATF_MASKEDMIDTEX) { - tex = tex->GetRawTexture(); + ttex = ttex->GetRawTexture(); } + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); const short *mfloorclip = ds->sprbottomclip - ds->x1; const short *mceilingclip = ds->sprtopclip - ds->x1; @@ -221,7 +222,7 @@ namespace swrenderer MaskedScaleY = -MaskedScaleY; sprflipvert = true; } - if (tex->bWorldPanning) + if (tex->useWorldPanning()) { // rowoffset is added before the multiply so that the masked texture will // still be positioned in world units rather than texels. @@ -335,7 +336,7 @@ namespace swrenderer { if (cameraLight->FixedColormap() == nullptr && cameraLight->FixedLightLevel() < 0) { - columndrawerargs.SetLight(basecolormap, rw_light, wallshade); + columndrawerargs.SetLight(basecolormap, rw_light, lightlevel, ds->foggy, Thread->Viewport.get()); } fixed_t iscale = xs_Fix<16>::ToFix(MaskedSWall[x] * MaskedScaleY); @@ -354,7 +355,7 @@ namespace swrenderer } else { // Texture does wrap vertically. - if (tex->bWorldPanning) + if (tex->useWorldPanning()) { // rowoffset is added before the multiply so that the masked texture will // still be positioned in world units rather than texels. @@ -412,14 +413,14 @@ namespace swrenderer GetMaskedWallTopBottom(ds, top, bot); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(walldrawerargs, frontsector, curline, WallC, rw_pic, x1, x2, mceilingclip, mfloorclip, texturemid, MaskedSWall, maskedtexturecol, ds->yscale, top, bot, true, wallshade, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap); + renderWallpart.Render(walldrawerargs, frontsector, curline, WallC, rw_pic, x1, x2, mceilingclip, mfloorclip, texturemid, MaskedSWall, maskedtexturecol, ds->yscale, top, bot, true, lightlevel, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap); } return false; } // kg3D - render one fake wall - void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int wallshade, FDynamicColormap *basecolormap, double clipTop, double clipBottom) + void RenderDrawSegment::RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int lightlevel, FDynamicColormap *basecolormap, double clipTop, double clipBottom) { int i; double xscale; @@ -459,8 +460,8 @@ namespace swrenderer scaledside = rover->master->sidedef[0]; scaledpart = side_t::mid; } - xscale = rw_pic->Scale.X * scaledside->GetTextureXScale(scaledpart); - yscale = rw_pic->Scale.Y * scaledside->GetTextureYScale(scaledpart); + xscale = rw_pic->GetScale().X * scaledside->GetTextureXScale(scaledpart); + yscale = rw_pic->GetScale().Y * scaledside->GetTextureYScale(scaledpart); double rowoffset = curline->sidedef->GetTextureYOffset(side_t::mid) + rover->master->sidedef[0]->GetTextureYOffset(side_t::mid); double planez = rover->model->GetPlaneTexZ(sector_t::ceiling); @@ -470,7 +471,7 @@ namespace swrenderer rowoffset += rw_pic->GetHeight(); } double texturemid = (planez - Thread->Viewport->viewpoint.Pos.Z) * yscale; - if (rw_pic->bWorldPanning) + if (rw_pic->useWorldPanning()) { // rowoffset is added before the multiply so that the masked texture will // still be positioned in world units rather than texels. @@ -523,15 +524,15 @@ namespace swrenderer GetMaskedWallTopBottom(ds, top, bot); RenderWallPart renderWallpart(Thread); - renderWallpart.Render(drawerargs, frontsector, curline, WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, texturemid, MaskedSWall, walltexcoords.UPos, yscale, top, bot, true, wallshade, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap); + renderWallpart.Render(drawerargs, frontsector, curline, WallC, rw_pic, x1, x2, wallupper.ScreenY, walllower.ScreenY, texturemid, MaskedSWall, walltexcoords.UPos, yscale, top, bot, true, lightlevel, rw_offset, rw_light, rw_lightstep, nullptr, ds->foggy, basecolormap); - RenderDecal::RenderDecals(Thread, curline->sidedef, ds, wallshade, rw_light, rw_lightstep, curline, WallC, ds->foggy, basecolormap, wallupper.ScreenY, walllower.ScreenY, true); + RenderDecal::RenderDecals(Thread, curline->sidedef, ds, lightlevel, rw_light, rw_lightstep, curline, WallC, ds->foggy, basecolormap, wallupper.ScreenY, walllower.ScreenY, true); } // kg3D - walls of fake floors - void RenderDrawSegment::RenderFakeWallRange(DrawSegment *ds, int x1, int x2, int wallshade) + void RenderDrawSegment::RenderFakeWallRange(DrawSegment *ds, int x1, int x2) { - FTexture *const DONT_DRAW = ((FTexture*)(intptr_t)-1); + FSoftwareTexture *const DONT_DRAW = ((FSoftwareTexture*)(intptr_t)-1); int i, j; F3DFloor *rover, *fover = nullptr; int passed, last; @@ -637,17 +638,22 @@ namespace swrenderer { // don't ever draw (but treat as something has been found) rw_pic = DONT_DRAW; } - else if (fover->flags & FF_UPPERTEXTURE) - { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true); - } - else if (fover->flags & FF_LOWERTEXTURE) - { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true); - } else { - rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + FTexture *rw_tex = nullptr; + if (fover->flags & FF_UPPERTEXTURE) + { + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + } + else if (fover->flags & FF_LOWERTEXTURE) + { + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + } + else + { + rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + } + rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -696,22 +702,24 @@ namespace swrenderer if (!rw_pic) { fover = nullptr; + FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true); + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true); + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } + rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } // correct colors now FDynamicColormap *basecolormap = nullptr; - wallshade = ds->shade; + int lightlevel = ds->lightlevel; CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() < 0) { @@ -723,8 +731,8 @@ namespace swrenderer { lightlist_t *lit = &backsector->e->XFloor.lightlist[j]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); - bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr) + LightVisibility::ActualExtraLight(ds->foggy, Thread->Viewport.get()), foggy); + //bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag + lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr); break; } } @@ -737,8 +745,8 @@ namespace swrenderer { lightlist_t *lit = &frontsector->e->XFloor.lightlist[j]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); - bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr) + LightVisibility::ActualExtraLight(ds->foggy, Thread->Viewport.get()), foggy); + //bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag + lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr); break; } } @@ -748,7 +756,7 @@ namespace swrenderer if (rw_pic != DONT_DRAW) { - RenderFakeWall(ds, x1, x2, fover ? fover : rover, wallshade, basecolormap, clipTop, clipBottom); + RenderFakeWall(ds, x1, x2, fover ? fover : rover, lightlevel, basecolormap, clipTop, clipBottom); } else rw_pic = nullptr; break; @@ -819,17 +827,22 @@ namespace swrenderer { rw_pic = DONT_DRAW; // don't ever draw (but treat as something has been found) } - else if (fover->flags & FF_UPPERTEXTURE) - { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true); - } - else if (fover->flags & FF_LOWERTEXTURE) - { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true); - } else { - rw_pic = TexMan(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + FTexture *rw_tex; + if (fover->flags & FF_UPPERTEXTURE) + { + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); + } + else if (fover->flags & FF_LOWERTEXTURE) + { + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); + } + else + { + rw_tex = TexMan.GetPalettedTexture(fover->master->sidedef[0]->GetTexture(side_t::mid), true); + } + rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } } else if (frontsector->e->XFloor.ffloors.Size()) @@ -875,22 +888,24 @@ namespace swrenderer if (rw_pic == nullptr) { fover = nullptr; + FTexture *rw_tex; if (rover->flags & FF_UPPERTEXTURE) { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::top), true); + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::top), true); } else if (rover->flags & FF_LOWERTEXTURE) { - rw_pic = TexMan(curline->sidedef->GetTexture(side_t::bottom), true); + rw_tex = TexMan.GetPalettedTexture(curline->sidedef->GetTexture(side_t::bottom), true); } else { - rw_pic = TexMan(rover->master->sidedef[0]->GetTexture(side_t::mid), true); + rw_tex = TexMan.GetPalettedTexture(rover->master->sidedef[0]->GetTexture(side_t::mid), true); } + rw_pic = rw_tex && rw_tex->isValid() ? rw_tex->GetSoftwareTexture() : nullptr; } // correct colors now FDynamicColormap *basecolormap = nullptr; - wallshade = ds->shade; + int lightlevel = ds->lightlevel; CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() < 0) { @@ -903,7 +918,7 @@ namespace swrenderer lightlist_t *lit = &backsector->e->XFloor.lightlist[j]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr) + LightVisibility::ActualExtraLight(ds->foggy, Thread->Viewport.get()), foggy); + lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr); break; } } @@ -917,7 +932,7 @@ namespace swrenderer lightlist_t *lit = &frontsector->e->XFloor.lightlist[j]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // [RH] set foggy flag - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr) + LightVisibility::ActualExtraLight(ds->foggy, Thread->Viewport.get()), foggy); + lightlevel = curline->sidedef->GetLightLevel(ds->foggy, *lit->p_lightlevel, lit->lightsource != nullptr); break; } } @@ -927,7 +942,7 @@ namespace swrenderer if (rw_pic != DONT_DRAW) { - RenderFakeWall(ds, x1, x2, fover ? fover : rover, wallshade, basecolormap, clipTop, clipBottom); + RenderFakeWall(ds, x1, x2, fover ? fover : rover, lightlevel, basecolormap, clipTop, clipBottom); } else { diff --git a/src/swrenderer/line/r_renderdrawsegment.h b/src/swrenderer/line/r_renderdrawsegment.h index 82186f317..229e8705d 100644 --- a/src/swrenderer/line/r_renderdrawsegment.h +++ b/src/swrenderer/line/r_renderdrawsegment.h @@ -37,10 +37,10 @@ namespace swrenderer RenderThread *Thread = nullptr; private: - bool RenderWall(DrawSegment *ds, int x1, int x2, WallDrawerArgs &walldrawerargs, SpriteDrawerArgs &columndrawerargs, bool visible, FDynamicColormap *basecolormap, int wallshade); + bool RenderWall(DrawSegment *ds, int x1, int x2, WallDrawerArgs &walldrawerargs, SpriteDrawerArgs &columndrawerargs, bool visible, FDynamicColormap *basecolormap, int lightlevel); void ClipMidtex(int x1, int x2); - void RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int wallshade, FDynamicColormap *basecolormap, double clipTop, double clipBottom); - void RenderFakeWallRange(DrawSegment *ds, int x1, int x2, int wallshade); + void RenderFakeWall(DrawSegment *ds, int x1, int x2, F3DFloor *rover, int lightlevel, FDynamicColormap *basecolormap, double clipTop, double clipBottom); + void RenderFakeWallRange(DrawSegment *ds, int x1, int x2); void GetMaskedWallTopBottom(DrawSegment *ds, double &top, double &bot); sector_t *frontsector = nullptr; @@ -55,7 +55,7 @@ namespace swrenderer float rw_light = 0.0f; float rw_lightstep = 0.0f; fixed_t rw_offset = 0; - FTexture *rw_pic = nullptr; + FSoftwareTexture *rw_pic = nullptr; ProjectedWallLine wallupper; ProjectedWallLine walllower; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 1f3637aa2..4eb940413 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -54,15 +54,16 @@ namespace swrenderer { - WallSampler::WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture) + WallSampler::WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FSoftwareTexture *texture) { xoffset += FLOAT2FIXED(xmagnitude * 0.5); + xoffset *= texture->GetPhysicalScale(); if (!viewport->RenderTarget->IsBgra()) { - height = texture->GetHeight(); + height = texture->GetPhysicalHeight(); - int uv_fracbits = 32 - texture->HeightBits; + int uv_fracbits = 32 - texture->GetHeightBits(); if (uv_fracbits != 32) { uv_max = height << uv_fracbits; @@ -70,13 +71,13 @@ namespace swrenderer // Find start uv in [0-base_height[ range. // Not using xs_ToFixed because it rounds the result and we need something that always rounds down to stay within the range. double uv_stepd = swal * yrepeat; - double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / height; + double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / texture->GetHeight(); v = v - floor(v); v *= height; v *= (1 << uv_fracbits); uv_pos = (uint32_t)(int64_t)v; - uv_step = xs_ToFixed(uv_fracbits, uv_stepd); + uv_step = xs_ToFixed(uv_fracbits, uv_stepd * texture->GetPhysicalScale()); if (uv_step == 0) // To prevent divide by zero elsewhere uv_step = 1; } @@ -92,7 +93,7 @@ namespace swrenderer // If the texture's width isn't a power of 2, then we need to make it a // positive offset for proper clamping. int width; - if (col < 0 && (width = texture->GetWidth()) != (1 << texture->WidthBits)) + if (col < 0 && (width = texture->GetPhysicalWidth()) != (1 << texture->GetWidthBits())) { col = width + (col % width); } @@ -129,8 +130,8 @@ namespace swrenderer bool magnifying = lod < 0.0f; int mipmap_offset = 0; - int mip_width = texture->GetWidth(); - int mip_height = texture->GetHeight(); + int mip_width = texture->GetPhysicalWidth(); + int mip_height = texture->GetPhysicalHeight(); if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1) { uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); @@ -327,10 +328,10 @@ namespace swrenderer void RenderWallPart::ProcessWallWorker(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal) { - if (rw_pic->UseType == ETextureType::Null) + if (rw_pic == nullptr) return; - int fracbits = 32 - rw_pic->HeightBits; + int fracbits = 32 - rw_pic->GetHeightBits(); if (fracbits == 32) { // Hack for one pixel tall textures fracbits = 0; @@ -343,7 +344,9 @@ namespace swrenderer CameraLight *cameraLight = CameraLight::Instance(); bool fixed = (cameraLight->FixedColormap() != NULL || cameraLight->FixedLightLevel() >= 0); - if (cameraLight->FixedColormap()) + if (cameraLight->FixedLightLevel() >= 0) + drawerargs.SetLight(cameraLight->FixedColormap(), 0, cameraLight->FixedLightLevelShade()); + else if (cameraLight->FixedColormap()) drawerargs.SetLight(cameraLight->FixedColormap(), 0, 0); else drawerargs.SetLight(basecolormap, 0, 0); @@ -366,7 +369,7 @@ namespace swrenderer continue; if (!fixed) - drawerargs.SetLight(basecolormap, curlight, wallshade); + drawerargs.SetLight(basecolormap, curlight, lightlevel, foggy, Thread->Viewport.get()); if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); @@ -414,7 +417,7 @@ namespace swrenderer lightlist_t *lit = &frontsector->e->XFloor.lightlist[i]; basecolormap = GetColorTable(lit->extra_colormap, frontsector->SpecialColors[sector_t::walltop]); - wallshade = LightVisibility::LightLevelToShade(curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL) + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); + lightlevel = curline->sidedef->GetLightLevel(foggy, *lit->p_lightlevel, lit->lightsource != NULL); } ProcessNormalWall(up, dwal, texturemid, swal, lwal); @@ -423,7 +426,7 @@ namespace swrenderer void RenderWallPart::ProcessWall(const short *uwal, const short *dwal, double texturemid, float *swal, fixed_t *lwal) { // Textures that aren't masked can use the faster ProcessNormalWall. - if (!rw_pic->bMasked && drawerargs.IsMaskedDrawer()) + if (!rw_pic->GetTexture()->isMasked() && drawerargs.IsMaskedDrawer()) { drawerargs.SetStyle(true, false, OPAQUE); } @@ -511,7 +514,7 @@ namespace swrenderer } } - void RenderWallPart::Render(const WallDrawerArgs &drawerargs, sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, double texturemid, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, int wallshade, fixed_t xoffset, float light, float lightstep, FLightNode *light_list, bool foggy, FDynamicColormap *basecolormap) + void RenderWallPart::Render(const WallDrawerArgs &drawerargs, sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FSoftwareTexture *pic, int x1, int x2, const short *walltop, const short *wallbottom, double texturemid, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, int lightlevel, fixed_t xoffset, float light, float lightstep, FLightNode *light_list, bool foggy, FDynamicColormap *basecolormap) { this->drawerargs = drawerargs; this->x1 = x1; @@ -520,7 +523,7 @@ namespace swrenderer this->curline = curline; this->WallC = WallC; this->yrepeat = yscale; - this->wallshade = wallshade; + this->lightlevel = lightlevel; this->xoffset = xoffset; this->light = light; this->lightstep = lightstep; @@ -532,7 +535,7 @@ namespace swrenderer Thread->PrepareTexture(pic, DefaultRenderStyle()); // Get correct render style? Shaded won't get here. - if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) + if (rw_pic->GetHeight() != 1 << rw_pic->GetHeightBits()) { ProcessWallNP2(walltop, wallbottom, texturemid, swall, lwall, top, bottom); } diff --git a/src/swrenderer/line/r_walldraw.h b/src/swrenderer/line/r_walldraw.h index d3cd026a2..b44484b15 100644 --- a/src/swrenderer/line/r_walldraw.h +++ b/src/swrenderer/line/r_walldraw.h @@ -50,7 +50,7 @@ namespace swrenderer sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, - FTexture *rw_pic, + FSoftwareTexture *rw_pic, int x1, int x2, const short *walltop, @@ -62,7 +62,7 @@ namespace swrenderer double top, double bottom, bool mask, - int wallshade, + int lightlevel, fixed_t xoffset, float light, float lightstep, @@ -82,13 +82,13 @@ namespace swrenderer int x1 = 0; int x2 = 0; - FTexture *rw_pic = nullptr; + FSoftwareTexture *rw_pic = nullptr; sector_t *frontsector = nullptr; seg_t *curline = nullptr; FWallCoords WallC; double yrepeat = 0.0; - int wallshade = 0; + int lightlevel = 0; fixed_t xoffset = 0; float light = 0.0f; float lightstep = 0.0f; @@ -103,7 +103,7 @@ namespace swrenderer struct WallSampler { WallSampler() { } - WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture); + WallSampler(RenderViewport *viewport, int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FSoftwareTexture *texture); uint32_t uv_pos; uint32_t uv_step; diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 6031fa904..3ddf3a1b6 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -60,13 +60,15 @@ namespace swrenderer Thread = thread; } - void RenderFlatPlane::Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *colormap, FTexture *texture) + void RenderFlatPlane::Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *colormap, FSoftwareTexture *texture) { if (alpha <= 0) { return; } + tex = texture; + drawerargs.SetSolidColor(3); drawerargs.SetTexture(Thread, texture); @@ -135,9 +137,7 @@ namespace swrenderer basecolormap = colormap; // [RH] set foggy flag - bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); - - GlobVis = Thread->Light->FlatPlaneGlobVis(foggy) / planeheight; + foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() >= 0) @@ -153,7 +153,7 @@ namespace swrenderer else { plane_shade = true; - planeshade = LightVisibility::LightLevelToShade(pl->lightlevel, foggy); + lightlevel = pl->lightlevel; } drawerargs.SetStyle(masked, additive, alpha); @@ -181,11 +181,11 @@ namespace swrenderer float zbufferdepth = (float)(1.0 / fabs(planeheight / Thread->Viewport->ScreenToViewY(y, 1.0))); - drawerargs.SetTextureUStep(distance * xstepscale / drawerargs.TextureWidth()); - drawerargs.SetTextureUPos((distance * curxfrac + pviewx) / drawerargs.TextureWidth()); + drawerargs.SetTextureUStep(distance * xstepscale / tex->GetWidth()); + drawerargs.SetTextureUPos((distance * curxfrac + pviewx) / tex->GetWidth()); - drawerargs.SetTextureVStep(distance * ystepscale / drawerargs.TextureHeight()); - drawerargs.SetTextureVPos((distance * curyfrac + pviewy) / drawerargs.TextureHeight()); + drawerargs.SetTextureVStep(distance * ystepscale / tex->GetHeight()); + drawerargs.SetTextureVPos((distance * curyfrac + pviewy) / tex->GetHeight()); if (viewport->RenderTarget->IsBgra()) { @@ -200,7 +200,7 @@ namespace swrenderer if (plane_shade) { // Determine lighting based on the span's distance from the viewer. - drawerargs.SetLight(basecolormap, (float)(GlobVis * fabs(viewport->CenterY - y)), planeshade); + drawerargs.SetLight(basecolormap, (float)Thread->Light->FlatPlaneVis(y, planeheight, foggy, viewport), lightlevel, foggy, viewport); } if (r_dynlights) diff --git a/src/swrenderer/plane/r_flatplane.h b/src/swrenderer/plane/r_flatplane.h index 56b70a40c..fa12101d7 100644 --- a/src/swrenderer/plane/r_flatplane.h +++ b/src/swrenderer/plane/r_flatplane.h @@ -34,7 +34,7 @@ namespace swrenderer { public: RenderFlatPlane(RenderThread *thread); - void Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *basecolormap, FTexture *texture); + void Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *basecolormap, FSoftwareTexture *texture); RenderThread *Thread = nullptr; @@ -44,13 +44,14 @@ namespace swrenderer int minx; double planeheight; bool plane_shade; - int planeshade; - double GlobVis; + int lightlevel; + bool foggy; FDynamicColormap *basecolormap; double pviewx, pviewy; double xstepscale, ystepscale; double basexfrac, baseyfrac; VisiblePlaneLight *light_list; + FSoftwareTexture *tex; SpanDrawerArgs drawerargs; }; diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index afa9496c0..5b5c4894a 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -57,8 +57,73 @@ CVAR(Bool, r_linearsky, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); EXTERN_CVAR(Int, r_skymode) + +double skytexturemid; +double skyscale; +float skyiscale; +fixed_t sky1cyl, sky2cyl; + +void InitSoftwareSky() +{ + auto skytex1 = TexMan.GetPalettedTexture(sky1texture, true); + auto skytex2 = TexMan.GetPalettedTexture(sky2texture, true); + + if (skytex1 == nullptr) + return; + + // Note: I don't think it is good that this stuff gets cached globally. + // For something that only needs to be once per frame it is rather pointless and makes it hard to swap out the underlying textures based on user settings. + FSoftwareTexture *sskytex1 = skytex1->GetSoftwareTexture(); + FSoftwareTexture *sskytex2 = skytex2->GetSoftwareTexture(); + skytexturemid = 0; + int skyheight = skytex1->GetDisplayHeight(); + if (skyheight >= 128 && skyheight < 200) + { + skytexturemid = -28; + } + else if (skyheight > 200) + { + skytexturemid = (200 - skyheight) * sskytex1->GetScale().Y + ((r_skymode == 2 && !(level.flags & LEVEL_FORCETILEDSKY)) ? skytex1->GetSkyOffset() : 0); + } + + if (viewwidth != 0 && viewheight != 0) + { + skyiscale = float(r_Yaspect / freelookviewheight); + skyscale = freelookviewheight / r_Yaspect; + + skyiscale *= float(r_viewpoint.FieldOfView.Degrees / 90.); + skyscale *= float(90. / r_viewpoint.FieldOfView.Degrees); + } + + if (skystretch) + { + skyscale *= (double)SKYSTRETCH_HEIGHT / skyheight; + skyiscale *= skyheight / (float)SKYSTRETCH_HEIGHT; + skytexturemid *= skyheight / (double)SKYSTRETCH_HEIGHT; + } + + // The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees, + // giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024, + // we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of + // the texture as the cylinder's circumfrence. + sky1cyl = MAX(sskytex1->GetWidth(), fixed_t(sskytex1->GetScale().X * 1024)); + sky2cyl = MAX(sskytex2->GetWidth(), fixed_t(sskytex2->GetScale().Y * 1024)); +} + + + + namespace swrenderer { + + static FSoftwareTexture *GetSWTex(FTextureID texid, bool allownull = true) + { + auto tex = TexMan.GetPalettedTexture(texid, true); + if (tex == nullptr) return nullptr; + if (!allownull && !tex->isValid()) return nullptr; + return tex->GetSoftwareTexture(); + } + RenderSkyPlane::RenderSkyPlane(RenderThread *thread) { Thread = thread; @@ -86,9 +151,9 @@ namespace swrenderer if (!(pl->sky & PL_SKYFLAT)) { // use sky1 sky1: - frontskytex = TexMan(sky1tex, true); + frontskytex = GetSWTex(sky1tex); if (level.flags & LEVEL_DOUBLESKY) - backskytex = TexMan(sky2tex, true); + backskytex = GetSWTex(sky2tex); else backskytex = NULL; skyflip = 0; @@ -99,7 +164,7 @@ namespace swrenderer } else if (pl->sky == PL_SKYFLAT) { // use sky2 - frontskytex = TexMan(sky2tex, true); + frontskytex = GetSWTex(sky2tex); backskytex = NULL; frontcyl = sky2cyl; skyflip = 0; @@ -125,8 +190,8 @@ namespace swrenderer pos = side_t::top; } - frontskytex = TexMan(s->GetTexture(pos), true); - if (frontskytex == NULL || frontskytex->UseType == ETextureType::Null) + frontskytex = GetSWTex(s->GetTexture(pos)); + if (frontskytex == nullptr) { // [RH] The blank texture: Use normal sky instead. goto sky1; } @@ -148,7 +213,7 @@ namespace swrenderer // allow old sky textures to be used. skyflip = l->args[2] ? 0u : ~0u; - int frontxscale = int(frontskytex->Scale.X * 1024); + int frontxscale = int(frontskytex->GetScale().X * 1024); frontcyl = MAX(frontskytex->GetWidth(), frontxscale); if (skystretch) { @@ -183,11 +248,9 @@ namespace swrenderer RenderPortal *renderportal = Thread->Portal.get(); auto viewport = Thread->Viewport.get(); - uint32_t height = frontskytex->GetHeight(); - double uv_stepd = skyiscale * yrepeat; - double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / height; - double v_step = uv_stepd / height; + double v = (texturemid + uv_stepd * (y1 - viewport->CenterY + 0.5)) / frontskytex->GetHeight(); + double v_step = uv_stepd / frontskytex->GetHeight(); uint32_t uv_pos = (uint32_t)(int32_t)(v * 0x01000000); uint32_t uv_step = (uint32_t)(int32_t)(v_step * 0x01000000); @@ -207,8 +270,8 @@ namespace swrenderer { ang = (skyangle + viewport->xtoviewangle[x]) ^ skyflip; } - angle1 = (uint32_t)((UMulScale16(ang, frontcyl) + frontpos) >> FRACBITS); - angle2 = (uint32_t)((UMulScale16(ang, backcyl) + backpos) >> FRACBITS); + angle1 = UMulScale16(ang, frontcyl) + frontpos; + angle2 = UMulScale16(ang, backcyl) + backpos; drawerargs.SetFrontTexture(Thread, frontskytex, angle1); drawerargs.SetBackTexture(Thread, backskytex, angle2); @@ -231,16 +294,16 @@ namespace swrenderer void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2) { - if (1 << frontskytex->HeightBits == frontskytex->GetHeight()) + if (1 << frontskytex->GetHeightBits() == frontskytex->GetPhysicalHeight()) { - double texturemid = skymid * frontskytex->Scale.Y + frontskytex->GetHeight(); - DrawSkyColumnStripe(start_x, y1, y2, frontskytex->Scale.Y, texturemid, frontskytex->Scale.Y); + double texturemid = skymid * frontskytex->GetScale().Y + frontskytex->GetHeight(); + DrawSkyColumnStripe(start_x, y1, y2, frontskytex->GetScale().Y, texturemid, frontskytex->GetScale().Y); } else { auto viewport = Thread->Viewport.get(); - double yrepeat = frontskytex->Scale.Y; - double scale = frontskytex->Scale.Y * skyscale; + double yrepeat = frontskytex->GetScale().Y; + double scale = frontskytex->GetScale().Y * skyscale; double iscale = 1 / scale; short drawheight = short(frontskytex->GetHeight() * scale); double topfrac = fmod(skymid + iscale * (1 - viewport->CenterY), frontskytex->GetHeight()); diff --git a/src/swrenderer/plane/r_skyplane.h b/src/swrenderer/plane/r_skyplane.h index 79a27c987..ac5e07d25 100644 --- a/src/swrenderer/plane/r_skyplane.h +++ b/src/swrenderer/plane/r_skyplane.h @@ -41,8 +41,8 @@ namespace swrenderer void DrawSkyColumnStripe(int start_x, int y1, int y2, double scale, double texturemid, double yrepeat); void DrawSkyColumn(int start_x, int y1, int y2); - FTexture *frontskytex = nullptr; - FTexture *backskytex = nullptr; + FSoftwareTexture *frontskytex = nullptr; + FSoftwareTexture *backskytex = nullptr; angle_t skyflip = 0; int frontpos = 0; int backpos = 0; diff --git a/src/swrenderer/plane/r_slopeplane.cpp b/src/swrenderer/plane/r_slopeplane.cpp index 20eb3dbf4..0f4ac159a 100644 --- a/src/swrenderer/plane/r_slopeplane.cpp +++ b/src/swrenderer/plane/r_slopeplane.cpp @@ -64,7 +64,7 @@ namespace swrenderer Thread = thread; } - void RenderSlopePlane::Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *colormap, FTexture *texture) + void RenderSlopePlane::Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *colormap, FSoftwareTexture *texture) { static const float ifloatpow2[16] = { @@ -98,6 +98,9 @@ namespace swrenderer drawerargs.SetSolidColor(3); drawerargs.SetTexture(Thread, texture); + _xscale /= texture->GetPhysicalScale(); + _yscale /= texture->GetPhysicalScale(); + lxscale = _xscale * ifloatpow2[drawerargs.TextureWidthBits()]; lyscale = _yscale * ifloatpow2[drawerargs.TextureHeightBits()]; xscale = 64.f / lxscale; @@ -171,7 +174,7 @@ namespace swrenderer // [RH] set foggy flag basecolormap = colormap; - bool foggy = level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE);; + foggy = level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE);; planelightfloat = (Thread->Light->SlopePlaneGlobVis(foggy) * lxscale * lyscale) / (fabs(pl->height.ZatPoint(Thread->Viewport->viewpoint.Pos) - Thread->Viewport->viewpoint.Pos.Z)) / 65536.f; @@ -194,7 +197,7 @@ namespace swrenderer { drawerargs.SetLight(basecolormap, 0, 0); plane_shade = true; - planeshade = LightVisibility::LightLevelToShade(pl->lightlevel, foggy); + lightlevel = pl->lightlevel; } // Hack in support for 1 x Z and Z x 1 texture sizes @@ -212,7 +215,7 @@ namespace swrenderer void RenderSlopePlane::RenderLine(int y, int x1, int x2) { - drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy, basecolormap); + drawerargs.DrawTiltedSpan(Thread, y, x1, x2, plane_sz, plane_su, plane_sv, plane_shade, lightlevel, foggy, planelightfloat, pviewx, pviewy, basecolormap); if (r_modelscene) { diff --git a/src/swrenderer/plane/r_slopeplane.h b/src/swrenderer/plane/r_slopeplane.h index c59fa3f58..b074492fc 100644 --- a/src/swrenderer/plane/r_slopeplane.h +++ b/src/swrenderer/plane/r_slopeplane.h @@ -33,7 +33,7 @@ namespace swrenderer { public: RenderSlopePlane(RenderThread *thread); - void Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *basecolormap, FTexture *texture); + void Render(VisiblePlane *pl, double _xscale, double _yscale, fixed_t alpha, bool additive, bool masked, FDynamicColormap *basecolormap, FSoftwareTexture *texture); RenderThread *Thread = nullptr; @@ -43,7 +43,8 @@ namespace swrenderer FVector3 plane_sz, plane_su, plane_sv; float planelightfloat; bool plane_shade; - int planeshade; + int lightlevel; + bool foggy; fixed_t pviewx, pviewy; fixed_t xscale, yscale; FDynamicColormap *basecolormap; diff --git a/src/swrenderer/plane/r_visibleplane.cpp b/src/swrenderer/plane/r_visibleplane.cpp index ac4e07079..72e838812 100644 --- a/src/swrenderer/plane/r_visibleplane.cpp +++ b/src/swrenderer/plane/r_visibleplane.cpp @@ -113,23 +113,24 @@ namespace swrenderer } else // regular flat { - FTexture *tex = TexMan(picnum, true); + FTexture *ttex = TexMan.GetPalettedTexture(picnum, true); - if (tex->UseType == ETextureType::Null) + if (!ttex->isValid()) { return; } + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); if (!masked && !additive) { // If we're not supposed to see through this plane, draw it opaque. alpha = OPAQUE; } - else if (!tex->bMasked) + else if (!tex->isMasked()) { // Don't waste time on a masked texture if it isn't really masked. masked = false; } - double xscale = xform.xScale * tex->Scale.X; - double yscale = xform.yScale * tex->Scale.Y; + double xscale = xform.xScale * tex->GetScale().X; + double yscale = xform.yScale * tex->GetScale().Y; if (!height.isSlope() && !tilt) { diff --git a/src/swrenderer/plane/r_visibleplanelist.cpp b/src/swrenderer/plane/r_visibleplanelist.cpp index 561930cc2..3c65e6386 100644 --- a/src/swrenderer/plane/r_visibleplanelist.cpp +++ b/src/swrenderer/plane/r_visibleplanelist.cpp @@ -99,7 +99,7 @@ namespace swrenderer } } - VisiblePlane *VisiblePlaneList::FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal, FDynamicColormap *basecolormap, Fake3DOpaque::Type fakeFloorType, fixed_t fakeAlpha) + VisiblePlane *VisiblePlaneList::FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, bool foggy, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal, FDynamicColormap *basecolormap, Fake3DOpaque::Type fakeFloorType, fixed_t fakeAlpha) { secplane_t plane; VisiblePlane *check; @@ -113,6 +113,8 @@ namespace swrenderer RenderPortal *renderportal = Thread->Portal.get(); + lightlevel += LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()); + if (picnum == skyflatnum) // killough 10/98 { // most skies map together lightlevel = 0; diff --git a/src/swrenderer/plane/r_visibleplanelist.h b/src/swrenderer/plane/r_visibleplanelist.h index a49479e6c..7c601238c 100644 --- a/src/swrenderer/plane/r_visibleplanelist.h +++ b/src/swrenderer/plane/r_visibleplanelist.h @@ -40,7 +40,7 @@ namespace swrenderer void Clear(); void ClearKeepFakePlanes(); - VisiblePlane *FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal, FDynamicColormap *basecolormap, Fake3DOpaque::Type fakeFloorType, fixed_t fakeAlpha); + VisiblePlane *FindPlane(const secplane_t &height, FTextureID picnum, int lightlevel, bool foggy, double Alpha, bool additive, const FTransform &xxform, int sky, FSectorPortal *portal, FDynamicColormap *basecolormap, Fake3DOpaque::Type fakeFloorType, fixed_t fakeAlpha); VisiblePlane *GetRange(VisiblePlane *pl, int start, int stop); bool HasPortalPlanes() const; diff --git a/src/swrenderer/r_all.cpp b/src/swrenderer/r_all.cpp index 8eaf961f6..c1dc53734 100644 --- a/src/swrenderer/r_all.cpp +++ b/src/swrenderer/r_all.cpp @@ -1,3 +1,4 @@ +#include "textures/r_swtexture.h" #include "r_memory.cpp" #include "r_renderthread.cpp" #include "r_swrenderer.cpp" diff --git a/src/swrenderer/r_renderthread.cpp b/src/swrenderer/r_renderthread.cpp index 90a0792ea..86e789721 100644 --- a/src/swrenderer/r_renderthread.cpp +++ b/src/swrenderer/r_renderthread.cpp @@ -90,8 +90,7 @@ namespace swrenderer } static std::mutex loadmutex; - void RenderThread::PrepareTexture(FTexture *texture, FRenderStyle style) - { + void RenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) { if (texture == nullptr) return; @@ -105,14 +104,18 @@ namespace swrenderer std::unique_lock lock(loadmutex); - texture->GetPixels(style); - const FTexture::Span *spans; - texture->GetColumn(style, 0, &spans); + const FSoftwareTextureSpan *spans; if (Viewport->RenderTarget->IsBgra()) { texture->GetPixelsBgra(); texture->GetColumnBgra(0, &spans); } + else + { + bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); + texture->GetPixels(alpha); + texture->GetColumn(alpha, 0, &spans); + } } static std::mutex polyobjmutex; diff --git a/src/swrenderer/r_renderthread.h b/src/swrenderer/r_renderthread.h index b65713e07..8823b59cf 100644 --- a/src/swrenderer/r_renderthread.h +++ b/src/swrenderer/r_renderthread.h @@ -88,7 +88,7 @@ namespace swrenderer SWPixelFormatDrawers *Drawers(RenderViewport *viewport); // Make sure texture can accessed safely - void PrepareTexture(FTexture *texture, FRenderStyle style); + void PrepareTexture(FSoftwareTexture *texture, FRenderStyle style); // Setup poly object in a threadsafe manner void PreparePolyObject(subsector_t *sub); diff --git a/src/swrenderer/r_swrenderer.cpp b/src/swrenderer/r_swrenderer.cpp index a20b474cd..873f5c85d 100644 --- a/src/swrenderer/r_swrenderer.cpp +++ b/src/swrenderer/r_swrenderer.cpp @@ -51,6 +51,8 @@ #include "polyrenderer/poly_renderer.h" #include "p_setup.h" #include "g_levellocals.h" +#include "image.h" +#include "imagehelpers.h" // [BB] Use ZDoom's freelook limit for the sotfware renderer. // Note: ZDoom's limit is chosen such that the sky is rendered properly. @@ -80,15 +82,35 @@ FRenderer *CreateSWRenderer() return new FSoftwareRenderer; } -void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache) +void FSoftwareRenderer::PreparePrecache(FTexture *ttex, int cache) { bool isbgra = V_IsTrueColor(); - if (tex != NULL) + if (ttex != NULL && ttex->isValid()) { + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); + + if (tex->CheckPixels()) + { + if (cache == 0) tex->Unload(); + } + else if (cache != 0) + { + FImageSource::RegisterForPrecache(ttex->GetImage()); + } + } +} + +void FSoftwareRenderer::PrecacheTexture(FTexture *ttex, int cache) +{ + bool isbgra = V_IsTrueColor(); + + if (ttex != NULL && ttex->isValid()) + { + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); if (cache & FTextureManager::HIT_Columnmode) { - const FTexture::Span *spanp; + const FSoftwareTextureSpan *spanp; if (isbgra) tex->GetColumnBgra(0, &spanp); else @@ -101,10 +123,6 @@ void FSoftwareRenderer::PrecacheTexture(FTexture *tex, int cache) else tex->GetPixels (DefaultRenderStyle()); } - else - { - tex->Unload (); - } } } @@ -151,10 +169,18 @@ void FSoftwareRenderer::Precache(uint8_t *texhitlist, TMap & delete[] spritelist; int cnt = TexMan.NumTextures(); + + FImageSource::BeginPrecaching(); + for (int i = cnt - 1; i >= 0; i--) + { + PreparePrecache(TexMan.ByIndex(i), texhitlist[i]); + } + for (int i = cnt - 1; i >= 0; i--) { PrecacheTexture(TexMan.ByIndex(i), texhitlist[i]); } + FImageSource::EndPrecaching(); } void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *videobuffer) @@ -176,7 +202,10 @@ void FSoftwareRenderer::RenderView(player_t *player, DCanvas *target, void *vide r_viewwindow = mScene.MainThread()->Viewport->viewwindow; } - FCanvasTextureInfo::UpdateAll(); + level.canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) + { + RenderTextureView(camtex, camera, fov); + }); } void FSoftwareRenderer::WriteSavePic (player_t *player, FileWriter *file, int width, int height) @@ -230,7 +259,7 @@ void FSoftwareRenderer::SetClearColor(int color) mScene.SetClearColor(color); } -void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) +void FSoftwareRenderer::RenderTextureView (FCanvasTexture *camtex, AActor *viewpoint, double fov) { auto renderTarget = V_IsPolyRenderer() ? PolyRenderer::Instance()->RenderTarget : mScene.MainThread()->Viewport->RenderTarget; auto &cameraViewpoint = V_IsPolyRenderer() ? PolyRenderer::Instance()->Viewpoint : mScene.MainThread()->Viewport->viewpoint; @@ -239,8 +268,9 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoin // Grab global state shared with rest of zdoom cameraViewpoint = r_viewpoint; cameraViewwindow = r_viewwindow; + + auto tex = static_cast(camtex->GetSoftwareTexture()); - uint8_t *Pixels = renderTarget->IsBgra() ? (uint8_t*)tex->GetPixelsBgra() : (uint8_t*)tex->GetPixels(DefaultRenderStyle()); DCanvas *Canvas = renderTarget->IsBgra() ? tex->GetCanvasBgra() : tex->GetCanvas(); // curse Doom's overuse of global variables in the renderer. @@ -251,59 +281,13 @@ void FSoftwareRenderer::RenderTextureView (FCanvasTexture *tex, AActor *viewpoin R_SetFOV (cameraViewpoint, fov); if (V_IsPolyRenderer()) - PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate); + PolyRenderer::Instance()->RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate); else - mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), tex->bFirstUpdate); + mScene.RenderViewToCanvas(viewpoint, Canvas, 0, 0, tex->GetWidth(), tex->GetHeight(), camtex->bFirstUpdate); R_SetFOV (cameraViewpoint, savedfov); - if (Canvas->IsBgra()) - { - if (Pixels == Canvas->GetPixels()) - { - FTexture::FlipSquareBlockBgra((uint32_t*)Pixels, tex->GetWidth(), tex->GetHeight()); - } - else - { - FTexture::FlipNonSquareBlockBgra((uint32_t*)Pixels, (const uint32_t*)Canvas->GetPixels(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch()); - } - } - else - { - if (Pixels == Canvas->GetPixels()) - { - FTexture::FlipSquareBlockRemap(Pixels, tex->GetWidth(), tex->GetHeight(), GPalette.Remap); - } - else - { - FTexture::FlipNonSquareBlockRemap(Pixels, Canvas->GetPixels(), tex->GetWidth(), tex->GetHeight(), Canvas->GetPitch(), GPalette.Remap); - } - } - - if (renderTarget->IsBgra()) - { - // True color render still sometimes uses palette textures (for sprites, mostly). - // We need to make sure that both pixel buffers contain data: - int width = tex->GetWidth(); - int height = tex->GetHeight(); - uint8_t *palbuffer = (uint8_t *)tex->GetPixels(DefaultRenderStyle()); - uint32_t *bgrabuffer = (uint32_t*)tex->GetPixelsBgra(); - for (int x = 0; x < width; x++) - { - for (int y = 0; y < height; y++) - { - uint32_t color = bgrabuffer[y]; - int r = RPART(color); - int g = GPART(color); - int b = BPART(color); - palbuffer[y] = RGB32k.RGB[r >> 3][g >> 3][b >> 3]; - } - palbuffer += height; - bgrabuffer += height; - } - } - - tex->SetUpdated(); + tex->UpdatePixels(renderTarget->IsBgra()); *CameraLight::Instance() = savedCameraLight; diff --git a/src/swrenderer/r_swrenderer.h b/src/swrenderer/r_swrenderer.h index 864cbb665..61d0044ff 100644 --- a/src/swrenderer/r_swrenderer.h +++ b/src/swrenderer/r_swrenderer.h @@ -21,12 +21,13 @@ struct FSoftwareRenderer : public FRenderer void DrawRemainingPlayerSprites() override; void SetClearColor(int color) override; - void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov) override; + void RenderTextureView (FCanvasTexture *tex, AActor *viewpoint, double fov); void SetColormap() override; void Init() override; private: + void PreparePrecache(FTexture *tex, int cache); void PrecacheTexture(FTexture *tex, int cache); swrenderer::RenderScene mScene; diff --git a/src/swrenderer/r_swscene.cpp b/src/swrenderer/r_swscene.cpp index c29e4fb67..807a3126e 100644 --- a/src/swrenderer/r_swscene.cpp +++ b/src/swrenderer/r_swscene.cpp @@ -33,24 +33,25 @@ #include "d_player.h" #include "textures/bitmap.h" #include "swrenderer/scene/r_light.h" +#include "image.h" // [RH] Base blending values (for e.g. underwater) int BaseBlendR, BaseBlendG, BaseBlendB; float BaseBlendA; +void InitSoftwareSky(); -class FSWPaletteTexture : public FTexture +class FSWPaletteTexture : public FImageSource { public: FSWPaletteTexture() { Width = 256; Height = 1; - UseType = ETextureType::MiscPatch; } - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) + int CopyPixels(FBitmap *bmp, int conversion) override { PalEntry *pe = (PalEntry*)bmp->GetPixels(); for (int i = 0; i < 256; i++) @@ -70,7 +71,13 @@ public: SWSceneDrawer::SWSceneDrawer() { - PaletteTexture.reset(new FSWPaletteTexture); + auto texid = TexMan.CheckForTexture("@@palette@@", ETextureType::Any); + if (!texid.Exists()) + { + auto tex = new FImageTexture(new FSWPaletteTexture, "@@palette@@"); + texid = TexMan.AddTexture(tex); + } + PaletteTexture = TexMan.GetTexture(texid); } SWSceneDrawer::~SWSceneDrawer() @@ -80,29 +87,30 @@ SWSceneDrawer::~SWSceneDrawer() sector_t *SWSceneDrawer::RenderView(player_t *player) { // Avoid using the pixel buffer from the last frame + InitSoftwareSky(); // do this here to avoid problems when texture modes are changed on the fly. FBTextureIndex = (FBTextureIndex + 1) % 2; auto &fbtex = FBTexture[FBTextureIndex]; - if (fbtex == nullptr || fbtex->SystemTexture[0] == nullptr || - fbtex->GetWidth() != screen->GetWidth() || - fbtex->GetHeight() != screen->GetHeight() || - (V_IsTrueColor() ? 1:0) != fbtex->WidthBits) + if (fbtex == nullptr || fbtex->GetSystemTexture() == nullptr || + fbtex->GetDisplayWidth() != screen->GetWidth() || + fbtex->GetDisplayHeight() != screen->GetHeight() || + (V_IsTrueColor() ? 1:0) != fbtex->GetColorFormat()) { // This manually constructs its own material here. fbtex.reset(); fbtex.reset(new FWrapperTexture(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); - fbtex->SystemTexture[0]->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); + fbtex->GetSystemTexture()->AllocateBuffer(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor() ? 4 : 1); auto mat = FMaterial::ValidateTexture(fbtex.get(), false); - mat->AddTextureLayer(PaletteTexture.get()); + mat->AddTextureLayer(PaletteTexture); Canvas.reset(); Canvas.reset(new DCanvas(screen->GetWidth(), screen->GetHeight(), V_IsTrueColor())); } - auto buf = fbtex->SystemTexture[0]->MapBuffer(); + auto buf = fbtex->GetSystemTexture()->MapBuffer(); if (!buf) I_FatalError("Unable to map buffer for software rendering"); SWRenderer->RenderView(player, Canvas.get(), buf); - fbtex->SystemTexture[0]->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); + fbtex->GetSystemTexture()->CreateTexture(nullptr, screen->GetWidth(), screen->GetHeight(), 0, false, 0, "swbuffer"); auto map = swrenderer::CameraLight::Instance()->ShaderColormap(); screen->DrawTexture(fbtex.get(), 0, 0, DTA_SpecialColormap, map, TAG_DONE); diff --git a/src/swrenderer/r_swscene.h b/src/swrenderer/r_swscene.h index 47757a334..7dc12488d 100644 --- a/src/swrenderer/r_swscene.h +++ b/src/swrenderer/r_swscene.h @@ -12,7 +12,7 @@ class FWrapperTexture; class SWSceneDrawer { - std::unique_ptr PaletteTexture; + FTexture *PaletteTexture; std::unique_ptr FBTexture[2]; int FBTextureIndex = 0; bool FBIsTruecolor = false; diff --git a/src/swrenderer/scene/r_light.cpp b/src/swrenderer/scene/r_light.cpp index c120c22eb..73a9e84d7 100644 --- a/src/swrenderer/scene/r_light.cpp +++ b/src/swrenderer/scene/r_light.cpp @@ -142,7 +142,7 @@ namespace swrenderer NoLightFade = !!(level.flags3 & LEVEL3_NOLIGHTFADE); } - fixed_t LightVisibility::LightLevelToShade(int lightlevel, bool foggy) + fixed_t LightVisibility::LightLevelToShadeImpl(int lightlevel, bool foggy) { bool nolightfade = !foggy && ((level.flags3 & LEVEL3_NOLIGHTFADE)); if (nolightfade) @@ -160,7 +160,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - void ColormapLight::SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack) + void ColormapLight::SetColormap(RenderThread *thread, double z, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack, bool psprite, bool particle) { if (fadeToBlack) { @@ -181,16 +181,16 @@ namespace swrenderer } CameraLight *cameraLight = CameraLight::Instance(); - if (cameraLight->FixedColormap()) - { - BaseColormap = cameraLight->FixedColormap(); - ColormapNum = 0; - } - else if (cameraLight->FixedLightLevel() >= 0) + if (cameraLight->FixedLightLevel() >= 0) { BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap; ColormapNum = cameraLight->FixedLightLevel() >> COLORMAPSHIFT; } + else if (cameraLight->FixedColormap()) + { + BaseColormap = cameraLight->FixedColormap(); + ColormapNum = 0; + } else if (fullbright) { BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : basecolormap; @@ -198,6 +198,14 @@ namespace swrenderer } else { + double visibility = thread->Light->SpriteVis(z, foggy); + if (particle) + visibility *= 0.5; + + int shade = LightVisibility::LightLevelToShade(lightlevel, foggy, thread->Viewport.get()); + if (psprite) + shade -= 24 * FRACUNIT; + BaseColormap = basecolormap; ColormapNum = GETPALOOKUP(visibility, shade); } diff --git a/src/swrenderer/scene/r_light.h b/src/swrenderer/scene/r_light.h index ae2a2e671..5c2938cec 100644 --- a/src/swrenderer/scene/r_light.h +++ b/src/swrenderer/scene/r_light.h @@ -80,22 +80,24 @@ namespace swrenderer void SetVisibility(RenderViewport *viewport, double visibility); double GetVisibility() const { return CurrentVisibility; } - double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; } - double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; } - double ParticleGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : (WallVisibility * 0.5); } - double FlatPlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : FloorVisibility; } - double SlopePlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : TiltVisibility; } - // The vis value to pass into the GETPALOOKUP or LIGHTSCALE macros double WallVis(double screenZ, bool foggy) const { return WallGlobVis(foggy) / screenZ; } - double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / screenZ; } - double ParticleVis(double screenZ, bool foggy) const { return ParticleGlobVis(foggy) / screenZ; } - double FlatPlaneVis(int screenY, double planeZ, bool foggy, RenderViewport *viewport) const { return FlatPlaneGlobVis(foggy) / fabs(planeZ - viewport->viewpoint.Pos.Z) * fabs(viewport->CenterY - screenY); } + double SpriteVis(double screenZ, bool foggy) const { return SpriteGlobVis(foggy) / MAX(screenZ, MINZ); } + double FlatPlaneVis(int screenY, double planeheight, bool foggy, RenderViewport *viewport) const { return FlatPlaneGlobVis(foggy) / planeheight * fabs(viewport->CenterY - screenY); } + + double SlopePlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : TiltVisibility; } + + static fixed_t LightLevelToShade(int lightlevel, bool foggy, RenderViewport *viewport) { return LightLevelToShadeImpl(lightlevel + ActualExtraLight(foggy, viewport), foggy); } - static fixed_t LightLevelToShade(int lightlevel, bool foggy); static int ActualExtraLight(bool fog, RenderViewport *viewport) { return fog ? 0 : viewport->viewpoint.extralight << 4; } private: + double WallGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; } + double SpriteGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : WallVisibility; } + double FlatPlaneGlobVis(bool foggy) const { return (NoLightFade && !foggy) ? 0.0f : FloorVisibility; } + + static fixed_t LightLevelToShadeImpl(int lightlevel, bool foggy); + double BaseVisibility = 0.0; double WallVisibility = 0.0; double FloorVisibility = 0.0; @@ -114,6 +116,6 @@ namespace swrenderer int ColormapNum = 0; FSWColormap *BaseColormap = nullptr; - void SetColormap(double visibility, int shade, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack); + void SetColormap(RenderThread *thread, double z, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool fullbright, bool invertColormap, bool fadeToBlack, bool psprite, bool particle); }; } diff --git a/src/swrenderer/scene/r_opaque_pass.cpp b/src/swrenderer/scene/r_opaque_pass.cpp index de6922500..30f656296 100644 --- a/src/swrenderer/scene/r_opaque_pass.cpp +++ b/src/swrenderer/scene/r_opaque_pass.cpp @@ -548,7 +548,7 @@ namespace swrenderer ceilingplane = Thread->PlaneList->FindPlane( frontsector->ceilingplane, frontsector->GetTexture(sector_t::ceiling), - adjusted_ceilinglightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), + adjusted_ceilinglightlevel, foggy, frontsector->GetAlpha(sector_t::ceiling), !!(frontsector->GetFlags(sector_t::ceiling) & PLANEF_ADDITIVE), frontsector->planes[sector_t::ceiling].xform, @@ -588,7 +588,7 @@ namespace swrenderer { floorplane = Thread->PlaneList->FindPlane(frontsector->floorplane, frontsector->GetTexture(sector_t::floor), - adjusted_floorlightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), + adjusted_floorlightlevel, foggy, frontsector->GetAlpha(sector_t::floor), !!(frontsector->GetFlags(sector_t::floor) & PLANEF_ADDITIVE), frontsector->planes[sector_t::floor].xform, @@ -613,10 +613,10 @@ namespace swrenderer // [RH] Add particles if ((unsigned int)(sub->Index()) < level.subsectors.Size()) { // Only do it for the main BSP. - int shade = LightVisibility::LightLevelToShade((floorlightlevel + ceilinglightlevel) / 2 + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); + int lightlevel = (floorlightlevel + ceilinglightlevel) / 2; for (int i = ParticlesInSubsec[sub->Index()]; i != NO_PARTICLE; i = Particles[i].snext) { - RenderParticle::Project(Thread, Particles + i, sub->sector, shade, FakeSide, foggy); + RenderParticle::Project(Thread, &Particles[i], sub->sector, lightlevel, FakeSide, foggy); } } @@ -732,7 +732,7 @@ namespace swrenderer VisiblePlane *floorplane3d = Thread->PlaneList->FindPlane( tempsec.floorplane, tempsec.GetTexture(sector_t::floor), - floorlightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), + floorlightlevel, foggy, tempsec.GetAlpha(sector_t::floor), !!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS), tempsec.planes[position].xform, @@ -800,7 +800,7 @@ namespace swrenderer VisiblePlane *ceilingplane3d = Thread->PlaneList->FindPlane( tempsec.ceilingplane, tempsec.GetTexture(sector_t::ceiling), - ceilinglightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), + ceilinglightlevel, foggy, tempsec.GetAlpha(sector_t::ceiling), !!(clip3d->fakeFloor->fakeFloor->flags & FF_ADDITIVETRANS), tempsec.planes[position].xform, @@ -891,8 +891,6 @@ namespace swrenderer //sec->validcount = validcount; SeenSpriteSectors.insert(sec); - int spriteshade = LightVisibility::LightLevelToShade(lightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); - // Handle all things in sector. for (auto p = sec->touching_renderthings; p != nullptr; p = p->m_snext) { @@ -947,25 +945,24 @@ namespace swrenderer else if (GetThingSprite(thing, sprite)) { FDynamicColormap *thingColormap = basecolormap; - int thingShade = spriteshade; + int thinglightlevel = lightlevel; if (sec->sectornum != thing->Sector->sectornum) // compare sectornums to account for R_FakeFlat copies. { - int lightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); - thingShade = LightVisibility::LightLevelToShade(lightlevel + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()), foggy); + thinglightlevel = thing->Sector->GetTexture(sector_t::ceiling) == skyflatnum ? thing->Sector->GetCeilingLight() : thing->Sector->GetFloorLight(); thingColormap = GetColorTable(thing->Sector->Colormap, thing->Sector->SpecialColors[sector_t::sprites], true); } if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE) { - RenderWallSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, thingShade, foggy, thingColormap); + RenderWallSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, thinglightlevel, foggy, thingColormap); } else if (sprite.voxel) { - RenderVoxel::Project(Thread, thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); + RenderVoxel::Project(Thread, thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap); } else { - RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thingShade, foggy, thingColormap); + RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap); } } } @@ -1023,16 +1020,16 @@ namespace swrenderer { sprite.picnum = thing->picnum; - sprite.tex = TexMan(sprite.picnum); - if (sprite.tex->UseType == ETextureType::Null) + sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, true); + if (!sprite.tex->isValid()) { return false; } - if (sprite.tex->Rotations != 0xFFFF) + if (sprite.tex->GetRotations() != 0xFFFF) { // choose a different rotation based on player view - spriteframe_t *sprframe = &SpriteFrames[sprite.tex->Rotations]; + spriteframe_t *sprframe = &SpriteFrames[sprite.tex->GetRotations()]; DAngle ang = (sprite.pos - Thread->Viewport->viewpoint.Pos).Angle(); angle_t rot; if (sprframe->Texture[0] == sprframe->Texture[1]) @@ -1054,7 +1051,7 @@ namespace swrenderer { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan[sprite.picnum]; // Do not animate the rotation + sprite.tex = TexMan.GetPalettedTexture(sprite.picnum, false); // Do not animate the rotation } } else @@ -1084,7 +1081,7 @@ namespace swrenderer { sprite.renderflags ^= RF_XFLIP; } - sprite.tex = TexMan[tex]; // Do not animate the rotation + sprite.tex = TexMan.GetPalettedTexture(tex, false); // Do not animate the rotation } if (r_drawvoxels) @@ -1096,7 +1093,7 @@ namespace swrenderer return false; } - if (sprite.voxel == nullptr && (sprite.tex == nullptr || sprite.tex->UseType == ETextureType::Null)) + if (sprite.voxel == nullptr && (sprite.tex == nullptr || !sprite.tex->isValid())) { return false; } diff --git a/src/swrenderer/scene/r_translucent_pass.h b/src/swrenderer/scene/r_translucent_pass.h index 5c28749a7..77344e2f6 100644 --- a/src/swrenderer/scene/r_translucent_pass.h +++ b/src/swrenderer/scene/r_translucent_pass.h @@ -23,8 +23,6 @@ #include "tarray.h" -#define MINZ double((2048*4) / double(1 << 20)) - struct particle_t; struct FVoxel; diff --git a/src/swrenderer/segments/r_drawsegment.h b/src/swrenderer/segments/r_drawsegment.h index a43e4dc28..8df4153ca 100644 --- a/src/swrenderer/segments/r_drawsegment.h +++ b/src/swrenderer/segments/r_drawsegment.h @@ -38,7 +38,7 @@ namespace swrenderer float yscale; uint8_t silhouette = 0; // 0=none, 1=bottom, 2=top, 3=both bool bFogBoundary = false; - int shade = 0; + int lightlevel = 0; bool foggy = false; // Pointers to lists for sprite clipping, all three adjusted so [x1] is first value. diff --git a/src/swrenderer/textures/r_swtexture.cpp b/src/swrenderer/textures/r_swtexture.cpp new file mode 100644 index 000000000..89f6f3bda --- /dev/null +++ b/src/swrenderer/textures/r_swtexture.cpp @@ -0,0 +1,602 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "r_swtexture.h" +#include "bitmap.h" +#include "m_alloc.h" +#include "imagehelpers.h" + +EXTERN_CVAR(Bool, gl_texture_usehires) + + +FSoftwareTexture *FTexture::GetSoftwareTexture() +{ + if (!SoftwareTexture) + { + if (bHasCanvas) SoftwareTexture = new FSWCanvasTexture(this); + else if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped); + else SoftwareTexture = new FSoftwareTexture(this); + } + return SoftwareTexture; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSoftwareTexture::FSoftwareTexture(FTexture *tex) +{ + mTexture = tex; + mSource = tex; + + mBufferFlags = (gl_texture_usehires && !tex->isScaled() && tex->GetImage() && !tex->isSprite() ) ? CTF_CheckHires|CTF_ProcessData : CTF_ProcessData; + auto info = tex->CreateTexBuffer(0, CTF_CheckOnly| mBufferFlags); + mPhysicalWidth = info.mWidth; + mPhysicalHeight = info.mHeight; + mPhysicalScale = mPhysicalWidth / tex->Width; + CalcBitSize(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSoftwareTexture::CalcBitSize () +{ + // WidthBits is rounded down, and HeightBits is rounded up + int i; + + for (i = 0; (1 << i) < GetPhysicalWidth(); ++i) + { } + + WidthBits = i; + + // Having WidthBits that would allow for columns past the end of the + // texture is not allowed, even if it means the entire texture is + // not drawn. + if (GetPhysicalWidth() < (1 << WidthBits)) + { + WidthBits--; + } + WidthMask = (1 << WidthBits) - 1; + + //
The minimum height is 2, because we cannot shift right 32 bits. + // Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it. + for (i = 0; (1 << i) < GetPhysicalHeight(); ++i) + { } + + HeightBits = i; +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint8_t *FSoftwareTexture::GetPixels(int style) +{ + if (Pixels.Size() == 0 || CheckModified(style)) + { + if (mPhysicalScale == 1) + { + Pixels = mSource->Get8BitPixels(style); + } + else + { + auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + Pixels.Resize(GetPhysicalWidth()*GetPhysicalHeight()); + PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; + if (!style) + { + for (int y = 0; y < GetPhysicalHeight(); y++) + { + for (int x = 0; x < GetPhysicalWidth(); x++) + { + Pixels[y + x * GetPhysicalHeight()] = ImageHelpers::RGBToPalette(false, pe[x + y * GetPhysicalWidth()], true); + } + } + } + else + { + for (int y = 0; y < GetPhysicalHeight(); y++) + { + for (int x = 0; x < GetPhysicalWidth(); x++) + { + Pixels[y + x * GetPhysicalHeight()] = pe[x + y * GetPhysicalWidth()].Luminance(); + } + } + } + } + } + return Pixels.Data(); +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint32_t *FSoftwareTexture::GetPixelsBgra() +{ + if (PixelsBgra.Size() == 0 || CheckModified(2)) + { + if (mPhysicalScale == 1) + { + FBitmap bitmap = mTexture->GetBgraBitmap(nullptr); + GenerateBgraFromBitmap(bitmap); + } + else + { + auto tempbuffer = mTexture->CreateTexBuffer(0, mBufferFlags); + CreatePixelsBgraWithMipmaps(); + PalEntry *pe = (PalEntry*)tempbuffer.mBuffer; + for (int y = 0; y < GetPhysicalHeight(); y++) + { + for (int x = 0; x < GetPhysicalWidth(); x++) + { + PixelsBgra[y + x * GetPhysicalHeight()] = pe[x + y * GetPhysicalWidth()]; + } + } + GenerateBgraMipmaps(); + } + } + return PixelsBgra.Data(); +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint8_t *FSoftwareTexture::GetColumn(int index, unsigned int column, const FSoftwareTextureSpan **spans_out) +{ + auto Pixeldata = GetPixels(index); + if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + { + if (WidthMask + 1 == GetPhysicalWidth()) + { + column &= WidthMask; + } + else + { + column %= GetPhysicalWidth(); + } + } + if (spans_out != nullptr) + { + if (Spandata[index] == nullptr) + { + Spandata[index] = CreateSpans(Pixeldata); + } + *spans_out = Spandata[index][column]; + } + return Pixeldata + column * GetPhysicalHeight(); +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out) +{ + auto Pixeldata = GetPixelsBgra(); + if ((unsigned)column >= (unsigned)GetPhysicalWidth()) + { + if (WidthMask + 1 == GetPhysicalWidth()) + { + column &= WidthMask; + } + else + { + column %= GetPhysicalWidth(); + } + } + if (spans_out != nullptr) + { + if (Spandata[2] == nullptr) + { + Spandata[2] = CreateSpans(Pixeldata); + } + *spans_out = Spandata[2][column]; + } + return Pixeldata + column * GetPhysicalHeight(); +} + +//========================================================================== +// +// +// +//========================================================================== + +static bool isTranslucent(uint8_t val) +{ + return val == 0; +} + +static bool isTranslucent(uint32_t val) +{ + return (val & 0xff000000) == 0; +} + +template +FSoftwareTextureSpan **FSoftwareTexture::CreateSpans (const T *pixels) +{ + FSoftwareTextureSpan **spans, *span; + + if (!mTexture->isMasked()) + { // Texture does not have holes, so it can use a simpler span structure + spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*GetPhysicalWidth() + sizeof(FSoftwareTextureSpan)*2); + span = (FSoftwareTextureSpan *)&spans[GetPhysicalWidth()]; + for (int x = 0; x < GetPhysicalWidth(); ++x) + { + spans[x] = span; + } + span[0].Length = GetPhysicalHeight(); + span[0].TopOffset = 0; + span[1].Length = 0; + span[1].TopOffset = 0; + } + else + { // Texture might have holes, so build a complete span structure + int numcols = GetPhysicalWidth(); + int numrows = GetPhysicalHeight(); + int numspans = numcols; // One span to terminate each column + const T *data_p; + bool newspan; + int x, y; + + data_p = pixels; + + // Count the number of spans in this texture + for (x = numcols; x > 0; --x) + { + newspan = true; + for (y = numrows; y > 0; --y) + { + + if (isTranslucent(*data_p++)) + { + if (!newspan) + { + newspan = true; + } + } + else if (newspan) + { + newspan = false; + numspans++; + } + } + } + + // Allocate space for the spans + spans = (FSoftwareTextureSpan **)M_Malloc (sizeof(FSoftwareTextureSpan*)*numcols + sizeof(FSoftwareTextureSpan)*numspans); + + // Fill in the spans + for (x = 0, span = (FSoftwareTextureSpan *)&spans[numcols], data_p = pixels; x < numcols; ++x) + { + newspan = true; + spans[x] = span; + for (y = 0; y < numrows; ++y) + { + if (isTranslucent(*data_p++)) + { + if (!newspan) + { + newspan = true; + span++; + } + } + else + { + if (newspan) + { + newspan = false; + span->TopOffset = y; + span->Length = 1; + } + else + { + span->Length++; + } + } + } + if (!newspan) + { + span++; + } + span->TopOffset = 0; + span->Length = 0; + span++; + } + } + return spans; +} + +void FSoftwareTexture::FreeSpans (FSoftwareTextureSpan **spans) +{ + M_Free (spans); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSoftwareTexture::GenerateBgraFromBitmap(const FBitmap &bitmap) +{ + CreatePixelsBgraWithMipmaps(); + + // Transpose + const uint32_t *src = (const uint32_t *)bitmap.GetPixels(); + uint32_t *dest = PixelsBgra.Data(); + for (int x = 0; x < GetPhysicalWidth(); x++) + { + for (int y = 0; y < GetPhysicalHeight(); y++) + { + dest[y + x * GetPhysicalHeight()] = src[x + y * GetPhysicalWidth()]; + } + } + + GenerateBgraMipmaps(); +} + +void FSoftwareTexture::CreatePixelsBgraWithMipmaps() +{ + int levels = MipmapLevels(); + int buffersize = 0; + for (int i = 0; i < levels; i++) + { + int w = MAX(GetPhysicalWidth() >> i, 1); + int h = MAX(GetPhysicalHeight() >> i, 1); + buffersize += w * h; + } + PixelsBgra.Resize(buffersize); +} + +int FSoftwareTexture::MipmapLevels() +{ + int widthbits = 0; + while ((GetPhysicalWidth() >> widthbits) != 0) widthbits++; + + int heightbits = 0; + while ((GetPhysicalHeight() >> heightbits) != 0) heightbits++; + + return MAX(widthbits, heightbits); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSoftwareTexture::GenerateBgraMipmaps() +{ + struct Color4f + { + float a, r, g, b; + Color4f operator*(const Color4f &v) const { return Color4f{ a * v.a, r * v.r, g * v.g, b * v.b }; } + Color4f operator/(const Color4f &v) const { return Color4f{ a / v.a, r / v.r, g / v.g, b / v.b }; } + Color4f operator+(const Color4f &v) const { return Color4f{ a + v.a, r + v.r, g + v.g, b + v.b }; } + Color4f operator-(const Color4f &v) const { return Color4f{ a - v.a, r - v.r, g - v.g, b - v.b }; } + Color4f operator*(float s) const { return Color4f{ a * s, r * s, g * s, b * s }; } + Color4f operator/(float s) const { return Color4f{ a / s, r / s, g / s, b / s }; } + Color4f operator+(float s) const { return Color4f{ a + s, r + s, g + s, b + s }; } + Color4f operator-(float s) const { return Color4f{ a - s, r - s, g - s, b - s }; } + }; + + int levels = MipmapLevels(); + std::vector image(PixelsBgra.Size()); + + // Convert to normalized linear colorspace + { + for (int x = 0; x < GetPhysicalWidth(); x++) + { + for (int y = 0; y < GetPhysicalHeight(); y++) + { + uint32_t c8 = PixelsBgra[x * GetPhysicalHeight() + y]; + Color4f c; + c.a = powf(APART(c8) * (1.0f / 255.0f), 2.2f); + c.r = powf(RPART(c8) * (1.0f / 255.0f), 2.2f); + c.g = powf(GPART(c8) * (1.0f / 255.0f), 2.2f); + c.b = powf(BPART(c8) * (1.0f / 255.0f), 2.2f); + image[x * GetPhysicalHeight() + y] = c; + } + } + } + + // Generate mipmaps + { + std::vector smoothed(GetPhysicalWidth() * GetPhysicalHeight()); + Color4f *src = image.data(); + Color4f *dest = src + GetPhysicalWidth() * GetPhysicalHeight(); + for (int i = 1; i < levels; i++) + { + int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1); + int srch = MAX(GetPhysicalHeight() >> (i - 1), 1); + int w = MAX(GetPhysicalWidth() >> i, 1); + int h = MAX(GetPhysicalHeight() >> i, 1); + + // Downscale + for (int x = 0; x < w; x++) + { + int sx0 = x * 2; + int sx1 = MIN((x + 1) * 2, srcw - 1); + for (int y = 0; y < h; y++) + { + int sy0 = y * 2; + int sy1 = MIN((y + 1) * 2, srch - 1); + + Color4f src00 = src[sy0 + sx0 * srch]; + Color4f src01 = src[sy1 + sx0 * srch]; + Color4f src10 = src[sy0 + sx1 * srch]; + Color4f src11 = src[sy1 + sx1 * srch]; + Color4f c = (src00 + src01 + src10 + src11) * 0.25f; + + dest[y + x * h] = c; + } + } + + // Sharpen filter with a 3x3 kernel: + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + Color4f c = { 0.0f, 0.0f, 0.0f, 0.0f }; + for (int kx = -1; kx < 2; kx++) + { + for (int ky = -1; ky < 2; ky++) + { + int a = y + ky; + int b = x + kx; + if (a < 0) a = h - 1; + if (a == h) a = 0; + if (b < 0) b = w - 1; + if (b == w) b = 0; + c = c + dest[a + b * h]; + } + } + c = c * (1.0f / 9.0f); + smoothed[y + x * h] = c; + } + } + float k = 0.08f; + for (int j = 0; j < w * h; j++) + dest[j] = dest[j] + (dest[j] - smoothed[j]) * k; + + src = dest; + dest += w * h; + } + } + + // Convert to bgra8 sRGB colorspace + { + Color4f *src = image.data() + GetPhysicalWidth() * GetPhysicalHeight(); + uint32_t *dest = PixelsBgra.Data() + GetPhysicalWidth() * GetPhysicalHeight(); + for (int i = 1; i < levels; i++) + { + int w = MAX(GetPhysicalWidth() >> i, 1); + int h = MAX(GetPhysicalHeight() >> i, 1); + for (int j = 0; j < w * h; j++) + { + uint32_t a = (uint32_t)clamp(powf(MAX(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t r = (uint32_t)clamp(powf(MAX(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t g = (uint32_t)clamp(powf(MAX(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + uint32_t b = (uint32_t)clamp(powf(MAX(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); + dest[j] = (a << 24) | (r << 16) | (g << 8) | b; + } + src += w * h; + dest += w * h; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSoftwareTexture::GenerateBgraMipmapsFast() +{ + uint32_t *src = PixelsBgra.Data(); + uint32_t *dest = src + GetPhysicalWidth() * GetPhysicalHeight(); + int levels = MipmapLevels(); + for (int i = 1; i < levels; i++) + { + int srcw = MAX(GetPhysicalWidth() >> (i - 1), 1); + int srch = MAX(GetPhysicalHeight() >> (i - 1), 1); + int w = MAX(GetPhysicalWidth() >> i, 1); + int h = MAX(GetPhysicalHeight() >> i, 1); + + for (int x = 0; x < w; x++) + { + int sx0 = x * 2; + int sx1 = MIN((x + 1) * 2, srcw - 1); + + for (int y = 0; y < h; y++) + { + int sy0 = y * 2; + int sy1 = MIN((y + 1) * 2, srch - 1); + + uint32_t src00 = src[sy0 + sx0 * srch]; + uint32_t src01 = src[sy1 + sx0 * srch]; + uint32_t src10 = src[sy0 + sx1 * srch]; + uint32_t src11 = src[sy1 + sx1 * srch]; + + uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4; + uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4; + uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4; + uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4; + + dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue; + } + } + + src = dest; + dest += w * h; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSoftwareTexture::FreeAllSpans() +{ + for(int i = 0; i < 3; i++) + { + if (Spandata[i] != nullptr) + { + FreeSpans (Spandata[i]); + Spandata[i] = nullptr; + } + } +} + diff --git a/src/swrenderer/textures/r_swtexture.h b/src/swrenderer/textures/r_swtexture.h new file mode 100644 index 000000000..f4baeb21b --- /dev/null +++ b/src/swrenderer/textures/r_swtexture.h @@ -0,0 +1,198 @@ +#pragma once +#include "textures/textures.h" +#include "v_video.h" +#include "g_levellocals.h" + + +struct FSoftwareTextureSpan +{ + uint16_t TopOffset; + uint16_t Length; // A length of 0 terminates this column +}; + + +// For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up. +class FSoftwareTexture +{ +protected: + FTexture *mTexture; + FTexture *mSource; + TArray Pixels; + TArray PixelsBgra; + FSoftwareTextureSpan **Spandata[3] = { }; + uint8_t WidthBits = 0, HeightBits = 0; + uint16_t WidthMask = 0; + int mPhysicalWidth, mPhysicalHeight; + int mPhysicalScale; + int mBufferFlags; + + void FreeAllSpans(); + template FSoftwareTextureSpan **CreateSpans(const T *pixels); + void FreeSpans(FSoftwareTextureSpan **spans); + void CalcBitSize(); + +public: + FSoftwareTexture(FTexture *tex); + + virtual ~FSoftwareTexture() + { + FreeAllSpans(); + } + + FTexture *GetTexture() const + { + return mTexture; + } + + // The feature from hell... :( + bool useWorldPanning() const + { + return mTexture->bWorldPanning || (level.flags3 & LEVEL3_FORCEWORLDPANNING); + } + + bool isMasked() + { + return mTexture->bMasked; + } + + int GetSkyOffset() const { return mTexture->GetSkyOffset(); } + PalEntry GetSkyCapColor(bool bottom) const { return mTexture->GetSkyCapColor(bottom); } + + int GetWidth () { return mTexture->GetWidth(); } + int GetHeight () { return mTexture->GetHeight(); } + int GetWidthBits() { return WidthBits; } + int GetHeightBits() { return HeightBits; } + + int GetScaledWidth () { return mTexture->GetScaledWidth(); } + int GetScaledHeight () { return mTexture->GetScaledHeight(); } + double GetScaledWidthDouble () { return mTexture->GetScaledWidthDouble(); } + double GetScaledHeightDouble () { return mTexture->GetScaledHeightDouble(); } + + // Now with improved offset adjustment. + int GetLeftOffset(int adjusted) { return mTexture->GetLeftOffset(adjusted); } + int GetTopOffset(int adjusted) { return mTexture->GetTopOffset(adjusted); } + int GetScaledLeftOffset (int adjusted) { return mTexture->GetScaledLeftOffset(adjusted); } + int GetScaledTopOffset (int adjusted) { return mTexture->GetScaledTopOffset(adjusted); } + double GetScaledLeftOffsetDouble(int adjusted) { return mTexture->GetScaledLeftOffsetDouble(adjusted); } + double GetScaledTopOffsetDouble(int adjusted) { return mTexture->GetScaledTopOffsetDouble(adjusted); } + + // Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets + // should use these, so that if changes are needed, this is the only place to edit. + + // For the original software renderer + int GetLeftOffsetSW() { return GetLeftOffset(r_spriteadjustSW); } + int GetTopOffsetSW() { return GetTopOffset(r_spriteadjustSW); } + int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); } + int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); } + + // For the softpoly renderer, in case it wants adjustment + int GetLeftOffsetPo() { return GetLeftOffset(r_spriteadjustSW); } + int GetTopOffsetPo() { return GetTopOffset(r_spriteadjustSW); } + int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); } + int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); } + + DVector2 GetScale() const { return mTexture->Scale; } + int GetPhysicalWidth() { return mPhysicalWidth; } + int GetPhysicalHeight() { return mPhysicalHeight; } + int GetPhysicalScale() const { return mPhysicalScale; } + + virtual void Unload() + { + Pixels.Reset(); + PixelsBgra.Reset(); + } + + // Returns true if the next call to GetPixels() will return an image different from the + // last call to GetPixels(). This should be considered valid only if a call to CheckModified() + // is immediately followed by a call to GetPixels(). + virtual bool CheckModified (int which) { return false; } + + void GenerateBgraFromBitmap(const FBitmap &bitmap); + void CreatePixelsBgraWithMipmaps(); + void GenerateBgraMipmaps(); + void GenerateBgraMipmapsFast(); + int MipmapLevels(); + + // Returns true if GetPixelsBgra includes mipmaps + virtual bool Mipmapped() { return true; } + + // Returns a single column of the texture + virtual const uint8_t *GetColumn(int style, unsigned int column, const FSoftwareTextureSpan **spans_out); + + // Returns a single column of the texture, in BGRA8 format + virtual const uint32_t *GetColumnBgra(unsigned int column, const FSoftwareTextureSpan **spans_out); + + // Returns the whole texture, stored in column-major order, in BGRA8 format + virtual const uint32_t *GetPixelsBgra(); + + // Returns the whole texture, stored in column-major order + virtual const uint8_t *GetPixels(int style); + + const uint8_t *GetPixels(FRenderStyle style) + { + bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); + return GetPixels(alpha); + } + + // Checks if the pixel data is loaded. + bool CheckPixels() const + { + return V_IsTrueColor() ? PixelsBgra.Size() > 0 : Pixels.Size() > 0; + } + + const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const FSoftwareTextureSpan **spans_out) + { + bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); + return GetColumn(alpha, column, spans_out); + } + +}; + +// A texture that returns a wiggly version of another texture. +class FWarpTexture : public FSoftwareTexture +{ + TArray WarpedPixels[2]; + TArray WarpedPixelsRgba; + + int bWarped = 0; + uint64_t GenTime[3] = { 0, 0, 0 }; + int WidthOffsetMultiplier, HeightOffsetMultiplier; // [mxd] + +public: + FWarpTexture (FTexture *source, int warptype); + + const uint32_t *GetPixelsBgra() override; + const uint8_t *GetPixels(int style) override; + bool CheckModified (int which) override; + +private: + + int NextPo2 (int v); // [mxd] + void SetupMultipliers (int width, int height); // [mxd] +}; + +class FSWCanvasTexture : public FSoftwareTexture +{ + void MakeTexture(); + void MakeTextureBgra(); + + DCanvas *Canvas = nullptr; + DCanvas *CanvasBgra = nullptr; + +public: + + FSWCanvasTexture(FTexture *source) : FSoftwareTexture(source) {} + ~FSWCanvasTexture(); + + // Returns the whole texture, stored in column-major order + const uint32_t *GetPixelsBgra() override; + const uint8_t *GetPixels(int style) override; + + virtual void Unload() override; + void UpdatePixels(bool truecolor); + + DCanvas *GetCanvas() { return Canvas; } + DCanvas *GetCanvasBgra() { return CanvasBgra; } + bool Mipmapped() override { return false; } + +}; \ No newline at end of file diff --git a/src/swrenderer/textures/swcanvastexture.cpp b/src/swrenderer/textures/swcanvastexture.cpp new file mode 100644 index 000000000..8c47ad152 --- /dev/null +++ b/src/swrenderer/textures/swcanvastexture.cpp @@ -0,0 +1,189 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "r_swtexture.h" +#include "bitmap.h" +#include "m_alloc.h" +#include "imagehelpers.h" + + +FSWCanvasTexture::~FSWCanvasTexture() +{ + if (Canvas != nullptr) + { + delete Canvas; + Canvas = nullptr; + } + + if (CanvasBgra != nullptr) + { + delete CanvasBgra; + CanvasBgra = nullptr; + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +const uint8_t *FSWCanvasTexture::GetPixels(int style) +{ + static_cast(mTexture)->NeedUpdate(); + if (Canvas == nullptr) + { + MakeTexture(); + } + return Pixels.Data(); + +} + +//========================================================================== +// +// +// +//========================================================================== + +const uint32_t *FSWCanvasTexture::GetPixelsBgra() +{ + static_cast(mTexture)->NeedUpdate(); + if (CanvasBgra == nullptr) + { + MakeTextureBgra(); + } + return PixelsBgra.Data(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::MakeTexture () +{ + Canvas = new DCanvas (GetWidth(), GetHeight(), false); + Pixels.Resize(GetWidth() * GetHeight()); + + // Draw a special "unrendered" initial texture into the buffer. + memset (Pixels.Data(), 0, GetWidth() * GetHeight() / 2); + memset (Pixels.Data() + GetWidth() * GetHeight() / 2, 255, GetWidth() * GetHeight() / 2); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::MakeTextureBgra() +{ + CanvasBgra = new DCanvas(GetWidth(), GetHeight(), true); + PixelsBgra.Resize(GetWidth() * GetHeight()); + + // Draw a special "unrendered" initial texture into the buffer. + memset(PixelsBgra.Data(), 0, 4* GetWidth() * GetHeight() / 2); + memset(PixelsBgra.Data() + GetWidth() * GetHeight() / 2, 255, 4* GetWidth() * GetHeight() / 2); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::Unload () +{ + if (Canvas != nullptr) + { + delete Canvas; + Canvas = nullptr; + } + + if (CanvasBgra != nullptr) + { + delete CanvasBgra; + CanvasBgra = nullptr; + } + + FSoftwareTexture::Unload(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSWCanvasTexture::UpdatePixels(bool truecolor) +{ + + if (Canvas->IsBgra()) + { + ImageHelpers::FlipNonSquareBlock(PixelsBgra.Data(), (const uint32_t*)Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch()); + } + else + { + ImageHelpers::FlipNonSquareBlockRemap(Pixels.Data(), Canvas->GetPixels(), GetWidth(), GetHeight(), Canvas->GetPitch(), GPalette.Remap); + } + + if (truecolor) + { + // True color render still sometimes uses palette textures (for sprites, mostly). + // We need to make sure that both pixel buffers contain data: + int width = GetWidth(); + int height = GetHeight(); + uint8_t *palbuffer = const_cast(GetPixels(0)); + const uint32_t *bgrabuffer = GetPixelsBgra(); + for (int x = 0; x < width; x++) + { + for (int y = 0; y < height; y++) + { + uint32_t color = bgrabuffer[y]; + int r = RPART(color); + int g = GPART(color); + int b = BPART(color); + palbuffer[y] = RGB32k.RGB[r >> 3][g >> 3][b >> 3]; + } + palbuffer += height; + bgrabuffer += height; + } + } + + static_cast(mTexture)->SetUpdated(false); +} \ No newline at end of file diff --git a/src/textures/warpbuffer.h b/src/swrenderer/textures/warpbuffer.h similarity index 100% rename from src/textures/warpbuffer.h rename to src/swrenderer/textures/warpbuffer.h diff --git a/src/textures/formats/warptexture.cpp b/src/swrenderer/textures/warptexture.cpp similarity index 53% rename from src/textures/formats/warptexture.cpp rename to src/swrenderer/textures/warptexture.cpp index 88a761ba0..22cbcaf7d 100644 --- a/src/textures/formats/warptexture.cpp +++ b/src/swrenderer/textures/warptexture.cpp @@ -4,6 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -35,67 +36,51 @@ #include "doomtype.h" #include "r_utility.h" -#include "textures/textures.h" +#include "r_swtexture.h" #include "warpbuffer.h" #include "v_video.h" FWarpTexture::FWarpTexture (FTexture *source, int warptype) - : SourcePic (source) + : FSoftwareTexture (source) { - CopyInfo(source); if (warptype == 2) SetupMultipliers(256, 128); SetupMultipliers(128, 128); // [mxd] bWarped = warptype; } -FWarpTexture::~FWarpTexture () +bool FWarpTexture::CheckModified (int style) { - Unload (); - delete SourcePic; -} - -void FWarpTexture::Unload () -{ - SourcePic->Unload (); - FWorldTexture::Unload(); - FreeAllSpans(); -} - -bool FWarpTexture::CheckModified (FRenderStyle style) -{ - return screen->FrameTime != GenTime[!!(style.Flags & STYLEF_RedIsAlpha)]; + return screen->FrameTime != GenTime[style]; } const uint32_t *FWarpTexture::GetPixelsBgra() { - auto Pixels = GetPixels(DefaultRenderStyle()); - if (PixelsBgra.empty() || GenTime[0] != GenTimeBgra) + uint64_t time = screen->FrameTime; + if (time != GenTime[2]) { - CreatePixelsBgraWithMipmaps(); - for (int i = 0; i < Width * Height; i++) - { - if (Pixels[i] != 0) - PixelsBgra[i] = 0xff000000 | GPalette.BaseColors[Pixels[i]].d; - else - PixelsBgra[i] = 0; - } - GenerateBgraMipmapsFast(); - GenTimeBgra = GenTime[0]; + auto otherpix = FSoftwareTexture::GetPixelsBgra(); + WarpedPixelsRgba.Resize(GetWidth() * GetHeight()); + WarpBuffer(WarpedPixelsRgba.Data(), otherpix, GetWidth(), GetHeight(), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + FreeAllSpans(); + GenTime[2] = time; } - return PixelsBgra.data(); + return WarpedPixelsRgba.Data(); } -uint8_t *FWarpTexture::MakeTexture(FRenderStyle style) +const uint8_t *FWarpTexture::GetPixels(int index) { uint64_t time = screen->FrameTime; - const uint8_t *otherpix = SourcePic->GetPixels(style); - auto Pixels = new uint8_t[Width * Height]; - WarpBuffer(Pixels, otherpix, Width, Height, WidthOffsetMultiplier, HeightOffsetMultiplier, time, Speed, bWarped); - FreeAllSpans(); - GenTime[!!(style.Flags & STYLEF_RedIsAlpha)] = time; - return Pixels; + if (time != GenTime[index]) + { + const uint8_t *otherpix = FSoftwareTexture::GetPixels(index); + WarpedPixels[index].Resize(GetWidth() * GetHeight()); + WarpBuffer(WarpedPixels[index].Data(), otherpix, GetWidth(), GetHeight(), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped); + FreeAllSpans(); + GenTime[index] = time; + } + return WarpedPixels[index].Data(); } // [mxd] Non power of 2 textures need different offset multipliers, otherwise warp animation won't sync across texture @@ -103,10 +88,10 @@ void FWarpTexture::SetupMultipliers (int width, int height) { WidthOffsetMultiplier = width; HeightOffsetMultiplier = height; - int widthpo2 = NextPo2(Width); - int heightpo2 = NextPo2(Height); - if(widthpo2 != Width) WidthOffsetMultiplier = (int)(WidthOffsetMultiplier * ((float)widthpo2 / Width)); - if(heightpo2 != Height) HeightOffsetMultiplier = (int)(HeightOffsetMultiplier * ((float)heightpo2 / Height)); + int widthpo2 = NextPo2(GetWidth()); + int heightpo2 = NextPo2(GetHeight()); + if(widthpo2 != GetWidth()) WidthOffsetMultiplier = (int)(WidthOffsetMultiplier * ((float)widthpo2 / GetWidth())); + if(heightpo2 != GetHeight()) HeightOffsetMultiplier = (int)(HeightOffsetMultiplier * ((float)heightpo2 / GetHeight())); } int FWarpTexture::NextPo2 (int v) @@ -119,24 +104,3 @@ int FWarpTexture::NextPo2 (int v) v |= v >> 16; return ++v; } - -//========================================================================== -// -// FMultiPatchTexture :: CopyTrueColorPixels -// -// True color texture generation must never hit the paletted path which -// always warps the buffer. -// As a result even CopyTrueColorTranslated must be overrideen here. -// -//========================================================================== - -int FWarpTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) -{ - return SourcePic->CopyTrueColorPixels(bmp, x, y, rotate, inf); -} - -int FWarpTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf) -{ - return SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, remap, inf); -} - diff --git a/src/swrenderer/things/r_decal.cpp b/src/swrenderer/things/r_decal.cpp index 1f9dbf6a7..f5393ce0b 100644 --- a/src/swrenderer/things/r_decal.cpp +++ b/src/swrenderer/things/r_decal.cpp @@ -57,15 +57,15 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); namespace swrenderer { - void RenderDecal::RenderDecals(RenderThread *thread, side_t *sidedef, DrawSegment *draw_segment, int wallshade, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass) + void RenderDecal::RenderDecals(RenderThread *thread, side_t *sidedef, DrawSegment *draw_segment, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass) { for (DBaseDecal *decal = sidedef->AttachedDecals; decal != NULL; decal = decal->WallNext) { - Render(thread, sidedef, decal, draw_segment, wallshade, lightleft, lightstep, curline, wallC, foggy, basecolormap, walltop, wallbottom, drawsegPass); + Render(thread, sidedef, decal, draw_segment, lightlevel, lightleft, lightstep, curline, wallC, foggy, basecolormap, walltop, wallbottom, drawsegPass); } } - void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, int wallshade, float lightleft, float lightstep, seg_t *curline, const FWallCoords &savecoord, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass) + void RenderDecal::Render(RenderThread *thread, side_t *wall, DBaseDecal *decal, DrawSegment *clipper, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &savecoord, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass) { DVector2 decal_left, decal_right, decal_pos; int x1, x2; @@ -129,13 +129,14 @@ namespace swrenderer } } - FTexture *WallSpriteTile = TexMan(decal->PicNum, true); + FTexture *tex = TexMan.GetPalettedTexture(decal->PicNum, true); flipx = (uint8_t)(decal->RenderFlags & RF_XFLIP); - if (WallSpriteTile == NULL || WallSpriteTile->UseType == ETextureType::Null) + if (tex == NULL || !tex->isValid()) { return; } + FSoftwareTexture *WallSpriteTile = tex->GetSoftwareTexture(); // Determine left and right edges of sprite. Since this sprite is bound // to a wall, we use the wall's angle instead of the decal's. This is @@ -317,7 +318,7 @@ namespace swrenderer { if (calclighting) { // calculate lighting - drawerargs.SetLight(usecolormap, light, wallshade); + drawerargs.SetLight(usecolormap, light, lightlevel, foggy, thread->Viewport.get()); } DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, decal->RenderStyle); light += lightstep; @@ -333,7 +334,7 @@ namespace swrenderer } while (needrepeat--); } - void RenderDecal::DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style) + void RenderDecal::DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FSoftwareTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style) { auto viewport = thread->Viewport.get(); diff --git a/src/swrenderer/things/r_decal.h b/src/swrenderer/things/r_decal.h index e617b04a6..3fe3956b1 100644 --- a/src/swrenderer/things/r_decal.h +++ b/src/swrenderer/things/r_decal.h @@ -12,10 +12,10 @@ namespace swrenderer class RenderDecal { public: - static void RenderDecals(RenderThread *thread, side_t *wall, DrawSegment *draw_segment, int wallshade, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass); + static void RenderDecals(RenderThread *thread, side_t *wall, DrawSegment *draw_segment, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass); private: - static void Render(RenderThread *thread, side_t *wall, DBaseDecal *first, DrawSegment *clipper, int wallshade, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass); - static void DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style); + static void Render(RenderThread *thread, side_t *wall, DBaseDecal *first, DrawSegment *clipper, int lightlevel, float lightleft, float lightstep, seg_t *curline, const FWallCoords &wallC, bool foggy, FDynamicColormap *basecolormap, const short *walltop, const short *wallbottom, bool drawsegPass); + static void DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FSoftwareTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style); }; } diff --git a/src/swrenderer/things/r_model.cpp b/src/swrenderer/things/r_model.cpp index 611d75669..938b5f20c 100644 --- a/src/swrenderer/things/r_model.cpp +++ b/src/swrenderer/things/r_model.cpp @@ -106,8 +106,8 @@ namespace swrenderer FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); if (lump.isValid()) { - FTexture * tex = TexMan(lump); - if (tex) disablefullbright = tex->bDisableFullbright; + FTexture * tex = TexMan.GetTexture(lump, true); + if (tex) disablefullbright = tex->isFullbrightDisabled(); } return psp->GetState()->GetFullbright() && !disablefullbright; } @@ -354,7 +354,7 @@ namespace swrenderer args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights); args.SetNormal(FVector3(0.0f, 0.0f, 0.0f)); - args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite); + args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite); args.SetDepthTest(true); args.SetWriteDepth(true); args.SetWriteStencil(false); @@ -371,7 +371,7 @@ namespace swrenderer args.SetLight(GetColorTable(sector->Colormap, sector->SpecialColors[sector_t::sprites], true), lightlevel, visibility, fullbrightSprite); args.SetLights(Lights, NumLights); args.SetNormal(FVector3(0.0f, 0.0f, 0.0f)); - args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture, fullbrightSprite); + args.SetStyle(RenderStyle, RenderAlpha, fillcolor, Translation, SkinTexture->GetSoftwareTexture(), fullbrightSprite); args.SetDepthTest(true); args.SetWriteDepth(true); args.SetWriteStencil(false); diff --git a/src/swrenderer/things/r_particle.cpp b/src/swrenderer/things/r_particle.cpp index 0e167f7c4..c3b53fcf1 100644 --- a/src/swrenderer/things/r_particle.cpp +++ b/src/swrenderer/things/r_particle.cpp @@ -69,7 +69,7 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); namespace swrenderer { - void RenderParticle::Project(RenderThread *thread, particle_t *particle, const sector_t *sector, int shade, WaterFakeSide fakeside, bool foggy) + void RenderParticle::Project(RenderThread *thread, particle_t *particle, const sector_t *sector, int lightlevel, WaterFakeSide fakeside, bool foggy) { double tr_x, tr_y; double tx, ty; @@ -220,7 +220,7 @@ namespace swrenderer vis->floorclip = 0; vis->foggy = foggy; - vis->Light.SetColormap(tiz * thread->Light->ParticleGlobVis(foggy), shade, map, particle->bright != 0, false, false); + vis->Light.SetColormap(thread, tz, lightlevel, foggy, map, particle->bright != 0, false, false, false, true); thread->SpriteList->Push(vis); } diff --git a/src/swrenderer/things/r_playersprite.cpp b/src/swrenderer/things/r_playersprite.cpp index a51b3b5fd..c206c4863 100644 --- a/src/swrenderer/things/r_playersprite.cpp +++ b/src/swrenderer/things/r_playersprite.cpp @@ -80,7 +80,6 @@ namespace swrenderer void RenderPlayerSprites::Render() { int i; - int lightnum; DPSprite* psp; DPSprite* weapon; sector_t* sec = NULL; @@ -138,8 +137,7 @@ namespace swrenderer bool foggy = (level.fadeto || basecolormap->Fade || (level.flags & LEVEL_HASFADETABLE)); // get light level - lightnum = ((floorlight + ceilinglight) >> 1) + LightVisibility::ActualExtraLight(foggy, Thread->Viewport.get()); - int spriteshade = LightVisibility::LightLevelToShade(lightnum, foggy) - 24 * FRACUNIT; + int lightlevel = (floorlight + ceilinglight) >> 1; if (Thread->Viewport->viewpoint.camera->player != NULL) { @@ -184,7 +182,7 @@ namespace swrenderer if ((psp->GetID() != PSP_TARGETCENTER || CrosshairImage == nullptr) && psp->GetCaller() != nullptr) { - RenderSprite(psp, viewport->viewpoint.camera, bobx, boby, wx, wy, viewport->viewpoint.TicFrac, spriteshade, basecolormap, foggy); + RenderSprite(psp, viewport->viewpoint.camera, bobx, boby, wx, wy, viewport->viewpoint.TicFrac, lightlevel, basecolormap, foggy); } psp = psp->GetNext(); @@ -194,7 +192,7 @@ namespace swrenderer } } - void RenderPlayerSprites::RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy) + void RenderPlayerSprites::RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int lightlevel, FDynamicColormap *basecolormap, bool foggy) { double tx; int x1; @@ -224,9 +222,9 @@ namespace swrenderer picnum = sprframe->Texture[0]; flip = sprframe->Flip & 1; - tex = TexMan(picnum); + tex = TexMan.GetTexture(picnum); - if (tex->UseType == ETextureType::Null) + if (!tex->isValid()) return; if (pspr->firstTic) @@ -263,8 +261,8 @@ namespace swrenderer double pspriteyscale = pspritexscale * viewport->BaseYaspectMul * ((double)SCREENHEIGHT / SCREENWIDTH) * r_viewwindow.WidescreenRatio; double pspritexiscale = 1 / pspritexscale; - int tleft = tex->GetScaledLeftOffset(0); - int twidth = tex->GetScaledWidth(); + int tleft = tex->GetDisplayLeftOffset(); + int twidth = tex->GetDisplayWidth(); // calculate edges of the shape tx = (pspr->Flags & PSPF_MIRROR) ? ((BASEXCENTER - twidth) - (sx - tleft)) : ((sx - BASEXCENTER) - tleft); @@ -286,7 +284,8 @@ namespace swrenderer vis.renderflags = owner->renderflags; - vis.texturemid = (BASEYCENTER - sy) * tex->Scale.Y + tex->GetTopOffset(0); + FSoftwareTexture *stex = tex->GetSoftwareTexture(); + vis.texturemid = (BASEYCENTER - sy) * stex->GetScale().Y + stex->GetTopOffset(0); // Force it to use software rendering when drawing to a canvas texture. bool renderToCanvas = viewport->RenderingToCanvas; @@ -303,20 +302,20 @@ namespace swrenderer } vis.x1 = x1 < 0 ? 0 : x1; vis.x2 = x2 >= viewwidth ? viewwidth : x2; - vis.xscale = FLOAT2FIXED(pspritexscale / tex->Scale.X); - vis.yscale = float(pspriteyscale / tex->Scale.Y); - vis.pic = tex; + vis.xscale = FLOAT2FIXED(pspritexscale / stex->GetScale().X); + vis.yscale = float(pspriteyscale / stex->GetScale().Y); + vis.pic = stex; // If flip is used, provided that it's not already flipped (that would just invert itself) // (It's an XOR...) if (!(flip) != !(pspr->Flags & PSPF_FLIP)) { - vis.xiscale = -FLOAT2FIXED(pspritexiscale * tex->Scale.X); - vis.startfrac = (tex->GetWidth() << FRACBITS) - 1; + vis.xiscale = -FLOAT2FIXED(pspritexiscale * stex->GetScale().X); + vis.startfrac = (stex->GetWidth() << FRACBITS) - 1; } else { - vis.xiscale = FLOAT2FIXED(pspritexiscale * tex->Scale.X); + vis.xiscale = FLOAT2FIXED(pspritexiscale * stex->GetScale().X); vis.startfrac = 0; } @@ -351,7 +350,7 @@ namespace swrenderer bool fullbright = !foggy && (psprState == nullptr ? false : psprState->GetFullbright()); bool fadeToBlack = (vis.RenderStyle.Flags & STYLEF_FadeToBlack) != 0; - vis.Light.SetColormap(0, spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack); + vis.Light.SetColormap(Thread, MINZ, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, true, false); colormap_to_use = (FDynamicColormap*)vis.Light.BaseColormap; @@ -384,6 +383,7 @@ namespace swrenderer { noaccel = true; } +#if 0 // If the main colormap has fixed lights, and this sprite is being drawn with that // colormap, disable acceleration so that the lights can remain fixed. CameraLight *cameraLight = CameraLight::Instance(); @@ -393,6 +393,7 @@ namespace swrenderer { noaccel = true; } +#endif } else { @@ -455,7 +456,7 @@ namespace swrenderer { for (const HWAccelPlayerSprite &sprite : AcceleratedSprites) { - screen->DrawTexture(sprite.pic, + screen->DrawTexture(sprite.pic->GetTexture(), viewwindowx + sprite.x1, viewwindowy + viewheight / 2 - sprite.texturemid * sprite.yscale - 0.5, DTA_DestWidthF, FIXED2DBL(sprite.pic->GetWidth() * sprite.xscale), diff --git a/src/swrenderer/things/r_playersprite.h b/src/swrenderer/things/r_playersprite.h index 64dd66172..494e693f2 100644 --- a/src/swrenderer/things/r_playersprite.h +++ b/src/swrenderer/things/r_playersprite.h @@ -39,7 +39,7 @@ namespace swrenderer fixed_t xscale = 0; float yscale = 0.0f; - FTexture *pic = nullptr; + FSoftwareTexture *pic = nullptr; fixed_t xiscale = 0; fixed_t startfrac = 0; @@ -59,7 +59,7 @@ namespace swrenderer class HWAccelPlayerSprite { public: - FTexture *pic = nullptr; + FSoftwareTexture *pic = nullptr; double texturemid = 0.0; float yscale = 0.0f; fixed_t xscale = 0; @@ -90,7 +90,7 @@ namespace swrenderer RenderThread *Thread = nullptr; private: - void RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int spriteshade, FDynamicColormap *basecolormap, bool foggy); + void RenderSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double wx, double wy, double ticfrac, int lightlevel, FDynamicColormap *basecolormap, bool foggy); enum { BASEXCENTER = 160 }; enum { BASEYCENTER = 100 }; diff --git a/src/swrenderer/things/r_sprite.cpp b/src/swrenderer/things/r_sprite.cpp index 1251860d9..1daa0b62a 100644 --- a/src/swrenderer/things/r_sprite.cpp +++ b/src/swrenderer/things/r_sprite.cpp @@ -72,8 +72,9 @@ EXTERN_CVAR(Bool, gl_light_sprites) namespace swrenderer { - void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade, bool foggy, FDynamicColormap *basecolormap) + void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ttex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { + FSoftwareTexture *tex = ttex->GetSoftwareTexture(); // transform the origin point double tr_x = pos.X - thread->Viewport->viewpoint.Pos.X; double tr_y = pos.Y - thread->Viewport->viewpoint.Pos.Y; @@ -151,7 +152,7 @@ namespace swrenderer renderflags ^= RF_XFLIP; // calculate edges of the shape - const double thingxscalemul = spriteScale.X / tex->Scale.X; + const double thingxscalemul = spriteScale.X / tex->GetScale().X; tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->GetLeftOffsetSW() - 1) : tex->GetLeftOffsetSW()) * thingxscalemul; double dtx1 = tx * xscale; @@ -168,10 +169,10 @@ namespace swrenderer if ((x2 < renderportal->WindowLeft || x2 <= x1)) return; - xscale = spriteScale.X * xscale / tex->Scale.X; + xscale = spriteScale.X * xscale / tex->GetScale().X; fixed_t iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases - double yscale = spriteScale.Y / tex->Scale.Y; + double yscale = spriteScale.Y / tex->GetScale().Y; // store information in a vissprite RenderSprite *vis = thread->FrameMemory->NewObject(); @@ -299,7 +300,7 @@ namespace swrenderer vis->dynlightcolor = 0; } - vis->Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(tz, MINZ), spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack); + vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false); thread->SpriteList->Push(vis); } @@ -309,7 +310,7 @@ namespace swrenderer auto vis = this; fixed_t frac; - FTexture *tex; + FSoftwareTexture *tex; int x2; fixed_t xiscale; diff --git a/src/swrenderer/things/r_sprite.h b/src/swrenderer/things/r_sprite.h index 8fe53080e..fefe5df68 100644 --- a/src/swrenderer/things/r_sprite.h +++ b/src/swrenderer/things/r_sprite.h @@ -7,7 +7,7 @@ namespace swrenderer class RenderSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); protected: void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; diff --git a/src/swrenderer/things/r_visiblesprite.cpp b/src/swrenderer/things/r_visiblesprite.cpp index 5687fe473..7145e2b1e 100644 --- a/src/swrenderer/things/r_visiblesprite.cpp +++ b/src/swrenderer/things/r_visiblesprite.cpp @@ -163,9 +163,7 @@ namespace swrenderer bool isFullBright = !foggy && (renderflags & RF_FULLBRIGHT); bool fadeToBlack = spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0; - int spriteshade = LightVisibility::LightLevelToShade(sec->lightlevel + LightVisibility::ActualExtraLight(spr->foggy, thread->Viewport.get()), foggy); - - Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(MINZ, (double)spr->depth), spriteshade, mybasecolormap, isFullBright, invertcolormap, fadeToBlack); + Light.SetColormap(thread, spr->depth, sec->lightlevel, foggy, mybasecolormap, isFullBright, invertcolormap, fadeToBlack, false, false); } } diff --git a/src/swrenderer/things/r_visiblesprite.h b/src/swrenderer/things/r_visiblesprite.h index 37787a809..01b9198d1 100644 --- a/src/swrenderer/things/r_visiblesprite.h +++ b/src/swrenderer/things/r_visiblesprite.h @@ -55,7 +55,7 @@ namespace swrenderer virtual void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) = 0; - FTexture *pic = nullptr; + FSoftwareTexture *pic = nullptr; short x1 = 0, x2 = 0; float gzb = 0.0f, gzt = 0.0f; // global bottom / top for silhouette clipping diff --git a/src/swrenderer/things/r_voxel.cpp b/src/swrenderer/things/r_voxel.cpp index faab6e785..30b8dc259 100644 --- a/src/swrenderer/things/r_voxel.cpp +++ b/src/swrenderer/things/r_voxel.cpp @@ -60,7 +60,7 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor) namespace swrenderer { - void RenderVoxel::Project(RenderThread *thread, AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade, bool foggy, FDynamicColormap *basecolormap) + void RenderVoxel::Project(RenderThread *thread, AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { // transform the origin point double tr_x = pos.X - thread->Viewport->viewpoint.Pos.X; @@ -188,7 +188,7 @@ namespace swrenderer bool fullbright = !vis->foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); bool fadeToBlack = (vis->RenderStyle.Flags & STYLEF_FadeToBlack) != 0; - vis->Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(tz, MINZ), spriteshade, basecolormap, fullbright, invertcolormap, fadeToBlack); + vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, fullbright, invertcolormap, fadeToBlack, false, false); // Fake a voxel drawing to find its extents.. SpriteDrawerArgs drawerargs; diff --git a/src/swrenderer/things/r_voxel.h b/src/swrenderer/things/r_voxel.h index 7121d3498..d9164899b 100644 --- a/src/swrenderer/things/r_voxel.h +++ b/src/swrenderer/things/r_voxel.h @@ -58,7 +58,7 @@ namespace swrenderer class RenderVoxel : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); static void Deinit(); diff --git a/src/swrenderer/things/r_wallsprite.cpp b/src/swrenderer/things/r_wallsprite.cpp index a9f815425..2046fe2f3 100644 --- a/src/swrenderer/things/r_wallsprite.cpp +++ b/src/swrenderer/things/r_wallsprite.cpp @@ -71,8 +71,9 @@ EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor); namespace swrenderer { - void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int spriteshade, bool foggy, FDynamicColormap *basecolormap) + void RenderWallSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *ppic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap) { + FSoftwareTexture *pic = ppic->GetSoftwareTexture(); FWallCoords wallc; double x1, x2; DVector2 left, right; @@ -140,7 +141,7 @@ namespace swrenderer vis->wallc = wallc; vis->foggy = foggy; - vis->Light.SetColormap(thread->Light->SpriteGlobVis(foggy) / MAX(tz, MINZ), spriteshade, basecolormap, false, false, false); + vis->Light.SetColormap(thread, tz, lightlevel, foggy, basecolormap, false, false, false, false, false); thread->SpriteList->Push(vis); } @@ -189,10 +190,8 @@ namespace swrenderer SpriteDrawerArgs drawerargs; - int shade = LightVisibility::LightLevelToShade(spr->sector->lightlevel + LightVisibility::ActualExtraLight(spr->foggy, thread->Viewport.get()), spr->foggy); - double GlobVis = thread->Light->WallGlobVis(foggy); - float lightleft = float(GlobVis / spr->wallc.sz1); - float lightstep = float((GlobVis / spr->wallc.sz2 - lightleft) / (spr->wallc.sx2 - spr->wallc.sx1)); + float lightleft = float(thread->Light->WallVis(spr->wallc.sz1, foggy)); + float lightstep = float((thread->Light->WallVis(spr->wallc.sz2, foggy) - lightleft) / (spr->wallc.sx2 - spr->wallc.sx1)); float light = lightleft + (x1 - spr->wallc.sx1) * lightstep; CameraLight *cameraLight = CameraLight::Instance(); if (cameraLight->FixedLightLevel() >= 0) @@ -205,7 +204,7 @@ namespace swrenderer calclighting = true; // Draw it - FTexture *WallSpriteTile = spr->pic; + auto WallSpriteTile = spr->pic; if (spr->renderflags & RF_YFLIP) { sprflipvert = true; @@ -244,7 +243,7 @@ namespace swrenderer { if (calclighting) { // calculate lighting - drawerargs.SetLight(usecolormap, light, shade); + drawerargs.SetLight(usecolormap, light, spr->sector->lightlevel, spr->foggy, thread->Viewport.get()); } if (!translucentPass->ClipSpriteColumnWithPortals(x, spr)) DrawColumn(thread, drawerargs, x, WallSpriteTile, walltexcoords, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip, spr->RenderStyle); @@ -254,7 +253,7 @@ namespace swrenderer } } - void RenderWallSprite::DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style) + void RenderWallSprite::DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FSoftwareTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style) { auto viewport = thread->Viewport.get(); diff --git a/src/swrenderer/things/r_wallsprite.h b/src/swrenderer/things/r_wallsprite.h index fa127ccf4..bcd0a1389 100644 --- a/src/swrenderer/things/r_wallsprite.h +++ b/src/swrenderer/things/r_wallsprite.h @@ -10,14 +10,14 @@ namespace swrenderer class RenderWallSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int spriteshade, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FTexture *pic, const DVector2 &scale, int renderflags, int lightlevel, bool foggy, FDynamicColormap *basecolormap); protected: bool IsWallSprite() const override { return true; } void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; private: - static void DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style); + static void DrawColumn(RenderThread *thread, SpriteDrawerArgs &drawerargs, int x, FSoftwareTexture *WallSpriteTile, const ProjectedWallTexcoords &walltexcoords, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style); FWallCoords wallc; uint32_t Translation = 0; diff --git a/src/swrenderer/viewport/r_drawerargs.cpp b/src/swrenderer/viewport/r_drawerargs.cpp index 19e9d6682..3306381a4 100644 --- a/src/swrenderer/viewport/r_drawerargs.cpp +++ b/src/swrenderer/viewport/r_drawerargs.cpp @@ -24,6 +24,11 @@ namespace swrenderer { + void DrawerArgs::SetLight(FSWColormap *base_colormap, float light, int lightlevel, bool foggy, RenderViewport *viewport) + { + SetLight(base_colormap, light, LightVisibility::LightLevelToShade(lightlevel, foggy, viewport)); + } + void DrawerArgs::SetLight(FSWColormap *base_colormap, float light, int shade) { mBaseColormap = base_colormap; diff --git a/src/swrenderer/viewport/r_drawerargs.h b/src/swrenderer/viewport/r_drawerargs.h index f1c5fc556..1ba8d5e61 100644 --- a/src/swrenderer/viewport/r_drawerargs.h +++ b/src/swrenderer/viewport/r_drawerargs.h @@ -31,6 +31,7 @@ namespace swrenderer { public: void SetLight(FSWColormap *base_colormap, float light, int shade); + void SetLight(FSWColormap *base_colormap, float light, int lightlevel, bool foggy, RenderViewport *viewport); void SetTranslationMap(lighttable_t *translation); uint8_t *Colormap(RenderViewport *viewport) const; diff --git a/src/swrenderer/viewport/r_skydrawer.cpp b/src/swrenderer/viewport/r_skydrawer.cpp index c134a46e2..2f75e30e2 100644 --- a/src/swrenderer/viewport/r_skydrawer.cpp +++ b/src/swrenderer/viewport/r_skydrawer.cpp @@ -47,21 +47,21 @@ namespace swrenderer dc_viewport = viewport; } - void SkyDrawerArgs::SetFrontTexture(RenderThread *thread, FTexture *texture, uint32_t column) + void SkyDrawerArgs::SetFrontTexture(RenderThread *thread, FSoftwareTexture *texture, fixed_t column) { if (thread->Viewport->RenderTarget->IsBgra()) { - dc_source = (const uint8_t *)texture->GetColumnBgra(column, nullptr); - dc_sourceheight = texture->GetHeight(); + dc_source = (const uint8_t *)texture->GetColumnBgra((column * texture->GetPhysicalScale()) >> FRACBITS, nullptr); + dc_sourceheight = texture->GetPhysicalHeight(); } else { - dc_source = texture->GetColumn(DefaultRenderStyle(), column, nullptr); - dc_sourceheight = texture->GetHeight(); + dc_source = texture->GetColumn(DefaultRenderStyle(), (column * texture->GetPhysicalScale()) >> FRACBITS, nullptr); + dc_sourceheight = texture->GetPhysicalHeight(); } } - void SkyDrawerArgs::SetBackTexture(RenderThread *thread, FTexture *texture, uint32_t column) + void SkyDrawerArgs::SetBackTexture(RenderThread *thread, FSoftwareTexture *texture, fixed_t column) { if (texture == nullptr) { @@ -70,13 +70,13 @@ namespace swrenderer } else if (thread->Viewport->RenderTarget->IsBgra()) { - dc_source2 = (const uint8_t *)texture->GetColumnBgra(column, nullptr); - dc_sourceheight2 = texture->GetHeight(); + dc_source2 = (const uint8_t *)texture->GetColumnBgra((column * texture->GetPhysicalScale()) >> FRACBITS, nullptr); + dc_sourceheight2 = texture->GetPhysicalHeight(); } else { - dc_source2 = texture->GetColumn(DefaultRenderStyle(), column, nullptr); - dc_sourceheight2 = texture->GetHeight(); + dc_source2 = texture->GetColumn(DefaultRenderStyle(), (column * texture->GetPhysicalScale()) >> FRACBITS, nullptr); + dc_sourceheight2 = texture->GetPhysicalHeight(); } } } diff --git a/src/swrenderer/viewport/r_skydrawer.h b/src/swrenderer/viewport/r_skydrawer.h index 24c7e6f08..2634c514f 100644 --- a/src/swrenderer/viewport/r_skydrawer.h +++ b/src/swrenderer/viewport/r_skydrawer.h @@ -15,8 +15,8 @@ namespace swrenderer public: void SetDest(RenderViewport *viewport, int x, int y); void SetCount(int count) { dc_count = count; } - void SetFrontTexture(RenderThread *thread, FTexture *texture, uint32_t column); - void SetBackTexture(RenderThread *thread, FTexture *texture, uint32_t column); + void SetFrontTexture(RenderThread *thread, FSoftwareTexture *texture, fixed_t column); + void SetBackTexture(RenderThread *thread, FSoftwareTexture *texture, fixed_t column); void SetTextureVPos(uint32_t texturefrac) { dc_texturefrac = texturefrac; } void SetTextureVStep(uint32_t iscale) { dc_iscale = iscale; } void SetSolidTop(uint32_t color) { solid_top = color; } diff --git a/src/swrenderer/viewport/r_spandrawer.cpp b/src/swrenderer/viewport/r_spandrawer.cpp index 0c1689f14..69c6ead64 100644 --- a/src/swrenderer/viewport/r_spandrawer.cpp +++ b/src/swrenderer/viewport/r_spandrawer.cpp @@ -30,25 +30,25 @@ namespace swrenderer spanfunc = &SWPixelFormatDrawers::DrawSpan; } - void SpanDrawerArgs::SetTexture(RenderThread *thread, FTexture *tex) + void SpanDrawerArgs::SetTexture(RenderThread *thread, FSoftwareTexture *tex) { thread->PrepareTexture(tex, DefaultRenderStyle()); - ds_texwidth = tex->GetWidth(); - ds_texheight = tex->GetHeight(); - ds_xbits = tex->WidthBits; - ds_ybits = tex->HeightBits; - if ((1 << ds_xbits) > tex->GetWidth()) + ds_texwidth = tex->GetPhysicalWidth(); + ds_texheight = tex->GetPhysicalHeight(); + ds_xbits = tex->GetWidthBits(); + ds_ybits = tex->GetHeightBits(); + if ((1 << ds_xbits) > tex->GetPhysicalWidth()) { ds_xbits--; } - if ((1 << ds_ybits) > tex->GetHeight()) + if ((1 << ds_ybits) > tex->GetPhysicalHeight()) { ds_ybits--; } ds_source = thread->Viewport->RenderTarget->IsBgra() ? (const uint8_t*)tex->GetPixelsBgra() : tex->GetPixels(DefaultRenderStyle()); // Get correct render style? Shaded won't get here. - ds_source_mipmapped = tex->Mipmapped() && tex->GetWidth() > 1 && tex->GetHeight() > 1; + ds_source_mipmapped = tex->Mipmapped() && tex->GetPhysicalWidth() > 1 && tex->GetPhysicalHeight() > 1; } void SpanDrawerArgs::SetStyle(bool masked, bool additive, fixed_t alpha) @@ -117,12 +117,12 @@ namespace swrenderer (thread->Drawers(ds_viewport)->*spanfunc)(*this); } - void SpanDrawerArgs::DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) + void SpanDrawerArgs::DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int lightlevel, bool foggy, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap) { SetDestY(thread->Viewport.get(), y); SetDestX1(x1); SetDestX2(x2); - thread->Drawers(ds_viewport)->DrawTiltedSpan(*this, plane_sz, plane_su, plane_sv, plane_shade, planeshade, planelightfloat, pviewx, pviewy, basecolormap); + thread->Drawers(ds_viewport)->DrawTiltedSpan(*this, plane_sz, plane_su, plane_sv, plane_shade, LightVisibility::LightLevelToShade(lightlevel, foggy, thread->Viewport.get()), planelightfloat, pviewx, pviewy, basecolormap); } void SpanDrawerArgs::DrawFogBoundaryLine(RenderThread *thread, int y, int x1, int x2) diff --git a/src/swrenderer/viewport/r_spandrawer.h b/src/swrenderer/viewport/r_spandrawer.h index 3dc7c6191..8bd2aeb10 100644 --- a/src/swrenderer/viewport/r_spandrawer.h +++ b/src/swrenderer/viewport/r_spandrawer.h @@ -19,7 +19,7 @@ namespace swrenderer void SetDestY(RenderViewport *viewport, int y) { ds_viewport = viewport; ds_y = y; } void SetDestX1(int x) { ds_x1 = x; } void SetDestX2(int x) { ds_x2 = x; } - void SetTexture(RenderThread *thread, FTexture *tex); + void SetTexture(RenderThread *thread, FSoftwareTexture *tex); void SetTextureLOD(double lod) { ds_lod = lod; } void SetTextureUPos(double u) { ds_xfrac = (uint32_t)(int64_t)(u * 4294967296.0); } void SetTextureVPos(double v) { ds_yfrac = (uint32_t)(int64_t)(v * 4294967296.0); } @@ -29,7 +29,7 @@ namespace swrenderer void DrawDepthSpan(RenderThread *thread, float idepth1, float idepth2); void DrawSpan(RenderThread *thread); - void DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int planeshade, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap); + void DrawTiltedSpan(RenderThread *thread, int y, int x1, int x2, const FVector3 &plane_sz, const FVector3 &plane_su, const FVector3 &plane_sv, bool plane_shade, int lightlevel, bool foggy, float planelightfloat, fixed_t pviewx, fixed_t pviewy, FDynamicColormap *basecolormap); void DrawColoredSpan(RenderThread *thread, int y, int x1, int x2); void DrawFogBoundaryLine(RenderThread *thread, int y, int x1, int x2); diff --git a/src/swrenderer/viewport/r_spritedrawer.cpp b/src/swrenderer/viewport/r_spritedrawer.cpp index 20abfca51..f6d870912 100644 --- a/src/swrenderer/viewport/r_spritedrawer.cpp +++ b/src/swrenderer/viewport/r_spritedrawer.cpp @@ -43,11 +43,15 @@ namespace swrenderer colfunc = &SWPixelFormatDrawers::DrawColumn; } - void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked) + void SpriteDrawerArgs::DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked) { if (x < thread->X1 || x >= thread->X2) return; + col *= tex->GetPhysicalScale(); + iscale *= tex->GetPhysicalScale(); + spryscale /= tex->GetPhysicalScale(); + auto viewport = thread->Viewport.get(); // Handle the linear filtered version in a different function to reduce chances of merge conflicts from zdoom. @@ -60,21 +64,21 @@ namespace swrenderer dc_viewport = viewport; dc_x = x; dc_iscale = iscale; - dc_textureheight = tex->GetHeight(); + dc_textureheight = tex->GetPhysicalHeight(); - const FTexture::Span *span; + const FSoftwareTextureSpan *span; const uint8_t *column; if (viewport->RenderTarget->IsBgra() && !drawer_needs_pal_input) column = (const uint8_t *)tex->GetColumnBgra(col >> FRACBITS, &span); else column = tex->GetColumn(style, col >> FRACBITS, &span); - FTexture::Span unmaskedSpan[2]; + FSoftwareTextureSpan unmaskedSpan[2]; if (unmasked) { span = unmaskedSpan; unmaskedSpan[0].TopOffset = 0; - unmaskedSpan[0].Length = tex->GetHeight(); + unmaskedSpan[0].Length = tex->GetPhysicalHeight(); unmaskedSpan[1].TopOffset = 0; unmaskedSpan[1].Length = 0; } @@ -126,7 +130,7 @@ namespace swrenderer } } - void SpriteDrawerArgs::DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked) + void SpriteDrawerArgs::DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t col, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked) { dc_viewport = thread->Viewport.get(); dc_x = x; @@ -134,7 +138,7 @@ namespace swrenderer // Normalize to 0-1 range: double uv_stepd = FIXED2DBL(dc_iscale); - double v_step = uv_stepd / tex->GetHeight(); + double v_step = uv_stepd / tex->GetPhysicalHeight(); // Convert to uint32_t: dc_iscale = (uint32_t)(v_step * (1 << 30)); @@ -150,8 +154,8 @@ namespace swrenderer bool magnifying = lod < 0.0f; int mipmap_offset = 0; - int mip_width = tex->GetWidth(); - int mip_height = tex->GetHeight(); + int mip_width = tex->GetPhysicalWidth(); + int mip_height = tex->GetPhysicalHeight(); uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); if (r_mipmap && tex->Mipmapped() && mip_width > 1 && mip_height > 1) { @@ -192,14 +196,14 @@ namespace swrenderer } // Grab the posts we need to draw - const FTexture::Span *span; + const FSoftwareTextureSpan *span; tex->GetColumnBgra(col >> FRACBITS, &span); - FTexture::Span unmaskedSpan[2]; + FSoftwareTextureSpan unmaskedSpan[2]; if (unmasked) { span = unmaskedSpan; unmaskedSpan[0].TopOffset = 0; - unmaskedSpan[0].Length = tex->GetHeight(); + unmaskedSpan[0].Length = tex->GetPhysicalHeight(); unmaskedSpan[1].TopOffset = 0; unmaskedSpan[1].Length = 0; } @@ -233,7 +237,7 @@ namespace swrenderer SetDest(dc_viewport, dc_x, dc_yl); dc_count = dc_yh - dc_yl + 1; - double v = ((dc_yl + 0.5 - sprtopscreen) / spryscale) / tex->GetHeight(); + double v = ((dc_yl + 0.5 - sprtopscreen) / spryscale) / tex->GetPhysicalHeight(); dc_texturefrac = (uint32_t)(v * (1 << 30)); (thread->Drawers(dc_viewport)->*colfunc)(*this); diff --git a/src/swrenderer/viewport/r_spritedrawer.h b/src/swrenderer/viewport/r_spritedrawer.h index f6a3aae79..e025d5c9e 100644 --- a/src/swrenderer/viewport/r_spritedrawer.h +++ b/src/swrenderer/viewport/r_spritedrawer.h @@ -33,7 +33,7 @@ namespace swrenderer void SetSolidColor(int color) { dc_color = color; dc_color_bgra = GPalette.BaseColors[color]; } void SetDynamicLight(uint32_t color) { dynlightcolor = color; } - void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false); + void DrawMaskedColumn(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *texture, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, FRenderStyle style, bool unmasked = false); void FillColumn(RenderThread *thread); void DrawVoxelBlocks(RenderThread *thread, const VoxelBlock *blocks, int blockcount); @@ -71,7 +71,7 @@ namespace swrenderer private: bool SetBlendFunc(int op, fixed_t fglevel, fixed_t bglevel, int flags); static fixed_t GetAlpha(int type, fixed_t alpha); - void DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FTexture *tex, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked); + void DrawMaskedColumnBgra(RenderThread *thread, int x, fixed_t iscale, FSoftwareTexture *tex, fixed_t column, double spryscale, double sprtopscreen, bool sprflipvert, const short *mfloorclip, const short *mceilingclip, bool unmasked); uint8_t *dc_dest = nullptr; int dc_dest_y = 0; diff --git a/src/swrenderer/viewport/r_viewport.h b/src/swrenderer/viewport/r_viewport.h index 7709e5701..69adc5778 100644 --- a/src/swrenderer/viewport/r_viewport.h +++ b/src/swrenderer/viewport/r_viewport.h @@ -7,6 +7,8 @@ #include "r_defs.h" #include "polyrenderer/math/gpu_types.h" +#define MINZ double((2048*4) / double(1 << 20)) + namespace swrenderer { class RenderThread; diff --git a/src/tarray.h b/src/tarray.h index bdbb7bb82..524c0942e 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -272,6 +272,18 @@ public: return i; } + template + unsigned int FindEx(Func compare) const + { + unsigned int i; + for (i = 0; i < Count; ++i) + { + if (compare(Array[i])) + break; + } + return i; + } + unsigned int Push (const T &item) { Grow (1); @@ -1019,7 +1031,7 @@ protected: if (!nold[i].IsNil()) { Node *n = NewKey(nold[i].Pair.Key); - ::new(&n->Pair.Value) VT(nold[i].Pair.Value); + ::new(&n->Pair.Value) VT(std::move(nold[i].Pair.Value)); nold[i].~Node(); } } diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index c1b8f5c48..031a940e7 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -224,10 +224,9 @@ void FTextureManager::InitAnimated (void) (anim_p[21] << 16) | (anim_p[22] << 24); // SMMU-style swirly hack? Don't apply on already-warping texture - if (animspeed > 65535 && tex1 != NULL && !tex1->bWarped) + if (animspeed > 65535 && tex1 != NULL && !tex1->isWarped()) { - FTexture *warper = new FWarpTexture (tex1, 2); - ReplaceTexture (pic1, warper, false); + tex1->bWarped = 2; } // These tests were not really relevant for swirling textures, or even potentially // harmful, so they have been moved to the else block. @@ -622,15 +621,14 @@ void FTextureManager::ParseWarp(FScanner &sc) // don't warp a texture more than once - if (!warper->bWarped) + if (!warper->isWarped()) { - warper = new FWarpTexture (warper, type2? 2:1); - ReplaceTexture (picnum, warper, false); + warper->bWarped = type2? 2:1; } if (sc.CheckFloat()) { - static_cast(warper)->SetSpeed(float(sc.Float)); + warper->SetSpeed(float(sc.Float)); } // No decals on warping textures, by default. diff --git a/src/textures/bitmap.h b/src/textures/bitmap.h index 51d857ac4..7b09fb21b 100644 --- a/src/textures/bitmap.h +++ b/src/textures/bitmap.h @@ -56,6 +56,22 @@ enum BLENDUNIT = (1<>8; } }; -enum ColorType -{ - CF_RGB, - CF_RGBT, - CF_RGBA, - CF_IA, - CF_CMYK, - CF_YCbCr, - CF_BGR, - CF_BGRA, - CF_I16, - CF_RGB555, - CF_PalEntry -}; - enum EBlend { BLEND_NONE = 0, diff --git a/src/textures/formats/automaptexture.cpp b/src/textures/formats/automaptexture.cpp index 4d6ddfeaf..81205291b 100644 --- a/src/textures/formats/automaptexture.cpp +++ b/src/textures/formats/automaptexture.cpp @@ -39,6 +39,8 @@ #include "files.h" #include "w_wad.h" #include "textures/textures.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== // @@ -46,11 +48,11 @@ // //========================================================================== -class FAutomapTexture : public FWorldTexture +class FAutomapTexture : public FImageSource { public: FAutomapTexture(int lumpnum); - uint8_t *MakeTexture (FRenderStyle style); + TArray CreatePalettedPixels(int conversion) override; }; @@ -62,10 +64,10 @@ public: // //========================================================================== -FTexture *AutomapTexture_TryCreate(FileReader &data, int lumpnum) +FImageSource *AutomapImage_TryCreate(FileReader &data, int lumpnum) { - if (data.GetLength() < 320) return NULL; - if (!Wads.CheckLumpName(lumpnum, "AUTOPAGE")) return NULL; + if (data.GetLength() < 320) return nullptr; + if (!Wads.CheckLumpName(lumpnum, "AUTOPAGE")) return nullptr; return new FAutomapTexture(lumpnum); } @@ -76,11 +78,11 @@ FTexture *AutomapTexture_TryCreate(FileReader &data, int lumpnum) //========================================================================== FAutomapTexture::FAutomapTexture (int lumpnum) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { Width = 320; Height = uint16_t(Wads.LumpLength(lumpnum) / 320); - CalcBitSize (); + bUseGamePalette = true; } //========================================================================== @@ -89,15 +91,15 @@ FAutomapTexture::FAutomapTexture (int lumpnum) // //========================================================================== -uint8_t *FAutomapTexture::MakeTexture (FRenderStyle style) +TArray FAutomapTexture::CreatePalettedPixels(int conversion) { int x, y; FMemLump data = Wads.ReadLump (SourceLump); const uint8_t *indata = (const uint8_t *)data.GetMem(); - auto Pixels = new uint8_t[Width * Height]; + TArray Pixels(Width * Height, true); - const uint8_t *remap = GetRemap(style); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); for (x = 0; x < Width; ++x) { for (y = 0; y < Height; ++y) diff --git a/src/textures/formats/brightmaptexture.cpp b/src/textures/formats/brightmaptexture.cpp index 7b3dae3a6..d56f06010 100644 --- a/src/textures/formats/brightmaptexture.cpp +++ b/src/textures/formats/brightmaptexture.cpp @@ -39,18 +39,17 @@ #include "r_data/r_translate.h" #include "bitmap.h" #include "v_video.h" +#include "image.h" -class FBrightmapTexture : public FWorldTexture +class FBrightmapTexture : public FImageSource { public: - FBrightmapTexture (FTexture *source); + FBrightmapTexture (FImageSource *source); - uint8_t *MakeTexture(FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; - bool UseBasePalette() override { return false; } + int CopyPixels(FBitmap *bmp, int conversion) override; protected: - FTexture *SourcePic; + FImageSource *SourcePic; }; //=========================================================================== @@ -61,33 +60,21 @@ protected: // //=========================================================================== -FBrightmapTexture::FBrightmapTexture (FTexture *source) +FBrightmapTexture::FBrightmapTexture (FImageSource *source) { - Name = ""; SourcePic = source; - CopySize(source); - bNoDecals = source->bNoDecals; - Rotations = source->Rotations; - UseType = source->UseType; + Width = source->GetWidth(); + Height = source->GetHeight(); bMasked = false; - id.SetInvalid(); - SourceLump = -1; } -uint8_t *FBrightmapTexture::MakeTexture(FRenderStyle style) +int FBrightmapTexture::CopyPixels(FBitmap *bmp, int conversion) { - // This function is only necessary to satisfy the parent class's interface. - // This will never be called. - return nullptr; -} - -int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) -{ - SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, TexMan.GlobalBrightmap.Palette); + SourcePic->CopyTranslatedPixels(bmp, TexMan.GlobalBrightmap.Palette); return 0; } -FTexture *CreateBrightmapTexture(FTexture *tex) +FTexture *CreateBrightmapTexture(FImageSource *tex) { - return new FBrightmapTexture(tex); -} \ No newline at end of file + return new FImageTexture(new FBrightmapTexture(tex)); +} diff --git a/src/textures/formats/buildtexture.cpp b/src/textures/formats/buildtexture.cpp index 3df85f90b..1b5be6543 100644 --- a/src/textures/formats/buildtexture.cpp +++ b/src/textures/formats/buildtexture.cpp @@ -44,6 +44,7 @@ #include "textures/textures.h" #include "r_data/sprites.h" #include "resourcefiles/resourcefile.h" +#include "image.h" //========================================================================== @@ -52,14 +53,12 @@ // //========================================================================== -class FBuildTexture : public FWorldTexture +class FBuildTexture : public FImageSource { public: FBuildTexture (const FString &pathprefix, int tilenum, const uint8_t *pixels, int translation, int width, int height, int left, int top); - uint8_t *MakeTexture(FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - bool UseBasePalette() override { return false; } - FTextureFormat GetFormat() override { return TEX_RGB; } + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; protected: const uint8_t *RawPixels; @@ -76,32 +75,28 @@ protected: FBuildTexture::FBuildTexture(const FString &pathprefix, int tilenum, const uint8_t *pixels, int translation, int width, int height, int left, int top) : RawPixels (pixels), Translation(translation) { - PixelsAreStatic = 3; Width = width; Height = height; - _LeftOffset[1] = _LeftOffset[0] = left; - _TopOffset[1] = _TopOffset[0] = top; - CalcBitSize (); - Name.Format("%sBTIL%04d", pathprefix.GetChars(), tilenum); - UseType = ETextureType::Override; + LeftOffset = left; + TopOffset = top; } -uint8_t *FBuildTexture::MakeTexture(FRenderStyle style) +TArray FBuildTexture::CreatePalettedPixels(int conversion) { - auto Pixels = new uint8_t[Width * Height]; + TArray Pixels(Width * Height, true); FRemapTable *Remap = translationtables[TRANSLATION_Standard][Translation]; for (int i = 0; i < Width*Height; i++) { auto c = RawPixels[i]; - Pixels[i] = (style.Flags & STYLEF_RedIsAlpha) ? Remap->Palette[c].Luminance() : Remap->Remap[c]; + Pixels[i] = conversion == luminance ? Remap->Palette[c].Luminance() : Remap->Remap[c]; } - return (uint8_t*)Pixels; + return Pixels; } -int FBuildTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FBuildTexture::CopyPixels(FBitmap *bmp, int conversion) { PalEntry *Remap = translationtables[TRANSLATION_Standard][Translation]->Palette; - bmp->CopyPixelData(x, y, RawPixels, Width, Height, Height, 1, rotate, Remap, inf); + bmp->CopyPixelData(0, 0, RawPixels, Width, Height, Height, 1, 0, Remap); return -1; } @@ -139,9 +134,12 @@ void FTextureManager::AddTiles (const FString &pathprefix, const void *tiles, in if (width <= 0 || height <= 0) continue; - tex = new FBuildTexture (pathprefix, i, tiledata, translation, width, height, xoffs, yoffs); + tex = new FImageTexture(new FBuildTexture (pathprefix, i, tiledata, translation, width, height, xoffs, yoffs)); texnum = AddTexture (tex); tiledata += size; + tex->Name.Format("%sBTIL%04d", pathprefix.GetChars(), i); + tex->UseType = ETextureType::Override; + // reactivate only if the texture counter works here. //StartScreen->Progress(); diff --git a/src/textures/formats/canvastexture.cpp b/src/textures/formats/canvastexture.cpp index 49729818b..d2ddcea95 100644 --- a/src/textures/formats/canvastexture.cpp +++ b/src/textures/formats/canvastexture.cpp @@ -36,153 +36,4 @@ #include "doomtype.h" #include "v_video.h" -FCanvasTexture::FCanvasTexture (const char *name, int width, int height) -{ - Name = name; - Width = width; - Height = height; - CalcBitSize (); - bMasked = false; - DummySpans[0].TopOffset = 0; - DummySpans[0].Length = height; - DummySpans[1].TopOffset = 0; - DummySpans[1].Length = 0; - UseType = ETextureType::Wall; - bNeedsUpdate = true; - bDidUpdate = false; - bHasCanvas = true; - bFirstUpdate = true; - bPixelsAllocated = false; -} - -FCanvasTexture::~FCanvasTexture () -{ - Unload (); -} - -const uint8_t *FCanvasTexture::GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out) -{ - bNeedsUpdate = true; - if (Canvas == NULL) - { - MakeTexture (style); - } - if ((unsigned)column >= (unsigned)Width) - { - if (WidthMask + 1 == Width) - { - column &= WidthMask; - } - else - { - column %= Width; - } - } - if (spans_out != NULL) - { - *spans_out = DummySpans; - } - return Pixels + column*Height; -} - -const uint8_t *FCanvasTexture::GetPixels (FRenderStyle style) -{ - bNeedsUpdate = true; - if (Canvas == NULL) - { - MakeTexture (style); - } - return Pixels; -} - -const uint32_t *FCanvasTexture::GetPixelsBgra() -{ - bNeedsUpdate = true; - if (CanvasBgra == NULL) - { - MakeTextureBgra(); - } - return PixelsBgra; -} - -void FCanvasTexture::MakeTexture (FRenderStyle) // This ignores the render style because making it work as alpha texture is impractical. -{ - Canvas = new DCanvas (Width, Height, false); - - if (Width != Height || Width != Canvas->GetPitch()) - { - Pixels = new uint8_t[Width*Height]; - bPixelsAllocated = true; - } - else - { - Pixels = (uint8_t*)Canvas->GetPixels(); - bPixelsAllocated = false; - } - - // Draw a special "unrendered" initial texture into the buffer. - memset (Pixels, 0, Width*Height/2); - memset (Pixels+Width*Height/2, 255, Width*Height/2); -} - -void FCanvasTexture::MakeTextureBgra() -{ - CanvasBgra = new DCanvas(Width, Height, true); - - if (Width != Height || Width != CanvasBgra->GetPitch()) - { - PixelsBgra = new uint32_t[Width*Height]; - bPixelsAllocatedBgra = true; - } - else - { - PixelsBgra = (uint32_t*)CanvasBgra->GetPixels(); - bPixelsAllocatedBgra = false; - } - - // Draw a special "unrendered" initial texture into the buffer. - memset(PixelsBgra, 0, Width*Height / 2 * 4); - memset(PixelsBgra + Width*Height / 2, 255, Width*Height / 2 * 4); -} - -void FCanvasTexture::Unload () -{ - if (bPixelsAllocated) - { - if (Pixels != NULL) delete[] Pixels; - bPixelsAllocated = false; - Pixels = NULL; - } - - if (bPixelsAllocatedBgra) - { - if (PixelsBgra != NULL) delete[] PixelsBgra; - bPixelsAllocatedBgra = false; - PixelsBgra = NULL; - } - - if (Canvas != NULL) - { - delete Canvas; - Canvas = nullptr; - } - - if (CanvasBgra != NULL) - { - delete CanvasBgra; - CanvasBgra = nullptr; - } - - FTexture::Unload(); -} - -bool FCanvasTexture::CheckModified (FRenderStyle) -{ - if (bDidUpdate) - { - bDidUpdate = false; - return true; - } - return false; -} diff --git a/src/textures/formats/ddstexture.cpp b/src/textures/formats/ddstexture.cpp index c0988bec7..f5ae1f056 100644 --- a/src/textures/formats/ddstexture.cpp +++ b/src/textures/formats/ddstexture.cpp @@ -53,6 +53,8 @@ #include "w_wad.h" #include "bitmap.h" #include "v_video.h" +#include "imagehelpers.h" +#include "image.h" // Since we want this to compile under Linux too, we need to define this // stuff ourselves instead of including a DirectX header. @@ -151,7 +153,7 @@ struct DDSFileHeader // //========================================================================== -class FDDSTexture : public FWorldTexture +class FDDSTexture : public FImageSource { enum { @@ -162,8 +164,7 @@ class FDDSTexture : public FWorldTexture public: FDDSTexture (FileReader &lump, int lumpnum, void *surfdesc); - FTextureFormat GetFormat () override; - uint8_t *MakeTexture(FRenderStyle style) override; + TArray CreatePalettedPixels(int conversion) override; protected: uint32_t Format; @@ -182,8 +183,7 @@ protected: void DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode); void DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t *buffer, int pixelmode); - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL); - bool UseBasePalette(); + int CopyPixels(FBitmap *bmp, int conversion) override; friend class FTexture; }; @@ -218,7 +218,7 @@ static bool CheckDDS (FileReader &file) // //========================================================================== -FTexture *DDSTexture_TryCreate (FileReader &data, int lumpnum) +FImageSource *DDSImage_TryCreate (FileReader &data, int lumpnum) { union { @@ -283,16 +283,13 @@ FTexture *DDSTexture_TryCreate (FileReader &data, int lumpnum) //========================================================================== FDDSTexture::FDDSTexture (FileReader &lump, int lumpnum, void *vsurfdesc) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { DDSURFACEDESC2 *surf = (DDSURFACEDESC2 *)vsurfdesc; - UseType = ETextureType::MiscPatch; bMasked = false; - Width = uint16_t(surf->Width); Height = uint16_t(surf->Height); - CalcBitSize (); if (surf->PixelFormat.Flags & DDPF_FOURCC) { @@ -375,54 +372,30 @@ void FDDSTexture::CalcBitShift (uint32_t mask, uint8_t *lshiftp, uint8_t *rshift // //========================================================================== -FTextureFormat FDDSTexture::GetFormat() -{ -#if 0 - switch (Format) - { - case ID_DXT1: return TEX_DXT1; - case ID_DXT2: return TEX_DXT2; - case ID_DXT3: return TEX_DXT3; - case ID_DXT4: return TEX_DXT4; - case ID_DXT5: return TEX_DXT5; - default: return TEX_RGB; - } -#else - // For now, create a true color texture to preserve all colors. - return TEX_RGB; -#endif -} - -//========================================================================== -// -// -// -//========================================================================== - -uint8_t *FDDSTexture::MakeTexture (FRenderStyle style) +TArray FDDSTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); - auto Pixels = new uint8_t[Width*Height]; + TArray Pixels(Width*Height, true); lump.Seek (sizeof(DDSURFACEDESC2) + 4, FileReader::SeekSet); - int pmode = (style.Flags & STYLEF_RedIsAlpha) ? PIX_Alphatex : PIX_Palette; + int pmode = conversion == luminance ? PIX_Alphatex : PIX_Palette; if (Format >= 1 && Format <= 4) // RGB: Format is # of bytes per pixel { - ReadRGB (lump, Pixels, pmode); + ReadRGB (lump, Pixels.Data(), pmode); } else if (Format == ID_DXT1) { - DecompressDXT1 (lump, Pixels, pmode); + DecompressDXT1 (lump, Pixels.Data(), pmode); } else if (Format == ID_DXT3 || Format == ID_DXT2) { - DecompressDXT3 (lump, Format == ID_DXT2, Pixels, pmode); + DecompressDXT3 (lump, Format == ID_DXT2, Pixels.Data(), pmode); } else if (Format == ID_DXT5 || Format == ID_DXT4) { - DecompressDXT5 (lump, Format == ID_DXT4, Pixels, pmode); + DecompressDXT5 (lump, Format == ID_DXT4, Pixels.Data(), pmode); } return Pixels; } @@ -471,7 +444,7 @@ void FDDSTexture::ReadRGB (FileReader &lump, uint8_t *buffer, int pixelmode) uint32_t g = (c & GMask) << GShiftL; g |= g >> GShiftR; uint32_t b = (c & BMask) << BShiftL; b |= b >> BShiftR; uint32_t a = (c & AMask) << AShiftL; a |= a >> AShiftR; - *pixelp = RGBToPalette(pixelmode == PIX_Alphatex, r >> 24, g >> 24, b >> 24, a >> 24); + *pixelp = ImageHelpers::RGBToPalette(pixelmode == PIX_Alphatex, r >> 24, g >> 24, b >> 24, a >> 24); } else { @@ -486,9 +459,9 @@ void FDDSTexture::ReadRGB (FileReader &lump, uint8_t *buffer, int pixelmode) uint32_t g = (c & GMask) << GShiftL; g |= g >> GShiftR; uint32_t b = (c & BMask) << BShiftL; b |= b >> BShiftR; uint32_t a = (c & AMask) << AShiftL; a |= a >> AShiftR; - pixelp[0] = (uint8_t)(r>>24); + pixelp[0] = (uint8_t)(b>>24); pixelp[1] = (uint8_t)(g>>24); - pixelp[2] = (uint8_t)(b>>24); + pixelp[2] = (uint8_t)(r>>24); pixelp[3] = (uint8_t)(a>>24); pixelp+=4; } @@ -557,7 +530,7 @@ void FDDSTexture::DecompressDXT1 (FileReader &lump, uint8_t *buffer, int pixelmo // Pick colors from the palette for each of the four colors. if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i) { - palcol[i] = RGBToPalette(pixelmode == PIX_Alphatex, color[i]); + palcol[i] = ImageHelpers::RGBToPalette(pixelmode == PIX_Alphatex, color[i]); } // Now decode this 4x4 block to the pixel buffer. for (y = 0; y < 4; ++y) @@ -581,9 +554,9 @@ void FDDSTexture::DecompressDXT1 (FileReader &lump, uint8_t *buffer, int pixelmo else { uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4]; - tcp[0] = color[ci].r; + tcp[0] = color[ci].b; tcp[1] = color[ci].g; - tcp[2] = color[ci].b; + tcp[2] = color[ci].r; tcp[3] = color[ci].a; } } @@ -637,7 +610,7 @@ void FDDSTexture::DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t // Pick colors from the palette for each of the four colors. if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i) { - palcol[i] = RGBToPalette(pixelmode == PIX_Alphatex, color[i], false); + palcol[i] = ImageHelpers::RGBToPalette(pixelmode == PIX_Alphatex, color[i], false); } // Now decode this 4x4 block to the pixel buffer. @@ -670,9 +643,9 @@ void FDDSTexture::DecompressDXT3 (FileReader &lump, bool premultiplied, uint8_t { uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4]; int c = (yslice >> (x + x)) & 3; - tcp[0] = color[c].r; + tcp[0] = color[c].b; tcp[1] = color[c].g; - tcp[2] = color[c].b; + tcp[2] = color[c].r; tcp[3] = ((yalphaslice >> (x * 4)) & 15) * 0x11; } } @@ -749,7 +722,7 @@ void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t // Pick colors from the palette for each of the four colors. if (pixelmode != PIX_ARGB) for (i = 3; i >= 0; --i) { - palcol[i] = RGBToPalette(pixelmode == PIX_Alphatex, color[i], false); + palcol[i] = ImageHelpers::RGBToPalette(pixelmode == PIX_Alphatex, color[i], false); } // Now decode this 4x4 block to the pixel buffer. for (y = 0; y < 4; ++y) @@ -789,9 +762,9 @@ void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t { uint8_t * tcp = &buffer[(ox + x)*4 + (oy + y) * Width*4]; int c = (yslice >> (x + x)) & 3; - tcp[0] = color[c].r; + tcp[0] = color[c].b; tcp[1] = color[c].g; - tcp[2] = color[c].b; + tcp[2] = color[c].r; tcp[3] = alpha[((yalphaslice >> (x*3)) & 7)]; } } @@ -804,15 +777,15 @@ void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t //=========================================================================== // -// FDDSTexture::CopyTrueColorPixels +// FDDSTexture::CopyPixels // //=========================================================================== -int FDDSTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FDDSTexture::CopyPixels(FBitmap *bmp, int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); - uint8_t *TexBuffer = new uint8_t[4*Width*Height]; + uint8_t *TexBuffer = bmp->GetPixels(); lump.Seek (sizeof(DDSURFACEDESC2) + 4, FileReader::SeekSet); @@ -833,18 +806,5 @@ int FDDSTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo DecompressDXT5 (lump, Format == ID_DXT4, TexBuffer, PIX_ARGB); } - // All formats decompress to RGBA. - bmp->CopyPixelDataRGB(x, y, TexBuffer, Width, Height, 4, Width*4, rotate, CF_RGBA, inf); - delete [] TexBuffer; return -1; } - -//=========================================================================== -// -// -//=========================================================================== - -bool FDDSTexture::UseBasePalette() -{ - return false; -} diff --git a/src/textures/formats/emptytexture.cpp b/src/textures/formats/emptytexture.cpp index 19698551f..1073de660 100644 --- a/src/textures/formats/emptytexture.cpp +++ b/src/textures/formats/emptytexture.cpp @@ -39,6 +39,7 @@ #include "files.h" #include "w_wad.h" #include "textures/textures.h" +#include "image.h" //========================================================================== // @@ -46,12 +47,11 @@ // //========================================================================== -class FEmptyTexture : public FWorldTexture +class FEmptyTexture : public FImageSource { - uint8_t Pixel = 0; public: FEmptyTexture (int lumpnum); - uint8_t *MakeTexture(FRenderStyle style) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -60,7 +60,7 @@ public: // //========================================================================== -FTexture *EmptyTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *EmptyImage_TryCreate(FileReader & file, int lumpnum) { char check[8]; if (file.GetLength() != 8) return NULL; @@ -78,13 +78,11 @@ FTexture *EmptyTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FEmptyTexture::FEmptyTexture (int lumpnum) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { bMasked = true; - WidthBits = HeightBits = 1; Width = Height = 1; - WidthMask = 0; - PixelsAreStatic = 3; + bUseGamePalette = true; } //========================================================================== @@ -93,8 +91,10 @@ FEmptyTexture::FEmptyTexture (int lumpnum) // //========================================================================== -uint8_t *FEmptyTexture::MakeTexture(FRenderStyle style) +TArray FEmptyTexture::CreatePalettedPixels(int conversion) { - return &Pixel; + TArray Pixel(1, true); + Pixel[0] = 0; + return Pixel; } diff --git a/src/textures/formats/flattexture.cpp b/src/textures/formats/flattexture.cpp index 1d2a47e56..7654b2b35 100644 --- a/src/textures/formats/flattexture.cpp +++ b/src/textures/formats/flattexture.cpp @@ -37,6 +37,8 @@ #include "files.h" #include "w_wad.h" #include "textures/textures.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== // @@ -44,11 +46,11 @@ // //========================================================================== -class FFlatTexture : public FWorldTexture +class FFlatTexture : public FImageSource { public: FFlatTexture (int lumpnum); - uint8_t *MakeTexture (FRenderStyle style) override; + TArray CreatePalettedPixels(int conversion) override; }; @@ -60,7 +62,7 @@ public: // //========================================================================== -FTexture *FlatTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *FlatImage_TryCreate(FileReader & file, int lumpnum) { return new FFlatTexture(lumpnum); } @@ -72,7 +74,7 @@ FTexture *FlatTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FFlatTexture::FFlatTexture (int lumpnum) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { int area; int bits; @@ -90,11 +92,10 @@ FFlatTexture::FFlatTexture (int lumpnum) case 256*256: bits = 8; break; } + bUseGamePalette = true; bMasked = false; bTranslucent = false; - WidthBits = HeightBits = bits; Width = Height = 1 << bits; - WidthMask = (1 << bits) - 1; } //========================================================================== @@ -103,16 +104,16 @@ FFlatTexture::FFlatTexture (int lumpnum) // //========================================================================== -uint8_t *FFlatTexture::MakeTexture (FRenderStyle style) +TArray FFlatTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); - auto Pixels = new uint8_t[Width*Height]; - auto numread = lump.Read (Pixels, Width*Height); + TArray Pixels(Width*Height, true); + auto numread = lump.Read (Pixels.Data(), Width*Height); if (numread < Width*Height) { - memset (Pixels + numread, 0xBB, Width*Height - numread); + memset (Pixels.Data() + numread, 0xBB, Width*Height - numread); } - FTexture::FlipSquareBlockRemap(Pixels, Width, Height, GetRemap(style)); + ImageHelpers::FlipSquareBlockRemap(Pixels.Data(), Width, ImageHelpers::GetRemap(conversion == luminance)); return Pixels; } diff --git a/src/textures/formats/fontchars.cpp b/src/textures/formats/fontchars.cpp new file mode 100644 index 000000000..afb643487 --- /dev/null +++ b/src/textures/formats/fontchars.cpp @@ -0,0 +1,252 @@ +/* +** fontchars.cpp +** Texture class for font characters +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "doomtype.h" +#include "w_wad.h" +#include "v_palette.h" +#include "v_video.h" +#include "bitmap.h" +#include "image.h" +#include "imagehelpers.h" +#include "fontchars.h" + +//========================================================================== +// +// FFontChar1 :: FFontChar1 +// +// Used by fonts made from textures. +// +//========================================================================== + +FFontChar1::FFontChar1 (FImageSource *sourcelump) +: BaseTexture(sourcelump), SourceRemap (nullptr) +{ + // now copy all the properties from the base texture + assert(BaseTexture != nullptr); + CopySize(*BaseTexture); + bUseGamePalette = false; +} + +//========================================================================== +// +// FFontChar1 :: GetPixels +// +// Render style is not relevant for fonts. This must not use it! +// +//========================================================================== + +TArray FFontChar1::CreatePalettedPixels (int) +{ + // Make the texture as normal, then remap it so that all the colors + // are at the low end of the palette + // Why? It only creates unnecessary work! + auto Pixels = BaseTexture->GetPalettedPixels(normal); + + if (SourceRemap) + { + for (int x = 0; x < Width*Height; ++x) + { + Pixels[x] = SourceRemap[Pixels[x]]; + } + } + return Pixels; +} + +//========================================================================== +// +// FFontChar1 :: SetSourceRemap +// +//========================================================================== + +void FFontChar1::SetSourceRemap(const uint8_t *sourceremap) +{ + SourceRemap = sourceremap; +} + +//========================================================================== +// +// FFontChar2 :: FFontChar2 +// +// Used by FON1 and FON2 fonts. +// +//========================================================================== + +FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) +: SourceLump (sourcelump), SourcePos (sourcepos), SourceRemap(nullptr) +{ + Width = width; + Height = height; + LeftOffset = leftofs; + TopOffset = topofs; +} + +//========================================================================== +// +// FFontChar2 :: SetSourceRemap +// +//========================================================================== + +void FFontChar2::SetSourceRemap(const uint8_t *sourceremap) +{ + SourceRemap = sourceremap; +} + +//========================================================================== +// +// FFontChar2 :: Get8BitPixels +// +// Like for FontChar1, the render style has no relevance here as well. +// +//========================================================================== + +TArray FFontChar2::CreatePalettedPixels(int) +{ + auto lump = Wads.OpenLumpReader (SourceLump); + int destSize = Width * Height; + uint8_t max = 255; + bool rle = true; + + // This is to "fix" bad fonts + { + uint8_t buff[16]; + lump.Read (buff, 4); + if (buff[3] == '2') + { + lump.Read (buff, 7); + max = buff[6]; + lump.Seek (SourcePos - 11, FileReader::SeekCur); + } + else if (buff[3] == 0x1A) + { + lump.Read(buff, 13); + max = buff[12] - 1; + lump.Seek (SourcePos - 17, FileReader::SeekCur); + rle = false; + } + else + { + lump.Seek (SourcePos - 4, FileReader::SeekCur); + } + } + + TArray Pixels(destSize, true); + + int runlen = 0, setlen = 0; + uint8_t setval = 0; // Shut up, GCC! + uint8_t *dest_p = Pixels.Data(); + int dest_adv = Height; + int dest_rew = destSize - 1; + + if (rle) + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; ) + { + if (runlen != 0) + { + uint8_t color = lump.ReadUInt8(); + color = MIN (color, max); + if (SourceRemap != nullptr) + { + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + x--; + runlen--; + } + else if (setlen != 0) + { + *dest_p = setval; + dest_p += dest_adv; + x--; + setlen--; + } + else + { + int8_t code = lump.ReadInt8(); + if (code >= 0) + { + runlen = code + 1; + } + else if (code != -128) + { + uint8_t color = lump.ReadUInt8(); + setlen = (-code) + 1; + setval = MIN (color, max); + if (SourceRemap != nullptr) + { + setval = SourceRemap[setval]; + } + } + } + } + dest_p -= dest_rew; + } + } + else + { + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + uint8_t color = lump.ReadUInt8(); + if (color > max) + { + color = max; + } + if (SourceRemap != nullptr) + { + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + } + + if (destSize < 0) + { + char name[9]; + Wads.GetLumpName (name, SourceLump); + name[8] = 0; + I_FatalError ("The font %s is corrupt", name); + } + return Pixels; +} + diff --git a/src/textures/formats/fontchars.h b/src/textures/formats/fontchars.h new file mode 100644 index 000000000..96437f3a8 --- /dev/null +++ b/src/textures/formats/fontchars.h @@ -0,0 +1,30 @@ + + +// This is a font character that loads a texture and recolors it. +class FFontChar1 : public FImageSource +{ +public: + FFontChar1 (FImageSource *sourcelump); + TArray CreatePalettedPixels(int conversion) override; + void SetSourceRemap(const uint8_t *sourceremap); + +protected: + + FImageSource *BaseTexture; + const uint8_t *SourceRemap; +}; + +// This is a font character that reads RLE compressed data. +class FFontChar2 : public FImageSource +{ +public: + FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0); + + TArray CreatePalettedPixels(int conversion) override; + void SetSourceRemap(const uint8_t *sourceremap); + +protected: + int SourceLump; + int SourcePos; + const uint8_t *SourceRemap; +}; diff --git a/src/textures/formats/imgztexture.cpp b/src/textures/formats/imgztexture.cpp index b01de82a6..2f466c5e2 100644 --- a/src/textures/formats/imgztexture.cpp +++ b/src/textures/formats/imgztexture.cpp @@ -38,6 +38,8 @@ #include "w_wad.h" #include "v_video.h" #include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" bool checkIMGZPalette(FileReader &file); @@ -49,7 +51,7 @@ bool checkIMGZPalette(FileReader &file); // //========================================================================== -class FIMGZTexture : public FWorldTexture +class FIMGZTexture : public FImageSource { struct ImageHeader { @@ -66,11 +68,8 @@ class FIMGZTexture : public FWorldTexture public: FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool isalpha); - uint8_t *MakeTexture (FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; - - bool UseBasePalette() override { return !isalpha; } - FTextureFormat GetFormat() override { return isalpha ? TEX_RGB : TEX_Pal; } // should be TEX_Gray instead of TEX_RGB. Maybe later when all is working. + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; }; @@ -80,7 +79,7 @@ public: // //========================================================================== -FTexture *IMGZTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *IMGZImage_TryCreate(FileReader & file, int lumpnum) { uint32_t magic = 0; uint16_t w, h; @@ -105,15 +104,14 @@ FTexture *IMGZTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FIMGZTexture::FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int16_t t, bool _isalpha) - : FWorldTexture(NULL, lumpnum) + : FImageSource(lumpnum) { - Wads.GetLumpName (Name, lumpnum); Width = w; Height = h; - _LeftOffset[1] = _LeftOffset[0] = l; - _TopOffset[1] = _TopOffset[0] = t; + LeftOffset = l; + TopOffset = t; isalpha = _isalpha; - CalcBitSize (); + bUseGamePalette = !isalpha; } //========================================================================== @@ -122,7 +120,7 @@ FIMGZTexture::FIMGZTexture (int lumpnum, uint16_t w, uint16_t h, int16_t l, int1 // //========================================================================== -uint8_t *FIMGZTexture::MakeTexture (FRenderStyle style) +TArray FIMGZTexture::CreatePalettedPixels(int conversion) { FMemLump lump = Wads.ReadLump (SourceLump); const ImageHeader *imgz = (const ImageHeader *)lump.GetMem(); @@ -132,11 +130,10 @@ uint8_t *FIMGZTexture::MakeTexture (FRenderStyle style) int dest_adv = Height; int dest_rew = Width * Height - 1; - CalcBitSize (); - auto Pixels = new uint8_t[Width*Height]; - dest_p = Pixels; + TArray Pixels(Width*Height, true); + dest_p = Pixels.Data(); - const uint8_t *remap = GetRemap(style, isalpha); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); // Convert the source image from row-major to column-major format and remap it if (!imgz->Compression) @@ -203,9 +200,9 @@ uint8_t *FIMGZTexture::MakeTexture (FRenderStyle style) // //========================================================================== -int FIMGZTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FIMGZTexture::CopyPixels(FBitmap *bmp, int conversion) { - if (!isalpha) return FTexture::CopyTrueColorPixels(bmp, x, y, rotate, inf); - else return CopyTrueColorTranslated(bmp, x, y, rotate, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette, inf); + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); + else return CopyTranslatedPixels(bmp, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette); } diff --git a/src/textures/formats/jpegtexture.cpp b/src/textures/formats/jpegtexture.cpp index f3f626622..68ead4a7d 100644 --- a/src/textures/formats/jpegtexture.cpp +++ b/src/textures/formats/jpegtexture.cpp @@ -45,6 +45,8 @@ extern "C" #include "v_text.h" #include "bitmap.h" #include "v_video.h" +#include "imagehelpers.h" +#include "image.h" struct FLumpSourceMgr : public jpeg_source_mgr @@ -178,15 +180,13 @@ void JPEG_OutputMessage (j_common_ptr cinfo) // //========================================================================== -class FJPEGTexture : public FWorldTexture +class FJPEGTexture : public FImageSource { public: FJPEGTexture (int lumpnum, int width, int height); - FTextureFormat GetFormat () override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - bool UseBasePalette() override; - uint8_t *MakeTexture (FRenderStyle style) override; + int CopyPixels(FBitmap *bmp, int conversion) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -195,7 +195,7 @@ public: // //========================================================================== -FTexture *JPEGTexture_TryCreate(FileReader & data, int lumpnum) +FImageSource *JPEGImage_TryCreate(FileReader & data, int lumpnum) { union { @@ -246,14 +246,12 @@ FTexture *JPEGTexture_TryCreate(FileReader & data, int lumpnum) //========================================================================== FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { - UseType = ETextureType::MiscPatch; bMasked = false; Width = width; Height = height; - CalcBitSize (); } //========================================================================== @@ -262,28 +260,16 @@ FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height) // //========================================================================== -FTextureFormat FJPEGTexture::GetFormat() -{ - return TEX_RGB; -} - -//========================================================================== -// -// -// -//========================================================================== - -uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) +TArray FJPEGTexture::CreatePalettedPixels(int conversion) { auto lump = Wads.OpenLumpReader (SourceLump); JSAMPLE *buff = NULL; - bool doalpha = !!(style.Flags & STYLEF_RedIsAlpha); jpeg_decompress_struct cinfo; jpeg_error_mgr jerr; - auto Pixels = new uint8_t[Width * Height]; - memset (Pixels, 0xBA, Width * Height); + TArray Pixels(Width * Height, true); + memset (Pixels.Data(), 0xBA, Width * Height); cinfo.err = jpeg_std_error(&jerr); cinfo.err->output_message = JPEG_OutputMessage; @@ -293,6 +279,7 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) FLumpSourceMgr sourcemgr(&lump, &cinfo); try { + bool doalpha = conversion == luminance; jpeg_read_header(&cinfo, TRUE); if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) || (cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) || @@ -312,13 +299,13 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) { int num_scanlines = jpeg_read_scanlines(&cinfo, &buff, 1); uint8_t *in = buff; - uint8_t *out = Pixels + y; + uint8_t *out = Pixels.Data() + y; switch (cinfo.out_color_space) { case JCS_RGB: for (int x = Width; x > 0; --x) { - *out = RGBToPalette(doalpha, in[0], in[1], in[2]); + *out = ImageHelpers::RGBToPalette(doalpha, in[0], in[1], in[2]); out += Height; in += 3; } @@ -326,7 +313,7 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) case JCS_GRAYSCALE: { - auto remap = GetRemap(style, true); + auto remap = ImageHelpers::GetRemap(doalpha, true); for (int x = Width; x > 0; --x) { *out = remap[in[0]]; @@ -344,7 +331,7 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) int r = in[3] - (((256 - in[0])*in[3]) >> 8); int g = in[3] - (((256 - in[1])*in[3]) >> 8); int b = in[3] - (((256 - in[2])*in[3]) >> 8); - *out = RGBToPalette(doalpha, r, g, b); + *out = ImageHelpers::RGBToPalette(doalpha, r, g, b); out += Height; in += 4; } @@ -358,7 +345,7 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) int r = clamp((int)(Y + 1.40200 * (Cr - 0x80)), 0, 255); int g = clamp((int)(Y - 0.34414 * (Cb - 0x80) - 0.71414 * (Cr - 0x80)), 0, 255); int b = clamp((int)(Y + 1.77200 * (Cb - 0x80)), 0, 255); - *out = RGBToPalette(doalpha, r, g, b); + *out = ImageHelpers::RGBToPalette(doalpha, r, g, b); out += Height; in += 4; } @@ -389,18 +376,17 @@ uint8_t *FJPEGTexture::MakeTexture (FRenderStyle style) //=========================================================================== // -// FJPEGTexture::CopyTrueColorPixels +// FJPEGTexture::CopyPixels // // Preserves the full color information (unlike software mode) // //=========================================================================== -int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FJPEGTexture::CopyPixels(FBitmap *bmp, int conversion) { PalEntry pe[256]; auto lump = Wads.OpenLumpReader (SourceLump); - JSAMPLE *buff = NULL; jpeg_decompress_struct cinfo; jpeg_error_mgr jerr; @@ -427,12 +413,11 @@ int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FC jpeg_start_decompress(&cinfo); int yc = 0; - buff = new uint8_t[cinfo.output_height * cinfo.output_width * cinfo.output_components]; - + TArray buff(cinfo.output_height * cinfo.output_width * cinfo.output_components, true); while (cinfo.output_scanline < cinfo.output_height) { - uint8_t * ptr = buff + cinfo.output_width * cinfo.output_components * yc; + uint8_t * ptr = buff.Data() + cinfo.output_width * cinfo.output_components * yc; jpeg_read_scanlines(&cinfo, &ptr, 1); yc++; } @@ -440,24 +425,24 @@ int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FC switch (cinfo.out_color_space) { case JCS_RGB: - bmp->CopyPixelDataRGB(x, y, buff, cinfo.output_width, cinfo.output_height, - 3, cinfo.output_width * cinfo.output_components, rotate, CF_RGB, inf); + bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, + 3, cinfo.output_width * cinfo.output_components, 0, CF_RGB); break; case JCS_GRAYSCALE: for (int i = 0; i < 256; i++) pe[i] = PalEntry(255, i, i, i); // default to a gray map - bmp->CopyPixelData(x, y, buff, cinfo.output_width, cinfo.output_height, - 1, cinfo.output_width, rotate, pe, inf); + bmp->CopyPixelData(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, + 1, cinfo.output_width, 0, pe); break; case JCS_CMYK: - bmp->CopyPixelDataRGB(x, y, buff, cinfo.output_width, cinfo.output_height, - 4, cinfo.output_width * cinfo.output_components, rotate, CF_CMYK, inf); + bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, + 4, cinfo.output_width * cinfo.output_components, 0, CF_CMYK); break; case JCS_YCbCr: - bmp->CopyPixelDataRGB(x, y, buff, cinfo.output_width, cinfo.output_height, - 4, cinfo.output_width * cinfo.output_components, rotate, CF_YCbCr, inf); + bmp->CopyPixelDataRGB(0, 0, buff.Data(), cinfo.output_width, cinfo.output_height, + 4, cinfo.output_width * cinfo.output_components, 0, CF_YCbCr); break; default: @@ -472,17 +457,6 @@ int FJPEGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FC Printf(TEXTCOLOR_ORANGE "JPEG error in %s\n", Wads.GetLumpFullPath(SourceLump).GetChars()); } jpeg_destroy_decompress(&cinfo); - if (buff != NULL) delete [] buff; return 0; } - -//=========================================================================== -// -// -//=========================================================================== - -bool FJPEGTexture::UseBasePalette() -{ - return false; -} diff --git a/src/textures/formats/multipatchtexture.cpp b/src/textures/formats/multipatchtexture.cpp index fb9381808..165a49344 100644 --- a/src/textures/formats/multipatchtexture.cpp +++ b/src/textures/formats/multipatchtexture.cpp @@ -49,164 +49,10 @@ #include "v_video.h" #include "v_text.h" #include "cmdlib.h" +#include "imagehelpers.h" +#include "image.h" +#include "multipatchtexture.h" -// On the Alpha, accessing the shorts directly if they aren't aligned on a -// 4-byte boundary causes unaligned access warnings. Why it does this at -// all and only while initing the textures is beyond me. - -#ifdef ALPHA -#define SAFESHORT(s) ((short)(((uint8_t *)&(s))[0] + ((uint8_t *)&(s))[1] * 256)) -#else -#define SAFESHORT(s) LittleShort(s) -#endif - - - -//-------------------------------------------------------------------------- -// -// Data structures for the TEXTUREx lumps -// -//-------------------------------------------------------------------------- - -// -// Each texture is composed of one or more patches, with patches being lumps -// stored in the WAD. The lumps are referenced by number, and patched into -// the rectangular texture space using origin and possibly other attributes. -// -struct mappatch_t -{ - int16_t originx; - int16_t originy; - int16_t patch; - int16_t stepdir; - int16_t colormap; -}; - -// -// A wall texture is a list of patches which are to be combined in a -// predefined order. -// -struct maptexture_t -{ - uint8_t name[8]; - uint16_t Flags; // [RH] Was unused - uint8_t ScaleX; // [RH] Scaling (8 is normal) - uint8_t ScaleY; // [RH] Same as above - int16_t width; - int16_t height; - uint8_t columndirectory[4]; // OBSOLETE - int16_t patchcount; - mappatch_t patches[1]; -}; - -#define MAPTEXF_WORLDPANNING 0x8000 - -// Strife uses versions of the above structures that remove all unused fields - -struct strifemappatch_t -{ - int16_t originx; - int16_t originy; - int16_t patch; -}; - -// -// A wall texture is a list of patches which are to be combined in a -// predefined order. -// -struct strifemaptexture_t -{ - uint8_t name[8]; - uint16_t Flags; // [RH] Was unused - uint8_t ScaleX; // [RH] Scaling (8 is normal) - uint8_t ScaleY; // [RH] Same as above - int16_t width; - int16_t height; - int16_t patchcount; - strifemappatch_t patches[1]; -}; - - -//========================================================================== -// -// In-memory representation of a single PNAMES lump entry -// -//========================================================================== - -struct FPatchLookup -{ - FString Name; -}; - - -//========================================================================== -// -// A texture defined in a TEXTURE1 or TEXTURE2 lump -// -//========================================================================== - -class FMultiPatchTexture : public FWorldTexture -{ -public: - FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflump); - FMultiPatchTexture (FScanner &sc, ETextureType usetype); - ~FMultiPatchTexture (); - - FTextureFormat GetFormat() override; - bool UseBasePalette() override; - virtual void SetFrontSkyLayer () override; - - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - int GetSourceLump() override { return DefinitionLump; } - FTexture *GetRedirect() override; - FTexture *GetRawTexture() override; - void ResolvePatches(); - -protected: - uint8_t *Pixels; - Span **Spans; - int DefinitionLump; - - struct TexPart - { - FRemapTable *Translation = nullptr; - FTexture *Texture = nullptr; - PalEntry Blend = 0; - blend_t Alpha = FRACUNIT; - int16_t OriginX = 0; - int16_t OriginY = 0; - uint8_t Rotate = 0; - uint8_t op = OP_COPY; - }; - - struct TexInit - { - FString TexName; - ETextureType UseType = ETextureType::Null; - bool Silent = false; - bool HasLine = false; - bool UseOffsets = false; - FScriptPosition sc; - }; - - int NumParts; - TexPart *Parts; - TexInit *Inits; - bool bRedirect; - bool bTranslucentPatches; - - uint8_t *MakeTexture (FRenderStyle style); - - // The getters must optionally redirect if it's a simple one-patch texture. - const uint8_t *GetPixels(FRenderStyle style) override { return bRedirect ? Parts->Texture->GetPixels(style) : FWorldTexture::GetPixels(style); } - const uint8_t *GetColumn(FRenderStyle style, unsigned int col, const Span **out) override - { return bRedirect ? Parts->Texture->GetColumn(style, col, out) : FWorldTexture::GetColumn(style, col, out); } - - -private: - void CheckForHacks (); - void ParsePatch(FScanner &sc, TexPart & part, TexInit &init); -}; //========================================================================== // @@ -214,130 +60,25 @@ private: // //========================================================================== -FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum) -: Pixels (0), Spans(0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false) +FMultiPatchTexture::FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual) { - union + Width = w; + Height = h; + bComplex = complex; + bTextual = textual; + Parts = (TexPart*)ImageArena.Alloc(sizeof(TexPart) * parts.Size()); + NumParts = parts.Size(); + memcpy(Parts, parts.Data(), sizeof(TexPart) * parts.Size()); + + bUseGamePalette = false; + if (!bComplex) { - const maptexture_t *d; - const strifemaptexture_t *s; - } - mtexture; - - union - { - const mappatch_t *d; - const strifemappatch_t *s; - } - mpatch; - - int i; - - mtexture.d = (const maptexture_t *)texdef; - bMultiPatch = 1; - - if (strife) - { - NumParts = SAFESHORT(mtexture.s->patchcount); - } - else - { - NumParts = SAFESHORT(mtexture.d->patchcount); - } - - if (NumParts < 0) - { - I_FatalError ("Bad texture directory"); - } - - UseType = ETextureType::Wall; - Parts = NumParts > 0 ? new TexPart[NumParts] : nullptr; - Inits = NumParts > 0 ? new TexInit[NumParts] : nullptr; - Width = SAFESHORT(mtexture.d->width); - Height = SAFESHORT(mtexture.d->height); - Name = (char *)mtexture.d->name; - CalcBitSize (); - - Scale.X = mtexture.d->ScaleX ? mtexture.d->ScaleX / 8. : 1.; - Scale.Y = mtexture.d->ScaleY ? mtexture.d->ScaleY / 8. : 1.; - - if (mtexture.d->Flags & MAPTEXF_WORLDPANNING) - { - bWorldPanning = true; - } - - if (strife) - { - mpatch.s = &mtexture.s->patches[0]; - } - else - { - mpatch.d = &mtexture.d->patches[0]; - } - - for (i = 0; i < NumParts; ++i) - { - if (unsigned(LittleShort(mpatch.d->patch)) >= unsigned(maxpatchnum)) + for (int i = 0; i < NumParts; i++) { - I_FatalError ("Bad PNAMES and/or texture directory:\n\nPNAMES has %d entries, but\n%s wants to use entry %d.", - maxpatchnum, Name.GetChars(), LittleShort(mpatch.d->patch)+1); + if (!Parts[i].Image->UseGamePalette()) return; } - Parts[i].OriginX = LittleShort(mpatch.d->originx); - Parts[i].OriginY = LittleShort(mpatch.d->originy); - Parts[i].Texture = nullptr; - Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name; - Inits[i].UseType = ETextureType::WallPatch; - if (strife) - mpatch.s++; - else - mpatch.d++; + bUseGamePalette = true; // only if all patches use the game palette. } - if (NumParts == 0) - { - Printf ("Texture %s is left without any patches\n", Name.GetChars()); - } - - DefinitionLump = deflumpnum; -} - -//========================================================================== -// -// FMultiPatchTexture :: ~FMultiPatchTexture -// -//========================================================================== - -FMultiPatchTexture::~FMultiPatchTexture () -{ - Unload (); - if (Parts != NULL) - { - for(int i=0; iSetFrontSkyLayer (); - } - bNoRemap0 = true; } //========================================================================== @@ -346,7 +87,7 @@ void FMultiPatchTexture::SetFrontSkyLayer () // //========================================================================== -uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) +static uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) { switch (blend.a==0 ? int(blend) : -1) { @@ -391,7 +132,56 @@ uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) } } } - return NULL; + return nullptr; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FMultiPatchTexture::CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style) +{ + auto cimage = source->GetCachedPalettedPixels(style); // should use composition cache + auto &image = cimage.Pixels; + const uint8_t *pixels = image.Data(); + int srcwidth = source->GetWidth(); + int srcheight = source->GetHeight(); + int step_x = source->GetHeight(); + int step_y = 1; + FClipRect cr = { 0, 0, dwidth, dheight }; + if (style) translation = nullptr; // do not apply translations to alpha textures. + + if (ClipCopyPixelRect(&cr, xpos, ypos, pixels, srcwidth, srcheight, step_x, step_y, rotate)) + { + dest += ypos + dheight * xpos; + if (translation == NULL) + { + for (int x = 0; x < srcwidth; x++) + { + int pos = x * dheight; + for (int y = 0; y < srcheight; y++, pos++) + { + // the optimizer is doing a good enough job here so there's no need to optimize this by hand + uint8_t v = pixels[y * step_y + x * step_x]; + if (v != 0) dest[pos] = v; + } + } + } + else + { + for (int x = 0; x < srcwidth; x++) + { + int pos = x * dheight; + for (int y = 0; y < srcheight; y++, pos++) + { + uint8_t v = pixels[y * step_y + x * step_x]; + if (v != 0) dest[pos] = translation[v]; + } + } + } + } } //========================================================================== @@ -400,20 +190,19 @@ uint8_t *GetBlendMap(PalEntry blend, uint8_t *blendwork) // //========================================================================== -uint8_t *FMultiPatchTexture::MakeTexture (FRenderStyle style) +TArray FMultiPatchTexture::CreatePalettedPixels(int conversion) { - // Add a little extra space at the end if the texture's height is not - // a power of 2, in case somebody accidentally makes it repeat vertically. - int numpix = Width * Height + (1 << HeightBits) - Height; + int numpix = Width * Height; uint8_t blendwork[256]; bool buildrgb = bComplex; - auto Pixels = new uint8_t[numpix]; - memset (Pixels, 0, numpix); + TArray Pixels(numpix, true); + memset (Pixels.Data(), 0, numpix); - if (style.Flags & STYLEF_RedIsAlpha) + if (conversion == luminance) { - buildrgb = !UseBasePalette(); + // For alpha textures, downconversion to the palette would lose too much precision if not all patches use the palette. + buildrgb = !UseGamePalette(); } else { @@ -426,20 +215,27 @@ uint8_t *FMultiPatchTexture::MakeTexture (FRenderStyle style) } } } + if (conversion == noremap0) + { + // sky remapping will only happen if + // - the texture was defined through a TEXTUREx lump (this implies only trivial copies) + // - all patches use the base palette. + // All other cases would not be able to properly deal with this special case. + // For textual definitions this hack isn't necessary. + if (bTextual || !UseGamePalette()) conversion = normal; + } if (!buildrgb) { for (int i = 0; i < NumParts; ++i) { - if (Parts[i].Texture->bHasCanvas) continue; // cannot use camera textures as patch. - uint8_t *trans = Parts[i].Translation? Parts[i].Translation->Remap : nullptr; { if (Parts[i].Blend != 0) { trans = GetBlendMap(Parts[i].Blend, blendwork); } - Parts[i].Texture->CopyToBlock (Pixels, Width, Height, Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate, trans, style); + CopyToBlock (Pixels.Data(), Width, Height, Parts[i].Image, Parts[i].OriginX, Parts[i].OriginY, Parts[i].Rotate, trans, conversion); } } } @@ -447,24 +243,23 @@ uint8_t *FMultiPatchTexture::MakeTexture (FRenderStyle style) { // In case there are translucent patches let's do the composition in // True color to keep as much precision as possible before downconverting to the palette. - uint8_t *buffer = new uint8_t[Width * Height * 4]; - memset(buffer, 0, Width * Height * 4); - FillBuffer(buffer, Width * 4, Height, TEX_RGB); + FBitmap PixelsIn; + PixelsIn.Create(Width, Height); + CopyPixels(&PixelsIn, normal); for(int y = 0; y < Height; y++) { - uint8_t *in = buffer + Width * y * 4; - uint8_t *out = Pixels + y; + uint8_t *in = PixelsIn.GetPixels() + Width * y * 4; + uint8_t *out = Pixels.Data() + y; for (int x = 0; x < Width; x++) { if (*out == 0 && in[3] != 0) { - *out = RGBToPalette(style, in[2], in[1], in[0]); + *out = ImageHelpers::RGBToPalette(conversion == luminance, in[2], in[1], in[0]); } out += Height; in += 4; } } - delete [] buffer; } return Pixels; } @@ -477,36 +272,13 @@ uint8_t *FMultiPatchTexture::MakeTexture (FRenderStyle style) // //=========================================================================== -int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FMultiPatchTexture::CopyPixels(FBitmap *bmp, int conversion) { int retv = -1; - if (bRedirect) - { // Redirect straight to the real texture's routine. - return Parts[0].Texture->CopyTrueColorPixels(bmp, x, y, rotate, inf); - } - - if (rotate != 0 || (inf != NULL && ((inf->op != OP_OVERWRITE && inf->op != OP_COPY) || inf->blend != BLEND_NONE))) - { // We are doing some sort of fancy stuff to the destination bitmap, so composite to - // a temporary bitmap, and copy that. - FBitmap tbmp; - if (tbmp.Create(Width, Height)) - { - retv = MAX(retv, CopyTrueColorPixels(&tbmp, 0, 0, 0)); - bmp->CopyPixelDataRGB(x, y, tbmp.GetPixels(), Width, Height, - 4, tbmp.GetPitch(), rotate, CF_BGRA, inf); - } - return retv; - } - - // When compositing a multipatch texture with multipatch parts, - // drawing must be restricted to the actual area which is covered by this texture. - FClipRect saved_cr = bmp->GetClipRect(); - bmp->IntersectClipRect(x, y, Width, Height); - - if (inf != NULL && inf->op == OP_OVERWRITE) + if (conversion == noremap0) { - bmp->Zero(); + if (bTextual || !UseGamePalette()) conversion = normal; } for(int i = 0; i < NumParts; i++) @@ -514,8 +286,6 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota int ret = -1; FCopyInfo info; - if (Parts[i].Texture->bHasCanvas) continue; // cannot use camera textures as patch. - memset (&info, 0, sizeof(info)); info.alpha = Parts[i].Alpha; info.invalpha = BLENDUNIT - info.alpha; @@ -545,776 +315,39 @@ int FMultiPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rota } } - if (Parts[i].Translation != NULL) - { // Using a translation forces downconversion to the base palette - ret = Parts[i].Texture->CopyTrueColorTranslated(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate, Parts[i].Translation->Palette, &info); - } - else - { - ret = Parts[i].Texture->CopyTrueColorPixels(bmp, x+Parts[i].OriginX, y+Parts[i].OriginY, Parts[i].Rotate, &info); - } + auto trans = Parts[i].Translation ? Parts[i].Translation->Palette : nullptr; + FBitmap Pixels = Parts[i].Image->GetCachedBitmap(trans, conversion, &ret); + bmp->Blit(Parts[i].OriginX, Parts[i].OriginY, Pixels, Pixels.GetWidth(), Pixels.GetHeight(), Parts[i].Rotate, &info); // treat -1 (i.e. unknown) as absolute. We have no idea if this may have overwritten previous info so a real check needs to be done. if (ret == -1) retv = ret; else if (retv != -1 && ret > retv) retv = ret; } - // Restore previous clipping rectangle. - bmp->SetClipRect(saved_cr); return retv; } //========================================================================== // -// FMultiPatchTexture :: GetFormat // -// only returns 'paletted' if all patches use the base palette. // //========================================================================== -FTextureFormat FMultiPatchTexture::GetFormat() -{ - if (bComplex) return TEX_RGB; - if (NumParts == 1) return Parts[0].Texture->GetFormat(); - return UseBasePalette() ? TEX_Pal : TEX_RGB; -} - - -//=========================================================================== -// -// FMultipatchTexture::UseBasePalette -// -// returns true if all patches in the texture use the unmodified base -// palette. -// -//=========================================================================== - -bool FMultiPatchTexture::UseBasePalette() -{ - if (bComplex) return false; - for(int i=0;iUseBasePalette()) return false; - } - return true; -} - -//========================================================================== -// -// FMultiPatchTexture :: CheckForHacks -// -//========================================================================== - -void FMultiPatchTexture::CheckForHacks () +void FMultiPatchTexture::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) { - if (NumParts <= 0) - { - return; - } + FImageSource::CollectForPrecache(info, requiretruecolor); - // Heretic sky textures are marked as only 128 pixels tall, - // even though they are really 200 pixels tall. - if (gameinfo.gametype == GAME_Heretic && - Name[0] == 'S' && - Name[1] == 'K' && - Name[2] == 'Y' && - Name[4] == 0 && - Name[3] >= '1' && - Name[3] <= '3' && - Height == 128) + if (!requiretruecolor) { - Height = 200; - HeightBits = 8; - return; - } + requiretruecolor = bComplex; - // The Doom E1 sky has its patch's y offset at -8 instead of 0. - if (gameinfo.gametype == GAME_Doom && - !(gameinfo.flags & GI_MAPxx) && - NumParts == 1 && - Height == 128 && - Parts->OriginY == -8 && - Name[0] == 'S' && - Name[1] == 'K' && - Name[2] == 'Y' && - Name[3] == '1' && - Name[4] == 0) - { - Parts->OriginY = 0; - return; - } - - // BIGDOOR7 in Doom also has patches at y offset -4 instead of 0. - if (gameinfo.gametype == GAME_Doom && - !(gameinfo.flags & GI_MAPxx) && - NumParts == 2 && - Height == 128 && - Parts[0].OriginY == -4 && - Parts[1].OriginY == -4 && - Name[0] == 'B' && - Name[1] == 'I' && - Name[2] == 'G' && - Name[3] == 'D' && - Name[4] == 'O' && - Name[5] == 'O' && - Name[6] == 'R' && - Name[7] == '7') - { - Parts[0].OriginY = 0; - Parts[1].OriginY = 0; - return; - } - - // [RH] Some wads (I forget which!) have single-patch textures 256 - // pixels tall that have patch lengths recorded as 0. I can't think of - // any good reason for them to do this, and since I didn't make note - // of which wad made me hack in support for them, the hack is gone - // because I've added support for DeePsea's true tall patches. - // - // Okay, I found a wad with crap patches: Pleiades.wad's sky patches almost - // fit this description and are a big mess, but they're not single patch! - if (Height == 256) - { - int i; - - // All patches must be at the top of the texture for this fix - for (i = 0; i < NumParts; ++i) + if (!requiretruecolor) for (int i = 0; i < NumParts; ++i) { - if (Parts[i].OriginY != 0) - { - break; - } + if (Parts[i].op != OP_COPY) requiretruecolor = true; } } -} - -//========================================================================== -// -// FMultiPatchTexture :: GetRedirect -// -//========================================================================== - -FTexture *FMultiPatchTexture::GetRedirect() -{ - return bRedirect ? Parts->Texture : this; -} - -//========================================================================== -// -// FMultiPatchTexture :: GetRawTexture -// -// Doom ignored all compositing of mid-sided textures on two-sided lines. -// Since these textures had to be single-patch in Doom, that essentially -// means it ignores their Y offsets. -// -// If this texture is composed of only one patch, return that patch. -// Otherwise, return this texture, since Doom wouldn't have been able to -// draw it anyway. -// -//========================================================================== - -FTexture *FMultiPatchTexture::GetRawTexture() -{ - return NumParts == 1 && UseType == ETextureType::Wall && bMultiPatch == 1 && Scale == Parts->Texture->Scale ? Parts->Texture : this; -} - -//========================================================================== -// -// FTextureManager :: AddTexturesLump -// -//========================================================================== - -void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1) -{ - FPatchLookup *patchlookup = NULL; - int i; - uint32_t numpatches; - - if (firstdup == 0) + for (int i = 0; i < NumParts; ++i) { - firstdup = (int)Textures.Size(); - } - - { - auto pnames = Wads.OpenLumpReader(patcheslump); - numpatches = pnames.ReadUInt32(); - - // Check whether the amount of names reported is correct. - if ((signed)numpatches < 0) - { - Printf("Corrupt PNAMES lump found (negative amount of entries reported)\n"); - return; - } - - // Check whether the amount of names reported is correct. - int lumplength = Wads.LumpLength(patcheslump); - if (numpatches > uint32_t((lumplength-4)/8)) - { - Printf("PNAMES lump is shorter than required (%u entries reported but only %d bytes (%d entries) long\n", - numpatches, lumplength, (lumplength-4)/8); - // Truncate but continue reading. Who knows how many such lumps exist? - numpatches = (lumplength-4)/8; - } - - // Catalog the patches these textures use so we know which - // textures they represent. - patchlookup = new FPatchLookup[numpatches]; - for (uint32_t i = 0; i < numpatches; ++i) - { - char pname[9]; - pnames.Read(pname, 8); - pname[8] = '\0'; - patchlookup[i].Name = pname; - } - } - - bool isStrife = false; - const uint32_t *maptex, *directory; - uint32_t maxoff; - int numtextures; - uint32_t offset = 0; // Shut up, GCC! - - maptex = (const uint32_t *)lumpdata; - numtextures = LittleLong(*maptex); - maxoff = lumpsize; - - if (maxoff < uint32_t(numtextures+1)*4) - { - Printf ("Texture directory is too short\n"); - delete[] patchlookup; - return; - } - - // Scan the texture lump to decide if it contains Doom or Strife textures - for (i = 0, directory = maptex+1; i < numtextures; ++i) - { - offset = LittleLong(directory[i]); - if (offset > maxoff) - { - Printf ("Bad texture directory\n"); - delete[] patchlookup; - return; - } - - maptexture_t *tex = (maptexture_t *)((uint8_t *)maptex + offset); - - // There is bizzarely a Doom editing tool that writes to the - // first two elements of columndirectory, so I can't check those. - if (SAFESHORT(tex->patchcount) < 0 || - tex->columndirectory[2] != 0 || - tex->columndirectory[3] != 0) - { - isStrife = true; - break; - } - } - - - // Textures defined earlier in the lump take precedence over those defined later, - // but later TEXTUREx lumps take precedence over earlier ones. - for (i = 1, directory = maptex; i <= numtextures; ++i) - { - if (i == 1 && texture1) - { - // The very first texture is just a dummy. Copy its dimensions to texture 0. - // It still needs to be created in case someone uses it by name. - offset = LittleLong(directory[1]); - const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); - FDummyTexture *tex0 = static_cast(Textures[0].Texture); - tex0->SetSize (SAFESHORT(tex->width), SAFESHORT(tex->height)); - } - - offset = LittleLong(directory[i]); - if (offset > maxoff) - { - Printf ("Bad texture directory\n"); - delete[] patchlookup; - return; - } - - // If this texture was defined already in this lump, skip it - // This could cause problems with animations that use the same name for intermediate - // textures. Should I be worried? - int j; - for (j = (int)Textures.Size() - 1; j >= firstdup; --j) - { - if (strnicmp (Textures[j].Texture->Name, (const char *)maptex + offset, 8) == 0) - break; - } - if (j + 1 == firstdup) - { - FMultiPatchTexture *tex = new FMultiPatchTexture ((const uint8_t *)maptex + offset, patchlookup, numpatches, isStrife, deflumpnum); - if (i == 1 && texture1) - { - tex->UseType = ETextureType::FirstDefined; - } - TexMan.AddTexture (tex); - StartScreen->Progress(); - } - } - delete[] patchlookup; -} - - -//========================================================================== -// -// FTextureManager :: AddTexturesLumps -// -//========================================================================== - -void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump) -{ - int firstdup = (int)Textures.Size(); - - if (lump1 >= 0) - { - FMemLump texdir = Wads.ReadLump (lump1); - AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump1), lump1, patcheslump, firstdup, true); - } - if (lump2 >= 0) - { - FMemLump texdir = Wads.ReadLump (lump2); - AddTexturesLump (texdir.GetMem(), Wads.LumpLength (lump2), lump2, patcheslump, firstdup, false); + Parts[i].Image->CollectForPrecache(info, requiretruecolor); } } -//========================================================================== -// -// -// -//========================================================================== - -void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init) -{ - FString patchname; - int Mirror = 0; - sc.MustGetString(); - - init.TexName = sc.String; - sc.MustGetStringName(","); - sc.MustGetNumber(); - part.OriginX = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - part.OriginY = sc.Number; - - if (sc.CheckString("{")) - { - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("flipx")) - { - Mirror |= 1; - } - else if (sc.Compare("flipy")) - { - Mirror |= 2; - } - else if (sc.Compare("rotate")) - { - sc.MustGetNumber(); - sc.Number = (((sc.Number + 90)%360)-90); - if (sc.Number != 0 && sc.Number !=90 && sc.Number != 180 && sc.Number != -90) - { - sc.ScriptError("Rotation must be a multiple of 90 degrees."); - } - part.Rotate = (sc.Number / 90) & 3; - } - else if (sc.Compare("Translation")) - { - int match; - - bComplex = true; - if (part.Translation != NULL) delete part.Translation; - part.Translation = NULL; - part.Blend = 0; - static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL }; - sc.MustGetString(); - - match = sc.MatchString(maps); - if (match >= 0) - { - part.Blend = BLEND_SPECIALCOLORMAP1 + match; - } - else if (sc.Compare("ICE")) - { - part.Blend = BLEND_ICEMAP; - } - else if (sc.Compare("DESATURATE")) - { - sc.MustGetStringName(","); - sc.MustGetNumber(); - part.Blend = BLEND_DESATURATE1 + clamp(sc.Number-1, 0, 30); - } - else - { - sc.UnGet(); - part.Translation = new FRemapTable; - part.Translation->MakeIdentity(); - do - { - sc.MustGetString(); - part.Translation->AddToTranslation(sc.String); - } - while (sc.CheckString(",")); - } - - } - else if (sc.Compare("Colormap")) - { - float r1,g1,b1; - float r2,g2,b2; - - sc.MustGetFloat(); - r1 = (float)sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - g1 = (float)sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - b1 = (float)sc.Float; - if (!sc.CheckString(",")) - { - part.Blend = AddSpecialColormap(0,0,0, r1, g1, b1); - } - else - { - sc.MustGetFloat(); - r2 = (float)sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - g2 = (float)sc.Float; - sc.MustGetStringName(","); - sc.MustGetFloat(); - b2 = (float)sc.Float; - part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2); - } - } - else if (sc.Compare("Blend")) - { - bComplex = true; - if (part.Translation != NULL) delete part.Translation; - part.Translation = NULL; - part.Blend = 0; - - if (!sc.CheckNumber()) - { - sc.MustGetString(); - part.Blend = V_GetColor(NULL, sc); - } - else - { - int r,g,b; - - r = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - g = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - b = sc.Number; - //sc.MustGetStringName(","); This was never supposed to be here. - part.Blend = MAKERGB(r, g, b); - } - // Blend.a may never be 0 here. - if (sc.CheckString(",")) - { - sc.MustGetFloat(); - if (sc.Float > 0.f) - part.Blend.a = clamp(int(sc.Float*255), 1, 254); - else - part.Blend = 0; - } - else part.Blend.a = 255; - } - else if (sc.Compare("alpha")) - { - sc.MustGetFloat(); - part.Alpha = clamp(int(sc.Float * BLENDUNIT), 0, BLENDUNIT); - // bComplex is not set because it is only needed when the style is not OP_COPY. - } - else if (sc.Compare("style")) - { - static const char *styles[] = {"copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay", NULL }; - sc.MustGetString(); - part.op = sc.MustMatchString(styles); - bComplex |= (part.op != OP_COPY); - bTranslucentPatches = bComplex; - } - else if (sc.Compare("useoffsets")) - { - init.UseOffsets = true; - } - } - } - if (Mirror & 2) - { - part.Rotate = (part.Rotate + 2) & 3; - Mirror ^= 1; - } - if (Mirror & 1) - { - part.Rotate |= 4; - } -} - -//========================================================================== -// -// Constructor for text based multipatch definitions -// -//========================================================================== - -FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, ETextureType usetype) -: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false) -{ - TArray parts; - TArray inits; - bool bSilent = false; - - bMultiPatch = 2; - sc.SetCMode(true); - sc.MustGetString(); - const char* textureName = NULL; - if (sc.Compare("optional")) - { - bSilent = true; - sc.MustGetString(); - if (sc.Compare(",")) - { - // this is not right. Apparently a texture named 'optional' is being defined right now... - sc.UnGet(); - textureName = "optional"; - bSilent = false; - } - } - Name = !textureName ? sc.String : textureName; - Name.ToUpper(); - sc.MustGetStringName(","); - sc.MustGetNumber(); - Width = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - Height = sc.Number; - UseType = usetype; - - bool offset2set = false; - if (sc.CheckString("{")) - { - while (!sc.CheckString("}")) - { - sc.MustGetString(); - if (sc.Compare("XScale")) - { - sc.MustGetFloat(); - Scale.X = sc.Float; - if (Scale.X == 0) sc.ScriptError("Texture %s is defined with null x-scale\n", Name.GetChars()); - } - else if (sc.Compare("YScale")) - { - sc.MustGetFloat(); - Scale.Y = sc.Float; - if (Scale.Y == 0) sc.ScriptError("Texture %s is defined with null y-scale\n", Name.GetChars()); - } - else if (sc.Compare("WorldPanning")) - { - bWorldPanning = true; - } - else if (sc.Compare("NullTexture")) - { - UseType = ETextureType::Null; - } - else if (sc.Compare("NoDecals")) - { - bNoDecals = true; - } - else if (sc.Compare("Patch")) - { - TexPart part; - TexInit init; - ParsePatch(sc, part, init); - if (init.TexName.IsNotEmpty()) - { - parts.Push(part); - init.UseType = ETextureType::WallPatch; - init.Silent = bSilent; - init.HasLine = true; - init.sc = sc; - inits.Push(init); - } - part.Texture = NULL; - part.Translation = NULL; - } - else if (sc.Compare("Sprite")) - { - TexPart part; - TexInit init; - ParsePatch(sc, part, init); - if (init.TexName.IsNotEmpty()) - { - parts.Push(part); - init.UseType = ETextureType::Sprite; - init.Silent = bSilent; - init.HasLine = true; - init.sc = sc; - inits.Push(init); - } - part.Texture = NULL; - part.Translation = NULL; - } - else if (sc.Compare("Graphic")) - { - TexPart part; - TexInit init; - ParsePatch(sc, part, init); - if (init.TexName.IsNotEmpty()) - { - parts.Push(part); - init.UseType = ETextureType::MiscPatch; - init.Silent = bSilent; - init.HasLine = true; - init.sc = sc; - inits.Push(init); - } - part.Texture = NULL; - part.Translation = NULL; - } - else if (sc.Compare("Offset")) - { - sc.MustGetNumber(); - _LeftOffset[0] = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - _TopOffset[0] = sc.Number; - if (!offset2set) - { - _LeftOffset[1] = _LeftOffset[0]; - _TopOffset[1] = _TopOffset[0]; - } - } - else if (sc.Compare("Offset2")) - { - sc.MustGetNumber(); - _LeftOffset[1] = sc.Number; - sc.MustGetStringName(","); - sc.MustGetNumber(); - _TopOffset[1] = sc.Number; - offset2set = true; - } - else - { - sc.ScriptError("Unknown texture property '%s'", sc.String); - } - } - - NumParts = parts.Size(); - Parts = new TexPart[NumParts]; - memcpy(Parts, &parts[0], NumParts * sizeof(*Parts)); - Inits = new TexInit[NumParts]; - for (int i = 0; i < NumParts; i++) - { - Inits[i] = inits[i]; - } - } - - if (Width <= 0 || Height <= 0) - { - UseType = ETextureType::Null; - Printf("Texture %s has invalid dimensions (%d, %d)\n", Name.GetChars(), Width, Height); - Width = Height = 1; - } - CalcBitSize (); - - - sc.SetCMode(false); -} - - -void FMultiPatchTexture::ResolvePatches() -{ - if (Inits != nullptr) - { - for (int i = 0; i < NumParts; i++) - { - FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType); - if (texno == id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. - { - TArray list; - TexMan.ListTextures(Inits[i].TexName, list, true); - for (int i = list.Size() - 1; i >= 0; i--) - { - if (list[i] != id && !TexMan[list[i]]->bMultiPatch) - { - texno = list[i]; - break; - } - } - if (texno == id) - { - if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); - else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", Inits[i].TexName.GetChars()); - continue; - } - else - { - // If it could be resolved, just print a developer warning. - DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s\n", Inits[i].TexName.GetChars()); - } - } - - if (!texno.isValid()) - { - if (!Inits[i].Silent) - { - if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); - else Printf(TEXTCOLOR_YELLOW "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name.GetChars()); - } - } - else - { - Parts[i].Texture = TexMan[texno]; - bComplex |= Parts[i].Texture->bComplex; - Parts[i].Texture->bKeepAround = true; - if (Inits[i].UseOffsets) - { - Parts[i].OriginX -= Parts[i].Texture->GetLeftOffset(0); - Parts[i].OriginY -= Parts[i].Texture->GetTopOffset(0); - } - } - } - for (int i = 0; i < NumParts; i++) - { - if (Parts[i].Texture == nullptr) - { - memmove(&Parts[i], &Parts[i + 1], (NumParts - i - 1) * sizeof(TexPart)); - i--; - NumParts--; - } - } - } - delete[] Inits; - Inits = nullptr; - - CheckForHacks(); - - // If this texture is just a wrapper around a single patch, we can simply - // forward GetPixels() and GetColumn() calls to that patch. - - if (NumParts == 1) - { - if (Parts->OriginX == 0 && Parts->OriginY == 0 && - Parts->Texture->GetWidth() == Width && - Parts->Texture->GetHeight() == Height && - Parts->Rotate == 0 && - !bComplex) - { - bRedirect = true; - } - } -} - - -void FTextureManager::ParseXTexture(FScanner &sc, ETextureType usetype) -{ - FTexture *tex = new FMultiPatchTexture(sc, usetype); - TexMan.AddTexture (tex); -} diff --git a/src/textures/formats/multipatchtexture.h b/src/textures/formats/multipatchtexture.h new file mode 100644 index 000000000..3d7800832 --- /dev/null +++ b/src/textures/formats/multipatchtexture.h @@ -0,0 +1,116 @@ +#pragma once +#include "sc_man.h" + +//========================================================================== +// +// TexPart is the data that will get passed to the final texture. +// +//========================================================================== + +struct TexPart +{ + FRemapTable *Translation = nullptr; + FImageSource *Image = nullptr; + PalEntry Blend = 0; + blend_t Alpha = FRACUNIT; + int16_t OriginX = 0; + int16_t OriginY = 0; + uint8_t Rotate = 0; + uint8_t op = OP_COPY; +}; + + + +//========================================================================== +// +// A texture defined in a TEXTURE1 or TEXTURE2 lump +// +//========================================================================== + +class FMultiPatchTexture : public FImageSource +{ + friend class FTexture; +public: + FMultiPatchTexture(int w, int h, const TArray &parts, bool complex, bool textual); + +protected: + int NumParts; + bool bComplex; + bool bTextual; + TexPart *Parts; + + // The getters must optionally redirect if it's a simple one-patch texture. + int CopyPixels(FBitmap *bmp, int conversion) override; + TArray CreatePalettedPixels(int conversion) override; + void CopyToBlock(uint8_t *dest, int dwidth, int dheight, FImageSource *source, int xpos, int ypos, int rotate, const uint8_t *translation, int style); + void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor); + +}; + + +//========================================================================== +// +// Additional data per patch which is needed for initialization +// +//========================================================================== + +struct TexInit +{ + FString TexName; + ETextureType UseType = ETextureType::Null; + FTexture *Texture = nullptr; + bool Silent = false; + bool HasLine = false; + bool UseOffsets = false; + FScriptPosition sc; +}; + +//========================================================================== +// +// All build info only needed to construct the multipatch textures +// +//========================================================================== + +struct FPatchLookup; + +struct BuildInfo +{ + FString Name; + TArray Parts; + TArray Inits; + int Width = 0; + int Height = 0; + DVector2 Scale = { 1, 1 }; + bool bWorldPanning = false; // This sucks! + int DefinitionLump = 0; + bool bComplex = false; + bool textual = false; + bool bNoDecals = false; + int LeftOffset[2] = {}; + int TopOffset[2] = {}; + FImageTexture *tex = nullptr; +}; + +class FMultipatchTextureBuilder +{ + FTextureManager &TexMan; + TArray BuiltTextures; + + void MakeTexture(BuildInfo &buildinfo, ETextureType usetype); + + void BuildTexture(const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum, ETextureType usetyoe); + void AddTexturesLump(const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1); + + void ParsePatch(FScanner &sc, BuildInfo &info, TexPart &part, TexInit &init); + void CheckForHacks(BuildInfo &buildinfo); + void ResolvePatches(BuildInfo &buildinfo); + +public: + FMultipatchTextureBuilder(FTextureManager &texMan) : TexMan(texMan) + { + } + + void AddTexturesLumps(int lump1, int lump2, int patcheslump); + void ParseTexture(FScanner &sc, ETextureType usetype); + void ResolveAllPatches(); +}; diff --git a/src/textures/formats/patchtexture.cpp b/src/textures/formats/patchtexture.cpp index 2fe928b05..705da984a 100644 --- a/src/textures/formats/patchtexture.cpp +++ b/src/textures/formats/patchtexture.cpp @@ -39,6 +39,8 @@ #include "v_palette.h" #include "v_video.h" #include "bitmap.h" +#include "image.h" +#include "imagehelpers.h" // posts are runs of non masked source pixels @@ -56,18 +58,15 @@ bool checkPatchForAlpha(const void *buffer, uint32_t length); // //========================================================================== -class FPatchTexture : public FWorldTexture +class FPatchTexture : public FImageSource { bool badflag = false; bool isalpha = false; public: FPatchTexture (int lumpnum, patch_t *header, bool isalphatex); - uint8_t *MakeTexture (FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; void DetectBadPatches(); - - bool UseBasePalette() override { return !isalpha; } - FTextureFormat GetFormat() override { return isalpha ? TEX_RGB : TEX_Pal; } // should be TEX_Gray instead of TEX_RGB. Maybe later when all is working. }; //========================================================================== @@ -80,11 +79,10 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) { if (file.GetLength() < 13) return false; // minimum length of a valid Doom patch - uint8_t *data = new uint8_t[file.GetLength()]; file.Seek(0, FileReader::SeekSet); - file.Read(data, file.GetLength()); + auto data = file.Read(file.GetLength()); - const patch_t *foo = (const patch_t *)data; + const patch_t *foo = (const patch_t *)data.Data(); int height = LittleShort(foo->height); int width = LittleShort(foo->width); @@ -107,7 +105,6 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) } else if (ofs >= (uint32_t)(file.GetLength())) // Need one byte for an empty column (but there's patches that don't know that!) { - delete [] data; return false; } } @@ -115,12 +112,10 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) { // only check this if the texture passed validation. // Here is a good point because we already have a valid buffer of the lump's data. - isalpha = checkPatchForAlpha(data, (uint32_t)file.GetLength()); + isalpha = checkPatchForAlpha(data.Data(), (uint32_t)file.GetLength()); } - delete[] data; return !gapAtStart; } - delete [] data; return false; } @@ -130,7 +125,7 @@ static bool CheckIfPatch(FileReader & file, bool &isalpha) // //========================================================================== -FTexture *PatchTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *PatchImage_TryCreate(FileReader & file, int lumpnum) { patch_t header; bool isalpha; @@ -151,15 +146,15 @@ FTexture *PatchTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FPatchTexture::FPatchTexture (int lumpnum, patch_t * header, bool isalphatex) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { + bUseGamePalette = !isalphatex; isalpha = isalphatex; Width = header->width; Height = header->height; - _LeftOffset[1] = _LeftOffset[0] = header->leftoffset; - _TopOffset[1] = _TopOffset[0] = header->topoffset; + LeftOffset = header->leftoffset; + TopOffset = header->topoffset; DetectBadPatches(); - CalcBitSize (); } //========================================================================== @@ -168,7 +163,7 @@ FPatchTexture::FPatchTexture (int lumpnum, patch_t * header, bool isalphatex) // //========================================================================== -uint8_t *FPatchTexture::MakeTexture (FRenderStyle style) +TArray FPatchTexture::CreatePalettedPixels(int conversion) { uint8_t *remap, remaptable[256]; int numspans; @@ -180,9 +175,9 @@ uint8_t *FPatchTexture::MakeTexture (FRenderStyle style) maxcol = (const column_t *)((const uint8_t *)patch + Wads.LumpLength (SourceLump) - 3); - remap = GetRemap(style, isalpha); + remap = ImageHelpers::GetRemap(conversion == luminance, isalpha); // Special case for skies - if (bNoRemap0 && remap == GPalette.Remap) + if (conversion == noremap0 && remap == GPalette.Remap) { memcpy(remaptable, GPalette.Remap, 256); remaptable[0] = 0; @@ -191,11 +186,11 @@ uint8_t *FPatchTexture::MakeTexture (FRenderStyle style) if (badflag) { - auto Pixels = new uint8_t[Width * Height]; + TArray Pixels(Width * Height, true); uint8_t *out; // Draw the image to the buffer - for (x = 0, out = Pixels; x < Width; ++x) + for (x = 0, out = Pixels.Data(); x < Width; ++x) { const uint8_t *in = (const uint8_t *)patch + LittleLong(patch->columnofs[x]) + 3; @@ -208,19 +203,17 @@ uint8_t *FPatchTexture::MakeTexture (FRenderStyle style) return Pixels; } - // Add a little extra space at the end if the texture's height is not - // a power of 2, in case somebody accidentally makes it repeat vertically. - int numpix = Width * Height + (1 << HeightBits) - Height; + int numpix = Width * Height; numspans = Width; - auto Pixels = new uint8_t[numpix]; - memset (Pixels, 0, numpix); + TArray Pixels(numpix, true); + memset (Pixels.Data(), 0, numpix); // Draw the image to the buffer for (x = 0; x < Width; ++x) { - uint8_t *outtop = Pixels + x*Height; + uint8_t *outtop = Pixels.Data() + x*Height; const column_t *column = (const column_t *)((const uint8_t *)patch + LittleLong(patch->columnofs[x])); int top = -1; @@ -267,10 +260,10 @@ uint8_t *FPatchTexture::MakeTexture (FRenderStyle style) // //========================================================================== -int FPatchTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FPatchTexture::CopyPixels(FBitmap *bmp, int conversion) { - if (!isalpha) return FTexture::CopyTrueColorPixels(bmp, x, y, rotate, inf); - else return CopyTrueColorTranslated(bmp, x, y, rotate, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette, inf); + if (!isalpha) return FImageSource::CopyPixels(bmp, conversion); + else return CopyTranslatedPixels(bmp, translationtables[TRANSLATION_Standard][STD_Grayscale]->Palette); } //========================================================================== @@ -307,8 +300,8 @@ void FPatchTexture::DetectBadPatches () return; // More than one post in a column! } } - _LeftOffset[1] = _LeftOffset[0] = 0; - _TopOffset[1] = _TopOffset[0] = 0; + LeftOffset = 0; + TopOffset = 0; badflag = true; bMasked = false; // Hacked textures don't have transparent parts. } diff --git a/src/textures/formats/pcxtexture.cpp b/src/textures/formats/pcxtexture.cpp index 4f7972312..70cb7e2e7 100644 --- a/src/textures/formats/pcxtexture.cpp +++ b/src/textures/formats/pcxtexture.cpp @@ -39,6 +39,8 @@ #include "w_wad.h" #include "bitmap.h" #include "v_video.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== // @@ -78,15 +80,12 @@ struct PCXHeader // //========================================================================== -class FPCXTexture : public FWorldTexture +class FPCXTexture : public FImageSource { public: FPCXTexture (int lumpnum, PCXHeader &); - FTextureFormat GetFormat () override; - - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - bool UseBasePalette() override; + int CopyPixels(FBitmap *bmp, int conversion) override; protected: void ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr); @@ -94,7 +93,7 @@ protected: void ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr); void ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr, int planes); - uint8_t *MakeTexture (FRenderStyle style) override; + TArray CreatePalettedPixels(int conversion) override; }; @@ -104,7 +103,7 @@ protected: // //========================================================================== -FTexture * PCXTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource * PCXImage_TryCreate(FileReader & file, int lumpnum) { PCXHeader hdr; @@ -143,23 +142,11 @@ FTexture * PCXTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FPCXTexture::FPCXTexture(int lumpnum, PCXHeader & hdr) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { bMasked = false; Width = LittleShort(hdr.xmax) - LittleShort(hdr.xmin) + 1; Height = LittleShort(hdr.ymax) - LittleShort(hdr.ymin) + 1; - CalcBitSize(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FTextureFormat FPCXTexture::GetFormat() -{ - return TEX_RGB; } //========================================================================== @@ -174,9 +161,8 @@ void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int rle_count = 0; uint8_t rle_value = 0; - uint8_t * srcp = new uint8_t[lump.GetLength() - sizeof(PCXHeader)]; - lump.Read(srcp, lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp; + TArray srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + uint8_t * src = srcp.Data(); for (y = 0; y < Height; ++y) { @@ -209,7 +195,6 @@ void FPCXTexture::ReadPCX1bit (uint8_t *dst, FileReader & lump, PCXHeader *hdr) } } } - delete [] srcp; } //========================================================================== @@ -223,12 +208,11 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int rle_count = 0, rle_value = 0; int x, y, c; int bytes; - uint8_t * line = new uint8_t[hdr->bytesPerScanLine]; - uint8_t * colorIndex = new uint8_t[Width]; + TArray line(hdr->bytesPerScanLine, true); + TArray colorIndex(Width, true); - uint8_t * srcp = new uint8_t[lump.GetLength() - sizeof(PCXHeader)]; - lump.Read(srcp, lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp; + TArray srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + uint8_t * src = srcp.Data(); for (y = 0; y < Height; ++y) { @@ -237,7 +221,7 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) for (c = 0; c < 4; ++c) { - uint8_t * pLine = line; + uint8_t * pLine = line.Data(); bytes = hdr->bytesPerScanLine; @@ -268,11 +252,6 @@ void FPCXTexture::ReadPCX4bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) ptr[x] += (1 << c); } } - - /* release memory */ - delete [] colorIndex; - delete [] line; - delete [] srcp; } //========================================================================== @@ -286,9 +265,8 @@ void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) int rle_count = 0, rle_value = 0; int y, bytes; - uint8_t * srcp = new uint8_t[lump.GetLength() - sizeof(PCXHeader)]; - lump.Read(srcp, lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp; + auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + uint8_t * src = srcp.Data(); for (y = 0; y < Height; ++y) { @@ -314,7 +292,6 @@ void FPCXTexture::ReadPCX8bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr) *ptr++ = rle_value; } } - delete [] srcp; } //========================================================================== @@ -329,9 +306,8 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr int y, c; int bytes; - uint8_t * srcp = new uint8_t[lump.GetLength() - sizeof(PCXHeader)]; - lump.Read(srcp, lump.GetLength() - sizeof(PCXHeader)); - uint8_t * src = srcp; + auto srcp = lump.Read(lump.GetLength() - sizeof(PCXHeader)); + uint8_t * src = srcp.Data(); for (y = 0; y < Height; ++y) { @@ -362,7 +338,6 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr } } } - delete [] srcp; } //========================================================================== @@ -371,20 +346,20 @@ void FPCXTexture::ReadPCX24bits (uint8_t *dst, FileReader & lump, PCXHeader *hdr // //========================================================================== -uint8_t *FPCXTexture::MakeTexture(FRenderStyle style) +TArray FPCXTexture::CreatePalettedPixels(int conversion) { uint8_t PaletteMap[256]; PCXHeader header; int bitcount; - bool alphatex = !!(style.Flags & STYLEF_RedIsAlpha); auto lump = Wads.OpenLumpReader(SourceLump); lump.Read(&header, sizeof(header)); bitcount = header.bitsPerPixel * header.numColorPlanes; - auto Pixels = new uint8_t[Width*Height]; + TArray Pixels(Width*Height, true); + bool alphatex = conversion == luminance; if (bitcount < 24) { if (bitcount < 8) @@ -393,17 +368,17 @@ uint8_t *FPCXTexture::MakeTexture(FRenderStyle style) { default: case 1: - PaletteMap[0] = alphatex? 0 : GrayMap[0]; - PaletteMap[1] = alphatex? 255 : GrayMap[255]; - ReadPCX1bit (Pixels, lump, &header); + PaletteMap[0] = alphatex? 0 : ImageHelpers::GrayMap[0]; + PaletteMap[1] = alphatex? 255 : ImageHelpers::GrayMap[255]; + ReadPCX1bit (Pixels.Data(), lump, &header); break; case 4: for (int i = 0; i < 16; i++) { - PaletteMap[i] = RGBToPalettePrecise(alphatex, header.palette[i * 3], header.palette[i * 3 + 1], header.palette[i * 3 + 2]); + PaletteMap[i] = ImageHelpers::RGBToPalettePrecise(alphatex, header.palette[i * 3], header.palette[i * 3 + 1], header.palette[i * 3 + 2]); } - ReadPCX4bits (Pixels, lump, &header); + ReadPCX4bits (Pixels.Data(), lump, &header); break; } } @@ -418,56 +393,53 @@ uint8_t *FPCXTexture::MakeTexture(FRenderStyle style) uint8_t r = lump.ReadUInt8(); uint8_t g = lump.ReadUInt8(); uint8_t b = lump.ReadUInt8(); - PaletteMap[i] = RGBToPalettePrecise(alphatex, r, g, b); + PaletteMap[i] = ImageHelpers::RGBToPalettePrecise(alphatex, r, g, b); } lump.Seek(sizeof(header), FileReader::SeekSet); - ReadPCX8bits (Pixels, lump, &header); + ReadPCX8bits (Pixels.Data(), lump, &header); } if (Width == Height) { - FlipSquareBlockRemap(Pixels, Width, Height, PaletteMap); + ImageHelpers::FlipSquareBlockRemap(Pixels.Data(), Width, PaletteMap); } else { - uint8_t *newpix = new uint8_t[Width*Height]; - FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, Width, PaletteMap); - uint8_t *oldpix = Pixels; - Pixels = newpix; - delete[] oldpix; + TArray newpix(Width*Height, true); + ImageHelpers::FlipNonSquareBlockRemap (newpix.Data(), Pixels.Data(), Width, Height, Width, PaletteMap); + return newpix; } } else { - uint8_t * buffer = new uint8_t[Width*Height * 3]; - uint8_t * row = buffer; - ReadPCX24bits (buffer, lump, &header, 3); + TArray buffer(Width*Height * 3, true); + uint8_t * row = buffer.Data(); + ReadPCX24bits (row, lump, &header, 3); for(int y=0; y Pixels; auto lump = Wads.OpenLumpReader(SourceLump); @@ -477,7 +449,7 @@ int FPCXTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo if (bitcount < 24) { - Pixels = new uint8_t[Width*Height]; + Pixels.Resize(Width*Height); if (bitcount < 8) { switch (bitcount) @@ -486,7 +458,7 @@ int FPCXTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo case 1: pe[0] = PalEntry(255, 0, 0, 0); pe[1] = PalEntry(255, 255, 255, 255); - ReadPCX1bit (Pixels, lump, &header); + ReadPCX1bit (Pixels.Data(), lump, &header); break; case 4: @@ -494,7 +466,7 @@ int FPCXTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo { pe[i] = PalEntry(255, header.palette[i * 3], header.palette[i * 3 + 1], header.palette[i * 3 + 2]); } - ReadPCX4bits (Pixels, lump, &header); + ReadPCX4bits (Pixels.Data(), lump, &header); break; } } @@ -515,27 +487,16 @@ int FPCXTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo pe[i] = PalEntry(255, r,g,b); } lump.Seek(sizeof(header), FileReader::SeekSet); - ReadPCX8bits (Pixels, lump, &header); + ReadPCX8bits (Pixels.Data(), lump, &header); } - bmp->CopyPixelData(x, y, Pixels, Width, Height, 1, Width, rotate, pe, inf); + bmp->CopyPixelData(0, 0, Pixels.Data(), Width, Height, 1, Width, 0, pe); } else { - Pixels = new uint8_t[Width*Height * 3]; - ReadPCX24bits (Pixels, lump, &header, 3); - bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 3, Width*3, rotate, CF_RGB, inf); + Pixels.Resize(Width*Height*4); + ReadPCX24bits (Pixels.Data(), lump, &header, 3); + bmp->CopyPixelDataRGB(0, 0, Pixels.Data(), Width, Height, 3, Width*3, 0, CF_RGB); } - delete [] Pixels; return 0; } - -//=========================================================================== -// -// -//=========================================================================== - -bool FPCXTexture::UseBasePalette() -{ - return false; -} diff --git a/src/textures/formats/pngtexture.cpp b/src/textures/formats/pngtexture.cpp index bdb232c0c..6f42eee41 100644 --- a/src/textures/formats/pngtexture.cpp +++ b/src/textures/formats/pngtexture.cpp @@ -39,6 +39,8 @@ #include "templates.h" #include "m_png.h" #include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== // @@ -46,23 +48,17 @@ // //========================================================================== -class FPNGTexture : public FWorldTexture +class FPNGTexture : public FImageSource { public: - FPNGTexture (FileReader &lump, int lumpnum, const FString &filename, int width, int height, uint8_t bitdepth, uint8_t colortype, uint8_t interlace); - ~FPNGTexture(); + FPNGTexture (FileReader &lump, int lumpnum, int width, int height, uint8_t bitdepth, uint8_t colortype, uint8_t interlace); - FTextureFormat GetFormat () override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - bool UseBasePalette() override; - uint8_t *MakeTexture(FRenderStyle style) override; + int CopyPixels(FBitmap *bmp, int conversion) override; + TArray CreatePalettedPixels(int conversion) override; protected: void ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap); - FString SourceFile; - FileReader fr; - uint8_t BitDepth; uint8_t ColorType; uint8_t Interlace; @@ -82,7 +78,7 @@ protected: // //========================================================================== -FTexture *PNGTexture_TryCreate(FileReader & data, int lumpnum) +FImageSource *PNGImage_TryCreate(FileReader & data, int lumpnum) { union { @@ -141,7 +137,7 @@ FTexture *PNGTexture_TryCreate(FileReader & data, int lumpnum) } } - return new FPNGTexture (data, lumpnum, FString(), width, height, bitdepth, colortype, interlace); + return new FPNGTexture (data, lumpnum, width, height, bitdepth, colortype, interlace); } //========================================================================== @@ -150,49 +146,9 @@ FTexture *PNGTexture_TryCreate(FileReader & data, int lumpnum) // //========================================================================== -FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) -{ - - if (M_FindPNGChunk(png, MAKE_ID('I','H','D','R')) == 0) - { - return NULL; - } - - // Check the IHDR to make sure it's a type of PNG we support. - auto &data = png->File; - int width = data.ReadInt32BE(); - int height = data.ReadInt32BE(); - uint8_t bitdepth = data.ReadUInt8(); - uint8_t colortype = data.ReadUInt8(); - uint8_t compression = data.ReadUInt8(); - uint8_t filter = data.ReadUInt8(); - uint8_t interlace = data.ReadUInt8(); - - if (compression != 0 || filter != 0 || interlace > 1) - { - return NULL; - } - if (!((1 << colortype) & 0x5D)) - { - return NULL; - } - if (!((1 << bitdepth) & 0x116)) - { - return NULL; - } - - return new FPNGTexture (png->File, -1, filename, width, height, bitdepth, colortype, interlace); -} - -//========================================================================== -// -// -// -//========================================================================== - -FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename, int width, int height, +FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, int width, int height, uint8_t depth, uint8_t colortype, uint8_t interlace) -: FWorldTexture(NULL, lumpnum), SourceFile(filename), +: FImageSource(lumpnum), BitDepth(depth), ColorType(colortype), Interlace(interlace), HaveTrans(false) { union @@ -204,12 +160,10 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename uint32_t len, id; int i; - UseType = ETextureType::MiscPatch; bMasked = false; Width = width; Height = height; - CalcBitSize (); memset(trans, 255, 256); @@ -247,8 +201,8 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename Printf ("Y-Offset for PNG texture %s is bad: %d (0x%08x)\n", Wads.GetLumpFullName (lumpnum), ihoty, ihoty); ihoty = 0; } - _LeftOffset[1] = _LeftOffset[0] = ihotx; - _TopOffset[1] = _TopOffset[0] = ihoty; + LeftOffset = ihotx; + TopOffset = ihoty; } break; @@ -293,18 +247,18 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename { bMasked = true; PaletteSize = 256; - PaletteMap = new uint8_t[256]; - memcpy (PaletteMap, GrayMap, 256); + PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); + memcpy (PaletteMap, ImageHelpers::GrayMap, 256); PaletteMap[NonPaletteTrans[0]] = 0; } else { - PaletteMap = GrayMap; + PaletteMap = ImageHelpers::GrayMap; } break; case 3: // Paletted - PaletteMap = new uint8_t[PaletteSize]; + PaletteMap = (uint8_t*)ImageArena.Alloc(PaletteSize); GPalette.MakeRemap (p.palette, PaletteMap, trans, PaletteSize); for (i = 0; i < PaletteSize; ++i) { @@ -324,44 +278,6 @@ FPNGTexture::FPNGTexture (FileReader &lump, int lumpnum, const FString &filename bMasked = HaveTrans; break; } - // If this is a savegame we must keep the reader. - if (lumpnum == -1) fr = std::move(lump); -} - -//========================================================================== -// -// -// -//========================================================================== - -FPNGTexture::~FPNGTexture () -{ - if (PaletteMap != nullptr && PaletteMap != FTexture::GrayMap) - { - delete[] PaletteMap; - PaletteMap = nullptr; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -FTextureFormat FPNGTexture::GetFormat() -{ -#if 0 - switch (ColorType) - { - case 3: return TEX_Pal; - case 0: return TEX_Gray; - default: return TEX_RGB; - } -#else - // For now, create a true color texture to preserve all colors. - return TEX_RGB; -#endif } //========================================================================== @@ -390,26 +306,18 @@ void FPNGTexture::ReadAlphaRemap(FileReader *lump, uint8_t *alpharemap) // //========================================================================== -uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) +TArray FPNGTexture::CreatePalettedPixels(int conversion) { FileReader *lump; FileReader lfr; - bool alphatex = !!(style.Flags & STYLEF_RedIsAlpha); - if (SourceLump >= 0) - { - lfr = Wads.OpenLumpReader(SourceLump); - lump = 𝔩 - } - else - { - lump = &fr; - } + lfr = Wads.OpenLumpReader(SourceLump); + lump = 𝔩 - auto Pixels = new uint8_t[Width*Height]; + TArray Pixels(Width*Height, true); if (StartOfIDAT == 0) { - memset (Pixels, 0x99, Width*Height); + memset (Pixels.Data(), 0x99, Width*Height); } else { @@ -418,47 +326,46 @@ uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) lump->Read(&len, 4); lump->Read(&id, 4); + bool alphatex = conversion == luminance; if (ColorType == 0 || ColorType == 3) /* Grayscale and paletted */ { - M_ReadIDAT (*lump, Pixels, Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); + M_ReadIDAT (*lump, Pixels.Data(), Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); if (Width == Height) { - if (!alphatex) + if (conversion != luminance) { - FTexture::FlipSquareBlockRemap (Pixels, Width, Height, PaletteMap); + ImageHelpers::FlipSquareBlockRemap (Pixels.Data(), Width, PaletteMap); } else if (ColorType == 0) { - FTexture::FlipSquareBlock (Pixels, Width, Height); + ImageHelpers::FlipSquareBlock (Pixels.Data(), Width); } else { uint8_t alpharemap[256]; ReadAlphaRemap(lump, alpharemap); - FTexture::FlipSquareBlockRemap(Pixels, Width, Height, alpharemap); + ImageHelpers::FlipSquareBlockRemap(Pixels.Data(), Width, alpharemap); } } else { - uint8_t *newpix = new uint8_t[Width*Height]; - if (!alphatex) + TArray newpix(Width*Height, true); + if (conversion != luminance) { - FTexture::FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, Width, PaletteMap); + ImageHelpers::FlipNonSquareBlockRemap (newpix.Data(), Pixels.Data(), Width, Height, Width, PaletteMap); } else if (ColorType == 0) { - FTexture::FlipNonSquareBlock (newpix, Pixels, Width, Height, Width); + ImageHelpers::FlipNonSquareBlock (newpix.Data(), Pixels.Data(), Width, Height, Width); } else { uint8_t alpharemap[256]; ReadAlphaRemap(lump, alpharemap); - FTexture::FlipNonSquareBlockRemap(newpix, Pixels, Width, Height, Width, alpharemap); + ImageHelpers::FlipNonSquareBlockRemap(newpix.Data(), Pixels.Data(), Width, Height, Width, alpharemap); } - uint8_t *oldpix = Pixels; - Pixels = newpix; - delete[] oldpix; + return newpix; } } else /* RGB and/or Alpha present */ @@ -470,7 +377,7 @@ uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) M_ReadIDAT (*lump, tempix, Width, Height, Width*bytesPerPixel, BitDepth, ColorType, Interlace, BigLong((unsigned int)len)); in = tempix; - out = Pixels; + out = Pixels.Data(); // Convert from source format to paletted, column-major. // Formats with alpha maps are reduced to only 1 bit of alpha. @@ -489,7 +396,7 @@ uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) } else { - *out++ = RGBToPalette(alphatex, in[0], in[1], in[2]); + *out++ = ImageHelpers::RGBToPalette(alphatex, in[0], in[1], in[2]); } in += pitch; } @@ -518,7 +425,7 @@ uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) { for (y = Height; y > 0; --y) { - *out++ = RGBToPalette(alphatex, in[0], in[1], in[2], in[3]); + *out++ = ImageHelpers::RGBToPalette(alphatex, in[0], in[1], in[2], in[3]); in += pitch; } in -= backstep; @@ -533,11 +440,11 @@ uint8_t *FPNGTexture::MakeTexture (FRenderStyle style) //=========================================================================== // -// FPNGTexture::CopyTrueColorPixels +// FPNGTexture::CopyPixels // //=========================================================================== -int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion) { // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? PalEntry pe[256]; @@ -549,15 +456,8 @@ int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo FileReader *lump; FileReader lfr; - if (SourceLump >= 0) - { - lfr = Wads.OpenLumpReader(SourceLump); - lump = 𝔩 - } - else - { - lump = &fr; - } + lfr = Wads.OpenLumpReader(SourceLump); + lump = 𝔩 lump->Seek(33, FileReader::SeekSet); for(int i = 0; i < 256; i++) // default to a gray map @@ -622,29 +522,29 @@ int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo { case 0: case 3: - bmp->CopyPixelData(x, y, Pixels, Width, Height, 1, Width, rotate, pe, inf); + bmp->CopyPixelData(0, 0, Pixels, Width, Height, 1, Width, 0, pe); break; case 2: if (!HaveTrans) { - bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 3, pixwidth, rotate, CF_RGB, inf); + bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 3, pixwidth, 0, CF_RGB); } else { - bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 3, pixwidth, rotate, CF_RGBT, inf, + bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 3, pixwidth, 0, CF_RGBT, nullptr, NonPaletteTrans[0], NonPaletteTrans[1], NonPaletteTrans[2]); transpal = true; } break; case 4: - bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 2, pixwidth, rotate, CF_IA, inf); + bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 2, pixwidth, 0, CF_IA); transpal = -1; break; case 6: - bmp->CopyPixelDataRGB(x, y, Pixels, Width, Height, 4, pixwidth, rotate, CF_RGBA, inf); + bmp->CopyPixelDataRGB(0, 0, Pixels, Width, Height, 4, pixwidth, 0, CF_RGBA); transpal = -1; break; @@ -657,15 +557,129 @@ int FPNGTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo } + +//========================================================================== +// +// A savegame picture +// This is essentially a stripped down version of the PNG texture +// only supporting the features actually present in a savegame +// that does not use an image source, because image sources are not +// meant to be transient data like the savegame picture. +// +//========================================================================== + +class FPNGFileTexture : public FTexture +{ +public: + FPNGFileTexture (FileReader &lump, int width, int height, uint8_t colortype); + virtual FBitmap GetBgraBitmap(PalEntry *remap, int *trans); + +protected: + + FileReader fr; + uint8_t ColorType; + int PaletteSize; +}; + + +//========================================================================== +// +// +// +//========================================================================== + +FTexture *PNGTexture_CreateFromFile(PNGHandle *png, const FString &filename) +{ + if (M_FindPNGChunk(png, MAKE_ID('I','H','D','R')) == 0) + { + return nullptr; + } + + // Savegame images can only be either 8 bit paletted or 24 bit RGB + auto &data = png->File; + int width = data.ReadInt32BE(); + int height = data.ReadInt32BE(); + uint8_t bitdepth = data.ReadUInt8(); + uint8_t colortype = data.ReadUInt8(); + uint8_t compression = data.ReadUInt8(); + uint8_t filter = data.ReadUInt8(); + uint8_t interlace = data.ReadUInt8(); + + // Reject anything that cannot be put into a savegame picture by GZDoom itself. + if (compression != 0 || filter != 0 || interlace > 0 || bitdepth != 8 || (colortype != 2 && colortype != 3)) return nullptr; + else return new FPNGFileTexture (png->File, width, height, colortype); +} + +//========================================================================== +// +// +// +//========================================================================== + +FPNGFileTexture::FPNGFileTexture (FileReader &lump, int width, int height, uint8_t colortype) +: ColorType(colortype) +{ + Width = width; + Height = height; + fr = std::move(lump); +} + //=========================================================================== // -// This doesn't check if the palette is identical with the base palette -// I don't think it's worth the hassle because it's only of importance -// when compositing multipatch textures. +// FPNGTexture::CopyPixels // //=========================================================================== -bool FPNGTexture::UseBasePalette() -{ - return false; +FBitmap FPNGFileTexture::GetBgraBitmap(PalEntry *remap, int *trans) +{ + FBitmap bmp; + // Parse pre-IDAT chunks. I skip the CRCs. Is that bad? + PalEntry pe[256]; + uint32_t len, id; + int pixwidth = Width * (ColorType == 2? 3:1); + + FileReader *lump = &fr; + + bmp.Create(Width, Height); + lump->Seek(33, FileReader::SeekSet); + lump->Read(&len, 4); + lump->Read(&id, 4); + while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D')) + { + len = BigLong((unsigned int)len); + if (id != MAKE_ID('P','L','T','E')) + lump->Seek (len, FileReader::SeekCur); + else + { + PaletteSize = MIN (len / 3, 256); + for(int i = 0; i < PaletteSize; i++) + { + pe[i].r = lump->ReadUInt8(); + pe[i].g = lump->ReadUInt8(); + pe[i].b = lump->ReadUInt8(); + } + } + lump->Seek(4, FileReader::SeekCur); // Skip CRC + lump->Read(&len, 4); + id = MAKE_ID('I','E','N','D'); + lump->Read(&id, 4); + } + auto StartOfIDAT = (uint32_t)lump->Tell() - 8; + + TArray Pixels(pixwidth * Height); + + lump->Seek (StartOfIDAT, FileReader::SeekSet); + lump->Read(&len, 4); + lump->Read(&id, 4); + M_ReadIDAT (*lump, Pixels.Data(), Width, Height, pixwidth, 8, ColorType, 0, BigLong((unsigned int)len)); + + if (ColorType == 3) + { + bmp.CopyPixelData(0, 0, Pixels.Data(), Width, Height, 1, Width, 0, pe); + } + else + { + bmp.CopyPixelDataRGB(0, 0, Pixels.Data(), Width, Height, 3, pixwidth, 0, CF_RGB); + } + return bmp; } diff --git a/src/textures/formats/rawpagetexture.cpp b/src/textures/formats/rawpagetexture.cpp index 0d42544fe..3cc136dfc 100644 --- a/src/textures/formats/rawpagetexture.cpp +++ b/src/textures/formats/rawpagetexture.cpp @@ -39,6 +39,8 @@ #include "gi.h" #include "bitmap.h" #include "textures/textures.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== @@ -47,13 +49,13 @@ // //========================================================================== -class FRawPageTexture : public FWorldTexture +class FRawPageTexture : public FImageSource { int mPaletteLump = -1; public: FRawPageTexture (int lumpnum); - uint8_t *MakeTexture (FRenderStyle style) override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) override; + TArray CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; }; //========================================================================== @@ -72,9 +74,9 @@ static bool CheckIfRaw(FileReader & data) int height; int width; - foo = (patch_t *)M_Malloc (data.GetLength()); - data.Seek (0, FileReader::SeekSet); - data.Read (foo, data.GetLength()); + data.Seek(0, FileReader::SeekSet); + auto bits = data.Read(data.GetLength()); + foo = (patch_t *)bits.Data();; height = LittleShort(foo->height); width = LittleShort(foo->width); @@ -97,7 +99,6 @@ static bool CheckIfRaw(FileReader & data) } else if (ofs >= 64000-1) // Need one byte for an empty column { - M_Free (foo); return true; } else @@ -108,29 +109,24 @@ static bool CheckIfRaw(FileReader & data) { if (foo2[ofs] == 255) { - M_Free (foo); return true; } ofs += foo2[ofs+1] + 4; } if (ofs >= 64000) { - M_Free (foo); return true; } } } if (gapAtStart || (x != width)) { - M_Free (foo); return true; } - M_Free(foo); return false; } else { - M_Free (foo); return true; } } @@ -141,9 +137,9 @@ static bool CheckIfRaw(FileReader & data) // //========================================================================== -FTexture *RawPageTexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *RawPageImage_TryCreate(FileReader & file, int lumpnum) { - if (!CheckIfRaw(file)) return NULL; + if (!CheckIfRaw(file)) return nullptr; return new FRawPageTexture(lumpnum); } @@ -155,20 +151,20 @@ FTexture *RawPageTexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FRawPageTexture::FRawPageTexture (int lumpnum) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { Width = 320; Height = 200; - WidthBits = 8; - HeightBits = 8; - WidthMask = 255; // Special case hack for Heretic's E2 end pic. This is not going to be exposed as an editing feature because the implications would be horrible. + FString Name; + Wads.GetLumpName(Name, lumpnum); if (Name.CompareNoCase("E2END") == 0 && gameinfo.gametype == GAME_Heretic) { mPaletteLump = Wads.CheckNumForName("E2PAL"); if (Wads.LumpLength(mPaletteLump) < 768) mPaletteLump = -1; } + else bUseGamePalette = true; } //========================================================================== @@ -177,17 +173,17 @@ FRawPageTexture::FRawPageTexture (int lumpnum) // //========================================================================== -uint8_t *FRawPageTexture::MakeTexture (FRenderStyle style) +TArray FRawPageTexture::CreatePalettedPixels(int conversion) { FMemLump lump = Wads.ReadLump (SourceLump); const uint8_t *source = (const uint8_t *)lump.GetMem(); const uint8_t *source_p = source; uint8_t *dest_p; - auto Pixels = new uint8_t[Width*Height]; - dest_p = Pixels; + TArray Pixels(Width*Height, true); + dest_p = Pixels.Data(); - const uint8_t *remap = GetRemap(style); + const uint8_t *remap = ImageHelpers::GetRemap(conversion == luminance); // This does not handle the custom palette. // User maps are encouraged to use a real image format when replacing E2END and the original could never be used anywhere else. @@ -206,9 +202,9 @@ uint8_t *FRawPageTexture::MakeTexture (FRenderStyle style) return Pixels; } -int FRawPageTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +int FRawPageTexture::CopyPixels(FBitmap *bmp, int conversion) { - if (mPaletteLump < 0) return FTexture::CopyTrueColorPixels(bmp, x, y, rotate, inf); + if (mPaletteLump < 0) return FImageSource::CopyPixels(bmp, conversion); else { FMemLump lump = Wads.ReadLump(SourceLump); @@ -223,7 +219,7 @@ int FRawPageTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, pe.b = *psource++; pe.a = 255; } - bmp->CopyPixelData(x, y, source, 320, 200, 1, 320, 0, paldata, inf); + bmp->CopyPixelData(0, 0, source, 320, 200, 1, 320, 0, paldata); } return 0; } diff --git a/src/textures/formats/shadertexture.cpp b/src/textures/formats/shadertexture.cpp index 1b1ab5c6f..8f817d9bc 100644 --- a/src/textures/formats/shadertexture.cpp +++ b/src/textures/formats/shadertexture.cpp @@ -39,22 +39,21 @@ #include "menu/menu.h" #include "w_wad.h" #include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" -class FBarShader : public FWorldTexture +class FBarShader : public FImageSource { public: FBarShader(bool vertical, bool reverse) { int i; - Name.Format("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); Width = vertical ? 2 : 256; Height = vertical ? 256 : 2; - CalcBitSize(); bMasked = false; bTranslucent = false; - PixelsAreStatic = 2; // The alpha buffer is static, but if this gets used as a regular texture, a separate buffer needs to be made. // Fill the column/row with shading values. // Vertical shaders have have minimum alpha at the top @@ -101,38 +100,32 @@ public: } } - uint8_t *MakeTexture(FRenderStyle style) override + TArray CreatePalettedPixels(int conversion) override { - if (style.Flags & STYLEF_RedIsAlpha) + TArray Pix(512, true); + if (conversion == luminance) { - return Pixels; + memcpy(Pix.Data(), Pixels, 512); } else { // Since this presents itself to the game as a regular named texture // it can easily be used on walls and flats and should work as such, // even if it makes little sense. - auto Pix = new uint8_t[512]; for (int i = 0; i < 512; i++) { - Pix[i] = GrayMap[Pixels[i]]; + Pix[i] = ImageHelpers::GrayMap[Pixels[i]]; } - return Pix; } + return Pix; } - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override + int CopyPixels(FBitmap *bmp, int conversion) override { - bmp->CopyPixelData(x, y, Pixels, Width, Height, Height, 1, rotate, translationtables[TRANSLATION_Standard][8]->Palette, inf); + bmp->CopyPixelData(0, 0, Pixels, Width, Height, Height, 1, 0, translationtables[TRANSLATION_Standard][8]->Palette); return 0; } - bool UseBasePalette() override - { - return false; - } - - private: uint8_t Pixels[512]; }; @@ -140,5 +133,7 @@ private: FTexture *CreateShaderTexture(bool vertical, bool reverse) { - return new FBarShader(vertical, reverse); + FStringf name("BarShader%c%c", vertical ? 'v' : 'h', reverse ? 'r' : 'f'); + return new FImageTexture(new FBarShader(vertical, reverse), name.GetChars()); + } diff --git a/src/textures/formats/tgatexture.cpp b/src/textures/formats/tgatexture.cpp index 36e0144ab..9936a828e 100644 --- a/src/textures/formats/tgatexture.cpp +++ b/src/textures/formats/tgatexture.cpp @@ -39,6 +39,8 @@ #include "templates.h" #include "bitmap.h" #include "v_video.h" +#include "imagehelpers.h" +#include "image.h" //========================================================================== @@ -74,18 +76,16 @@ struct TGAHeader // //========================================================================== -class FTGATexture : public FWorldTexture +class FTGATexture : public FImageSource { public: FTGATexture (int lumpnum, TGAHeader *); - FTextureFormat GetFormat () override; - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL) override; - bool UseBasePalette() override; + int CopyPixels(FBitmap *bmp, int conversion) override; protected: void ReadCompressed(FileReader &lump, uint8_t * buffer, int bytesperpixel); - uint8_t *MakeTexture (FRenderStyle style) override; + TArray CreatePalettedPixels(int conversion) override; }; //========================================================================== @@ -94,7 +94,7 @@ protected: // //========================================================================== -FTexture *TGATexture_TryCreate(FileReader & file, int lumpnum) +FImageSource *TGAImage_TryCreate(FileReader & file, int lumpnum) { TGAHeader hdr; @@ -129,25 +129,12 @@ FTexture *TGATexture_TryCreate(FileReader & file, int lumpnum) //========================================================================== FTGATexture::FTGATexture (int lumpnum, TGAHeader * hdr) -: FWorldTexture(NULL, lumpnum) +: FImageSource(lumpnum) { - Wads.GetLumpName (Name, lumpnum); Width = hdr->width; Height = hdr->height; // Alpha channel is used only for 32 bit RGBA and paletted images with RGBA palettes. bMasked = (hdr->img_desc&15)==8 && (hdr->bpp==32 || (hdr->img_type==1 && hdr->cm_size==32)); - CalcBitSize(); -} - -//========================================================================== -// -// -// -//========================================================================== - -FTextureFormat FTGATexture::GetFormat() -{ - return TEX_RGB; } //========================================================================== @@ -192,17 +179,15 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe // //========================================================================== -uint8_t *FTGATexture::MakeTexture (FRenderStyle style) +TArray FTGATexture::CreatePalettedPixels(int conversion) { uint8_t PaletteMap[256]; auto lump = Wads.OpenLumpReader (SourceLump); TGAHeader hdr; uint16_t w; uint8_t r,g,b,a; - uint8_t * buffer; - bool alphatex = !!(style.Flags & STYLEF_RedIsAlpha); - auto Pixels = new uint8_t[Width*Height]; + TArray Pixels(Width*Height, true); lump.Read(&hdr, sizeof(hdr)); lump.Seek(hdr.id_len, FileReader::SeekCur); @@ -246,23 +231,23 @@ uint8_t *FTGATexture::MakeTexture (FRenderStyle style) r=g=b=a=0; break; } - PaletteMap[i] = RGBToPalettePrecise(alphatex, r, g, b, a); + PaletteMap[i] = ImageHelpers::RGBToPalettePrecise(conversion == luminance, r, g, b, a); } } int Size = Width * Height * (hdr.bpp>>3); - buffer = new uint8_t[Size]; + TArray buffer(Size, true); if (hdr.img_type < 4) // uncompressed { - lump.Read(buffer, Size); + lump.Read(buffer.Data(), Size); } else // compressed { - ReadCompressed(lump, buffer, hdr.bpp>>3); + ReadCompressed(lump, buffer.Data(), hdr.bpp>>3); } - uint8_t * ptr = buffer; + uint8_t * ptr = buffer.Data(); int step_x = (hdr.bpp>>3); int Pitch = Width * step_x; @@ -305,7 +290,7 @@ uint8_t *FTGATexture::MakeTexture (FRenderStyle style) for(int x=0;x> 10) & 0x1f) * 8, ((v >> 5) & 0x1f) * 8, (v & 0x1f) * 8); + Pixels[x*Height + y] = ImageHelpers::RGBToPalette(conversion == luminance, ((v >> 10) & 0x1f) * 8, ((v >> 5) & 0x1f) * 8, (v & 0x1f) * 8); p+=step_x; } } @@ -317,7 +302,7 @@ uint8_t *FTGATexture::MakeTexture (FRenderStyle style) uint8_t * p = ptr + y * Pitch; for(int x=0;x>3); - sbuffer = new uint8_t[Size]; + TArray sbuffer(Size); if (hdr.img_type < 4) // uncompressed { - lump.Read(sbuffer, Size); + lump.Read(sbuffer.Data(), Size); } else // compressed { - ReadCompressed(lump, sbuffer, hdr.bpp>>3); + ReadCompressed(lump, sbuffer.Data(), hdr.bpp>>3); } - uint8_t * ptr = sbuffer; + uint8_t * ptr = sbuffer.Data(); int step_x = (hdr.bpp>>3); int Pitch = Width * step_x; @@ -492,7 +475,7 @@ int FTGATexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo switch (hdr.img_type & 7) { case 1: // paletted - bmp->CopyPixelData(x, y, ptr, Width, Height, step_x, Pitch, rotate, pe, inf); + bmp->CopyPixelData(0, 0, ptr, Width, Height, step_x, Pitch, 0, pe); break; case 2: // RGB @@ -500,21 +483,21 @@ int FTGATexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo { case 15: case 16: - bmp->CopyPixelDataRGB(x, y, ptr, Width, Height, step_x, Pitch, rotate, CF_RGB555, inf); + bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_RGB555); break; case 24: - bmp->CopyPixelDataRGB(x, y, ptr, Width, Height, step_x, Pitch, rotate, CF_BGR, inf); + bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGR); break; case 32: if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel { - bmp->CopyPixelDataRGB(x, y, ptr, Width, Height, step_x, Pitch, rotate, CF_BGR, inf); + bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_BGR); } else { - bmp->CopyPixelDataRGB(x, y, ptr, Width, Height, step_x, Pitch, rotate, CF_BGRA, inf); + bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 9, CF_BGRA); transval = -1; } break; @@ -529,11 +512,11 @@ int FTGATexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo { case 8: for(int i=0;i<256;i++) pe[i]=PalEntry(255,i,i,i); // gray map - bmp->CopyPixelData(x, y, ptr, Width, Height, step_x, Pitch, rotate, pe, inf); + bmp->CopyPixelData(0, 0, ptr, Width, Height, step_x, Pitch, 0, pe); break; case 16: - bmp->CopyPixelDataRGB(x, y, ptr, Width, Height, step_x, Pitch, rotate, CF_I16, inf); + bmp->CopyPixelDataRGB(0, 0, ptr, Width, Height, step_x, Pitch, 0, CF_I16); break; default: @@ -544,16 +527,5 @@ int FTGATexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCo default: break; } - delete [] sbuffer; return transval; } - -//=========================================================================== -// -// -//=========================================================================== - -bool FTGATexture::UseBasePalette() -{ - return false; -} diff --git a/src/textures/hires/hirestex.cpp b/src/textures/hires/hirestex.cpp index dae7654a0..3ba988eda 100644 --- a/src/textures/hires/hirestex.cpp +++ b/src/textures/hires/hirestex.cpp @@ -36,6 +36,7 @@ #include "gi.h" #include "cmdlib.h" #include "bitmap.h" +#include "image.h" #ifndef _WIN32 #define _access(a,b) access(a,b) @@ -357,7 +358,7 @@ int FTexture::CheckExternalFile(bool & hascolorkey) // //========================================================================== -unsigned char *FTexture::LoadHiresTexture(int *width, int *height) +bool FTexture::LoadHiresTexture(FTextureBuffer &texbuffer, bool checkonly) { if (HiresLump == -1) { @@ -367,8 +368,7 @@ unsigned char *FTexture::LoadHiresTexture(int *width, int *height) if (HiresLump >= 0) { - HiresTexture = FTexture::CreateTexture(HiresLump, ETextureType::Any); - HiresTexture->Name = ""; + HiresTexture = FTexture::CreateTexture("", HiresLump, ETextureType::Any); TexMan.AddTexture(HiresTexture); // let the texture manager manage this. } } @@ -377,28 +377,38 @@ unsigned char *FTexture::LoadHiresTexture(int *width, int *height) int w = HiresTexture->GetWidth(); int h = HiresTexture->GetHeight(); - unsigned char * buffer = new unsigned char[w*(h + 1) * 4]; - memset(buffer, 0, w * (h + 1) * 4); - - FBitmap bmp(buffer, w * 4, w, h); - - int trans = HiresTexture->CopyTrueColorPixels(&bmp, 0, 0); - HiresTexture->CheckTrans(buffer, w*h, trans); - - if (bHiresHasColorKey) + if (!checkonly) { - // This is a crappy Doomsday color keyed image - // We have to remove the key manually. :( - uint32_t * dwdata = (uint32_t*)buffer; - for (int i = (w*h); i>0; i--) + unsigned char * buffer = new unsigned char[w*(h + 1) * 4]; + memset(buffer, 0, w * (h + 1) * 4); + + FBitmap bmp(buffer, w * 4, w, h); + int trans; + auto Pixels = HiresTexture->GetBgraBitmap(nullptr, &trans); + bmp.Blit(0, 0, Pixels); + + HiresTexture->CheckTrans(buffer, w*h, trans); + + if (bHiresHasColorKey) { - if (dwdata[i] == 0xffffff00 || dwdata[i] == 0xffff00ff) dwdata[i] = 0; + // This is a crappy Doomsday color keyed image + // We have to remove the key manually. :( + uint32_t * dwdata = (uint32_t*)buffer; + for (int i = (w*h); i > 0; i--) + { + if (dwdata[i] == 0xffffff00 || dwdata[i] == 0xffff00ff) dwdata[i] = 0; + } } + texbuffer.mBuffer = buffer; } - *width = w; - *height = h; - return buffer; + FContentIdBuilder contentId; + contentId.id = 0; + contentId.imageID = HiresTexture->GetImage()->GetId(); + texbuffer.mWidth = w; + texbuffer.mHeight = h; + texbuffer.mContentId = contentId.id; + return true; } - return nullptr; + return false; } diff --git a/src/textures/hires/hqresize.cpp b/src/textures/hires/hqresize.cpp index 01f310ed2..82a4d8817 100644 --- a/src/textures/hires/hqresize.cpp +++ b/src/textures/hires/hqresize.cpp @@ -45,30 +45,34 @@ #include "parallel_for.h" #include "hwrenderer/textures/hw_material.h" -CUSTOM_CVAR(Int, gl_texture_hqresize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +EXTERN_CVAR(Int, gl_texture_hqresizemult) +CUSTOM_CVAR(Int, gl_texture_hqresizemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { - if (self < 0 || self > 24) - { + if (self < 0 || self > 6) self = 0; - } - #ifndef HAVE_MMX - // This is to allow the menu option to work properly so that these filters can be skipped while cycling through them. - if (self == 7) self = 10; - if (self == 8) self = 10; - if (self == 9) self = 6; - #endif - FMaterial::FlushAll(); + if ((gl_texture_hqresizemult > 4) && (self < 4) && (self > 0)) + gl_texture_hqresizemult = 4; + TexMan.FlushAll(); +} + +CUSTOM_CVAR(Int, gl_texture_hqresizemult, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (self < 1 || self > 6) + self = 1; + if ((self > 4) && (gl_texture_hqresizemode < 4) && (gl_texture_hqresizemode > 0)) + self = 4; + TexMan.FlushAll(); } CUSTOM_CVAR(Int, gl_texture_hqresize_maxinputsize, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { if (self > 1024) self = 1024; - FMaterial::FlushAll(); + TexMan.FlushAll(); } CUSTOM_CVAR(Int, gl_texture_hqresize_targets, 7, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { - FMaterial::FlushAll(); + TexMan.FlushAll(); } CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); @@ -344,106 +348,110 @@ static void xbrzOldScale(size_t factor, const uint32_t* src, uint32_t* trg, int //=========================================================================== // -// [BB] Upsamples the texture in inputBuffer, frees inputBuffer and returns +// [BB] Upsamples the texture in texbuffer.mBuffer, frees texbuffer.mBuffer and returns // the upsampled buffer. // //=========================================================================== -unsigned char *FTexture::CreateUpsampledTextureBuffer (unsigned char *inputBuffer, const int inWidth, const int inHeight, int &outWidth, int &outHeight, bool hasAlpha ) +void FTexture::CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly) { - // [BB] Make sure that outWidth and outHeight denote the size of + // [BB] Make sure that inWidth and inHeight denote the size of // the returned buffer even if we don't upsample the input buffer. - outWidth = inWidth; - outHeight = inHeight; + int inWidth = texbuffer.mWidth; + int inHeight = texbuffer.mHeight; // [BB] Don't resample if the width or height of the input texture is bigger than gl_texture_hqresize_maxinputsize. - if ( ( inWidth > gl_texture_hqresize_maxinputsize ) || ( inHeight > gl_texture_hqresize_maxinputsize ) ) - return inputBuffer; + if ((inWidth > gl_texture_hqresize_maxinputsize) || (inHeight > gl_texture_hqresize_maxinputsize)) + return; - // [BB] Don't try to upsample textures based off FCanvasTexture. - if ( bHasCanvas ) - return inputBuffer; + // [BB] Don't try to upsample textures based off FCanvasTexture. (This should never get here in the first place!) + if (bHasCanvas) + return; // already scaled? if (Scale.X >= 2 && Scale.Y >= 2) - return inputBuffer; + return; switch (UseType) { case ETextureType::Sprite: case ETextureType::SkinSprite: - if (!(gl_texture_hqresize_targets & 2)) return inputBuffer; + if (!(gl_texture_hqresize_targets & 2)) return; break; case ETextureType::FontChar: - if (!(gl_texture_hqresize_targets & 4)) return inputBuffer; + if (!(gl_texture_hqresize_targets & 4)) return; break; default: - if (!(gl_texture_hqresize_targets & 1)) return inputBuffer; + if (!(gl_texture_hqresize_targets & 1)) return; break; } - if (inputBuffer) + int type = gl_texture_hqresizemode; + int mult = gl_texture_hqresizemult; +#ifdef HAVE_MMX + // hqNx MMX does not preserve the alpha channel so fall back to C-version for such textures + if (hasAlpha && type == 3) { - int type = gl_texture_hqresize; - outWidth = inWidth; - outHeight = inHeight; -#ifdef HAVE_MMX - // hqNx MMX does not preserve the alpha channel so fall back to C-version for such textures - if (hasAlpha && type > 6 && type <= 9) - { - type -= 3; - } -#endif - - switch (type) - { - case 1: - return scaleNxHelper( &scale2x, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 2: - return scaleNxHelper( &scale3x, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 3: - return scaleNxHelper( &scale4x, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 4: - return hqNxHelper( &hq2x_32, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 5: - return hqNxHelper( &hq3x_32, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 6: - return hqNxHelper( &hq4x_32, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight ); -#ifdef HAVE_MMX - case 7: - return hqNxAsmHelper( &HQnX_asm::hq2x_32, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 8: - return hqNxAsmHelper( &HQnX_asm::hq3x_32, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 9: - return hqNxAsmHelper( &HQnX_asm::hq4x_32, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight ); -#endif - case 10: - case 11: - case 12: - return xbrzHelper(xbrz::scale, type - 8, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - - case 13: - case 14: - case 15: - case 16: - case 17: - return xbrzHelper(xbrzOldScale, type - 11, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - - case 18: - case 19: - return xbrzHelper(xbrz::scale, type - 13, inputBuffer, inWidth, inHeight, outWidth, outHeight); - case 20: - return normalNxHelper( &normalNx, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 21: - return normalNxHelper( &normalNx, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 22: - return normalNxHelper( &normalNx, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 23: - return normalNxHelper( &normalNx, 5, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - case 24: - return normalNxHelper( &normalNx, 6, inputBuffer, inWidth, inHeight, outWidth, outHeight ); - } + type = 2; } - return inputBuffer; +#endif + // These checks are to ensure consistency of the content ID. + if (mult < 2 || mult > 6 || type < 1 || type > 6) return; + if (type < 4 && mult > 4) mult = 4; + + if (!checkonly) + { + if (type == 1) + { + if (mult == 2) + texbuffer.mBuffer = scaleNxHelper(&scale2x, 2, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 3) + texbuffer.mBuffer = scaleNxHelper(&scale3x, 3, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 4) + texbuffer.mBuffer = scaleNxHelper(&scale4x, 4, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else return; + } + else if (type == 2) + { + if (mult == 2) + texbuffer.mBuffer = hqNxHelper(&hq2x_32, 2, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 3) + texbuffer.mBuffer = hqNxHelper(&hq3x_32, 3, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 4) + texbuffer.mBuffer = hqNxHelper(&hq4x_32, 4, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else return; + } +#ifdef HAVE_MMX + else if (type == 3) + { + if (mult == 2) + texbuffer.mBuffer = hqNxAsmHelper(&HQnX_asm::hq2x_32, 2, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 3) + texbuffer.mBuffer = hqNxAsmHelper(&HQnX_asm::hq3x_32, 3, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (mult == 4) + texbuffer.mBuffer = hqNxAsmHelper(&HQnX_asm::hq4x_32, 4, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else return; + } +#endif + else if (type == 4) + texbuffer.mBuffer = xbrzHelper(xbrz::scale, mult, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (type == 5) + texbuffer.mBuffer = xbrzHelper(xbrzOldScale, mult, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else if (type == 6) + texbuffer.mBuffer = normalNxHelper(&normalNx, mult, texbuffer.mBuffer, inWidth, inHeight, texbuffer.mWidth, texbuffer.mHeight); + else + return; + } + else + { + texbuffer.mWidth *= mult; + texbuffer.mHeight *= mult; + } + // Encode the scaling method in the content ID. + FContentIdBuilder contentId; + contentId.id = texbuffer.mContentId; + contentId.scaler = type; + contentId.scalefactor = mult; + texbuffer.mContentId = contentId.id; } diff --git a/src/textures/image.cpp b/src/textures/image.cpp new file mode 100644 index 000000000..f047b8137 --- /dev/null +++ b/src/textures/image.cpp @@ -0,0 +1,386 @@ +/* +** texture.cpp +** The base texture class +** +**--------------------------------------------------------------------------- +** Copyright 2004-2007 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "v_video.h" +#include "bitmap.h" +#include "image.h" +#include "w_wad.h" +#include "files.h" + +FMemArena FImageSource::ImageArena(32768); +TArrayFImageSource::ImageForLump; +int FImageSource::NextID; +static PrecacheInfo precacheInfo; + +struct PrecacheDataPaletted +{ + TArray Pixels; + int RefCount; + int ImageID; +}; + +struct PrecacheDataRgba +{ + FBitmap Pixels; + int TransInfo; + int RefCount; + int ImageID; +}; + +// TMap doesn't handle this kind of data well. std::map neither. The linear search is still faster, even for a few 100 entries because it doesn't have to access the heap as often.. +TArray precacheDataPaletted; +TArray precacheDataRgba; + +//=========================================================================== +// +// the default just returns an empty texture. +// +//=========================================================================== + +TArray FImageSource::CreatePalettedPixels(int conversion) +{ + TArray Pixels(Width * Height, true); + memset(Pixels.Data(), 0, Width * Height); + return Pixels; +} + +PalettedPixels FImageSource::GetCachedPalettedPixels(int conversion) +{ + PalettedPixels ret; + + FString name; + Wads.GetLumpName(name, SourceLump); + + std::pair *info = nullptr; + auto imageID = ImageID; + + // Do we have this image in the cache? + unsigned index = conversion != normal? UINT_MAX : precacheDataPaletted.FindEx([=](PrecacheDataPaletted &entry) { return entry.ImageID == imageID; }); + if (index < precacheDataPaletted.Size()) + { + auto cache = &precacheDataPaletted[index]; + + if (cache->RefCount > 1) + { + //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Pixels.Set(cache->Pixels.Data(), cache->Pixels.Size()); + cache->RefCount--; + } + else if (cache->Pixels.Size() > 0) + { + //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.PixelStore = std::move(cache->Pixels); + ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size()); + precacheDataPaletted.Delete(index); + } + else + { + //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); + } + } + else + { + // The image wasn't cached. Now there's two possibilities: + auto info = precacheInfo.CheckKey(ImageID); + if (!info || info->second <= 1 || conversion != normal) + { + // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. + //Printf("returning fresh copy of %s\n", name.GetChars()); + ret.PixelStore = CreatePalettedPixels(conversion); + ret.Pixels.Set(ret.PixelStore.Data(), ret.PixelStore.Size()); + } + else + { + //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->second); + // This is the first time it gets accessed and needs to be placed in the cache. + PrecacheDataPaletted *pdp = &precacheDataPaletted[precacheDataPaletted.Reserve(1)]; + + pdp->ImageID = imageID; + pdp->RefCount = info->second - 1; + info->second = 0; + pdp->Pixels = CreatePalettedPixels(normal); + ret.Pixels.Set(pdp->Pixels.Data(), pdp->Pixels.Size()); + } + } + return ret; +} + +TArray FImageSource::GetPalettedPixels(int conversion) +{ + auto pix = GetCachedPalettedPixels(conversion); + if (pix.ownsPixels()) + { + // return the pixel store of the returned data directly if this was the last reference. + auto array = std::move(pix.PixelStore); + return array; + } + else + { + // If there are pending references, make a copy. + TArray array(pix.Pixels.Size(), true); + memcpy(array.Data(), pix.Pixels.Data(), array.Size()); + return array; + } +} + + + +//=========================================================================== +// +// FImageSource::CopyPixels +// +// this is the generic case that can handle +// any properly implemented texture for software rendering. +// Its drawback is that it is limited to the base palette which is +// why all classes that handle different palettes should subclass this +// method +// +//=========================================================================== + +int FImageSource::CopyPixels(FBitmap *bmp, int conversion) +{ + if (conversion == luminance) conversion = normal; // luminance images have no use as an RGB source. + PalEntry *palette = screen->GetPalette(); + for(int i=1;i<256;i++) palette[i].a = 255; // set proper alpha values + auto ppix = CreatePalettedPixels(conversion); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, palette, nullptr); + for(int i=1;i<256;i++) palette[i].a = 0; + return 0; +} + +int FImageSource::CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap) +{ + auto ppix = CreatePalettedPixels(false); + bmp->CopyPixelData(0, 0, ppix.Data(), Width, Height, Height, 1, 0, remap, nullptr); + return 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +FBitmap FImageSource::GetCachedBitmap(PalEntry *remap, int conversion, int *ptrans) +{ + FBitmap ret; + + FString name; + int trans = -1; + Wads.GetLumpName(name, SourceLump); + + std::pair *info = nullptr; + auto imageID = ImageID; + + if (remap != nullptr) + { + // Remapped images are never run through the cache because they would complicate matters too much for very little gain. + // Translated images are normally sprites which normally just consist of a single image and use no composition. + // Additionally, since translation requires the base palette, the really time consuming stuff will never be subjected to it. + ret.Create(Width, Height); + trans = CopyTranslatedPixels(&ret, remap); + } + else + { + if (conversion == luminance) conversion = normal; // luminance has no meaning for true color. + // Do we have this image in the cache? + unsigned index = conversion != normal? UINT_MAX : precacheDataRgba.FindEx([=](PrecacheDataRgba &entry) { return entry.ImageID == imageID; }); + if (index < precacheDataRgba.Size()) + { + auto cache = &precacheDataRgba[index]; + + trans = cache->TransInfo; + if (cache->RefCount > 1) + { + //Printf("returning reference to %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Copy(cache->Pixels, false); + cache->RefCount--; + } + else if (cache->Pixels.GetPixels()) + { + //Printf("returning contents of %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret = std::move(cache->Pixels); + precacheDataRgba.Delete(index); + } + else + { + // This should never happen if the function is implemented correctly + //Printf("something bad happened for %s, refcount = %d\n", name.GetChars(), cache->RefCount); + ret.Create(Width, Height); + trans = CopyPixels(&ret, normal); + } + } + else + { + // The image wasn't cached. Now there's two possibilities: + auto info = precacheInfo.CheckKey(ImageID); + if (!info || info->first <= 1 || conversion != normal) + { + // This is either the only copy needed or some access outside the caching block. In these cases create a new one and directly return it. + //Printf("returning fresh copy of %s\n", name.GetChars()); + ret.Create(Width, Height); + trans = CopyPixels(&ret, conversion); + } + else + { + //Printf("creating cached entry for %s, refcount = %d\n", name.GetChars(), info->first); + // This is the first time it gets accessed and needs to be placed in the cache. + PrecacheDataRgba *pdr = &precacheDataRgba[precacheDataRgba.Reserve(1)]; + + pdr->ImageID = imageID; + pdr->RefCount = info->first - 1; + info->first = 0; + pdr->Pixels.Create(Width, Height); + trans = pdr->TransInfo = CopyPixels(&pdr->Pixels, normal); + ret.Copy(pdr->Pixels, false); + } + } + } + if (ptrans) *ptrans = trans; + return ret; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FImageSource::CollectForPrecache(PrecacheInfo &info, bool requiretruecolor) +{ + auto val = info.CheckKey(ImageID); + bool tc = requiretruecolor || V_IsTrueColor(); + if (val) + { + val->first += tc; + val->second += !tc; + } + else + { + auto pair = std::make_pair(tc, !tc); + info.Insert(ImageID, pair); + } +} + +void FImageSource::BeginPrecaching() +{ + precacheInfo.Clear(); +} + +void FImageSource::EndPrecaching() +{ + precacheDataPaletted.Clear(); + precacheDataRgba.Clear(); +} + +void FImageSource::RegisterForPrecache(FImageSource *img) +{ + img->CollectForPrecache(precacheInfo); +} + +//========================================================================== +// +// +// +//========================================================================== + +typedef FImageSource * (*CreateFunc)(FileReader & file, int lumpnum); + +struct TexCreateInfo +{ + CreateFunc TryCreate; + ETextureType usetype; +}; + +FImageSource *IMGZImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PNGImage_TryCreate(FileReader &, int lumpnum); +FImageSource *JPEGImage_TryCreate(FileReader &, int lumpnum); +FImageSource *DDSImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); +FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); +FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); +FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); +FImageSource *PatchImage_TryCreate(FileReader &, int lumpnum); +FImageSource *EmptyImage_TryCreate(FileReader &, int lumpnum); +FImageSource *AutomapImage_TryCreate(FileReader &, int lumpnum); + + +// Examines the lump contents to decide what type of texture to create, +// and creates the texture. +FImageSource * FImageSource::GetImage(int lumpnum, ETextureType usetype) +{ + static TexCreateInfo CreateInfo[] = { + { IMGZImage_TryCreate, ETextureType::Any }, + { PNGImage_TryCreate, ETextureType::Any }, + { JPEGImage_TryCreate, ETextureType::Any }, + { DDSImage_TryCreate, ETextureType::Any }, + { PCXImage_TryCreate, ETextureType::Any }, + { TGAImage_TryCreate, ETextureType::Any }, + { RawPageImage_TryCreate, ETextureType::MiscPatch }, + { FlatImage_TryCreate, ETextureType::Flat }, + { PatchImage_TryCreate, ETextureType::Any }, + { EmptyImage_TryCreate, ETextureType::Any }, + { AutomapImage_TryCreate, ETextureType::MiscPatch }, + }; + + if (lumpnum == -1) return nullptr; + + unsigned size = ImageForLump.Size(); + if (size <= (unsigned)lumpnum) + { + // Hires textures can be added dynamically to the end of the lump array, so this must be checked each time. + ImageForLump.Resize(lumpnum + 1); + for (; size < ImageForLump.Size(); size++) ImageForLump[size] = nullptr; + } + // An image for this lump already exists. We do not need another one. + if (ImageForLump[lumpnum] != nullptr) return ImageForLump[lumpnum]; + + auto data = Wads.OpenLumpReader(lumpnum); + + for (size_t i = 0; i < countof(CreateInfo); i++) + { + if ((CreateInfo[i].usetype == usetype || CreateInfo[i].usetype == ETextureType::Any)) + { + auto image = CreateInfo[i].TryCreate(data, lumpnum); + if (image != nullptr) + { + ImageForLump[lumpnum] = image; + return image; + } + } + } + return nullptr; +} diff --git a/src/textures/image.h b/src/textures/image.h new file mode 100644 index 000000000..7e0db353f --- /dev/null +++ b/src/textures/image.h @@ -0,0 +1,155 @@ +#pragma once + +#include +#include "tarray.h" +#include "textures/bitmap.h" +#include "memarena.h" + +class FImageSource; +using PrecacheInfo = TMap>; + +struct PalettedPixels +{ + friend class FImageSource; + TArrayView Pixels; +private: + TArray PixelStore; + + bool ownsPixels() const + { + return Pixels.Data() == PixelStore.Data(); + } +}; + +// This represents a naked image. It has no high level logic attached to it. +// All it can do is provide raw image data to its users. +class FImageSource +{ + friend class FBrightmapTexture; +protected: + + static FMemArena ImageArena; + static TArrayImageForLump; + static int NextID; + + int SourceLump; + int Width = 0, Height = 0; + int LeftOffset = 0, TopOffset = 0; // Offsets stored in the image. + bool bUseGamePalette = false; // true if this is an image without its own color set. + int ImageID = -1; + + // Internal image creation functions. All external access should go through the cache interface, + // so that all code can benefit from future improvements to that. + + virtual TArray CreatePalettedPixels(int conversion); + virtual int CopyPixels(FBitmap *bmp, int conversion); // This will always ignore 'luminance'. + int CopyTranslatedPixels(FBitmap *bmp, PalEntry *remap); + + +public: + + void CopySize(FImageSource &other) + { + Width = other.Width; + Height = other.Height; + LeftOffset = other.LeftOffset; + TopOffset = other.TopOffset; + SourceLump = other.SourceLump; + } + + // Images are statically allocated and freed in bulk. None of the subclasses may hold any destructible data. + void *operator new(size_t block) { return ImageArena.Alloc(block); } + void operator delete(void *block) {} + + bool bMasked = true; // Image (might) have holes (Assume true unless proven otherwise!) + int8_t bTranslucent = -1; // Image has pixels with a non-0/1 value. (-1 means the user needs to do a real check) + + int GetId() const { return ImageID; } + + // 'noremap0' will only be looked at by FPatchTexture and forwarded by FMultipatchTexture. + + // Either returns a reference to the cache, or a newly created item. The return of this has to be considered transient. If you need to store the result, use GetPalettedPixels + PalettedPixels GetCachedPalettedPixels(int conversion); + + // tries to get a buffer from the cache. If not available, create a new one. If further references are pending, create a copy. + TArray GetPalettedPixels(int conversion); + + + // Unlile for paletted images there is no variant here that returns a persistent bitmap, because all users have to process the returned image into another format. + FBitmap GetCachedBitmap(PalEntry *remap, int conversion, int *trans = nullptr); + + static void ClearImages() { ImageArena.FreeAll(); ImageForLump.Clear(); NextID = 0; } + static FImageSource * GetImage(int lumpnum, ETextureType usetype); + + + + // Conversion option + enum EType + { + normal = 0, + luminance = 1, + noremap0 = 2 + }; + + FImageSource(int sourcelump = -1) : SourceLump(sourcelump) { ImageID = ++NextID; } + virtual ~FImageSource() {} + + int GetWidth() const + { + return Width; + } + + int GetHeight() const + { + return Height; + } + + std::pair GetSize() const + { + return std::make_pair(Width, Height); + } + + std::pair GetOffsets() const + { + return std::make_pair(LeftOffset, TopOffset); + } + + int LumpNum() const + { + return SourceLump; + } + + bool UseGamePalette() const + { + return bUseGamePalette; + } + + virtual void CollectForPrecache(PrecacheInfo &info, bool requiretruecolor = false); + static void BeginPrecaching(); + static void EndPrecaching(); + static void RegisterForPrecache(FImageSource *img); +}; + +//========================================================================== +// +// a TGA texture +// +//========================================================================== + +class FImageTexture : public FTexture +{ + FImageSource *mImage; +public: + FImageTexture (FImageSource *image, const char *name = nullptr); + virtual TArray Get8BitPixels(bool alphatex); + + void SetImage(FImageSource *img) // This is only for the multipatch texture builder! + { + mImage = img; + } + + FImageSource *GetImage() const override { return mImage; } + FBitmap GetBgraBitmap(PalEntry *p, int *trans) override; + +}; + diff --git a/src/textures/imagehelpers.h b/src/textures/imagehelpers.h new file mode 100644 index 000000000..39cd83e67 --- /dev/null +++ b/src/textures/imagehelpers.h @@ -0,0 +1,154 @@ +#pragma once + +/* + ** imagehelpers.h + ** Utilities for image conversion - mostly 8 bit paletted baggage + ** + **--------------------------------------------------------------------------- + ** Copyright 2004-2007 Randy Heit + ** Copyright 2006-2018 Christoph Oelckers + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + ** + */ + + +#include +#include "tarray.h" +#include "colormatcher.h" +#include "v_palette.h" +#include "textures/bitmap.h" +#include "r_data/renderstyle.h" +#include "r_data/r_translate.h" + +namespace ImageHelpers +{ + extern uint8_t GrayMap[256]; + + // Helpers for creating paletted images. + inline uint8_t *GetRemap(bool wantluminance, bool srcisgrayscale = false) + { + if (wantluminance) + { + return translationtables[TRANSLATION_Standard][srcisgrayscale ? STD_Gray : STD_Grayscale]->Remap; + } + else + { + return srcisgrayscale ? GrayMap : GPalette.Remap; + } + } + + inline uint8_t RGBToPalettePrecise(bool wantluminance, int r, int g, int b, int a = 255) + { + if (wantluminance) + { + return (uint8_t)Luminance(r, g, b) * a / 255; + } + else + { + return ColorMatcher.Pick(r, g, b); + } + } + + inline uint8_t RGBToPalette(bool wantluminance, int r, int g, int b, int a = 255) + { + if (wantluminance) + { + // This is the same formula the OpenGL renderer uses for grayscale textures with an alpha channel. + return (uint8_t)(Luminance(r, g, b) * a / 255); + } + else + { + return a < 128? 0 : RGB256k.RGB[r >> 2][g >> 2][b >> 2]; + } + } + + inline uint8_t RGBToPalette(bool wantluminance, PalEntry pe, bool hasalpha = true) + { + return RGBToPalette(wantluminance, pe.r, pe.g, pe.b, hasalpha? pe.a : 255); + } + + //========================================================================== + // + // Converts a texture between row-major and column-major format + // by flipping it about the X=Y axis. + // + //========================================================================== + + template + void FlipSquareBlock (T *block, int x) + { + for (int i = 0; i < x; ++i) + { + T *corner = block + x*i + i; + int count = x - i; + for (int j = 0; j < count; j++) + { + std::swap(corner[j], corner[j*x]); + } + } + } + + inline void FlipSquareBlockRemap (uint8_t *block, int x, const uint8_t *remap) + { + for (int i = 0; i < x; ++i) + { + uint8_t *corner = block + x*i + i; + int count = x - i; + for (int j = 0; j < count; j++) + { + auto t = remap[corner[j]]; + corner[j] = remap[corner[j*x]]; + corner[j*x] = t; + } + } + } + + template + void FlipNonSquareBlock (T *dst, const T *src, int x, int y, int srcpitch) + { + for (int i = 0; i < x; ++i) + { + for (int j = 0; j < y; ++j) + { + dst[i*y+j] = src[i+j*srcpitch]; + } + } + } + + inline void FlipNonSquareBlockRemap (uint8_t *dst, const uint8_t *src, int x, int y, int srcpitch, const uint8_t *remap) + { + for (int i = 0; i < x; ++i) + { + for (int j = 0; j < y; ++j) + { + dst[i*y+j] = remap[src[i+j*srcpitch]]; + } + } + } + +} diff --git a/src/textures/formats/worldtexture.cpp b/src/textures/imagetexture.cpp similarity index 56% rename from src/textures/formats/worldtexture.cpp rename to src/textures/imagetexture.cpp index db50c7fb4..43adee19a 100644 --- a/src/textures/formats/worldtexture.cpp +++ b/src/textures/imagetexture.cpp @@ -1,6 +1,6 @@ /* -** worldtexture.cpp -** Intermediate class for some common code for several classes +** imagetexture.cpp +** Texture class based on FImageSource ** **--------------------------------------------------------------------------- ** Copyright 2018 Christoph Oelckers @@ -33,7 +33,13 @@ ** */ -#include "textures.h" +#include "doomtype.h" +#include "files.h" +#include "w_wad.h" +#include "templates.h" +#include "bitmap.h" +#include "v_video.h" +#include "image.h" //========================================================================== @@ -42,109 +48,65 @@ // //========================================================================== -FWorldTexture::FWorldTexture(const char *name, int lumpnum) - : FTexture(name, lumpnum) +FImageTexture::FImageTexture(FImageSource *img, const char *name) +: FTexture(name, img? img->LumpNum() : 0) { -} - -//========================================================================== -// -// -// -//========================================================================== - -FWorldTexture::~FWorldTexture() -{ - Unload(); - FreeAllSpans(); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FWorldTexture::FreeAllSpans() -{ - for(int i = 0; i < 2; i++) + mImage = img; + if (img != nullptr) { - if (Spandata[i] != nullptr) - { - FreeSpans (Spandata[i]); - Spandata[i] = nullptr; - } + if (name == nullptr) Wads.GetLumpName(Name, img->LumpNum()); + Width = img->GetWidth(); + Height = img->GetHeight(); + + auto offsets = img->GetOffsets(); + _LeftOffset[1] = _LeftOffset[0] = offsets.first; + _TopOffset[1] = _TopOffset[0] = offsets.second; + + bMasked = img->bMasked; + bTranslucent = img->bTranslucent; } } -//========================================================================== +//=========================================================================== // +// // -// -//========================================================================== +//=========================================================================== -void FWorldTexture::Unload () +FBitmap FImageTexture::GetBgraBitmap(PalEntry *p, int *trans) { - for(int i = 0; i < 2; i++) - { - if (!(PixelsAreStatic & (1 << i))) - { - delete[] Pixeldata[i]; - } - Pixeldata[i] = nullptr; - } - FTexture::Unload(); -} + return mImage->GetCachedBitmap(p, bNoRemap0? FImageSource::noremap0 : FImageSource::normal, trans); +} -//========================================================================== +//=========================================================================== // +// // -// -//========================================================================== +//=========================================================================== -const uint8_t *FWorldTexture::GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out) +TArray FImageTexture::Get8BitPixels(bool alpha) { - int index = !!(style.Flags & STYLEF_RedIsAlpha); - GetPixels(style); - if ((unsigned)column >= (unsigned)Width) - { - if (WidthMask + 1 == Width) - { - column &= WidthMask; - } - else - { - column %= Width; - } - } - if (spans_out != nullptr) - { - if (Spandata[index] == nullptr) - { - Spandata[index] = CreateSpans (Pixeldata[index]); - } - *spans_out = Spandata[index][column]; - } - return Pixeldata[index] + column*Height; -} + return mImage->GetPalettedPixels(alpha? alpha : bNoRemap0 ? FImageSource::noremap0 : FImageSource::normal); +} //========================================================================== // +// FMultiPatchTexture :: GetRawTexture // +// Doom ignored all compositing of mid-sided textures on two-sided lines. +// Since these textures had to be single-patch in Doom, that essentially +// means it ignores their Y offsets. +// +// If this texture is composed of only one patch, return that patch. +// Otherwise, return this texture, since Doom wouldn't have been able to +// draw it anyway. // //========================================================================== -const uint8_t *FWorldTexture::GetPixels (FRenderStyle style) +/* todo: this needs to be reimplemented without assuming that the underlying patch will be usable as-is. +FTexture *FMultiPatchTexture::GetRawTexture() { - if (CheckModified(style)) - { - Unload(); - } - int index = !!(style.Flags & STYLEF_RedIsAlpha); - if (Pixeldata[index] == nullptr) - { - Pixeldata[index] = MakeTexture (style); - } - return Pixeldata[index]; + return NumParts == 1 && UseType == ETextureType::Wall && bMultiPatch == 1 && Scale == Parts->Texture->Scale ? Parts->Texture : this; } +*/ diff --git a/src/textures/multipatchtexturebuilder.cpp b/src/textures/multipatchtexturebuilder.cpp new file mode 100644 index 000000000..2ec06d0e9 --- /dev/null +++ b/src/textures/multipatchtexturebuilder.cpp @@ -0,0 +1,984 @@ +/* +** multipatchtexturebuilder.cpp +** Texture class for standard Doom multipatch textures +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include +#include "doomtype.h" +#include "files.h" +#include "w_wad.h" +#include "i_system.h" +#include "gi.h" +#include "st_start.h" +#include "sc_man.h" +#include "templates.h" +#include "r_data/r_translate.h" +#include "bitmap.h" +#include "colormatcher.h" +#include "v_palette.h" +#include "v_video.h" +#include "v_text.h" +#include "cmdlib.h" +#include "imagehelpers.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "doomerrors.h" + +// On the Alpha, accessing the shorts directly if they aren't aligned on a +// 4-byte boundary causes unaligned access warnings. Why it does this at +// all and only while initing the textures is beyond me. + +#ifdef ALPHA +#define SAFESHORT(s) ((short)(((uint8_t *)&(s))[0] + ((uint8_t *)&(s))[1] * 256)) +#else +#define SAFESHORT(s) LittleShort(s) +#endif + + + +//-------------------------------------------------------------------------- +// +// Data structures for the TEXTUREx lumps +// +//-------------------------------------------------------------------------- + +// +// Each texture is composed of one or more patches, with patches being lumps +// stored in the WAD. The lumps are referenced by number, and patched into +// the rectangular texture space using origin and possibly other attributes. +// +struct mappatch_t +{ + int16_t originx; + int16_t originy; + int16_t patch; + int16_t stepdir; + int16_t colormap; +}; + +// +// A wall texture is a list of patches which are to be combined in a +// predefined order. +// +struct maptexture_t +{ + uint8_t name[8]; + uint16_t Flags; // [RH] Was unused + uint8_t ScaleX; // [RH] Scaling (8 is normal) + uint8_t ScaleY; // [RH] Same as above + int16_t width; + int16_t height; + uint8_t columndirectory[4]; // OBSOLETE + int16_t patchcount; + mappatch_t patches[1]; +}; + +#define MAPTEXF_WORLDPANNING 0x8000 + +// Strife uses versions of the above structures that remove all unused fields + +struct strifemappatch_t +{ + int16_t originx; + int16_t originy; + int16_t patch; +}; + +// +// A wall texture is a list of patches which are to be combined in a +// predefined order. +// +struct strifemaptexture_t +{ + uint8_t name[8]; + uint16_t Flags; // [RH] Was unused + uint8_t ScaleX; // [RH] Scaling (8 is normal) + uint8_t ScaleY; // [RH] Same as above + int16_t width; + int16_t height; + int16_t patchcount; + strifemappatch_t patches[1]; +}; + + +//========================================================================== +// +// In-memory representation of a single PNAMES lump entry +// +//========================================================================== + +struct FPatchLookup +{ + FString Name; +}; + + +void FMultipatchTextureBuilder::MakeTexture(BuildInfo &buildinfo, ETextureType usetype) +{ + FImageTexture *tex = new FImageTexture(nullptr, buildinfo.Name); + tex->SetUseType(usetype); + tex->bMultiPatch = true; + tex->Width = buildinfo.Width; + tex->Height = buildinfo.Height; + tex->_LeftOffset[0] = buildinfo.LeftOffset[0]; + tex->_LeftOffset[1] = buildinfo.LeftOffset[1]; + tex->_TopOffset[0] = buildinfo.TopOffset[0]; + tex->_TopOffset[1] = buildinfo.TopOffset[1]; + tex->Scale = buildinfo.Scale; + tex->bMasked = true; // we do not really know yet. + tex->bTranslucent = -1; + tex->bWorldPanning = buildinfo.bWorldPanning; + tex->bNoDecals = buildinfo.bNoDecals; + tex->SourceLump = buildinfo.DefinitionLump; + buildinfo.tex = tex; + TexMan.AddTexture(tex); +} + +//========================================================================== +// +// The reader for TEXTUREx +// +//========================================================================== + + +//========================================================================== +// +// FMultiPatchTexture :: FMultiPatchTexture +// +//========================================================================== + +void FMultipatchTextureBuilder::BuildTexture(const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum, ETextureType usetype) +{ + BuildInfo &buildinfo = BuiltTextures[BuiltTextures.Reserve(1)]; + + union + { + const maptexture_t *d; + const strifemaptexture_t *s; + } + mtexture; + + union + { + const mappatch_t *d; + const strifemappatch_t *s; + } + mpatch; + + int i; + + mtexture.d = (const maptexture_t *)texdef; + int NumParts; + + if (strife) + { + NumParts = SAFESHORT(mtexture.s->patchcount); + } + else + { + NumParts = SAFESHORT(mtexture.d->patchcount); + } + + if (NumParts < 0) + { + I_Error("Bad texture directory"); + } + + buildinfo.Parts.Resize(NumParts); + buildinfo.Inits.Resize(NumParts); + buildinfo.Width = SAFESHORT(mtexture.d->width); + buildinfo.Height = SAFESHORT(mtexture.d->height); + buildinfo.Name = (char *)mtexture.d->name; + + buildinfo.Scale.X = mtexture.d->ScaleX ? mtexture.d->ScaleX / 8. : 1.; + buildinfo.Scale.Y = mtexture.d->ScaleY ? mtexture.d->ScaleY / 8. : 1.; + + if (mtexture.d->Flags & MAPTEXF_WORLDPANNING) + { + buildinfo.bWorldPanning = true; + } + + if (strife) + { + mpatch.s = &mtexture.s->patches[0]; + } + else + { + mpatch.d = &mtexture.d->patches[0]; + } + + for (i = 0; i < NumParts; ++i) + { + if (unsigned(LittleShort(mpatch.d->patch)) >= unsigned(maxpatchnum)) + { + I_Error("Bad PNAMES and/or texture directory:\n\nPNAMES has %d entries, but\n%s wants to use entry %d.", + maxpatchnum, buildinfo.Name.GetChars(), LittleShort(mpatch.d->patch) + 1); + } + buildinfo.Parts[i].OriginX = LittleShort(mpatch.d->originx); + buildinfo.Parts[i].OriginY = LittleShort(mpatch.d->originy); + buildinfo.Parts[i].Image = nullptr; + buildinfo.Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name; + buildinfo.Inits[i].UseType = ETextureType::WallPatch; + if (strife) + mpatch.s++; + else + mpatch.d++; + } + if (NumParts == 0) + { + Printf("Texture %s is left without any patches\n", buildinfo.Name.GetChars()); + } + + // Insert the incomplete texture right here so that it's in the correct place. + MakeTexture(buildinfo, usetype); + buildinfo.DefinitionLump = deflumpnum; +} + +//========================================================================== +// +// FTextureManager :: AddTexturesLump +// +//========================================================================== + +void FMultipatchTextureBuilder::AddTexturesLump(const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup, bool texture1) +{ + TArray patchlookup; + int i; + uint32_t numpatches; + + if (firstdup == 0) + { + firstdup = (int)TexMan.NumTextures(); + } + + { + auto pnames = Wads.OpenLumpReader(patcheslump); + numpatches = pnames.ReadUInt32(); + + // Check whether the amount of names reported is correct. + if ((signed)numpatches < 0) + { + Printf("Corrupt PNAMES lump found (negative amount of entries reported)\n"); + return; + } + + // Check whether the amount of names reported is correct. + int lumplength = Wads.LumpLength(patcheslump); + if (numpatches > uint32_t((lumplength - 4) / 8)) + { + Printf("PNAMES lump is shorter than required (%u entries reported but only %d bytes (%d entries) long\n", + numpatches, lumplength, (lumplength - 4) / 8); + // Truncate but continue reading. Who knows how many such lumps exist? + numpatches = (lumplength - 4) / 8; + } + + // Catalog the patches these textures use so we know which + // textures they represent. + patchlookup.Resize(numpatches); + for (uint32_t i = 0; i < numpatches; ++i) + { + char pname[9]; + pnames.Read(pname, 8); + pname[8] = '\0'; + patchlookup[i].Name = pname; + } + } + + bool isStrife = false; + const uint32_t *maptex, *directory; + uint32_t maxoff; + int numtextures; + uint32_t offset = 0; // Shut up, GCC! + + maptex = (const uint32_t *)lumpdata; + numtextures = LittleLong(*maptex); + maxoff = lumpsize; + + if (maxoff < uint32_t(numtextures + 1) * 4) + { + Printf("Texture directory is too short\n"); + return; + } + + // Scan the texture lump to decide if it contains Doom or Strife textures + for (i = 0, directory = maptex + 1; i < numtextures; ++i) + { + offset = LittleLong(directory[i]); + if (offset > maxoff) + { + Printf("Bad texture directory\n"); + return; + } + + maptexture_t *tex = (maptexture_t *)((uint8_t *)maptex + offset); + + // There is bizzarely a Doom editing tool that writes to the + // first two elements of columndirectory, so I can't check those. + if (SAFESHORT(tex->patchcount) < 0 || + tex->columndirectory[2] != 0 || + tex->columndirectory[3] != 0) + { + isStrife = true; + break; + } + } + + + // Textures defined earlier in the lump take precedence over those defined later, + // but later TEXTUREx lumps take precedence over earlier ones. + for (i = 1, directory = maptex; i <= numtextures; ++i) + { + if (i == 1 && texture1) + { + // The very first texture is just a dummy. Copy its dimensions to texture 0. + // It still needs to be created in case someone uses it by name. + offset = LittleLong(directory[1]); + const maptexture_t *tex = (const maptexture_t *)((const uint8_t *)maptex + offset); + FTexture *tex0 = TexMan.ByIndex(0); + tex0->SetSize(SAFESHORT(tex->width), SAFESHORT(tex->height)); + } + + offset = LittleLong(directory[i]); + if (offset > maxoff) + { + Printf("Bad texture directory\n"); + return; + } + + // If this texture was defined already in this lump, skip it + // This could cause problems with animations that use the same name for intermediate + // textures. Should I be worried? + int j; + for (j = (int)TexMan.NumTextures() - 1; j >= firstdup; --j) + { + if (strnicmp(TexMan.ByIndex(j)->GetName(), (const char *)maptex + offset, 8) == 0) + break; + } + if (j + 1 == firstdup) + { + BuildTexture((const uint8_t *)maptex + offset, patchlookup.Data(), numpatches, isStrife, deflumpnum, (i == 1 && texture1) ? ETextureType::FirstDefined : ETextureType::Wall); + StartScreen->Progress(); + } + } +} + + +//========================================================================== +// +// FTextureManager :: AddTexturesLumps +// +//========================================================================== + +void FMultipatchTextureBuilder::AddTexturesLumps(int lump1, int lump2, int patcheslump) +{ + int firstdup = (int)TexMan.NumTextures(); + + if (lump1 >= 0) + { + FMemLump texdir = Wads.ReadLump(lump1); + AddTexturesLump(texdir.GetMem(), Wads.LumpLength(lump1), lump1, patcheslump, firstdup, true); + } + if (lump2 >= 0) + { + FMemLump texdir = Wads.ReadLump(lump2); + AddTexturesLump(texdir.GetMem(), Wads.LumpLength(lump2), lump2, patcheslump, firstdup, false); + } +} + +//========================================================================== +// +// THe reader for the textual format +// +//========================================================================== + + +//========================================================================== +// +// +// +//========================================================================== + +void FMultipatchTextureBuilder::ParsePatch(FScanner &sc, BuildInfo &info, TexPart & part, TexInit &init) +{ + FString patchname; + int Mirror = 0; + sc.MustGetString(); + + init.TexName = sc.String; + sc.MustGetStringName(","); + sc.MustGetNumber(); + part.OriginX = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + part.OriginY = sc.Number; + + if (sc.CheckString("{")) + { + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("flipx")) + { + Mirror |= 1; + } + else if (sc.Compare("flipy")) + { + Mirror |= 2; + } + else if (sc.Compare("rotate")) + { + sc.MustGetNumber(); + sc.Number = (((sc.Number + 90) % 360) - 90); + if (sc.Number != 0 && sc.Number != 90 && sc.Number != 180 && sc.Number != -90) + { + sc.ScriptError("Rotation must be a multiple of 90 degrees."); + } + part.Rotate = (sc.Number / 90) & 3; + } + else if (sc.Compare("Translation")) + { + int match; + + info.bComplex = true; + if (part.Translation != NULL) delete part.Translation; + part.Translation = NULL; + part.Blend = 0; + static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL }; + sc.MustGetString(); + + match = sc.MatchString(maps); + if (match >= 0) + { + part.Blend = BLEND_SPECIALCOLORMAP1 + match; + } + else if (sc.Compare("ICE")) + { + part.Blend = BLEND_ICEMAP; + } + else if (sc.Compare("DESATURATE")) + { + sc.MustGetStringName(","); + sc.MustGetNumber(); + part.Blend = BLEND_DESATURATE1 + clamp(sc.Number - 1, 0, 30); + } + else + { + sc.UnGet(); + part.Translation = new FRemapTable; + part.Translation->MakeIdentity(); + do + { + sc.MustGetString(); + + try + { + part.Translation->AddToTranslation(sc.String); + } + catch (CRecoverableError &err) + { + sc.ScriptMessage("Error in translation '%s':\n" TEXTCOLOR_YELLOW "%s\n", sc.String, err.GetMessage()); + } + } while (sc.CheckString(",")); + } + + } + else if (sc.Compare("Colormap")) + { + float r1, g1, b1; + float r2, g2, b2; + + sc.MustGetFloat(); + r1 = (float)sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + g1 = (float)sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + b1 = (float)sc.Float; + if (!sc.CheckString(",")) + { + part.Blend = AddSpecialColormap(0, 0, 0, r1, g1, b1); + } + else + { + sc.MustGetFloat(); + r2 = (float)sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + g2 = (float)sc.Float; + sc.MustGetStringName(","); + sc.MustGetFloat(); + b2 = (float)sc.Float; + part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2); + } + } + else if (sc.Compare("Blend")) + { + info.bComplex = true; + if (part.Translation != NULL) delete part.Translation; + part.Translation = NULL; + part.Blend = 0; + + if (!sc.CheckNumber()) + { + sc.MustGetString(); + part.Blend = V_GetColor(NULL, sc); + } + else + { + int r, g, b; + + r = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + g = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + b = sc.Number; + //sc.MustGetStringName(","); This was never supposed to be here. + part.Blend = MAKERGB(r, g, b); + } + // Blend.a may never be 0 here. + if (sc.CheckString(",")) + { + sc.MustGetFloat(); + if (sc.Float > 0.f) + part.Blend.a = clamp(int(sc.Float * 255), 1, 254); + else + part.Blend = 0; + } + else part.Blend.a = 255; + } + else if (sc.Compare("alpha")) + { + sc.MustGetFloat(); + part.Alpha = clamp(int(sc.Float * BLENDUNIT), 0, BLENDUNIT); + // bComplex is not set because it is only needed when the style is not OP_COPY. + } + else if (sc.Compare("style")) + { + static const char *styles[] = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay", NULL }; + sc.MustGetString(); + part.op = sc.MustMatchString(styles); + info.bComplex |= (part.op != OP_COPY); + } + else if (sc.Compare("useoffsets")) + { + init.UseOffsets = true; + } + } + } + if (Mirror & 2) + { + part.Rotate = (part.Rotate + 2) & 3; + Mirror ^= 1; + } + if (Mirror & 1) + { + part.Rotate |= 4; + } +} + + +//========================================================================== +// +// Constructor for text based multipatch definitions +// +//========================================================================== + +void FMultipatchTextureBuilder::ParseTexture(FScanner &sc, ETextureType UseType) +{ + BuildInfo &buildinfo = BuiltTextures[BuiltTextures.Reserve(1)]; + + bool bSilent = false; + + buildinfo.textual = true; + sc.SetCMode(true); + sc.MustGetString(); + + const char *textureName = nullptr; + if (sc.Compare("optional")) + { + bSilent = true; + sc.MustGetString(); + if (sc.Compare(",")) + { + // this is not right. Apparently a texture named 'optional' is being defined right now... + sc.UnGet(); + textureName = "optional"; + bSilent = false; + } + } + buildinfo.Name = !textureName ? sc.String : textureName; + buildinfo.Name.ToUpper(); + sc.MustGetStringName(","); + sc.MustGetNumber(); + buildinfo.Width = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + buildinfo.Height = sc.Number; + + bool offset2set = false; + if (sc.CheckString("{")) + { + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (sc.Compare("XScale")) + { + sc.MustGetFloat(); + buildinfo.Scale.X = sc.Float; + if (buildinfo.Scale.X == 0) sc.ScriptError("Texture %s is defined with null x-scale\n", buildinfo.Name.GetChars()); + } + else if (sc.Compare("YScale")) + { + sc.MustGetFloat(); + buildinfo.Scale.Y = sc.Float; + if (buildinfo.Scale.Y == 0) sc.ScriptError("Texture %s is defined with null y-scale\n", buildinfo.Name.GetChars()); + } + else if (sc.Compare("WorldPanning")) + { + buildinfo.bWorldPanning = true; + } + else if (sc.Compare("NullTexture")) + { + UseType = ETextureType::Null; + } + else if (sc.Compare("NoDecals")) + { + buildinfo.bNoDecals = true; + } + else if (sc.Compare("Patch")) + { + TexPart part; + TexInit init; + ParsePatch(sc, buildinfo, part, init); + if (init.TexName.IsNotEmpty()) + { + buildinfo.Parts.Push(part); + init.UseType = ETextureType::WallPatch; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + buildinfo.Inits.Push(init); + } + part.Image = nullptr; + part.Translation = nullptr; + } + else if (sc.Compare("Sprite")) + { + TexPart part; + TexInit init; + ParsePatch(sc, buildinfo, part, init); + if (init.TexName.IsNotEmpty()) + { + buildinfo.Parts.Push(part); + init.UseType = ETextureType::Sprite; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + buildinfo.Inits.Push(init); + } + part.Image = nullptr; + part.Translation = nullptr; + } + else if (sc.Compare("Graphic")) + { + TexPart part; + TexInit init; + ParsePatch(sc, buildinfo, part, init); + if (init.TexName.IsNotEmpty()) + { + buildinfo.Parts.Push(part); + init.UseType = ETextureType::MiscPatch; + init.Silent = bSilent; + init.HasLine = true; + init.sc = sc; + buildinfo.Inits.Push(init); + } + part.Image = nullptr; + part.Translation = nullptr; + } + else if (sc.Compare("Offset")) + { + sc.MustGetNumber(); + buildinfo.LeftOffset[0] = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + buildinfo.TopOffset[0] = sc.Number; + if (!offset2set) + { + buildinfo.LeftOffset[1] = buildinfo.LeftOffset[0]; + buildinfo.TopOffset[1] = buildinfo.TopOffset[0]; + } + } + else if (sc.Compare("Offset2")) + { + sc.MustGetNumber(); + buildinfo.LeftOffset[1] = sc.Number; + sc.MustGetStringName(","); + sc.MustGetNumber(); + buildinfo.TopOffset[1] = sc.Number; + offset2set = true; + } + else + { + sc.ScriptError("Unknown texture property '%s'", sc.String); + } + } + } + + if (buildinfo.Width <= 0 || buildinfo.Height <= 0) + { + UseType = ETextureType::Null; + Printf("Texture %s has invalid dimensions (%d, %d)\n", buildinfo.Name.GetChars(), buildinfo.Width, buildinfo.Height); + buildinfo.Width = buildinfo.Height = 1; + } + + MakeTexture(buildinfo, UseType); + sc.SetCMode(false); +} + + + +//========================================================================== +// +// FMultiPatchTexture :: CheckForHacks +// +//========================================================================== + +void FMultipatchTextureBuilder::CheckForHacks(BuildInfo &buildinfo) +{ + if (buildinfo.Parts.Size() == 0) + { + return; + } + + // Heretic sky textures are marked as only 128 pixels tall, + // even though they are really 200 pixels tall. + if (gameinfo.gametype == GAME_Heretic && + buildinfo.Name.Len() == 4 && + buildinfo.Name[0] == 'S' && + buildinfo.Name[1] == 'K' && + buildinfo.Name[2] == 'Y' && + buildinfo.Name[3] >= '1' && + buildinfo.Name[3] <= '3' && + buildinfo.Height == 128) + { + buildinfo.Height = 200; + return; + } + + // The Doom E1 sky has its patch's y offset at -8 instead of 0. + if (gameinfo.gametype == GAME_Doom && + !(gameinfo.flags & GI_MAPxx) && + buildinfo.Name.Len() == 4 && + buildinfo.Parts.Size() == 1 && + buildinfo.Height == 128 && + buildinfo.Parts[0].OriginY == -8 && + buildinfo.Name[0] == 'S' && + buildinfo.Name[1] == 'K' && + buildinfo.Name[2] == 'Y' && + buildinfo.Name[3] == '1') + { + buildinfo.Parts[0].OriginY = 0; + return; + } + + // BIGDOOR7 in Doom also has patches at y offset -4 instead of 0. + if (gameinfo.gametype == GAME_Doom && + !(gameinfo.flags & GI_MAPxx) && + buildinfo.Name.CompareNoCase("BIGDOOR7") == 0 && + buildinfo.Parts.Size() == 2 && + buildinfo.Height == 128 && + buildinfo.Parts[0].OriginY == -4 && + buildinfo.Parts[1].OriginY == -4) + { + buildinfo.Parts[0].OriginY = 0; + buildinfo.Parts[1].OriginY = 0; + return; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FMultipatchTextureBuilder::ResolvePatches(BuildInfo &buildinfo) +{ + for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) + { + FTextureID texno = TexMan.CheckForTexture(buildinfo.Inits[i].TexName, buildinfo.Inits[i].UseType); + if (texno == buildinfo.tex->id) // we found ourselves. Try looking for another one with the same name which is not a multipatch texture itself. + { + TArray list; + TexMan.ListTextures(buildinfo.Inits[i].TexName, list, true); + for (int i = list.Size() - 1; i >= 0; i--) + { + if (list[i] != buildinfo.tex->id && !TexMan.GetTexture(list[i])->bMultiPatch) + { + texno = list[i]; + break; + } + } + if (texno == buildinfo.tex->id) + { + if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); + else Printf(TEXTCOLOR_YELLOW "Texture '%s' references itself as patch\n", buildinfo.Inits[i].TexName.GetChars()); + continue; + } + else + { + // If it could be resolved, just print a developer warning. + DPrintf(DMSG_WARNING, "Resolved self-referencing texture by picking an older entry for %s\n", buildinfo.Inits[i].TexName.GetChars()); + } + } + + if (!texno.isValid()) + { + if (!buildinfo.Inits[i].Silent) + { + if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); + else Printf(TEXTCOLOR_YELLOW "Unknown patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); + } + } + else + { + FTexture *tex = TexMan.GetTexture(texno); + + if (tex != nullptr && tex->isValid()) + { + //We cannot set the image source yet. First all textures need to be resolved. + buildinfo.Inits[i].Texture = tex; + buildinfo.tex->bComplex |= tex->bComplex; + buildinfo.bComplex |= tex->bComplex; + if (buildinfo.Inits[i].UseOffsets) + { + buildinfo.Parts[i].OriginX -= tex->GetLeftOffset(0); + buildinfo.Parts[i].OriginY -= tex->GetTopOffset(0); + } + } + else + { + // The patch is bogus. Remove it. + if (buildinfo.Inits[i].HasLine) buildinfo.Inits[i].sc.Message(MSG_WARNING, "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); + else Printf(TEXTCOLOR_YELLOW "Invalid patch '%s' in texture '%s'\n", buildinfo.Inits[i].TexName.GetChars(), buildinfo.Name.GetChars()); + i--; + } + } + } + for (unsigned i = 0; i < buildinfo.Inits.Size(); i++) + { + if (buildinfo.Inits[i].Texture == nullptr) + { + buildinfo.Inits.Delete(i); + buildinfo.Parts.Delete(i); + i--; + } + } + + CheckForHacks(buildinfo); +} + +void FMultipatchTextureBuilder::ResolveAllPatches() +{ + for (auto &bi : BuiltTextures) + { + ResolvePatches(bi); + } + // Now try to resolve the images. We only can do this at the end when all multipatch textures are set up. + int i = 0; + while (BuiltTextures.Size() > 0) + { + bool donesomething = false; + for (unsigned i = 0; i < BuiltTextures.Size(); i++) + { + auto &buildinfo = BuiltTextures[i]; + bool hasEmpty = false; + + for (unsigned j = 0; j < buildinfo.Inits.Size(); j++) + { + if (buildinfo.Parts[j].Image == nullptr) + { + auto image = buildinfo.Inits[j].Texture->GetImage(); + if (image != nullptr) + { + buildinfo.Parts[j].Image = image; + donesomething = true; + } + else hasEmpty = true; + } + } + if (!hasEmpty) + { + // If this texture is just a wrapper around a single patch, we can simply + // use that patch's image directly here. + + bool done = false; + if (buildinfo.Parts.Size() == 1) + { + if (buildinfo.Parts[0].OriginX == 0 && buildinfo.Parts[0].OriginY == 0 && + buildinfo.Parts[0].Image->GetWidth() == buildinfo.Width && + buildinfo.Parts[0].Image->GetHeight() == buildinfo.Height && + buildinfo.Parts[0].Rotate == 0 && + !buildinfo.bComplex) + { + buildinfo.tex->SetImage(buildinfo.Parts[0].Image); + done = true; + } + } + if (!done) + { + auto img = new FMultiPatchTexture(buildinfo.Width, buildinfo.Height, buildinfo.Parts, buildinfo.bComplex, buildinfo.textual); + buildinfo.tex->SetImage(img); + } + + BuiltTextures.Delete(i); + i--; + donesomething = true; + } + } + if (!donesomething) + { + Printf("%d Unresolved textures remain\n", BuiltTextures.Size()); + for (auto &b : BuiltTextures) + { + Printf("%s\n", b.Name.GetChars()); + } + break; + } + } +} diff --git a/src/textures/skyboxtexture.cpp b/src/textures/skyboxtexture.cpp index 36581553c..45e79bf74 100644 --- a/src/textures/skyboxtexture.cpp +++ b/src/textures/skyboxtexture.cpp @@ -24,6 +24,7 @@ #include "w_wad.h" #include "textures.h" #include "skyboxtexture.h" +#include "bitmap.h" @@ -33,9 +34,17 @@ // //----------------------------------------------------------------------------- -FSkyBox::FSkyBox() -{ - faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5]=NULL; +FSkyBox::FSkyBox(const char *name) +: FTexture(name) +{ + FTextureID texid = TexMan.CheckForTexture(name, ETextureType::Wall); + previous = nullptr; + if (texid.isValid()) + { + previous = TexMan.GetTexture(texid); + CopySize(previous); + } + faces[0]=faces[1]=faces[2]=faces[3]=faces[4]=faces[5] = nullptr; UseType = ETextureType::Override; bSkybox = true; fliptop = false; @@ -47,21 +56,9 @@ FSkyBox::FSkyBox() // //----------------------------------------------------------------------------- -FSkyBox::~FSkyBox() +TArray FSkyBox::Get8BitPixels(bool alphatex) { - // The faces are only referenced but not owned so don't delete them. -} - -//----------------------------------------------------------------------------- -// -// If something attempts to use this as a texture just pass the information of the first face. -// -//----------------------------------------------------------------------------- - -const uint8_t *FSkyBox::GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out) -{ - if (faces[0]) return faces[0]->GetColumn(style, column, spans_out); - return NULL; + return previous->Get8BitPixels(alphatex); } //----------------------------------------------------------------------------- @@ -70,10 +67,9 @@ const uint8_t *FSkyBox::GetColumn(FRenderStyle style, unsigned int column, const // //----------------------------------------------------------------------------- -const uint8_t *FSkyBox::GetPixels (FRenderStyle style) +FBitmap FSkyBox::GetBgraBitmap(PalEntry *p, int *trans) { - if (faces[0]) return faces[0]->GetPixels(style); - return NULL; + return previous->GetBgraBitmap(p, trans); } //----------------------------------------------------------------------------- @@ -82,30 +78,7 @@ const uint8_t *FSkyBox::GetPixels (FRenderStyle style) // //----------------------------------------------------------------------------- -int FSkyBox::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +FImageSource *FSkyBox::GetImage() const { - if (faces[0]) return faces[0]->CopyTrueColorPixels(bmp, x, y, rotate, inf); - return 0; + return previous->GetImage(); } - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -bool FSkyBox::UseBasePalette() -{ - return false; // not really but here it's not important. -} - -//----------------------------------------------------------------------------- -// -// -// -//----------------------------------------------------------------------------- - -void FSkyBox::Unload () -{ -} - diff --git a/src/textures/skyboxtexture.h b/src/textures/skyboxtexture.h index 79fb9da4d..2288a4094 100644 --- a/src/textures/skyboxtexture.h +++ b/src/textures/skyboxtexture.h @@ -12,30 +12,28 @@ class FSkyBox : public FTexture { public: + FTexture *previous; FTexture * faces[6]; bool fliptop; - FSkyBox(); - ~FSkyBox(); - const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out); - const uint8_t *GetPixels (FRenderStyle style); - int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf); - bool UseBasePalette(); - void Unload (); + FSkyBox(const char *name); + TArray Get8BitPixels(bool alphatex); + FBitmap GetBgraBitmap(PalEntry *, int *trans) override; + FImageSource *GetImage() const override; + void SetSize() { - if (faces[0]) + if (!previous && faces[0]) previous = faces[0]; + if (previous) { - Width=faces[0]->GetWidth(); - Height=faces[0]->GetHeight(); - CalcBitSize(); + CopySize(previous); } } bool Is3Face() const { - return faces[5]==NULL; + return faces[5] == nullptr; } bool IsFlipped() const diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 85b57798d..44203413a 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -45,11 +45,15 @@ #include "c_dispatch.h" #include "v_video.h" #include "m_fixed.h" -#include "textures/warpbuffer.h" #include "hwrenderer/textures/hw_material.h" #include "hwrenderer/textures/hw_ihwtexture.h" +#include "swrenderer/textures/r_swtexture.h" +#include "imagehelpers.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "g_levellocals.h" -FTexture *CreateBrightmapTexture(FTexture*); +FTexture *CreateBrightmapTexture(FImageSource*); // Make sprite offset adjustment user-configurable per renderer. int r_spriteadjustSW, r_spriteadjustHW; @@ -66,13 +70,13 @@ CUSTOM_CVAR(Int, r_spriteadjust, 2, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) // //========================================================================== -uint8_t FTexture::GrayMap[256]; +uint8_t ImageHelpers::GrayMap[256]; void FTexture::InitGrayMap() { for (int i = 0; i < 256; ++i) { - GrayMap[i] = ColorMatcher.Pick(i, i, i); + ImageHelpers::GrayMap[i] = ColorMatcher.Pick(i, i, i); } } @@ -83,91 +87,45 @@ void FTexture::InitGrayMap() // //========================================================================== -typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum); - -struct TexCreateInfo -{ - CreateFunc TryCreate; - ETextureType usetype; -}; - -FTexture *IMGZTexture_TryCreate(FileReader &, int lumpnum); -FTexture *PNGTexture_TryCreate(FileReader &, int lumpnum); -FTexture *JPEGTexture_TryCreate(FileReader &, int lumpnum); -FTexture *DDSTexture_TryCreate(FileReader &, int lumpnum); -FTexture *PCXTexture_TryCreate(FileReader &, int lumpnum); -FTexture *TGATexture_TryCreate(FileReader &, int lumpnum); -FTexture *RawPageTexture_TryCreate(FileReader &, int lumpnum); -FTexture *FlatTexture_TryCreate(FileReader &, int lumpnum); -FTexture *PatchTexture_TryCreate(FileReader &, int lumpnum); -FTexture *EmptyTexture_TryCreate(FileReader &, int lumpnum); -FTexture *AutomapTexture_TryCreate(FileReader &, int lumpnum); - // Examines the lump contents to decide what type of texture to create, // and creates the texture. -FTexture * FTexture::CreateTexture (int lumpnum, ETextureType usetype) +FTexture * FTexture::CreateTexture(const char *name, int lumpnum, ETextureType usetype) { - static TexCreateInfo CreateInfo[]={ - { IMGZTexture_TryCreate, ETextureType::Any }, - { PNGTexture_TryCreate, ETextureType::Any }, - { JPEGTexture_TryCreate, ETextureType::Any }, - { DDSTexture_TryCreate, ETextureType::Any }, - { PCXTexture_TryCreate, ETextureType::Any }, - { TGATexture_TryCreate, ETextureType::Any }, - { RawPageTexture_TryCreate, ETextureType::MiscPatch }, - { FlatTexture_TryCreate, ETextureType::Flat }, - { PatchTexture_TryCreate, ETextureType::Any }, - { EmptyTexture_TryCreate, ETextureType::Any }, - { AutomapTexture_TryCreate, ETextureType::MiscPatch }, - }; + if (lumpnum == -1) return nullptr; - if (lumpnum == -1) return NULL; - - auto data = Wads.OpenLumpReader (lumpnum); - - for(size_t i = 0; i < countof(CreateInfo); i++) + auto image = FImageSource::GetImage(lumpnum, usetype); + if (image != nullptr) { - if ((CreateInfo[i].usetype == usetype || CreateInfo[i].usetype == ETextureType::Any)) + FTexture *tex = new FImageTexture(image); + if (tex != nullptr) { - FTexture * tex = CreateInfo[i].TryCreate(data, lumpnum); - if (tex != NULL) + tex->UseType = usetype; + if (usetype == ETextureType::Flat) { - tex->UseType = usetype; - if (usetype == ETextureType::Flat) - { - int w = tex->GetWidth(); - int h = tex->GetHeight(); + int w = tex->GetWidth(); + int h = tex->GetHeight(); - // Auto-scale flats with dimensions 128x128 and 256x256. - // In hindsight, a bad idea, but RandomLag made it sound better than it really is. - // Now we're stuck with this stupid behaviour. - if (w==128 && h==128) - { - tex->Scale.X = tex->Scale.Y = 2; - tex->bWorldPanning = true; - } - else if (w==256 && h==256) - { - tex->Scale.X = tex->Scale.Y = 4; - tex->bWorldPanning = true; - } + // Auto-scale flats with dimensions 128x128 and 256x256. + // In hindsight, a bad idea, but RandomLag made it sound better than it really is. + // Now we're stuck with this stupid behaviour. + if (w==128 && h==128) + { + tex->Scale.X = tex->Scale.Y = 2; + tex->bWorldPanning = true; + } + else if (w==256 && h==256) + { + tex->Scale.X = tex->Scale.Y = 4; + tex->bWorldPanning = true; } - return tex; } + tex->Name = name; + tex->Name.ToUpper(); + return tex; } } - return NULL; -} - -FTexture * FTexture::CreateTexture (const char *name, int lumpnum, ETextureType usetype) -{ - FTexture *tex = CreateTexture(lumpnum, usetype); - if (tex != NULL && name != NULL) { - tex->Name = name; - tex->Name.ToUpper(); - } - return tex; + return nullptr; } //========================================================================== @@ -178,10 +136,10 @@ FTexture * FTexture::CreateTexture (const char *name, int lumpnum, ETextureType FTexture::FTexture (const char *name, int lumpnum) : - WidthBits(0), HeightBits(0), Scale(1,1), SourceLump(lumpnum), + Scale(1,1), SourceLump(lumpnum), UseType(ETextureType::Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false), bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bKeepAround(false), bFullNameTexture(false), - Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0), WidthMask(0) + Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0) { bBrightmapChecked = false; bGlowing = false; @@ -222,49 +180,12 @@ FTexture::~FTexture () { if (Material[i] != nullptr) delete Material[i]; Material[i] = nullptr; - - if (SystemTexture[i] != nullptr) delete SystemTexture[i]; - SystemTexture[i] = nullptr; } - -} - -void FTexture::Unload() -{ - PixelsBgra = std::vector(); -} - -//========================================================================== -// -// -// -//========================================================================== - -const uint32_t *FTexture::GetColumnBgra(unsigned int column, const Span **spans_out) -{ - const uint32_t *pixels = GetPixelsBgra(); - if (pixels == nullptr) return nullptr; - - column %= Width; - - if (spans_out != nullptr) - GetColumn(DefaultRenderStyle(), column, spans_out); // This isn't the right way to create the spans. - return pixels + column * Height; -} - -const uint32_t *FTexture::GetPixelsBgra() -{ - if (PixelsBgra.empty() || CheckModified(DefaultRenderStyle())) + if (SoftwareTexture != nullptr) { - if (!GetColumn(DefaultRenderStyle(), 0, nullptr)) - return nullptr; - - FBitmap bitmap; - bitmap.Create(GetWidth(), GetHeight()); - CopyTrueColorPixels(&bitmap, 0, 0); - GenerateBgraFromBitmap(bitmap); + delete SoftwareTexture; + SoftwareTexture = nullptr; } - return PixelsBgra.data(); } //========================================================================== @@ -273,621 +194,25 @@ const uint32_t *FTexture::GetPixelsBgra() // //========================================================================== -bool FTexture::CheckModified (FRenderStyle) -{ - return false; -} - -FTextureFormat FTexture::GetFormat() -{ - return TEX_Pal; -} - void FTexture::SetFrontSkyLayer () { bNoRemap0 = true; } -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::CalcBitSize () -{ - // WidthBits is rounded down, and HeightBits is rounded up - int i; - - for (i = 0; (1 << i) < Width; ++i) - { } - - WidthBits = i; - - // Having WidthBits that would allow for columns past the end of the - // texture is not allowed, even if it means the entire texture is - // not drawn. - if (Width < (1 << WidthBits)) - { - WidthBits--; - } - WidthMask = (1 << WidthBits) - 1; - - //
The minimum height is 2, because we cannot shift right 32 bits. - // Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it. - for (i = 0; (1 << i) < Height; ++i) - { } - - HeightBits = i; -} - -//========================================================================== -// -// -// -//========================================================================== - -FTexture::Span **FTexture::CreateSpans (const uint8_t *pixels) const -{ - Span **spans, *span; - - if (!bMasked) - { // Texture does not have holes, so it can use a simpler span structure - spans = (Span **)M_Malloc (sizeof(Span*)*Width + sizeof(Span)*2); - span = (Span *)&spans[Width]; - for (int x = 0; x < Width; ++x) - { - spans[x] = span; - } - span[0].Length = Height; - span[0].TopOffset = 0; - span[1].Length = 0; - span[1].TopOffset = 0; - } - else - { // Texture might have holes, so build a complete span structure - int numcols = Width; - int numrows = Height; - int numspans = numcols; // One span to terminate each column - const uint8_t *data_p; - bool newspan; - int x, y; - - data_p = pixels; - - // Count the number of spans in this texture - for (x = numcols; x > 0; --x) - { - newspan = true; - for (y = numrows; y > 0; --y) - { - - if (*data_p++ == 0) - { - if (!newspan) - { - newspan = true; - } - } - else if (newspan) - { - newspan = false; - numspans++; - } - } - } - - // Allocate space for the spans - spans = (Span **)M_Malloc (sizeof(Span*)*numcols + sizeof(Span)*numspans); - - // Fill in the spans - for (x = 0, span = (Span *)&spans[numcols], data_p = pixels; x < numcols; ++x) - { - newspan = true; - spans[x] = span; - for (y = 0; y < numrows; ++y) - { - if (*data_p++ == 0) - { - if (!newspan) - { - newspan = true; - span++; - } - } - else - { - if (newspan) - { - newspan = false; - span->TopOffset = y; - span->Length = 1; - } - else - { - span->Length++; - } - } - } - if (!newspan) - { - span++; - } - span->TopOffset = 0; - span->Length = 0; - span++; - } - } - return spans; -} - -void FTexture::FreeSpans (Span **spans) const -{ - M_Free (spans); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::GenerateBgraFromBitmap(const FBitmap &bitmap) -{ - CreatePixelsBgraWithMipmaps(); - - // Transpose - const uint32_t *src = (const uint32_t *)bitmap.GetPixels(); - uint32_t *dest = PixelsBgra.data(); - for (int x = 0; x < Width; x++) - { - for (int y = 0; y < Height; y++) - { - dest[y + x * Height] = src[x + y * Width]; - } - } - - GenerateBgraMipmaps(); -} - -void FTexture::CreatePixelsBgraWithMipmaps() -{ - int levels = MipmapLevels(); - int buffersize = 0; - for (int i = 0; i < levels; i++) - { - int w = MAX(Width >> i, 1); - int h = MAX(Height >> i, 1); - buffersize += w * h; - } - PixelsBgra.resize(buffersize, 0xffff0000); -} - -int FTexture::MipmapLevels() const -{ - int widthbits = 0; - while ((Width >> widthbits) != 0) widthbits++; - - int heightbits = 0; - while ((Height >> heightbits) != 0) heightbits++; - - return MAX(widthbits, heightbits); -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::GenerateBgraMipmaps() -{ - struct Color4f - { - float a, r, g, b; - Color4f operator*(const Color4f &v) const { return Color4f{ a * v.a, r * v.r, g * v.g, b * v.b }; } - Color4f operator/(const Color4f &v) const { return Color4f{ a / v.a, r / v.r, g / v.g, b / v.b }; } - Color4f operator+(const Color4f &v) const { return Color4f{ a + v.a, r + v.r, g + v.g, b + v.b }; } - Color4f operator-(const Color4f &v) const { return Color4f{ a - v.a, r - v.r, g - v.g, b - v.b }; } - Color4f operator*(float s) const { return Color4f{ a * s, r * s, g * s, b * s }; } - Color4f operator/(float s) const { return Color4f{ a / s, r / s, g / s, b / s }; } - Color4f operator+(float s) const { return Color4f{ a + s, r + s, g + s, b + s }; } - Color4f operator-(float s) const { return Color4f{ a - s, r - s, g - s, b - s }; } - }; - - int levels = MipmapLevels(); - std::vector image(PixelsBgra.size()); - - // Convert to normalized linear colorspace - { - for (int x = 0; x < Width; x++) - { - for (int y = 0; y < Height; y++) - { - uint32_t c8 = PixelsBgra[x * Height + y]; - Color4f c; - c.a = powf(APART(c8) * (1.0f / 255.0f), 2.2f); - c.r = powf(RPART(c8) * (1.0f / 255.0f), 2.2f); - c.g = powf(GPART(c8) * (1.0f / 255.0f), 2.2f); - c.b = powf(BPART(c8) * (1.0f / 255.0f), 2.2f); - image[x * Height + y] = c; - } - } - } - - // Generate mipmaps - { - std::vector smoothed(Width * Height); - Color4f *src = image.data(); - Color4f *dest = src + Width * Height; - for (int i = 1; i < levels; i++) - { - int srcw = MAX(Width >> (i - 1), 1); - int srch = MAX(Height >> (i - 1), 1); - int w = MAX(Width >> i, 1); - int h = MAX(Height >> i, 1); - - // Downscale - for (int x = 0; x < w; x++) - { - int sx0 = x * 2; - int sx1 = MIN((x + 1) * 2, srcw - 1); - for (int y = 0; y < h; y++) - { - int sy0 = y * 2; - int sy1 = MIN((y + 1) * 2, srch - 1); - - Color4f src00 = src[sy0 + sx0 * srch]; - Color4f src01 = src[sy1 + sx0 * srch]; - Color4f src10 = src[sy0 + sx1 * srch]; - Color4f src11 = src[sy1 + sx1 * srch]; - Color4f c = (src00 + src01 + src10 + src11) * 0.25f; - - dest[y + x * h] = c; - } - } - - // Sharpen filter with a 3x3 kernel: - for (int x = 0; x < w; x++) - { - for (int y = 0; y < h; y++) - { - Color4f c = { 0.0f, 0.0f, 0.0f, 0.0f }; - for (int kx = -1; kx < 2; kx++) - { - for (int ky = -1; ky < 2; ky++) - { - int a = y + ky; - int b = x + kx; - if (a < 0) a = h - 1; - if (a == h) a = 0; - if (b < 0) b = w - 1; - if (b == w) b = 0; - c = c + dest[a + b * h]; - } - } - c = c * (1.0f / 9.0f); - smoothed[y + x * h] = c; - } - } - float k = 0.08f; - for (int j = 0; j < w * h; j++) - dest[j] = dest[j] + (dest[j] - smoothed[j]) * k; - - src = dest; - dest += w * h; - } - } - - // Convert to bgra8 sRGB colorspace - { - Color4f *src = image.data() + Width * Height; - uint32_t *dest = PixelsBgra.data() + Width * Height; - for (int i = 1; i < levels; i++) - { - int w = MAX(Width >> i, 1); - int h = MAX(Height >> i, 1); - for (int j = 0; j < w * h; j++) - { - uint32_t a = (uint32_t)clamp(powf(MAX(src[j].a, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t r = (uint32_t)clamp(powf(MAX(src[j].r, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t g = (uint32_t)clamp(powf(MAX(src[j].g, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - uint32_t b = (uint32_t)clamp(powf(MAX(src[j].b, 0.0f), 1.0f / 2.2f) * 255.0f + 0.5f, 0.0f, 255.0f); - dest[j] = (a << 24) | (r << 16) | (g << 8) | b; - } - src += w * h; - dest += w * h; - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::GenerateBgraMipmapsFast() -{ - uint32_t *src = PixelsBgra.data(); - uint32_t *dest = src + Width * Height; - int levels = MipmapLevels(); - for (int i = 1; i < levels; i++) - { - int srcw = MAX(Width >> (i - 1), 1); - int srch = MAX(Height >> (i - 1), 1); - int w = MAX(Width >> i, 1); - int h = MAX(Height >> i, 1); - - for (int x = 0; x < w; x++) - { - int sx0 = x * 2; - int sx1 = MIN((x + 1) * 2, srcw - 1); - - for (int y = 0; y < h; y++) - { - int sy0 = y * 2; - int sy1 = MIN((y + 1) * 2, srch - 1); - - uint32_t src00 = src[sy0 + sx0 * srch]; - uint32_t src01 = src[sy1 + sx0 * srch]; - uint32_t src10 = src[sy0 + sx1 * srch]; - uint32_t src11 = src[sy1 + sx1 * srch]; - - uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4; - uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4; - uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4; - uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4; - - dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue; - } - } - - src = dest; - dest += w * h; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::CopyToBlock (uint8_t *dest, int dwidth, int dheight, int xpos, int ypos, int rotate, const uint8_t *translation, FRenderStyle style) -{ - const uint8_t *pixels = GetPixels(style); - int srcwidth = Width; - int srcheight = Height; - int step_x = Height; - int step_y = 1; - FClipRect cr = {0, 0, dwidth, dheight}; - if (style.Flags & STYLEF_RedIsAlpha) translation = nullptr; // do not apply translations to alpha textures. - - if (ClipCopyPixelRect(&cr, xpos, ypos, pixels, srcwidth, srcheight, step_x, step_y, rotate)) - { - dest += ypos + dheight * xpos; - if (translation == NULL) - { - for (int x = 0; x < srcwidth; x++) - { - int pos = x * dheight; - for (int y = 0; y < srcheight; y++, pos++) - { - // the optimizer is doing a good enough job here so there's no need to optimize this by hand - uint8_t v = pixels[y * step_y + x * step_x]; - if (v != 0) dest[pos] = v; - } - } - } - else - { - for (int x = 0; x < srcwidth; x++) - { - int pos = x * dheight; - for (int y = 0; y < srcheight; y++, pos++) - { - uint8_t v = pixels[y * step_y + x * step_x]; - if (v != 0) dest[pos] = translation[v]; - } - } - } - } -} - -//========================================================================== -// -// Converts a texture between row-major and column-major format -// by flipping it about the X=Y axis. -// -//========================================================================== - -void FTexture::FlipSquareBlock (uint8_t *block, int x, int y) -{ - int i, j; - - if (x != y) return; - - for (i = 0; i < x; ++i) - { - uint8_t *corner = block + x*i + i; - int count = x - i; - if (count & 1) - { - count--; - swapvalues (corner[count], corner[count*x]); - } - for (j = 0; j < count; j += 2) - { - swapvalues (corner[j], corner[j*x]); - swapvalues (corner[j+1], corner[(j+1)*x]); - } - } -} - -void FTexture::FlipSquareBlockBgra(uint32_t *block, int x, int y) -{ - int i, j; - - if (x != y) return; - - for (i = 0; i < x; ++i) - { - uint32_t *corner = block + x*i + i; - int count = x - i; - if (count & 1) - { - count--; - swapvalues(corner[count], corner[count*x]); - } - for (j = 0; j < count; j += 2) - { - swapvalues(corner[j], corner[j*x]); - swapvalues(corner[j + 1], corner[(j + 1)*x]); - } - } -} - -void FTexture::FlipSquareBlockRemap (uint8_t *block, int x, int y, const uint8_t *remap) -{ - int i, j; - uint8_t t; - - if (x != y) return; - - for (i = 0; i < x; ++i) - { - uint8_t *corner = block + x*i + i; - int count = x - i; - if (count & 1) - { - count--; - t = remap[corner[count]]; - corner[count] = remap[corner[count*x]]; - corner[count*x] = t; - } - for (j = 0; j < count; j += 2) - { - t = remap[corner[j]]; - corner[j] = remap[corner[j*x]]; - corner[j*x] = t; - t = remap[corner[j+1]]; - corner[j+1] = remap[corner[(j+1)*x]]; - corner[(j+1)*x] = t; - } - } -} - -void FTexture::FlipNonSquareBlock (uint8_t *dst, const uint8_t *src, int x, int y, int srcpitch) -{ - int i, j; - - for (i = 0; i < x; ++i) - { - for (j = 0; j < y; ++j) - { - dst[i*y+j] = src[i+j*srcpitch]; - } - } -} - -void FTexture::FlipNonSquareBlockBgra(uint32_t *dst, const uint32_t *src, int x, int y, int srcpitch) -{ - int i, j; - - for (i = 0; i < x; ++i) - { - for (j = 0; j < y; ++j) - { - dst[i*y + j] = src[i + j*srcpitch]; - } - } -} - -void FTexture::FlipNonSquareBlockRemap (uint8_t *dst, const uint8_t *src, int x, int y, int srcpitch, const uint8_t *remap) -{ - int i, j; - - for (i = 0; i < x; ++i) - { - for (j = 0; j < y; ++j) - { - dst[i*y+j] = remap[src[i+j*srcpitch]]; - } - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void FTexture::FillBuffer(uint8_t *buff, int pitch, int height, FTextureFormat fmt) -{ - const uint8_t *pix; - int x, y, w, h, stride; - - w = GetWidth(); - h = GetHeight(); - - switch (fmt) - { - case TEX_Pal: - case TEX_Gray: - pix = GetPixels(fmt == TEX_Pal? DefaultRenderStyle() : LegacyRenderStyles[STYLE_Shaded]); - stride = pitch - w; - for (y = 0; y < h; ++y) - { - const uint8_t *pix2 = pix; - for (x = 0; x < w; ++x) - { - *buff++ = *pix2; - pix2 += h; - } - pix++; - buff += stride; - } - break; - - case TEX_RGB: - { - FCopyInfo inf = {OP_OVERWRITE, BLEND_NONE, {0}, 0, 0}; - FBitmap bmp(buff, pitch, pitch/4, height); - CopyTrueColorPixels(&bmp, 0, 0, 0, &inf); - break; - } - - default: - I_Error("FTexture::FillBuffer: Unsupported format %d", fmt); - } -} - //=========================================================================== // -// FTexture::CopyTrueColorPixels +// FTexture::GetBgraBitmap // -// this is the generic case that can handle -// any properly implemented texture for software rendering. -// Its drawback is that it is limited to the base palette which is -// why all classes that handle different palettes should subclass this -// method +// Default returns just an empty bitmap. This needs to be overridden by +// any subclass that actually does return a software pixel buffer. // //=========================================================================== -int FTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf) +FBitmap FTexture::GetBgraBitmap(PalEntry *remap, int *ptrans) { - PalEntry *palette = screen->GetPalette(); - for(int i=1;i<256;i++) palette[i].a = 255; // set proper alpha values - bmp->CopyPixelData(x, y, GetPixels(DefaultRenderStyle()), Width, Height, Height, 1, rotate, palette, inf); - for(int i=1;i<256;i++) palette[i].a = 0; - return 0; -} - -int FTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf) -{ - bmp->CopyPixelData(x, y, GetPixels(DefaultRenderStyle()), Width, Height, Height, 1, rotate, remap, inf); - return 0; + FBitmap bmp; + bmp.Create(Width, Height); + return bmp; } //========================================================================== @@ -896,19 +221,22 @@ int FTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, Pa // //========================================================================== -bool FTexture::UseBasePalette() -{ - return true; -} - -FTexture *FTexture::GetRedirect() -{ - return this; -} - FTexture *FTexture::GetRawTexture() { - return this; + if (OffsetLess) return OffsetLess; + // Reject anything that cannot have been a single-patch multipatch texture in vanilla. + auto image = static_cast(GetImage()); + if (bMultiPatch != 1 || UseType != ETextureType::Wall || Scale.X != 1 || Scale.Y != 1 || bWorldPanning || image == nullptr || image->NumParts != 1) + { + OffsetLess = this; + return this; + } + // Set up a new texture that directly references the underlying patch. + // From here we cannot retrieve the original texture made for it, so just create a new one. + FImageSource *source = image->Parts[0].Image; + OffsetLess = new FImageTexture(source, ""); + TexMan.AddTexture(OffsetLess); + return OffsetLess; } void FTexture::SetScaledSize(int fitwidth, int fitheight) @@ -965,11 +293,9 @@ PalEntry FTexture::GetSkyCapColor(bool bottom) { bSWSkyColorDone = true; - FBitmap bitmap; - bitmap.Create(GetWidth(), GetHeight()); - CopyTrueColorPixels(&bitmap, 0, 0); - int w = GetWidth(); - int h = GetHeight(); + FBitmap bitmap = GetBgraBitmap(nullptr); + int w = bitmap.GetWidth(); + int h = bitmap.GetHeight(); const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels(); if (buffer) @@ -996,29 +322,22 @@ PalEntry FTexture::GetSkyCapColor(bool bottom) int FTexture::CheckRealHeight() { - const FTexture::Span *span; - int maxy = 0, miny = GetHeight(); - - for (int i = 0; i < GetWidth(); ++i) + auto pixels = Get8BitPixels(false); + + for(int h = GetHeight()-1; h>= 0; h--) { - GetColumn(DefaultRenderStyle(), i, &span); - while (span->Length != 0) + for(int w = 0; w < GetWidth(); w++) { - if (span->TopOffset < miny) + if (pixels[h + w * GetHeight()] != 0) { - miny = span->TopOffset; + // Scale maxy before returning it + h = int((h * 2) / Scale.Y); + h = (h >> 1) + (h & 1); + return h; } - if (span->TopOffset + span->Length > maxy) - { - maxy = span->TopOffset + span->Length; - } - span++; } } - // Scale maxy before returning it - maxy = int((maxy * 2) / Scale.Y); - maxy = (maxy >> 1) + (maxy & 1); - return maxy; + return 0; } //========================================================================== @@ -1087,14 +406,12 @@ void FTexture::CreateDefaultBrightmap() if (!bBrightmapChecked) { // Check for brightmaps - if (UseBasePalette() && TexMan.HasGlobalBrightmap && + if (GetImage() && GetImage()->UseGamePalette() && TexMan.HasGlobalBrightmap && UseType != ETextureType::Decal && UseType != ETextureType::MiscPatch && UseType != ETextureType::FontChar && - Brightmap == NULL && bWarped == 0 && - GetPixels(DefaultRenderStyle()) - ) + Brightmap == NULL && bWarped == 0) { // May have one - let's check when we use this texture - const uint8_t *texbuf = GetPixels(DefaultRenderStyle()); + auto texbuf = Get8BitPixels(false); const int white = ColorMatcher.Pick(255, 255, 255); int size = GetWidth() * GetHeight(); @@ -1104,7 +421,7 @@ void FTexture::CreateDefaultBrightmap() { // Create a brightmap DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", Name.GetChars()); - Brightmap = CreateBrightmapTexture(this); + Brightmap = CreateBrightmapTexture(static_cast(this)->GetImage()); bBrightmapChecked = true; TexMan.AddTexture(Brightmap); return; @@ -1133,14 +450,8 @@ void FTexture::GetGlowColor(float *data) { if (bGlowing && GlowColor == 0) { - int w = Width, h = Height; - auto buffer = new uint8_t[w * h * 4]; - if (buffer) - { - FillBuffer(buffer, w * 4, h, TEX_RGB); - GlowColor = averageColor((uint32_t *)buffer, w*h, 153); - delete[] buffer; - } + auto buffer = GetBgraBitmap(nullptr); + GlowColor = averageColor((uint32_t*)buffer.GetPixels(), buffer.GetWidth() * buffer.GetHeight(), 153); // Black glow equals nothing so switch glowing off if (GlowColor == 0) bGlowing = false; @@ -1351,11 +662,6 @@ bool FTexture::ProcessData(unsigned char * buffer, int w, int h, bool ispatch) if (bMasked) { bMasked = SmoothEdges(buffer, w, h); - if (!bMasked) - { - auto stex = GetRedirect(); - stex->bMasked = false; // also clear in the base texture if there is a redirection. - } if (bMasked && !ispatch) FindHoles(buffer, w, h); } return true; @@ -1367,53 +673,72 @@ bool FTexture::ProcessData(unsigned char * buffer, int w, int h, bool ispatch) // //=========================================================================== -unsigned char * FTexture::CreateTexBuffer(int translation, int & w, int & h, int flags) +FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) { + FTextureBuffer result; + unsigned char * buffer = nullptr; int W, H; int isTransparent = -1; - + bool checkonly = !!(flags & CTF_CheckOnly); if (flags & CTF_CheckHires) { - buffer = LoadHiresTexture(&w, &h); - if (buffer != nullptr) - return buffer; + // No image means that this cannot be checked, + if (GetImage() && LoadHiresTexture(result, checkonly)) return result; } - int exx = !!(flags & CTF_Expand); - W = w = GetWidth() + 2 * exx; - H = h = GetHeight() + 2 * exx; + W = GetWidth() + 2 * exx; + H = GetHeight() + 2 * exx; - - buffer = new unsigned char[W*(H + 1) * 4]; - memset(buffer, 0, W * (H + 1) * 4); - - FBitmap bmp(buffer, W * 4, W, H); - - if (translation <= 0) + if (!checkonly) { - int trans = CopyTrueColorPixels(&bmp, exx, exx, 0, nullptr); - CheckTrans(buffer, W*H, trans); - isTransparent = bTranslucent; - } - else - { - // When using translations everything must be mapped to the base palette. - // so use CopyTrueColorTranslated - CopyTrueColorTranslated(&bmp, exx, exx, 0, FUniquePalette::GetPalette(translation)); - isTransparent = 0; - // This is not conclusive for setting the texture's transparency info. + buffer = new unsigned char[W*(H + 1) * 4]; + memset(buffer, 0, W * (H + 1) * 4); + + auto remap = translation <= 0 ? nullptr : FUniquePalette::GetPalette(translation); + FBitmap bmp(buffer, W * 4, W, H); + + int trans; + auto Pixels = GetBgraBitmap(remap, &trans); + bmp.Blit(exx, exx, Pixels); + + if (remap == nullptr) + { + CheckTrans(buffer, W*H, trans); + isTransparent = bTranslucent; + } + else + { + isTransparent = 0; + // A translated image is not conclusive for setting the texture's transparency info. + } } - if (flags & CTF_ProcessData) + if (GetImage()) { - buffer = CreateUpsampledTextureBuffer(buffer, W, H, w, h, !!isTransparent); - ProcessData(buffer, w, h, false); + FContentIdBuilder builder; + builder.id = 0; + builder.imageID = GetImage()->GetId(); + builder.translation = MAX(0, translation); + builder.expand = exx; + result.mContentId = builder.id; + } + else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0. + + result.mBuffer = buffer; + result.mWidth = W; + result.mHeight = H; + + // Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.) + if (GetImage() && flags & CTF_ProcessData) + { + CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly); + if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false); } - return buffer; + return result; } //=========================================================================== @@ -1428,9 +753,8 @@ bool FTexture::GetTranslucency() { if (!bHasCanvas) { - int w, h; - unsigned char *buffer = CreateTexBuffer(0, w, h); - delete[] buffer; + // This will calculate all we need, so just discard the result. + CreateTexBuffer(0); } else { @@ -1457,44 +781,17 @@ void FTexture::SetSpriteAdjust() //=========================================================================== // -// empty stubs to be overloaded by child classes. +// the default just returns an empty texture. // //=========================================================================== -const uint8_t *FTexture::GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out) +TArray FTexture::Get8BitPixels(bool alphatex) { - return nullptr; + TArray Pixels(Width * Height, true); + memset(Pixels.Data(), 0, Width * Height); + return Pixels; } -const uint8_t *FTexture::GetPixels(FRenderStyle style) -{ - return nullptr; -} - -//=========================================================================== -// -// Dummy texture for the 0-entry. -// -//=========================================================================== - -FDummyTexture::FDummyTexture () -{ - Width = 64; - Height = 64; - HeightBits = 6; - WidthBits = 6; - WidthMask = 63; - UseType = ETextureType::Null; -} - -void FDummyTexture::SetSize (int width, int height) -{ - Width = width; - Height = height; - CalcBitSize (); -} - - //========================================================================== // // @@ -1505,49 +802,14 @@ FWrapperTexture::FWrapperTexture(int w, int h, int bits) { Width = w; Height = h; - WidthBits = bits; + Format = bits; UseType = ETextureType::SWCanvas; bNoCompress = true; - SystemTexture[0] = screen->CreateHardwareTexture(this); + auto hwtex = screen->CreateHardwareTexture(); + // todo: Initialize here. + SystemTextures.AddHardwareTexture(0, false, hwtex); } -//========================================================================== -// -// Debug stuff -// -//========================================================================== - -#ifdef _DEBUG -// Prints the spans generated for a texture. Only needed for debugging. -CCMD (printspans) -{ - if (argv.argc() != 2) - return; - - FTextureID picnum = TexMan.CheckForTexture (argv[1], ETextureType::Any); - if (!picnum.Exists()) - { - Printf ("Unknown texture %s\n", argv[1]); - return; - } - FTexture *tex = TexMan[picnum]; - for (int x = 0; x < tex->GetWidth(); ++x) - { - const FTexture::Span *spans; - Printf ("%4d:", x); - tex->GetColumn(DefaultRenderStyle(), x, &spans); - while (spans->Length != 0) - { - Printf (" (%4d,%4d)", spans->TopOffset, spans->TopOffset+spans->Length-1); - spans++; - } - Printf ("\n"); - } -} - -#endif - - //=========================================================================== // // Coordinate helper. @@ -1566,19 +828,9 @@ CCMD (printspans) float FTexCoordInfo::RowOffset(float rowoffset) const { - float tscale = fabs(mTempScale.Y); float scale = fabs(mScale.Y); - - if (tscale == 1.f) - { - if (scale == 1.f || mWorldPanning) return rowoffset; - else return rowoffset / scale; - } - else - { - if (mWorldPanning) return rowoffset / tscale; - else return rowoffset / scale; - } + if (scale == 1.f || mWorldPanning) return rowoffset; + else return rowoffset / scale; } //=========================================================================== @@ -1589,18 +841,9 @@ float FTexCoordInfo::RowOffset(float rowoffset) const float FTexCoordInfo::TextureOffset(float textureoffset) const { - float tscale = fabs(mTempScale.X); float scale = fabs(mScale.X); - if (tscale == 1.f) - { - if (scale == 1.f || mWorldPanning) return textureoffset; - else return textureoffset / scale; - } - else - { - if (mWorldPanning) return textureoffset / tscale; - else return textureoffset / scale; - } + if (scale == 1.f || mWorldPanning) return textureoffset; + else return textureoffset / scale; } //=========================================================================== @@ -1661,6 +904,8 @@ void FTexCoordInfo::GetFromTexture(FTexture *tex, float x, float y) mScale.Y = -mScale.Y; mRenderHeight = -mRenderHeight; } - mWorldPanning = tex->bWorldPanning; + mWorldPanning = tex->bWorldPanning || (level.flags3 & LEVEL3_FORCEWORLDPANNING); mWidth = tex->GetWidth(); } + + diff --git a/src/textures/texturemanager.cpp b/src/textures/texturemanager.cpp index 4080018bf..799edb4aa 100644 --- a/src/textures/texturemanager.cpp +++ b/src/textures/texturemanager.cpp @@ -52,6 +52,9 @@ #include "r_renderer.h" #include "r_sky.h" #include "vm.h" +#include "image.h" +#include "formats/multipatchtexture.h" +#include "swrenderer/textures/r_swtexture.h" FTextureManager TexMan; @@ -96,6 +99,7 @@ FTextureManager::~FTextureManager () void FTextureManager::DeleteAll() { + FImageSource::ClearImages(); for (unsigned int i = 0; i < Textures.Size(); ++i) { delete Textures[i].Texture; @@ -138,6 +142,31 @@ void FTextureManager::DeleteAll() BuildTileData.Clear(); } +//========================================================================== +// +// Flushes all hardware dependent data. +// Thia must not, under any circumstances, delete the wipe textures, because +// all CCMDs triggering a flush can be executed while a wipe is in progress +// +// This now also deletes the software textures because having the software +// renderer use the texture scalers is a planned feature and that is the +// main reason to call this outside of the destruction code. +// +//========================================================================== + +void FTextureManager::FlushAll() +{ + for (int i = TexMan.NumTextures() - 1; i >= 0; i--) + { + for (int j = 0; j < 2; j++) + { + Textures[i].Texture->SystemTextures.Clean(true, true); + delete Textures[i].Texture->SoftwareTexture; + Textures[i].Texture->SoftwareTexture = nullptr; + } + } +} + //========================================================================== // // FTextureManager :: CheckForTexture @@ -329,7 +358,7 @@ int FTextureManager::ListTextures (const char *name, TArray &list, b // //========================================================================== -FTextureID FTextureManager::GetTexture (const char *name, ETextureType usetype, BITFIELD flags) +FTextureID FTextureManager::GetTextureID (const char *name, ETextureType usetype, BITFIELD flags) { FTextureID i; @@ -363,20 +392,6 @@ FTexture *FTextureManager::FindTexture(const char *texname, ETextureType usetype return !texnum.isValid()? NULL : Textures[texnum.GetIndex()].Texture; } -//========================================================================== -// -// FTextureManager :: UnloadAll -// -//========================================================================== - -void FTextureManager::UnloadAll () -{ - for (unsigned int i = 0; i < Textures.Size(); ++i) - { - Textures[i].Texture->Unload (); - } -} - //========================================================================== // // FTextureManager :: AddTexture @@ -423,7 +438,9 @@ FTextureID FTextureManager::CreateTexture (int lumpnum, ETextureType usetype) { if (lumpnum != -1) { - FTexture *out = FTexture::CreateTexture(lumpnum, usetype); + FString str; + Wads.GetLumpName(str, lumpnum); + FTexture *out = FTexture::CreateTexture(str, lumpnum, usetype); if (out != NULL) return AddTexture (out); else @@ -570,7 +587,7 @@ void FTextureManager::AddHiresTextures (int wadnum) if (amount == 0) { // A texture with this name does not yet exist - FTexture * newtex = FTexture::CreateTexture (firsttx, ETextureType::Any); + FTexture * newtex = FTexture::CreateTexture (Name, firsttx, ETextureType::Any); if (newtex != NULL) { newtex->UseType=ETextureType::Override; @@ -581,7 +598,7 @@ void FTextureManager::AddHiresTextures (int wadnum) { for(unsigned int i = 0; i < tlist.Size(); i++) { - FTexture * newtex = FTexture::CreateTexture (firsttx, ETextureType::Any); + FTexture * newtex = FTexture::CreateTexture ("", firsttx, ETextureType::Any); if (newtex != NULL) { FTexture * oldtex = Textures[tlist[i].GetIndex()].Texture; @@ -609,7 +626,7 @@ void FTextureManager::AddHiresTextures (int wadnum) // //========================================================================== -void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) +void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build) { int remapLump, lastLump; @@ -619,12 +636,12 @@ void FTextureManager::LoadTextureDefs(int wadnum, const char *lumpname) { if (Wads.GetLumpFile(remapLump) == wadnum) { - ParseTextureDef(remapLump); + ParseTextureDef(remapLump, build); } } } -void FTextureManager::ParseTextureDef(int lump) +void FTextureManager::ParseTextureDef(int lump, FMultipatchTextureBuilder &build) { TArray tlist; @@ -680,7 +697,7 @@ void FTextureManager::ParseTextureDef(int lump) (sl=oldtex->GetSourceLump()) >= 0 && Wads.GetLumpNamespace(sl) == ns_sprites) ) { - FTexture * newtex = FTexture::CreateTexture (lumpnum, ETextureType::Any); + FTexture * newtex = FTexture::CreateTexture ("", lumpnum, ETextureType::Any); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. @@ -719,14 +736,13 @@ void FTextureManager::ParseTextureDef(int lump) if (lumpnum>=0) { - FTexture *newtex = FTexture::CreateTexture(lumpnum, ETextureType::Override); + FTexture *newtex = FTexture::CreateTexture(src, lumpnum, ETextureType::Override); if (newtex != NULL) { // Replace the entire texture and adjust the scaling and offset factors. newtex->bWorldPanning = true; newtex->SetScaledSize(width, height); - newtex->Name = src; FTextureID oldtex = TexMan.CheckForTexture(src, ETextureType::MiscPatch); if (oldtex.isValid()) @@ -742,23 +758,23 @@ void FTextureManager::ParseTextureDef(int lump) } else if (sc.Compare("texture")) { - ParseXTexture(sc, ETextureType::Override); + build.ParseTexture(sc, ETextureType::Override); } else if (sc.Compare("sprite")) { - ParseXTexture(sc, ETextureType::Sprite); + build.ParseTexture(sc, ETextureType::Sprite); } else if (sc.Compare("walltexture")) { - ParseXTexture(sc, ETextureType::Wall); + build.ParseTexture(sc, ETextureType::Wall); } else if (sc.Compare("flat")) { - ParseXTexture(sc, ETextureType::Flat); + build.ParseTexture(sc, ETextureType::Flat); } else if (sc.Compare("graphic")) { - ParseXTexture(sc, ETextureType::MiscPatch); + build.ParseTexture(sc, ETextureType::MiscPatch); } else if (sc.Compare("#include")) { @@ -772,7 +788,7 @@ void FTextureManager::ParseTextureDef(int lump) } else { - ParseTextureDef(includelump); + ParseTextureDef(includelump, build); } } else @@ -818,7 +834,7 @@ void FTextureManager::AddPatches (int lumpnum) // //========================================================================== -void FTextureManager::LoadTextureX(int wadnum) +void FTextureManager::LoadTextureX(int wadnum, FMultipatchTextureBuilder &build) { // Use the most recent PNAMES for this WAD. // Multiple PNAMES in a WAD will be ignored. @@ -836,7 +852,7 @@ void FTextureManager::LoadTextureX(int wadnum) int texlump1 = Wads.CheckNumForName ("TEXTURE1", ns_global, wadnum); int texlump2 = Wads.CheckNumForName ("TEXTURE2", ns_global, wadnum); - AddTexturesLumps (texlump1, texlump2, pnames); + build.AddTexturesLumps (texlump1, texlump2, pnames); } //========================================================================== @@ -845,7 +861,7 @@ void FTextureManager::LoadTextureX(int wadnum) // //========================================================================== -void FTextureManager::AddTexturesForWad(int wadnum) +void FTextureManager::AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build) { int firsttexture = Textures.Size(); int lumpcount = Wads.GetNumLumps(); @@ -860,7 +876,7 @@ void FTextureManager::AddTexturesForWad(int wadnum) AddGroup(wadnum, ns_patches, ETextureType::WallPatch); // Second step: TEXTUREx lumps - LoadTextureX(wadnum); + LoadTextureX(wadnum, build); // Third step: Flats AddGroup(wadnum, ns_flats, ETextureType::Flat); @@ -922,7 +938,7 @@ void FTextureManager::AddTexturesForWad(int wadnum) // Try to create a texture from this lump and add it. // Unfortunately we have to look at everything that comes through here... - FTexture *out = FTexture::CreateTexture(i, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); + FTexture *out = FTexture::CreateTexture(Name, i, skin ? ETextureType::SkinGraphic : ETextureType::MiscPatch); if (out != NULL) { @@ -931,8 +947,8 @@ void FTextureManager::AddTexturesForWad(int wadnum) } // Check for text based texture definitions - LoadTextureDefs(wadnum, "TEXTURES"); - LoadTextureDefs(wadnum, "HIRESTEX"); + LoadTextureDefs(wadnum, "TEXTURES", build); + LoadTextureDefs(wadnum, "HIRESTEX", build); // Seventh step: Check for hires replacements. AddHiresTextures(wadnum); @@ -1013,7 +1029,9 @@ void FTextureManager::Init() FTexture::InitGrayMap(); // Texture 0 is a dummy texture used to indicate "no texture" - AddTexture (new FDummyTexture); + auto nulltex = new FImageTexture(nullptr); + nulltex->SetUseType(ETextureType::Null); + AddTexture (nulltex); // some special textures used in the game. AddTexture(CreateShaderTexture(false, false)); AddTexture(CreateShaderTexture(false, true)); @@ -1021,14 +1039,14 @@ void FTextureManager::Init() AddTexture(CreateShaderTexture(true, true)); int wadcnt = Wads.GetNumWads(); + + FMultipatchTextureBuilder build(*this); + for(int i = 0; i< wadcnt; i++) { - AddTexturesForWad(i); - } - for (unsigned i = 0; i < Textures.Size(); i++) - { - Textures[i].Texture->ResolvePatches(); + AddTexturesForWad(i, build); } + build.ResolveAllPatches(); // Add one marker so that the last WAD is easier to handle and treat // Build tiles as a completely separate block. @@ -1116,8 +1134,8 @@ void FTextureManager::InitPalettedVersions() } if (pic1.isValid() && pic2.isValid()) { - FTexture *owner = TexMan[pic1]; - FTexture *owned = TexMan[pic2]; + FTexture *owner = GetTexture(pic1); + FTexture *owned = GetTexture(pic2); if (owner && owned) owner->PalVersion = owned; } @@ -1131,11 +1149,11 @@ void FTextureManager::InitPalettedVersions() // //========================================================================== -// fixme: The way this is used, it is mostly useless. FTextureID FTextureManager::PalCheck(FTextureID tex) { - if (vid_nopalsubstitutions) return tex; - auto ftex = operator[](tex); + // In any true color mode this shouldn't do anything. + if (vid_nopalsubstitutions || V_IsTrueColor()) return tex; + auto ftex = GetTexture(tex); if (ftex != nullptr && ftex->PalVersion != nullptr) return ftex->PalVersion->id; return tex; } @@ -1259,7 +1277,7 @@ void FTextureManager::AdjustSpriteOffsets() Wads.GetLumpName(str, i); str[8] = 0; FTextureID texid = TexMan.CheckForTexture(str, ETextureType::Sprite, 0); - if (texid.isValid() && Wads.GetLumpFile(TexMan[texid]->SourceLump) > Wads.GetIwadNum()) + if (texid.isValid() && Wads.GetLumpFile(GetTexture(texid)->SourceLump) > Wads.GetIwadNum()) { // This texture has been replaced by some PWAD. memcpy(&sprid, str, 4); @@ -1294,7 +1312,7 @@ void FTextureManager::AdjustSpriteOffsets() } if (texno.isValid()) { - FTexture * tex = TexMan[texno]; + FTexture * tex = GetTexture(texno); int lumpnum = tex->GetSourceLump(); // We only want to change texture offsets for sprites in the IWAD or the file this lump originated from. @@ -1399,7 +1417,7 @@ DEFINE_ACTION_FUNCTION(_TexMan, GetName) if (tex != nullptr) { - if (tex->Name.IsNotEmpty()) retval = tex->Name; + if (tex->GetName().IsNotEmpty()) retval = tex->GetName(); else { // Textures for full path names do not have their own name, they merely link to the source lump. @@ -1423,8 +1441,8 @@ static int GetTextureSize(int texid, int *py) int x, y; if (tex != nullptr) { - x = tex->GetWidth(); - y = tex->GetHeight(); + x = tex->GetDisplayWidth(); + y = tex->GetDisplayHeight(); } else x = y = -1; if (py) *py = y; @@ -1453,8 +1471,8 @@ static void GetScaledSize(int texid, DVector2 *pvec) double x, y; if (tex != nullptr) { - x = tex->GetScaledWidthDouble(); - y = tex->GetScaledHeightDouble(); + x = tex->GetDisplayWidthDouble(); + y = tex->GetDisplayHeightDouble(); } else x = y = -1; if (pvec) @@ -1484,8 +1502,8 @@ static void GetScaledOffset(int texid, DVector2 *pvec) double x, y; if (tex != nullptr) { - x = tex->GetScaledLeftOffsetDouble(0); - y = tex->GetScaledTopOffsetDouble(0); + x = tex->GetDisplayLeftOffsetDouble(); + y = tex->GetDisplayTopOffsetDouble(); } else x = y = -1; if (pvec) diff --git a/src/textures/textures.h b/src/textures/textures.h index 4c4cd57c6..934fb122f 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -42,12 +42,14 @@ #include "colormatcher.h" #include "r_data/renderstyle.h" #include "r_data/r_translate.h" +#include "hwrenderer/textures/hw_texcontainer.h" #include // 15 because 0th texture is our texture #define MAX_CUSTOM_HW_SHADER_TEXTURES 15 typedef TMap SpriteHits; +class FImageSource; enum MaterialShaderIndex { @@ -108,6 +110,7 @@ enum ECreateTexBufferFlags CTF_CheckHires = 1, // use external hires replacement if found CTF_Expand = 2, // create buffer with a one-pixel wide border CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. + CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. }; @@ -122,6 +125,8 @@ class FTextureManager; class FTerrainTypeArray; class IHardwareTexture; class FMaterial; +class FMultipatchTextureBuilder; + extern int r_spriteadjustSW, r_spriteadjustHW; class FNullTextureID : public FTextureID @@ -211,21 +216,152 @@ enum FTextureFormat : uint32_t TEX_Count }; +class FSoftwareTexture; +class FGLRenderState; + +struct spriteframewithrotate; +class FSerializer; +namespace OpenGLRenderer +{ + class FGLRenderState; + class FHardwareTexture; +} + +union FContentIdBuilder +{ + uint64_t id; + struct + { + unsigned imageID : 24; + unsigned translation : 16; + unsigned expand : 1; + unsigned scaler : 4; + unsigned scalefactor : 4; + }; +}; + +struct FTextureBuffer +{ + uint8_t *mBuffer = nullptr; + int mWidth = 0; + int mHeight = 0; + uint64_t mContentId = 0; // unique content identifier. (Two images created from the same image source with the same settings will return the same value.) + + FTextureBuffer() = default; + + ~FTextureBuffer() + { + if (mBuffer) delete[] mBuffer; + } + + FTextureBuffer(const FTextureBuffer &other) = delete; + FTextureBuffer(FTextureBuffer &&other) + { + mBuffer = other.mBuffer; + mWidth = other.mWidth; + mHeight = other.mHeight; + mContentId = other.mContentId; + other.mBuffer = nullptr; + } + + FTextureBuffer& operator=(FTextureBuffer &&other) + { + mBuffer = other.mBuffer; + mWidth = other.mWidth; + mHeight = other.mHeight; + mContentId = other.mContentId; + other.mBuffer = nullptr; + return *this; + } + +}; // Base texture class class FTexture { + // This is initialization code that is allowed to have full access. + friend void R_InitSpriteDefs (); + friend void R_InstallSprite (int num, spriteframewithrotate *sprtemp, int &maxframe); + friend class GLDefsParser; + friend class FMultipatchTextureBuilder; + + // The serializer also needs access to more specific info that shouldn't be accessible through the interface. + friend FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); + + // For now only give access to classes which cannot be reworked yet. None of these should remain here when all is done. + friend class FSoftwareTexture; + friend class FWarpTexture; + friend class FMaterial; + friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class + friend struct FTexCoordInfo; + friend class OpenGLRenderer::FHardwareTexture; + friend class FMultiPatchTexture; + friend class FSkyBox; + friend class FBrightmapTexture; + friend class FFontChar1; + friend void RecordTextureColors (FTexture *pic, uint8_t *usedcolors); + public: static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType usetype); - static FTexture *CreateTexture(int lumpnum, ETextureType usetype); virtual ~FTexture (); + virtual FImageSource *GetImage() const { return nullptr; } void AddAutoMaterials(); - unsigned char *CreateUpsampledTextureBuffer(unsigned char *inputBuffer, const int inWidth, const int inHeight, int &outWidth, int &outHeight, bool hasAlpha); + void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); - //int16_t LeftOffset, TopOffset; + // These are mainly meant for 2D code which only needs logical information about the texture to position it properly. + int GetDisplayWidth() { return GetScaledWidth(); } + int GetDisplayHeight() { return GetScaledHeight(); } + double GetDisplayWidthDouble() { return GetScaledWidthDouble(); } + double GetDisplayHeightDouble() { return GetScaledHeightDouble(); } + int GetDisplayLeftOffset() { return GetScaledLeftOffset(0); } + int GetDisplayTopOffset() { return GetScaledTopOffset(0); } + double GetDisplayLeftOffsetDouble() { return GetScaledLeftOffsetDouble(0); } + double GetDisplayTopOffsetDouble() { return GetScaledTopOffsetDouble(0); } + + + bool isValid() const { return UseType != ETextureType::Null; } + bool isSWCanvas() const { return UseType == ETextureType::SWCanvas; } + bool isSkybox() const { return bSkybox; } + bool isFullbrightDisabled() const { return bDisableFullbright; } + bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later. + bool isCanvas() const { return bHasCanvas; } + bool isMiscPatch() const { return UseType == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. + int isWarped() const { return bWarped; } + int GetRotations() const { return Rotations; } + void SetRotations(int rot) { Rotations = int16_t(rot); } + bool isSprite() const { return UseType == ETextureType::Sprite || UseType == ETextureType::SkinSprite || UseType == ETextureType::Decal; } + + const FString &GetName() const { return Name; } + bool allowNoDecals() const { return bNoDecals; } + bool isScaled() const { return Scale.X != 1 || Scale.Y != 1; } + bool isMasked() const { return bMasked; } + int GetSkyOffset() const { return SkyOffset; } + FTextureID GetID() const { return id; } + PalEntry GetSkyCapColor(bool bottom); + FTexture *GetRawTexture(); + virtual int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. + void GetGlowColor(float *data); + bool isGlowing() const { return bGlowing; } + bool isAutoGlowing() const { return bAutoGlowing; } + int GetGlowHeight() const { return GlowHeight; } + bool isFullbright() const { return bFullbright; } + void CreateDefaultBrightmap(); + bool FindHoles(const unsigned char * buffer, int w, int h); + void SetUseType(ETextureType type) { UseType = type; } - uint8_t WidthBits, HeightBits; + // Returns the whole texture, stored in column-major order + virtual TArray Get8BitPixels(bool alphatex); + virtual FBitmap GetBgraBitmap(PalEntry *remap, int *trans = nullptr); + +public: + static bool SmoothEdges(unsigned char * buffer,int w, int h); + static PalEntry averageColor(const uint32_t *data, int size, int maxout); + + + FSoftwareTexture *GetSoftwareTexture(); + +protected: DVector2 Scale; @@ -233,10 +369,15 @@ public: FTextureID id; FMaterial *Material[2] = { nullptr, nullptr }; - IHardwareTexture *SystemTexture[2] = { nullptr, nullptr }; +public: + FHardwareTextureContainer SystemTextures; +protected: + FSoftwareTexture *SoftwareTexture = nullptr; // None of the following pointers are owned by this texture, they are all controlled by the texture manager. + // Offset-less version for COMPATF_MASKEDMIDTEX + FTexture *OffsetLess = nullptr; // Paletted variant FTexture *PalVersion = nullptr; // External hires texture @@ -290,43 +431,17 @@ public: float shaderspeed = 1.f; int shaderindex = 0; - - - struct Span + // This is only legal for the null texture! + void SetSize(int w, int h) { - uint16_t TopOffset; - uint16_t Length; // A length of 0 terminates this column - }; + if (UseType == ETextureType::Null) + { + Width = w; + Height = h; + } + } - // Returns a single column of the texture - virtual const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out); - - // Returns a single column of the texture, in BGRA8 format - virtual const uint32_t *GetColumnBgra(unsigned int column, const Span **spans_out); - - // Returns the whole texture, stored in column-major order - virtual const uint8_t *GetPixels(FRenderStyle style); - - // Returns the whole texture, stored in column-major order, in BGRA8 format - virtual const uint32_t *GetPixelsBgra(); - - // Returns true if GetPixelsBgra includes mipmaps - virtual bool Mipmapped() { return true; } - - virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0, FCopyInfo *inf = NULL); - virtual int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf = NULL); - virtual bool UseBasePalette(); - virtual int GetSourceLump() { return SourceLump; } - virtual FTexture *GetRedirect(); - virtual FTexture *GetRawTexture(); // for FMultiPatchTexture to override - - virtual void Unload (); - - // Returns the native pixel format for this image - virtual FTextureFormat GetFormat(); - - // Fill the native texture buffer with pixel data for this image - virtual void FillBuffer(uint8_t *buff, int pitch, int height, FTextureFormat fmt); + void SetSpeed(float fac) { shaderspeed = fac; } int GetWidth () { return Width; } int GetHeight () { return Height; } @@ -348,32 +463,13 @@ public: // Interfaces for the different renderers. Everything that needs to check renderer-dependent offsets // should use these, so that if changes are needed, this is the only place to edit. - // For the original software renderer - int GetLeftOffsetSW() { return _LeftOffset[r_spriteadjustSW]; } - int GetTopOffsetSW() { return _TopOffset[r_spriteadjustSW]; } - int GetScaledLeftOffsetSW() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetSW() { return GetScaledTopOffset(r_spriteadjustSW); } - - // For the softpoly renderer, in case it wants adjustment - int GetLeftOffsetPo() { return _LeftOffset[r_spriteadjustSW]; } - int GetTopOffsetPo() { return _TopOffset[r_spriteadjustSW]; } - int GetScaledLeftOffsetPo() { return GetScaledLeftOffset(r_spriteadjustSW); } - int GetScaledTopOffsetPo() { return GetScaledTopOffset(r_spriteadjustSW); } - - // For the hardware renderer + // For the hardware renderer. The software renderer's have been offloaded to FSoftwareTexture int GetLeftOffsetHW() { return _LeftOffset[r_spriteadjustHW]; } int GetTopOffsetHW() { return _TopOffset[r_spriteadjustHW]; } virtual void ResolvePatches() {} - virtual void SetFrontSkyLayer(); - - void CopyToBlock (uint8_t *dest, int dwidth, int dheight, int x, int y, int rotate, const uint8_t *translation, FRenderStyle style); - - // Returns true if the next call to GetPixels() will return an image different from the - // last call to GetPixels(). This should be considered valid only if a call to CheckModified() - // is immediately followed by a call to GetPixels(). - virtual bool CheckModified (FRenderStyle style); + void SetFrontSkyLayer(); static void InitGrayMap(); @@ -385,72 +481,17 @@ public: _TopOffset[1] = BaseTexture->_TopOffset[1]; _LeftOffset[0] = BaseTexture->_LeftOffset[0]; _LeftOffset[1] = BaseTexture->_LeftOffset[1]; - WidthBits = BaseTexture->WidthBits; - HeightBits = BaseTexture->HeightBits; Scale = BaseTexture->Scale; - WidthMask = (1 << WidthBits) - 1; } void SetScaledSize(int fitwidth, int fitheight); - PalEntry GetSkyCapColor(bool bottom); - static PalEntry averageColor(const uint32_t *data, int size, int maxout); protected: - uint16_t Width, Height, WidthMask; + uint16_t Width, Height; int16_t _LeftOffset[2], _TopOffset[2]; - static uint8_t GrayMap[256]; - uint8_t *GetRemap(FRenderStyle style, bool srcisgrayscale = false) - { - if (style.Flags & STYLEF_RedIsAlpha) - { - return translationtables[TRANSLATION_Standard][srcisgrayscale ? STD_Gray : STD_Grayscale]->Remap; - } - else - { - return srcisgrayscale ? GrayMap : GPalette.Remap; - } - } - - uint8_t RGBToPalettePrecise(bool wantluminance, int r, int g, int b, int a = 255) - { - if (wantluminance) - { - return (uint8_t)Luminance(r, g, b) * a / 255; - } - else - { - return ColorMatcher.Pick(r, g, b); - } - } - - uint8_t RGBToPalette(bool wantluminance, int r, int g, int b, int a = 255) - { - if (wantluminance) - { - // This is the same formula the OpenGL renderer uses for grayscale textures with an alpha channel. - return (uint8_t)(Luminance(r, g, b) * a / 255); - } - else - { - return a < 128? 0 : RGB256k.RGB[r >> 2][g >> 2][b >> 2]; - } - } - - uint8_t RGBToPalette(bool wantluminance, PalEntry pe, bool hasalpha = true) - { - return RGBToPalette(wantluminance, pe.r, pe.g, pe.b, hasalpha? pe.a : 255); - } - - uint8_t RGBToPalette(FRenderStyle style, int r, int g, int b, int a = 255) - { - return RGBToPalette(!!(style.Flags & STYLEF_RedIsAlpha), r, g, b, a); - } FTexture (const char *name = NULL, int lumpnum = -1); - Span **CreateSpans (const uint8_t *pixels) const; - void FreeSpans (Span **spans) const; - void CalcBitSize (); void CopyInfo(FTexture *other) { CopySize(other); @@ -458,44 +499,23 @@ protected: Rotations = other->Rotations; } - std::vector PixelsBgra; - - void GenerateBgraFromBitmap(const FBitmap &bitmap); - void CreatePixelsBgraWithMipmaps(); - void GenerateBgraMipmaps(); - void GenerateBgraMipmapsFast(); - int MipmapLevels() const; public: - unsigned char * CreateTexBuffer(int translation, int & w, int & h, int flags = 0); + FTextureBuffer CreateTexBuffer(int translation, int flags = 0); bool GetTranslucency(); private: int CheckDDPK3(); int CheckExternalFile(bool & hascolorkey); - unsigned char *LoadHiresTexture(int *width, int *height); + bool LoadHiresTexture(FTextureBuffer &texbuffer, bool checkonly); bool bSWSkyColorDone = false; PalEntry FloorSkyColor; PalEntry CeilingSkyColor; public: - static void FlipSquareBlock (uint8_t *block, int x, int y); - static void FlipSquareBlockBgra (uint32_t *block, int x, int y); - static void FlipSquareBlockRemap (uint8_t *block, int x, int y, const uint8_t *remap); - static void FlipNonSquareBlock (uint8_t *blockto, const uint8_t *blockfrom, int x, int y, int srcpitch); - static void FlipNonSquareBlockBgra (uint32_t *blockto, const uint32_t *blockfrom, int x, int y, int srcpitch); - static void FlipNonSquareBlockRemap (uint8_t *blockto, const uint8_t *blockfrom, int x, int y, int srcpitch, const uint8_t *remap); -public: - - void GetGlowColor(float *data); - bool isGlowing() { return bGlowing; } - bool isFullbright() { return bFullbright; } - void CreateDefaultBrightmap(); - bool FindHoles(const unsigned char * buffer, int w, int h); - static bool SmoothEdges(unsigned char * buffer,int w, int h); void CheckTrans(unsigned char * buffer, int size, int trans); bool ProcessData(unsigned char * buffer, int w, int h, bool ispatch); int CheckRealHeight(); @@ -504,6 +524,7 @@ public: friend class FTextureManager; }; + class FxAddSub; // Texture manager class FTextureManager @@ -513,49 +534,42 @@ public: FTextureManager (); ~FTextureManager (); - // Get texture without translation -//private: - FTexture *operator[] (FTextureID texnum) + // This only gets used in UI code so we do not need PALVERS handling. + FTexture *GetTextureByName(const char *name, bool animate = false) { - if ((unsigned)texnum.GetIndex() >= Textures.Size()) return NULL; + FTextureID texnum = GetTextureID (name, ETextureType::MiscPatch); + if (!texnum.Exists()) return nullptr; + if (!animate) return Textures[texnum.GetIndex()].Texture; + else return Textures[Translation[texnum.GetIndex()]].Texture; + } + + FTexture *GetTexture(FTextureID texnum, bool animate = false) + { + if ((size_t)texnum.GetIndex() >= Textures.Size()) return nullptr; + if (animate) texnum = Translation[texnum.GetIndex()]; return Textures[texnum.GetIndex()].Texture; } - FTexture *operator[] (const char *texname) + + // This is the only access function that should be used inside the software renderer. + FTexture *GetPalettedTexture(FTextureID texnum, bool animate) { - FTextureID texnum = GetTexture (texname, ETextureType::MiscPatch); - if (!texnum.Exists()) return NULL; + if ((size_t)texnum.texnum >= Textures.Size()) return nullptr; + if (animate) texnum = Translation[texnum.GetIndex()]; + texnum = PalCheck(texnum).GetIndex(); return Textures[texnum.GetIndex()].Texture; } - FTexture *ByIndex(int i) + + FTexture *ByIndex(int i, bool animate = false) { if (unsigned(i) >= Textures.Size()) return NULL; + if (animate) i = Translation[i]; return Textures[i].Texture; } FTexture *FindTexture(const char *texname, ETextureType usetype = ETextureType::MiscPatch, BITFIELD flags = TEXMAN_TryAny); - // Get texture with translation - FTexture *operator() (FTextureID texnum, bool withpalcheck=false) - { - if ((size_t)texnum.texnum >= Textures.Size()) return NULL; - int picnum = Translation[texnum.texnum]; - if (withpalcheck) - { - picnum = PalCheck(picnum).GetIndex(); - } - return Textures[picnum].Texture; - } - FTexture *operator() (const char *texname) - { - FTextureID texnum = GetTexture (texname, ETextureType::MiscPatch); - if (texnum.texnum == -1) return NULL; - return Textures[Translation[texnum.texnum]].Texture; - } + void FlushAll(); + - FTexture *ByIndexTranslated(int i) - { - if (unsigned(i) >= Textures.Size()) return NULL; - return Textures[Translation[i]].Texture; - } //public: FTextureID PalCheck(FTextureID tex); @@ -581,17 +595,14 @@ public: }; FTextureID CheckForTexture (const char *name, ETextureType usetype, BITFIELD flags=TEXMAN_TryAny); - FTextureID GetTexture (const char *name, ETextureType usetype, BITFIELD flags=0); + FTextureID GetTextureID (const char *name, ETextureType usetype, BITFIELD flags=0); int ListTextures (const char *name, TArray &list, bool listall = false); - void AddTexturesLump (const void *lumpdata, int lumpsize, int deflumpnum, int patcheslump, int firstdup=0, bool texture1=false); - void AddTexturesLumps (int lump1, int lump2, int patcheslump); void AddGroup(int wadnum, int ns, ETextureType usetype); void AddPatches (int lumpnum); void AddHiresTextures (int wadnum); - void LoadTextureDefs(int wadnum, const char *lumpname); - void ParseTextureDef(int remapLump); - void ParseXTexture(FScanner &sc, ETextureType usetype); + void LoadTextureDefs(int wadnum, const char *lumpname, FMultipatchTextureBuilder &build); + void ParseTextureDef(int remapLump, FMultipatchTextureBuilder &build); void SortTexturesByType(int start, int end); bool AreTexturesCompatible (FTextureID picnum1, FTextureID picnum2); @@ -599,23 +610,14 @@ public: FTextureID AddTexture (FTexture *texture); FTextureID GetDefaultTexture() const { return DefaultTexture; } - void LoadTextureX(int wadnum); - void AddTexturesForWad(int wadnum); + void LoadTextureX(int wadnum, FMultipatchTextureBuilder &build); + void AddTexturesForWad(int wadnum, FMultipatchTextureBuilder &build); void Init(); void DeleteAll(); void SpriteAdjustChanged(); - // Replaces one texture with another. The new texture will be assigned - // the same name, slot, and use type as the texture it is replacing. - // The old texture will no longer be managed. Set free true if you want - // the old texture to be deleted or set it false if you want it to - // be left alone in memory. You will still need to delete it at some - // point, because the texture manager no longer knows about it. - // This function can be used for such things as warping textures. void ReplaceTexture (FTextureID picnum, FTexture *newtexture, bool free); - void UnloadAll (); - int NumTextures () const { return (int)Textures.Size(); } void UpdateAnimations (uint64_t mstime); @@ -677,11 +679,12 @@ private: TArray FirstTextureForFile; TArray > BuildTileData; - TArray mAnimations; TArray mSwitchDefs; TArray mAnimatedDoors; public: + TArray mAnimations; + bool HasGlobalBrightmap; FRemapTable GlobalBrightmap; short sintable[2048]; // for texture warping @@ -697,61 +700,6 @@ public: }; -// base class for everything that can be used as a world texture. -// This intermediate class encapsulates the buffers for the software renderer. -class FWorldTexture : public FTexture -{ -protected: - uint8_t *Pixeldata[2] = { nullptr, nullptr }; - Span **Spandata[2] = { nullptr, nullptr }; - uint8_t PixelsAreStatic = 0; // can be set by subclasses which provide static pixel buffers. - - FWorldTexture(const char *name = nullptr, int lumpnum = -1); - ~FWorldTexture(); - - const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out) override; - const uint8_t *GetPixels(FRenderStyle style) override; - void Unload() override; - virtual uint8_t *MakeTexture(FRenderStyle style) = 0; - void FreeAllSpans(); -}; - -// A texture that doesn't really exist -class FDummyTexture : public FTexture -{ -public: - FDummyTexture (); - void SetSize (int width, int height); -}; - -// A texture that returns a wiggly version of another texture. -class FWarpTexture : public FWorldTexture -{ -public: - FWarpTexture (FTexture *source, int warptype); - ~FWarpTexture (); - void Unload() override; - - virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0, FCopyInfo *inf = NULL) override; - virtual int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf = NULL) override; - const uint32_t *GetPixelsBgra() override; - bool CheckModified (FRenderStyle) override; - - float GetSpeed() const { return Speed; } - int GetSourceLump() { return SourcePic->GetSourceLump(); } - void SetSpeed(float fac) { Speed = fac; } - - uint64_t GenTime[2] = { 0, 0 }; - uint64_t GenTimeBgra = 0; - float Speed = 1.f; - int WidthOffsetMultiplier, HeightOffsetMultiplier; // [mxd] -protected: - FTexture *SourcePic; - - uint8_t *MakeTexture (FRenderStyle style) override; - int NextPo2 (int v); // [mxd] - void SetupMultipliers (int width, int height); // [mxd] -}; // A texture that can be drawn to. class DCanvas; @@ -760,36 +708,28 @@ class AActor; class FCanvasTexture : public FTexture { public: - FCanvasTexture (const char *name, int width, int height); - ~FCanvasTexture (); + FCanvasTexture(const char *name, int width, int height) + { + Name = name; + Width = width; + Height = height; - const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out); - const uint8_t *GetPixels (FRenderStyle style); - const uint32_t *GetPixelsBgra() override; - void Unload (); - bool CheckModified (FRenderStyle) override; - void NeedUpdate() { bNeedsUpdate=true; } - void SetUpdated() { bNeedsUpdate = false; bDidUpdate = true; bFirstUpdate = false; } - DCanvas *GetCanvas() { return Canvas; } - DCanvas *GetCanvasBgra() { return CanvasBgra; } - bool Mipmapped() override { return false; } - void MakeTexture (FRenderStyle style); - void MakeTextureBgra (); + bMasked = false; + bHasCanvas = true; + bTranslucent = false; + bNoExpand = true; + UseType = ETextureType::Wall; + } + + void NeedUpdate() { bNeedsUpdate = true; } + void SetUpdated(bool rendertype) { bNeedsUpdate = false; bFirstUpdate = false; bLastUpdateType = rendertype; } protected: - DCanvas *Canvas = nullptr; - DCanvas *CanvasBgra = nullptr; - uint8_t *Pixels = nullptr; - uint32_t *PixelsBgra = nullptr; - Span DummySpans[2]; + bool bLastUpdateType = false; bool bNeedsUpdate = true; - bool bDidUpdate = false; - bool bPixelsAllocated = false; - bool bPixelsAllocatedBgra = false; public: - bool bFirstUpdate; - + bool bFirstUpdate = true; friend struct FCanvasTextureInfo; }; @@ -797,8 +737,18 @@ public: // A wrapper around a hardware texture, to allow using it in the 2D drawing interface. class FWrapperTexture : public FTexture { + int Format; public: FWrapperTexture(int w, int h, int bits = 1); + IHardwareTexture *GetSystemTexture() + { + return SystemTextures.GetHardwareTexture(0, false); + } + + int GetColorFormat() const + { + return Format; + } }; extern FTextureManager TexMan; @@ -821,6 +771,7 @@ struct FTexCoordInfo }; + #endif diff --git a/src/v_2ddrawer.cpp b/src/v_2ddrawer.cpp index 6b4305de9..7b3fa1963 100644 --- a/src/v_2ddrawer.cpp +++ b/src/v_2ddrawer.cpp @@ -125,7 +125,6 @@ void F2DDrawer::AddIndices(int firstvert, int count, ...) bool F2DDrawer::SetStyle(FTexture *tex, DrawParms &parms, PalEntry &vertexcolor, RenderCommand &quad) { - auto fmt = tex->GetFormat(); FRenderStyle style = parms.style; float alpha; bool stencilling; @@ -298,12 +297,12 @@ void F2DDrawer::AddTexture(FTexture *img, DrawParms &parms) dg.mType = DrawTypeTriangles; dg.mVertCount = 4; dg.mTexture = img; - if (img->bWarped) dg.mFlags |= DTF_Wrap; + if (img->isWarped()) dg.mFlags |= DTF_Wrap; dg.mTranslation = 0; SetStyle(img, parms, vertexcolor, dg); - if (!img->bHasCanvas && parms.remap != nullptr && !parms.remap->Inactive) + if (!img->isHardwareCanvas() && parms.remap != nullptr && !parms.remap->Inactive) { dg.mTranslation = parms.remap; } @@ -378,7 +377,7 @@ void F2DDrawer::AddShape( FTexture *img, DShape2D *shape, DrawParms &parms ) dg.mTranslation = 0; SetStyle(img, parms, vertexcolor, dg); - if (!img->bHasCanvas && parms.remap != nullptr && !parms.remap->Inactive) + if (!img->isHardwareCanvas() && parms.remap != nullptr && !parms.remap->Inactive) dg.mTranslation = parms.remap; double minx = 16383, miny = 16383, maxx = -16384, maxy = -16384; @@ -430,7 +429,7 @@ void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, double fadelevel; // The hardware renderer's light modes 0, 1 and 4 use a linear light scale which must be used here as well. Otherwise the automap gets too dark. - if (vid_rendermode != 4 || (level.lightmode >= 2 && level.lightmode != 4)) + if (vid_rendermode != 4 || level.isDarkLightMode() || level.isSoftwareLighting()) { double map = (NUMCOLORMAPS * 2.) - ((lightlevel + 12) * (NUMCOLORMAPS / 128.)); fadelevel = clamp((map - 12) / NUMCOLORMAPS, 0.0, 1.0); @@ -466,8 +465,8 @@ void F2DDrawer::AddPoly(FTexture *texture, FVector2 *points, int npoints, float cosrot = (float)cos(rotation.Radians()); float sinrot = (float)sin(rotation.Radians()); - float uscale = float(1.f / (texture->GetScaledWidth() * scalex)); - float vscale = float(1.f / (texture->GetScaledHeight() * scaley)); + float uscale = float(1.f / (texture->GetDisplayWidth() * scalex)); + float vscale = float(1.f / (texture->GetDisplayHeight() * scaley)); float ox = float(originx); float oy = float(originy); @@ -529,17 +528,17 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FTexture * // scaling is not used here. if (!local_origin) { - fU1 = float(left) / src->GetWidth(); - fV1 = float(top) / src->GetHeight(); - fU2 = float(right) / src->GetWidth(); - fV2 = float(bottom) / src->GetHeight(); + fU1 = float(left) / src->GetDisplayWidth(); + fV1 = float(top) / src->GetDisplayHeight(); + fU2 = float(right) / src->GetDisplayWidth(); + fV2 = float(bottom) / src->GetDisplayHeight(); } else { fU1 = 0; fV1 = 0; - fU2 = float(right - left) / src->GetWidth(); - fV2 = float(bottom - top) / src->GetHeight(); + fU2 = float(right - left) / src->GetDisplayWidth(); + fV2 = float(bottom - top) / src->GetDisplayHeight(); } dg.mVertIndex = (int)mVertices.Reserve(4); auto ptr = &mVertices[dg.mVertIndex]; diff --git a/src/v_collection.cpp b/src/v_collection.cpp index 95f35097a..053eeec45 100644 --- a/src/v_collection.cpp +++ b/src/v_collection.cpp @@ -77,5 +77,5 @@ FTexture *FImageCollection::operator[] (int index) const { return NULL; } - return ImageMap[index].Exists()? TexMan(ImageMap[index]) : NULL; + return ImageMap[index].Exists()? TexMan.GetPalettedTexture(ImageMap[index], true) : NULL; } diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 80f51f141..442705e71 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -175,7 +175,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)]; + FTexture *tex = TexMan.ByIndex(texid, animate); VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; screen->DrawTexture(tex, x, y, args); return 0; @@ -231,7 +231,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShape) if (!screen->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function"); - FTexture *tex = animate ? TexMan(FSetTextureID(texid)) : TexMan[FSetTextureID(texid)]; + FTexture *tex = TexMan.ByIndex(texid, animate); VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 }; screen->DrawShape(tex, shape, args); @@ -312,23 +312,23 @@ bool DFrameBuffer::SetTextureParms(DrawParms *parms, FTexture *img, double xx, d { parms->x = xx; parms->y = yy; - parms->texwidth = img->GetScaledWidthDouble(); - parms->texheight = img->GetScaledHeightDouble(); + parms->texwidth = img->GetDisplayWidthDouble(); + parms->texheight = img->GetDisplayHeightDouble(); if (parms->top == INT_MAX || parms->fortext) { - parms->top = img->GetScaledTopOffset(0); + parms->top = img->GetDisplayTopOffset(); } if (parms->left == INT_MAX || parms->fortext) { - parms->left = img->GetScaledLeftOffset(0); + parms->left = img->GetDisplayLeftOffset(); } if (parms->destwidth == INT_MAX || parms->fortext) { - parms->destwidth = img->GetScaledWidthDouble(); + parms->destwidth = img->GetDisplayWidthDouble(); } if (parms->destheight == INT_MAX || parms->fortext) { - parms->destheight = img->GetScaledHeightDouble(); + parms->destheight = img->GetDisplayHeightDouble(); } switch (parms->cleanmode) @@ -470,7 +470,7 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 if (!fortext) { - if (img == NULL || img->UseType == ETextureType::Null) + if (img == NULL || !img->isValid()) { ListEnd(tags); return false; @@ -650,8 +650,8 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 assert(fortext == false); if (img == NULL) return false; parms->cleanmode = DTA_Fullscreen; - parms->virtWidth = img->GetScaledWidthDouble(); - parms->virtHeight = img->GetScaledHeightDouble(); + parms->virtWidth = img->GetDisplayWidthDouble(); + parms->virtHeight = img->GetDisplayHeightDouble(); } break; @@ -697,19 +697,19 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 break; case DTA_SrcX: - parms->srcx = ListGetDouble(tags) / img->GetScaledWidthDouble(); + parms->srcx = ListGetDouble(tags) / img->GetDisplayWidthDouble(); break; case DTA_SrcY: - parms->srcy = ListGetDouble(tags) / img->GetScaledHeightDouble(); + parms->srcy = ListGetDouble(tags) / img->GetDisplayHeightDouble(); break; case DTA_SrcWidth: - parms->srcwidth = ListGetDouble(tags) / img->GetScaledWidthDouble(); + parms->srcwidth = ListGetDouble(tags) / img->GetDisplayWidthDouble(); break; case DTA_SrcHeight: - parms->srcheight = ListGetDouble(tags) / img->GetScaledHeightDouble(); + parms->srcheight = ListGetDouble(tags) / img->GetDisplayHeightDouble(); break; case DTA_TopOffset: @@ -741,8 +741,8 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 if (fortext) return false; if (ListGetInt(tags)) { - parms->left = img->GetScaledWidthDouble() * 0.5; - parms->top = img->GetScaledHeightDouble() * 0.5; + parms->left = img->GetDisplayWidthDouble() * 0.5; + parms->top = img->GetDisplayHeightDouble() * 0.5; } break; @@ -751,8 +751,8 @@ bool DFrameBuffer::ParseDrawTextureTags(FTexture *img, double x, double y, uint3 if (fortext) return false; if (ListGetInt(tags)) { - parms->left = img->GetScaledWidthDouble() * 0.5; - parms->top = img->GetScaledHeightDouble(); + parms->left = img->GetDisplayWidthDouble() * 0.5; + parms->top = img->GetDisplayHeightDouble(); } break; @@ -1304,22 +1304,22 @@ void DFrameBuffer::DrawFrame (int left, int top, int width, int height) int bottom = top + height; // Draw top and bottom sides. - p = TexMan[border->t]; - FlatFill(left, top - p->GetHeight(), right, top, p, true); - p = TexMan[border->b]; - FlatFill(left, bottom, right, bottom + p->GetHeight(), p, true); + p = TexMan.GetTextureByName(border->t); + FlatFill(left, top - p->GetDisplayHeight(), right, top, p, true); + p = TexMan.GetTextureByName(border->b); + FlatFill(left, bottom, right, bottom + p->GetDisplayHeight(), p, true); // Draw left and right sides. - p = TexMan[border->l]; - FlatFill(left - p->GetWidth(), top, left, bottom, p, true); - p = TexMan[border->r]; - FlatFill(right, top, right + p->GetWidth(), bottom, p, true); + p = TexMan.GetTextureByName(border->l); + FlatFill(left - p->GetDisplayWidth(), top, left, bottom, p, true); + p = TexMan.GetTextureByName(border->r); + FlatFill(right, top, right + p->GetDisplayWidth(), bottom, p, true); // Draw beveled corners. - DrawTexture (TexMan[border->tl], left-offset, top-offset, TAG_DONE); - DrawTexture (TexMan[border->tr], left+width, top-offset, TAG_DONE); - DrawTexture (TexMan[border->bl], left-offset, top+height, TAG_DONE); - DrawTexture (TexMan[border->br], left+width, top+height, TAG_DONE); + DrawTexture (TexMan.GetTextureByName(border->tl), left-offset, top-offset, TAG_DONE); + DrawTexture (TexMan.GetTextureByName(border->tr), left+width, top-offset, TAG_DONE); + DrawTexture (TexMan.GetTextureByName(border->bl), left-offset, top+height, TAG_DONE); + DrawTexture (TexMan.GetTextureByName(border->br), left+width, top+height, TAG_DONE); } DEFINE_ACTION_FUNCTION(_Screen, DrawFrame) @@ -1354,7 +1354,7 @@ void DFrameBuffer::DrawBorder (int x1, int y1, int x2, int y2) if (picnum.isValid()) { - FlatFill (x1, y1, x2, y2, TexMan(picnum)); + FlatFill (x1, y1, x2, y2, TexMan.GetTexture(picnum, false)); } else { diff --git a/src/v_font.cpp b/src/v_font.cpp index eed94341b..da3335236 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -90,13 +90,15 @@ The FON2 header is followed by variable length data: #include "gstrings.h" #include "v_text.h" #include "vm.h" +#include "image.h" +#include "textures/formats/fontchars.h" // MACROS ------------------------------------------------------------------ #define DEFAULT_LOG_COLOR PalEntry(223,223,223) // TYPES ------------------------------------------------------------------- -void RecordTextureColors (FTexture *pic, uint8_t *colorsused); +void RecordTextureColors (FImageSource *pic, uint8_t *colorsused); // This structure is used by BuildTranslations() to hold color information. struct TranslationParm @@ -147,7 +149,7 @@ public: FSinglePicFont(const char *picname); // FFont interface - FTexture *GetChar (int code, int *const width) const; + FTexture *GetChar(int code, int translation, int *const width, bool *redirected = nullptr) const override; int GetCharWidth (int code) const; protected: @@ -166,47 +168,6 @@ protected: bool notranslate[256]; }; -// This is a font character that loads a texture and recolors it. -class FFontChar1 : public FTexture -{ -public: - FFontChar1 (FTexture *sourcelump); - const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out); - const uint8_t *GetPixels (FRenderStyle style); - void SetSourceRemap(const uint8_t *sourceremap); - void Unload (); - ~FFontChar1 (); - -protected: - void MakeTexture (); - - FTexture *BaseTexture; - uint8_t *Pixels; - const uint8_t *SourceRemap; -}; - -// This is a font character that reads RLE compressed data. -class FFontChar2 : public FTexture -{ -public: - FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0); - ~FFontChar2 (); - - const uint8_t *GetColumn(FRenderStyle style, unsigned int column, const Span **spans_out); - const uint8_t *GetPixels (FRenderStyle style); - void SetSourceRemap(const uint8_t *sourceremap); - void Unload (); - -protected: - int SourceLump; - int SourcePos; - uint8_t *Pixels; - Span **Spans; - const uint8_t *SourceRemap; - - void MakeTexture (); -}; - struct TempParmInfo { unsigned int StartParm[2]; @@ -234,7 +195,7 @@ extern int PrintColors[]; // PUBLIC DATA DEFINITIONS ------------------------------------------------- -FFont *FFont::FirstFont = NULL; +FFont *FFont::FirstFont = nullptr; int NumTextColors; // PRIVATE DATA DEFINITIONS ------------------------------------------------ @@ -305,7 +266,7 @@ static int stripaccent(int code) FFont *V_GetFont(const char *name) { FFont *font = FFont::FindFont (name); - if (font == NULL) + if (font == nullptr) { int lump = -1; @@ -324,7 +285,7 @@ FFont *V_GetFont(const char *name) font = new FSingleLumpFont (name, lump); } } - if (font == NULL) + if (font == nullptr) { FTextureID picnum = TexMan.CheckForTexture (name, ETextureType::Any); if (picnum.isValid()) @@ -349,16 +310,14 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, int i; FTextureID lump; char buffer[12]; - TArray charLumps; + TArray charLumps(count, true); int maxyoffs; bool doomtemplate = gameinfo.gametype & GAME_DoomChex ? strncmp (nametemplate, "STCFN", 5) == 0 : false; bool stcfn121 = false; noTranslate = notranslate; Lump = fdlump; - Chars = new CharData[count]; - charLumps.Resize(count); - PatchRemap = new uint8_t[256]; + Chars.Resize(count); FirstChar = first; LastChar = first + count - 1; FontHeight = 0; @@ -368,12 +327,15 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, FirstFont = this; Cursor = '_'; ActiveColors = 0; + uint8_t pp = 0; + for (auto &p : PatchRemap) p = pp++; + translateUntranslated = false; maxyoffs = 0; for (i = 0; i < count; i++) { - charLumps[i] = NULL; + charLumps[i] = nullptr; mysnprintf (buffer, countof(buffer), nametemplate, i + start); lump = TexMan.CheckForTexture(buffer, ETextureType::MiscPatch); @@ -387,7 +349,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, !TexMan.CheckForTexture("STCFN122", ETextureType::MiscPatch).isValid()) { // insert the incorrectly named '|' graphic in its correct position. - if (count > 124-start) charLumps[124-start] = TexMan[lump]; + if (count > 124-start) charLumps[124-start] = TexMan.GetTexture(lump); lump.SetInvalid(); stcfn121 = true; } @@ -395,15 +357,15 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, if (lump.isValid()) { - FTexture *pic = TexMan[lump]; - if (pic != NULL) + FTexture *pic = TexMan.GetTexture(lump); + if (pic != nullptr) { // set the lump here only if it represents a valid texture if (i != 124-start || !stcfn121) charLumps[i] = pic; - int height = pic->GetScaledHeight(); - int yoffs = pic->GetScaledTopOffset(0); + int height = pic->GetDisplayHeight(); + int yoffs = pic->GetDisplayTopOffset(); if (yoffs > maxyoffs) { @@ -419,13 +381,19 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, if (charLumps[i] != nullptr) { - if (!noTranslate) Chars[i].Pic = new FFontChar1 (charLumps[i]); - else Chars[i].Pic = charLumps[i]; - Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); + if (!noTranslate) + { + Chars[i].OriginalPic = charLumps[i]; + Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charLumps[i]->GetImage()), ""); + TexMan.AddTexture(Chars[i].TranslatedPic); + } + else Chars[i].TranslatedPic = charLumps[i]; + + Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); } else { - Chars[i].Pic = NULL; + Chars[i].TranslatedPic = nullptr; Chars[i].XMove = INT_MIN; } } @@ -434,7 +402,7 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, { SpaceWidth = spacewidth; } - else if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL) + else if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr) { SpaceWidth = (Chars['N' - first].XMove + 1) / 2; } @@ -456,40 +424,16 @@ FFont::FFont (const char *name, const char *nametemplate, int first, int count, FFont::~FFont () { - if (Chars) - { - int count = LastChar - FirstChar + 1; - - // A noTranslate font directly references the original textures. - if (!noTranslate) - { - for (int i = 0; i < count; ++i) - { - if (Chars[i].Pic != NULL && Chars[i].Pic->Name[0] == 0) - { - delete Chars[i].Pic; - } - } - } - delete[] Chars; - Chars = NULL; - } - if (PatchRemap) - { - delete[] PatchRemap; - PatchRemap = NULL; - } - FFont **prev = &FirstFont; FFont *font = *prev; - while (font != NULL && font != this) + while (font != nullptr && font != this) { prev = &font->Next; font = *prev; } - if (font != NULL) + if (font != nullptr) { *prev = font->Next; } @@ -529,27 +473,16 @@ FFont *FFont::FindFont (FName name) // //========================================================================== -void RecordTextureColors (FTexture *pic, uint8_t *usedcolors) +void RecordTextureColors (FImageSource *pic, uint8_t *usedcolors) { int x; - - for (x = pic->GetWidth() - 1; x >= 0; x--) + + auto pixels = pic->GetPalettedPixels(false); + auto size = pic->GetWidth() * pic->GetHeight(); + + for(x = 0;x < size; x++) { - const FTexture::Span *spans; - const uint8_t *column = pic->GetColumn(DefaultRenderStyle(), x, &spans); // This shouldn't use the spans... - - while (spans->Length != 0) - { - const uint8_t *source = column + spans->TopOffset; - int count = spans->Length; - - do - { - usedcolors[*source++] = 1; - } while (--count); - - spans++; - } + usedcolors[pixels[x]]++; } } @@ -593,7 +526,7 @@ static int compare (const void *arg1, const void *arg2) // //========================================================================== -int FFont::SimpleTranslation (uint8_t *colorsused, uint8_t *translation, uint8_t *reverse, double **luminosity) +int FFont::SimpleTranslation (uint8_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray &Luminosity) { double min, max, diver; int i, j; @@ -611,26 +544,26 @@ int FFont::SimpleTranslation (uint8_t *colorsused, uint8_t *translation, uint8_t qsort (reverse+1, j-1, 1, compare); - *luminosity = new double[j]; - (*luminosity)[0] = 0.0; // [BL] Prevent uninitalized memory + Luminosity.Resize(j); + Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory max = 0.0; min = 100000000.0; for (i = 1; i < j; i++) { translation[reverse[i]] = i; - (*luminosity)[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 + + Luminosity[i] = RPART(GPalette.BaseColors[reverse[i]]) * 0.299 + GPART(GPalette.BaseColors[reverse[i]]) * 0.587 + BPART(GPalette.BaseColors[reverse[i]]) * 0.114; - if ((*luminosity)[i] > max) - max = (*luminosity)[i]; - if ((*luminosity)[i] < min) - min = (*luminosity)[i]; + if (Luminosity[i] > max) + max = Luminosity[i]; + if (Luminosity[i] < min) + min = Luminosity[i]; } diver = 1.0 / (max - min); for (i = 1; i < j; i++) { - (*luminosity)[i] = ((*luminosity)[i] - min) * diver; + Luminosity[i] = (Luminosity[i] - min) * diver; } return j; @@ -664,10 +597,10 @@ void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity { if (i == CR_UNTRANSLATED) { - if (identity != NULL) + if (identity != nullptr) { memcpy (remap.Remap, identity, ActiveColors); - if (palette != NULL) + if (palette != nullptr) { memcpy (remap.Palette, palette, ActiveColors*sizeof(PalEntry)); } @@ -748,9 +681,10 @@ FRemapTable *FFont::GetColorTranslation (EColorRange range, PalEntry *color) con if (color != nullptr) *color = retcolor; } if (ActiveColors == 0) - return NULL; + return nullptr; else if (range >= NumTextColors) range = CR_UNTRANSLATED; + //if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr; return &Ranges[range]; } @@ -771,7 +705,7 @@ int FFont::GetCharCode(int code, bool needpic) const // regular chars turn negative when the 8th bit is set. code &= 255; } - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) { return code; } @@ -779,7 +713,7 @@ int FFont::GetCharCode(int code, bool needpic) const if (myislower(code)) { code -= 32; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) { return code; } @@ -789,7 +723,7 @@ int FFont::GetCharCode(int code, bool needpic) const if (newcode != code) { code = newcode; - if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].Pic != NULL)) + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) { return code; } @@ -803,7 +737,7 @@ int FFont::GetCharCode(int code, bool needpic) const // //========================================================================== -FTexture *FFont::GetChar (int code, int *const width) const +FTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const { code = GetCharCode(code, false); int xmove = SpaceWidth; @@ -812,7 +746,7 @@ FTexture *FFont::GetChar (int code, int *const width) const { code -= FirstChar; xmove = Chars[code].XMove; - if (Chars[code].Pic == NULL) + if (Chars[code].TranslatedPic == nullptr) { code = GetCharCode(code + FirstChar, true); if (code >= 0) @@ -822,11 +756,22 @@ FTexture *FFont::GetChar (int code, int *const width) const } } } - if (width != NULL) + if (width != nullptr) { *width = xmove; } - return (code < 0) ? NULL : Chars[code].Pic; + if (code < 0) return nullptr; + + + if (translation == CR_UNTRANSLATED) + { + bool redirect = Chars[code].OriginalPic && Chars[code].OriginalPic != Chars[code].TranslatedPic; + if (redirected) *redirected = redirect; + if (redirect) + return Chars[code].OriginalPic; + } + if (redirected) *redirected = false; + return Chars[code].TranslatedPic; } //========================================================================== @@ -850,11 +795,11 @@ int FFont::GetCharWidth (int code) const double GetBottomAlignOffset(FFont *font, int c) { int w; - FTexture *tex_zero = font->GetChar('0', &w); - FTexture *texc = font->GetChar(c, &w); + FTexture *tex_zero = font->GetChar('0', CR_UNDEFINED, &w); + FTexture *texc = font->GetChar(c, CR_UNDEFINED, &w); double offset = 0; - if (texc) offset += texc->GetScaledTopOffsetDouble(0); - if (tex_zero) offset += -tex_zero->GetScaledTopOffsetDouble(0) + tex_zero->GetScaledHeightDouble(); + if (texc) offset += texc->GetDisplayTopOffsetDouble(); + if (tex_zero) offset += -tex_zero->GetDisplayTopOffsetDouble() + tex_zero->GetDisplayHeightDouble(); return offset; } @@ -913,30 +858,33 @@ void FFont::LoadTranslations() { unsigned int count = LastChar - FirstChar + 1; uint8_t usedcolors[256], identity[256]; - double *luminosity; + TArray Luminosity; memset (usedcolors, 0, 256); for (unsigned int i = 0; i < count; i++) { - FFontChar1 *pic = static_cast(Chars[i].Pic); - if(pic) + if (Chars[i].TranslatedPic) { - pic->SetSourceRemap(NULL); // Force the FFontChar1 to return the same pixels as the base texture - RecordTextureColors (pic, usedcolors); + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + if (pic) + { + pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture + RecordTextureColors(pic, usedcolors); + } } } - ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity); + // Fixme: This needs to build a translation based on the source palette, not some intermediate 'ordered' table. + + ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); for (unsigned int i = 0; i < count; i++) { - if(Chars[i].Pic) - static_cast(Chars[i].Pic)->SetSourceRemap(PatchRemap); + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); } - BuildTranslations (luminosity, identity, &TranslationParms[0][0], ActiveColors, NULL); - - delete[] luminosity; + BuildTranslations (Luminosity.Data(), identity, &TranslationParms[0][0], ActiveColors, nullptr); } //========================================================================== @@ -948,11 +896,11 @@ void FFont::LoadTranslations() FFont::FFont (int lump) { Lump = lump; - Chars = NULL; - PatchRemap = NULL; FontName = NAME_None; Cursor = '_'; noTranslate = false; + uint8_t pp = 0; + for (auto &p : PatchRemap) p = pp++; } //========================================================================== @@ -1007,15 +955,15 @@ FSingleLumpFont::FSingleLumpFont (const char *name, int lump) : FFont(lump) void FSingleLumpFont::CreateFontFromPic (FTextureID picnum) { - FTexture *pic = TexMan[picnum]; + FTexture *pic = TexMan.GetTexture(picnum); - FontHeight = pic->GetHeight (); - SpaceWidth = pic->GetWidth (); + FontHeight = pic->GetDisplayHeight (); + SpaceWidth = pic->GetDisplayWidth (); GlobalKerning = 0; FirstChar = LastChar = 'A'; - Chars = new CharData[1]; - Chars->Pic = pic; + Chars.Resize(1); + Chars[0].TranslatedPic = pic; // Only one color range. Don't bother with the others. ActiveColors = 0; @@ -1061,11 +1009,11 @@ void FSingleLumpFont::LoadTranslations() for(unsigned int i = 0;i < count;++i) { - if(Chars[i].Pic) - static_cast(Chars[i].Pic)->SetSourceRemap(PatchRemap); + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); } - BuildTranslations (luminosity, useidentity ? identity : NULL, ranges, ActiveColors, usepalette ? local_palette : NULL); + BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr); } //========================================================================== @@ -1080,7 +1028,7 @@ void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) { int w, h; - Chars = new CharData[256]; + Chars.Resize(256); w = data[4] + data[5]*256; h = data[6] + data[7]*256; @@ -1091,11 +1039,7 @@ void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) FirstChar = 0; LastChar = 255; GlobalKerning = 0; - PatchRemap = new uint8_t[256]; - - for(unsigned int i = 0;i < 256;++i) - Chars[i].Pic = NULL; - + translateUntranslated = true; LoadTranslations(); } @@ -1111,7 +1055,6 @@ void FSingleLumpFont::LoadFON1 (int lump, const uint8_t *data) void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) { int count, i, totalwidth; - int *widths2; uint16_t *widths; const uint8_t *palette; const uint8_t *data_p; @@ -1121,12 +1064,11 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) FirstChar = data[6]; LastChar = data[7]; ActiveColors = data[10]+1; - PatchRemap = NULL; RescalePalette = data[9] == 0; count = LastChar - FirstChar + 1; - Chars = new CharData[count]; - widths2 = new int[count]; + Chars.Resize(count); + TArray widths2(count, true); if (data[11] & 1) { // Font specifies a kerning value. GlobalKerning = LittleShort(*(int16_t *)&data[12]); @@ -1182,11 +1124,12 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) Chars[i].XMove = widths2[i]; if (destSize <= 0) { - Chars[i].Pic = NULL; + Chars[i].TranslatedPic = nullptr; } else { - Chars[i].Pic = new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight); + Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight)); + TexMan.AddTexture(Chars[i].TranslatedPic); do { int8_t code = *data_p++; @@ -1210,7 +1153,6 @@ void FSingleLumpFont::LoadFON2 (int lump, const uint8_t *data) } LoadTranslations(); - delete[] widths2; } //========================================================================== @@ -1269,13 +1211,7 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) I_FatalError("BMF font defines no characters"); } count = LastChar - FirstChar + 1; - Chars = new CharData[count]; - for (i = 0; i < count; ++i) - { - Chars[i].Pic = NULL; - Chars[i].XMove = INT_MIN; - } - + Chars.Resize(count); // BMF palettes are only six bits per component. Fix that. for (i = 0; i < ActiveColors*3; ++i) { @@ -1295,7 +1231,6 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare); // Create the PatchRemap table from the sorted "alpha" values. - PatchRemap = new uint8_t[ActiveColors]; PatchRemap[0] = 0; for (i = 1; i < ActiveColors; ++i) { @@ -1322,12 +1257,14 @@ void FSingleLumpFont::LoadBMF(int lump, const uint8_t *data) { // Empty character: skip it. continue; } - Chars[chardata[chari] - FirstChar].Pic = new FFontChar2(lump, int(chardata + chari + 6 - data), + auto tex = new FImageTexture(new FFontChar2(lump, int(chardata + chari + 6 - data), chardata[chari+1], // width chardata[chari+2], // height -(int8_t)chardata[chari+3], // x offset -(int8_t)chardata[chari+4] // y offset - ); + )); + Chars[chardata[chari] - FirstChar].TranslatedPic = tex; + TexMan.AddTexture(tex); } // If the font did not define a space character, determine a suitable space width now. @@ -1390,10 +1327,11 @@ void FSingleLumpFont::CheckFON1Chars (double *luminosity) { int destSize = SpaceWidth * FontHeight; - if(!Chars[i].Pic) + if(!Chars[i].TranslatedPic) { - Chars[i].Pic = new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight); + Chars[i].TranslatedPic = new FImageTexture(new FFontChar2 (Lump, int(data_p - data), SpaceWidth, FontHeight)); Chars[i].XMove = SpaceWidth; + TexMan.AddTexture(Chars[i].TranslatedPic); } // Advance to next char's data and count the used colors. @@ -1505,11 +1443,11 @@ FSinglePicFont::FSinglePicFont(const char *picname) : I_FatalError ("%s is not a font or texture", picname); } - FTexture *pic = TexMan[picnum]; + FTexture *pic = TexMan.GetTexture(picnum); FontName = picname; - FontHeight = pic->GetScaledHeight(); - SpaceWidth = pic->GetScaledWidth(); + FontHeight = pic->GetDisplayHeight(); + SpaceWidth = pic->GetDisplayWidth(); GlobalKerning = 0; FirstChar = LastChar = 'A'; ActiveColors = 0; @@ -1523,20 +1461,21 @@ FSinglePicFont::FSinglePicFont(const char *picname) : // // FSinglePicFont :: GetChar // -// Returns the texture if code is 'a' or 'A', otherwise NULL. +// Returns the texture if code is 'a' or 'A', otherwise nullptr. // //========================================================================== -FTexture *FSinglePicFont::GetChar (int code, int *const width) const +FTexture *FSinglePicFont::GetChar (int code, int translation, int *const width, bool *redirected) const { *width = SpaceWidth; + if (redirected) *redirected = false; if (code == 'a' || code == 'A') { - return TexMan(PicNum); + return TexMan.GetPalettedTexture(PicNum, true); } else { - return NULL; + return nullptr; } } @@ -1554,365 +1493,17 @@ int FSinglePicFont::GetCharWidth (int code) const return SpaceWidth; } -//========================================================================== -// -// FFontChar1 :: FFontChar1 -// -// Used by fonts made from textures. -// -//========================================================================== - -FFontChar1::FFontChar1 (FTexture *sourcelump) -: SourceRemap (NULL) -{ - UseType = ETextureType::FontChar; - BaseTexture = sourcelump; - - // now copy all the properties from the base texture - assert(BaseTexture != NULL); - CopySize(BaseTexture); - Pixels = NULL; -} - -//========================================================================== -// -// FFontChar1 :: GetPixels -// -// Render style is not relevant for fonts. This must not use it! -// -//========================================================================== - -const uint8_t *FFontChar1::GetPixels (FRenderStyle) -{ - if (Pixels == NULL) - { - MakeTexture (); - } - return Pixels; -} - -//========================================================================== -// -// FFontChar1 :: MakeTexture -// -//========================================================================== - -void FFontChar1::MakeTexture () -{ - // Make the texture as normal, then remap it so that all the colors - // are at the low end of the palette - Pixels = new uint8_t[Width*Height]; - const uint8_t *pix = BaseTexture->GetPixels(DefaultRenderStyle()); - - if (!SourceRemap) - { - memcpy(Pixels, pix, Width*Height); - } - else - { - for (int x = 0; x < Width*Height; ++x) - { - Pixels[x] = SourceRemap[pix[x]]; - } - } -} - -//========================================================================== -// -// FFontChar1 :: GetColumn -// -//========================================================================== - -const uint8_t *FFontChar1::GetColumn(FRenderStyle, unsigned int column, const Span **spans_out) -{ - if (Pixels == NULL) - { - MakeTexture (); - } - - BaseTexture->GetColumn(DefaultRenderStyle(), column, spans_out); - return Pixels + column*Height; -} - -//========================================================================== -// -// FFontChar1 :: SetSourceRemap -// -//========================================================================== - -void FFontChar1::SetSourceRemap(const uint8_t *sourceremap) -{ - Unload(); - SourceRemap = sourceremap; -} - -//========================================================================== -// -// FFontChar1 :: Unload -// -//========================================================================== - -void FFontChar1::Unload () -{ - if (Pixels != NULL) - { - delete[] Pixels; - Pixels = NULL; - } - FTexture::Unload(); -} - -//========================================================================== -// -// FFontChar1 :: ~FFontChar1 -// -//========================================================================== - -FFontChar1::~FFontChar1 () -{ - Unload (); -} - -//========================================================================== -// -// FFontChar2 :: FFontChar2 -// -// Used by FON1 and FON2 fonts. -// -//========================================================================== - -FFontChar2::FFontChar2 (int sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) -: SourceLump (sourcelump), SourcePos (sourcepos), Pixels (0), Spans (0), SourceRemap(NULL) -{ - UseType = ETextureType::FontChar; - Width = width; - Height = height; - _LeftOffset[1] = _LeftOffset[0] = leftofs; - _TopOffset[1] = _TopOffset[0] = topofs; - CalcBitSize (); -} - -//========================================================================== -// -// FFontChar2 :: ~FFontChar2 -// -//========================================================================== - -FFontChar2::~FFontChar2 () -{ - Unload (); - if (Spans != NULL) - { - FreeSpans (Spans); - Spans = NULL; - } -} - -//========================================================================== -// -// FFontChar2 :: Unload -// -//========================================================================== - -void FFontChar2::Unload () -{ - if (Pixels != NULL) - { - delete[] Pixels; - Pixels = NULL; - } - FTexture::Unload(); -} - -//========================================================================== -// -// FFontChar2 :: GetPixels -// -// Like for FontChar1, the render style has no relevance here as well. -// -//========================================================================== - -const uint8_t *FFontChar2::GetPixels (FRenderStyle) -{ - if (Pixels == NULL) - { - MakeTexture (); - } - return Pixels; -} - -//========================================================================== -// -// FFontChar2 :: GetColumn -// -//========================================================================== - -const uint8_t *FFontChar2::GetColumn(FRenderStyle, unsigned int column, const Span **spans_out) -{ - if (Pixels == NULL) - { - MakeTexture (); - } - if (column >= Width) - { - column = WidthMask; - } - if (spans_out != NULL) - { - if (Spans == NULL) - { - Spans = CreateSpans (Pixels); - } - *spans_out = Spans[column]; - } - return Pixels + column*Height; -} - -//========================================================================== -// -// FFontChar2 :: SetSourceRemap -// -//========================================================================== - -void FFontChar2::SetSourceRemap(const uint8_t *sourceremap) -{ - Unload(); - SourceRemap = sourceremap; -} - -//========================================================================== -// -// FFontChar2 :: MakeTexture -// -//========================================================================== - -void FFontChar2::MakeTexture () -{ - auto lump = Wads.OpenLumpReader (SourceLump); - int destSize = Width * Height; - uint8_t max = 255; - bool rle = true; - - // This is to "fix" bad fonts - { - uint8_t buff[16]; - lump.Read (buff, 4); - if (buff[3] == '2') - { - lump.Read (buff, 7); - max = buff[6]; - lump.Seek (SourcePos - 11, FileReader::SeekCur); - } - else if (buff[3] == 0x1A) - { - lump.Read(buff, 13); - max = buff[12] - 1; - lump.Seek (SourcePos - 17, FileReader::SeekCur); - rle = false; - } - else - { - lump.Seek (SourcePos - 4, FileReader::SeekCur); - } - } - - Pixels = new uint8_t[destSize]; - - int runlen = 0, setlen = 0; - uint8_t setval = 0; // Shut up, GCC! - uint8_t *dest_p = Pixels; - int dest_adv = Height; - int dest_rew = destSize - 1; - - if (rle) - { - for (int y = Height; y != 0; --y) - { - for (int x = Width; x != 0; ) - { - if (runlen != 0) - { - uint8_t color = lump.ReadUInt8(); - color = MIN (color, max); - if (SourceRemap != NULL) - { - color = SourceRemap[color]; - } - *dest_p = color; - dest_p += dest_adv; - x--; - runlen--; - } - else if (setlen != 0) - { - *dest_p = setval; - dest_p += dest_adv; - x--; - setlen--; - } - else - { - int8_t code = lump.ReadInt8(); - if (code >= 0) - { - runlen = code + 1; - } - else if (code != -128) - { - uint8_t color = lump.ReadUInt8(); - setlen = (-code) + 1; - setval = MIN (color, max); - if (SourceRemap != NULL) - { - setval = SourceRemap[setval]; - } - } - } - } - dest_p -= dest_rew; - } - } - else - { - for (int y = Height; y != 0; --y) - { - for (int x = Width; x != 0; --x) - { - uint8_t color = lump.ReadUInt8(); - if (color > max) - { - color = max; - } - if (SourceRemap != NULL) - { - color = SourceRemap[color]; - } - *dest_p = color; - dest_p += dest_adv; - } - dest_p -= dest_rew; - } - } - - if (destSize < 0) - { - char name[9]; - Wads.GetLumpName (name, SourceLump); - name[8] = 0; - I_FatalError ("The font %s is corrupt", name); - } -} - //========================================================================== // // FSpecialFont :: FSpecialFont // //========================================================================== -FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) : FFont(lump) +FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate) + : FFont(lump) { int i; - FTexture **charlumps; + TArray charlumps(count, true); int maxyoffs; FTexture *pic; @@ -1920,9 +1511,7 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l noTranslate = donttranslate; FontName = name; - Chars = new CharData[count]; - charlumps = new FTexture*[count]; - PatchRemap = new uint8_t[256]; + Chars.Resize(count); FirstChar = first; LastChar = first + count - 1; FontHeight = 0; @@ -1935,10 +1524,10 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l for (i = 0; i < count; i++) { pic = charlumps[i] = lumplist[i]; - if (pic != NULL) + if (pic != nullptr) { - int height = pic->GetScaledHeight(); - int yoffs = pic->GetScaledTopOffset(0); + int height = pic->GetDisplayHeight(); + int yoffs = pic->GetDisplayTopOffset(); if (yoffs > maxyoffs) { @@ -1951,21 +1540,26 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l } } - if (charlumps[i] != NULL) + if (charlumps[i] != nullptr) { - if (!noTranslate) Chars[i].Pic = new FFontChar1 (charlumps[i]); - else Chars[i].Pic = charlumps[i]; - Chars[i].XMove = Chars[i].Pic->GetScaledWidth(); + Chars[i].OriginalPic = charlumps[i]; + if (!noTranslate) + { + Chars[i].TranslatedPic = new FImageTexture(new FFontChar1 (charlumps[i]->GetImage()), ""); + TexMan.AddTexture(Chars[i].TranslatedPic); + } + else Chars[i].TranslatedPic = charlumps[i]; + Chars[i].XMove = Chars[i].TranslatedPic->GetDisplayWidth(); } else { - Chars[i].Pic = NULL; + Chars[i].TranslatedPic = nullptr; Chars[i].XMove = INT_MIN; } } // Special fonts normally don't have all characters so be careful here! - if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].Pic != NULL) + if ('N'-first >= 0 && 'N'-first < count && Chars['N' - first].TranslatedPic != nullptr) { SpaceWidth = (Chars['N' - first].XMove + 1) / 2; } @@ -1984,8 +1578,6 @@ FSpecialFont::FSpecialFont (const char *name, int first, int count, FTexture **l { LoadTranslations(); } - - delete[] charlumps; } //========================================================================== @@ -1998,18 +1590,21 @@ void FSpecialFont::LoadTranslations() { int count = LastChar - FirstChar + 1; uint8_t usedcolors[256], identity[256]; - double *luminosity; + TArray Luminosity; int TotalColors; int i, j; memset (usedcolors, 0, 256); for (i = 0; i < count; i++) { - FFontChar1 *pic = static_cast(Chars[i].Pic); - if(pic) + if (Chars[i].TranslatedPic) { - pic->SetSourceRemap(NULL); // Force the FFontChar1 to return the same pixels as the base texture - RecordTextureColors (pic, usedcolors); + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic->GetImage()); + if (pic) + { + pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture + RecordTextureColors(pic, usedcolors); + } } } @@ -2018,7 +1613,7 @@ void FSpecialFont::LoadTranslations() if (notranslate[i]) usedcolors[i] = false; - TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, &luminosity); + TotalColors = ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); // Map all untranslated colors into the table of used colors for (i = 0; i < 256; i++) @@ -2033,11 +1628,11 @@ void FSpecialFont::LoadTranslations() for (i = 0; i < count; i++) { - if(Chars[i].Pic) - static_cast(Chars[i].Pic)->SetSourceRemap(PatchRemap); + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic->GetImage())->SetSourceRemap(PatchRemap); } - BuildTranslations (luminosity, identity, &TranslationParms[0][0], TotalColors, NULL); + BuildTranslations (Luminosity.Data(), identity, &TranslationParms[0][0], TotalColors, nullptr); // add the untranslated colors to the Ranges tables if (ActiveColors < TotalColors) @@ -2054,8 +1649,6 @@ void FSpecialFont::LoadTranslations() } } ActiveColors = TotalColors; - - delete[] luminosity; } //========================================================================== @@ -2206,7 +1799,7 @@ void V_InitCustomFonts() FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); if (texid.Exists()) { - *p = TexMan[texid]; + *p = TexMan.GetTexture(texid); } else if (Wads.GetLumpFile(sc.LumpNum) >= Wads.GetIwadNum()) { @@ -2225,7 +1818,7 @@ void V_InitCustomFonts() { for (i = 0; i < 256; i++) { - if (lumplist[i] != NULL) + if (lumplist[i] != nullptr) { first = i; break; @@ -2233,7 +1826,7 @@ void V_InitCustomFonts() } for (i = 255; i >= 0; i--) { - if (lumplist[i] != NULL) + if (lumplist[i] != nullptr) { count = i - first + 1; break; @@ -2337,19 +1930,19 @@ void V_InitFontColors () else if (sc.Compare ("Flat:")) { sc.MustGetString(); - logcolor = V_GetColor (NULL, sc); + logcolor = V_GetColor (nullptr, sc); } else { // Get first color - c = V_GetColor (NULL, sc); + c = V_GetColor (nullptr, sc); tparm.Start[0] = RPART(c); tparm.Start[1] = GPART(c); tparm.Start[2] = BPART(c); // Get second color sc.MustGetString(); - c = V_GetColor (NULL, sc); + c = V_GetColor (nullptr, sc); tparm.End[0] = RPART(c); tparm.End[1] = GPART(c); tparm.End[2] = BPART(c); @@ -2677,7 +2270,7 @@ void V_InitFonts() { IntermissionFont = FFont::FindFont("IntermissionFont_Doom"); } - if (IntermissionFont == NULL) + if (IntermissionFont == nullptr) { IntermissionFont = BigFont; } @@ -2686,11 +2279,11 @@ void V_InitFonts() void V_ClearFonts() { - while (FFont::FirstFont != NULL) + while (FFont::FirstFont != nullptr) { delete FFont::FirstFont; } - FFont::FirstFont = NULL; - SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = NULL; + FFont::FirstFont = nullptr; + SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr; } diff --git a/src/v_font.h b/src/v_font.h index 383363ce8..7e8373532 100644 --- a/src/v_font.h +++ b/src/v_font.h @@ -82,7 +82,7 @@ public: FFont (const char *fontname, const char *nametemplate, int first, int count, int base, int fdlump, int spacewidth=-1, bool notranslate = false); virtual ~FFont (); - virtual FTexture *GetChar (int code, int *const width) const; + virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; virtual int GetCharWidth (int code) const; FRemapTable *GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; int GetLump() const { return Lump; } @@ -112,7 +112,7 @@ protected: void FixXMoves(); static int SimpleTranslation (uint8_t *colorsused, uint8_t *translation, - uint8_t *identity, double **luminosity); + uint8_t *identity, TArray &Luminosity); int FirstChar, LastChar; int SpaceWidth; @@ -120,14 +120,17 @@ protected: int GlobalKerning; char Cursor; bool noTranslate; + bool translateUntranslated; struct CharData { - FTexture *Pic; - int XMove; - } *Chars; + FTexture *TranslatedPic = nullptr; // Texture for use with font translations. + FTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. + int XMove = INT_MIN; + }; + TArray Chars; int ActiveColors; TArray Ranges; - uint8_t *PatchRemap; + uint8_t PatchRemap[256]; int Lump; FName FontName = NAME_None; diff --git a/src/v_framebuffer.cpp b/src/v_framebuffer.cpp index dd697d943..43204c8be 100644 --- a/src/v_framebuffer.cpp +++ b/src/v_framebuffer.cpp @@ -359,11 +359,6 @@ uint32_t DFrameBuffer::GetCaps() return (uint32_t)FlagSet; } -void DFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) -{ - SWRenderer->RenderTextureView(tex, Viewpoint, FOV); -} - void DFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) { SWRenderer->WriteSavePic(player, file, width, height); diff --git a/src/v_text.cpp b/src/v_text.cpp index e9a78bee4..a6d57399b 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -139,8 +139,9 @@ void DFrameBuffer::DrawChar (FFont *font, int normalcolor, double x, double y, i FTexture *pic; int dummy; + bool redirected; - if (NULL != (pic = font->GetChar (character, &dummy))) + if (NULL != (pic = font->GetChar (character, normalcolor, &dummy, &redirected))) { DrawParms parms; Va_List tags; @@ -152,7 +153,7 @@ void DFrameBuffer::DrawChar (FFont *font, int normalcolor, double x, double y, i return; } PalEntry color = 0xffffffff; - parms.remap = font->GetColorTranslation((EColorRange)normalcolor, &color); + parms.remap = redirected? nullptr : font->GetColorTranslation((EColorRange)normalcolor, &color); parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); DrawTextureParms(pic, parms); } @@ -168,15 +169,16 @@ void DFrameBuffer::DrawChar(FFont *font, int normalcolor, double x, double y, in FTexture *pic; int dummy; + bool redirected; - if (NULL != (pic = font->GetChar(character, &dummy))) + if (NULL != (pic = font->GetChar(character, normalcolor, &dummy, &redirected))) { DrawParms parms; uint32_t tag = ListGetInt(args); bool res = ParseDrawTextureTags(pic, x, y, tag, args, &parms, false); if (!res) return; PalEntry color = 0xffffffff; - parms.remap = font->GetColorTranslation((EColorRange)normalcolor, &color); + parms.remap = redirected ? nullptr : font->GetColorTranslation((EColorRange)normalcolor, &color); parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); DrawTextureParms(pic, parms); } @@ -238,6 +240,7 @@ void DFrameBuffer::DrawTextCommon(FFont *font, int normalcolor, double x, double cy = y; + auto currentcolor = normalcolor; while ((const char *)ch - string < parms.maxstrlen) { c = GetCharFromString(ch); @@ -251,6 +254,7 @@ void DFrameBuffer::DrawTextCommon(FFont *font, int normalcolor, double x, double { range = font->GetColorTranslation(newcolor, &color); parms.color = PalEntry(colorparm.a, (color.r * colorparm.r) / 255, (color.g * colorparm.g) / 255, (color.b * colorparm.b) / 255); + currentcolor = newcolor; } continue; } @@ -262,9 +266,10 @@ void DFrameBuffer::DrawTextCommon(FFont *font, int normalcolor, double x, double continue; } - if (NULL != (pic = font->GetChar(c, &w))) + bool redirected = false; + if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected))) { - parms.remap = range; + parms.remap = redirected? nullptr : range; SetTextureParms(&parms, pic, cx, cy); if (parms.cellx) { diff --git a/src/v_video.cpp b/src/v_video.cpp index b9efcf6a1..7c2adec6c 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -93,6 +93,11 @@ CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { + if (self < 0 || self > 4) + { + self = 4; + } + if (usergame) { // [SP] Update pitch limits to the netgame/gamesim. @@ -919,7 +924,7 @@ void ScaleWithAspect (int &w, int &h, int Width, int Height) CCMD(vid_setsize) { - if (argv.argc() < 2) + if (argv.argc() < 3) { Printf("Usage: vid_setsize width height\n"); } diff --git a/src/v_video.h b/src/v_video.h index 1cba846f0..216fa2d31 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -318,9 +318,6 @@ class FUniquePalette; class IHardwareTexture; class FTexture; -// A canvas that represents the actual display. The video code is responsible -// for actually implementing this. Built on top of SimpleCanvas, because it -// needs a system memory buffer when buffered output is enabled. class DFrameBuffer { @@ -427,7 +424,7 @@ public: // Delete any resources that need to be deleted after restarting with a different IWAD virtual void CleanForRestart() {} virtual void SetTextureFilterMode() {} - virtual IHardwareTexture *CreateHardwareTexture(FTexture *tex) { return nullptr; } + virtual IHardwareTexture *CreateHardwareTexture() { return nullptr; } virtual void PrecacheMaterial(FMaterial *mat, int translation) {} virtual FModelRenderer *CreateModelRenderer(int mli) { return nullptr; } virtual void UnbindTexUnit(int no) {} @@ -471,7 +468,6 @@ public: void InitPalette(); void SetClearColor(int color); virtual uint32_t GetCaps(); - virtual void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); virtual void WriteSavePic(player_t *player, FileWriter *file, int width, int height); virtual sector_t *RenderView(player_t *player) { return nullptr; } diff --git a/src/version.h b/src/version.h index 1bda2ce5e..e8d079ff1 100644 --- a/src/version.h +++ b/src/version.h @@ -68,7 +68,7 @@ const char *GetVersionString(); // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to // be able to migrate in FGameConfigFile::DoGlobalSetup(). -#define LASTRUNVERSION "215" +#define LASTRUNVERSION "216" // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. diff --git a/src/w_wad.h b/src/w_wad.h index a7009d65e..c223a6bd0 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -180,7 +180,6 @@ public: int GetNumWads () const; int AddExternalFile(const char *filename); - int AddData(const char *filename, int length); protected: diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index e3e010fed..905a27287 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -217,10 +217,10 @@ private: int bottom; - right = c[i]->GetScaledWidth(); - bottom = c[i]->GetScaledHeight(); - left = lnodes[n].x - c[i]->GetScaledLeftOffset(0); - top = lnodes[n].y - c[i]->GetScaledTopOffset(0); + right = c[i]->GetDisplayWidth(); + bottom = c[i]->GetDisplayHeight(); + left = lnodes[n].x - c[i]->GetDisplayLeftOffset(); + top = lnodes[n].y - c[i]->GetDisplayTopOffset(); right += left; bottom += top; @@ -383,13 +383,13 @@ bool DInterBackground::LoadBackground(bool isenterpic) case 1: // Splat sc.MustGetString(); - splat = TexMan[sc.String]; + splat = TexMan.GetTextureByName(sc.String); break; case 2: // Pointers while (sc.GetString() && !sc.Crossed) { - yah.Push(TexMan[sc.String]); + yah.Push(TexMan.GetTextureByName(sc.String)); } if (sc.Crossed) sc.UnGet(); @@ -481,14 +481,14 @@ bool DInterBackground::LoadBackground(bool isenterpic) if (!sc.CheckString("{")) { sc.MustGetString(); - an.frames.Push(TexMan[sc.String]); + an.frames.Push(TexMan.GetTextureByName(sc.String)); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - an.frames.Push(TexMan[sc.String]); + an.frames.Push(TexMan.GetTextureByName(sc.String)); } } an.ctr = -1; @@ -503,7 +503,7 @@ bool DInterBackground::LoadBackground(bool isenterpic) an.loc.y = sc.Number; sc.MustGetString(); an.frames.Reserve(1); // allocate exactly one element - an.frames[0] = TexMan[sc.String]; + an.frames[0] = TexMan.GetTextureByName(sc.String); anims.Push(an); break; @@ -516,10 +516,10 @@ bool DInterBackground::LoadBackground(bool isenterpic) else { Printf("Intermission script %s not found!\n", lumpname + 1); - texture = TexMan.GetTexture("INTERPIC", ETextureType::MiscPatch); + texture = TexMan.GetTextureID("INTERPIC", ETextureType::MiscPatch); } } - background = TexMan[texture]; + background = TexMan.GetTexture(texture); return noautostartmap; } @@ -589,13 +589,13 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe if (background) { // background - if (background->UseType == ETextureType::MiscPatch) + if (background->isMiscPatch()) { // scale all animations below to fit the size of the base pic // The base pic is always scaled to fit the screen so this allows // placing the animations precisely where they belong on the base pic - animwidth = background->GetScaledWidthDouble(); - animheight = background->GetScaledHeightDouble(); + animwidth = background->GetDisplayWidthDouble(); + animheight = background->GetDisplayHeightDouble(); screen->FillBorder(NULL); screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); } diff --git a/src/win32/i_main.cpp b/src/win32/i_main.cpp index 6a75a597a..4bd3aed66 100644 --- a/src/win32/i_main.cpp +++ b/src/win32/i_main.cpp @@ -71,6 +71,7 @@ #include "r_utility.h" #include "g_levellocals.h" #include "s_sound.h" +#include "vm.h" #include "stats.h" #include "st_start.h" @@ -1057,6 +1058,11 @@ void DoMain (HINSTANCE hInstance) auto msg = error.what(); if (strcmp(msg, "NoRunExit")) { + if (CVMAbortException::stacktrace.IsNotEmpty()) + { + Printf("%s", CVMAbortException::stacktrace.GetChars()); + } + if (!batchrun) { ShowErrorPane(msg); diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index 1e5c78640..45bb50b4d 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -105,8 +105,8 @@ extern void LayoutMainWindow(HWND hWnd, HWND pane); static void CalculateCPUSpeed(); -static HCURSOR CreateCompatibleCursor(FTexture *cursorpic); -static HCURSOR CreateAlphaCursor(FTexture *cursorpic); +static HCURSOR CreateCompatibleCursor(FBitmap &cursorpic, int leftofs, int topofs); +static HCURSOR CreateAlphaCursor(FBitmap &cursorpic, int leftofs, int topofs); static HCURSOR CreateBitmapCursor(int xhot, int yhot, HBITMAP and_mask, HBITMAP color_mask); static void DestroyCustomCursor(); @@ -709,9 +709,9 @@ void I_PrintStr(const char *cp) if (con_debugoutput) { // Strip out any color escape sequences before writing to debug output - char * copy = new char[strlen(cp)+1]; + TArray copy(strlen(cp) + 1, true); const char * srcp = cp; - char * dstp = copy; + char * dstp = copy.Data(); while (*srcp != 0) { @@ -727,8 +727,7 @@ void I_PrintStr(const char *cp) } *dstp=0; - OutputDebugStringA(copy); - delete [] copy; + OutputDebugStringA(copy.Data()); } if (ConWindowHidden) @@ -916,18 +915,22 @@ bool I_SetCursor(FTexture *cursorpic) { HCURSOR cursor; - if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null) + if (cursorpic != NULL && cursorpic->isValid()) { - // Must be no larger than 32x32. - if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32) + auto image = cursorpic->GetBgraBitmap(nullptr); + // Must be no larger than 32x32. (is this still necessary? + if (image.GetWidth() > 32 || image.GetHeight() > 32) { return false; } + // Fixme: This should get a raw image, not a texture. (Once raw images get implemented.) + int lo = cursorpic->GetDisplayLeftOffset(); + int to = cursorpic->GetDisplayTopOffset(); - cursor = CreateAlphaCursor(cursorpic); + cursor = CreateAlphaCursor(image, lo, to); if (cursor == NULL) { - cursor = CreateCompatibleCursor(cursorpic); + cursor = CreateCompatibleCursor(image, lo, to); } if (cursor == NULL) { @@ -972,10 +975,10 @@ bool I_SetCursor(FTexture *cursorpic) // //========================================================================== -static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) +static HCURSOR CreateCompatibleCursor(FBitmap &bmp, int leftofs, int topofs) { - int picwidth = cursorpic->GetWidth(); - int picheight = cursorpic->GetHeight(); + int picwidth = bmp.GetWidth(); + int picheight = bmp.GetHeight(); // Create bitmap masks for the cursor from the texture. HDC dc = GetDC(NULL); @@ -1000,12 +1003,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) SelectObject(xor_mask_dc, GetStockObject(BLACK_BRUSH)); Rectangle(xor_mask_dc, 0, 0, 32, 32); - FBitmap bmp; - const uint8_t *pixels; - - bmp.Create(picwidth, picheight); - cursorpic->CopyTrueColorPixels(&bmp, 0, 0); - pixels = bmp.GetPixels(); + const uint8_t *pixels = bmp.GetPixels(); // Copy color data from the source texture to the cursor bitmaps. for (int y = 0; y < picheight; ++y) @@ -1024,7 +1022,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) DeleteDC(xor_mask_dc); // Create the cursor from the bitmaps. - return CreateBitmapCursor(cursorpic->GetLeftOffset(0), cursorpic->GetTopOffset(0), and_mask, xor_mask); + return CreateBitmapCursor(leftofs, topofs, and_mask, xor_mask); } //========================================================================== @@ -1035,7 +1033,7 @@ static HCURSOR CreateCompatibleCursor(FTexture *cursorpic) // //========================================================================== -static HCURSOR CreateAlphaCursor(FTexture *cursorpic) +static HCURSOR CreateAlphaCursor(FBitmap &source, int leftofs, int topofs) { HDC dc; BITMAPV5HEADER bi; @@ -1085,11 +1083,11 @@ static HCURSOR CreateAlphaCursor(FTexture *cursorpic) // Copy cursor to the color bitmap. Note that GDI bitmaps are upside down compared // to normal conventions, so we create the FBitmap pointing at the last row and use - // a negative pitch so that CopyTrueColorPixels will use GDI's orientation. + // a negative pitch so that Blit will use GDI's orientation. if (scale == 1) { FBitmap bmp((uint8_t *)bits + 31 * 32 * 4, -32 * 4, 32, 32); - cursorpic->CopyTrueColorPixels(&bmp, 0, 0); + bmp.Blit(0, 0, source); } else { @@ -1097,7 +1095,7 @@ static HCURSOR CreateAlphaCursor(FTexture *cursorpic) unscaled.Resize(32 * 32); for (int i = 0; i < 32 * 32; i++) unscaled[i] = 0; FBitmap bmp((uint8_t *)&unscaled[0] + 31 * 32 * 4, -32 * 4, 32, 32); - cursorpic->CopyTrueColorPixels(&bmp, 0, 0); + bmp.Blit(0, 0, source); uint32_t *scaled = (uint32_t*)bits; for (int y = 0; y < 32 * scale; y++) { @@ -1108,7 +1106,7 @@ static HCURSOR CreateAlphaCursor(FTexture *cursorpic) } } - return CreateBitmapCursor(cursorpic->GetLeftOffset(0) * scale, cursorpic->GetTopOffset(0) * scale, mono, color); + return CreateBitmapCursor(leftofs * scale, topofs * scale, mono, color); } //========================================================================== diff --git a/wadsrc/static/compatibility.txt b/wadsrc/static/compatibility.txt index 030cea322..2ab378ba3 100644 --- a/wadsrc/static/compatibility.txt +++ b/wadsrc/static/compatibility.txt @@ -167,6 +167,26 @@ AF40D0E49BD1B76D4B1AADD8212ADC46 // MAP01 (the wad that shall not be named =P) pointonline } +920F8D876ECD96D8C2A978FF1AB2B401 // Darken2.wad map01 - Nodes go out of bounds/beyond normal sector boundaries +CFEDB7FA89885E24856CAC9A2FB3CE58 // Darken2.wad map03 - GZDoomBuilder crashes when displaying Nodes +8E961FA7029761D5FAB3932C40F10CD2 // Darken2.wad map04 - Nodes go out of bounds/beyond normal sector boundaries +DEA5E9C6253FFF8FDB2D5E5BADE13A9D // Darken2.wad map06 - Nodes go out of bounds/beyond normal sector boundaries +0E72254C0C26F721333A1C56E3648D68 // Darken2.wad map07 - Nodes go out of bounds/beyond normal sector boundaries +1437B40F2D56DF82346366814E9729D9 // Darken2.wad map08 - Nodes go out of bounds/beyond normal sector boundaries +8B15F89E47E422780FBF2D6CDE3AA050 // Darken2.wad map09 - GZDoomBuilder crashes when displaying Nodes +5A2FD43D23B45191229E5C74E9398D36 // Darken2.wad map10 - Nodes go out of bounds/beyond normal sector boundaries +FA25A78B3DFD7CC44E9B10C7B78EADAE // Darken2.wad map11 - Nodes go out beyond normal sector boundaries +01592ACF001C534076556D9E1B5D85E7 // Darken2.wad map12 - Nodes go out of bounds/beyond normal sector boundaries +16A2ED2917A68B2FD8D264BE4D64EA09 // Darken2.wad map13 - Nodes go out of bounds/beyond normal sector boundaries +F5DA2AA0C7112E090167A6B2F6D4A079 // Darken2.wad map15 - Nodes go out beyond normal sector boundaries +A40A4472AB0FDBE2D55ADADA7D9005C8 // Darken2.wad map16 - Nodes go out of bounds/beyond normal sector boundaries +244701904E6B754A02842415AB183EBE // Darken2.wad map17 - Nodes go out beyond normal sector boundaries +661D3C9221114A1CD16674CBFF239DDF // Darken2.wad map19 - Nodes go out of bounds/beyond normal sector boundaries +1FB559C4C37CCE8C3883057C963952A8 // Darken2.wad map20 - Nodes go out beyond normal sector boundaries +D36E7D121F28F77A3780A5BD88425FB4 // Darken2.wad map21 - Nodes go out beyond normal sector boundaries +3253B280FB7A4A04284FE08A6D9F222D // Darken2.wad map22 - Nodes go out beyond normal sector boundaries +E0E5517B7928E88B88F6A5B77AC449DF // Darken2.wad map23 - Nodes go out of bounds/beyond normal sector boundaries +6DD76422593381E3234FA703C155C493 // Darken2.wad map24 - Nodes go out of bounds/beyond normal sector boundaries 8B2AC8D4DB4A49A5DCCBB067E04434D6 // The Hell Factory Hub One, map04 65A1EB4C87386F290816660A52932FF1 // Master Levels, garrison.wad 3DEE4EFEFAF3260C800A30734F54CE75 // Hellbound, map14 @@ -175,6 +195,8 @@ AF40D0E49BD1B76D4B1AADD8212ADC46 // MAP01 (the wad that shall not be named =P) D5F64E02679A81B82006AF34A6A8EAC3 // plutonia.wad map32 BA4860C7A2F5D705DB32A1A38DB77EC4 // pl2.wad map10 EDA5CE7C462BD171BF8110AC56B67857 // pl2.wad map11 +A9A9A728E689266939C1B71655F320CA // pl2.wad map25 +62CA74092FC88C1E7FE2D0B1A8034E29 // pl2.wad map29 { rebuildnodes } diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 2b49fe55f..81b7d17f2 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -2783,7 +2783,8 @@ GLTEXMNU_ANISOTROPIC = "Anisotropic filter"; GLTEXMNU_TEXFORMAT = "Texture Format"; GLTEXMNU_ENABLEHIRES = "Enable hires textures"; GLTEXMNU_HQRESIZE = "High Quality Resize mode"; -GLTEXMNU_HQRESIZEWARN = "This mode requires %d times more video memory"; +GLTEXMNU_HQRESIZEMULT = "High Quality Resize multiplier"; +GLTEXMNU_HQRESIZEWARN = "This mode requires %d times more video memory"; GLTEXMNU_RESIZETEX = "Resize textures"; GLTEXMNU_RESIZESPR = "Resize sprites"; GLTEXMNU_RESIZEFNT = "Resize fonts"; @@ -2881,30 +2882,12 @@ OPTVAL_YAXIS = "Y Axis"; OPTVAL_XYAXIS = "X/Y Axis"; OPTVAL_SQUARE = "Square"; OPTVAL_ROUND = "Round"; -OPTVAL_SCALE2X = "Scale2x"; -OPTVAL_SCALE3X = "Scale3x"; -OPTVAL_SCALE4X = "Scale4x"; -OPTVAL_NORMAL2X = "Normal2x"; -OPTVAL_NORMAL3X = "Normal3x"; -OPTVAL_NORMAL4X = "Normal4x"; -OPTVAL_NORMAL5X = "Normal5x"; -OPTVAL_NORMAL6X = "Normal6x"; -OPTVAL_HQ2X = "hq2x"; -OPTVAL_HQ3X = "hq3x"; -OPTVAL_HQ4X = "hq4x"; -OPTVAL_HQ2XMMX = "hq2x MMX"; -OPTVAL_HQ3XMMX = "hq3x MMX"; -OPTVAL_HQ4XMMX = "hq4x MMX"; -OPTVAL_2XBRZ = "2xBRZ"; -OPTVAL_3XBRZ = "3xBRZ"; -OPTVAL_4XBRZ = "4xBRZ"; -OPTVAL_5XBRZ = "5xBRZ"; -OPTVAL_6XBRZ = "6xBRZ"; -OPTVAL_OLD_2XBRZ = "Old 2xBRZ"; -OPTVAL_OLD_3XBRZ = "Old 3xBRZ"; -OPTVAL_OLD_4XBRZ = "Old 4xBRZ"; -OPTVAL_OLD_5XBRZ = "Old 5xBRZ"; -OPTVAL_OLD_6XBRZ = "Old 6xBRZ"; +OPTVAL_SCALENX = "ScaleNx"; +OPTVAL_NORMALNX = "NormalNx"; +OPTVAL_HQNX = "hqNx"; +OPTVAL_HQNXMMX = "hqNx MMX"; +OPTVAL_NXBRZ = "xBRZ"; +OPTVAL_OLD_NXBRZ = "Old xBRZ"; OPTVAL_RADIAL = "Radial"; OPTVAL_PIXELFUZZ = "Pixel fuzz"; OPTVAL_SMOOTHFUZZ = "Smooth fuzz"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 965f23d0c..1ff8697b3 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -2105,6 +2105,7 @@ OptionValue "LightingModes" 3, "$OPTVAL_DARK" 4, "$OPTVAL_LEGACY" 8, "$OPTVAL_SOFTWARE" + 16, "$OPTVAL_VANILLA" } OptionValue "Precision" @@ -2151,51 +2152,32 @@ OptionValue "Particles" OptionValue "HqResizeModes" { 0, "$OPTVAL_OFF" - 1, "$OPTVAL_SCALE2X" - 2, "$OPTVAL_SCALE3X" - 3, "$OPTVAL_SCALE4X" - 4, "$OPTVAL_HQ2X" - 5, "$OPTVAL_HQ3X" - 6, "$OPTVAL_HQ4X" - 7, "$OPTVAL_HQ2XMMX" - 8, "$OPTVAL_HQ3XMMX" - 9, "$OPTVAL_HQ4XMMX" - 10, "$OPTVAL_2XBRZ" - 11, "$OPTVAL_3XBRZ" - 12, "$OPTVAL_4XBRZ" - 18, "$OPTVAL_5XBRZ" - 19, "$OPTVAL_6XBRZ" - 13, "$OPTVAL_OLD_2XBRZ" - 14, "$OPTVAL_OLD_3XBRZ" - 15, "$OPTVAL_OLD_4XBRZ" - 16, "$OPTVAL_OLD_5XBRZ" - 17, "$OPTVAL_OLD_6XBRZ" - 20, "$OPTVAL_NORMAL2X" - 21, "$OPTVAL_NORMAL3X" - 22, "$OPTVAL_NORMAL4X" - 23, "$OPTVAL_NORMAL5X" - 24, "$OPTVAL_NORMAL6X" + 1, "$OPTVAL_SCALENX" + 2, "$OPTVAL_HQNX" + 3, "$OPTVAL_HQNXMMX" + 4, "$OPTVAL_NXBRZ" + 5, "$OPTVAL_OLD_NXBRZ" + 6, "$OPTVAL_NORMALNX" +} + +OptionValue "HqResizeMultipliers" +{ + 1, "$OPTVAL_OFF" + 2, "2x" + 3, "3x" + 4, "4x" + 5, "5x" + 6, "6x" } OptionValue "HqResizeModesNoMMX" { 0, "$OPTVAL_OFF" - 1, "$OPTVAL_SCALE2X" - 2, "$OPTVAL_SCALE3X" - 3, "$OPTVAL_SCALE4X" - 4, "$OPTVAL_HQ2X" - 5, "$OPTVAL_HQ3X" - 6, "$OPTVAL_HQ4X" - 10, "$OPTVAL_2XBRZ" - 11, "$OPTVAL_3XBRZ" - 12, "$OPTVAL_4XBRZ" - 18, "$OPTVAL_5XBRZ" - 19, "$OPTVAL_6XBRZ" - 13, "$OPTVAL_OLD_2XBRZ" - 14, "$OPTVAL_OLD_3XBRZ" - 15, "$OPTVAL_OLD_4XBRZ" - 16, "$OPTVAL_OLD_5XBRZ" - 17, "$OPTVAL_OLD_6XBRZ" + 1, "$OPTVAL_SCALENX" + 2, "$OPTVAL_HQNX" + 4, "$OPTVAL_NXBRZ" + 5, "$OPTVAL_OLD_NXBRZ" + 6, "$OPTVAL_NORMALNX" } OptionValue "FogMode" @@ -2262,12 +2244,13 @@ OptionMenu "GLTextureGLOptions" protected ifOption(MMX) { - Option "$GLTEXMNU_HQRESIZE", gl_texture_hqresize, "HqResizeModes" + Option "$GLTEXMNU_HQRESIZE", gl_texture_hqresizemode, "HqResizeModes" } else { - Option "$GLTEXMNU_HQRESIZE", gl_texture_hqresize, "HqResizeModesNoMMX" + Option "$GLTEXMNU_HQRESIZE", gl_texture_hqresizemode, "HqResizeModesNoMMX" } + Option "$GLTEXMNU_HQRESIZEMULT", gl_texture_hqresizemult, "HqResizeMultipliers" StaticText "!HQRESIZE_WARNING!" Option "$GLTEXMNU_RESIZETEX", gl_texture_hqresize_textures, "OnOff" diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 77855a85a..e6ec4c63f 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -119,17 +119,84 @@ vec4 getTexel(vec2 st) //=========================================================================== // -// Doom lighting equation exactly as calculated by zdoom. +// Vanilla Doom wall colormap equation +// +//=========================================================================== +float R_WallColormap(float lightnum, float z) +{ + // R_ScaleFromGlobalAngle calculation + float projection = 160.0; // projection depends on SCREENBLOCKS!! 160 is the fullscreen value + vec2 line_v1 = pixelpos.xz; // in vanilla this is the first curline vertex + vec2 line_normal = vWorldNormal.xz; + float texscale = projection * clamp(dot(normalize(uCameraPos.xz - line_v1), line_normal), 0.0, 1.0) / z; + + float lightz = clamp(16.0 * texscale, 0.0, 47.0); + + // scalelight[lightnum][lightz] lookup + float startmap = (15.0 - lightnum) * 4.0; + return startmap - lightz * 0.5; +} + +//=========================================================================== +// +// Vanilla Doom plane colormap equation +// +//=========================================================================== +float R_PlaneColormap(float lightnum, float z) +{ + float lightz = clamp(z / 16.0f, 0.0, 127.0); + + // zlight[lightnum][lightz] lookup + float startmap = (15.0 - lightnum) * 4.0; + float scale = 160.0 / (lightz + 1.0); + return startmap - scale * 0.5; +} + +//=========================================================================== +// +// zdoom colormap equation +// +//=========================================================================== +float R_ZDoomColormap(float light, float z) +{ + float L = light * 255.0; + float vis = min(uGlobVis / z, 24.0 / 32.0); + float shade = 2.0 - (L + 12.0) / 128.0; + float lightscale = shade - vis; + return lightscale * 31.0; +} + +float R_DoomColormap(float light, float z) +{ + if ((uPalLightLevels >> 16) == 16) // gl_lightmode 16 + { + float lightnum = clamp(light * 15.0, 0.0, 15.0); + + if (dot(vWorldNormal.xyz, vWorldNormal.xyz) > 0.5) + { + return mix(R_WallColormap(lightnum, z), R_PlaneColormap(lightnum, z), abs(vWorldNormal.y)); + } + else // vWorldNormal is not set on sprites + { + return R_PlaneColormap(lightnum, z); + } + } + else + { + return R_ZDoomColormap(light, z); + } +} + +//=========================================================================== +// +// Doom software lighting equation // //=========================================================================== float R_DoomLightingEquation(float light) { - // L is the integer light level used in the game - float L = light * 255.0; - - // z is the depth in view/eye space, positive going into the screen + // z is the depth in view space, positive going into the screen float z; - if ((uPalLightLevels >> 8) == 2) + if (((uPalLightLevels >> 8) & 0xff) == 2) { z = distance(pixelpos.xyz, uCameraPos.xyz); } @@ -138,17 +205,13 @@ float R_DoomLightingEquation(float light) z = pixelpos.w; } - // The zdoom light equation - float vis = min(uGlobVis / z, 24.0 / 32.0); - float shade = 2.0 - (L + 12.0) / 128.0; - float lightscale; + float colormap = R_DoomColormap(light, z); + if ((uPalLightLevels & 0xff) != 0) - lightscale = float(-floor(-(shade - vis) * 31.0) - 0.5) / 31.0; - else - lightscale = shade - vis; + colormap = floor(colormap) + 0.5; // Result is the normalized colormap index (0 bright .. 1 dark) - return clamp(lightscale, 1.0 - light, 31.0 / 32.0); + return clamp(colormap, 0.0, 31.0) / 32.0; } //=========================================================================== diff --git a/wadsrc/static/zscript/menu/optionmenu.txt b/wadsrc/static/zscript/menu/optionmenu.txt index f73035ab0..10bd91140 100644 --- a/wadsrc/static/zscript/menu/optionmenu.txt +++ b/wadsrc/static/zscript/menu/optionmenu.txt @@ -579,47 +579,9 @@ class GLTextureGLOptions : OptionMenu { string message; - if (gl_texture_hqresize > 0) + if (gl_texture_hqresizemult > 1 && gl_texture_hqresizemode > 0) { - int multiplier; - - switch (gl_texture_hqresize) - { - case 1: - case 4: - case 7: - case 10: - case 13: - case 20: - multiplier = 4; - break; - case 2: - case 5: - case 8: - case 11: - case 14: - case 21: - multiplier = 9; - break; - case 3: - case 6: - case 9: - case 12: - case 15: - case 22: - multiplier = 16; - break; - case 16: - case 18: - case 23: - multiplier = 25; - break; - case 17: - case 19: - case 24: - multiplier = 36; - break; - } + int multiplier = gl_texture_hqresizemult * gl_texture_hqresizemult; string localized = StringTable.Localize("$GLTEXMNU_HQRESIZEWARN"); message = String.Format(localized, multiplier); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 391ae38a6..9a06f78b4 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -2431,6 +2431,11 @@ struct PlayerInfo native play // self is what internally is known as player_t mo.DropWeapon(); } } + + deprecated("3.7") void BringUpWeapon() + { + if (mo) mo.BringUpWeapon(); + } bool IsTotallyFrozen() { diff --git a/wadsrc/static/zscript/statusbar/alt_hud.txt b/wadsrc/static/zscript/statusbar/alt_hud.txt index 6f7a5f8dd..ccc9b568d 100644 --- a/wadsrc/static/zscript/statusbar/alt_hud.txt +++ b/wadsrc/static/zscript/statusbar/alt_hud.txt @@ -674,7 +674,7 @@ class AltHud ui { double trans = rover == CPlayer.mo.InvSel ? 1.0 : 0.4; - DrawImageToBox(AltIcon.isValid()? AltIcon : rover.Icon, x, y, 19, 25, trans); + DrawImageToBox(AltIcon.isValid()? AltIcon : rover.Icon, x, y, 19, 25, trans, true); if (rover.Amount > 1) { int xx; @@ -989,4 +989,4 @@ class AltHud ui } } -} \ No newline at end of file +} diff --git a/wadsrc/static/zscript/statusbar/harm_sbar.txt b/wadsrc/static/zscript/statusbar/harm_sbar.txt index 42a30f2fc..ebed03f92 100644 --- a/wadsrc/static/zscript/statusbar/harm_sbar.txt +++ b/wadsrc/static/zscript/statusbar/harm_sbar.txt @@ -1,6 +1,6 @@ class HarmonyStatusBar : DoomStatusBar { - int scalestate; + double scaleFactor; override void Init() { @@ -10,22 +10,14 @@ class HarmonyStatusBar : DoomStatusBar let tex = TexMan.CheckForTexture("MEDIA0", TexMan.Type_Sprite); if (tex.isValid()) { - int size = TexMan.GetSize(tex); Vector2 ssize = TexMan.GetScaledSize(tex); - if (ssize.X ~== size) scalestate = 1; - else scalestate = 0; + Vector2 facs = (ssize.X / 31, ssize.Y / 18); + scaleFactor = min(facs.X, facs.Y, 1); } - else scalestate = 1; } override void Draw (int state, double TicFrac) { - if (!scalestate) - { - Super.Draw(state, TicFrac); - return; - } - BaseStatusBar.Draw (state, TicFrac); if (state == HUD_StatusBar) @@ -44,13 +36,13 @@ class HarmonyStatusBar : DoomStatusBar { Vector2 iconbox = (40, 20); // Draw health - DrawImage("MEDIA0", (20, -2), scale:(0.3, 0.3)); + DrawImage("MEDIA0", (20, -2), scale:(scaleFactor, scaleFactor)); DrawString(mHUDFont, FormatNumber(CPlayer.health, 3), (44, -20)); let armor = CPlayer.mo.FindInventory("BasicArmor"); if (armor != null && armor.Amount > 0) { - DrawInventoryIcon(armor, (20, -22), scale:(0.3, 0.3)); + DrawInventoryIcon(armor, (20, -22), scale:(scaleFactor, scaleFactor)); DrawString(mHUDFont, FormatNumber(armor.Amount, 3), (44, -40)); } Inventory ammotype1, ammotype2; @@ -58,13 +50,13 @@ class HarmonyStatusBar : DoomStatusBar int invY = -20; if (ammotype1 != null) { - DrawInventoryIcon(ammotype1, (-14, -4), scale:(0.3, 0.3)); + DrawInventoryIcon(ammotype1, (-14, -4), scale:(scaleFactor, scaleFactor)); DrawString(mHUDFont, FormatNumber(ammotype1.Amount, 3), (-30, -20), DI_TEXT_ALIGN_RIGHT); invY -= 20; } if (ammotype2 != null && ammotype2 != ammotype1) { - DrawInventoryIcon(ammotype2, (-14, invY + 17), scale:(0.3, 0.3)); + DrawInventoryIcon(ammotype2, (-14, invY + 17), scale:(scaleFactor, scaleFactor)); DrawString(mHUDFont, FormatNumber(ammotype2.Amount, 3), (-30, invY), DI_TEXT_ALIGN_RIGHT); invY -= 20; }