diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 3dfb293da..a975cc1df 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -13,6 +13,7 @@ #include "simulation/gravity/Gravity.h" #include "simulation/orbitalparts.h" #include +#include void Renderer::RenderBackground() { @@ -264,7 +265,7 @@ void Renderer::render_parts() BlendPixel({ nx, ny }, 0x646464_rgb .WithAlpha(80)); } } - foundParticles = 0; + stats.foundParticles = 0; for(i = 0; i<=sim->parts.lastActiveIndex; i++) { if (sim->parts[i].type && sim->parts[i].type >= 0 && sim->parts[i].type < PT_NUM) { t = sim->parts[i].type; @@ -360,10 +361,8 @@ void Renderer::render_parts() //Alter colour based on display mode if(colorMode & COLOUR_HEAT) { - constexpr float min_temp = MIN_TEMP; - constexpr float max_temp = MAX_TEMP; firea = 255; - RGB color = heatTableAt(int((sim->parts[i].temp - min_temp) / (max_temp - min_temp) * 1024)); + RGB color = heatTableAt(int((sim->parts[i].temp - stats.hdispLimitMin) / (stats.hdispLimitMax - stats.hdispLimitMin) * 1024)); firer = colr = color.Red; fireg = colg = color.Green; fireb = colb = color.Blue; @@ -485,7 +484,7 @@ void Renderer::render_parts() { colr = firer = 255; colg = fireg = colb = fireb = 0; - foundParticles++; + stats.foundParticles++; } else { @@ -952,7 +951,7 @@ void Renderer::draw_air() } else if (displayMode & DISPLAY_AIRH) { - c = RGB::Unpack(HeatToColour(hv[y][x])); + c = RGB::Unpack(HeatToColour(hv[y][x], stats.hdispLimitMin, stats.hdispLimitMax)); //c = RGB(clamp_flt(fabsf(vx[y][x]), 0.0f, 8.0f),//vx adds red // clamp_flt(hv[y][x], 0.0f, 1600.0f),//heat adds green // clamp_flt(fabsf(vy[y][x]), 0.0f, 8.0f)).Pack();//vy adds blue @@ -1296,11 +1295,9 @@ void Renderer::render_fire() } } -int HeatToColour(float temp) +int HeatToColour(float temp, float hdispLimitMin, float hdispLimitMax) { - constexpr float min_temp = MIN_TEMP; - constexpr float max_temp = MAX_TEMP; - RGB color = Renderer::heatTableAt(int((temp - min_temp) / (max_temp - min_temp) * 1024)); + RGB color = Renderer::heatTableAt(int((temp - hdispLimitMin) / (hdispLimitMax - hdispLimitMin) * 1024)); color.Red = uint8_t(color.Red * 0.7f); color.Green = uint8_t(color.Green * 0.7f); color.Blue = uint8_t(color.Blue * 0.7f); @@ -1376,6 +1373,62 @@ const std::vector Renderer::renderModePresets = { }, }; +void Renderer::AdjustHdispLimit() +{ + stats.hdispLimitValid = false; + float autoHdispLimitMin = MAX_TEMP; + float autoHdispLimitMax = MIN_TEMP; + auto visit = [this, &autoHdispLimitMin, &autoHdispLimitMax](Vec2 point, float value) { + if (autoHdispLimitArea.Contains(point)) + { + autoHdispLimitMin = std::min(autoHdispLimitMin, value); + autoHdispLimitMax = std::max(autoHdispLimitMax, value); + stats.hdispLimitValid = true; + } + }; + if (std::holds_alternative(wantHdispLimitMin) || + std::holds_alternative(wantHdispLimitMax)) + { + auto &sd = SimulationData::CRef(); + for (int i = 0; i <= sim->parts.lastActiveIndex; ++i) + { + auto t = sim->parts[i].type; + if (t > 0 && t < PT_NUM) + { + if (!sd.elements[t].HeatConduct) + { + continue; + } + auto nx = int(sim->parts[i].x + 0.5f); + auto ny = int(sim->parts[i].y + 0.5f); + visit({ nx, ny }, sim->parts[i].temp); + } + } + if (sim->aheat_enable && (displayMode & DISPLAY_AIR) && (displayMode & DISPLAY_AIRH)) + { + auto *hv = sim->hv; + for (auto p : CELLS.OriginRect()) + { + visit(p * CELL, hv[p.Y][p.X]); + } + } + } + stats.hdispLimitMin = autoHdispLimitMin; + stats.hdispLimitMax = autoHdispLimitMax; + if (auto *hdispLimitExplicit = std::get_if(&wantHdispLimitMin)) + { + stats.hdispLimitMin = hdispLimitExplicit->value; + } + if (auto *hdispLimitExplicit = std::get_if(&wantHdispLimitMax)) + { + stats.hdispLimitMax = hdispLimitExplicit->value; + } + if (std::isnan(stats.hdispLimitMin)) stats.hdispLimitMin = MIN_TEMP; + if (std::isnan(stats.hdispLimitMax)) stats.hdispLimitMax = MAX_TEMP; + stats.hdispLimitMax = std::clamp(stats.hdispLimitMax, MIN_TEMP, MAX_TEMP); + stats.hdispLimitMin = std::clamp(stats.hdispLimitMin, MIN_TEMP, stats.hdispLimitMax); +} + void Renderer::Clear() { if(displayMode & DISPLAY_PERS) @@ -1386,6 +1439,7 @@ void Renderer::Clear() { std::fill_n(video.data(), WINDOWW * YRES, 0); } + AdjustHdispLimit(); } void Renderer::DrawBlob(Vec2 pos, RGB colour) diff --git a/src/graphics/Renderer.h b/src/graphics/Renderer.h index e554de3c4..7a414db08 100644 --- a/src/graphics/Renderer.h +++ b/src/graphics/Renderer.h @@ -25,14 +25,14 @@ struct GraphicsFuncContext Particle *pipeSubcallTpart; }; -int HeatToColour(float temp); +int HeatToColour(float temp, float hdispLimitMin, float hdispLimitMax); class Renderer : private RendererSettings, public RasterDrawMethods { RendererFrame video; std::array persistentVideo; RendererFrame warpVideo; - int foundParticles = 0; + RendererStats stats; Rect GetClipRect() const { @@ -59,6 +59,8 @@ class Renderer : private RendererSettings, public RasterDrawMethods void draw_grav(); void draw_other(); + void AdjustHdispLimit(); + public: Renderer(); void ApplySettings(const RendererSettings &newSettings); @@ -73,9 +75,9 @@ public: return video; } - int GetFoundParticles() const + RendererStats GetStats() const { - return foundParticles; + return stats; } const RenderableSimulation *sim = nullptr; diff --git a/src/graphics/RendererFrame.h b/src/graphics/RendererFrame.h index 4a02d4ac0..a546ffeaf 100644 --- a/src/graphics/RendererFrame.h +++ b/src/graphics/RendererFrame.h @@ -6,3 +6,11 @@ constexpr auto RendererFrameSize = Vec2{ WINDOW.X, RES.Y }; using RendererFrame = PlaneAdapter, RendererFrameSize.X, RendererFrameSize.Y>; + +struct RendererStats +{ + int foundParticles = 0; + float hdispLimitMin = 0; + float hdispLimitMax = 0; + bool hdispLimitValid = false; +}; diff --git a/src/graphics/RendererSettings.h b/src/graphics/RendererSettings.h index 36c5de0a5..12313224d 100644 --- a/src/graphics/RendererSettings.h +++ b/src/graphics/RendererSettings.h @@ -1,9 +1,23 @@ #pragma once #include "gui/interface/Point.h" #include "simulation/ElementGraphics.h" +#include "simulation/ElementDefs.h" #include "FindingElement.h" #include #include +#include + +struct HdispLimitExplicit +{ + float value; +}; +struct HdispLimitAuto +{ +}; +using HdispLimit = std::variant< + HdispLimitExplicit, + HdispLimitAuto +>; struct RendererSettings { @@ -24,4 +38,7 @@ struct RendererSettings ui::Point mousePos = { 0, 0 }; int gridSize = 0; float fireIntensity = 1; + HdispLimit wantHdispLimitMin = HdispLimitExplicit{ MIN_TEMP }; + HdispLimit wantHdispLimitMax = HdispLimitExplicit{ MAX_TEMP }; + Rect autoHdispLimitArea = RES.OriginRect(); }; diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index ce72a57e6..738a66e59 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -2166,7 +2166,7 @@ void GameView::OnDraw() StartRendererThread(); WaitForRendererThread(); AfterSimDraw(*sim); - foundParticles = ren->GetFoundParticles(); + rendererStats = ren->GetStats(); *rendererThreadResult = ren->GetVideo(); rendererFrame = rendererThreadResult.get(); DispatchRendererThread(); @@ -2177,7 +2177,7 @@ void GameView::OnDraw() ren->ApplySettings(*rendererSettings); RenderSimulation(*sim, true); AfterSimDraw(*sim); - foundParticles = ren->GetFoundParticles(); + rendererStats = ren->GetStats(); rendererFrame = &ren->GetVideo(); } } @@ -2525,10 +2525,19 @@ void GameView::OnDraw() if (showDebug) { if (rendererSettings->findingElement) - fpsInfo << " Parts: " << foundParticles << "/" << sample.NumParts; + fpsInfo << " Parts: " << rendererStats.foundParticles << "/" << sample.NumParts; else fpsInfo << " Parts: " << sample.NumParts; } + if ((std::holds_alternative(rendererSettings->wantHdispLimitMin) || + std::holds_alternative(rendererSettings->wantHdispLimitMax)) && rendererStats.hdispLimitValid) + { + fpsInfo << " [TEMP L:"; + format::RenderTemperature(fpsInfo, rendererStats.hdispLimitMin, c->GetTemperatureScale()); + fpsInfo << " H:"; + format::RenderTemperature(fpsInfo, rendererStats.hdispLimitMax, c->GetTemperatureScale()); + fpsInfo << "]"; + } if (c->GetReplaceModeFlags()&REPLACE_MODE) fpsInfo << " [REPLACE MODE]"; if (c->GetReplaceModeFlags()&SPECIFIC_DELETE) diff --git a/src/gui/game/GameView.h b/src/gui/game/GameView.h index 11c114896..897c57570 100644 --- a/src/gui/game/GameView.h +++ b/src/gui/game/GameView.h @@ -174,7 +174,7 @@ private: void DispatchRendererThread(); std::unique_ptr rendererThreadSim; std::unique_ptr rendererThreadResult; - int foundParticles = 0; + RendererStats rendererStats; const RendererFrame *rendererFrame = nullptr; SimFpsLimit simFpsLimit = FpsLimitExplicit{ 60.f }; diff --git a/src/gui/options/OptionsView.cpp b/src/gui/options/OptionsView.cpp index 20084d8b6..4e5bda5cd 100644 --- a/src/gui/options/OptionsView.cpp +++ b/src/gui/options/OptionsView.cpp @@ -411,7 +411,7 @@ void OptionsView::UpdateAmbientAirTempPreview(float airTemp, bool isValid) { if (isValid) { - ambientAirTempPreview->Appearance.BackgroundInactive = RGB::Unpack(HeatToColour(airTemp)).WithAlpha(0xFF); + ambientAirTempPreview->Appearance.BackgroundInactive = RGB::Unpack(HeatToColour(airTemp, MIN_TEMP, MAX_TEMP)).WithAlpha(0xFF); ambientAirTempPreview->SetText(""); } else diff --git a/src/lua/LuaRenderer.cpp b/src/lua/LuaRenderer.cpp index 470c02099..56c35d11d 100644 --- a/src/lua/LuaRenderer.cpp +++ b/src/lua/LuaRenderer.cpp @@ -243,6 +243,62 @@ static int separateThread(lua_State *L) return 1; } +static int heatDisplayLimits(lua_State *L) +{ + auto *lsi = GetLSI(); + lsi->AssertInterfaceEvent(); + auto &rendererSettings = lsi->gameModel->GetRendererSettings(); + if (lua_gettop(L)) + { + auto write = [L](auto &setting, int index) { + if (lua_isstring(L, index) && byteStringEqualsLiteral(tpt_lua_toByteString(L, index), "auto")) + { + setting = HdispLimitAuto{}; + } + else + { + setting = HdispLimitExplicit{ float(luaL_checknumber(L, index)) }; + } + }; + write(rendererSettings.wantHdispLimitMin, 1); + write(rendererSettings.wantHdispLimitMax, 2); + return 0; + } + auto read = [L](auto &setting) { + if (auto *hdispLimitExplicit = std::get_if(&setting)) + { + lua_pushnumber(L, hdispLimitExplicit->value); + } + else + { + lua_pushliteral(L, "auto"); + } + }; + read(rendererSettings.wantHdispLimitMin); + read(rendererSettings.wantHdispLimitMax); + return 2; +} + +static int heatDisplayAutoArea(lua_State *L) +{ + auto *lsi = GetLSI(); + lsi->AssertInterfaceEvent(); + auto &rendererSettings = lsi->gameModel->GetRendererSettings(); + if (lua_gettop(L)) + { + rendererSettings.autoHdispLimitArea.pos .X = luaL_checkinteger(L, 1); + rendererSettings.autoHdispLimitArea.pos .Y = luaL_checkinteger(L, 2); + rendererSettings.autoHdispLimitArea.size.X = luaL_checkinteger(L, 3); + rendererSettings.autoHdispLimitArea.size.Y = luaL_checkinteger(L, 4); + return 0; + } + lua_pushinteger(L, rendererSettings.autoHdispLimitArea.pos .X); + lua_pushinteger(L, rendererSettings.autoHdispLimitArea.pos .Y); + lua_pushinteger(L, rendererSettings.autoHdispLimitArea.size.X); + lua_pushinteger(L, rendererSettings.autoHdispLimitArea.size.Y); + return 4; +} + void LuaRenderer::Open(lua_State *L) { static const luaL_Reg reg[] = { @@ -262,6 +318,8 @@ void LuaRenderer::Open(lua_State *L) LFUNC(fireSize), LFUNC(useDisplayPreset), LFUNC(separateThread), + LFUNC(heatDisplayLimits), + LFUNC(heatDisplayAutoArea), #undef LFUNC { nullptr, nullptr } };