Cogs.Core
ShapeSystem.cpp
1#include "ShapeSystem.h"
2
3#include "Context.h"
4
5#include "Components/Core/MeshComponent.h"
6#include "Components/Appearance/MaterialComponent.h"
7
8#include "Foundation/Logging/Logger.h"
9
10#include "Resources/Mesh.h"
11#include "Resources/MeshManager.h"
12#include "Resources/ModelManager.h"
13
14#include "Services/Variables.h"
15
16#include "Math/IndexConversion.h"
17#include "Math/NormalGenerator.h"
18
19#include "Foundation/Geometry/Glm.hpp"
20
21#include "Rendering/ICapabilities.h"
22
23namespace {
24 using namespace Cogs::Core;
25
26 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ShapeSystem");
27
28 const Cogs::StringView instancedLinesSettingName = "shapeSystem.instancedLine";
29
30 bool buildInstancedLineList(Mesh* mesh, MaterialComponent* materialComponent, const ShapeComponent& shapeComponent)
31 {
32 size_t vn = shapeComponent.indexes.empty() ? shapeComponent.positions.size() : shapeComponent.indexes.size();
33
34 size_t stride = 0;
35 size_t instanceCount = 0;
36 switch (shapeComponent.primitiveType) {
37
38 case ShapePrimitiveType::LineList:
39 stride = 2;
40 instanceCount = vn / 2;
41 break;
42
43 case ShapePrimitiveType::LineStrip:
44 stride = 1;
45 instanceCount = std::max(size_t(1), vn) - 1;
46 break;
47
48 default:
49 return false;
50 }
51
52 {
53 Cogs::VertexElement format[] = {
55 .offset = 0,
56 .format = Cogs::DataFormat::X32Y32Z32_FLOAT,
58 .semanticIndex = 0,
60 .instanceStep = 1
61 },
63 .offset = 3 * sizeof(float),
64 .format = Cogs::DataFormat::X32Y32Z32_FLOAT,
66 .semanticIndex = 1,
68 .instanceStep = 1
69 }
70 };
71 Cogs::VertexFormatHandle formatHandle = Cogs::VertexFormats::createVertexFormat(format, std::size(format));
72
73
74 glm::vec3 hi(-std::numeric_limits<float>::max());
75 glm::vec3 lo(std::numeric_limits<float>::max());
76 if (glm::vec3* ptr = (glm::vec3*)mesh->mapStream(VertexDataType::Positions, formatHandle, 0, (vn + stride - 1) / stride, stride * sizeof(glm::vec3), true); ptr != nullptr) {
77 if (shapeComponent.indexes.empty()) {
78 for (size_t i = 0; i < vn; i++) {
79 const glm::vec3 p = shapeComponent.positions[i];
80 hi = glm::max(hi, p);
81 lo = glm::min(lo, p);
82 ptr[i] = p;
83 }
84 }
85 else {
86 for (size_t i = 0; i < vn; i++) {
87 const glm::vec3 p = shapeComponent.positions[shapeComponent.indexes[i]];
88 hi = glm::max(hi, p);
89 lo = glm::min(lo, p);
90 ptr[i] = p;
91 }
92 }
93 mesh->unmap(VertexDataType::Positions);
94 mesh->setBounds(Cogs::Geometry::BoundingBox{ lo, hi });
95 }
96 }
97
98 mesh->primitiveType = Cogs::PrimitiveType::TriangleStrip;
99 mesh->setCount(4);
100 mesh->setInstanceCount(instanceCount);
102
103 materialComponent->primitiveType = Cogs::PrimitiveType::LineStrip;
104 materialComponent->instancedLine = true;
105 materialComponent->setChanged();
106
107 return true;
108 }
109
110
111}
112
113using namespace Cogs::Geometry;
114
115
117{
119 supportsInstancing = context->renderer->getDevice()->getCapabilities()->supportsInstancing();
120}
121
123{
124 bool forceUpdate = false;
125 if (supportsInstancing) {
126 Variable* instancedLinesVar = context->variables->get(instancedLinesSettingName);
127 if (instancedLinesVar->isEmpty()) {
128 instancedLinesVar->setBool(false);
129 forceUpdate = true;
130 }
131 instancedLines = instancedLinesVar->getBool();
132 }
133
134 for (const auto & shapeComponent : pool) {
135 MeshComponent* meshComponent = shapeComponent.getComponent<MeshComponent>(); assert(meshComponent);
136 MaterialComponent* materialComponent = shapeComponent.getComponent<MaterialComponent>();
137
138 if (forceUpdate || shapeComponent.hasChanged()) {
139 if (!HandleIsValid(meshComponent->meshHandle)) {
140 meshComponent->meshHandle = context->meshManager->create();
141 context->meshManager->get(meshComponent->meshHandle)->setName(shapeComponent.getContainer()->getName());
142 }
143
144 auto mesh = context->meshManager->get(meshComponent->meshHandle);
145
146 mesh->clear();
147
148 if (!shapeComponent.positions.size()) {
149 continue;
150 }
151
152 if (instancedLines) {
153 switch (shapeComponent.primitiveType) {
154
155 case ShapePrimitiveType::LineList:
156 case ShapePrimitiveType::LineStrip:
157 if (buildInstancedLineList(mesh, materialComponent, shapeComponent)) {
158 continue;
159 }
160 break;
161
162 default:
163 break;
164 }
165 }
166
167 if (materialComponent) {
168 materialComponent->instancedLine = false;
169 }
170 switch (shapeComponent.primitiveType) {
171 case ShapePrimitiveType::Default:
172 {
173 if (shapeComponent.positions.size() == shapeComponent.normals.size()) {
174 mesh->setPositions(shapeComponent.positions);
175
176 if (shapeComponent.normals.size()) {
177 mesh->setNormals(shapeComponent.normals);
178 }
179
180 if (shapeComponent.texCoords.size()) {
181 mesh->setTexCoords(shapeComponent.texCoords);
182 }
183
184 reindex(shapeComponent.indexes, mesh, false);
185 } else if (shapeComponent.positions.size() && !shapeComponent.normals.size()) {
186 const auto & idx = shapeComponent.indexes;
187
188 bool quads = idx.size() >= 5 && (idx.size() % 5) == 0 && idx[4] == -1;
189
190 std::vector<glm::vec3> positions;
191 std::vector<glm::vec3> normals;
192 std::vector<int32_t> indexes;
193 std::vector<glm::vec2> texCoords;
194
195 Cogs::Geometry::generateFacetNormals(
196 shapeComponent.positions.data(),
197 shapeComponent.positions.size(),
198 shapeComponent.indexes.data(),
199 shapeComponent.indexes.size(),
200 shapeComponent.texCoords.data(),
201 quads,
202 true,
203 true,
204 1.0f,
205 false,
206 0,
207 positions,
208 normals,
209 indexes,
210 &texCoords);
211
212 mesh->setPositions(std::move(positions));
213 mesh->setNormals(std::move(normals));
214
215 if (texCoords.size()) {
216 mesh->setTexCoords(std::move(texCoords));
217 }
218
219 reindex(indexes, mesh, false);
220 }
221 }
222 break;
223 case ShapePrimitiveType::DefaultLine:
224 {
225 if (materialComponent) {
226 materialComponent->primitiveType = PrimitiveType::LineList;
227 }
228
229 mesh->setPositions(shapeComponent.positions);
230
231 if (shapeComponent.normals.size()) {
232 mesh->setNormals(shapeComponent.normals);
233 }
234
235 if (shapeComponent.texCoords.size()) {
236 mesh->setTexCoords(shapeComponent.texCoords);
237 }
238
239 reindex(shapeComponent.indexes, mesh, true);
240
241 if (!shapeComponent.normals.size() && materialComponent) {
242 materialComponent->enableLighting = false;
243 materialComponent->setChanged();
244 }
245 }
246 break;
247 case ShapePrimitiveType::LineListAdjacency:
248 case ShapePrimitiveType::LineStripAdjacency:
249 case ShapePrimitiveType::LineList:
250 case ShapePrimitiveType::LineStrip:
251 case ShapePrimitiveType::PointList:
252 {
253 if (materialComponent) {
254 materialComponent->enableLighting = shapeComponent.normals.size() > 0;
255 materialComponent->setChanged();
256 }
257 }
258 case ShapePrimitiveType::TriangleList:
259 case ShapePrimitiveType::TriangleStrip:
260 {
261 mesh->setPositions(shapeComponent.positions);
262
263 if (shapeComponent.normals.size()) {
264 mesh->setNormals(shapeComponent.normals);
265 }
266
267 if (shapeComponent.texCoords.size()) {
268 mesh->setTexCoords(shapeComponent.texCoords);
269 }
270
271 if (shapeComponent.indexes.size()) {
272 mesh->setIndexData(reinterpret_cast<const uint32_t *>(shapeComponent.indexes.data()), shapeComponent.indexes.size());
273 }
274
287 };
288
289 static_assert(sizeof(typeMap) / sizeof(typeMap[0]) == (size_t)ShapePrimitiveType::ShapePrimitiveType_Size, "Type map wrong size.");
290
291 mesh->primitiveType = typeMap[static_cast<int>(shapeComponent.primitiveType)];
292
293 if (materialComponent) {
294 materialComponent->primitiveType = mesh->primitiveType;
295 }
296 }
297 break;
298 default:
299 break;
300 }
301 }
302 }
303}
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
class Entity * getContainer() const
Get the container currently owning this component instance.
Definition: Component.h:151
const std::string & getName() const noexcept
Get the name of this entity.
Definition: Entity.h:120
Context * context
Pointer to the Context instance the system lives in.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class IRenderer * renderer
Renderer.
Definition: Context.h:228
std::unique_ptr< class Variables > variables
Variables service instance.
Definition: Context.h:180
virtual IGraphicsDevice * getDevice()=0
Get the graphics device used by the renderer.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Definition: MeshComponent.h:29
void initialize(Context *context) override
Initialize the system.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ InstanceData
Per instance data.
@ Position
Position semantic.
Exposes material properties for legacy entities and code.
bool instancedLine
Lines rendered with instancing.
@ Instanced
Mesh contains instance data.
Definition: Mesh.h:70
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void unmap(VertexDataType::EVertexDataType type)
Unmap the stream with the given vertex data type index.
Definition: Mesh.h:900
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
void setTexCoords(std::span< const glm::vec2 > texCoords)
Set the texture coordinate data of the Mesh.
Definition: Mesh.h:504
void setIndexData(const uint32_t *data, size_t count)
Convenience method for setting index data from a raw pointer to data and count number of elements.
Definition: Mesh.h:705
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
Definition: Mesh.h:298
void setInstanceCount(size_t count)
Set the number of instances in this mesh.
Definition: Mesh.h:1033
void setNormals(std::span< const glm::vec3 > normals)
Set the normal data of the Mesh.
Definition: Mesh.h:392
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
void setMeshFlag(MeshFlags::EMeshFlags flag)
Set the given mesh flag.
Definition: Mesh.h:659
void setCount(size_t count)
Explicitly set the vertex count of the mesh.
Definition: Mesh.h:1019
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
Definition: Mesh.h:315
Runtime control variable.
Definition: Variables.h:27
virtual bool supportsInstancing() const
Check if the graphics device supports instancing.
EPrimitiveType
Primitive type enumeration.
Definition: Common.h:114
@ LineStrip
Line strip.
Definition: Common.h:122
@ LineStripAdjacency
Line strip with adjacency.
Definition: Common.h:132
@ LineList
List of lines.
Definition: Common.h:120
@ TriangleStrip
Triangle strip.
Definition: Common.h:118
@ TriangleListAdjacency
List of triangles with adjacency.
Definition: Common.h:126
@ PointList
List of points.
Definition: Common.h:124
@ TriangleStripAdjacency
Triangle strip with adjacency.
Definition: Common.h:128
@ LineListAdjacency
List of lines with adjacency.
Definition: Common.h:130
@ TriangleList
List of triangles.
Definition: Common.h:116
Vertex element structure used to describe a single data element in a vertex for the input assembler.
Definition: VertexFormat.h:38
uint16_t offset
Offset in bytes from the vertex position in memory.
Definition: VertexFormat.h:39