3#include "structure/design_pattern/spk_cached_data.hpp"
4#include "structure/design_pattern/spk_contract_provider.hpp"
5#include "structure/geometry/spk_polygon.hpp"
6#include "structure/opengl/spk_buffer_set_object.hpp"
27 template <
typename TVertex>
45 std::vector<Polygon> _shapes;
46 mutable std::shared_ptr<spk::OpenGL::BufferSetObject> _bufferSet;
47 mutable bool _bufferSetConfigured =
false;
48 mutable bool _needsSynchronization =
true;
57 mutable ContractProvider _onEditionContractProvider;
59 std::pair<std::size_t, std::size_t> _computeTotals()
const
61 std::size_t totalVertices = 0;
62 std::size_t totalIndices = 0;
64 for (
const auto &polygon : _shapes)
66 const std::size_t n = polygon.points.size();
71 totalIndices += (n - 2) * 3;
75 return {totalVertices, totalIndices};
78 void _appendPolygon(
const Polygon &p_polygon, Cache &p_cache)
const
80 const std::size_t vertexCount = p_polygon.points.size();
86 const uint32_t startIndex =
static_cast<uint32_t
>(p_cache.vertices.size());
88 p_cache.vertices.insert(p_cache.vertices.end(), p_polygon.points.begin(), p_polygon.points.end());
90 switch (p_polygon.order)
92 case PolygonOrder::TriangleFanFromFirst:
93 _emitTriangleFanIndices(startIndex, vertexCount, p_cache.indexes);
96 case PolygonOrder::TriangleStrip:
97 _emitTriangleStripIndices(startIndex, vertexCount, p_cache.indexes);
102 static void _emitTriangleFanIndices(uint32_t p_startIndex, std::size_t p_vertexCount, std::vector<uint32_t> &p_indices)
104 for (uint32_t i = 1; i + 1 < p_vertexCount; ++i)
106 p_indices.push_back(p_startIndex);
107 p_indices.push_back(p_startIndex + i);
108 p_indices.push_back(p_startIndex + i + 1);
112 static void _emitTriangleStripIndices(uint32_t p_startIndex, std::size_t p_vertexCount, std::vector<uint32_t> &p_indices)
114 for (uint32_t i = 0; i + 2 < p_vertexCount; ++i)
118 p_indices.push_back(p_startIndex + i);
119 p_indices.push_back(p_startIndex + i + 1);
120 p_indices.push_back(p_startIndex + i + 2);
124 p_indices.push_back(p_startIndex + i + 1);
125 p_indices.push_back(p_startIndex + i);
126 p_indices.push_back(p_startIndex + i + 2);
131 Cache _updateCache()
const
135 const auto [totalVertices, totalIndices] = _computeTotals();
136 cache.vertices.reserve(totalVertices);
137 cache.indexes.reserve(totalIndices);
139 for (
const auto &polygon : _shapes)
141 _appendPolygon(polygon, cache);
147 void _synchronize()
const
149 if (_bufferSet ==
nullptr)
154 if (_bufferSetConfigured ==
false)
156 _configureBufferSet();
157 _bufferSetConfigured =
true;
160 _bufferSet->vbo().setVertices(
vertices());
161 _bufferSet->ibo().setIndexes(
indexes());
164 virtual void _configureBufferSet()
const = 0;
171 _bufferSet(
std::make_shared<spk::OpenGL::BufferSetObject>(spk::OpenGL::BufferObject::Usage::Dynamic)),
173 return _updateCache();
183 _shapes(p_other._shapes),
184 _bufferSet(
std::make_shared<spk::OpenGL::BufferSetObject>(spk::OpenGL::BufferObject::Usage::Dynamic)),
185 _bufferSetConfigured(false),
186 _needsSynchronization(true),
188 return _updateCache();
190 _onEditionContractProvider()
201 if (
this != &p_other)
203 _shapes = p_other._shapes;
204 _bufferSet = std::make_shared<spk::OpenGL::BufferSetObject>(spk::OpenGL::BufferObject::Usage::Dynamic);
205 _bufferSetConfigured =
false;
206 _needsSynchronization =
true;
207 _cache.configure([
this]() {
208 return _updateCache();
210 _onEditionContractProvider = ContractProvider{};
220 _shapes(std::move(p_other._shapes)),
221 _bufferSet(std::move(p_other._bufferSet)),
222 _bufferSetConfigured(p_other._bufferSetConfigured),
223 _needsSynchronization(p_other._needsSynchronization),
225 return _updateCache();
227 _onEditionContractProvider(std::move(p_other._onEditionContractProvider))
239 if (
this != &p_other)
241 _shapes = std::move(p_other._shapes);
242 _bufferSet = std::move(p_other._bufferSet);
243 _bufferSetConfigured = p_other._bufferSetConfigured;
244 _needsSynchronization = p_other._needsSynchronization;
245 _onEditionContractProvider = std::move(p_other._onEditionContractProvider);
246 _cache.configure([
this]() {
247 return _updateCache();
253 virtual ~IMesh() =
default;
262 _needsSynchronization =
true;
263 _onEditionContractProvider.trigger();
272 _shapes.push_back(p_shape);
274 _needsSynchronization =
true;
275 _onEditionContractProvider.trigger();
285 return (std::move(_onEditionContractProvider.subscribe(p_job)));
294 return (_cache.get().vertices);
312 return (_cache.get().indexes);
322 if (p_other._shapes.empty())
327 _shapes.insert(_shapes.end(), p_other._shapes.begin(), p_other._shapes.end());
329 _needsSynchronization =
true;
330 _onEditionContractProvider.trigger();
338 const std::shared_ptr<spk::OpenGL::BufferSetObject> &
bufferSet()
const
348 if (_needsSynchronization ==
false)
354 _needsSynchronization =
false;
Lazily generates and caches a value with optional custom destructor.
Definition spk_cached_data.hpp:26
void release() const
Releases the cached value by invoking destructor if provided.
Definition spk_cached_data.hpp:190
Stores polygon data and exposes GPU-ready vertex/index buffers.
Definition spk_mesh.hpp:29
const std::shared_ptr< spk::OpenGL::BufferSetObject > & bufferSet() const
Returns the underlying buffer set.
Definition spk_mesh.hpp:338
friend IMesh operator+(const IMesh< TVertex > &p_lhs, const IMesh< TVertex > &p_rhs)
Returns a mesh that combines both operands.
Definition spk_mesh.hpp:375
EditionContract subscribeToEdition(const EditionJob &p_job) const
Subscribes to mesh edition notifications.
Definition spk_mesh.hpp:283
const std::vector< Polygon > & polygons() const
Returns the stored polygons.
Definition spk_mesh.hpp:301
IMesh fuze(const IMesh &p_other) const
Returns a new mesh by concatenating another mesh.
Definition spk_mesh.hpp:362
IMesh()
Builds an empty mesh with a dynamic buffer set.
Definition spk_mesh.hpp:170
IMesh & operator=(const IMesh &p_other)
Assigns polygon data from another mesh.
Definition spk_mesh.hpp:199
void append(const Polygon &p_shape)
Appends a polygon and notifies subscribers.
Definition spk_mesh.hpp:270
ContractProvider::Job EditionJob
Definition spk_mesh.hpp:42
void synchronize() const
Updates GPU buffers when mesh data has changed.
Definition spk_mesh.hpp:346
ContractProvider::Contract EditionContract
Definition spk_mesh.hpp:38
IPolygon< spk::Vector2 > Polygon
Definition spk_mesh.hpp:34
IMesh & operator=(IMesh &&p_other) noexcept
Move-assigns polygon data from another mesh.
Definition spk_mesh.hpp:237
const std::vector< spk::Vector2 > & vertices() const
Definition spk_mesh.hpp:292
IMesh(const IMesh &p_other)
Copies polygon data into a new mesh instance.
Definition spk_mesh.hpp:182
const std::vector< uint32_t > & indexes() const
Definition spk_mesh.hpp:310
void clear()
Clears all polygons and notifies subscribers.
Definition spk_mesh.hpp:258
IMesh & operator+=(const IMesh &p_other)
Appends polygons from another mesh and notifies subscribers.
Definition spk_mesh.hpp:320
IMesh(IMesh &&p_other) noexcept
Moves polygon data from another mesh.
Definition spk_mesh.hpp:219
typename Contract::Job Job
Definition spk_contract_provider.hpp:267
Stores vertex points and winding order for polygon triangulation.
Definition spk_polygon.hpp:24