From 49d0393775d49db58f48cad6953d5cb8cd225431 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 30 Mar 2026 00:50:50 +0100 Subject: Use uint32_t for indexes in InstanceVertices Passable to GLSL and more than big enough --- gfx/gl/instanceVertices.h | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h index d984938..e31fa83 100644 --- a/gfx/gl/instanceVertices.h +++ b/gfx/gl/instanceVertices.h @@ -9,11 +9,12 @@ template class InstanceVertices : protected glVector { using base = glVector; + using IndexT = uint32_t; public: class [[nodiscard]] InstanceProxy { public: - InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { } + InstanceProxy(InstanceVertices * iv, IndexT idx) : instances {iv}, index {idx} { } InstanceProxy(InstanceProxy && other) noexcept : instances {std::exchange(other.instances, nullptr)}, index {other.index} @@ -98,9 +99,9 @@ public: return instances->lookup(index); } - private: + // private: InstanceVertices * instances; - std::size_t index; + IndexT index; }; template @@ -110,15 +111,15 @@ public: if (!unused.empty()) { auto idx = unused.back(); unused.pop_back(); - index[idx] = base::size(); + index[idx] = static_cast(base::size()); reverseIndex.emplace_back(idx); base::emplace_back(std::forward(params)...); return InstanceProxy {this, idx}; } - index.emplace_back(base::size()); - reverseIndex.push_back(base::size()); + index.emplace_back(static_cast(base::size())); + reverseIndex.push_back(static_cast(base::size())); base::emplace_back(std::forward(params)...); - return InstanceProxy {this, index.size() - 1}; + return InstanceProxy {this, static_cast(index.size() - 1)}; } [[nodiscard]] GLuint @@ -176,7 +177,7 @@ public: } protected: - static constexpr auto npos = static_cast(-1); + static constexpr auto npos = static_cast(-1); friend InstanceProxy; base::size_type @@ -186,9 +187,9 @@ protected: } void - release(const size_t pidx) + release(const IndexT pidx) { - if (const size_t last = base::size() - 1; last != index[pidx]) { + if (const auto last = static_cast(base::size() - 1); last != index[pidx]) { lookup(pidx) = std::move(base::back()); const auto movedKey = reverseIndex[last]; index[movedKey] = std::exchange(index[pidx], npos); @@ -207,7 +208,7 @@ protected: } [[nodiscard]] T & - lookup(size_t pindex) + lookup(IndexT pindex) { return base::data()[index[pindex]]; } @@ -231,8 +232,8 @@ protected: } // Index into buffer given to nth proxy - std::vector index; - std::vector reverseIndex; + std::vector index; + std::vector reverseIndex; // List of free spaces in index - std::vector unused; + std::vector unused; }; -- cgit v1.3 From fb78c88576d9fed90ee69dfa35a9fbd3179ff486 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 30 Mar 2026 13:04:36 +0100 Subject: Use a single buffer for the location/rotation data of all renderable objects Removes the BufferedLocation and BufferedLocationUpdater mess. Note: appears to break bogie rendering in asset factory test only, same symptom as broken network render test? (out of date buffer data) --- game/scenary/foliage.cpp | 21 ++++--- game/scenary/foliage.h | 12 ++-- game/scenary/illuminator.cpp | 11 ++-- game/scenary/illuminator.h | 7 ++- game/scenary/light.cpp | 3 +- game/scenary/light.h | 2 +- game/scenary/plant.cpp | 2 +- game/scenary/plant.h | 2 +- game/vehicles/railVehicle.cpp | 49 +++++++-------- game/vehicles/railVehicle.h | 8 +-- game/vehicles/railVehicleClass.cpp | 25 ++++---- game/vehicles/railVehicleClass.h | 11 +--- game/vehicles/train.cpp | 6 ++ game/vehicles/train.h | 7 +-- game/vehicles/vehicle.h | 2 +- gfx/followCameraController.cpp | 3 +- gfx/gl/bufferedLocation.cpp | 70 ---------------------- gfx/gl/bufferedLocation.h | 48 --------------- gfx/gl/instanceVertices.h | 8 ++- gfx/gl/sceneRenderer.cpp | 4 ++ gfx/gl/shaders/billboard.vert | 10 +++- gfx/gl/shaders/commonLocationData.glsl | 20 +++++++ gfx/gl/shaders/dynamicPointInst.vert | 6 +- gfx/gl/shaders/pointLight.vert | 8 ++- gfx/gl/shaders/shadowDynamicPointInst.vert | 6 +- .../shadowDynamicPointInstWithTextures.vert | 6 +- gfx/gl/shaders/shadowDynamicPointStencil.vert | 10 ++-- gfx/gl/shaders/spotLight.vert | 8 ++- gfx/renderable.cpp | 35 +++++++++++ gfx/renderable.h | 27 ++++++++- lib/location.cpp | 8 +++ lib/location.h | 2 + test/test-render.cpp | 10 +--- 33 files changed, 219 insertions(+), 238 deletions(-) delete mode 100644 gfx/gl/bufferedLocation.cpp delete mode 100644 gfx/gl/bufferedLocation.h create mode 100644 gfx/gl/shaders/commonLocationData.glsl diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index ff00af4..5902e09 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -25,8 +25,8 @@ std::weak_ptr Foliage::commonInstanceVAO, Foliage::commonInstance std::any Foliage::createAt(const Location & position) const { - return std::make_shared::InstanceProxy>( - instances.acquire(position.getRotationTransform(), position.rot.y, position.pos)); + return std::make_shared::InstanceProxy>( + instances.acquire(locationData->acquire(position))); } bool @@ -42,12 +42,11 @@ Foliage::postLoad() glDebugScope _ {0}; if (!(instanceVAO = commonInstanceVAO.lock())) { commonInstanceVAO = instanceVAO = std::make_shared(); - bodyMesh->configureVAO(*instanceVAO, 0) - .addAttribs(1); + bodyMesh->configureVAO(*instanceVAO, 0).addAttribs(1); } if (!(instancePointVAO = commonInstancePointVAO.lock())) { commonInstancePointVAO = instancePointVAO = std::make_shared(); - instancePointVAO->configure().addAttribs(0); + instancePointVAO->configure().addAttribs(0); } const auto & size = bodyMesh->getDimensions().size; billboardSize = billboardTextureSizeForObject(size); @@ -82,14 +81,14 @@ Foliage::preFrame(const Frustum & frustum, const Frustum & lighting) if (instances.size() > 0) { const auto & dims = bodyMesh->getDimensions(); instancePartitions = instances.partition( - [&frustum, &dims](const auto & location) { - return frustum.contains(location.position + dims.centre, dims.size); + [&frustum, &dims](const auto & instance) { + return frustum.contains(instance.location->position.xyz() + dims.centre, dims.size); }, - [&frustum, this](const auto & location) { - return distance(frustum.getPosition(), location.position) < useMeshClipDist; + [&frustum, this](const auto & instance) { + return distance(frustum.getPosition(), instance.location->position.xyz()) < useMeshClipDist; }, - [&lighting, &dims](const auto & location) { - return lighting.contains(location.position + dims.centre, dims.size); + [&lighting, &dims](const auto & instance) { + return lighting.contains(instance.location->position.xyz() + dims.centre, dims.size); }); // In view frustum / Outside view frustum / // Close to view / Far from view / Casts shadow into view / No shadow in view / diff --git a/game/scenary/foliage.h b/game/scenary/foliage.h index c599649..f424ffc 100644 --- a/game/scenary/foliage.h +++ b/game/scenary/foliage.h @@ -18,13 +18,13 @@ class Foliage : public Asset, public Renderable, public StdTypeDefs { public: [[nodiscard]] std::any createAt(const Location &) const override; - struct LocationVertex { - glm::mat3 rotation; - float yaw; - GlobalPosition3D position; + struct InstanceVertex { + CommonLocationInstance location; + // float scale; + // something colorBias; }; - mutable InstanceVertices instances; + mutable InstanceVertices instances; void preFrame(const Frustum &, const Frustum &) override; void render(const SceneShader &, const Frustum &) const override; void shadows(const ShadowMapper &, const Frustum &) const override; @@ -43,5 +43,5 @@ protected: glTextures billboard; private: - InstanceVertices::PartitionResult instancePartitions; + InstanceVertices::PartitionResult instancePartitions; }; diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index 4398853..e991baa 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -11,8 +11,8 @@ std::weak_ptr Illuminator::commonInstanceVAO, Illuminator::common std::any Illuminator::createAt(const Location & position) const { - return std::make_shared::InstanceProxy>( - instances.acquire(position.getRotationTransform(), position.pos)); + return std::make_shared::InstanceProxy>( + instances.acquire(locationData->acquire(position))); } bool @@ -46,8 +46,7 @@ Illuminator::postLoad() glDebugScope _ {0}; if (!(instanceVAO = commonInstanceVAO.lock())) { commonInstanceVAO = instanceVAO = std::make_shared(); - bodyMesh->configureVAO(*instanceVAO, 0) - .addAttribs(1); + bodyMesh->configureVAO(*instanceVAO, 0).addAttribs(1); } if (!spotLight.empty()) { if (!(instancesSpotLightVAO = commonInstancesSpotLightVAO.lock())) { @@ -55,7 +54,7 @@ Illuminator::postLoad() instancesSpotLightVAO->configure() .addAttribs(0) - .addAttribs(1); + .addAttribs(1); } std::transform( spotLight.begin(), spotLight.end(), std::back_inserter(spotLightInstances), [this](const auto & s) { @@ -68,7 +67,7 @@ Illuminator::postLoad() instancesPointLightVAO->configure() .addAttribs(0) - .addAttribs(1); + .addAttribs(1); } std::transform( pointLight.begin(), pointLight.end(), std::back_inserter(pointLightInstances), [this](const auto & s) { diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index 7b6e7ad..53a7981 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -42,8 +42,11 @@ public: bool persist(Persistence::PersistenceStore & store) override; }; - using LocationVertex = std::pair; - mutable InstanceVertices instances; + struct InstanceVertex { + CommonLocationInstance location; + }; + + mutable InstanceVertices instances; mutable InstanceVertices instancesSpotLight; mutable InstanceVertices instancesPointLight; void render(const SceneShader &, const Frustum &) const override; diff --git a/game/scenary/light.cpp b/game/scenary/light.cpp index 6207497..7c38ca2 100644 --- a/game/scenary/light.cpp +++ b/game/scenary/light.cpp @@ -2,6 +2,7 @@ #include "location.h" Light::Light(std::shared_ptr type, const Location & position) : - type {std::move(type)}, location {this->type->instances.acquire(position.getRotationTransform(), position.pos)} + type {std::move(type)}, + instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { } diff --git a/game/scenary/light.h b/game/scenary/light.h index 0b19535..afb7e03 100644 --- a/game/scenary/light.h +++ b/game/scenary/light.h @@ -7,7 +7,7 @@ class Location; class Light : public WorldObject { std::shared_ptr type; - InstanceVertices::InstanceProxy location; + InstanceVertices::InstanceProxy instance; void tick(TickDuration) override diff --git a/game/scenary/plant.cpp b/game/scenary/plant.cpp index 2006225..b0e7d16 100644 --- a/game/scenary/plant.cpp +++ b/game/scenary/plant.cpp @@ -3,6 +3,6 @@ Plant::Plant(std::shared_ptr type, const Location & position) : type {std::move(type)}, - location {this->type->instances.acquire(position.getRotationTransform(), position.rot.y, position.pos)} + instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { } diff --git a/game/scenary/plant.h b/game/scenary/plant.h index 77c9ff7..cc690c5 100644 --- a/game/scenary/plant.h +++ b/game/scenary/plant.h @@ -7,7 +7,7 @@ class Location; class Plant : public WorldObject { std::shared_ptr type; - InstanceVertices::InstanceProxy location; + InstanceVertices::InstanceProxy instance; void tick(TickDuration) override diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 61f6c93..5f92066 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -11,24 +11,14 @@ #include #include -RailVehicle::RailVehicle(RailVehicleClassPtr rvc) : - RailVehicleClass::Instance {rvc->instances.acquire()}, rvClass {std::move(rvc)}, - location {[this](const BufferedLocation * l) { - this->get()->body.rotation = l->getRotationTransform(); - this->get()->body.position = l->position(); - }}, - bogies {{ - {[this](const BufferedLocation * l) { - this->get()->front.rotation = l->getRotationTransform(); - this->get()->front.position = l->position(); - }, - GlobalPosition3D {0, rvClass->wheelBase / 2.F, 0}}, - {[this](const BufferedLocation * l) { - this->get()->back.rotation = l->getRotationTransform(); - this->get()->back.position = l->position(); - }, - GlobalPosition3D {0, -rvClass->wheelBase / 2.F, 0}}, - }} +RailVehicle::RailVehicle(RailVehicleClassPtr rvc, GlobalPosition3D position) : + RailVehicleClass::Instance {rvc->instances.acquire( + RailVehicleClass::commonLocationData.lock()->acquire(Location {.pos = position, .rot = {}}), + RailVehicleClass::commonLocationData.lock()->acquire( + Location {.pos = position + RelativePosition3D {0, rvc->wheelBase / 2.F, 0}, .rot = {}}), + RailVehicleClass::commonLocationData.lock()->acquire( + Location {.pos = position + RelativePosition3D {0, -rvc->wheelBase / 2.F, 0}, .rot = {}}))}, + rvClass {std::move(rvc)} { } @@ -36,23 +26,30 @@ void RailVehicle::move(const Train * t, float & trailBy) { const auto overhang {(rvClass->length - rvClass->wheelBase) / 2}; - const auto & b1Pos = bogies[0] = t->getBogiePosition(t->linkDist, trailBy += overhang); - const auto & b2Pos = bogies[1] = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase); - const auto diff = glm::normalize(RelativePosition3D(b2Pos.position() - b1Pos.position())); - location.setLocation((b1Pos.position() + b2Pos.position()) / 2, {vector_pitch(diff), vector_yaw(diff), 0}); + const auto & b1Pos = *(get()->front = t->getBogiePosition(t->linkDist, trailBy += overhang)); + const auto & b2Pos = *(get()->back = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase)); + const auto diff = glm::normalize(difference(b2Pos.position, b1Pos.position)); + get()->body = Location { + .pos = midpoint(b1Pos.position, b2Pos.position), .rot = {vector_pitch(diff), vector_yaw(diff), 0}}; trailBy += 600.F + overhang; } +Location +RailVehicle::getLocation() const +{ + return {.pos = get()->body->position, .rot = get()->body->rotation}; +} + bool RailVehicle::intersectRay(const Ray & ray, BaryPosition & baryPos, RelativeDistance & distance) const { constexpr const auto X = 1350.F; const auto Y = this->rvClass->length / 2.F; constexpr const auto Z = 3900.F; - const glm::mat3 moveBy = location.getRotationTransform(); - const auto cornerVertices = cuboidCorners(-X, X, -Y, Y, 0.F, Z) * [&moveBy, this](const auto & corner) { - return location.position() + (moveBy * corner); - }; + const auto cornerVertices + = cuboidCorners(-X, X, -Y, Y, 0.F, Z) * [body = this->get()->body.get()](const auto & corner) { + return body->position + (body->rotationMatrix * corner); + }; static constexpr const std::array, 10> triangles {{ // Front {0, 1, 2}, diff --git a/game/vehicles/railVehicle.h b/game/vehicles/railVehicle.h index bf1e782..0f341f9 100644 --- a/game/vehicles/railVehicle.h +++ b/game/vehicles/railVehicle.h @@ -1,8 +1,6 @@ #pragma once -#include "gfx/gl/bufferedLocation.h" #include "railVehicleClass.h" -#include #include #include #include @@ -12,16 +10,14 @@ class Train; class RailVehicle : Selectable, RailVehicleClass::Instance { public: - explicit RailVehicle(RailVehicleClassPtr rvc); + explicit RailVehicle(RailVehicleClassPtr rvc, GlobalPosition3D = {}); void move(const Train *, float & trailBy); + [[nodiscard]] Location getLocation() const; [[nodiscard]] bool intersectRay(const Ray &, BaryPosition &, RelativeDistance &) const override; RailVehicleClassPtr rvClass; - using LV = RailVehicleClass::LocationVertex; - BufferedLocationUpdater location; - std::array bogies; }; using RailVehiclePtr = std::unique_ptr; diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp index 176fe82..4e9404c 100644 --- a/game/vehicles/railVehicleClass.cpp +++ b/game/vehicles/railVehicleClass.cpp @@ -7,7 +7,6 @@ #include #include #include -#include bool RailVehicleClass::persist(Persistence::PersistenceStore & store) @@ -20,12 +19,10 @@ RailVehicleClass::persist(Persistence::PersistenceStore & store) std::any RailVehicleClass::createAt(const Location & position) const { - return std::make_shared::InstanceProxy>(instances.acquire(LocationVertex { - .body = {.rotation = position.getRotationTransform(), .position = position.pos}, - .front = {.rotation = position.getRotationTransform(), - .position = {sincos(position.rot.x) * wheelBase * 0.5F, position.pos.z}}, - .back = {.rotation = position.getRotationTransform(), - .position = {sincos(position.rot.x) * wheelBase * -0.5F, position.pos.z}}, + return std::make_shared::InstanceProxy>(instances.acquire(InstanceVertex { + .body = locationData->acquire(position), + .front = locationData->acquire(position + ((sincos(position.rot.x) * wheelBase * 0.5F) || 0.F)), + .back = locationData->acquire(position + ((sincos(position.rot.x) * wheelBase * -0.5F) || 0.F)), })); } @@ -34,22 +31,20 @@ RailVehicleClass::postLoad() { texture = getTexture(); glDebugScope _ {0}; - bodyMesh->configureVAO(instanceVAO, 0) - .addAttribs(1); - static_assert(sizeof(LocationVertex) == 144UL); + bodyMesh->configureVAO(instanceVAO, 0).addAttribs(1); } void RailVehicleClass::renderAllParts(const size_t count) const { - using PartPair = std::pair; + using PartPair = std::pair; const auto bufferName = instances.bufferName(); for (const auto & [mesh, part] : { - PartPair {bodyMesh, &LocationVertex::body}, - PartPair {bogies.front(), &LocationVertex::front}, - PartPair {bogies.back(), &LocationVertex::back}, + PartPair {bodyMesh, &InstanceVertex::body}, + PartPair {bogies.front(), &InstanceVertex::front}, + PartPair {bogies.back(), &InstanceVertex::back}, }) { - instanceVAO.useBuffer(1, bufferName, part); + instanceVAO.useBuffer(1, bufferName, part); mesh->drawInstanced(instanceVAO, static_cast(count)); } } diff --git a/game/vehicles/railVehicleClass.h b/game/vehicles/railVehicleClass.h index fe27230..a635122 100644 --- a/game/vehicles/railVehicleClass.h +++ b/game/vehicles/railVehicleClass.h @@ -19,13 +19,8 @@ public: [[nodiscard]] std::any createAt(const Location &) const override; - struct LocationVertex { - struct Part { - glm::mat3 rotation; - GlobalPosition3D position; - }; - - Part body, front, back; + struct InstanceVertex { + CommonLocationInstance body, front, back; }; std::array bogies; @@ -35,7 +30,7 @@ public: float length; float maxSpeed; - mutable InstanceVertices instances; + mutable InstanceVertices instances; using Instance = decltype(instances)::InstanceProxy; protected: diff --git a/game/vehicles/train.cpp b/game/vehicles/train.cpp index 2461d9c..c79fd17 100644 --- a/game/vehicles/train.cpp +++ b/game/vehicles/train.cpp @@ -21,6 +21,12 @@ Train::getBogiePosition(float linkDist, float dist) const return b2Link.first->positionAt(b2linkDist, b2Link.second); } +Location +Train::getLocation() const +{ + return objects.front()->getLocation(); +} + bool Train::intersectRay(const Ray & ray, BaryPosition & baryPos, RelativeDistance & distance) const { diff --git a/game/vehicles/train.h b/game/vehicles/train.h index 88e30f9..9ca53a8 100644 --- a/game/vehicles/train.h +++ b/game/vehicles/train.h @@ -19,12 +19,7 @@ class Train : public Vehicle, public UniqueCollection, public Canlocation; - } - + [[nodiscard]] Location getLocation() const override; [[nodiscard]] bool intersectRay(const Ray &, BaryPosition &, RelativeDistance &) const override; void tick(TickDuration elapsed) override; diff --git a/game/vehicles/vehicle.h b/game/vehicles/vehicle.h index c3b35b7..cca8ff0 100644 --- a/game/vehicles/vehicle.h +++ b/game/vehicles/vehicle.h @@ -18,7 +18,7 @@ public: float linkDist; // distance along current link float speed {}; // speed in m/s (~75 km/h) - [[nodiscard]] virtual const Location & getLocation() const = 0; + [[nodiscard]] virtual Location getLocation() const = 0; Orders orders; ActivityPtr currentActivity; diff --git a/gfx/followCameraController.cpp b/gfx/followCameraController.cpp index d7bbc0b..c3a5d08 100644 --- a/gfx/followCameraController.cpp +++ b/gfx/followCameraController.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -15,7 +14,7 @@ FollowCameraController::updateCamera(Camera * camera) const { const auto [pos, rot] = [this]() { const auto t {target.lock()}; - return std::tie(t->getLocation().pos, t->getLocation().rot); + return std::make_pair(t->getLocation().pos, t->getLocation().rot); }(); switch (mode) { diff --git a/gfx/gl/bufferedLocation.cpp b/gfx/gl/bufferedLocation.cpp deleted file mode 100644 index f1bedfe..0000000 --- a/gfx/gl/bufferedLocation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "bufferedLocation.h" -#include "location.h" -#include - -BufferedLocation::BufferedLocation(GlobalPosition3D p, Rotation3D r) : BufferedLocation {Location {p, r}} { } - -BufferedLocation::BufferedLocation(const Location & l) : loc {l} { } - -BufferedLocation::operator const Location &() const -{ - return loc; -} - -BufferedLocation & -BufferedLocation::operator=(const Location & l) -{ - loc = l; - updateBuffer(); - return *this; -} - -GlobalPosition3D -BufferedLocation::position() const -{ - return loc.pos; -} - -Rotation3D -BufferedLocation::rotation() const -{ - return loc.rot; -} - -void -BufferedLocation::setPosition(GlobalPosition3D p, bool update) -{ - loc.pos = p; - if (update) { - updateBuffer(); - } -} - -void -BufferedLocation::setRotation(Rotation3D r, bool update) -{ - loc.rot = r; - if (update) { - updateBuffer(); - } -} - -void -BufferedLocation::setLocation(GlobalPosition3D p, Rotation3D r) -{ - loc.pos = p; - loc.rot = r; - updateBuffer(); -} - -glm::mat4 -BufferedLocation::getRotationTransform() const -{ - return loc.getRotationTransform(); -} - -void -BufferedLocationUpdater::updateBuffer() const -{ - onUpdate(this); -} diff --git a/gfx/gl/bufferedLocation.h b/gfx/gl/bufferedLocation.h deleted file mode 100644 index 87b957f..0000000 --- a/gfx/gl/bufferedLocation.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "location.h" -#include -#include -#include -#include - -class BufferedLocation { -public: - BufferedLocation(GlobalPosition3D = {}, Rotation3D = {}); - BufferedLocation(const Location &); - virtual ~BufferedLocation() = default; - - BufferedLocation & operator=(const Location &); - - operator const Location &() const; - - [[nodiscard]] GlobalPosition3D position() const; - [[nodiscard]] Rotation3D rotation() const; - void setPosition(GlobalPosition3D, bool update = true); - void setRotation(Rotation3D, bool update = true); - void setLocation(GlobalPosition3D, Rotation3D); - - [[nodiscard]] glm::mat4 getRotationTransform() const; - -private: - virtual void updateBuffer() const = 0; - - Location loc; -}; - -class BufferedLocationUpdater : public BufferedLocation { -public: - template - BufferedLocationUpdater(std::function onUpdate, LocationArgs &&... t) : - BufferedLocation {std::forward(t)...}, onUpdate {std::move(onUpdate)} - { - updateBuffer(); - } - - using BufferedLocation::operator=; - -private: - void updateBuffer() const override; - - std::function onUpdate; -}; diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h index e31fa83..9963a96 100644 --- a/gfx/gl/instanceVertices.h +++ b/gfx/gl/instanceVertices.h @@ -128,6 +128,12 @@ public: return base::begin().base().bufferName(); } + [[nodiscard]] GLuint + indexBufferName() const + { + return index.begin().base().bufferName(); + } + using typename base::value_type; using base::at; @@ -232,7 +238,7 @@ protected: } // Index into buffer given to nth proxy - std::vector index; + glVector index; std::vector reverseIndex; // List of free spaces in index std::vector unused; diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index ea11bea..a809ed5 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -78,6 +78,10 @@ SceneRenderer::preFrame(const SceneProvider & scene, const LightDirection lightD renderable->preFrame(camera, lightView); renderable->updateBillboard(billboardPainter); }); + if (auto cld = Renderable::commonLocationData.lock()) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cld->bufferName()); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, cld->indexBufferName()); + } } void diff --git a/gfx/gl/shaders/billboard.vert b/gfx/gl/shaders/billboard.vert index faf8b19..d6d3869 100644 --- a/gfx/gl/shaders/billboard.vert +++ b/gfx/gl/shaders/billboard.vert @@ -1,12 +1,15 @@ #version 460 core +#extension GL_ARB_shading_language_include : enable + +#include "commonLocationData.glsl" uniform mat4 viewProjection; uniform ivec4 viewPort; uniform ivec3 viewPoint; uniform vec3 centre; uniform float size; -layout(location = 0) in ivec3 modelPos; -layout(location = 1) in float yaw; + +layout(location = 0) in uint index; flat out vec3 ModelPos; flat out float Yaw; @@ -15,8 +18,9 @@ flat out float Depth; void main() { + const ivec3 modelPos = locations[cldIndex[index]].position.xyz; ModelPos = modelPos - viewPoint; - Yaw = yaw; + Yaw = locations[cldIndex[index]].rotation.x; gl_Position = viewProjection * vec4(ModelPos + centre, 1); Depth = gl_Position.w; gl_PointSize = (viewPort.w * size * 2) / gl_Position.w; diff --git a/gfx/gl/shaders/commonLocationData.glsl b/gfx/gl/shaders/commonLocationData.glsl new file mode 100644 index 0000000..4939b9b --- /dev/null +++ b/gfx/gl/shaders/commonLocationData.glsl @@ -0,0 +1,20 @@ +#ifndef COMMON_LOCATION_DATA_INCLUDED +#define COMMON_LOCATION_DATA_INCLUDED + +struct CommonLocationData { + ivec4 position; + vec4 rotation; + mat3x4 rotationMatrix; +}; + +layout(binding = 0, std430) restrict readonly buffer commonLocationData +{ + CommonLocationData locations[]; +}; + +layout(binding = 1, std430) restrict readonly buffer commonLocationDataIndex +{ + uint cldIndex[]; +}; + +#endif diff --git a/gfx/gl/shaders/dynamicPointInst.vert b/gfx/gl/shaders/dynamicPointInst.vert index 7a00099..7c50706 100644 --- a/gfx/gl/shaders/dynamicPointInst.vert +++ b/gfx/gl/shaders/dynamicPointInst.vert @@ -3,12 +3,14 @@ layout(binding = 1) uniform usampler2DRect materialData; +#include "commonLocationData.glsl" #include "materialInterface.glsl" #include "meshIn.glsl" uniform mat4 viewProjection; uniform ivec3 viewPoint; -layout(location = 5) in mat3 model; -layout(location = 8) in ivec3 modelPos; +layout(location = 5) in uint index; +mat3 model = mat3(locations[cldIndex[index]].rotationMatrix); +ivec3 modelPos = locations[cldIndex[index]].position.xyz; #include "commonPoint.glsl" diff --git a/gfx/gl/shaders/pointLight.vert b/gfx/gl/shaders/pointLight.vert index b8ddecb..61953ad 100644 --- a/gfx/gl/shaders/pointLight.vert +++ b/gfx/gl/shaders/pointLight.vert @@ -1,10 +1,14 @@ #version 460 core +#extension GL_ARB_shading_language_include : enable + +#include "commonLocationData.glsl" layout(location = 0) in vec3 v_position; layout(location = 1) in vec3 v_colour; layout(location = 2) in float v_kq; -layout(location = 3) in mat3 model; -layout(location = 6) in ivec3 modelPos; +layout(location = 3) in uint index; +mat3 model = mat3(locations[cldIndex[index]].rotationMatrix); +ivec3 modelPos = locations[cldIndex[index]].position.xyz; uniform ivec3 viewPoint; diff --git a/gfx/gl/shaders/shadowDynamicPointInst.vert b/gfx/gl/shaders/shadowDynamicPointInst.vert index d020717..b978e4a 100644 --- a/gfx/gl/shaders/shadowDynamicPointInst.vert +++ b/gfx/gl/shaders/shadowDynamicPointInst.vert @@ -1,10 +1,12 @@ #version 460 core #extension GL_ARB_shading_language_include : enable +#include "commonLocationData.glsl" #include "meshIn.glsl" uniform ivec3 viewPoint; -layout(location = 5) in mat3 model; -layout(location = 8) in ivec3 modelPos; +layout(location = 5) in uint index; +mat3 model = mat3(locations[cldIndex[index]].rotationMatrix); +ivec3 modelPos = locations[cldIndex[index]].position.xyz; #include "commonShadowPoint.glsl" diff --git a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert index 51b05c8..a5e8245 100644 --- a/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert +++ b/gfx/gl/shaders/shadowDynamicPointInstWithTextures.vert @@ -4,12 +4,14 @@ layout(binding = 4) uniform usampler2DRect materialData; +#include "commonLocationData.glsl" #include "getMaterialDetail.glsl" #include "materialInterface.glsl" #include "meshIn.glsl" uniform ivec3 viewPoint; -layout(location = 5) in mat3 model; -layout(location = 8) in ivec3 modelPos; +layout(location = 5) in uint index; +mat3 model = mat3(locations[cldIndex[index]].rotationMatrix); +ivec3 modelPos = locations[cldIndex[index]].position.xyz; #include "commonShadowPoint.glsl" diff --git a/gfx/gl/shaders/shadowDynamicPointStencil.vert b/gfx/gl/shaders/shadowDynamicPointStencil.vert index b750b3e..0a41143 100644 --- a/gfx/gl/shaders/shadowDynamicPointStencil.vert +++ b/gfx/gl/shaders/shadowDynamicPointStencil.vert @@ -1,7 +1,9 @@ #version 460 core +#extension GL_ARB_shading_language_include : enable -layout(location = 0) in ivec3 worldPos; -layout(location = 1) in float modelYaw; +#include "commonLocationData.glsl" + +layout(location = 0) in uint index; uniform ivec3 viewPoint; uniform vec3 centre; @@ -11,6 +13,6 @@ out ivec3 vworldPos; void main() { - vmodelYaw = modelYaw; - vworldPos = worldPos - viewPoint + ivec3(centre); + vmodelYaw = locations[cldIndex[index]].rotation.x; + vworldPos = locations[cldIndex[index]].position.xyz - viewPoint + ivec3(centre); } diff --git a/gfx/gl/shaders/spotLight.vert b/gfx/gl/shaders/spotLight.vert index 83f3859..6f72a63 100644 --- a/gfx/gl/shaders/spotLight.vert +++ b/gfx/gl/shaders/spotLight.vert @@ -1,12 +1,16 @@ #version 460 core +#extension GL_ARB_shading_language_include : enable + +#include "commonLocationData.glsl" layout(location = 0) in vec3 v_position; layout(location = 1) in vec3 v_direction; layout(location = 2) in vec3 v_colour; layout(location = 3) in float v_kq; layout(location = 4) in float v_arc; -layout(location = 5) in mat3 model; -layout(location = 8) in ivec3 modelPos; +layout(location = 5) in uint index; +mat3 model = mat3(locations[cldIndex[index]].rotationMatrix); +ivec3 modelPos = locations[cldIndex[index]].position.xyz; uniform ivec3 viewPoint; diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 8caab93..4597597 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -1,4 +1,39 @@ #include "renderable.h" +#include "gl_traits.h" +#include "location.h" +#include "maths.h" + +std::weak_ptr Renderable::commonLocationData; + +Renderable::CommonLocation::CommonLocation(Location const & location) : + position {location.pos, 0}, rotation {location.rot, 0}, rotationMatrix {location.getRotationTransform()} +{ +} + +Renderable::CommonLocation & +Renderable::CommonLocation ::operator=(Location const & location) +{ + position = location.pos || 0; + rotation = location.rot || 0.F; + rotationMatrix = location.getRotationTransform(); + return *this; +} + +Renderable::Renderable() +{ + if (!(locationData = commonLocationData.lock())) { + commonLocationData = locationData = std::make_shared(); + } +} + +GLuint +gl_traits::InstanceProxy>::vertexArrayAttribFormat( + GLuint vao, GLuint index, GLuint offset) +{ + return gl_traits< + decltype(InstanceVertices::InstanceProxy::index)>::vertexArrayAttribFormat(vao, + index, offset + offsetof(InstanceVertices::InstanceProxy, index)); +}; void Renderable::preFrame(const Frustum &, const Frustum &) diff --git a/gfx/renderable.h b/gfx/renderable.h index d0870ad..b0a42f2 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -1,5 +1,8 @@ #pragma once +#include "gfx/gl/instanceVertices.h" +#include "gl_traits.h" +#include #include class SceneShader; @@ -7,10 +10,11 @@ class Frustum; class ShadowMapper; class ShadowStenciller; class BillboardPainter; +class Location; class Renderable { public: - Renderable() = default; + Renderable(); virtual ~Renderable() = default; DEFAULT_MOVE_COPY(Renderable); @@ -21,4 +25,25 @@ public: virtual void updateStencil(const ShadowStenciller & lightDir) const; virtual void updateBillboard(const BillboardPainter &) const; + + struct CommonLocation { + CommonLocation(const Location &); + CommonLocation & operator=(const Location &); + + glm::ivec4 position; + glm::vec4 rotation; + glm::mat3x4 rotationMatrix; + }; + + using CommonLocationData = InstanceVertices; + using CommonLocationInstance = CommonLocationData::InstanceProxy; + + std::shared_ptr locationData; + + static std::weak_ptr commonLocationData; +}; + +template<> struct gl_traits::InstanceProxy> { + static GLuint vertexArrayAttribFormat(GLuint vao, GLuint index, GLuint offset); }; + diff --git a/lib/location.cpp b/lib/location.cpp index 13acfde..2138f0a 100644 --- a/lib/location.cpp +++ b/lib/location.cpp @@ -2,6 +2,14 @@ #include "maths.h" #include +Location +Location::operator+(RelativePosition3D offset) const +{ + Location ret {*this}; + ret.pos += offset; + return ret; +} + glm::mat3 Location::getRotationTransform() const { diff --git a/lib/location.h b/lib/location.h index 016aee7..e642b41 100644 --- a/lib/location.h +++ b/lib/location.h @@ -11,6 +11,8 @@ public: [[nodiscard]] glm::mat3 getRotationTransform() const; + Location operator+(RelativePosition3D) const; + GlobalPosition3D pos; Rotation3D rot; }; diff --git a/test/test-render.cpp b/test/test-render.cpp index 35d71f3..b21f440 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -49,14 +49,8 @@ namespace { std::uniform_int_distribution positionOffsetDistribution {-1500, +1500}; std::uniform_int_distribution treeDistribution {1, 3}; std::uniform_int_distribution treeVariantDistribution {1, 4}; - train1 = std::make_shared(brush47rvc); - train1->location.setPosition({52000, 50000, 2000}); - train1->bogies.front().setPosition(train1->bogies.front().position() + train1->location.position()); - train1->bogies.back().setPosition(train1->bogies.back().position() + train1->location.position()); - train2 = std::make_shared(brush47rvc); - train2->location.setPosition({52000, 30000, 2000}); - train2->bogies.front().setPosition(train2->bogies.front().position() + train2->location.position()); - train2->bogies.back().setPosition(train2->bogies.back().position() + train2->location.position()); + train1 = std::make_shared(brush47rvc, GlobalPosition3D {52000, 50000, 2000}); + train2 = std::make_shared(brush47rvc, GlobalPosition3D {52000, 30000, 2000}); for (auto posX = 40000; posX < 100000; posX += 5000) { for (auto posY = 65000; posY < 125000; posY += 5000) { gameState->world.create( -- cgit v1.3 From c29c04aa3caf6487b127c87dc42fc293f354a85d Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 31 Mar 2026 00:45:41 +0100 Subject: Move light vertex structs out --- game/scenary/illuminator.h | 14 +------------- gfx/gl/lights.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 gfx/gl/lights.h diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index 53a7981..c342bd4 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -2,6 +2,7 @@ #include "assetFactory/asset.h" #include "gfx/gl/instanceVertices.h" +#include "gfx/gl/lights.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -17,19 +18,6 @@ class Illuminator : public Asset, public Renderable, public StdTypeDefs { private: friend Persistence::SelectionPtrBase>; diff --git a/gfx/gl/lights.h b/gfx/gl/lights.h new file mode 100644 index 0000000..3247e25 --- /dev/null +++ b/gfx/gl/lights.h @@ -0,0 +1,16 @@ +#pragma once + +#include "config/types.h" + +struct LightCommonVertex { + RelativePosition3D position; + RGB colour; + RelativeDistance kq; +}; + +struct SpotLightVertex : LightCommonVertex { + Direction3D direction; + Angle arc; +}; + +struct PointLightVertex : LightCommonVertex { }; -- cgit v1.3 From 56207fbf4e8662b6cf93632193ba68d2576c2d4e Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 1 Apr 2026 12:07:58 +0100 Subject: Helper to instantiate transient static values as required --- game/scenary/foliage.cpp | 7 +++---- game/scenary/illuminator.cpp | 4 ++-- gfx/renderable.cpp | 5 ++--- lib/util.h | 12 ++++++++++++ 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp index 5902e09..f27ac26 100644 --- a/game/scenary/foliage.cpp +++ b/game/scenary/foliage.cpp @@ -4,6 +4,7 @@ #include "gfx/gl/sceneShader.h" #include "gfx/gl/shadowMapper.h" #include "gfx/gl/shadowStenciller.h" +#include "util.h" #include static_assert(std::is_constructible_v); @@ -40,12 +41,10 @@ Foliage::postLoad() { texture = getTexture(); glDebugScope _ {0}; - if (!(instanceVAO = commonInstanceVAO.lock())) { - commonInstanceVAO = instanceVAO = std::make_shared(); + if (createIfRequired(instanceVAO, commonInstanceVAO)) { bodyMesh->configureVAO(*instanceVAO, 0).addAttribs(1); } - if (!(instancePointVAO = commonInstancePointVAO.lock())) { - commonInstancePointVAO = instancePointVAO = std::make_shared(); + if (createIfRequired(instancePointVAO, commonInstancePointVAO)) { instancePointVAO->configure().addAttribs(0); } const auto & size = bodyMesh->getDimensions().size; diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index e991baa..3b73cd3 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -1,6 +1,7 @@ #include "illuminator.h" #include "gfx/gl/sceneShader.h" #include "gfx/models/texture.h" // IWYU pragma: keep +#include "util.h" #include static_assert(std::is_constructible_v); @@ -44,8 +45,7 @@ Illuminator::postLoad() } texture = getTexture(); glDebugScope _ {0}; - if (!(instanceVAO = commonInstanceVAO.lock())) { - commonInstanceVAO = instanceVAO = std::make_shared(); + if (createIfRequired(instanceVAO, commonInstanceVAO)) { bodyMesh->configureVAO(*instanceVAO, 0).addAttribs(1); } if (!spotLight.empty()) { diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 4597597..90035c3 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -2,6 +2,7 @@ #include "gl_traits.h" #include "location.h" #include "maths.h" +#include "util.h" std::weak_ptr Renderable::commonLocationData; @@ -21,9 +22,7 @@ Renderable::CommonLocation ::operator=(Location const & location) Renderable::Renderable() { - if (!(locationData = commonLocationData.lock())) { - commonLocationData = locationData = std::make_shared(); - } + createIfRequired(locationData, commonLocationData); } GLuint diff --git a/lib/util.h b/lib/util.h index cd7971b..b60b093 100644 --- a/lib/util.h +++ b/lib/util.h @@ -3,6 +3,7 @@ #include // IWYU pragma: keep #include #include +#include #include template @@ -33,3 +34,14 @@ template inline constexpr auto Nth = GetNth {}; inline constexpr auto GetFirst = Nth<0>; inline constexpr auto GetSecond = Nth<1>; inline constexpr auto GetSwapped = Nth<0, 1>; + +template +bool +createIfRequired(std::shared_ptr & instance, std::weak_ptr & common) +{ + if (!instance && !(instance = common.lock())) { + common = instance = std::make_shared(); + return true; + } + return false; +} -- cgit v1.3 From 6635cee143eb4cf3882bac519b8c12b83b62de62 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 1 Apr 2026 14:21:10 +0100 Subject: Add helper to Decompose a member pointer --- lib/util.cpp | 1 - lib/util.h | 10 ++++++++++ test/Jamfile.jam | 1 + test/test-static-util.cpp | 29 +++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) delete mode 100644 lib/util.cpp create mode 100644 test/test-static-util.cpp diff --git a/lib/util.cpp b/lib/util.cpp deleted file mode 100644 index 408a76a..0000000 --- a/lib/util.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "util.h" diff --git a/lib/util.h b/lib/util.h index b60b093..093462d 100644 --- a/lib/util.h +++ b/lib/util.h @@ -35,6 +35,16 @@ inline constexpr auto GetFirst = Nth<0>; inline constexpr auto GetSecond = Nth<1>; inline constexpr auto GetSwapped = Nth<0, 1>; +template struct Decompose { + consteval Decompose(M T::*) { } + + using ValueType = M; + using ContainerType = T; +}; + +template using MemberValueType = typename decltype(Decompose {MbrPtr})::ValueType; +template using ContainerType = typename decltype(Decompose {MbrPtr})::ContainerType; + template bool createIfRequired(std::shared_ptr & instance, std::weak_ptr & common) diff --git a/test/Jamfile.jam b/test/Jamfile.jam index da2a61a..baf0db4 100644 --- a/test/Jamfile.jam +++ b/test/Jamfile.jam @@ -79,5 +79,6 @@ run test-environment.cpp : : : test ; run test-ui.cpp : : : test ; compile test-static-enumDetails.cpp ; compile test-static-stream_support.cpp ; +compile test-static-util.cpp ; alias perf : perf-assetFactory perf-persistence perf-geoData perf-instancing perf-terrain ; explicit perf ; diff --git a/test/test-static-util.cpp b/test/test-static-util.cpp new file mode 100644 index 0000000..2a8aa81 --- /dev/null +++ b/test/test-static-util.cpp @@ -0,0 +1,29 @@ +#include "util.h" + +namespace { + struct Base1 { + int a; + float b; + }; + + struct Base2 { + int x; + float y; + }; + + struct Sub : Base1, Base2 { + double value; + }; + + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, float>); + static_assert(std::is_same_v, int>); + static_assert(std::is_same_v, float>); + static_assert(std::is_same_v, double>); + + static_assert(std::is_same_v, Base1>); + static_assert(std::is_same_v, Base2>); + static_assert(std::is_same_v, Base1>); + static_assert(std::is_same_v, Base2>); + static_assert(std::is_same_v, Sub>); +} -- cgit v1.3 From e3e84d182d4d7ecffecf004f3cfd35f7b87df199 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 1 Apr 2026 14:24:09 +0100 Subject: Fix VertexArrayConfigurator with derived classes Fixing passing a pointer to member of base class; previously the offset was deduced relative to the structure it was in, not the vertex as a whole. --- gfx/gl/glVertexArray.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/gfx/gl/glVertexArray.h b/gfx/gl/glVertexArray.h index 323303c..4e8113f 100644 --- a/gfx/gl/glVertexArray.h +++ b/gfx/gl/glVertexArray.h @@ -4,6 +4,7 @@ #include "glArrays.h" #include "glBuffer.h" #include "gl_traits.h" +#include "util.h" namespace Impl { class VertexArrayConfigurator { @@ -20,11 +21,8 @@ namespace Impl { } M T::* ptr; - using ValueType = M; }; - template MP(M T::*) -> MP; - explicit VertexArrayConfigurator(GLuint name) : name {name} { } VertexArrayConfigurator & @@ -52,7 +50,7 @@ namespace Impl { return addAttribsFor(divisor); } - template + template VertexArrayConfigurator & addAttribs(const GLuint divisor) { @@ -60,7 +58,7 @@ namespace Impl { return *this; } - template + template VertexArrayConfigurator & addAttribs(const GLuint divisor, const glBuffer & buffer) { @@ -68,7 +66,7 @@ namespace Impl { return addAttribs(divisor); } - template + template VertexArrayConfigurator & addAttribs(const GLuint divisor, glBuffer & buffer, const SequentialCollection auto & data) { @@ -93,14 +91,15 @@ namespace Impl { setPointerMeta(attrib + gl_traits::vertexArrayAttribFormat(name, attrib, offset)); } - template + template void setPointer() { - setPointer(Attrib); + using Mbr = MemberValueType; + setPointer(MP {Attrib}); } - template + template void configureAttribs(const GLuint divisor) { @@ -108,7 +107,7 @@ namespace Impl { setPointer(0); } else { - ((setPointer()), ...); + ((setPointer()), ...); } glVertexArrayBindingDivisor(name, binding++, divisor); } -- cgit v1.3 From 30fcb8bce7b60b6754a0d35f2f15b627d0fba4cb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 1 Apr 2026 20:21:23 +0100 Subject: Have Renderable manage all instance lights Spot and point lights now existing in Renderable, the vertex data contains the owning parent object's index in CommonLocationData, the render step is just a single draw call. --- application/main.cpp | 4 ++++ game/scenary/illuminator.cpp | 55 +------------------------------------------- game/scenary/illuminator.h | 16 +++++-------- game/scenary/light.cpp | 9 ++++++++ game/scenary/light.h | 3 +++ gfx/gl/lights.h | 16 ------------- gfx/models/lights.cpp | 11 +++++++++ gfx/models/lights.h | 29 +++++++++++++++++++++++ gfx/renderable.cpp | 42 ++++++++++++++++++++++++++++++++- gfx/renderable.h | 15 +++++++++--- test/test-assetFactory.cpp | 2 +- test/test-render.cpp | 8 ++++++- ui/gameMainWindow.cpp | 4 ++-- 13 files changed, 126 insertions(+), 88 deletions(-) delete mode 100644 gfx/gl/lights.h create mode 100644 gfx/models/lights.cpp create mode 100644 gfx/models/lights.h diff --git a/application/main.cpp b/application/main.cpp index f5acb3b..d64d799 100644 --- a/application/main.cpp +++ b/application/main.cpp @@ -1,3 +1,4 @@ +#include "game/scenary/light.h" #include "ui/mainApplication.h" #include "ui/mainWindow.h" #include @@ -108,6 +109,9 @@ public: {0, rotationDistribution(randomdev), 0}}); } } + + world.create(assets.at("old-lamp").dynamicCast(), + Location {.pos = terrain->positionAt({{311000000, 491100000}})}); } mainLoop(); diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index 3b73cd3..55791a5 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -6,8 +6,7 @@ static_assert(std::is_constructible_v); -std::weak_ptr Illuminator::commonInstanceVAO, Illuminator::commonInstancesSpotLightVAO, - Illuminator::commonInstancesPointLightVAO; +std::weak_ptr Illuminator::commonInstanceVAO; std::any Illuminator::createAt(const Location & position) const @@ -48,32 +47,6 @@ Illuminator::postLoad() if (createIfRequired(instanceVAO, commonInstanceVAO)) { bodyMesh->configureVAO(*instanceVAO, 0).addAttribs(1); } - if (!spotLight.empty()) { - if (!(instancesSpotLightVAO = commonInstancesSpotLightVAO.lock())) { - commonInstancesSpotLightVAO = instancesSpotLightVAO = std::make_shared(); - instancesSpotLightVAO->configure() - .addAttribs(0) - .addAttribs(1); - } - std::transform( - spotLight.begin(), spotLight.end(), std::back_inserter(spotLightInstances), [this](const auto & s) { - return instancesSpotLight.acquire(*s); - }); - } - if (!pointLight.empty()) { - if (!(instancesPointLightVAO = commonInstancesPointLightVAO.lock())) { - commonInstancesPointLightVAO = instancesPointLightVAO = std::make_shared(); - instancesPointLightVAO->configure() - .addAttribs(0) - .addAttribs(1); - } - std::transform( - pointLight.begin(), pointLight.end(), std::back_inserter(pointLightInstances), [this](const auto & s) { - return instancesPointLight.acquire(*s); - }); - } } void @@ -89,29 +62,3 @@ Illuminator::render(const SceneShader & shader, const Frustum &) const bodyMesh->drawInstanced(*instanceVAO, static_cast(count)); } } - -void -Illuminator::lights(const SceneShader & shader) const -{ - if (const auto count = instances.size()) { - glDebugScope _ {*instanceVAO}; - if (const auto scount = instancesSpotLight.size()) { - glDebugScope _ {*instancesSpotLightVAO, "Spot lights"}; - shader.spotLightInst.use(); - glBindVertexArray(*instancesSpotLightVAO); - instancesSpotLightVAO->useBuffer(0, instancesSpotLight); - instancesSpotLightVAO->useBuffer(1, instances); - glDrawArraysInstanced(GL_POINTS, 0, static_cast(scount), static_cast(count)); - } - if (const auto pcount = instancesPointLight.size()) { - glDebugScope _ {*instancesPointLightVAO, "Point llights"}; - shader.pointLightInst.use(); - glBindVertexArray(*instancesPointLightVAO); - instancesPointLightVAO->useBuffer(0, instancesPointLight); - instancesPointLightVAO->useBuffer(1, instances); - glDrawArraysInstanced(GL_POINTS, 0, static_cast(pcount), static_cast(count)); - } - - glBindVertexArray(0); - } -} diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index c342bd4..b99a19e 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -2,7 +2,7 @@ #include "assetFactory/asset.h" #include "gfx/gl/instanceVertices.h" -#include "gfx/gl/lights.h" +#include "gfx/models/lights.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -12,19 +12,19 @@ class Location; class Illuminator : public Asset, public Renderable, public StdTypeDefs { Mesh::Ptr bodyMesh; Texture::Ptr texture; - std::shared_ptr instanceVAO, instancesSpotLightVAO, instancesPointLightVAO; - static std::weak_ptr commonInstanceVAO, commonInstancesSpotLightVAO, commonInstancesPointLightVAO; + std::shared_ptr instanceVAO; + static std::weak_ptr commonInstanceVAO; public: [[nodiscard]] std::any createAt(const Location &) const override; - struct SpotLight : Persistence::Persistable, SpotLightVertex, StdTypeDefs { + struct SpotLight : Persistence::Persistable, SpotLightDef, StdTypeDefs { private: friend Persistence::SelectionPtrBase>; bool persist(Persistence::PersistenceStore & store) override; }; - struct PointLight : Persistence::Persistable, PointLightVertex, StdTypeDefs { + struct PointLight : Persistence::Persistable, PointLightDef, StdTypeDefs { private: friend Persistence::SelectionPtrBase>; bool persist(Persistence::PersistenceStore & store) override; @@ -35,18 +35,14 @@ public: }; mutable InstanceVertices instances; - mutable InstanceVertices instancesSpotLight; - mutable InstanceVertices instancesPointLight; void render(const SceneShader &, const Frustum &) const override; - void lights(const SceneShader &) const override; protected: friend Persistence::SelectionPtrBase>; bool persist(Persistence::PersistenceStore & store) override; void postLoad() override; +public: std::vector spotLight; std::vector pointLight; - std::vector::InstanceProxy> spotLightInstances; - std::vector::InstanceProxy> pointLightInstances; }; diff --git a/game/scenary/light.cpp b/game/scenary/light.cpp index 7c38ca2..bd83f04 100644 --- a/game/scenary/light.cpp +++ b/game/scenary/light.cpp @@ -5,4 +5,13 @@ Light::Light(std::shared_ptr type, const Location & position) type {std::move(type)}, instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { + std::ranges::transform(this->type->spotLight, std::back_inserter(spotLightInstances), + [spotLights = Renderable::commonSpotLights.lock(), this](const Illuminator::SpotLight::CPtr & spotLight) { + return spotLights->acquire(*spotLight, instance->location.index); + }); + std::ranges::transform(this->type->pointLight, std::back_inserter(pointLightInstances), + [pointLights = Renderable::commonPointLights.lock(), this]( + const Illuminator::PointLight::CPtr & pointLight) { + return pointLights->acquire(*pointLight, instance->location.index); + }); } diff --git a/game/scenary/light.h b/game/scenary/light.h index afb7e03..b1ea469 100644 --- a/game/scenary/light.h +++ b/game/scenary/light.h @@ -14,6 +14,9 @@ class Light : public WorldObject { { } + std::vector::InstanceProxy> spotLightInstances; + std::vector::InstanceProxy> pointLightInstances; + public: Light(std::shared_ptr type, const Location & position); }; diff --git a/gfx/gl/lights.h b/gfx/gl/lights.h deleted file mode 100644 index 3247e25..0000000 --- a/gfx/gl/lights.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "config/types.h" - -struct LightCommonVertex { - RelativePosition3D position; - RGB colour; - RelativeDistance kq; -}; - -struct SpotLightVertex : LightCommonVertex { - Direction3D direction; - Angle arc; -}; - -struct PointLightVertex : LightCommonVertex { }; diff --git a/gfx/models/lights.cpp b/gfx/models/lights.cpp new file mode 100644 index 0000000..8c0e9e6 --- /dev/null +++ b/gfx/models/lights.cpp @@ -0,0 +1,11 @@ +#include "lights.h" + +SpotLightVertex::SpotLightVertex(const SpotLightDef & light, uint32_t parentObjectIdx) : + SpotLightDef {light}, LightCommonVertex {parentObjectIdx} +{ +} + +PointLightVertex::PointLightVertex(const PointLightDef & light, uint32_t parentObjectIdx) : + PointLightDef {light}, LightCommonVertex {parentObjectIdx} +{ +} diff --git a/gfx/models/lights.h b/gfx/models/lights.h new file mode 100644 index 0000000..586b3ef --- /dev/null +++ b/gfx/models/lights.h @@ -0,0 +1,29 @@ +#pragma once + +#include "config/types.h" + +struct LightCommon { + RelativePosition3D position; + RGB colour; + RelativeDistance kq; +}; + +struct LightCommonVertex { + uint32_t parentObject; +}; + +struct SpotLightDef : LightCommon { + Direction3D direction; + Angle arc; +}; + +struct PointLightDef : LightCommon { }; + +struct SpotLightVertex : SpotLightDef, LightCommonVertex { + SpotLightVertex(const SpotLightDef &, uint32_t); +}; + +struct PointLightVertex : PointLightDef, LightCommonVertex { + PointLightVertex(const PointLightDef &, uint32_t); +}; + diff --git a/gfx/renderable.cpp b/gfx/renderable.cpp index 90035c3..8523118 100644 --- a/gfx/renderable.cpp +++ b/gfx/renderable.cpp @@ -1,10 +1,14 @@ #include "renderable.h" +#include "gfx/gl/sceneShader.h" #include "gl_traits.h" #include "location.h" #include "maths.h" #include "util.h" std::weak_ptr Renderable::commonLocationData; +std::weak_ptr Renderable::commonSpotLights; +std::weak_ptr Renderable::commonPointLights; +std::weak_ptr Renderable::commonInstancesSpotLightVAO, Renderable::commonInstancesPointLightVAO; Renderable::CommonLocation::CommonLocation(Location const & location) : position {location.pos, 0}, rotation {location.rot, 0}, rotationMatrix {location.getRotationTransform()} @@ -23,6 +27,19 @@ Renderable::CommonLocation ::operator=(Location const & location) Renderable::Renderable() { createIfRequired(locationData, commonLocationData); + createIfRequired(spotLights, commonSpotLights); + createIfRequired(pointLights, commonPointLights); + if (createIfRequired(instancesSpotLightVAO, commonInstancesSpotLightVAO)) { + instancesSpotLightVAO->configure() + .addAttribs(0); + } + if (createIfRequired(instancesPointLightVAO, commonInstancesPointLightVAO)) { + instancesPointLightVAO->configure() + .addAttribs(0); + } } GLuint @@ -40,8 +57,31 @@ Renderable::preFrame(const Frustum &, const Frustum &) } void -Renderable::lights(const SceneShader &) const +Renderable::lights(const SceneShader & shader) { + glDebugScope _ {0}; + if (const auto instancesSpotLight = commonSpotLights.lock()) { + if (const auto scount = instancesSpotLight->size()) { + if (const auto instancesSpotLightVAO = commonInstancesSpotLightVAO.lock()) { + glDebugScope _ {*instancesSpotLightVAO, "Spot lights"}; + shader.spotLightInst.use(); + glBindVertexArray(*instancesSpotLightVAO); + instancesSpotLightVAO->useBuffer(0, *instancesSpotLight); + glDrawArrays(GL_POINTS, 0, static_cast(scount)); + } + } + } + if (const auto instancesPointLight = commonPointLights.lock()) { + if (const auto pcount = instancesPointLight->size()) { + if (const auto instancesPointLightVAO = commonInstancesPointLightVAO.lock()) { + glDebugScope _ {*instancesPointLightVAO, "Point lights"}; + shader.pointLightInst.use(); + glBindVertexArray(*instancesPointLightVAO); + instancesPointLightVAO->useBuffer(0, *instancesPointLight); + glDrawArrays(GL_POINTS, 0, static_cast(pcount)); + } + } + } } void diff --git a/gfx/renderable.h b/gfx/renderable.h index b0a42f2..7f4f52e 100644 --- a/gfx/renderable.h +++ b/gfx/renderable.h @@ -1,6 +1,8 @@ #pragma once +#include "gfx/gl/glVertexArray.h" #include "gfx/gl/instanceVertices.h" +#include "gfx/models/lights.h" #include "gl_traits.h" #include #include @@ -20,7 +22,7 @@ public: virtual void preFrame(const Frustum &, const Frustum &); virtual void render(const SceneShader & shader, const Frustum &) const = 0; - virtual void lights(const SceneShader & shader) const; + static void lights(const SceneShader & shader); virtual void shadows(const ShadowMapper & shadowMapper, const Frustum &) const; virtual void updateStencil(const ShadowStenciller & lightDir) const; @@ -37,10 +39,17 @@ public: using CommonLocationData = InstanceVertices; using CommonLocationInstance = CommonLocationData::InstanceProxy; - std::shared_ptr locationData; - static std::weak_ptr commonLocationData; + + using CommonSpotLights = InstanceVertices; + std::shared_ptr spotLights; + static std::weak_ptr commonSpotLights; + using CommonPointLights = InstanceVertices; + std::shared_ptr pointLights; + static std::weak_ptr commonPointLights; + std::shared_ptr instancesSpotLightVAO, instancesPointLightVAO; + static std::weak_ptr commonInstancesSpotLightVAO, commonInstancesPointLightVAO; }; template<> struct gl_traits::InstanceProxy> { diff --git a/test/test-assetFactory.cpp b/test/test-assetFactory.cpp index 90fae9b..b1cd822 100644 --- a/test/test-assetFactory.cpp +++ b/test/test-assetFactory.cpp @@ -51,7 +51,7 @@ namespace { void lights(const SceneShader & shader) const override { - objects.apply(&Renderable::lights, shader); + Renderable::lights(shader); } void diff --git a/test/test-render.cpp b/test/test-render.cpp index b21f440..688275c 100644 --- a/test/test-render.cpp +++ b/test/test-render.cpp @@ -1,3 +1,4 @@ +#include "game/scenary/light.h" #define BOOST_TEST_MODULE test_render #include "testHelpers.h" @@ -65,6 +66,10 @@ namespace { } rail->addLinksBetween({42000, 50000, 1000}, {65000, 50000, 1000}); rail->addLinksBetween({65000, 50000, 1000}, {75000, 45000, 2000}); + gameState->world.create(gameState->assets.at("old-lamp").dynamicCast(), + Location {.pos = {25000, 52000, 1}, .rot = {}}); + gameState->world.create(gameState->assets.at("r-light").dynamicCast(), + Location {.pos = {20000, 57000, 1}, .rot = {}}); } void @@ -94,8 +99,9 @@ namespace { } void - lights(const SceneShader &) const override + lights(const SceneShader & shader) const override { + Renderable::lights(shader); } void diff --git a/ui/gameMainWindow.cpp b/ui/gameMainWindow.cpp index cc81a9b..01b93bb 100644 --- a/ui/gameMainWindow.cpp +++ b/ui/gameMainWindow.cpp @@ -124,9 +124,9 @@ GameMainWindow::environment(const SceneShader &, const SceneRenderer & r) const } void -GameMainWindow::lights(const SceneShader & shader) const +GameMainWindow::lights(const SceneShader & sceneShader) const { - gameState->world.apply(&Renderable::lights, shader); + Renderable::lights(sceneShader); } void -- cgit v1.3 From 74a241680dcb8e543c7e2ab70eb0cfe00d01f22a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 1 Apr 2026 20:31:29 +0100 Subject: Move spot/point light persistence wrappers to assetFactory --- assetFactory/lights.cpp | 14 ++++++++++++++ assetFactory/lights.h | 18 ++++++++++++++++++ game/scenary/illuminator.cpp | 13 ------------- game/scenary/illuminator.h | 14 +------------- game/scenary/light.cpp | 5 ++--- 5 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 assetFactory/lights.cpp create mode 100644 assetFactory/lights.h diff --git a/assetFactory/lights.cpp b/assetFactory/lights.cpp new file mode 100644 index 0000000..ec8e17e --- /dev/null +++ b/assetFactory/lights.cpp @@ -0,0 +1,14 @@ +#include "lights.h" + +bool +SpotLight::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(direction) && STORE_MEMBER(colour) && STORE_MEMBER(kq) + && STORE_MEMBER(arc); +} + +bool +PointLight::persist(Persistence::PersistenceStore & store) +{ + return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(colour) && STORE_MEMBER(kq); +} diff --git a/assetFactory/lights.h b/assetFactory/lights.h new file mode 100644 index 0000000..8657d85 --- /dev/null +++ b/assetFactory/lights.h @@ -0,0 +1,18 @@ +#pragma once + +#include "gfx/models/lights.h" +#include "persistence.h" +#include "stdTypeDefs.h" + +struct SpotLight : Persistence::Persistable, SpotLightDef, StdTypeDefs { +private: + friend Persistence::SelectionPtrBase>; + bool persist(Persistence::PersistenceStore & store) override; +}; + +struct PointLight : Persistence::Persistable, PointLightDef, StdTypeDefs { +private: + friend Persistence::SelectionPtrBase>; + bool persist(Persistence::PersistenceStore & store) override; +}; + diff --git a/game/scenary/illuminator.cpp b/game/scenary/illuminator.cpp index 55791a5..7f0c7c2 100644 --- a/game/scenary/illuminator.cpp +++ b/game/scenary/illuminator.cpp @@ -15,19 +15,6 @@ Illuminator::createAt(const Location & position) const instances.acquire(locationData->acquire(position))); } -bool -Illuminator::SpotLight::persist(Persistence::PersistenceStore & store) -{ - return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(direction) && STORE_MEMBER(colour) && STORE_MEMBER(kq) - && STORE_MEMBER(arc); -} - -bool -Illuminator::PointLight::persist(Persistence::PersistenceStore & store) -{ - return STORE_TYPE && STORE_MEMBER(position) && STORE_MEMBER(colour) && STORE_MEMBER(kq); -} - bool Illuminator::persist(Persistence::PersistenceStore & store) { diff --git a/game/scenary/illuminator.h b/game/scenary/illuminator.h index b99a19e..216b536 100644 --- a/game/scenary/illuminator.h +++ b/game/scenary/illuminator.h @@ -1,8 +1,8 @@ #pragma once #include "assetFactory/asset.h" +#include "assetFactory/lights.h" #include "gfx/gl/instanceVertices.h" -#include "gfx/models/lights.h" #include "gfx/models/texture.h" #include "gfx/renderable.h" @@ -18,18 +18,6 @@ class Illuminator : public Asset, public Renderable, public StdTypeDefs { - private: - friend Persistence::SelectionPtrBase>; - bool persist(Persistence::PersistenceStore & store) override; - }; - - struct PointLight : Persistence::Persistable, PointLightDef, StdTypeDefs { - private: - friend Persistence::SelectionPtrBase>; - bool persist(Persistence::PersistenceStore & store) override; - }; - struct InstanceVertex { CommonLocationInstance location; }; diff --git a/game/scenary/light.cpp b/game/scenary/light.cpp index bd83f04..c51efda 100644 --- a/game/scenary/light.cpp +++ b/game/scenary/light.cpp @@ -6,12 +6,11 @@ Light::Light(std::shared_ptr type, const Location & position) instance {this->type->instances.acquire(Renderable::commonLocationData.lock()->acquire(position))} { std::ranges::transform(this->type->spotLight, std::back_inserter(spotLightInstances), - [spotLights = Renderable::commonSpotLights.lock(), this](const Illuminator::SpotLight::CPtr & spotLight) { + [spotLights = Renderable::commonSpotLights.lock(), this](const auto & spotLight) { return spotLights->acquire(*spotLight, instance->location.index); }); std::ranges::transform(this->type->pointLight, std::back_inserter(pointLightInstances), - [pointLights = Renderable::commonPointLights.lock(), this]( - const Illuminator::PointLight::CPtr & pointLight) { + [pointLights = Renderable::commonPointLights.lock(), this](const auto & pointLight) { return pointLights->acquire(*pointLight, instance->location.index); }); } -- cgit v1.3 From 4b65fcaba60a41f5ac5ce2fecf4ce636d4fe0470 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 3 Apr 2026 11:54:15 +0100 Subject: Fix direction of difference vector calculating railVehicle new position --- game/vehicles/railVehicle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/vehicles/railVehicle.cpp b/game/vehicles/railVehicle.cpp index 5f92066..c11d817 100644 --- a/game/vehicles/railVehicle.cpp +++ b/game/vehicles/railVehicle.cpp @@ -28,7 +28,7 @@ RailVehicle::move(const Train * t, float & trailBy) const auto overhang {(rvClass->length - rvClass->wheelBase) / 2}; const auto & b1Pos = *(get()->front = t->getBogiePosition(t->linkDist, trailBy += overhang)); const auto & b2Pos = *(get()->back = t->getBogiePosition(t->linkDist, trailBy += rvClass->wheelBase)); - const auto diff = glm::normalize(difference(b2Pos.position, b1Pos.position)); + const auto diff = glm::normalize(difference(b1Pos.position, b2Pos.position)); get()->body = Location { .pos = midpoint(b1Pos.position, b2Pos.position), .rot = {vector_pitch(diff), vector_yaw(diff), 0}}; trailBy += 600.F + overhang; -- cgit v1.3