mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-08-06 08:27:27 +02:00
Do rendering on another thread when possible
"Possible" here means "when there are no particles with Lua graphics functions that haven't reported that they don't want to be called again and there are no beforesimdraw/aftersimdraw event handlers". I put my trust in Simulation::elementCount here; I sure hope it's always correct. If there is any of these, the renderer thread is paused and rendering happens on the main thread. To be clear, these are the situations in which Lua code is called with LuaScriptInterface::eventTraits having the eventTraitSimGraphics bit set. If the detection of this situation is somehow flawed, there will still be no crashes because when running on the renderer thread, Renderer is told to not call Lua functions, and GameController::BeforeSimDraw/AfterSimDraw is not called by GameView::RendererThread. The worst that can happen is that some particles are not rendered properly. Renderer settings (color and display modes, deco state, finding-element state, etc.) are managed by GameModel in the form of a RendererSettings and are passed to Renderer before each frame. The RenderableSimulation that Renderer works off of is also configured before each frame, either to point to a copy dedicated to the renderer thread, or directly to GameModel's Simulation, if the renderer thread is paused. Similarly, the result of the rendering is managed by GameView in the form of a RendererFrame, to enable e.g. sampling with deco tools without having to pause the renderer thread. Each time GameView::OnDraw is called, it checks whether rendering is allowed to happen on a different thread (see above for conditions). If it is, but the renderer thread is absent, GameView starts it and dispatches it (provides with settings and simulation data) right away. At this point, the renderer thread is definitely rendering a frame. GameView waits for this to finish and exchanges data with the renderer once it's done: it takes the result of the rendering and also dispatches the renderer thread again. This introduces a one-frame delay in rendering, which we can live with. If rendering is not allowed to happen on a different thread, GameView waits for the renderer thread to finish what it's currently doing and pauses it, then proceeds to render the frame by itself. Affecting this condition (whether rendering is allowed to happen on a different) by installing or removing event handlers, or clearing graphics cache (which, note, requires acquiring a unique lock on it), while the renderer thread is working, is not an issue because the renderer thread doesn't bother with event handlers, and because it acquires a shared lock on the graphics cache for rendering. The GameModel's Renderer is thus still primarily managed by GameView, potentially in two different threads, in a strictly non-overlapping manner. The exception to this is when RenderView butts in and starts doing renders of its own; in such cases, the renderer thread must be paused explicitly, as RenderView does by calling GameView::PauseRendererThread.
This commit is contained in:
@@ -52,8 +52,10 @@ int main(int argc, char *argv[])
|
||||
sim->Load(gameSave.get(), true, { 0, 0 });
|
||||
|
||||
//Render save
|
||||
ren->decorations_enable = true;
|
||||
ren->blackDecorations = true;
|
||||
RendererSettings rendererSettings;
|
||||
rendererSettings.decorations_enable = true;
|
||||
rendererSettings.blackDecorations = true;
|
||||
ren->ApplySettings(rendererSettings);
|
||||
|
||||
int frame = 15;
|
||||
while(frame)
|
||||
|
@@ -29,7 +29,7 @@ ThumbnailRendererTask::~ThumbnailRendererTask()
|
||||
|
||||
bool ThumbnailRendererTask::doWork()
|
||||
{
|
||||
thumbnail = SaveRenderer::Ref().Render(save.get(), decorations, fire);
|
||||
thumbnail = SaveRenderer::Ref().Render(save.get(), decorations, fire, RendererSettings{});
|
||||
if (thumbnail)
|
||||
{
|
||||
thumbnail->ResizeToFit(size, true);
|
||||
|
@@ -2,10 +2,9 @@
|
||||
#include "Icons.h"
|
||||
#include "RasterDrawMethods.h"
|
||||
#include "gui/game/RenderPreset.h"
|
||||
#include "gui/interface/Point.h"
|
||||
#include "RendererSettings.h"
|
||||
#include "common/tpt-rand.h"
|
||||
#include "RendererFrame.h"
|
||||
#include "FindingElement.h"
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
@@ -13,13 +12,13 @@
|
||||
#include <vector>
|
||||
|
||||
struct RenderPreset;
|
||||
struct RenderableSimulation;
|
||||
class Renderer;
|
||||
struct RenderableSimulation;
|
||||
struct Particle;
|
||||
|
||||
struct GraphicsFuncContext
|
||||
{
|
||||
const Renderer *ren;
|
||||
const RendererSettings *ren;
|
||||
const RenderableSimulation *sim;
|
||||
RNG rng;
|
||||
const Particle *pipeSubcallCpart;
|
||||
@@ -28,7 +27,7 @@ struct GraphicsFuncContext
|
||||
|
||||
int HeatToColour(float temp);
|
||||
|
||||
class Renderer: public RasterDrawMethods<Renderer>
|
||||
class Renderer : private RendererSettings, public RasterDrawMethods<Renderer>
|
||||
{
|
||||
RendererFrame video;
|
||||
std::array<pixel, WINDOW.X * RES.Y> persistentVideo;
|
||||
@@ -41,39 +40,24 @@ class Renderer: public RasterDrawMethods<Renderer>
|
||||
|
||||
friend struct RasterDrawMethods<Renderer>;
|
||||
|
||||
float fireIntensity = 1;
|
||||
RNG rng;
|
||||
unsigned char fire_r[YCELLS][XCELLS];
|
||||
unsigned char fire_g[YCELLS][XCELLS];
|
||||
unsigned char fire_b[YCELLS][XCELLS];
|
||||
unsigned int fire_alpha[CELL*3][CELL*3];
|
||||
|
||||
public:
|
||||
RNG rng;
|
||||
const RenderableSimulation *sim = nullptr;
|
||||
|
||||
const RendererFrame &GetVideo() const
|
||||
{
|
||||
return video;
|
||||
}
|
||||
|
||||
uint32_t renderMode = 0;
|
||||
uint32_t colorMode = 0;
|
||||
uint32_t displayMode = 0;
|
||||
const RenderableSimulation *sim = nullptr;
|
||||
|
||||
void ApplySettings(const RendererSettings &newSettings);
|
||||
|
||||
static const std::vector<RenderPreset> renderModePresets;
|
||||
//
|
||||
unsigned char fire_r[YCELLS][XCELLS];
|
||||
unsigned char fire_g[YCELLS][XCELLS];
|
||||
unsigned char fire_b[YCELLS][XCELLS];
|
||||
unsigned int fire_alpha[CELL*3][CELL*3];
|
||||
//
|
||||
bool gravityZonesEnabled;
|
||||
bool gravityFieldEnabled;
|
||||
int decorations_enable;
|
||||
bool blackDecorations;
|
||||
bool debugLines;
|
||||
std::optional<FindingElement> findingElement;
|
||||
int foundElements;
|
||||
|
||||
//Mouse position for debug information
|
||||
ui::Point mousePos;
|
||||
|
||||
//Renderers
|
||||
void RenderSimulation();
|
||||
|
||||
void DrawBlob(Vec2<int> pos, RGB<uint8_t> colour);
|
||||
@@ -81,10 +65,6 @@ public:
|
||||
void DrawSigns();
|
||||
void render_gravlensing(const RendererFrame &source);
|
||||
void render_fire();
|
||||
float GetFireIntensity() const
|
||||
{
|
||||
return fireIntensity;
|
||||
}
|
||||
void prepare_alpha(int size, float intensity);
|
||||
void render_parts();
|
||||
void draw_grav_zones();
|
||||
@@ -95,22 +75,6 @@ public:
|
||||
void ClearAccumulation();
|
||||
void clearScreen();
|
||||
|
||||
void draw_icon(int x, int y, Icon icon);
|
||||
|
||||
//...
|
||||
//Display mode modifiers
|
||||
void SetRenderMode(uint32_t newRenderMode);
|
||||
uint32_t GetRenderMode();
|
||||
void SetDisplayMode(uint32_t newDisplayMode);
|
||||
uint32_t GetDisplayMode();
|
||||
void SetColorMode(uint32_t newColorMode);
|
||||
uint32_t GetColorMode();
|
||||
|
||||
void ResetModes();
|
||||
|
||||
int GetGridSize() { return gridSize; }
|
||||
void SetGridSize(int value) { gridSize = value; }
|
||||
|
||||
static std::unique_ptr<VideoBuffer> WallIcon(int wallID, Vec2<int> size);
|
||||
|
||||
Renderer();
|
||||
@@ -140,7 +104,4 @@ public:
|
||||
RENDERER_TABLE(firwTable)
|
||||
#undef RENDERER_TABLE
|
||||
static void PopulateTables();
|
||||
|
||||
private:
|
||||
int gridSize;
|
||||
};
|
||||
|
@@ -180,15 +180,7 @@ void Renderer::PopulateTables()
|
||||
}
|
||||
}
|
||||
|
||||
Renderer::Renderer():
|
||||
gravityZonesEnabled(false),
|
||||
gravityFieldEnabled(false),
|
||||
decorations_enable(1),
|
||||
blackDecorations(false),
|
||||
debugLines(false),
|
||||
foundElements(0),
|
||||
mousePos(0, 0),
|
||||
gridSize(0)
|
||||
Renderer::Renderer()
|
||||
{
|
||||
PopulateTables();
|
||||
|
||||
@@ -197,9 +189,8 @@ Renderer::Renderer():
|
||||
memset(fire_b, 0, sizeof(fire_b));
|
||||
|
||||
//Set defauly display modes
|
||||
ResetModes();
|
||||
|
||||
prepare_alpha(CELL, 1.0f);
|
||||
ClearAccumulation();
|
||||
}
|
||||
|
||||
void Renderer::ClearAccumulation()
|
||||
@@ -210,51 +201,17 @@ void Renderer::ClearAccumulation()
|
||||
std::fill(persistentVideo.begin(), persistentVideo.end(), 0);
|
||||
}
|
||||
|
||||
void Renderer::SetRenderMode(uint32_t newRenderMode)
|
||||
void Renderer::ApplySettings(const RendererSettings &newSettings)
|
||||
{
|
||||
int oldRenderMode = renderMode;
|
||||
renderMode = newRenderMode;
|
||||
if (!(renderMode & FIREMODE) && (oldRenderMode & FIREMODE))
|
||||
if (!(newSettings.renderMode & FIREMODE) && (renderMode & FIREMODE))
|
||||
{
|
||||
ClearAccumulation();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Renderer::GetRenderMode()
|
||||
{
|
||||
return renderMode;
|
||||
}
|
||||
|
||||
void Renderer::SetDisplayMode(uint32_t newDisplayMode)
|
||||
{
|
||||
int oldDisplayMode = displayMode;
|
||||
displayMode = newDisplayMode;
|
||||
if (!(displayMode & DISPLAY_PERS) && (oldDisplayMode & DISPLAY_PERS))
|
||||
if (!(newSettings.displayMode & DISPLAY_PERS) && (displayMode & DISPLAY_PERS))
|
||||
{
|
||||
ClearAccumulation();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Renderer::GetDisplayMode()
|
||||
{
|
||||
return displayMode;
|
||||
}
|
||||
|
||||
void Renderer::SetColorMode(uint32_t newColorMode)
|
||||
{
|
||||
colorMode = newColorMode;
|
||||
}
|
||||
|
||||
uint32_t Renderer::GetColorMode()
|
||||
{
|
||||
return colorMode;
|
||||
}
|
||||
|
||||
void Renderer::ResetModes()
|
||||
{
|
||||
SetRenderMode(RENDER_BASC | RENDER_FIRE | RENDER_SPRK | RENDER_EFFE);
|
||||
SetDisplayMode(0);
|
||||
SetColorMode(COLOUR_DEFAULT);
|
||||
static_cast<RendererSettings &>(*this) = newSettings;
|
||||
}
|
||||
|
||||
template struct RasterDrawMethods<Renderer>;
|
||||
|
23
src/graphics/RendererSettings.h
Normal file
23
src/graphics/RendererSettings.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "gui/interface/Point.h"
|
||||
#include "simulation/ElementGraphics.h"
|
||||
#include "FindingElement.h"
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
struct RendererSettings
|
||||
{
|
||||
uint32_t renderMode = RENDER_BASC | RENDER_FIRE | RENDER_SPRK | RENDER_EFFE;
|
||||
uint32_t displayMode = 0;
|
||||
uint32_t colorMode = COLOUR_DEFAULT;
|
||||
std::optional<FindingElement> findingElement;
|
||||
bool gravityZonesEnabled = false;
|
||||
bool gravityFieldEnabled = false;
|
||||
int decorations_enable = 1;
|
||||
bool blackDecorations = false;
|
||||
bool debugLines = false;
|
||||
int foundElements = 0;
|
||||
ui::Point mousePos = { 0, 0 };
|
||||
int gridSize = 0;
|
||||
float fireIntensity = 1;
|
||||
};
|
@@ -271,9 +271,9 @@ void GameController::Install()
|
||||
void GameController::AdjustGridSize(int direction)
|
||||
{
|
||||
if(direction > 0)
|
||||
gameModel->GetRenderer()->SetGridSize((gameModel->GetRenderer()->GetGridSize()+1)%10);
|
||||
gameModel->GetRendererSettings().gridSize = (gameModel->GetRendererSettings().gridSize+1)%10;
|
||||
else
|
||||
gameModel->GetRenderer()->SetGridSize((gameModel->GetRenderer()->GetGridSize()+9)%10);
|
||||
gameModel->GetRendererSettings().gridSize = (gameModel->GetRendererSettings().gridSize+9)%10;
|
||||
}
|
||||
|
||||
void GameController::InvertAirSim()
|
||||
@@ -851,19 +851,19 @@ void GameController::ToggleNewtonianGravity()
|
||||
|
||||
void GameController::LoadRenderPreset(int presetNum)
|
||||
{
|
||||
Renderer * renderer = gameModel->GetRenderer();
|
||||
auto &settings = gameModel->GetRendererSettings();
|
||||
RenderPreset preset = Renderer::renderModePresets[presetNum];
|
||||
gameModel->SetInfoTip(preset.Name);
|
||||
renderer->SetRenderMode(preset.renderMode);
|
||||
renderer->SetDisplayMode(preset.displayMode);
|
||||
renderer->SetColorMode(preset.colorMode);
|
||||
settings.renderMode = preset.renderMode;
|
||||
settings.displayMode = preset.displayMode;
|
||||
settings.colorMode = preset.colorMode;
|
||||
}
|
||||
|
||||
void GameController::Update()
|
||||
{
|
||||
auto &sd = SimulationData::CRef();
|
||||
ui::Point pos = gameView->GetMousePosition();
|
||||
gameModel->GetRenderer()->mousePos = PointTranslate(pos);
|
||||
gameModel->GetRendererSettings().mousePos = PointTranslate(pos);
|
||||
if (pos.X < XRES && pos.Y < YRES)
|
||||
gameView->SetSample(gameModel->GetSimulation()->GetSample(PointTranslate(pos).X, PointTranslate(pos).Y));
|
||||
else
|
||||
@@ -1106,7 +1106,7 @@ void GameController::SetActiveTool(int toolSelection, Tool * tool)
|
||||
if (gameModel->GetActiveMenu() == SC_DECO && toolSelection == 2)
|
||||
toolSelection = 0;
|
||||
gameModel->SetActiveTool(toolSelection, tool);
|
||||
gameModel->GetRenderer()->gravityZonesEnabled = false;
|
||||
gameModel->GetRendererSettings().gravityZonesEnabled = false;
|
||||
if (toolSelection == 3)
|
||||
gameModel->GetSimulation()->replaceModeSelected = tool->ToolID;
|
||||
gameModel->SetLastTool(tool);
|
||||
@@ -1115,7 +1115,7 @@ void GameController::SetActiveTool(int toolSelection, Tool * tool)
|
||||
auto *activeTool = gameModel->GetActiveTool(i);
|
||||
if (activeTool && activeTool->Identifier == "DEFAULT_WL_GRVTY")
|
||||
{
|
||||
gameModel->GetRenderer()->gravityZonesEnabled = true;
|
||||
gameModel->GetRendererSettings().gravityZonesEnabled = true;
|
||||
}
|
||||
}
|
||||
if (tool->Identifier == "DEFAULT_UI_PROPERTY")
|
||||
@@ -1404,7 +1404,7 @@ void GameController::HideConsole()
|
||||
|
||||
void GameController::OpenRenderOptions()
|
||||
{
|
||||
renderOptions = new RenderController(gameModel->GetSimulation(), gameModel->GetRenderer(), NULL);
|
||||
renderOptions = new RenderController(gameModel->GetSimulation(), gameModel->GetRenderer(), &gameModel->GetRendererSettings(), NULL);
|
||||
ui::Engine::Ref().ShowWindow(renderOptions->GetView());
|
||||
}
|
||||
|
||||
@@ -1727,3 +1727,8 @@ void GameController::AfterSimDraw()
|
||||
{
|
||||
commandInterface->HandleEvent(AfterSimDrawEvent{});
|
||||
}
|
||||
|
||||
bool GameController::HaveSimGraphicsEventHandlers()
|
||||
{
|
||||
return commandInterface->HaveSimGraphicsEventHandlers();
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "lua/CommandInterfacePtr.h"
|
||||
#include "client/ClientListener.h"
|
||||
#include "client/StartupInfo.h"
|
||||
#include "common/ExplicitSingleton.h"
|
||||
#include "gui/interface/Point.h"
|
||||
#include "gui/interface/Colour.h"
|
||||
#include "gui/SavePreviewType.h"
|
||||
@@ -37,7 +38,7 @@ class GameSave;
|
||||
class LoginController;
|
||||
class TagsController;
|
||||
class ConsoleController;
|
||||
class GameController: public ClientListener
|
||||
class GameController : public ClientListener, public ExplicitSingleton<GameController>
|
||||
{
|
||||
CommandInterfacePtr commandInterface;
|
||||
|
||||
@@ -204,4 +205,5 @@ public:
|
||||
|
||||
void BeforeSimDraw();
|
||||
void AfterSimDraw();
|
||||
bool HaveSimGraphicsEventHandlers();
|
||||
};
|
||||
|
@@ -91,15 +91,15 @@ GameModel::GameModel():
|
||||
setFunc(*pref);
|
||||
};
|
||||
handleOldModes("Renderer.RenderMode", "Renderer.RenderModes", RENDER_FIRE | RENDER_EFFE | RENDER_BASC, [this](uint32_t renderMode) {
|
||||
ren->SetRenderMode(renderMode);
|
||||
rendererSettings.renderMode = renderMode;
|
||||
});
|
||||
handleOldModes("Renderer.DisplayMode", "Renderer.DisplayModes", 0, [this](uint32_t displayMode) {
|
||||
ren->SetDisplayMode(displayMode);
|
||||
rendererSettings.displayMode = displayMode;
|
||||
});
|
||||
ren->SetColorMode(prefs.Get("Renderer.ColourMode", UINT32_C(0)));
|
||||
rendererSettings.colorMode = prefs.Get("Renderer.ColourMode", UINT32_C(0));
|
||||
|
||||
ren->gravityFieldEnabled = prefs.Get("Renderer.GravityField", false);
|
||||
ren->decorations_enable = prefs.Get("Renderer.Decorations", true);
|
||||
rendererSettings.gravityFieldEnabled = prefs.Get("Renderer.GravityField", false);
|
||||
rendererSettings.decorations_enable = prefs.Get("Renderer.Decorations", true);
|
||||
|
||||
//Load config into simulation
|
||||
edgeMode = prefs.Get("Simulation.EdgeMode", NUM_EDGEMODES, EDGE_VOID);
|
||||
@@ -170,12 +170,12 @@ GameModel::~GameModel()
|
||||
{
|
||||
//Save to config:
|
||||
Prefs::DeferWrite dw(prefs);
|
||||
prefs.Set("Renderer.ColourMode", ren->GetColorMode());
|
||||
prefs.Set("Renderer.DisplayMode", ren->GetDisplayMode());
|
||||
prefs.Set("Renderer.RenderMode", ren->GetRenderMode());
|
||||
prefs.Set("Renderer.GravityField", (bool)ren->gravityFieldEnabled);
|
||||
prefs.Set("Renderer.Decorations", (bool)ren->decorations_enable);
|
||||
prefs.Set("Renderer.DebugMode", ren->debugLines); //These two should always be equivalent, even though they are different things
|
||||
prefs.Set("Renderer.ColourMode", rendererSettings.colorMode);
|
||||
prefs.Set("Renderer.DisplayMode", rendererSettings.displayMode);
|
||||
prefs.Set("Renderer.RenderMode", rendererSettings.renderMode);
|
||||
prefs.Set("Renderer.GravityField", (bool)rendererSettings.gravityFieldEnabled);
|
||||
prefs.Set("Renderer.Decorations", (bool)rendererSettings.decorations_enable);
|
||||
prefs.Set("Renderer.DebugMode", rendererSettings.debugLines); //These two should always be equivalent, even though they are different things
|
||||
prefs.Set("Simulation.NewtonianGravity", bool(sim->grav));
|
||||
prefs.Set("Simulation.AmbientHeat", sim->aheat_enable);
|
||||
prefs.Set("Simulation.PrettyPowder", sim->pretty_powder);
|
||||
@@ -1260,9 +1260,9 @@ bool GameModel::GetPaused()
|
||||
|
||||
void GameModel::SetDecoration(bool decorationState)
|
||||
{
|
||||
if (ren->decorations_enable != (decorationState?1:0))
|
||||
if (rendererSettings.decorations_enable != (decorationState?1:0))
|
||||
{
|
||||
ren->decorations_enable = decorationState?1:0;
|
||||
rendererSettings.decorations_enable = decorationState?1:0;
|
||||
notifyDecorationChanged();
|
||||
UpdateQuickOptions();
|
||||
if (decorationState)
|
||||
@@ -1274,7 +1274,7 @@ void GameModel::SetDecoration(bool decorationState)
|
||||
|
||||
bool GameModel::GetDecoration()
|
||||
{
|
||||
return ren->decorations_enable?true:false;
|
||||
return rendererSettings.decorations_enable?true:false;
|
||||
}
|
||||
|
||||
void GameModel::SetAHeatEnable(bool aHeat)
|
||||
@@ -1318,7 +1318,7 @@ bool GameModel::GetNewtonianGrvity()
|
||||
|
||||
void GameModel::ShowGravityGrid(bool showGrid)
|
||||
{
|
||||
ren->gravityFieldEnabled = showGrid;
|
||||
rendererSettings.gravityFieldEnabled = showGrid;
|
||||
if (showGrid)
|
||||
SetInfoTip("Gravity Grid: On");
|
||||
else
|
||||
@@ -1327,7 +1327,7 @@ void GameModel::ShowGravityGrid(bool showGrid)
|
||||
|
||||
bool GameModel::GetGravityGrid()
|
||||
{
|
||||
return ren->gravityFieldEnabled;
|
||||
return rendererSettings.gravityFieldEnabled;
|
||||
}
|
||||
|
||||
void GameModel::FrameStep(int frames)
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#include "gui/interface/Colour.h"
|
||||
#include "client/User.h"
|
||||
#include "gui/interface/Point.h"
|
||||
#include "graphics/RendererSettings.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
@@ -66,6 +67,7 @@ private:
|
||||
|
||||
Simulation * sim;
|
||||
Renderer * ren;
|
||||
RendererSettings rendererSettings;
|
||||
std::vector<Menu*> menuList;
|
||||
std::vector<QuickOption*> quickOptions;
|
||||
int activeMenu;
|
||||
@@ -231,6 +233,10 @@ public:
|
||||
void SetUser(User user);
|
||||
Simulation * GetSimulation();
|
||||
Renderer * GetRenderer();
|
||||
RendererSettings &GetRendererSettings()
|
||||
{
|
||||
return rendererSettings;
|
||||
}
|
||||
void SetZoomEnabled(bool enabled);
|
||||
bool GetZoomEnabled();
|
||||
void SetZoomSize(int size);
|
||||
|
@@ -203,7 +203,6 @@ GameView::GameView():
|
||||
recordingFolder(0),
|
||||
currentPoint(ui::Point(0, 0)),
|
||||
lastPoint(ui::Point(0, 0)),
|
||||
ren(NULL),
|
||||
activeBrush(NULL),
|
||||
saveSimulationButtonEnabled(false),
|
||||
saveReuploadAllowed(true),
|
||||
@@ -332,6 +331,7 @@ GameView::GameView():
|
||||
|
||||
GameView::~GameView()
|
||||
{
|
||||
StopRendererThread();
|
||||
if(!colourPicker->GetParentWindow())
|
||||
delete colourPicker;
|
||||
|
||||
@@ -470,8 +470,7 @@ bool GameView::GetBrushEnable()
|
||||
void GameView::SetDebugHUD(bool mode)
|
||||
{
|
||||
showDebug = mode;
|
||||
if (ren)
|
||||
ren->debugLines = showDebug;
|
||||
rendererSettings->debugLines = showDebug;
|
||||
}
|
||||
|
||||
bool GameView::GetDebugHUD()
|
||||
@@ -518,9 +517,10 @@ void GameView::NotifyActiveToolsChanged(GameModel * sender)
|
||||
|
||||
decoBrush = sender->GetActiveTool(0)->Identifier.BeginsWith("DEFAULT_DECOR_");
|
||||
|
||||
if (sender->GetRenderer()->findingElement)
|
||||
auto &settings = sender->GetRendererSettings();
|
||||
if (settings.findingElement)
|
||||
{
|
||||
ren->findingElement = FindingElementCandidate();
|
||||
settings.findingElement = FindingElementCandidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,6 +734,7 @@ void GameView::NotifyColourSelectorColourChanged(GameModel * sender)
|
||||
void GameView::NotifyRendererChanged(GameModel * sender)
|
||||
{
|
||||
ren = sender->GetRenderer();
|
||||
rendererSettings = &sender->GetRendererSettings();
|
||||
}
|
||||
|
||||
void GameView::NotifySimulationChanged(GameModel * sender)
|
||||
@@ -1443,13 +1444,13 @@ void GameView::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl,
|
||||
if (ctrl)
|
||||
{
|
||||
auto findingElementCandidate = FindingElementCandidate();
|
||||
if (ren->findingElement == findingElementCandidate)
|
||||
if (rendererSettings->findingElement == findingElementCandidate)
|
||||
{
|
||||
ren->findingElement = std::nullopt;
|
||||
rendererSettings->findingElement = std::nullopt;
|
||||
}
|
||||
else
|
||||
{
|
||||
ren->findingElement = findingElementCandidate;
|
||||
rendererSettings->findingElement = findingElementCandidate;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1982,7 +1983,7 @@ void GameView::NotifyTransformedPlaceSaveChanged(GameModel *sender)
|
||||
{
|
||||
if (sender->GetTransformedPlaceSave())
|
||||
{
|
||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRenderer());
|
||||
placeSaveThumb = SaveRenderer::Ref().Render(sender->GetTransformedPlaceSave(), true, true, sender->GetRendererSettings());
|
||||
selectMode = PlaceSave;
|
||||
selectPoint2 = mousePosition;
|
||||
}
|
||||
@@ -2126,166 +2127,189 @@ void GameView::SetSaveButtonTooltips()
|
||||
saveSimulationButton->SetToolTips("Re-upload the current simulation", "Upload a new simulation. Hold Ctrl to save offline.");
|
||||
}
|
||||
|
||||
void GameView::RenderSimulation(const RenderableSimulation &sim, bool handleEvents)
|
||||
{
|
||||
ren->sim = ∼
|
||||
ren->clearScreen();
|
||||
ren->draw_air();
|
||||
if (handleEvents)
|
||||
{
|
||||
c->BeforeSimDraw();
|
||||
}
|
||||
{
|
||||
// we may write graphicscache here
|
||||
auto &sd = SimulationData::Ref();
|
||||
std::unique_lock lk(sd.elementGraphicsMx);
|
||||
ren->RenderSimulation();
|
||||
}
|
||||
if (handleEvents)
|
||||
{
|
||||
c->AfterSimDraw();
|
||||
}
|
||||
ren->sim = nullptr;
|
||||
}
|
||||
|
||||
void GameView::OnDraw()
|
||||
{
|
||||
Graphics * g = GetGraphics();
|
||||
if (ren)
|
||||
|
||||
auto wantRendererThread = !c->HaveSimGraphicsEventHandlers();
|
||||
if (wantRendererThread)
|
||||
{
|
||||
// we're the main thread, we may write graphicscache
|
||||
auto &sd = SimulationData::Ref();
|
||||
std::unique_lock lk(sd.elementGraphicsMx);
|
||||
ren->sim = sim;
|
||||
ren->clearScreen();
|
||||
ren->draw_air();
|
||||
c->BeforeSimDraw();
|
||||
ren->RenderSimulation();
|
||||
ren->sim = nullptr;
|
||||
|
||||
c->AfterSimDraw();
|
||||
|
||||
StartRendererThread();
|
||||
WaitForRendererThread();
|
||||
rendererFrame = ren->GetVideo();
|
||||
std::copy_n(rendererFrame.data(), rendererFrame.Size().X * rendererFrame.Size().Y, g->Data());
|
||||
DispatchRendererThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
PauseRendererThread();
|
||||
ren->ApplySettings(*rendererSettings);
|
||||
RenderSimulation(*sim, true);
|
||||
rendererFrame = ren->GetVideo();
|
||||
}
|
||||
|
||||
if (showBrush && selectMode == SelectNone && (!zoomEnabled || zoomCursorFixed) && activeBrush && (isMouseDown || (currentMouse.X >= 0 && currentMouse.X < XRES && currentMouse.Y >= 0 && currentMouse.Y < YRES)))
|
||||
std::copy_n(rendererFrame.data(), rendererFrame.Size().X * rendererFrame.Size().Y, g->Data());
|
||||
|
||||
if (showBrush && selectMode == SelectNone && (!zoomEnabled || zoomCursorFixed) && activeBrush && (isMouseDown || (currentMouse.X >= 0 && currentMouse.X < XRES && currentMouse.Y >= 0 && currentMouse.Y < YRES)))
|
||||
{
|
||||
ui::Point finalCurrentMouse = windTool ? c->PointTranslateNoClamp(currentMouse) : c->PointTranslate(currentMouse);
|
||||
ui::Point initialDrawPoint = drawPoint1;
|
||||
|
||||
if (wallBrush)
|
||||
{
|
||||
ui::Point finalCurrentMouse = windTool ? c->PointTranslateNoClamp(currentMouse) : c->PointTranslate(currentMouse);
|
||||
ui::Point initialDrawPoint = drawPoint1;
|
||||
|
||||
if (wallBrush)
|
||||
{
|
||||
finalCurrentMouse = c->NormaliseBlockCoord(finalCurrentMouse);
|
||||
initialDrawPoint = c->NormaliseBlockCoord(initialDrawPoint);
|
||||
}
|
||||
|
||||
if (drawMode == DrawRect && isMouseDown)
|
||||
{
|
||||
if (drawSnap)
|
||||
{
|
||||
finalCurrentMouse = rectSnapCoords(c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
if (wallBrush)
|
||||
{
|
||||
if (finalCurrentMouse.X > initialDrawPoint.X)
|
||||
finalCurrentMouse.X += CELL-1;
|
||||
else
|
||||
initialDrawPoint.X += CELL-1;
|
||||
|
||||
if (finalCurrentMouse.Y > initialDrawPoint.Y)
|
||||
finalCurrentMouse.Y += CELL-1;
|
||||
else
|
||||
initialDrawPoint.Y += CELL-1;
|
||||
}
|
||||
activeBrush->RenderRect(g, c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
else if (drawMode == DrawLine && isMouseDown)
|
||||
{
|
||||
if (drawSnap)
|
||||
{
|
||||
finalCurrentMouse = lineSnapCoords(c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
activeBrush->RenderLine(g, c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
else if (drawMode == DrawFill)// || altBehaviour)
|
||||
{
|
||||
if (!decoBrush)
|
||||
activeBrush->RenderFill(g, finalCurrentMouse);
|
||||
}
|
||||
if (drawMode == DrawPoints || drawMode==DrawLine || (drawMode == DrawRect && !isMouseDown))
|
||||
{
|
||||
if (wallBrush)
|
||||
{
|
||||
ui::Point finalBrushRadius = c->NormaliseBlockCoord(activeBrush->GetRadius());
|
||||
auto topLeft = finalCurrentMouse - finalBrushRadius;
|
||||
auto bottomRight = finalCurrentMouse + finalBrushRadius + Vec2{ CELL - 1, CELL - 1 };
|
||||
g->XorLine({ topLeft.X, topLeft.Y }, { bottomRight.X, topLeft.Y });
|
||||
g->XorLine({ topLeft.X, bottomRight.Y }, { bottomRight.X, bottomRight.Y });
|
||||
g->XorLine({ topLeft.X, topLeft.Y + 1 }, { topLeft.X, bottomRight.Y - 1 }); // offset by 1 so the corners don't get xor'd twice
|
||||
g->XorLine({ bottomRight.X, topLeft.Y + 1 }, { bottomRight.X, bottomRight.Y - 1 }); // offset by 1 so the corners don't get xor'd twice
|
||||
}
|
||||
else
|
||||
{
|
||||
activeBrush->RenderPoint(g, finalCurrentMouse);
|
||||
}
|
||||
}
|
||||
finalCurrentMouse = c->NormaliseBlockCoord(finalCurrentMouse);
|
||||
initialDrawPoint = c->NormaliseBlockCoord(initialDrawPoint);
|
||||
}
|
||||
|
||||
if(selectMode!=SelectNone)
|
||||
if (drawMode == DrawRect && isMouseDown)
|
||||
{
|
||||
if(selectMode==PlaceSave)
|
||||
if (drawSnap)
|
||||
{
|
||||
if(placeSaveThumb && selectPoint2.X!=-1)
|
||||
{
|
||||
auto rect = RectSized(PlaceSavePos() * CELL, placeSaveThumb->Size());
|
||||
g->BlendImage(placeSaveThumb->Data(), 0x80, rect);
|
||||
g->XorDottedRect(rect);
|
||||
}
|
||||
finalCurrentMouse = rectSnapCoords(c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
if (wallBrush)
|
||||
{
|
||||
if (finalCurrentMouse.X > initialDrawPoint.X)
|
||||
finalCurrentMouse.X += CELL-1;
|
||||
else
|
||||
initialDrawPoint.X += CELL-1;
|
||||
|
||||
if (finalCurrentMouse.Y > initialDrawPoint.Y)
|
||||
finalCurrentMouse.Y += CELL-1;
|
||||
else
|
||||
initialDrawPoint.Y += CELL-1;
|
||||
}
|
||||
activeBrush->RenderRect(g, c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
else if (drawMode == DrawLine && isMouseDown)
|
||||
{
|
||||
if (drawSnap)
|
||||
{
|
||||
finalCurrentMouse = lineSnapCoords(c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
activeBrush->RenderLine(g, c->PointTranslate(initialDrawPoint), finalCurrentMouse);
|
||||
}
|
||||
else if (drawMode == DrawFill)// || altBehaviour)
|
||||
{
|
||||
if (!decoBrush)
|
||||
activeBrush->RenderFill(g, finalCurrentMouse);
|
||||
}
|
||||
if (drawMode == DrawPoints || drawMode==DrawLine || (drawMode == DrawRect && !isMouseDown))
|
||||
{
|
||||
if (wallBrush)
|
||||
{
|
||||
ui::Point finalBrushRadius = c->NormaliseBlockCoord(activeBrush->GetRadius());
|
||||
auto topLeft = finalCurrentMouse - finalBrushRadius;
|
||||
auto bottomRight = finalCurrentMouse + finalBrushRadius + Vec2{ CELL - 1, CELL - 1 };
|
||||
g->XorLine({ topLeft.X, topLeft.Y }, { bottomRight.X, topLeft.Y });
|
||||
g->XorLine({ topLeft.X, bottomRight.Y }, { bottomRight.X, bottomRight.Y });
|
||||
g->XorLine({ topLeft.X, topLeft.Y + 1 }, { topLeft.X, bottomRight.Y - 1 }); // offset by 1 so the corners don't get xor'd twice
|
||||
g->XorLine({ bottomRight.X, topLeft.Y + 1 }, { bottomRight.X, bottomRight.Y - 1 }); // offset by 1 so the corners don't get xor'd twice
|
||||
}
|
||||
else
|
||||
{
|
||||
if(selectPoint1.X==-1)
|
||||
{
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, 0 }, Vec2{ XRES, YRES }), 0x000000_rgb .WithAlpha(100));
|
||||
}
|
||||
else
|
||||
{
|
||||
int x2 = (selectPoint1.X>selectPoint2.X)?selectPoint1.X:selectPoint2.X;
|
||||
int y2 = (selectPoint1.Y>selectPoint2.Y)?selectPoint1.Y:selectPoint2.Y;
|
||||
int x1 = (selectPoint2.X<selectPoint1.X)?selectPoint2.X:selectPoint1.X;
|
||||
int y1 = (selectPoint2.Y<selectPoint1.Y)?selectPoint2.Y:selectPoint1.Y;
|
||||
|
||||
if(x2>XRES-1)
|
||||
x2 = XRES-1;
|
||||
if(y2>YRES-1)
|
||||
y2 = YRES-1;
|
||||
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, 0 }, Vec2{ XRES, y1 }), 0x000000_rgb .WithAlpha(100));
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, y2+1 }, Vec2{ XRES, YRES-y2-1 }), 0x000000_rgb .WithAlpha(100));
|
||||
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, y1 }, Vec2{ x1, (y2-y1)+1 }), 0x000000_rgb .WithAlpha(100));
|
||||
g->BlendFilledRect(RectSized(Vec2{ x2+1, y1 }, Vec2{ XRES-x2-1, (y2-y1)+1 }), 0x000000_rgb .WithAlpha(100));
|
||||
|
||||
g->XorDottedRect(RectBetween(Vec2{ x1, y1 }, Vec2{ x2, y2 }));
|
||||
}
|
||||
activeBrush->RenderPoint(g, finalCurrentMouse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g->RenderZoom();
|
||||
|
||||
if (doScreenshot)
|
||||
if(selectMode!=SelectNone)
|
||||
{
|
||||
if(selectMode==PlaceSave)
|
||||
{
|
||||
doScreenshot = false;
|
||||
TakeScreenshot(0, 0);
|
||||
}
|
||||
|
||||
if(recording)
|
||||
{
|
||||
std::vector<char> data = VideoBuffer(rendererFrame).ToPPM();
|
||||
|
||||
ByteString filename = ByteString::Build("recordings", PATH_SEP_CHAR, recordingFolder, PATH_SEP_CHAR, "frame_", Format::Width(recordingIndex++, 6), ".ppm");
|
||||
|
||||
Platform::WriteFile(data, filename);
|
||||
}
|
||||
|
||||
if (logEntries.size())
|
||||
{
|
||||
int startX = 20;
|
||||
int startY = YRES-20;
|
||||
std::deque<std::pair<String, int> >::iterator iter;
|
||||
for(iter = logEntries.begin(); iter != logEntries.end(); iter++)
|
||||
if(placeSaveThumb && selectPoint2.X!=-1)
|
||||
{
|
||||
String message = (*iter).first;
|
||||
int alpha = std::min((*iter).second, 255);
|
||||
if (alpha <= 0) //erase this and everything older
|
||||
{
|
||||
logEntries.erase(iter, logEntries.end());
|
||||
break;
|
||||
}
|
||||
startY -= 14;
|
||||
g->BlendFilledRect(RectSized(Vec2{ startX-3, startY-3 }, Vec2{ Graphics::TextSize(message).X + 5, 14 }), 0x000000_rgb .WithAlpha(std::min(100, alpha)));
|
||||
g->BlendText({ startX, startY }, message, 0xFFFFFF_rgb .WithAlpha(alpha));
|
||||
(*iter).second -= 3;
|
||||
auto rect = RectSized(PlaceSavePos() * CELL, placeSaveThumb->Size());
|
||||
g->BlendImage(placeSaveThumb->Data(), 0x80, rect);
|
||||
g->XorDottedRect(rect);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(selectPoint1.X==-1)
|
||||
{
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, 0 }, Vec2{ XRES, YRES }), 0x000000_rgb .WithAlpha(100));
|
||||
}
|
||||
else
|
||||
{
|
||||
int x2 = (selectPoint1.X>selectPoint2.X)?selectPoint1.X:selectPoint2.X;
|
||||
int y2 = (selectPoint1.Y>selectPoint2.Y)?selectPoint1.Y:selectPoint2.Y;
|
||||
int x1 = (selectPoint2.X<selectPoint1.X)?selectPoint2.X:selectPoint1.X;
|
||||
int y1 = (selectPoint2.Y<selectPoint1.Y)?selectPoint2.Y:selectPoint1.Y;
|
||||
|
||||
if(x2>XRES-1)
|
||||
x2 = XRES-1;
|
||||
if(y2>YRES-1)
|
||||
y2 = YRES-1;
|
||||
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, 0 }, Vec2{ XRES, y1 }), 0x000000_rgb .WithAlpha(100));
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, y2+1 }, Vec2{ XRES, YRES-y2-1 }), 0x000000_rgb .WithAlpha(100));
|
||||
|
||||
g->BlendFilledRect(RectSized(Vec2{ 0, y1 }, Vec2{ x1, (y2-y1)+1 }), 0x000000_rgb .WithAlpha(100));
|
||||
g->BlendFilledRect(RectSized(Vec2{ x2+1, y1 }, Vec2{ XRES-x2-1, (y2-y1)+1 }), 0x000000_rgb .WithAlpha(100));
|
||||
|
||||
g->XorDottedRect(RectBetween(Vec2{ x1, y1 }, Vec2{ x2, y2 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g->RenderZoom();
|
||||
|
||||
if (doScreenshot)
|
||||
{
|
||||
doScreenshot = false;
|
||||
TakeScreenshot(0, 0);
|
||||
}
|
||||
|
||||
if(recording)
|
||||
{
|
||||
std::vector<char> data = VideoBuffer(rendererFrame).ToPPM();
|
||||
|
||||
ByteString filename = ByteString::Build("recordings", PATH_SEP_CHAR, recordingFolder, PATH_SEP_CHAR, "frame_", Format::Width(recordingIndex++, 6), ".ppm");
|
||||
|
||||
Platform::WriteFile(data, filename);
|
||||
}
|
||||
|
||||
if (logEntries.size())
|
||||
{
|
||||
int startX = 20;
|
||||
int startY = YRES-20;
|
||||
std::deque<std::pair<String, int> >::iterator iter;
|
||||
for(iter = logEntries.begin(); iter != logEntries.end(); iter++)
|
||||
{
|
||||
String message = (*iter).first;
|
||||
int alpha = std::min((*iter).second, 255);
|
||||
if (alpha <= 0) //erase this and everything older
|
||||
{
|
||||
logEntries.erase(iter, logEntries.end());
|
||||
break;
|
||||
}
|
||||
startY -= 14;
|
||||
g->BlendFilledRect(RectSized(Vec2{ startX-3, startY-3 }, Vec2{ Graphics::TextSize(message).X + 5, 14 }), 0x000000_rgb .WithAlpha(std::min(100, alpha)));
|
||||
g->BlendText({ startX, startY }, message, 0xFFFFFF_rgb .WithAlpha(alpha));
|
||||
(*iter).second -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (recording)
|
||||
@@ -2487,8 +2511,8 @@ void GameView::OnDraw()
|
||||
|
||||
if (showDebug)
|
||||
{
|
||||
if (ren->findingElement)
|
||||
fpsInfo << " Parts: " << ren->foundElements << "/" << sample.NumParts;
|
||||
if (rendererSettings->findingElement)
|
||||
fpsInfo << " Parts: " << rendererSettings->foundElements << "/" << sample.NumParts;
|
||||
else
|
||||
fpsInfo << " Parts: " << sample.NumParts;
|
||||
}
|
||||
@@ -2496,10 +2520,17 @@ void GameView::OnDraw()
|
||||
fpsInfo << " [REPLACE MODE]";
|
||||
if (c->GetReplaceModeFlags()&SPECIFIC_DELETE)
|
||||
fpsInfo << " [SPECIFIC DELETE]";
|
||||
if (ren && ren->GetGridSize())
|
||||
fpsInfo << " [GRID: " << ren->GetGridSize() << "]";
|
||||
if (ren && ren->findingElement)
|
||||
if (rendererSettings->gridSize)
|
||||
fpsInfo << " [GRID: " << rendererSettings->gridSize << "]";
|
||||
if (rendererSettings->findingElement)
|
||||
fpsInfo << " [FIND]";
|
||||
if (showDebug)
|
||||
{
|
||||
if (wantRendererThread)
|
||||
{
|
||||
fpsInfo << " [SRT]";
|
||||
}
|
||||
}
|
||||
|
||||
int textWidth = Graphics::TextSize(fpsInfo.Build()).X - 1;
|
||||
int alpha = 255-introText*5;
|
||||
@@ -2584,3 +2615,106 @@ pixel GameView::GetPixelUnderMouse() const
|
||||
}
|
||||
return rendererFrame[point];
|
||||
}
|
||||
|
||||
void GameView::RendererThread()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
std::unique_lock lk(rendererThreadMx);
|
||||
rendererThreadOwnsRenderer = false;
|
||||
rendererThreadCv.notify_one();
|
||||
rendererThreadCv.wait(lk, [this]() {
|
||||
return rendererThreadState == rendererThreadStopping || rendererThreadOwnsRenderer;
|
||||
});
|
||||
if (rendererThreadState == rendererThreadStopping)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
RenderSimulation(*rendererThreadSim, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::StartRendererThread()
|
||||
{
|
||||
bool start = false;
|
||||
bool notify = false;
|
||||
{
|
||||
std::lock_guard lk(rendererThreadMx);
|
||||
if (rendererThreadState == rendererThreadAbsent)
|
||||
{
|
||||
rendererThreadSim = std::make_unique<RenderableSimulation>();
|
||||
rendererThreadState = rendererThreadRunning;
|
||||
start = true;
|
||||
}
|
||||
else if (rendererThreadState == rendererThreadPaused)
|
||||
{
|
||||
rendererThreadState = rendererThreadRunning;
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
if (start)
|
||||
{
|
||||
rendererThread = std::thread([this]() {
|
||||
RendererThread();
|
||||
});
|
||||
notify = true;
|
||||
}
|
||||
if (notify)
|
||||
{
|
||||
DispatchRendererThread();
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::StopRendererThread()
|
||||
{
|
||||
bool join = false;
|
||||
{
|
||||
std::lock_guard lk(rendererThreadMx);
|
||||
if (rendererThreadState != rendererThreadAbsent)
|
||||
{
|
||||
rendererThreadState = rendererThreadStopping;
|
||||
join = true;
|
||||
}
|
||||
}
|
||||
if (join)
|
||||
{
|
||||
rendererThreadCv.notify_one();
|
||||
rendererThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::PauseRendererThread()
|
||||
{
|
||||
std::unique_lock lk(rendererThreadMx);
|
||||
if (rendererThreadState == rendererThreadRunning)
|
||||
{
|
||||
rendererThreadState = rendererThreadPaused;
|
||||
rendererThreadCv.notify_one();
|
||||
rendererThreadCv.wait(lk, [this]() {
|
||||
return !rendererThreadOwnsRenderer;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GameView::DispatchRendererThread()
|
||||
{
|
||||
ren->ApplySettings(*rendererSettings);
|
||||
*rendererThreadSim = *sim;
|
||||
rendererThreadSim->useLuaCallbacks = false;
|
||||
rendererThreadOwnsRenderer = true;
|
||||
{
|
||||
std::lock_guard lk(rendererThreadMx);
|
||||
rendererThreadOwnsRenderer = true;
|
||||
}
|
||||
rendererThreadCv.notify_one();
|
||||
}
|
||||
|
||||
void GameView::WaitForRendererThread()
|
||||
{
|
||||
std::unique_lock lk(rendererThreadMx);
|
||||
rendererThreadCv.wait(lk, [this]() {
|
||||
return !rendererThreadOwnsRenderer;
|
||||
});
|
||||
}
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
enum DrawMode
|
||||
{
|
||||
@@ -29,9 +32,11 @@ namespace ui
|
||||
|
||||
class SplitButton;
|
||||
class Simulation;
|
||||
struct RenderableSimulation;
|
||||
|
||||
class MenuButton;
|
||||
class Renderer;
|
||||
struct RendererSettings;
|
||||
class VideoBuffer;
|
||||
class ToolButton;
|
||||
class GameController;
|
||||
@@ -82,7 +87,8 @@ private:
|
||||
|
||||
ui::Point currentPoint, lastPoint;
|
||||
GameController * c;
|
||||
Renderer * ren;
|
||||
Renderer *ren = nullptr;
|
||||
RendererSettings *rendererSettings = nullptr;
|
||||
Simulation *sim = nullptr;
|
||||
Brush const *activeBrush;
|
||||
//UI Elements
|
||||
@@ -147,10 +153,28 @@ private:
|
||||
Vec2<int> PlaceSavePos() const;
|
||||
|
||||
std::optional<FindingElement> FindingElementCandidate() const;
|
||||
enum RendererThreadState
|
||||
{
|
||||
rendererThreadAbsent,
|
||||
rendererThreadRunning,
|
||||
rendererThreadPaused,
|
||||
rendererThreadStopping,
|
||||
};
|
||||
RendererThreadState rendererThreadState = rendererThreadAbsent;
|
||||
std::thread rendererThread;
|
||||
std::mutex rendererThreadMx;
|
||||
std::condition_variable rendererThreadCv;
|
||||
bool rendererThreadOwnsRenderer = false;
|
||||
void StartRendererThread();
|
||||
void StopRendererThread();
|
||||
void RendererThread();
|
||||
void WaitForRendererThread();
|
||||
void DispatchRendererThread();
|
||||
std::unique_ptr<RenderableSimulation> rendererThreadSim;
|
||||
|
||||
public:
|
||||
GameView();
|
||||
virtual ~GameView();
|
||||
~GameView();
|
||||
|
||||
//Breaks MVC, but any other way is going to be more of a mess.
|
||||
ui::Point GetMousePosition();
|
||||
@@ -238,4 +262,12 @@ public:
|
||||
pixel GetPixelUnderMouse() const;
|
||||
|
||||
RendererFrame rendererFrame;
|
||||
// Call this before accessing Renderer "out of turn", e.g. from RenderView. This *does not*
|
||||
// include OptionsModel or Lua setting functions because they only access the RendererSettings
|
||||
// in GameModel, or Lua drawing functions because they only access Renderer in eventTraitSimGraphics
|
||||
// and *SimDraw events, and the renderer thread gets paused anyway if there are handlers
|
||||
// installed for such events.
|
||||
void PauseRendererThread();
|
||||
|
||||
void RenderSimulation(const RenderableSimulation &sim, bool handleEvents);
|
||||
};
|
||||
|
@@ -575,7 +575,7 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender)
|
||||
if(save->GetGameSave())
|
||||
{
|
||||
missingElements = save->GetGameSave()->missingElements;
|
||||
savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true);
|
||||
savePreview = SaveRenderer::Ref().Render(save->GetGameSave(), false, true, RendererSettings{});
|
||||
if (savePreview)
|
||||
savePreview->ResizeToFit(RES / 2, true);
|
||||
missingElementsButton->Visible = missingElements;
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "Controller.h"
|
||||
|
||||
RenderController::RenderController(Simulation *sim, Renderer * ren, std::function<void ()> onDone_):
|
||||
RenderController::RenderController(Simulation *sim, Renderer * ren, RendererSettings *rendererSettings, std::function<void ()> onDone_):
|
||||
HasExited(false)
|
||||
{
|
||||
renderView = new RenderView();
|
||||
@@ -14,7 +14,7 @@ RenderController::RenderController(Simulation *sim, Renderer * ren, std::functio
|
||||
renderView->AttachController(this);
|
||||
renderModel->AddObserver(renderView);
|
||||
|
||||
renderModel->SetRenderer(ren);
|
||||
renderModel->SetRenderer(ren, rendererSettings);
|
||||
renderModel->SetSimulation(sim);
|
||||
onDone = onDone_;
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
class RenderView;
|
||||
class RenderModel;
|
||||
class Renderer;
|
||||
struct RendererSettings;
|
||||
class Simulation;
|
||||
class RenderController
|
||||
{
|
||||
@@ -13,7 +14,7 @@ class RenderController
|
||||
std::function<void ()> onDone;
|
||||
public:
|
||||
bool HasExited;
|
||||
RenderController(Simulation *sim, Renderer * ren, std::function<void ()> onDone = nullptr);
|
||||
RenderController(Simulation *sim, Renderer * ren, RendererSettings *rendererSettings, std::function<void ()> onDone = nullptr);
|
||||
void Exit();
|
||||
RenderView * GetView() { return renderView; }
|
||||
virtual ~RenderController();
|
||||
|
@@ -1,17 +1,10 @@
|
||||
#include "RenderModel.h"
|
||||
|
||||
#include "RenderView.h"
|
||||
|
||||
#include "gui/game/RenderPreset.h"
|
||||
|
||||
#include "gui/game/GameController.h"
|
||||
#include "gui/game/GameView.h"
|
||||
#include "graphics/Renderer.h"
|
||||
|
||||
RenderModel::RenderModel():
|
||||
renderer(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void RenderModel::AddObserver(RenderView * observer)
|
||||
{
|
||||
observers.push_back(observer);
|
||||
@@ -23,44 +16,35 @@ void RenderModel::AddObserver(RenderView * observer)
|
||||
|
||||
void RenderModel::SetRenderMode(uint32_t newRenderMode)
|
||||
{
|
||||
if (renderer)
|
||||
{
|
||||
renderer->SetRenderMode(newRenderMode);
|
||||
}
|
||||
rendererSettings->renderMode = newRenderMode;
|
||||
notifyRenderChanged();
|
||||
}
|
||||
|
||||
uint32_t RenderModel::GetRenderMode()
|
||||
{
|
||||
return renderer ? renderer->GetRenderMode() : 0;
|
||||
return rendererSettings->renderMode;
|
||||
}
|
||||
|
||||
void RenderModel::SetDisplayMode(uint32_t newDisplayMode)
|
||||
{
|
||||
if (renderer)
|
||||
{
|
||||
renderer->SetDisplayMode(newDisplayMode);
|
||||
}
|
||||
rendererSettings->displayMode = newDisplayMode;
|
||||
notifyDisplayChanged();
|
||||
}
|
||||
|
||||
uint32_t RenderModel::GetDisplayMode()
|
||||
{
|
||||
return renderer ? renderer->GetDisplayMode() : 0;
|
||||
return rendererSettings->displayMode;
|
||||
}
|
||||
|
||||
void RenderModel::SetColorMode(uint32_t newColorMode)
|
||||
{
|
||||
if (renderer)
|
||||
{
|
||||
renderer->SetColorMode(newColorMode);
|
||||
}
|
||||
rendererSettings->colorMode = newColorMode;
|
||||
notifyColourChanged();
|
||||
}
|
||||
|
||||
uint32_t RenderModel::GetColorMode()
|
||||
{
|
||||
return renderer ? renderer->GetColorMode() : 0;
|
||||
return rendererSettings->colorMode;
|
||||
}
|
||||
|
||||
void RenderModel::LoadRenderPreset(int presetNum)
|
||||
@@ -71,9 +55,10 @@ void RenderModel::LoadRenderPreset(int presetNum)
|
||||
SetColorMode(preset.colorMode);
|
||||
}
|
||||
|
||||
void RenderModel::SetRenderer(Renderer * ren)
|
||||
void RenderModel::SetRenderer(Renderer * ren, RendererSettings *newRendererSettings)
|
||||
{
|
||||
renderer = ren;
|
||||
rendererSettings = newRendererSettings;
|
||||
notifyRendererChanged();
|
||||
notifyRenderChanged();
|
||||
notifyDisplayChanged();
|
||||
@@ -94,6 +79,11 @@ Renderer * RenderModel::GetRenderer()
|
||||
return renderer;
|
||||
}
|
||||
|
||||
RendererSettings *RenderModel::GetRendererSettings()
|
||||
{
|
||||
return rendererSettings;
|
||||
}
|
||||
|
||||
Simulation *RenderModel::GetSimulation()
|
||||
{
|
||||
return sim;
|
||||
|
@@ -4,11 +4,13 @@
|
||||
|
||||
class RenderView;
|
||||
class Renderer;
|
||||
struct RendererSettings;
|
||||
class Simulation;
|
||||
class RenderModel
|
||||
{
|
||||
std::vector<RenderView*> observers;
|
||||
Renderer * renderer;
|
||||
Renderer * renderer = nullptr;
|
||||
RendererSettings *rendererSettings = nullptr;
|
||||
Simulation *sim = nullptr;
|
||||
void notifyRendererChanged();
|
||||
void notifySimulationChanged();
|
||||
@@ -16,11 +18,11 @@ class RenderModel
|
||||
void notifyDisplayChanged();
|
||||
void notifyColourChanged();
|
||||
public:
|
||||
RenderModel();
|
||||
Renderer * GetRenderer();
|
||||
RendererSettings *GetRendererSettings();
|
||||
Simulation *GetSimulation();
|
||||
void AddObserver(RenderView * observer);
|
||||
void SetRenderer(Renderer * ren);
|
||||
void SetRenderer(Renderer * ren, RendererSettings *newRendererSettings);
|
||||
void SetSimulation(Simulation *newSim);
|
||||
void SetRenderMode(uint32_t newRenderMode);
|
||||
uint32_t GetRenderMode();
|
||||
|
@@ -1,18 +1,16 @@
|
||||
#include "RenderView.h"
|
||||
|
||||
#include "simulation/ElementGraphics.h"
|
||||
#include "simulation/SimulationData.h"
|
||||
#include "simulation/Simulation.h"
|
||||
|
||||
#include "graphics/Graphics.h"
|
||||
#include "graphics/Renderer.h"
|
||||
#include "graphics/VideoBuffer.h"
|
||||
|
||||
#include "RenderController.h"
|
||||
#include "RenderModel.h"
|
||||
|
||||
#include "gui/interface/Checkbox.h"
|
||||
#include "gui/interface/Button.h"
|
||||
#include "gui/game/GameController.h"
|
||||
#include "gui/game/GameView.h"
|
||||
|
||||
class ModeCheckbox : public ui::Checkbox
|
||||
{
|
||||
@@ -144,6 +142,7 @@ void RenderView::OnTryExit(ExitMethod method)
|
||||
void RenderView::NotifyRendererChanged(RenderModel * sender)
|
||||
{
|
||||
ren = sender->GetRenderer();
|
||||
rendererSettings = sender->GetRendererSettings();
|
||||
}
|
||||
|
||||
void RenderView::NotifySimulationChanged(RenderModel * sender)
|
||||
@@ -183,20 +182,14 @@ void RenderView::OnDraw()
|
||||
{
|
||||
Graphics * g = GetGraphics();
|
||||
g->DrawFilledRect(WINDOW.OriginRect(), 0x000000_rgb);
|
||||
if(ren)
|
||||
auto *view = GameController::Ref().GetView();
|
||||
view->PauseRendererThread();
|
||||
ren->ApplySettings(*rendererSettings);
|
||||
view->RenderSimulation(*sim, true);
|
||||
for (auto y = 0; y < YRES; ++y)
|
||||
{
|
||||
// we're the main thread, we may write graphicscache
|
||||
auto &sd = SimulationData::Ref();
|
||||
std::unique_lock lk(sd.elementGraphicsMx);
|
||||
ren->sim = sim;
|
||||
ren->clearScreen();
|
||||
ren->RenderSimulation();
|
||||
ren->sim = nullptr;
|
||||
for (auto y = 0; y < YRES; ++y)
|
||||
{
|
||||
auto &video = ren->GetVideo();
|
||||
std::copy_n(video.data() + video.Size().X * y, video.Size().X, g->Data() + g->Size().X * y);
|
||||
}
|
||||
auto &video = ren->GetVideo();
|
||||
std::copy_n(video.data() + video.Size().X * y, video.Size().X, g->Data() + g->Size().X * y);
|
||||
}
|
||||
g->DrawLine({ 0, YRES }, { XRES-1, YRES }, 0xC8C8C8_rgb);
|
||||
g->DrawLine({ line1, YRES }, { line1, WINDOWH }, 0xC8C8C8_rgb);
|
||||
|
@@ -5,12 +5,14 @@
|
||||
class ModeCheckbox;
|
||||
|
||||
class Renderer;
|
||||
struct RendererSettings;
|
||||
class Simulation;
|
||||
class RenderController;
|
||||
class RenderModel;
|
||||
class RenderView: public ui::Window {
|
||||
RenderController * c;
|
||||
Renderer * ren;
|
||||
RendererSettings *rendererSettings = nullptr;
|
||||
Simulation *sim = nullptr;
|
||||
std::vector<ModeCheckbox *> renderModes;
|
||||
std::vector<ModeCheckbox *> displayModes;
|
||||
|
@@ -34,6 +34,7 @@ public:
|
||||
void Init();
|
||||
|
||||
bool HandleEvent(const GameControllerEvent &event);
|
||||
bool HaveSimGraphicsEventHandlers();
|
||||
|
||||
int Command(String command);
|
||||
String FormatCommand(String command);
|
||||
|
@@ -11,16 +11,6 @@ static int32_t int32Truncate(double n)
|
||||
return int32_t(n);
|
||||
}
|
||||
|
||||
static std::variant<Graphics *, Renderer *> currentGraphics()
|
||||
{
|
||||
auto *lsi = GetLSI();
|
||||
if (lsi->eventTraits & eventTraitSimGraphics)
|
||||
{
|
||||
return lsi->ren;
|
||||
}
|
||||
return lsi->g;
|
||||
}
|
||||
|
||||
static int textSize(lua_State *L)
|
||||
{
|
||||
auto text = tpt_lua_optString(L, 1, "");
|
||||
@@ -51,7 +41,7 @@ static int drawText(lua_State *L)
|
||||
|
||||
std::visit([x, y, r, g, b, a, &text](auto p) {
|
||||
p->BlendText({ x, y }, text, RGBA<uint8_t>(r, g, b, a));
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -73,7 +63,7 @@ static int drawPixel(lua_State *L)
|
||||
else if (a > 255) a = 255;
|
||||
std::visit([x, y, r, g, b, a](auto p) {
|
||||
p->BlendPixel({ x, y }, RGBA<uint8_t>(r, g, b, a));
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -106,7 +96,7 @@ static int drawLine(lua_State *L)
|
||||
{
|
||||
p->BlendLine({ x1, y1 }, { x2, y2 }, RGBA<uint8_t>(r, g, b, a));
|
||||
}
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -139,7 +129,7 @@ static int drawRect(lua_State *L)
|
||||
{
|
||||
p->BlendRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA<uint8_t>(r, g, b, a));
|
||||
}
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -172,7 +162,7 @@ static int fillRect(lua_State *L)
|
||||
{
|
||||
p->BlendFilledRect(RectSized(Vec2{ x, y }, Vec2{ width, height }), RGBA<uint8_t>(r, g, b, a));
|
||||
}
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -198,7 +188,7 @@ static int drawCircle(lua_State *L)
|
||||
|
||||
std::visit([x, y, rx, ry, r, g, b, a](auto p) {
|
||||
p->BlendEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA<uint8_t>(r, g, b, a));
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -224,7 +214,7 @@ static int fillCircle(lua_State *L)
|
||||
|
||||
std::visit([x, y, rx, ry, r, g, b, a](auto p) {
|
||||
p->BlendFilledEllipse({ x, y }, { abs(rx), abs(ry) }, RGBA<uint8_t>(r, g, b, a));
|
||||
}, currentGraphics());
|
||||
}, GetLSI()->GetGraphics());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -10,10 +10,10 @@ static int renderMode(lua_State *L)
|
||||
auto *lsi = GetLSI();
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
lsi->ren->SetRenderMode(luaL_checkinteger(L, 1));
|
||||
lsi->gameModel->GetRendererSettings().renderMode = luaL_checkinteger(L, 1);
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, lsi->ren->GetRenderMode());
|
||||
lua_pushinteger(L, lsi->gameModel->GetRendererSettings().renderMode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -63,11 +63,10 @@ static int fireSize(lua_State *L)
|
||||
auto *lsi = GetLSI();
|
||||
if (lua_gettop(L) < 1)
|
||||
{
|
||||
lua_pushnumber(L, lsi->gameModel->GetRenderer()->GetFireIntensity());
|
||||
lua_pushnumber(L, lsi->gameModel->GetRendererSettings().fireIntensity);
|
||||
return 1;
|
||||
}
|
||||
float fireintensity = float(luaL_checknumber(L, 1));
|
||||
lsi->gameModel->GetRenderer()->prepare_alpha(CELL, fireintensity);
|
||||
lsi->gameModel->GetRendererSettings().fireIntensity = float(luaL_checknumber(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -76,10 +75,10 @@ static int displayMode(lua_State *L)
|
||||
auto *lsi = GetLSI();
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
lsi->ren->SetDisplayMode(luaL_checkinteger(L, 1));
|
||||
lsi->gameModel->GetRendererSettings().displayMode = luaL_checkinteger(L, 1);
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, lsi->ren->GetDisplayMode());
|
||||
lua_pushinteger(L, lsi->gameModel->GetRendererSettings().displayMode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -89,10 +88,10 @@ static int colorMode(lua_State *L)
|
||||
auto *lsi = GetLSI();
|
||||
if (lua_gettop(L))
|
||||
{
|
||||
lsi->ren->SetColorMode(luaL_checkinteger(L, 1));
|
||||
lsi->gameModel->GetRendererSettings().colorMode = luaL_checkinteger(L, 1);
|
||||
return 0;
|
||||
}
|
||||
lua_pushinteger(L, lsi->ren->GetColorMode());
|
||||
lua_pushinteger(L, lsi->gameModel->GetRendererSettings().colorMode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -117,11 +116,11 @@ static int grid(lua_State *L)
|
||||
int acount = lua_gettop(L);
|
||||
if (acount == 0)
|
||||
{
|
||||
lua_pushnumber(L, lsi->ren->GetGridSize());
|
||||
lua_pushnumber(L, lsi->gameModel->GetRendererSettings().gridSize);
|
||||
return 1;
|
||||
}
|
||||
int grid = luaL_optint(L, 1, -1);
|
||||
lsi->ren->SetGridSize(grid);
|
||||
lsi->gameModel->GetRendererSettings().gridSize = grid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -116,12 +116,12 @@ String LuaGetError()
|
||||
|
||||
LuaScriptInterface::LuaScriptInterface(GameController *newGameController, GameModel *newGameModel) :
|
||||
CommandInterface(newGameController, newGameModel),
|
||||
ren(newGameModel->GetRenderer()),
|
||||
gameModel(newGameModel),
|
||||
gameController(newGameController),
|
||||
window(gameController->GetView()),
|
||||
sim(gameModel->GetSimulation()),
|
||||
g(ui::Engine::Ref().g),
|
||||
ren(gameModel->GetRenderer()),
|
||||
customElements(PT_NUM),
|
||||
gameControllerEventHandlers(std::variant_size_v<GameControllerEvent>)
|
||||
{
|
||||
@@ -417,6 +417,42 @@ bool CommandInterface::HandleEvent(const GameControllerEvent &event)
|
||||
return cont;
|
||||
}
|
||||
|
||||
template<size_t Index>
|
||||
std::enable_if_t<Index != std::variant_size_v<GameControllerEvent>, bool> HaveSimGraphicsEventHandlersHelper(lua_State *L, std::vector<LuaSmartRef> &gameControllerEventHandlers)
|
||||
{
|
||||
if (std::variant_alternative_t<Index, GameControllerEvent>::traits & eventTraitSimGraphics)
|
||||
{
|
||||
gameControllerEventHandlers[Index].Push(L);
|
||||
auto have = lua_objlen(L, -1) > 0;
|
||||
lua_pop(L, 1);
|
||||
if (have)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return HaveSimGraphicsEventHandlersHelper<Index + 1>(L, gameControllerEventHandlers);
|
||||
}
|
||||
|
||||
template<size_t Index>
|
||||
std::enable_if_t<Index == std::variant_size_v<GameControllerEvent>, bool> HaveSimGraphicsEventHandlersHelper(lua_State *L, std::vector<LuaSmartRef> &gameControllerEventHandlers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CommandInterface::HaveSimGraphicsEventHandlers()
|
||||
{
|
||||
auto &sd = SimulationData::CRef();
|
||||
auto *lsi = static_cast<LuaScriptInterface *>(this);
|
||||
for (int i = 0; i < int(lsi->customElements.size()); ++i)
|
||||
{
|
||||
if (lsi->customElements[i].graphics && !sd.graphicscache[i].isready && lsi->sim->elementCount[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return HaveSimGraphicsEventHandlersHelper<0>(lsi->L, lsi->gameControllerEventHandlers);
|
||||
}
|
||||
|
||||
void CommandInterface::OnTick()
|
||||
{
|
||||
auto *lsi = static_cast<LuaScriptInterface *>(this);
|
||||
@@ -804,3 +840,4 @@ void CommandInterfaceDeleter::operator ()(CommandInterface *ptr) const
|
||||
{
|
||||
delete static_cast<LuaScriptInterface *>(ptr);
|
||||
}
|
||||
|
||||
|
@@ -62,6 +62,8 @@ class LuaScriptInterface : public CommandInterface
|
||||
{
|
||||
LuaStatePtr luaState;
|
||||
|
||||
Renderer *ren;
|
||||
|
||||
public:
|
||||
lua_State *L{};
|
||||
|
||||
@@ -70,7 +72,18 @@ public:
|
||||
ui::Window *window;
|
||||
Simulation *sim;
|
||||
Graphics *g;
|
||||
Renderer *ren;
|
||||
|
||||
std::variant<Graphics *, Renderer *> GetGraphics()
|
||||
{
|
||||
if (eventTraits & eventTraitSimGraphics)
|
||||
{
|
||||
// This is ok without calling gameModel->view->PauseRendererThread() because
|
||||
// the renderer thread gets paused anyway if there are handlers
|
||||
// installed for eventTraitSimGraphics and *SimDraw events.
|
||||
return ren;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
std::vector<CustomElement> customElements; // must come after luaState
|
||||
|
||||
|
@@ -23,6 +23,11 @@ bool CommandInterface::HandleEvent(const GameControllerEvent &event)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandInterface::HaveSimGraphicsEventHandlers()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int CommandInterface::Command(String command)
|
||||
{
|
||||
return PlainCommand(command);
|
||||
|
@@ -13,32 +13,24 @@ SaveRenderer::SaveRenderer()
|
||||
sim = std::make_unique<Simulation>();
|
||||
ren = std::make_unique<Renderer>();
|
||||
ren->sim = sim.get();
|
||||
ren->decorations_enable = true;
|
||||
ren->blackDecorations = true;
|
||||
}
|
||||
|
||||
SaveRenderer::~SaveRenderer() = default;
|
||||
|
||||
std::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, Renderer *renderModeSource)
|
||||
std::unique_ptr<VideoBuffer> SaveRenderer::Render(const GameSave *save, bool decorations, bool fire, RendererSettings rendererSettings)
|
||||
{
|
||||
// this function usually runs on a thread different from where element info in SimulationData may be written, so we acquire a read-only lock on it
|
||||
auto &sd = SimulationData::CRef();
|
||||
std::shared_lock lk(sd.elementGraphicsMx);
|
||||
std::lock_guard<std::mutex> gx(renderMutex);
|
||||
|
||||
ren->ResetModes();
|
||||
if (renderModeSource)
|
||||
{
|
||||
ren->SetRenderMode(renderModeSource->GetRenderMode());
|
||||
ren->SetDisplayMode(renderModeSource->GetDisplayMode());
|
||||
ren->SetColorMode(renderModeSource->GetColorMode());
|
||||
}
|
||||
rendererSettings.decorations_enable = true;
|
||||
rendererSettings.blackDecorations = !decorations;
|
||||
ren->ApplySettings(rendererSettings);
|
||||
|
||||
sim->clear_sim();
|
||||
|
||||
sim->Load(save, true, { 0, 0 });
|
||||
ren->decorations_enable = true;
|
||||
ren->blackDecorations = !decorations;
|
||||
ren->ClearAccumulation();
|
||||
ren->clearScreen();
|
||||
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/ExplicitSingleton.h"
|
||||
#include "graphics/RendererSettings.h"
|
||||
#include "common/String.h"
|
||||
|
||||
class GameSave;
|
||||
@@ -20,5 +21,5 @@ class SaveRenderer: public ExplicitSingleton<SaveRenderer>
|
||||
public:
|
||||
SaveRenderer();
|
||||
~SaveRenderer();
|
||||
std::unique_ptr<VideoBuffer> Render(const GameSave *save, bool decorations = true, bool fire = true, Renderer *renderModeSource = nullptr);
|
||||
std::unique_ptr<VideoBuffer> Render(const GameSave *save, bool decorations, bool fire, RendererSettings rendererSettings);
|
||||
};
|
||||
|
Reference in New Issue
Block a user