Cogs.Core
Mesh.cpp
1#include "Mesh.h"
2
3#include "Foundation/Logging/Logger.h"
4
5#include "MeshManager.h"
6#include "Buffer.h"
7
8namespace {
10}
11
13{
14 streamIndexes.fill(NoStream);
15}
16
17void Cogs::Core::Mesh::clearStream(DataStream & stream)
18{
19 stream.buffer->clear();
20 stream.numElements = 0;
21
22 streamsUpdated |= toFlag(stream.type);
23
24 setMeshFlag(MeshFlags::StreamsChanged);
25}
26
28{
29 submeshCount = 0;
30 instanceCount = 0;
31 count = 0;
32
33 unsetMeshFlag(MeshFlags::Indexed);
34 unsetMeshFlag(MeshFlags::Instanced);
35
36 for (auto & si : streamIndexes) {
37 if (si != NoStream) {
38 clearStream(streams[si]);
39 }
40 }
41
42 boundingBox = Geometry::BoundingBox();
43 unsetMeshFlag(MeshFlags::BoundingBoxSet);
44}
45
47 VertexFormatHandle format,
48 const size_t start,
49 const size_t count,
50 const size_t elementSize,
51 bool resize)
52{
53 auto & stream = getStream(type);
54 stream.format = format;
55
56 //assert(elementSize == getSize(*format) && "Vertex format and element size must match.");
57
58 return mapStream(type, start, count, elementSize, resize);
59}
60
62 const size_t start,
63 const size_t count,
64 const size_t stride,
65 bool resize)
66{
67 auto & stream = getStream(type);
68
69 const size_t neededCapacity = size_t(start + count) * stride;
70
71 if (stream.size() < neededCapacity || (resize && stream.size() != neededCapacity)) {
72 stream.buffer->resize(neededCapacity);
73 }
74
75 stream.numElements = static_cast<uint32_t>(start + count);
76 stream.stride = static_cast<uint32_t>(stride);
77
78 if (type == VertexDataType::Positions && !isIndexed()) {
79 setCount(start + count);
80 }
81
82 return static_cast<uint8_t *>(stream.data()) + (start * stride);
83}
84
86{
87 assert(streams.size() < MaxStreams && "Vertex stream limit reached.");
88
89 if (streamIndexes[dataType] == NoStream) {
90 streamIndexes[dataType] = static_cast<int8_t>(streams.size());
91
92 auto & stream = streams.emplace_back();
93 stream.type = dataType;
94
95 //TODO: Supply projected size & bind flags to buffer getter to facilitate e.g reuse of existing buffer
96 // resources with same configuration.
97 stream.buffer = getManager()->createBuffer();
98
99 if (dataType < VertexDataType::LastVertexType) {
101 } else if (dataType == VertexDataType::Indexes) {
103 }
104
105 return stream;
106 }
107
108 return streams[streamIndexes[dataType]];
109}
110
112{
113 assert(streamIndexes[dataType] != NoStream && "Invalid stream type.");
114
115 return streams[streamIndexes[dataType]];
116}
117
118const Cogs::Core::DataStream * Cogs::Core::Mesh::getAllocatedStream(const VertexDataType::EVertexDataType dataType) const
119{
120 if (streamIndexes[dataType] != NoStream) {
121 return &streams[streamIndexes[dataType]];
122 } else {
123 return nullptr;
124 }
125}
126
127Cogs::Core::DataStream * Cogs::Core::Mesh::getAllocatedStream(const VertexDataType::EVertexDataType dataType)
128{
129 if (streamIndexes[dataType] != NoStream) {
130 return &streams[streamIndexes[dataType]];
131 } else {
132 return nullptr;
133 }
134}
135
137{
138 auto vec3Ref = getSemanticStream(ElementSemantic::Position, DataFormat::X32Y32Z32_FLOAT);
139 if (vec3Ref.ptr) return vec3Ref;
140
141 return getSemanticStream(ElementSemantic::Position, DataFormat::X32Y32Z32W32_FLOAT);
142}
143
145{
146 for (auto & stream : streams) {
147 if (!stream.format) continue;
148
149 auto vertexFormat = Cogs::VertexFormats::getVertexFormat(stream.format);
150
151 auto & elements = vertexFormat->elements;
152
153 auto found = std::find_if(elements.begin(), elements.end(), [semantic, format](const VertexElement & element) {
154 return element.semantic == semantic && element.format == format;
155 });
156
157 if (found != elements.end()) {
158 auto offset = (*found).offset;
159
160 return { static_cast<uint8_t*>(stream.data()) + offset, stream.numElements, Cogs::getSize(*vertexFormat) };
161 }
162 }
163
164 return StreamReference{ nullptr, 0, 0 };
165}
166
167Cogs::Core::MeshManager* Cogs::Core::Mesh::getManager() const
168{
169 return static_cast<MeshManager *>(getOwner());
170}
171
172std::span<uint32_t> Cogs::Core::Mesh::mapPoseIndexes(uint32_t count)
173{
174 void* poseData = mapStream(VertexDataType::PoseIndexes, 0, count, sizeof(uint32_t), true);
175 return std::span(static_cast<uint32_t *>(poseData), count);
176}
177
178std::span<const uint32_t> Cogs::Core::Mesh::getPoseIndexes() const
179{
180 auto stream = getAllocatedStream(VertexDataType::PoseIndexes);
181
182 if (stream) {
183 return std::span(static_cast<const uint32_t *>(stream->data()), stream->numElements);
184 } else {
185 return {};
186 }
187}
188
189void Cogs::Core::Mesh::addSubMesh(std::span<uint32_t> collection, PrimitiveType::EPrimitiveType primitiveType)
190{
191 assert(submeshCount != uint16_t{ 0xffff });
192 uint32_t indexCount = static_cast<uint32_t>(getIndexes().size());
193 if (submeshCount == 0 && isIndexed() && !getIndexes().empty()) {
194 // Inject current geometry as submesh
195 auto subMeshes = mapSubMeshes(submeshCount + 1);
196 auto & indexStream = getStream(VertexDataType::Indexes);
197 subMeshes[0] = { 0, indexStream.numElements, this->primitiveType };
198 indexCount = indexStream.numElements;
199 }
200
201 auto subMeshes = mapSubMeshes(submeshCount + 1);
202
203 subMeshes[submeshCount - 1] = { indexCount, static_cast<uint32_t>(collection.size()), primitiveType };
204
205 auto indexData = mapStream(VertexDataType::Indexes, 0, indexCount + collection.size(), sizeof(uint32_t));
206
207 memcpy(indexData + indexCount * sizeof(uint32_t), collection.data(), sizeof(uint32_t) * collection.size());
208
209 count = static_cast<uint32_t>(indexCount + collection.size());
210
211 setMeshFlag(MeshFlags::Indexed);
212 setMeshFlag(MeshFlags::IndexesChanged);
213}
214
215void Cogs::Core::Mesh::setBufferStream(VertexDataType::EVertexDataType type,
217 VertexFormatHandle format,
218 uint32_t numElements,
219 uint32_t offset,
220 uint32_t stride)
221{
222
223 if (streamIndexes[type] == NoStream) {
224 streams.emplace_back();
225 streamIndexes[type] = (uint8_t)streams.size() - 1;
226 }
227
228 auto & stream = streams[streamIndexes[type]];
229
230 stream.buffer = buffer;
231 stream.format = format;
232 stream.numElements = numElements;
233 stream.offset = offset;
234 stream.stride = stride;
235 stream.type = type;
236
237 streamsUpdated |= toFlag(type);
238 setMeshFlag(MeshFlags::StreamsChanged);
239}
240
241std::span<Cogs::Core::SubMesh> Cogs::Core::Mesh::mapSubMeshes(uint32_t count)
242{
243 assert(count < uint16_t{ 0xffff });
244 void* data = mapStream(VertexDataType::SubMeshes, 0, count, sizeof(SubMesh));
245 submeshCount = (uint16_t)count;
246
247 return std::span(static_cast<SubMesh *>(data), count);
248}
249
250std::span<Cogs::Core::SubMesh> Cogs::Core::Mesh::getSubMeshes()
251{
252 if (submeshCount) {
253 auto & stream = getStream(VertexDataType::SubMeshes);
254 return std::span(static_cast<SubMesh *>(stream.data()), stream.numElements);
255 } else {
256 return {};
257 }
258}
259
260std::span<const uint32_t> Cogs::Core::Mesh::getIndexes() const
261{
262 if (!isIndexed()) return {};
263
264 auto & indexStream = getStream(VertexDataType::Indexes);
265
266 if (indexStream.stride != sizeof(uint32_t)) return {};
267
268 return std::span(static_cast<const uint32_t *>(indexStream.data()), indexStream.numElements);
269}
270
271std::span<const uint16_t> Cogs::Core::Mesh::getIndexesU16() const
272{
273 if (!hasIndexesU16()) return {};
274
275 auto & indexStream = getStream(VertexDataType::Indexes);
276
277 if (indexStream.stride != sizeof(uint16_t)) return {};
278
279 return std::span(static_cast<const uint16_t *>(indexStream.data()), indexStream.numElements);
280}
281
282bool Cogs::Core::Mesh::hasIndexesU16() const
283{
284 return isIndexed() && getStream(VertexDataType::Indexes).stride == sizeof(uint16_t);
285}
286
287void* Cogs::Core::DataStream::data() { return buffer ? static_cast<uint8_t*>(buffer->data()) + offset : nullptr; }
288const void* Cogs::Core::DataStream::data() const { return buffer ? static_cast<const uint8_t*>(buffer->data()) + offset : nullptr; }
289size_t Cogs::Core::DataStream::size() const { return buffer ? buffer->size() : 0; }
290
291
292Cogs::Core::MeshStreamsLayout Cogs::Core::Mesh::getStreamsLayout() const
293{
294 MeshStreamsLayout streamsLayout;
295 streamsLayout.numStreams = 0;
296 for (size_t i = 0; i < VertexDataType::LastVertexType; ++i) {
298 if (hasStream(type)) {
299 const DataStream& stream = getStream(type);
300 streamsLayout.vertexFormats[streamsLayout.numStreams++] = stream.format;
301 }
302 }
303 streamsLayout.updateHash();
304 return streamsLayout;
305}
Mesh manager handling the creation, processing and lifetime of Mesh resources.
Definition: MeshManager.h:18
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
ElementSemantic
Element semantics used to map data to the shader stage.
Definition: VertexFormat.h:14
@ Position
Position semantic.
@ VertexBuffer
Buffer can be bound as vertex buffer.
Definition: Buffer.h:40
@ IndexBuffer
Buffer can be bound as index buffer.
Definition: Buffer.h:42
void setBindFlags(uint16_t flags)
Set the bind flags for the buffer determining how the buffer data may be uploaded to GPU.
Definition: Buffer.h:89
void resize(size_t size)
Resize the buffer to accomodate the given number of bytes.
Definition: Buffer.cpp:17
size_t size() const
Size of the buffer in bytes.
Definition: Buffer.h:62
void clear()
Clear the buffer contents. Note that the buffer may retain reserved storage after clearing.
Definition: Buffer.h:86
void * data()
Get a pointer to the buffer data.
Definition: Buffer.h:74
Contains a stream of data used by Mesh resources.
Definition: Mesh.h:80
uint32_t numElements
Number of elements of the type given by format contained in data.
Definition: Mesh.h:108
uint32_t offset
Byte offset from the start of the buffer.
Definition: Mesh.h:102
VertexFormatHandle format
A pointer to the format describing the contents of the byte buffer.
Definition: Mesh.h:99
VertexDataType::EVertexDataType type
Type index used to index streams in a Mesh resource.
Definition: Mesh.h:111
uint32_t stride
Element stride.
Definition: Mesh.h:105
Cogs::Core::ResourceBufferHandle buffer
Data buffer.
Definition: Mesh.h:96
@ Instanced
Mesh contains instance data.
Definition: Mesh.h:70
@ StreamsChanged
One or more of the data streams in the mesh changed.
Definition: Mesh.h:59
@ IndexesChanged
The index data of the mesh changed.
Definition: Mesh.h:61
@ Indexed
The mesh should be drawn indexed, using index data to order the triangle vertexes.
Definition: Mesh.h:65
@ BoundingBoxSet
Custom bounding box set, no automatic calculation of bounds should be performed.
Definition: Mesh.h:67
Utility structure containing reference to a data stream in a mesh.
Definition: Mesh.h:960
uint8_t * mapStream(const VertexDataType::EVertexDataType type, VertexFormatHandle format, const size_t start, const size_t count, const size_t elementSize, bool resize=false)
Raw stream mapping method.
Definition: Mesh.cpp:46
StreamReference getPositionStream()
Get the data of the stream containing positions.
Definition: Mesh.cpp:136
StreamReference getSemanticStream(ElementSemantic semantic, DataFormat format)
Get the data of the stream containing data with the given semantic, format and minimum element size.
Definition: Mesh.cpp:144
void clear()
Clear all data from the Mesh, returning it to its initial non-indexed state with no streams and no su...
Definition: Mesh.cpp:27
static constexpr int NoStream
Used to indicate no stream.
Definition: Mesh.h:308
void addSubMesh(std::span< uint32_t > collection, PrimitiveType::EPrimitiveType primitiveType)
Add a sub-mesh to the Mesh.
Definition: Mesh.cpp:189
DataStream & getStream(const VertexDataType::EVertexDataType dataType)
Get the stream corresponding to the given dataType.
Definition: Mesh.cpp:85
Mesh()
Construct a default mesh instance.
Definition: Mesh.cpp:12
EVertexDataType
Contains data types.
Definition: Mesh.h:26
EPrimitiveType
Primitive type enumeration.
Definition: Common.h:114
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38