summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/scenary/foliage.cpp4
-rw-r--r--game/vehicles/railVehicleClass.cpp14
-rw-r--r--gfx/gl/instanceVertices.h124
-rw-r--r--lib/glContainer.h1
-rw-r--r--test/test-instancing.cpp65
5 files changed, 68 insertions, 140 deletions
diff --git a/game/scenary/foliage.cpp b/game/scenary/foliage.cpp
index 9304842..702a52c 100644
--- a/game/scenary/foliage.cpp
+++ b/game/scenary/foliage.cpp
@@ -21,7 +21,7 @@ Foliage::postLoad()
void
Foliage::render(const SceneShader & shader) const
{
- if (const auto count = instances.count()) {
+ if (const auto count = instances.size()) {
shader.basicInst.use();
if (texture) {
texture->bind();
@@ -33,7 +33,7 @@ Foliage::render(const SceneShader & shader) const
void
Foliage::shadows(const ShadowMapper & mapper) const
{
- if (const auto count = instances.count()) {
+ if (const auto count = instances.size()) {
mapper.dynamicPointInst.use();
bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
}
diff --git a/game/vehicles/railVehicleClass.cpp b/game/vehicles/railVehicleClass.cpp
index 64a21be..148081f 100644
--- a/game/vehicles/railVehicleClass.cpp
+++ b/game/vehicles/railVehicleClass.cpp
@@ -46,26 +46,24 @@ RailVehicleClass::postLoad()
void
RailVehicleClass::render(const SceneShader & shader) const
{
- if (const auto count = instancesBody.count()) {
+ if (const auto count = instancesBody.size()) {
if (texture) {
texture->bind();
}
shader.basicInst.use();
bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
- bogies.front()->DrawInstanced(
- instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().count()));
- bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().count()));
+ bogies.front()->DrawInstanced(instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().size()));
+ bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().size()));
}
}
void
RailVehicleClass::shadows(const ShadowMapper & mapper) const
{
- if (const auto count = instancesBody.count()) {
+ if (const auto count = instancesBody.size()) {
mapper.dynamicPointInst.use();
bodyMesh->DrawInstanced(instanceVAO, static_cast<GLsizei>(count));
- bogies.front()->DrawInstanced(
- instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().count()));
- bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().count()));
+ bogies.front()->DrawInstanced(instancesBogiesVAO.front(), static_cast<GLsizei>(instancesBogies.front().size()));
+ bogies.back()->DrawInstanced(instancesBogiesVAO.back(), static_cast<GLsizei>(instancesBogies.back().size()));
}
}
diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h
index 9df6e12..7b0341b 100644
--- a/gfx/gl/instanceVertices.h
+++ b/gfx/gl/instanceVertices.h
@@ -1,20 +1,15 @@
#pragma once
-#include "glArrays.h"
+#include "glContainer.h"
+#include "pack.h"
#include <cassert>
-#include <iterator>
-#include <span>
#include <special_members.h>
#include <utility>
-#include <vector>
-template<typename T> class InstanceVertices {
-public:
- InstanceVertices(size_t initialSize = 16)
- {
- allocBuffer(initialSize);
- }
+template<typename T> class InstanceVertices : protected glContainer<T> {
+ using base = glContainer<T>;
+public:
class [[nodiscard]] InstanceProxy {
public:
InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { }
@@ -44,27 +39,27 @@ public:
T &
operator=(U && v)
{
- return instances->at(index) = std::forward<U>(v);
+ return instances->lookup(index) = std::forward<U>(v);
}
[[nodiscard]]
operator T &()
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] operator const T &() const
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] T *
get()
{
- return &instances->at(index);
+ return &instances->lookup(index);
}
[[nodiscard]] const T *
get() const
{
- return &instances->at(index);
+ return &instances->lookup(index);
}
[[nodiscard]] T *
operator->()
@@ -79,12 +74,12 @@ public:
[[nodiscard]] T &
operator*()
{
- return instances->at(index);
+ return instances->lookup(index);
}
[[nodiscard]] const T &
operator*() const
{
- return instances->at(index);
+ return instances->lookup(index);
}
private:
@@ -96,33 +91,25 @@ public:
[[nodiscard]] InstanceProxy
acquire(Params &&... params)
{
- map();
if (!unused.empty()) {
auto idx = unused.back();
unused.pop_back();
- index[idx] = next++;
- new (&at(idx)) T(std::forward<Params>(params)...);
+ index[idx] = base::size();
+ base::emplace_back(std::forward<Params>(params)...);
return InstanceProxy {this, idx};
}
- if (next >= capacity) {
- resize(capacity * 2);
- }
- index.emplace_back(next++);
- new (data + index.back()) T(std::forward<Params>(params)...);
+ index.emplace_back(base::size());
+ base::emplace_back(std::forward<Params>(params)...);
return InstanceProxy {this, index.size() - 1};
}
- [[nodiscard]] const auto &
- bufferName() const
- {
- return buffer;
- }
+ using base::bufferName;
[[nodiscard]] auto
- count() const
+ size() const
{
- unmap();
- return next;
+ base::unmap();
+ return base::size();
}
protected:
@@ -131,16 +118,13 @@ protected:
void
release(const size_t pidx)
{
- // Destroy p's object
- at(pidx).~T();
- if (--next != index[pidx]) {
- // Move last object into p's slot
- new (&at(pidx)) T {std::move(data[next])};
- (data[next]).~T();
- *std::find_if(index.begin(), index.end(), [this](const auto & i) {
- return i == next && !std::binary_search(unused.begin(), unused.end(), &i - index.data());
+ if (base::size() - 1 != index[pidx]) {
+ lookup(pidx) = std::move(base::back());
+ *std::find_if(index.begin(), index.end(), [this, old = base::size() - 1](const auto & i) {
+ return i == old && !std::binary_search(unused.begin(), unused.end(), &i - index.data());
}) = index[pidx];
}
+ base::pop_back();
if (pidx == index.size() - 1) {
index.pop_back();
}
@@ -150,64 +134,14 @@ protected:
}
}
- void
- allocBuffer(std::size_t newCapacity)
- {
- glBindBuffer(GL_ARRAY_BUFFER, buffer);
- glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- capacity = newCapacity;
- data = nullptr;
- }
-
- void
- resize(size_t newCapacity)
- {
- const auto maintain = std::min(newCapacity, capacity);
- std::vector<T> existing;
- const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain);
- existing.reserve(maintain);
- map();
- std::move(data, data + maintain, std::back_inserter(existing));
- allocBuffer(newCapacity);
- map();
- std::move(existing.begin(), existing.begin() + maintaind, data);
- capacity = newCapacity;
- }
-
[[nodiscard]] T &
- at(size_t pindex)
- {
- map();
- return data[index[pindex]];
- }
-
- void
- map() const
+ lookup(size_t pindex)
{
- if (!data) {
- data = static_cast<T *>(glMapNamedBuffer(buffer, GL_READ_WRITE));
- assert(data);
- }
- }
-
- void
- unmap() const
- {
- if (data) {
- glUnmapNamedBuffer(buffer);
- data = nullptr;
- }
+ return base::data()[index[pindex]];
}
- glBuffer buffer;
- mutable T * data {};
- // Size of buffer
- std::size_t capacity {};
- // # used of capacity
- std::size_t next {};
- // Index into buffer given to nth proxy
+ // Index into buffer given to nth proxy
std::vector<size_t> index;
- // List of free spaces in index
+ // List of free spaces in index
std::vector<size_t> unused;
};
diff --git a/lib/glContainer.h b/lib/glContainer.h
index 94ba118..993170e 100644
--- a/lib/glContainer.h
+++ b/lib/glContainer.h
@@ -1,6 +1,7 @@
#pragma once
#include "glArrays.h"
+#include <cassert>
#include <stdexcept>
#include <utility>
#include <vector>
diff --git a/test/test-instancing.cpp b/test/test-instancing.cpp
index 8745484..7d8ea55 100644
--- a/test/test-instancing.cpp
+++ b/test/test-instancing.cpp
@@ -17,14 +17,8 @@ BOOST_FIXTURE_TEST_SUITE(i, InstanceVertices<int>)
BOOST_AUTO_TEST_CASE(createDestroy)
{
- BOOST_CHECK(!data);
- map();
- BOOST_REQUIRE(data);
- BOOST_CHECK_EQUAL(0, next);
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
- unmap();
- BOOST_CHECK(!data);
}
BOOST_AUTO_TEST_CASE(acquireRelease)
@@ -32,12 +26,12 @@ BOOST_AUTO_TEST_CASE(acquireRelease)
{
auto proxy = acquire();
*proxy = 20;
- BOOST_CHECK_EQUAL(1, next);
+ BOOST_CHECK_EQUAL(1, size());
BOOST_REQUIRE_EQUAL(1, index.size());
BOOST_CHECK_EQUAL(0, index.front());
BOOST_CHECK(unused.empty());
}
- BOOST_CHECK_EQUAL(0, next);
+ BOOST_CHECK_EQUAL(0, size());
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
}
@@ -47,13 +41,13 @@ BOOST_AUTO_TEST_CASE(acquireReleaseMove)
{
auto proxy1 = acquire();
*proxy1 = 20;
- BOOST_CHECK_EQUAL(1, next);
+ BOOST_CHECK_EQUAL(1, size());
auto proxy2 = std::move(proxy1);
proxy2 = 40;
- BOOST_CHECK_EQUAL(1, next);
- BOOST_CHECK_EQUAL(data[0], 40);
+ BOOST_CHECK_EQUAL(1, size());
+ BOOST_CHECK_EQUAL(at(0), 40);
}
- BOOST_CHECK_EQUAL(0, next);
+ BOOST_CHECK_EQUAL(0, size());
BOOST_CHECK(unused.empty());
BOOST_CHECK(index.empty());
}
@@ -62,13 +56,13 @@ BOOST_AUTO_TEST_CASE(autoMapUnmap)
{
{
auto proxy = acquire();
- BOOST_CHECK(data);
+ BOOST_CHECK(data_);
std::ignore = bufferName();
- BOOST_CHECK(data);
- BOOST_CHECK_EQUAL(1, count());
- BOOST_CHECK(!data);
+ BOOST_CHECK(data_);
+ BOOST_CHECK_EQUAL(1, size());
+ BOOST_CHECK(!data_);
}
- BOOST_CHECK_EQUAL(0, count());
+ BOOST_CHECK_EQUAL(0, size());
}
BOOST_AUTO_TEST_CASE(initialize)
@@ -89,7 +83,7 @@ BOOST_AUTO_TEST_CASE(resize)
proxies.push_back(acquire(n));
expected.emplace_back(n);
}
- BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), data, data + COUNT);
+ BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), data(), data() + COUNT);
BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), proxies.begin(), proxies.end());
}
@@ -100,11 +94,11 @@ BOOST_AUTO_TEST_CASE(shuffle)
BOOST_CHECK_EQUAL(1, proxies.emplace_back(acquire(1)));
BOOST_CHECK_EQUAL(2, proxies.emplace_back(acquire(2)));
BOOST_CHECK_EQUAL(3, proxies.emplace_back(acquire(3)));
- BOOST_CHECK_EQUAL(4, next);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[2].get());
- BOOST_CHECK_EQUAL(data + 3, proxies[3].get());
+ BOOST_CHECK_EQUAL(4, size());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[2].get());
+ BOOST_CHECK_EQUAL(at(3), *proxies[3].get());
BOOST_CHECK(unused.empty());
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_CHECK_EQUAL(0, index[0]);
@@ -113,28 +107,29 @@ BOOST_AUTO_TEST_CASE(shuffle)
BOOST_CHECK_EQUAL(3, index[3]);
// Remove 1, 3 moves to [1]
proxies.erase(proxies.begin() + 1);
+ BOOST_REQUIRE_EQUAL(3, proxies.size());
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(1, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[2].get());
- // Remove 1, 2 moves to [1]
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[2].get());
+ // Remove 1, 2 moves to [1]
proxies.erase(proxies.begin() + 1);
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(2, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
BOOST_CHECK_EQUAL(2, unused[1]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
// Add new, takes 2 at [2]
BOOST_CHECK_EQUAL(4, proxies.emplace_back(acquire(4)));
BOOST_REQUIRE_EQUAL(4, index.size());
BOOST_REQUIRE_EQUAL(1, unused.size());
BOOST_CHECK_EQUAL(1, unused[0]);
- BOOST_CHECK_EQUAL(data + 0, proxies[0].get());
- BOOST_CHECK_EQUAL(data + 1, proxies[1].get());
- BOOST_CHECK_EQUAL(data + 2, proxies[2].get());
+ BOOST_CHECK_EQUAL(at(0), *proxies[0].get());
+ BOOST_CHECK_EQUAL(at(1), *proxies[1].get());
+ BOOST_CHECK_EQUAL(at(2), *proxies[2].get());
}
BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
@@ -158,7 +153,7 @@ BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
break;
}
- BOOST_REQUIRE_EQUAL(next, proxies.size());
+ BOOST_REQUIRE_EQUAL(size(), proxies.size());
for (const auto & [n, p] : proxies) {
BOOST_REQUIRE_EQUAL(n, p);
}
@@ -169,10 +164,10 @@ BOOST_DATA_TEST_CASE(shuffle_random, boost::unit_test::data::xrange(0, 10), x)
}
}
BOOST_TEST_CONTEXT(index) {
- BOOST_REQUIRE_EQUAL(iused.size(), next);
+ BOOST_REQUIRE_EQUAL(iused.size(), size());
if (!iused.empty()) {
BOOST_REQUIRE_EQUAL(*iused.begin(), 0);
- BOOST_REQUIRE_EQUAL(*iused.rbegin(), next - 1);
+ BOOST_REQUIRE_EQUAL(*iused.rbegin(), size() - 1);
}
}
}