1#include "VariableExtrusionSystem.h"
3#include "EntityStore.h"
5#include "Components/Core/TransformComponent.h"
6#include "Components/Data/TrajectoryComponent.h"
7#include "Components/Appearance/MaterialComponent.h"
9#include "Systems/Core/RenderSystem.h"
11#include "Utilities/Math.h"
13#include "Math/ExtrusionGenerator.h"
14#include "Math/CrossSectionGenerator.h"
15#include "Math/IndexConversion.h"
16#include "Math/NormalGenerator.h"
18#include "Services/Variables.h"
19#include "Services/TaskManager.h"
21#include "Foundation/ComponentModel/Entity.h"
22#include "Foundation/Geometry/Glm.hpp"
23#include "Foundation/Geometry/PathGenerator.hpp"
31 for (
const auto & component :
pool) {
32 if (!component.isActive())
continue;;
35 auto & componentData = getData(&component);
37 if (!component.closed && !componentData.sideShape) {
43 auto updateComponent = [&,
context]()
45 auto & data = getData(&component);
49 if (data.pathLength < 2) {
55 auto masterMaterial = materialComponent->
material.lock();
59 data.primaryAxis = glm::vec3(0, 0, -1);
61 updateSegmentCount(
context, component);
63 updateRotations(
context, component);
64 updateCrossSections(
context, component);
65 updateOffsets(
context, component);
66 updateTransformation(
context, component);
67 offsetCrossSections(
context, component);
68 updateTextureCoordinates(
context, component);
69 updateIndexes(
context, component);
70 updateSideShape(
context, component);
71 updateNormals(
context, component);
84 auto & data = getData(&component);
86 data.positions.clear();
87 data.directions.clear();
95 data.positions.resize(component.
depths.size());
96 data.directions.resize(component.
depths.size());
99 data.offsetDepths.clear();
100 data.offsetDepths.resize(component.
depths.size());
102 for (
size_t i = 0; i < component.
depths.size(); ++i) {
106 Geometry::PathGenerator::generateLinearPath(data.offsetDepths.data(),
107 data.offsetDepths.size(),
108 trajectoryComponent->indexes.data(),
109 trajectoryComponent->positions.data(),
110 static_cast<int>(trajectoryComponent->positions.size()),
111 data.positions.data(),
112 data.directions.data());
114 Geometry::PathGenerator::generateLinearPath(component.
depths.data(),
116 trajectoryComponent->indexes.data(),
117 trajectoryComponent->positions.data(),
118 static_cast<int>(trajectoryComponent->positions.size()),
119 data.positions.data(),
120 data.directions.data());
123 data.pathLength = data.positions.size();
126void Cogs::Core::VariableExtrusionSystem::updateRotations(Context * ,
const VariableExtrusionComponent & component)
128 auto & data = getData(&component);
130 data.rotations.resize(data.directions.size());
132 glm::vec3 primaryAxis = glm::vec3(0, 0, -1);
134 for (
size_t i = 0; i < data.directions.size(); ++i) {
135 data.rotations[i] = getRotation(primaryAxis, data.directions[i]);
138 if (component.useTwist && component.twist.size() == component.profile.size()) {
141 if (component.enableRotation && !component.useSimpleRotation) {
142 angle = component.angle;
145 for (
size_t i = 0; i < data.rotations.size(); ++i) {
146 data.rotations[i] = glm::angleAxis(component.twist[i] + angle, data.directions[i]) * data.rotations[i];
149 for (
size_t i = 0; i < data.rotations.size(); ++i) {
150 data.rotations[i] = glm::angleAxis(component.angle, data.directions[i]) * data.rotations[i];
155void Cogs::Core::VariableExtrusionSystem::updateCrossSections(Context * context,
const VariableExtrusionComponent & component)
157 auto & data = getData(&component);
158 auto mesh = getMesh(context, component);
159 auto positionData = mesh->mapPositions(0, data.numSegments * data.positions.size());
161 if (component.useMorph && component.morph.size() == component.profile.size()) {
162 if (data.useTexture) {
163 data.crossSection.assign(component.crossSection.begin(), component.crossSection.end());
164 data.morphCrossSection.assign(component.morphCrossSection.begin(), component.morphCrossSection.end());
166 data.crossSection.push_back(data.crossSection[0]);
167 data.morphCrossSection.push_back(data.morphCrossSection[0]);
170 static_cast<int>(data.positions.size()),
171 data.crossSection.data(),
172 data.morphCrossSection.data(),
173 component.morph.data(),
174 static_cast<int>(data.numSegments),
175 data.rotations.data());
178 static_cast<int>(data.positions.size()),
179 component.crossSection.data(),
180 component.morphCrossSection.data(),
181 component.morph.data(),
182 static_cast<int>(data.numSegments),
183 data.rotations.data());
186 std::vector<glm::vec3> crossSection(data.numSegments, glm::vec3(0, 0, 0));
187 CrossSectionGenerator::generateCircularCrossection(crossSection.data(),
188 static_cast<int>(data.numSegments),
191 component.closed ? glm::pi<float>() * 2.0f : glm::pi<float>(),
192 !component.closed || data.useTexture);
195 static_cast<int>(data.positions.size()),
197 static_cast<int>(data.numSegments),
198 data.rotations.data());
201 if (component.radiusScale != 1.0f) {
203 static_cast<int>(data.positions.size()),
204 static_cast<int>(data.numSegments),
205 &component.radiusScale,
210 static_cast<int>(data.positions.size()),
211 static_cast<int>(data.numSegments),
212 reinterpret_cast<const float *
>(component.profile.data()),
216void Cogs::Core::VariableExtrusionSystem::updateOffsets(Context * context,
const VariableExtrusionComponent & component)
218 const auto & data = getData(&component);
219 auto mesh = getMesh(context, component);
221 auto positionData = mesh->mapPositions(0, data.numSegments * data.positions.size());
223 std::vector<glm::vec3> offsets(data.pathLength, glm::vec3(0, 0, 0));
225 for (
size_t i = 0; i < offsets.size(); ++i) {
226 const float offset = component.profile[i][1];
230 offsets[i] = data.rotations[i] * data.primaryAxis;
232 offsets[i] *= offset;
237 static_cast<int>(data.pathLength),
238 static_cast<int>(data.numSegments),
242void Cogs::Core::VariableExtrusionSystem::updateTransformation(Context * ,
const VariableExtrusionComponent & component)
244 auto & data = getData(&component);
245 auto transformComponent = component.getComponent<TransformComponent>();
247 if (component.enableRotation && component.useSimpleRotation) {
248 transformComponent->position = data.positions.front();
250 auto offset = transformComponent->position;
252 for (
size_t i = 0; i < data.pathLength; ++i) {
253 data.positions[i] -= offset;
256 transformComponent->position = glm::vec3(0, 0, 0);
259 transformComponent->setChanged();
262void Cogs::Core::VariableExtrusionSystem::offsetCrossSections(Context * context,
const VariableExtrusionComponent & component)
264 const auto & data = getData(&component);
265 auto mesh = getMesh(context, component);
267 auto positionData = mesh->mapPositions(0, data.numSegments * data.positions.size());
270 static_cast<int>(data.pathLength),
271 static_cast<int>(data.numSegments),
272 data.positions.data());
275void Cogs::Core::VariableExtrusionSystem::updateTextureCoordinates(Context * ,
const VariableExtrusionComponent & component)
277 auto & data = getData(&component);
279 const size_t numTextureCoordinates = data.pathLength * data.numSegments;
281 data.textureCoordinates.resize(numTextureCoordinates);
283 ExtrusionGenerator::generateDepthBasedTextureCoordinates(data.pathLength,
285 component.depths.data(),
286 reinterpret_cast<const float *
>(component.profile.data()) + 1,
288 data.textureCoordinates.data());
290 const glm::vec2 & textureScale = component.textureScale;
291 const glm::vec2 & textureOffset = component.textureOffset;
293 if (textureOffset != glm::vec2(0, 0)) {
294 for (
size_t i = 0; i < numTextureCoordinates; ++i) {
295 data.textureCoordinates[i][0] += textureOffset[0];
296 data.textureCoordinates[i][1] += textureOffset[1];
300 if (textureScale != glm::vec2(1, 1)) {
301 for (
size_t i = 0; i < numTextureCoordinates; ++i) {
302 data.textureCoordinates[i][0] *= textureScale[0];
303 data.textureCoordinates[i][1] *= textureScale[1];
308void Cogs::Core::VariableExtrusionSystem::updateIndexes(Context * ,
const VariableExtrusionComponent & component)
310 auto & data = getData(&component);
313 const size_t numIndexes = (data.pathLength - 1) * (data.numSegments - ((component.closed && !data.useTexture) ? 0 : 1)) * 8;
315 data.indexes.resize(numIndexes);
320void Cogs::Core::VariableExtrusionSystem::updateSideShape(Context * context,
const VariableExtrusionComponent & component)
322 auto & data = getData(&component);
326 if (component.closed) {
327 if (data.sideShape) {
328 auto meshComponent = data.sideShape->getComponent<MeshComponent>();
330 if (meshComponent->meshHandle) {
331 meshComponent->getMesh(context)->clear();
335 auto meshComponent = data.sideShape->getComponent<MeshComponent>();
338 meshComponent->meshHandle = context->meshManager->create();
341 auto regularMesh = getMesh(context, component);
342 auto mesh = meshComponent->meshHandle.resolve();
346 const size_t pathLength = data.pathLength;
347 const int32_t numSegments =
static_cast<int32_t
>(data.numSegments);
349 auto positions = regularMesh->mapPositions(0, regularMesh->getCount());
351 std::vector<int32_t> indexes((data.pathLength + 2) * 2);
353 for (
size_t i = 0; i < data.pathLength; ++i) {
354 indexes[i] =
static_cast<int32_t
>(i) * numSegments;
355 indexes[i + pathLength + 2_uz] =
static_cast<int32_t
>(i) * numSegments + numSegments - 1;
358 indexes[pathLength] = 0;
359 indexes[pathLength + 1_uz] = -1;
361 indexes[pathLength + pathLength + 2_uz] = numSegments - 1;
362 indexes[pathLength + pathLength + 3_uz] = -1;
364 std::vector<glm::vec3> newPositions;
365 std::vector<glm::vec3> normals;
366 std::vector<int32_t> newIndexes;
367 std::vector<glm::vec2> texCoords;
370 auto tessPositions = mesh->mapPositions(0, indexes.size() - 2);
374 size_t currentIdx = 0;
375 size_t currentIIdx = 0;
376 while (currentIIdx < indexes.size()) {
377 tessPositions[currentIdx] = positions[indexes[currentIIdx]];
379 indexes[currentIIdx++] =
static_cast<int32_t
>(currentIdx++);
381 if (indexes[currentIIdx] == -1) ++currentIIdx;
385 auto tesselatedIndexes = tesselatePolygons(indexes, mesh);
387 Cogs::Geometry::generateFacetNormals(
390 tesselatedIndexes.data(),
391 tesselatedIndexes.size(),
392 data.textureCoordinates.data(),
405 mesh->setPositions(std::move(newPositions));
406 mesh->setNormals(std::move(normals));
408 if (texCoords.size()) {
409 mesh->setTexCoords(std::move(texCoords));
412 reindex(newIndexes, mesh,
false);
416void Cogs::Core::VariableExtrusionSystem::updateNormals(Context * context,
const VariableExtrusionComponent & component)
418 auto & data = getData(&component);
419 auto mesh = getMesh(context, component);
420 const size_t numElements = data.numSegments * data.positions.size();
421 auto positionData = mesh->mapPositions(0, numElements);
423 std::vector<glm::vec3> positions;
424 std::vector<glm::vec3> normals;
425 std::vector<int32_t> indexes;
426 std::vector<glm::vec2> texCoords;
428 Cogs::Geometry::generateFacetNormals(
433 data.textureCoordinates.data(),
437 component.creaseAngle,
445 mesh->setPositions(std::move(positions));
446 mesh->setNormals(std::move(normals));
448 if (texCoords.size()) {
449 mesh->setTexCoords(std::move(texCoords));
452 reindex(indexes, mesh,
false);
455Cogs::Core::Mesh * Cogs::Core::VariableExtrusionSystem::getMesh(Context * context,
const VariableExtrusionComponent & component)
457 auto meshComponent = component.getComponent<MeshComponent>();
460 meshComponent->meshHandle = context->meshManager->create();
463 return meshComponent->meshHandle.resolve();
466void Cogs::Core::VariableExtrusionSystem::updateSegmentCount(Context * ,
const VariableExtrusionComponent & component)
468 auto & data = getData(&component);
470 const bool useTexture = data.useTexture;
474 int textureExtra = useTexture ? 1 : 0;
476 if (component.useMorph && component.morph.size() == component.profile.size()) {
478 data.numSegments = component.crossSection.size() + textureExtra;
480 data.numSegments = component.closed ? component.segmentCount : component.segmentCount / 2 + 1;
482 data.numSegments += textureExtra;
ComponentType * getComponent() const
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class EntityStore * store
Entity store.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
std::unique_ptr< class Engine > engine
Engine instance.
EntityPtr getEntity(const StringView &name, bool logIfNotFound=true) const
Retrieve a reference to the shared entity pointer to the Entity with the given name.
EntityPtr createChildEntity(const StringView &type, ComponentModel::Entity *parent, const StringView &name=StringView())
Create a new Entity, parenting it to the given parent.
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.
Exposes material properties for legacy entities and code.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Data component defining a 3D trajectory, for example a Well trajectory.
bool useOffset
If offsets are applied.
float depthOffset
Offset amount applied to the given profile depths before calculating the trajectory.
std::vector< float > depths
Depth values for the profile.
std::shared_ptr< ComponentModel::Entity > trajectory
The trajectory this component is connected to.
static void offsetCrossSections(glm::vec3 *vertices, int numSections, int numSegments, const glm::vec3 *positions)
Offset vertices with per section positions.
static bool generateCrossSections(glm::vec3 *vertices, int numSections, const glm::vec3 *crossSectionElements, int numSegments, const glm::quat *rotations)
Generates cross section vertices in vertices from the cross section definition given.
static void modulateSections(glm::vec3 *vertices, const int numSections, const int numSegments, const float *values, const size_t stride=1)
Modulate extrusion vertices with per section data.
static void generateTriangleIndices(int32_t *indices, int numSections, int numSegments, bool closed, bool useTexture, int32_t offset=0)
Generate legacy triangle extrusion indices.