From e9a067dd655fe4c17c0993a46ca6d4d1e9d892f1 Mon Sep 17 00:00:00 2001 From: "Dileep V. Reddy" Date: Sat, 26 Apr 2025 09:11:58 -0600 Subject: [PATCH] Skymist is a third sky layer with transparency, and adopts the fade color and skyfog density. Size not connected to SKY1 or SKY2. Works with 6-sided skyboxes. Three template pngs (skymist1, 2, & 3) all 1x544 pixels, 8-bit grayscale with transparency are part of gzdoom.pk3 for general usage. Can supply custom lump through mapinfo. Console command 'skymisttoggle' shows the effect (make sure fade has a non-zero color in mapinfo and skyfog has non-zero density). Oh, and skyfog now works with 6-sided skyboxes. --- .../rendering/hwrenderer/data/hw_skydome.cpp | 2 +- src/console/c_cmds.cpp | 10 +++++++++ src/g_level.cpp | 2 ++ src/g_levellocals.h | 4 +++- src/gamedata/g_mapinfo.cpp | 21 +++++++++++++++++-- src/gamedata/g_mapinfo.h | 3 +++ src/p_saveg.cpp | 2 ++ src/p_setup.cpp | 4 ++++ src/playsim/p_acs.cpp | 1 + src/rendering/hwrenderer/scene/hw_portal.h | 5 ++--- src/rendering/hwrenderer/scene/hw_sky.cpp | 3 +++ .../hwrenderer/scene/hw_skyportal.cpp | 17 ++++++++++----- src/rendering/r_sky.cpp | 5 +++++ src/scripting/vmthunks.cpp | 13 ++++++++++++ 14 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_skydome.cpp b/src/common/rendering/hwrenderer/data/hw_skydome.cpp index 18108c8f2..d0f2e471d 100644 --- a/src/common/rendering/hwrenderer/data/hw_skydome.cpp +++ b/src/common/rendering/hwrenderer/data/hw_skydome.cpp @@ -488,7 +488,7 @@ void FSkyVertexBuffer::DoRenderDome(FRenderState& state, FGameTexture* tex, int RenderRow(state, DT_TriangleFan, rc, primStart); state.EnableTexture(true); } - state.SetObjectColor(0xffffffff); + state.SetObjectColor(color); for (int i = 1; i <= mRows; i++) { RenderRow(state, DT_TriangleStrip, i, primStart, i == 1); diff --git a/src/console/c_cmds.cpp b/src/console/c_cmds.cpp index 19c5c9d50..f92415477 100644 --- a/src/console/c_cmds.cpp +++ b/src/console/c_cmds.cpp @@ -942,6 +942,16 @@ CCMD(changesky) InitSkyMap (primaryLevel); } +//----------------------------------------------------------------------------- +// +// +// +//----------------------------------------------------------------------------- +CCMD(skymisttoggle) +{ + primaryLevel->flags3 ^= LEVEL3_SKYMIST; +} + //----------------------------------------------------------------------------- // // diff --git a/src/g_level.cpp b/src/g_level.cpp index b42d5885f..4a269c66b 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1835,8 +1835,10 @@ void FLevelLocals::Init() skyspeed1 = info->skyspeed1; skyspeed2 = info->skyspeed2; + skymistspeed = info->skymistspeed; skytexture1 = TexMan.GetTextureID(info->SkyPic1.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); skytexture2 = TexMan.GetTextureID(info->SkyPic2.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); + skymisttexture = TexMan.GetTextureID(info->SkyMistPic.GetChars(), ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); fadeto = info->fadeto; cdtrack = info->cdtrack; cdid = info->cdid; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index fb553d984..01c95dac1 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -687,12 +687,14 @@ public: unsigned int cdid; FTextureID skytexture1; FTextureID skytexture2; + FTextureID skymisttexture; float skyspeed1; // Scrolling speed of sky textures, in pixels per ms float skyspeed2; + float skymistspeed; double sky1pos, sky2pos; - float hw_sky1pos, hw_sky2pos; + float hw_sky1pos, hw_sky2pos, hw_skymistpos; bool skystretch; uint32_t globalcolormap; diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index fee2347cb..3f72be352 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -97,6 +97,7 @@ level_info_t *FindLevelInfo (const char *mapname, bool allowdefault) if (TheDefaultLevelInfo.LevelName.IsEmpty()) { TheDefaultLevelInfo.SkyPic2 = TheDefaultLevelInfo.SkyPic1 = "SKY1"; + TheDefaultLevelInfo.SkyMistPic = "SKYMIST1"; TheDefaultLevelInfo.LevelName = "Unnamed"; } return &TheDefaultLevelInfo; @@ -255,6 +256,7 @@ void level_info_t::Reset() NextMap = ""; NextSecretMap = ""; SkyPic1 = SkyPic2 = "-NOFLAT-"; + SkyMistPic = "SKYMIST1"; cluster = 0; partime = 0; sucktime = 0; @@ -277,7 +279,7 @@ void level_info_t::Reset() musicorder = 0; Snapshot = { 0,0,0,0,0,nullptr }; deferred.Clear(); - skyspeed1 = skyspeed2 = 0.f; + skyspeed1 = skyspeed2 = skymistspeed = 0.f; fadeto = 0; outsidefog = 0xff000000; cdtrack = 0; @@ -1099,6 +1101,20 @@ DEFINE_MAP_OPTION(sky2, true) } } +DEFINE_MAP_OPTION(skymist, true) +{ + parse.ParseAssign(); + parse.ParseLumpOrTextureName(info->SkyMistPic); + if (parse.CheckFloat()) + { + if (parse.HexenHack) + { + parse.sc.Float /= 256; + } + info->skymistspeed = float(parse.sc.Float * (TICRATE / 1000.)); + } +} + // Vavoom compatibility DEFINE_MAP_OPTION(skybox, true) { @@ -1857,7 +1873,8 @@ MapFlagHandlers[] = { "disableskyboxao", MITYPE_CLRFLAG3, LEVEL3_SKYBOXAO, 0 }, { "avoidmelee", MITYPE_SETFLAG3, LEVEL3_AVOIDMELEE, 0 }, { "attenuatelights", MITYPE_SETFLAG3, LEVEL3_ATTENUATE, 0 }, - { "nofogofwar", MITYPE_SETFLAG3, LEVEL3_NOFOGOFWAR, 0 }, + { "nofogofwar", MITYPE_SETFLAG3, LEVEL3_NOFOGOFWAR, 0 }, + { "useskymist", MITYPE_SETFLAG3, LEVEL3_SKYMIST, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, { "passover", MITYPE_CLRCOMPATFLAG, COMPATF_NO_PASSMOBJ, 0 }, diff --git a/src/gamedata/g_mapinfo.h b/src/gamedata/g_mapinfo.h index d6bd695df..4c3d6a18a 100644 --- a/src/gamedata/g_mapinfo.h +++ b/src/gamedata/g_mapinfo.h @@ -274,6 +274,7 @@ enum ELevelFlags : unsigned int LEVEL3_LIGHTCREATED = 0x00080000, // a light had been created in the last frame LEVEL3_NOFOGOFWAR = 0x00100000, // disables effect of r_radarclipper CVAR on this map LEVEL3_SECRET = 0x00200000, // level is a secret level + LEVEL3_SKYMIST = 0x00400000, // level skyfog uses the skymist texture }; @@ -333,6 +334,7 @@ struct level_info_t FString PName; FString SkyPic1; FString SkyPic2; + FString SkyMistPic; FString FadeTable; FString CustomColorMap; FString F1Pic; @@ -359,6 +361,7 @@ struct level_info_t TArray deferred; float skyspeed1; float skyspeed2; + float skymistspeed; uint32_t fadeto; uint32_t outsidefog; int cdtrack; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 659e67664..6248f2329 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -964,6 +964,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) ("fadeto", fadeto) ("skyspeed1", skyspeed1) ("skyspeed2", skyspeed2) + ("skymistspeed", skymistspeed) ("found_secrets", found_secrets) ("found_items", found_items) ("killed_monsters", killed_monsters) @@ -977,6 +978,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) ("totaltime", i) ("skytexture1", skytexture1) ("skytexture2", skytexture2) + ("skymisttexture", skymisttexture) ("fogdensity", fogdensity) ("outsidefogdensity", outsidefogdensity) ("skyfog", skyfog) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c18cb1621..b948d4734 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -212,6 +212,10 @@ static void PrecacheLevel(FLevelLocals *Level) { AddToList(hitlist.Data(), Level->skytexture2, FTextureManager::HIT_Sky); } + if (Level->skymisttexture.isValid()) + { + AddToList(hitlist.Data(), Level->skymisttexture, FTextureManager::HIT_Sky); + } static const BITFIELD checkForTextureFlags = FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_ReturnFirst | FTextureManager::TEXMAN_DontCreate; diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index aa26c0163..63432a9eb 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -5545,6 +5545,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args, int & { if (args[0] == 1) Level->skyspeed1 = ACSToFloat(args[1]); else if (args[0] == 2) Level->skyspeed2 = ACSToFloat(args[1]); + else if (args[0] == 3) Level->skymistspeed = ACSToFloat(args[1]); return 1; } diff --git a/src/rendering/hwrenderer/scene/hw_portal.h b/src/rendering/hwrenderer/scene/hw_portal.h index 207cefc2f..64952b88b 100644 --- a/src/rendering/hwrenderer/scene/hw_portal.h +++ b/src/rendering/hwrenderer/scene/hw_portal.h @@ -13,9 +13,9 @@ class FSkyBox; struct HWSkyInfo { - float x_offset[2]; + float x_offset[3]; float y_offset; // doubleskies don't have a y-offset - FGameTexture * texture[2]; + FGameTexture * texture[3]; FTextureID skytexno1; bool mirrored; bool doublesky; @@ -351,7 +351,6 @@ public: }; - struct HWSkyPortal : public HWPortal { HWSkyInfo * origin; diff --git a/src/rendering/hwrenderer/scene/hw_sky.cpp b/src/rendering/hwrenderer/scene/hw_sky.cpp index ce89b545a..a3fc89902 100644 --- a/src/rendering/hwrenderer/scene/hw_sky.cpp +++ b/src/rendering/hwrenderer/scene/hw_sky.cpp @@ -118,6 +118,9 @@ void HWSkyInfo::init(HWDrawInfo *di, sector_t* sec, int skypos, int sky1, PalEnt } else fadecolor = 0; + texture[2] = TexMan.GetGameTexture(di->Level->skymisttexture); + x_offset[2] = di->Level->hw_skymistpos; + } diff --git a/src/rendering/hwrenderer/scene/hw_skyportal.cpp b/src/rendering/hwrenderer/scene/hw_skyportal.cpp index 656b9dd16..6f1e0c1da 100644 --- a/src/rendering/hwrenderer/scene/hw_skyportal.cpp +++ b/src/rendering/hwrenderer/scene/hw_skyportal.cpp @@ -74,19 +74,26 @@ void HWSkyPortal::DrawContents(HWDrawInfo *di, FRenderState &state) vertexBuffer->RenderDome(state, origin->texture[0], origin->x_offset[0], origin->y_offset, origin->mirrored, FSkyVertexBuffer::SKYMODE_MAINLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY)); state.SetTextureMode(TM_NORMAL); } - + state.AlphaFunc(Alpha_Greater, 0.f); if (origin->doublesky && origin->texture[1]) { vertexBuffer->RenderDome(state, origin->texture[1], origin->x_offset[1], origin->y_offset, false, FSkyVertexBuffer::SKYMODE_SECONDLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY)); } + } - if (di->Level->skyfog>0 && !di->isFullbrightScene() && (origin->fadecolor & 0xffffff) != 0) + if (di->Level->skyfog>0 && (origin->fadecolor & 0xffffff) != 0) + { + PalEntry FadeColor = origin->fadecolor; + FadeColor.a = clamp(di->Level->skyfog, 0, 255); + + if (di->Level->flags3 & LEVEL3_SKYMIST && origin->texture[2]) + { + vertexBuffer->RenderDome(state, origin->texture[2], origin->x_offset[2], 0.f, false, FSkyVertexBuffer::SKYMODE_FOGLAYER, !!(di->Level->flags & LEVEL_FORCETILEDSKY), 0, 0, FadeColor); + } + else if (!di->isFullbrightScene()) { - PalEntry FadeColor = origin->fadecolor; - FadeColor.a = clamp(di->Level->skyfog, 0, 255); - state.EnableTexture(false); state.SetObjectColor(FadeColor); state.Draw(DT_Triangles, 0, 12); diff --git a/src/rendering/r_sky.cpp b/src/rendering/r_sky.cpp index 4d9e2a5cf..22e339e0d 100644 --- a/src/rendering/r_sky.cpp +++ b/src/rendering/r_sky.cpp @@ -79,6 +79,10 @@ void InitSkyMap(FLevelLocals *Level) { Level->skytexture1 = TexMan.GetFrontSkyLayer(Level->skytexture1); } + if (Level->skymisttexture.isNull()) + { + Level->skymisttexture = TexMan.CheckForTexture("skymist1", ETextureType::Any); + } skytex1 = TexMan.GetGameTexture(Level->skytexture1, false); skytex2 = TexMan.GetGameTexture(Level->skytexture2, false); @@ -143,6 +147,7 @@ void R_UpdateSky (uint64_t mstime) // The hardware renderer uses a different value range and clamps it to a single rotation Level->hw_sky1pos = (float)(fmod((double(mstime) * Level->skyspeed1), 1024.) * (90. / 256.)); Level->hw_sky2pos = (float)(fmod((double(mstime) * Level->skyspeed2), 1024.) * (90. / 256.)); + Level->hw_skymistpos = (float)(fmod((double(mstime) * Level->skymistspeed), 1024.) * (90. / 256.)); } } diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 5d3aea03f..8388b8f9c 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -1738,6 +1738,15 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetXOffset, SetXOffset) return 0; } + DEFINE_ACTION_FUNCTION(FLevelLocals, ChangeSkyMist) + { + PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); + PARAM_INT(skymist); + self->skymisttexture = FSetTextureID(skymist); + InitSkyMap(self); + return 0; + } + DEFINE_ACTION_FUNCTION(FLevelLocals, StartIntermission) { PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals); @@ -2802,6 +2811,7 @@ DEFINE_FIELD_X(LevelInfo, level_info_t, NextMap) DEFINE_FIELD_X(LevelInfo, level_info_t, NextSecretMap) DEFINE_FIELD_X(LevelInfo, level_info_t, SkyPic1) DEFINE_FIELD_X(LevelInfo, level_info_t, SkyPic2) +DEFINE_FIELD_X(LevelInfo, level_info_t, SkyMistPic) DEFINE_FIELD_X(LevelInfo, level_info_t, F1Pic) DEFINE_FIELD_X(LevelInfo, level_info_t, cluster) DEFINE_FIELD_X(LevelInfo, level_info_t, partime) @@ -2817,6 +2827,7 @@ DEFINE_FIELD_X(LevelInfo, level_info_t, MapLabel) DEFINE_FIELD_X(LevelInfo, level_info_t, musicorder) DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed1) DEFINE_FIELD_X(LevelInfo, level_info_t, skyspeed2) +DEFINE_FIELD_X(LevelInfo, level_info_t, skymistspeed) DEFINE_FIELD_X(LevelInfo, level_info_t, cdtrack) DEFINE_FIELD_X(LevelInfo, level_info_t, gravity) DEFINE_FIELD_X(LevelInfo, level_info_t, aircontrol) @@ -2860,8 +2871,10 @@ DEFINE_FIELD(FLevelLocals, Music) DEFINE_FIELD(FLevelLocals, musicorder) DEFINE_FIELD(FLevelLocals, skytexture1) DEFINE_FIELD(FLevelLocals, skytexture2) +DEFINE_FIELD(FLevelLocals, skymisttexture) DEFINE_FIELD(FLevelLocals, skyspeed1) DEFINE_FIELD(FLevelLocals, skyspeed2) +DEFINE_FIELD(FLevelLocals, skymistspeed) DEFINE_FIELD(FLevelLocals, total_secrets) DEFINE_FIELD(FLevelLocals, found_secrets) DEFINE_FIELD(FLevelLocals, total_items)