Cogs.Core
LoftedCrossSectionsSystem.cpp
1
2#include "Context.h"
3
4#include "Systems/Core/CameraSystem.h"
5#include "Systems/Core/TransformSystem.h"
6#include "Components/Core/MeshComponent.h"
7#include "Components/Core/MeshRenderComponent.h"
8
9#include "Resources/MeshManager.h"
10
11#include "LoftedCrossSectionsSystem.h"
12#include "LoftedCrossSectionsSystem_tables.h"
13
14#include "Foundation/Logging/Logger.h"
15
16namespace
17{
18 Cogs::Logging::Log logger = Cogs::Logging::getLogger("Cogs.Core.System.LoftedCrossSectionsSystem");
19}
20
22{
24
25 shellInitialize();
26 hollowInitialize();
27 solidInitialize();
28}
29
30bool Cogs::Core::LoftedCrossSectionsSystem::process(Context* context,
31 glm::vec4 viewer_world,
34 Mesh* mesh)
35{
36 bool retval = false;
37 bool reconsiderView = component.open && component.hasChanged();
38 bool updateIndices = component.hasChanged();
39
40 // check if viewpoint has changed enough to trigger a retriangulation
41 if (component.open && component.screenAligned) {
42 auto transform = component.getComponent<TransformComponent>();
43 glm::mat4 worldToLocal = glm::inverse(context->transformSystem->getLocalToWorld(transform));
44 glm::vec4 t = worldToLocal * viewer_world;
45 glm::vec3 viewpoint = (1.f / t.w)*glm::vec3(t.x, t.y, t.z);
46
47 if (glm::distance(viewpoint, data.viewpoint) > std::numeric_limits<float>::epsilon()) {
48 data.viewpoint = viewpoint;
49 reconsiderView = true;
50 }
51 }
52
53 // get pointer to vertex data
54 {
55 const float* pos = nullptr;
56 size_t pos_stride = 0;
57
58 if (!component.vertices_vn.empty()) {
59 pos = (const float*)((const uint8_t*)component.vertices_vn.data() + offsetof(PositionNormalVertex, position));
60 pos_stride = sizeof(PositionNormalVertex) / sizeof(float);
61 } else if (!component.vertices_vnt.empty()) {
62 pos = (const float*)((const uint8_t*)component.vertices_vnt.data() + offsetof(PositionNormalTexVertex, position));
63 pos_stride = sizeof(PositionNormalTexVertex) / sizeof(float);
64 } else {
65 return false;
66 }
67
68 // classify cell corners as inside or outside based on current view
69 if (component.open && component.screenAligned) {
70 if (reconsiderView) {
71 switch (component.shape) {
72 case LoftedCrossSectionsComponent::Shape::Hollow:
73 hollowOpenAlignedClassifySamples(data.inside, pos, pos_stride, component.spine, data.viewpoint, component.crossSections, component.samples);
74 break;
75
76 case LoftedCrossSectionsComponent::Shape::Solid:
77 solidOpenAlignedClassifySamples(data.inside, pos, pos_stride, component.spine, data.viewpoint, component.crossSections, component.samples);
78 break;
79
80 case LoftedCrossSectionsComponent::Shape::Shell:
81 shellOpenAlignedClassifySamples(data.inside, pos, pos_stride, component.spine, data.viewpoint, component.crossSections, component.samples);
82 break;
83 }
84 updateIndices = true;
85 }
86 }
87 }
88
89 // determine new indices
90 if (updateIndices) {
91 // Determine size of arrays
92 size_t newVertices = 0;
93 size_t outIndices = 0;
94 size_t cutIndices = 0;
95 switch (component.shape) {
96 case LoftedCrossSectionsComponent::Shape::Hollow:
97 if (component.open && component.screenAligned) {
98 hollowOpenAlignedCountCellResources(newVertices, outIndices, cutIndices, data.classification,
99 component.spine, data.inside, data.viewpoint,
100 component.crossSections, component.samples, component.doubleSeamVertices);
101 } else if (component.open) {
102 hollowOpenCountCellResources(newVertices, outIndices, cutIndices,
103 component.crossSections, component.samples, component.doubleSeamVertices);
104 } else {
105 hollowClosedCountCellResources(newVertices, outIndices, cutIndices,
106 component.crossSections, component.samples, component.doubleSeamVertices);
107 }
108
109 newVertices += 2 * component.samples*component.crossSections;
110 break;
111
112 case LoftedCrossSectionsComponent::Shape::Solid:
113 if (component.open && component.screenAligned) {
114 solidOpenAlignedCountCellResources(newVertices, outIndices, cutIndices, data.classification,
115 component.spine, data.inside, data.viewpoint,
116 component.crossSections, component.samples, component.doubleSeamVertices);
117 } else if (component.open) {
118 solidOpenCountCellResources(newVertices, outIndices, cutIndices,
119 component.crossSections, component.samples, component.doubleSeamVertices);
120 } else {
121 solidClosedCountCellResources(newVertices, outIndices,
122 component.crossSections, component.samples, component.doubleSeamVertices);
123 }
124
125 newVertices += component.samples*component.crossSections;
126 break;
127
128 case LoftedCrossSectionsComponent::Shape::Shell:
129 if (component.open && component.screenAligned) {
130 shellOpenAlignedCountCellResources(newVertices, outIndices, data.classification,
131 component.spine, data.inside, data.viewpoint,
132 component.crossSections, component.samples, component.doubleSeamVertices);
133 } else if (component.open) {
134 shellOpenCountCellResources(outIndices,
135 component.crossSections, component.samples,
136 component.doubleSeamVertices);
137 } else {
138 shellClosedCountCellResources(outIndices,
139 component.crossSections, component.samples,
140 component.doubleSeamVertices);
141 }
142 newVertices += component.samples*component.crossSections;
143 break;
144 }
145
146
147 // resize and extract pointers
148 std::vector<unsigned int> surface(outIndices);
149 std::vector<unsigned int> cut(cutIndices);
150 float* pos;
151 float* nrm;
152 float *tex = nullptr;
153 size_t pos_stride, nrm_stride, tex_stride;
154
155 if (!component.vertices_vn.empty()) {
156 component.vertices_vn.resize(newVertices);
157 pos = (float*)((uint8_t*)component.vertices_vn.data() + offsetof(PositionNormalVertex, position));
158 nrm = (float*)((uint8_t*)component.vertices_vn.data() + offsetof(PositionNormalVertex, normal));
159 pos_stride = sizeof(PositionNormalVertex) / sizeof(float);
160 nrm_stride = sizeof(PositionNormalVertex) / sizeof(float);
161 tex_stride = 0;
162 } else {
163 component.vertices_vnt.resize(newVertices);
164 pos = (float*)((uint8_t*)component.vertices_vnt.data() + offsetof(PositionNormalTexVertex, position));
165 nrm = (float*)((uint8_t*)component.vertices_vnt.data() + offsetof(PositionNormalTexVertex, normal));
166 tex = (float*)((uint8_t*)component.vertices_vnt.data() + offsetof(PositionNormalTexVertex, tex));
167 pos_stride = sizeof(PositionNormalTexVertex) / sizeof(float);
168 nrm_stride = sizeof(PositionNormalTexVertex) / sizeof(float);
169 tex_stride = sizeof(PositionNormalTexVertex) / sizeof(float);
170 }
171
172
173 // extract indices and new vertices
174 switch (component.shape) {
175 case LoftedCrossSectionsComponent::Shape::Hollow:
176 if (component.open && component.screenAligned) {
177 hollowOpenAlignedSkin(surface, cut, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
178 data.classification, component.spine, data.viewpoint,
179 component.crossSections, component.samples, component.doubleSeamVertices);
180 } else if (component.open) {
181 hollowOpenSkin(surface, cut, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
182 component.crossSections, component.samples, component.doubleSeamVertices);
183 } else {
184 hollowClosedSkin(surface, component.crossSections, component.samples, component.doubleSeamVertices);
185 }
186 break;
187
188 case LoftedCrossSectionsComponent::Shape::Solid:
189 if (component.open && component.screenAligned) {
190 solidOpenAlignedSkin(surface, cut, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
191 data.classification, component.spine, data.viewpoint,
192 component.crossSections, component.samples, component.doubleSeamVertices);
193 } else if (component.open) {
194 solidOpenSkin(surface, cut, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
195 component.spine,
196 component.crossSections, component.samples, component.doubleSeamVertices);
197 } else {
198 solidClosedSkin(surface, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
199 component.spine,
200 component.crossSections, component.samples, component.doubleSeamVertices);
201 }
202 break;
203
204 case LoftedCrossSectionsComponent::Shape::Shell:
205 if (component.open && component.screenAligned) {
206 shellOpenAlignedSkin(surface, pos, pos_stride, tex, tex_stride, nrm, nrm_stride,
207 data.classification, component.spine, data.viewpoint,
208 component.crossSections, component.samples, component.doubleSeamVertices);
209 } else if (component.open) {
210 shellOpenSkin(surface,
211 component.crossSections, component.samples,
212 component.doubleSeamVertices);
213 } else {
214 shellClosedSkin(surface,
215 component.crossSections, component.samples,
216 component.doubleSeamVertices);
217 }
218 break;
219 }
220
221 // while we only support single material, use same for both skin and cut.
222 surface.reserve(surface.size() + cut.size());
223 surface.insert(surface.end(), cut.begin(), cut.end());
224
225 if (!component.vertices_vn.empty()) {
226 mesh->setVertexData(component.vertices_vn.data(), component.vertices_vn.size());
227 } else {
228 mesh->setVertexData(component.vertices_vnt.data(), component.vertices_vnt.size());
229 }
230
231 mesh->clearIndexes();
232 mesh->setIndexes(std::move(surface));
233 mesh->primitiveType = PrimitiveType::TriangleList;
234
235 retval = true;
236 }
237
238 return retval;
239}
240
242{
243 auto & meshManager = context->meshManager;
244 const auto & cameraComponent = context->cameraSystem->getMainCamera();
245 const auto & cameraData = context->cameraSystem->getData(cameraComponent);
246
247 glm::vec4 viewerWorld = cameraData.inverseViewMatrix * glm::vec4(0.f, 0.f, 0.f, 1.f);
248
249 for (auto& component : pool) {
250 auto& data = getData(&component);
251
252 auto meshComponent = component.getComponent<MeshComponent>();
253 if (meshComponent->meshHandle == MeshHandle::NoHandle) {
254 meshComponent->meshHandle = context->meshManager->create();
255 component.setChanged();
256 }
257 auto mesh = meshManager->get(meshComponent->meshHandle);
258
259 // forward bounding box to mesh
260 if (component.boundingBoxSet) {
261 component.boundingBoxSet = false;
262 mesh->setBounds(component.boundingBox);
263 meshComponent->setChanged();
264 }
265
266 // sanity checks and forward visibility to mesh
267 if (!component.visibility || !component.hasData) {
268 if (data.visibilityProcessed) {
269 data.visibilityProcessed = false;
270 mesh->clear();
271 mesh->clearIndexes();
272 meshComponent->setChanged();
273 }
274 continue;
275 }
276 data.visibilityProcessed = true;
277
278 if (component.hasData) {
279 process(context, viewerWorld, component, data, mesh);
280 }
281 }
282}
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Definition: Component.h:202
ComponentType * getComponent() const
Definition: Component.h:159
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
void initialize(Context *context) override
Initialize the system.
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
Defines a 4x4 transformation matrix for the entity and a global offset for root entities.
Log implementation class.
Definition: LogManager.h:139
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
bool boundingBoxSet
True when bounding box info is set but not yet forwarded to mesh.
int crossSections
Number of cross sections (inner & outer cross sections count as one).
bool screenAligned
Let open geometry be screen-aligned.
int samples
Number of sample points in each of the cross sections.
bool open
If true, cull the front of the shape such that the inside is visible.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void setIndexes(std::span< const uint32_t > collection)
Set the index data to the collection given.
Definition: Mesh.h:596
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
Definition: Mesh.h:298
void clearIndexes()
Clear all index data, also clearing all sub-meshes.
Definition: Mesh.h:607
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 setVertexData(Element *elements, size_t count)
Set vertex data.
Definition: Mesh.h:754
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ TriangleList
List of triangles.
Definition: Common.h:116