From cb6957e78683cbe4887dac80c1ff23dc9523c4cf Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 6 Apr 2025 12:41:58 +0100 Subject: Drop WindowContent::render const ImGui promotes "doing things immediately" and this const makes that very awkward. --- ui/gameMainWindow.cpp | 2 +- ui/gameMainWindow.h | 2 +- ui/windowContent.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index cc74f66..afb7a2e 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -85,7 +85,7 @@ GameMainWindow::handleInput(const SDL_Event & event) } void -GameMainWindow::render() const +GameMainWindow::render() { SceneRenderer::render(*this); glEnable(GL_BLEND); diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h index b0f1592..14e099c 100644 --- a/ui/gameMainWindow.h +++ b/ui/gameMainWindow.h @@ -14,7 +14,7 @@ public: NO_COPY(GameMainWindow); void tick(TickDuration) override; - void render() const override; + void render() override; private: bool handleInput(const SDL_Event &) override; diff --git a/ui/windowContent.h b/ui/windowContent.h index 762d1cc..34cbea3 100644 --- a/ui/windowContent.h +++ b/ui/windowContent.h @@ -14,7 +14,7 @@ public: NO_COPY(WindowContent); virtual void tick(TickDuration); - virtual void render() const = 0; + virtual void render() = 0; virtual bool handleInput(const SDL_Event & e); protected: -- cgit v1.2.3 From 237da037606bad97445562ef1f8863becb71a25c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 3 Apr 2025 00:28:54 +0100 Subject: Basically empty ResViewer application --- Jamroot.jam | 10 +++++----- application/resviewer.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 application/resviewer.cpp diff --git a/Jamroot.jam b/Jamroot.jam index 9b589cf..7585ec7 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -46,15 +46,15 @@ project i-like-trains : requirements tidy:TIDY ; -exe iliketrains : - application/main.cpp - : - ilt - ; +exe iliketrains : application/main.cpp : ilt ; +exe resviewer : application/resviewer.cpp : ilt ; explicit main ; always main ; run iliketrains : -- : [ sequence.insertion-sort [ glob-tree-ex res : *.* ] ] : : main ; +explicit runresviewer ; +always runresviewer ; +run resviewer : -- : [ sequence.insertion-sort [ glob-tree-ex res : *.xml ] ] : : runresviewer ; lib ilt : [ glob-tree *.cpp *.?s *.t?s : application bin test thirdparty ] diff --git a/application/resviewer.cpp b/application/resviewer.cpp new file mode 100644 index 0000000..99e3425 --- /dev/null +++ b/application/resviewer.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr int DEFAULT_WIDTH = 240; +constexpr int DEFAULT_HEIGHT = 160; + +int +main(int argc, char ** argv) +{ + class ResViewer : GameState, MainApplication { + public: + void + run(std::span fileList) + { + windows.create(DEFAULT_WIDTH, DEFAULT_HEIGHT/*, "ILT - Resource Viewer", + SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL*/); + mainLoop(); + } + }; + + std::span files {argv, static_cast(argc)}; + + ResViewer {}.run(files.subspan(2)); +} -- cgit v1.2.3 From 6f90c4e319fd59c42ae287a72ccd90bf378fb2ef Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 6 Apr 2025 20:35:11 +0100 Subject: Default environment direction light shines down, not up --- gfx/gl/sceneProvider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/gl/sceneProvider.cpp b/gfx/gl/sceneProvider.cpp index e01532e..3681c60 100644 --- a/gfx/gl/sceneProvider.cpp +++ b/gfx/gl/sceneProvider.cpp @@ -5,7 +5,7 @@ void SceneProvider::environment(const SceneShader &, const SceneRenderer & renderer) const { renderer.setAmbientLight({0.5F, 0.5F, 0.5F}); - renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {{-quarter_pi, -quarter_pi}}, *this); + renderer.setDirectionalLight({0.6F, 0.6F, 0.6F}, {{-quarter_pi, quarter_pi}}, *this); } void -- cgit v1.2.3 From 7e7ddf53b54e52f2106c4adce2818df7877254f1 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 7 Apr 2025 01:16:19 +0100 Subject: More uniform/flexible window constructors --- application/main.cpp | 2 +- application/resviewer.cpp | 3 +-- ui/mainWindow.cpp | 7 +------ ui/mainWindow.h | 6 ++---- ui/window.cpp | 6 +++--- ui/window.h | 2 +- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index 9120376..ad7abf2 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -44,7 +44,7 @@ public: int run() { - windows.create(DISPLAY_WIDTH, DISPLAY_HEIGHT)->setContent(); + windows.create(DISPLAY_WIDTH, DISPLAY_HEIGHT, "I Like Trains")->setContent(); terrain = world.create(GeoData::loadFromAsciiGrid("test/fixtures/height/SD19.asc")); world.create(terrain); diff --git a/application/resviewer.cpp b/application/resviewer.cpp index 99e3425..ced76f8 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -18,8 +18,7 @@ main(int argc, char ** argv) void run(std::span fileList) { - windows.create(DEFAULT_WIDTH, DEFAULT_HEIGHT/*, "ILT - Resource Viewer", - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL*/); + windows.create(DEFAULT_WIDTH, DEFAULT_HEIGHT, "ILT - Resource Viewer"); mainLoop(); } }; diff --git a/ui/mainWindow.cpp b/ui/mainWindow.cpp index 73c0b5b..8d46d43 100644 --- a/ui/mainWindow.cpp +++ b/ui/mainWindow.cpp @@ -8,12 +8,7 @@ #include "backends/imgui_impl_sdl2.h" #pragma GCC diagnostic pop -MainWindow::MainWindow(size_t w, size_t h) : - MainWindow {w, h, "I Like Trains", SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL} -{ -} - -MainWindow::MainWindow(size_t w, size_t h, const std::string & title, Uint32 flags) : Window {w, h, title, flags} +MainWindow::MainWindow(size_t w, size_t h, const char * title, Uint32 flags) : Window {w, h, title, flags} { if (const auto version = gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress)); version < 30003) { throw std::runtime_error {std::format("Insufficient OpenGL version: {}", version)}; diff --git a/ui/mainWindow.h b/ui/mainWindow.h index fe26c5c..490ef09 100644 --- a/ui/mainWindow.h +++ b/ui/mainWindow.h @@ -5,12 +5,10 @@ class MainWindow : public Window { public: - MainWindow(size_t w, size_t h); + MainWindow( + size_t width, size_t height, const char * title, Uint32 flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); ~MainWindow() override; NO_MOVE(MainWindow); NO_COPY(MainWindow); - -protected: - MainWindow(size_t width, size_t height, const std::string & title, Uint32 flags); }; diff --git a/ui/window.cpp b/ui/window.cpp index 732e9ef..3d4634e 100644 --- a/ui/window.cpp +++ b/ui/window.cpp @@ -7,10 +7,10 @@ #include "backends/imgui_impl_sdl2.h" #pragma GCC diagnostic pop -Window::Window(size_t width, size_t height, const std::string & title, Uint32 flags) : +Window::Window(size_t width, size_t height, const char * title, Uint32 flags) : size {static_cast(width), static_cast(height)}, - m_window {title.c_str(), static_cast(SDL_WINDOWPOS_CENTERED), static_cast(SDL_WINDOWPOS_CENTERED), size.x, - size.y, flags}, + m_window {title, static_cast(SDL_WINDOWPOS_CENTERED), static_cast(SDL_WINDOWPOS_CENTERED), size.x, size.y, + flags}, glContext {m_window} { } diff --git a/ui/window.h b/ui/window.h index 62c34de..0316a1f 100644 --- a/ui/window.h +++ b/ui/window.h @@ -15,7 +15,7 @@ using SDL_GLContextPtr = wrapped_ptrt Date: Mon, 7 Apr 2025 20:48:14 +0100 Subject: Add Asset interface to create an arbitrarily placed instance InstanceProxy is returned out via a std::any containing a std::shared_ptr because any can only contain copyable things. --- assetFactory/asset.cpp | 6 ++++++ assetFactory/asset.h | 5 +++++ game/scenary/foliage.cpp | 10 ++++++++++ game/scenary/foliage.h | 2 ++ game/scenary/illuminator.cpp | 10 ++++++++++ game/scenary/illuminator.h | 2 ++ game/vehicles/railVehicleClass.cpp | 13 +++++++++++++ game/vehicles/railVehicleClass.h | 2 ++ 8 files changed, 50 insertions(+) diff --git a/assetFactory/asset.cpp b/assetFactory/asset.cpp index e3f5feb..0254943 100644 --- a/assetFactory/asset.cpp +++ b/assetFactory/asset.cpp @@ -7,6 +7,12 @@ Asset::persist(Persistence::PersistenceStore & store) return STORE_MEMBER(id) && STORE_MEMBER(name); } +std::any +Asset::createAt(const Location &) const +{ + return {}; +} + Asset::TexturePtr Asset::getTexture() const { diff --git a/assetFactory/asset.h b/assetFactory/asset.h index b5de056..061a7c8 100644 --- a/assetFactory/asset.h +++ b/assetFactory/asset.h @@ -2,17 +2,22 @@ #include "factoryMesh.h" #include "persistence.h" +#include #include #include class TextureAtlas; class Renderable; +class Location; class Asset : public Persistence::Persistable, public StdTypeDefs { public: using ManyPtr = ManySharedPtr; using TexturePtr = std::shared_ptr; + /// Used only for the asset viewer + [[nodiscard]] virtual std::any createAt(const Location &) const; + std::string id; std::string name; diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 159a078..140c4e5 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -2,6 +2,16 @@ #include "gfx/gl/sceneShader.h" #include "gfx/gl/shadowMapper.h" #include "gfx/gl/vertexArrayObject.h" +#include + +static_assert(std::is_constructible_v); + +std::any +Foliage::createAt(const Location & position) const +{ + return std::make_shared::InstanceProxy>( + instances.acquire(position.getRotationTransform(), position.rot.y, position.pos)); +} bool Foliage::persist(Persistence::PersistenceStore & store) diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index 71bc734..d15a8b0 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -17,6 +17,8 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { glVertexArray instancePointVAO; public: + [[nodiscard]] std::any createAt(const Location &) const override; + struct LocationVertex { glm::mat3 rotation; float yaw; diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index f1a02b2..d8e4c4e 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -2,6 +2,16 @@ #include "gfx/gl/sceneShader.h" #include "gfx/gl/vertexArrayObject.h" #include "gfx/models/texture.h" // IWYU pragma: keep +#include + +static_assert(std::is_constructible_v); + +std::any +Illuminator::createAt(const Location & position) const +{ + return std::make_shared::InstanceProxy>( + instances.acquire(position.getRotationTransform(), position.pos)); +} bool Illuminator::SpotLight::persist(Persistence::PersistenceStore & store) diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index 47ce337..200ba40 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -15,6 +15,8 @@ class Illuminator : public Asset, public Renderable, public StdTypeDefs instancesSpotLightVAO, instancesPointLightVAO; public: + [[nodiscard]] std::any createAt(const Location &) const override; + struct LightCommonVertex { RelativePosition3D position; RGB colour; diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp index 162a29a..21f01c8 100644 --- a/game/vehicles/railVehicleClass.cpp +++ b/game/vehicles/railVehicleClass.cpp @@ -17,6 +17,19 @@ RailVehicleClass::persist(Persistence::PersistenceStore & store) && STORE_HELPER(bodyMesh, Asset::MeshConstruct) && Asset::persist(store); } +std::any +RailVehicleClass::createAt(const Location & position) const +{ + return std::make_shared::InstanceProxy>(instances.acquire(LocationVertex { + .body = position.getRotationTransform(), + .front = position.getRotationTransform(), + .back = position.getRotationTransform(), + .bodyPos = position.pos, + .frontPos = {sincos(position.rot.x) * wheelBase * 0.5F, position.pos.z}, + .backPos = {sincos(position.rot.x) * wheelBase * -0.5F, position.pos.z}, + })); +} + void RailVehicleClass::postLoad() { diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h index 6eb4ca5..ccff3e2 100644 --- a/game/vehicles/railVehicleClass.h +++ b/game/vehicles/railVehicleClass.h @@ -17,6 +17,8 @@ public: void render(const SceneShader & shader, const Frustum &) const override; void shadows(const ShadowMapper & shadowMapper, const Frustum &) const override; + [[nodiscard]] std::any createAt(const Location &) const override; + struct LocationVertex { glm::mat3 body, front, back; GlobalPosition3D bodyPos, frontPos, backPos; -- cgit v1.2.3 From e73e24de4dabde817b0c8e953776305e1649786f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 8 Apr 2025 00:17:44 +0100 Subject: Update the SceneShader's view port on sceneRenderer resize --- gfx/gl/sceneRenderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 5d35d01..9a4d153 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -71,6 +71,7 @@ SceneRenderer::resize(ScreenAbsCoord newSize) configuregdata(gIllumination, GL_RGB8, GL_RGB); glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.x, size.y); + shader.setViewPort({0, 0, size.x, size.y}); } void -- cgit v1.2.3 From 0255a421906b9b3a77d9b51eb7d0126f16a9f0db Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 8 Apr 2025 02:14:41 +0100 Subject: Create WindowContent with a size object Not individual width/height parameters. --- ui/gameMainWindow.cpp | 2 +- ui/gameMainWindow.h | 2 +- ui/window.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index afb7a2e..e87009f 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -50,7 +50,7 @@ private: GameMainSelector * gms; }; -GameMainWindow::GameMainWindow(size_t w, size_t h) : SceneRenderer {{w, h}, 0} +GameMainWindow::GameMainWindow(ScreenAbsCoord size) : SceneRenderer {size, 0} { uiComponents.create(glm::vec2 {310'727'624, 494'018'810}); auto gms = uiComponents.create(&camera); diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h index 14e099c..41163d0 100644 --- a/ui/gameMainWindow.h +++ b/ui/gameMainWindow.h @@ -7,7 +7,7 @@ class GameMainWindow : public WindowContent, SceneRenderer, public SceneProvider { public: - GameMainWindow(size_t w, size_t h); + GameMainWindow(ScreenAbsCoord size); ~GameMainWindow() override; NO_MOVE(GameMainWindow); diff --git a/ui/window.h b/ui/window.h index 0316a1f..1c3d09c 100644 --- a/ui/window.h +++ b/ui/window.h @@ -27,7 +27,7 @@ public: { glm::ivec2 size {}; SDL_GetWindowSizeInPixels(m_window, &size.x, &size.y); - content = std::make_unique(size.x, size.y, std::forward

(p)...); + content = std::make_unique(ScreenAbsCoord {size.x, size.y}, std::forward

(p)...); } void tick(TickDuration elapsed); -- cgit v1.2.3 From c6fb8dd64e0c323e46c73162e21a3a34103bb407 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 8 Apr 2025 02:32:39 +0100 Subject: Create Windows with a size object Not individual width/height parameters. --- application/main.cpp | 5 ++--- application/resviewer.cpp | 5 ++--- test/testMainWindow.cpp | 2 +- ui/mainWindow.cpp | 2 +- ui/mainWindow.h | 3 +-- ui/window.cpp | 3 +-- ui/window.h | 3 +-- 7 files changed, 9 insertions(+), 14 deletions(-) diff --git a/application/main.cpp b/application/main.cpp index ad7abf2..a0c87c0 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -36,15 +36,14 @@ #include #include -static const int DISPLAY_WIDTH = 1280; -static const int DISPLAY_HEIGHT = 1024; +constexpr ScreenAbsCoord DEFAULT_WINDOW_SIZE {1280, 1024}; class DummyMainApplication : public GameState, public MainApplication { public: int run() { - windows.create(DISPLAY_WIDTH, DISPLAY_HEIGHT, "I Like Trains")->setContent(); + windows.create(DEFAULT_WINDOW_SIZE, "I Like Trains")->setContent(); terrain = world.create(GeoData::loadFromAsciiGrid("test/fixtures/height/SD19.asc")); world.create(terrain); diff --git a/application/resviewer.cpp b/application/resviewer.cpp index ced76f8..2eb40f2 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -7,8 +7,7 @@ #include #include -constexpr int DEFAULT_WIDTH = 240; -constexpr int DEFAULT_HEIGHT = 160; +constexpr ScreenAbsCoord DEFAULT_WINDOW_SIZE {800, 600}; int main(int argc, char ** argv) @@ -18,7 +17,7 @@ main(int argc, char ** argv) void run(std::span fileList) { - windows.create(DEFAULT_WIDTH, DEFAULT_HEIGHT, "ILT - Resource Viewer"); + windows.create(DEFAULT_WINDOW_SIZE, "ILT - Resource Viewer"); mainLoop(); } }; diff --git a/test/testMainWindow.cpp b/test/testMainWindow.cpp index 4a76044..d048682 100644 --- a/test/testMainWindow.cpp +++ b/test/testMainWindow.cpp @@ -2,7 +2,7 @@ #include #include -TestMainWindow::TestMainWindow() : MainWindow {1, 1, __FILE__, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN} +TestMainWindow::TestMainWindow() : MainWindow {{1, 1}, __FILE__, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN} { glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback( diff --git a/ui/mainWindow.cpp b/ui/mainWindow.cpp index 8d46d43..57dabc0 100644 --- a/ui/mainWindow.cpp +++ b/ui/mainWindow.cpp @@ -8,7 +8,7 @@ #include "backends/imgui_impl_sdl2.h" #pragma GCC diagnostic pop -MainWindow::MainWindow(size_t w, size_t h, const char * title, Uint32 flags) : Window {w, h, title, flags} +MainWindow::MainWindow(ScreenAbsCoord size, const char * title, Uint32 flags) : Window {size, title, flags} { if (const auto version = gladLoadGL(reinterpret_cast(SDL_GL_GetProcAddress)); version < 30003) { throw std::runtime_error {std::format("Insufficient OpenGL version: {}", version)}; diff --git a/ui/mainWindow.h b/ui/mainWindow.h index 490ef09..d2de9b3 100644 --- a/ui/mainWindow.h +++ b/ui/mainWindow.h @@ -5,8 +5,7 @@ class MainWindow : public Window { public: - MainWindow( - size_t width, size_t height, const char * title, Uint32 flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); + MainWindow(ScreenAbsCoord size, const char * title, Uint32 flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL); ~MainWindow() override; NO_MOVE(MainWindow); diff --git a/ui/window.cpp b/ui/window.cpp index 3d4634e..06857b2 100644 --- a/ui/window.cpp +++ b/ui/window.cpp @@ -7,8 +7,7 @@ #include "backends/imgui_impl_sdl2.h" #pragma GCC diagnostic pop -Window::Window(size_t width, size_t height, const char * title, Uint32 flags) : - size {static_cast(width), static_cast(height)}, +Window::Window(ScreenAbsCoord size, const char * title, Uint32 flags) : m_window {title, static_cast(SDL_WINDOWPOS_CENTERED), static_cast(SDL_WINDOWPOS_CENTERED), size.x, size.y, flags}, glContext {m_window} diff --git a/ui/window.h b/ui/window.h index 1c3d09c..99a977f 100644 --- a/ui/window.h +++ b/ui/window.h @@ -15,7 +15,7 @@ using SDL_GLContextPtr = wrapped_ptrt Date: Tue, 8 Apr 2025 02:38:10 +0100 Subject: Remove GameMainWindow empty destructor and special members --- ui/gameMainWindow.cpp | 2 -- ui/gameMainWindow.h | 5 ----- 2 files changed, 7 deletions(-) diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index e87009f..dbbf8a7 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -57,8 +57,6 @@ GameMainWindow::GameMainWindow(ScreenAbsCoord size) : SceneRenderer {size, 0} uiComponents.create(gms); } -GameMainWindow::~GameMainWindow() { } - void GameMainWindow::tick(TickDuration) { diff --git a/ui/gameMainWindow.h b/ui/gameMainWindow.h index 41163d0..71b6314 100644 --- a/ui/gameMainWindow.h +++ b/ui/gameMainWindow.h @@ -3,15 +3,10 @@ #include "chronology.h" #include "gfx/gl/sceneRenderer.h" #include "windowContent.h" -#include class GameMainWindow : public WindowContent, SceneRenderer, public SceneProvider { public: GameMainWindow(ScreenAbsCoord size); - ~GameMainWindow() override; - - NO_MOVE(GameMainWindow); - NO_COPY(GameMainWindow); void tick(TickDuration) override; void render() override; -- cgit v1.2.3 From eaae60886c432b6d9d5862a04f3abf03f7a13fee Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 9 Apr 2025 20:32:12 +0100 Subject: Reasonably function asset viewing functionality --- application/resviewer.cpp | 155 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/application/resviewer.cpp b/application/resviewer.cpp index 2eb40f2..e512b41 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -1,13 +1,165 @@ #include #include +#include #include +#include #include #include +#include +#include #include #include #include constexpr ScreenAbsCoord DEFAULT_WINDOW_SIZE {800, 600}; +constexpr GlobalDistance TERRAIN_LIMIT = 1'000'000; +constexpr GlobalDistance TERRAIN_HEIGHT = 10'000; +constexpr RelativeDistance DEFAULT_CAMERA_DIST = 7'000; +constexpr GlobalDistance DEFAULT_CAMERA_HEIGHT = 5'000; +constexpr GlobalDistance DEFAULT_CAMERA_FOCUS = 3'000; +constexpr GlobalDistance MAX_CAMERA_HEIGHT = 10'000; +constexpr GlobalDistance MIN_CAMERA_DIST = 1'000; +constexpr GlobalDistance MAX_CAMERA_DIST = 30'000; + +class ViewerContent : public WindowContent, SceneRenderer, SceneProvider { +public: + ViewerContent(ScreenAbsCoord size, std::span files) : SceneRenderer {size, 0}, fileList(files) + { + camera.setPosition(calcCameraPosition()); + camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); + gameState->terrain = std::make_shared( + GeoData::createFlat({-TERRAIN_LIMIT, -TERRAIN_LIMIT}, {TERRAIN_LIMIT, TERRAIN_LIMIT}, TERRAIN_HEIGHT)); + } + +private: + [[nodiscard]] + GlobalPosition3D + calcCameraPosition() const + { + return {sincos(cameraAngle) * cameraDistance, TERRAIN_HEIGHT + cameraHeight}; + } + + void + render() override + { + SceneRenderer::render(*this); + controls(); + } + + void + tick(TickDuration tick) override + { + if (autoRotate != 0) { + cameraAngle = normalize(cameraAngle + autoRotate * tick.count()); + camera.setPosition(calcCameraPosition()); + camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); + } + } + + bool + handleInput(const SDL_Event & event) override + { + if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) { + SceneRenderer::resize({event.window.data1, event.window.data2}); + } + + return WindowContent::handleInput(event); + } + + void + controls() + { + if (ImGui::Begin("Resource view")) { + ImGui::SetWindowSize({}); + fileSelection(); + assetSelection(); + } + ImGui::End(); + + if (ImGui::Begin("Camera")) { + ImGui::SetWindowSize({}); + if (std::max({ImGui::SliderFloat("Camera position", &cameraAngle, -pi, pi), + ImGui::SliderInt("Camera focus", &cameraFocus, 1, MAX_CAMERA_HEIGHT), + ImGui::SliderInt("Camera height", &cameraHeight, 1, MAX_CAMERA_HEIGHT), + ImGui::SliderFloat("Camera distance", &cameraDistance, MIN_CAMERA_DIST, MAX_CAMERA_DIST)})) { + camera.setPosition(calcCameraPosition()); + camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); + } + ImGui::SliderFloat("Auto rotate speed", &autoRotate, -1, 1); + } + ImGui::End(); + } + + void + fileSelection() + { + ImGui::BeginListBox("File"); + for (const auto file : fileList) { + if (ImGui::Selectable(file, file == selectedFile)) { + location.reset(); + selectedAsset = nullptr; + gameState->assets = AssetFactory::loadXML(file)->assets; + selectedFile = file; + } + } + ImGui::EndListBox(); + } + + void + assetSelection() + { + if (!gameState->assets.empty()) { + ImGui::BeginListBox("Asset"); + for (const auto & asset : gameState->assets) { + auto renderable = asset.second.getAs(); + if (renderable) { + if (ImGui::Selectable(asset.first.c_str(), renderable == selectedAsset)) { + selectedAsset = renderable; + location = asset.second->createAt(position); + } + } + } + ImGui::EndListBox(); + } + } + + void + content(const SceneShader & sceneShader, const Frustum & frustum) const override + { + gameState->terrain->render(sceneShader, frustum); + if (selectedAsset) { + selectedAsset->render(sceneShader, frustum); + } + } + + void + lights(const SceneShader & sceneShader) const override + { + if (selectedAsset) { + selectedAsset->lights(sceneShader); + } + } + + void + shadows(const ShadowMapper & mapper, const Frustum & frustum) const override + { + gameState->terrain->shadows(mapper, frustum); + if (selectedAsset) { + selectedAsset->shadows(mapper, frustum); + } + } + + std::span fileList; + char * selectedFile {}; + const Renderable * selectedAsset {}; + Location position {.pos = {0, 0, TERRAIN_HEIGHT}, .rot = {}}; + std::any location; + Angle cameraAngle {0.F}; + RelativeDistance cameraDistance {DEFAULT_CAMERA_DIST}; + GlobalDistance cameraHeight {DEFAULT_CAMERA_HEIGHT}; + GlobalDistance cameraFocus {DEFAULT_CAMERA_FOCUS}; + float autoRotate {0.F}; +}; int main(int argc, char ** argv) @@ -17,7 +169,8 @@ main(int argc, char ** argv) void run(std::span fileList) { - windows.create(DEFAULT_WINDOW_SIZE, "ILT - Resource Viewer"); + windows.create(DEFAULT_WINDOW_SIZE, "ILT - Resource Viewer") + ->setContent(fileList); mainLoop(); } }; -- cgit v1.2.3 From f606183442b3548a47649d55fe32ff06d04958e0 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 9 Apr 2025 20:53:45 +0100 Subject: Add boost_program_options for command line parsing --- Jamroot.jam | 3 ++- application/resviewer.cpp | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Jamroot.jam b/Jamroot.jam index 7585ec7..8589861 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -12,6 +12,7 @@ pkg-config.import mxml : : shared ; pkg-config.import assimp : : shared ; lib pthread : : shared ; lib OpenMeshCore : : shared ; +lib boost_program_options : : shared ; variant coverage : debug ; project i-like-trains : requirements @@ -47,7 +48,7 @@ project i-like-trains : requirements ; exe iliketrains : application/main.cpp : ilt ; -exe resviewer : application/resviewer.cpp : ilt ; +exe resviewer : application/resviewer.cpp : ilt boost_program_options ; explicit main ; always main ; diff --git a/application/resviewer.cpp b/application/resviewer.cpp index e512b41..7656b29 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -23,7 +24,8 @@ constexpr GlobalDistance MAX_CAMERA_DIST = 30'000; class ViewerContent : public WindowContent, SceneRenderer, SceneProvider { public: - ViewerContent(ScreenAbsCoord size, std::span files) : SceneRenderer {size, 0}, fileList(files) + ViewerContent(ScreenAbsCoord size, std::span files) : + SceneRenderer {size, 0}, fileList(files) { camera.setPosition(calcCameraPosition()); camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); @@ -94,12 +96,12 @@ private: fileSelection() { ImGui::BeginListBox("File"); - for (const auto file : fileList) { - if (ImGui::Selectable(file, file == selectedFile)) { + for (const auto & file : fileList) { + if (ImGui::Selectable(file.c_str(), &file == selectedFile)) { location.reset(); selectedAsset = nullptr; gameState->assets = AssetFactory::loadXML(file)->assets; - selectedFile = file; + selectedFile = &file; } } ImGui::EndListBox(); @@ -149,8 +151,8 @@ private: } } - std::span fileList; - char * selectedFile {}; + std::span fileList; + const std::filesystem::path * selectedFile {}; const Renderable * selectedAsset {}; Location position {.pos = {0, 0, TERRAIN_HEIGHT}, .rot = {}}; std::any location; @@ -167,7 +169,7 @@ main(int argc, char ** argv) class ResViewer : GameState, MainApplication { public: void - run(std::span fileList) + run(std::span fileList) { windows.create(DEFAULT_WINDOW_SIZE, "ILT - Resource Viewer") ->setContent(fileList); @@ -175,7 +177,26 @@ main(int argc, char ** argv) } }; - std::span files {argv, static_cast(argc)}; + namespace po = boost::program_options; + po::options_description opts("ILT - Resource Viewer"); + std::vector resources; + // clang-format off + opts.add_options() + ("resource,r", po::value(&resources)->composing(), "Resource file") + ("help,h", po::value()->default_value(false)->zero_tokens(), "Help") + ; + // clang-format on + po::positional_options_description pod; + pod.add("resource", -1); + po::variables_map varmap; + po::store(po::command_line_parser(argc, argv).options(opts).positional(pod).run(), varmap); + po::notify(varmap); + + if (varmap.at("help").as()) { + std::cout << opts << '\n'; + return EXIT_SUCCESS; + } - ResViewer {}.run(files.subspan(2)); + ResViewer {}.run(resources); + return EXIT_SUCCESS; } -- cgit v1.2.3 From fae89fbf16b961cbc79e373da13dfe13794659bb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 9 Apr 2025 20:58:19 +0100 Subject: Fix operator precedence warning --- application/resviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/resviewer.cpp b/application/resviewer.cpp index 7656b29..418ac74 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -52,7 +52,7 @@ private: tick(TickDuration tick) override { if (autoRotate != 0) { - cameraAngle = normalize(cameraAngle + autoRotate * tick.count()); + cameraAngle = normalize(cameraAngle + (autoRotate * tick.count())); camera.setPosition(calcCameraPosition()); camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); } -- cgit v1.2.3 From 058264ec2f43d84478568588993fb05df298b125 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 15 Apr 2025 01:34:25 +0100 Subject: Remember selected asset id and reload/reselect resource file on change --- application/resviewer.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/application/resviewer.cpp b/application/resviewer.cpp index 418ac74..c82017b 100644 --- a/application/resviewer.cpp +++ b/application/resviewer.cpp @@ -56,6 +56,26 @@ private: camera.setPosition(calcCameraPosition()); camera.lookAt({0, 0, TERRAIN_HEIGHT + cameraFocus}); } + if (selectedFile) { + try { + if (const auto curmTime = std::filesystem::last_write_time(*selectedFile); curmTime != fileTime) { + location.reset(); + selectedAsset = nullptr; + gameState->assets = AssetFactory::loadXML(*selectedFile)->assets; + fileTime = curmTime; + if (!selectedAssetId.empty() && gameState->assets.contains(selectedAssetId)) { + auto asset = gameState->assets.at(selectedAssetId); + auto renderable = asset.getAs(); + if (renderable) { + location = asset->createAt(position); + selectedAsset = renderable; + } + } + } + } + catch (...) { + } + } } bool @@ -99,8 +119,10 @@ private: for (const auto & file : fileList) { if (ImGui::Selectable(file.c_str(), &file == selectedFile)) { location.reset(); + selectedAssetId.clear(); selectedAsset = nullptr; gameState->assets = AssetFactory::loadXML(file)->assets; + fileTime = std::filesystem::last_write_time(file); selectedFile = &file; } } @@ -116,6 +138,7 @@ private: auto renderable = asset.second.getAs(); if (renderable) { if (ImGui::Selectable(asset.first.c_str(), renderable == selectedAsset)) { + selectedAssetId = asset.first; selectedAsset = renderable; location = asset.second->createAt(position); } @@ -152,7 +175,9 @@ private: } std::span fileList; + std::filesystem::file_time_type fileTime; const std::filesystem::path * selectedFile {}; + std::string selectedAssetId; const Renderable * selectedAsset {}; Location position {.pos = {0, 0, TERRAIN_HEIGHT}, .rot = {}}; std::any location; -- cgit v1.2.3