diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-03-22 11:50:31 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2025-03-22 11:50:31 +0000 |
commit | 9fd25e8b10b1291525a18c8b3e34256ca6151dd6 (patch) | |
tree | c483b55010f310ed60cb7381130feedd2b3980a9 | |
parent | Support resizing the main window (diff) | |
download | ilt-9fd25e8b10b1291525a18c8b3e34256ca6151dd6.tar.bz2 ilt-9fd25e8b10b1291525a18c8b3e34256ca6151dd6.tar.xz ilt-9fd25e8b10b1291525a18c8b3e34256ca6151dd6.zip |
Add ManyPtr which tracks specified subclasses
This removes the need to repeated dynamic_cast the pointer.
Provides interface which enforces the fastest option for the required
types.
-rw-r--r-- | application/main.cpp | 7 | ||||
-rw-r--r-- | assetFactory/asset.h | 3 | ||||
-rw-r--r-- | assetFactory/assetFactory.cpp | 3 | ||||
-rw-r--r-- | assetFactory/assetFactory.h | 2 | ||||
-rw-r--r-- | game/network/rail.cpp | 2 | ||||
-rw-r--r-- | gfx/gl/shadowMapper.cpp | 2 | ||||
-rw-r--r-- | lib/manyPtr.h | 86 | ||||
-rw-r--r-- | lib/persistence.h | 3 | ||||
-rw-r--r-- | test/test-assetFactory.cpp | 12 | ||||
-rw-r--r-- | test/test-render.cpp | 13 | ||||
-rw-r--r-- | ui/gameMainWindow.cpp | 12 |
11 files changed, 119 insertions, 26 deletions
diff --git a/application/main.cpp b/application/main.cpp index 723f3d2..514fab6 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -86,7 +86,7 @@ public: } const std::shared_ptr<Train> train = world.create<Train>(l3, 800000); - auto b47 = std::dynamic_pointer_cast<RailVehicleClass>(assets.at("brush-47")); + auto b47 = assets.at("brush-47").dynamicCast<RailVehicleClass>(); for (int N = 0; N < 6; N++) { train->create<RailVehicle>(b47); } @@ -101,8 +101,9 @@ public: std::uniform_int_distribution<int> treeVariantDistribution {1, 4}; for (auto x = 311000000; x < 311830000; x += 5000) { for (auto y = 491100000; y < 491130000; y += 5000) { - world.create<Plant>(std::dynamic_pointer_cast<Foliage>(assets.at(std::format("Tree-{:#02}-{}", - treeDistribution(randomdev), treeVariantDistribution(randomdev)))), + world.create<Plant>(assets.at(std::format("Tree-{:#02}-{}", treeDistribution(randomdev), + treeVariantDistribution(randomdev))) + .dynamicCast<Foliage>(), Location {terrain->positionAt({{x + positionOffsetDistribution(randomdev), y + positionOffsetDistribution(randomdev)}}), {0, rotationDistribution(randomdev), 0}}); diff --git a/assetFactory/asset.h b/assetFactory/asset.h index 5bdd2f2..b5de056 100644 --- a/assetFactory/asset.h +++ b/assetFactory/asset.h @@ -2,12 +2,15 @@ #include "factoryMesh.h" #include "persistence.h" +#include <manyPtr.h> #include <stdTypeDefs.h> class TextureAtlas; +class Renderable; class Asset : public Persistence::Persistable, public StdTypeDefs<Asset> { public: + using ManyPtr = ManySharedPtr<Asset, const Renderable>; using TexturePtr = std::shared_ptr<TextureAtlas>; std::string id; diff --git a/assetFactory/assetFactory.cpp b/assetFactory/assetFactory.cpp index 176e1f5..426fecc 100644 --- a/assetFactory/assetFactory.cpp +++ b/assetFactory/assetFactory.cpp @@ -5,6 +5,7 @@ #include "filesystem.h" #include "gfx/image.h" #include "gfx/models/texture.h" +#include "gfx/renderable.h" #include "object.h" #include "plane.h" #include "saxParse-persistence.h" @@ -146,7 +147,7 @@ bool AssetFactory::persist(Persistence::PersistenceStore & store) { using MapObjects = Persistence::MapByMember<Shapes, std::shared_ptr<Object>>; - using MapAssets = Persistence::MapByMember<Assets>; + using MapAssets = Persistence::MapByMember<Assets, Asset::Ptr>; using MapTextureFragments = Persistence::MapByMember<TextureFragments>; using MapAssImp = Persistence::MapByMember<AssImps, std::shared_ptr<AssImp>, &AssImp::path>; return STORE_TYPE && STORE_NAME_HELPER("object", shapes, MapObjects) diff --git a/assetFactory/assetFactory.h b/assetFactory/assetFactory.h index 787f0a4..864e882 100644 --- a/assetFactory/assetFactory.h +++ b/assetFactory/assetFactory.h @@ -12,7 +12,7 @@ class Texture; class AssetFactory : public Persistence::Persistable { public: using Shapes = std::map<std::string, Shape::Ptr, std::less<>>; - using Assets = std::map<std::string, Asset::Ptr, std::less<>>; + using Assets = std::map<std::string, Asset::ManyPtr, std::less<>>; using AssImps = std::map<std::string, AssImp::Ptr, std::less<>>; using TextureFragments = std::map<std::string, TextureFragment::Ptr, std::less<>>; using Colour = RGB; diff --git a/game/network/rail.cpp b/game/network/rail.cpp index 2a18b9a..5ce6036 100644 --- a/game/network/rail.cpp +++ b/game/network/rail.cpp @@ -182,7 +182,7 @@ RailLinks::render(const SceneShader & shader, const Frustum &) const const Surface * RailLinks::getBaseSurface() const { - return std::dynamic_pointer_cast<Surface>(gameState->assets.at("terrain.surface.gravel")).get(); + return gameState->assets.at("terrain.surface.gravel").dynamicCast<const Surface>().get(); } RelativeDistance diff --git a/gfx/gl/shadowMapper.cpp b/gfx/gl/shadowMapper.cpp index 6525f76..3cb73f7 100644 --- a/gfx/gl/shadowMapper.cpp +++ b/gfx/gl/shadowMapper.cpp @@ -88,7 +88,7 @@ ShadowMapper::update(const SceneProvider & scene, const LightDirection & dir, co shadowStenciller.setLightDirection(dir); for (const auto & [id, asset] : gameState->assets) { - if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { + if (const auto r = asset.getAs<const Renderable>()) { r->updateStencil(shadowStenciller); } } diff --git a/lib/manyPtr.h b/lib/manyPtr.h new file mode 100644 index 0000000..9e08452 --- /dev/null +++ b/lib/manyPtr.h @@ -0,0 +1,86 @@ +#pragma once + +#include <memory> +#include <tuple> + +template<typename Primary, typename... Others> class ManyPtr : Primary { +public: + using element_type = typename Primary::element_type; + + template<typename... Params> ManyPtr(Params &&... params) : Primary {std::forward<Params>(params)...} + { + updatePtrs(); + } + + using Primary::operator->; + using Primary::operator*; + using Primary::operator bool; + using Primary::get; + + template<typename... Params> + void + reset(Params &&... params) + { + Primary::reset(std::forward<Params>(params)...); + updatePtrs(); + } + + template<typename Other> + [[nodiscard]] consteval static bool + couldBe() + { + return (std::is_convertible_v<Others *, Other *> || ...); + } + + template<typename Other> + requires(couldBe<Other>()) + [[nodiscard]] auto + getAs() const + { + return std::get<idx<Other>()>(others); + } + + template<typename Other> + requires(!couldBe<Other>() && requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); }) + [[nodiscard]] auto + dynamicCast() const + { + return std::dynamic_pointer_cast<Other>(*this); + } + + template<typename Other> + requires(!couldBe<Other>() && !requires { std::dynamic_pointer_cast<Other>(std::declval<Primary>()); }) + [[nodiscard]] auto + dynamicCast() const + { + return dynamic_cast<Other *>(get()); + } + +private: + using OtherPtrs = std::tuple<Others *...>; + + template<typename Other> + requires(couldBe<Other>()) + [[nodiscard]] consteval static bool + idx() + { + size_t typeIdx = 0; + return ((typeIdx++ && std::is_convertible_v<Others *, Other *>) || ...); + } + + void + updatePtrs() + { + if (*this) { + others = {dynamic_cast<Others *>(get())...}; + } + else { + others = {}; + } + } + + OtherPtrs others; +}; + +template<typename Primary, typename... Others> using ManySharedPtr = ManyPtr<std::shared_ptr<Primary>, Others...>; +template<typename Primary, typename... Others> using ManyUniquePtr = ManyPtr<std::unique_ptr<Primary>, Others...>; diff --git a/lib/persistence.h b/lib/persistence.h index e385b20..75bcea6 100644 --- a/lib/persistence.h +++ b/lib/persistence.h @@ -1,5 +1,6 @@ #pragma once +#include "manyPtr.h" #include <charconv> #include <format> #include <functional> @@ -200,7 +201,7 @@ namespace Persistence { } [[nodiscard]] virtual NameActionSelection setName(const std::string_view key, SelectionFactory &&) = 0; - virtual void selHandler() {}; + virtual void selHandler() { }; virtual void setType(const std::string_view, const Persistable *) = 0; SelectionPtr sel {}; diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 9bade82..03319da 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(surfaces, *boost::unit_test::timeout(5)) BOOST_CHECK_EQUAL(4, mf->assets.size()); auto gravelAsset = mf->assets.at("terrain.surface.gravel"); BOOST_REQUIRE(gravelAsset); - auto gravel = std::dynamic_pointer_cast<Surface>(gravelAsset); + auto gravel = gravelAsset.dynamicCast<Surface>(); BOOST_REQUIRE(gravel); BOOST_REQUIRE_EQUAL(gravel->name, "Gravel"); BOOST_REQUIRE_EQUAL(gravel->colorBias, RGB {.9F}); @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(brush47xml, *boost::unit_test::timeout(5)) BOOST_CHECK_EQUAL(1, mf->assets.size()); auto brush47 = mf->assets.at("brush-47"); BOOST_REQUIRE(brush47); - auto brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(brush47); + auto brush47rvc = brush47.dynamicCast<RailVehicleClass>(); BOOST_REQUIRE(brush47rvc); BOOST_REQUIRE(brush47rvc->bodyMesh); BOOST_REQUIRE(brush47rvc->bogies.front()); @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(foliage, *boost::unit_test::timeout(5)) gameState.assets = mf->assets; auto tree_01_1 = mf->assets.at("Tree-01-1"); BOOST_REQUIRE(tree_01_1); - auto tree_01_1_f = std::dynamic_pointer_cast<Foliage>(tree_01_1); + auto tree_01_1_f = tree_01_1.dynamicCast<Foliage>(); BOOST_REQUIRE(tree_01_1_f); auto plant1 = std::make_shared<Plant>(tree_01_1_f, Location {{-2000, 2000, 0}, {0, 0, 0}}); @@ -151,9 +151,9 @@ BOOST_AUTO_TEST_CASE(lights, *boost::unit_test::timeout(5)) BOOST_REQUIRE(rlight); auto oldlamp = mf->assets.at("old-lamp"); BOOST_REQUIRE(oldlamp); - auto rlight_f = std::dynamic_pointer_cast<Illuminator>(rlight); + auto rlight_f = rlight.dynamicCast<Illuminator>(); BOOST_REQUIRE(rlight_f); - auto oldlamp_f = std::dynamic_pointer_cast<Illuminator>(oldlamp); + auto oldlamp_f = oldlamp.dynamicCast<Illuminator>(); BOOST_REQUIRE(oldlamp_f); auto light1 = std::make_shared<Light>(oldlamp_f, Location {{0, 0, 0}, {0, 0, 0}}); @@ -164,7 +164,7 @@ BOOST_AUTO_TEST_CASE(lights, *boost::unit_test::timeout(5)) objects.objects.push_back(oldlamp_f); // yes I'm hacking some floor to light up as though its a bush - auto floorf = std::dynamic_pointer_cast<Foliage>(mf->assets.at("floor")); + auto floorf = mf->assets.at("floor").dynamicCast<Foliage>(); auto floor = std::make_shared<Plant>(floorf, Location {}); objects.objects.push_back(floorf); diff --git a/test/test-render.cpp b/test/test-render.cpp index 8390d25..a6e28bc 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -41,7 +41,7 @@ public: terrain->point(GeoData::VertexHandle {517}).z = 100'000; terrain->generateMeshes(); gameState->assets = AssetFactory::loadAll(RESDIR); - brush47rvc = std::dynamic_pointer_cast<RailVehicleClass>(gameState->assets.at("brush-47")); + brush47rvc = gameState->assets.at("brush-47").dynamicCast<RailVehicleClass>(); std::random_device randomdev {}; std::uniform_real_distribution<Angle> rotationDistribution {0, two_pi}; std::uniform_int_distribution<GlobalDistance> positionOffsetDistribution {-1500, +1500}; @@ -57,9 +57,10 @@ public: train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position()); for (auto x = 40000; x < 100000; x += 5000) { for (auto y = 65000; y < 125000; y += 5000) { - gameState->world.create<Plant>( - std::dynamic_pointer_cast<Foliage>(gameState->assets.at(std::format( - "Tree-{:#02}-{}", treeDistribution(randomdev), treeVariantDistribution(randomdev)))), + gameState->world.create<Plant>(gameState->assets + .at(std::format("Tree-{:#02}-{}", treeDistribution(randomdev), + treeVariantDistribution(randomdev))) + .dynamicCast<Foliage>(), Location {{x + positionOffsetDistribution(randomdev), y + positionOffsetDistribution(randomdev), 1}, {0, rotationDistribution(randomdev), 0}}); @@ -76,7 +77,7 @@ public: water.render(shader, frustum); rail.render(shader, frustum); std::ranges::for_each(gameState->assets, [&shader, &frustum](const auto & asset) { - if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) { + if (const auto renderable = asset.second.template getAs<const Renderable>()) { renderable->render(shader, frustum); } }); @@ -98,7 +99,7 @@ public: { terrain->shadows(shadowMapper, frustum); std::ranges::for_each(gameState->assets, [&shadowMapper, &frustum](const auto & asset) { - if (const auto renderable = std::dynamic_pointer_cast<const Renderable>(asset.second)) { + if (const auto renderable = asset.second.template getAs<const Renderable>()) { renderable->shadows(shadowMapper, frustum); } }); diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index d88bab5..b58f3dc 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -75,9 +75,9 @@ GameMainWindow::render() const void GameMainWindow::content(const SceneShader & shader, const Frustum & frustum) const { - for (const auto & [id, asset] : gameState->assets) { - if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { - r->render(shader, frustum); + for (const auto & [assetId, asset] : gameState->assets) { + if (const auto renderable = asset.getAs<const Renderable>()) { + renderable->render(shader, frustum); } } gameState->world.apply<Renderable>(&Renderable::render, shader, frustum); @@ -99,9 +99,9 @@ GameMainWindow::lights(const SceneShader & shader) const void GameMainWindow::shadows(const ShadowMapper & shadowMapper, const Frustum & frustum) const { - for (const auto & [id, asset] : gameState->assets) { - if (const auto r = std::dynamic_pointer_cast<const Renderable>(asset)) { - r->shadows(shadowMapper, frustum); + for (const auto & [assetId, asset] : gameState->assets) { + if (const auto renderable = asset.getAs<const Renderable>()) { + renderable->shadows(shadowMapper, frustum); } } gameState->world.apply<Renderable>(&Renderable::shadows, shadowMapper, frustum); |