1#include "ExtrusionSystem.h"
3#include "Components/Data/TrajectoryComponent.h"
4#include "Components/Core/TransformComponent.h"
5#include "Components/Core/MeshComponent.h"
6#include "Components/Core/MeshRenderComponent.h"
7#include "Components/Data/DataSetComponent.h"
8#include "Components/Appearance/MaterialComponent.h"
10#include "Systems/Core/TransformSystem.h"
14#include "Resources/Mesh.h"
15#include "Resources/VertexFormats.h"
16#include "Resources/MeshManager.h"
17#include "Resources/MaterialManager.h"
18#include "Resources/DefaultMaterial.h"
20#include "Utilities/Math.h"
22#include "Math/CrossSectionGenerator.h"
23#include "Math/ExtrusionGenerator.h"
25#include "Foundation/ComponentModel/Entity.h"
26#include "Foundation/Geometry/Glm.hpp"
27#include "Foundation/Geometry/SampleListGenerator.hpp"
28#include "Foundation/Geometry/ValueQuery.hpp"
29#include "Foundation/Geometry/PathGenerator.hpp"
33static void generateExtrusionVertices(
float radius,
const size_t numSegments,
const std::vector<glm::vec3> & positions, std::vector<Cogs::Core::PositionNormalTexVertex> & vertices)
35 std::vector<glm::vec3> crossection(numSegments);
37 CrossSectionGenerator::generateCircularCrossection(crossection.data(),
static_cast<int>(numSegments), radius, 0, glm::pi<float>() * 2.0f,
false);
39 vertices.resize(numSegments * positions.size());
41 glm::vec3 direction = positions[1] - positions[0];
43 for (
size_t i = 0; i < positions.size(); ++i) {
44 if (i > 0 && i < (positions.size() - 2)) {
45 direction = positions[i + 1] - positions[i - 1];
46 direction = glm::normalize(direction);
49 glm::quat rotation = Cogs::Core::getRotation(glm::vec3(0, 0, -1), direction);
51 for (
size_t j = 0; j < crossection.size(); ++j) {
52 const size_t index = (i * numSegments) + j;
54 glm::vec3 position = rotation * crossection[j];
55 position = glm::normalize(position);
56 glm::vec3 normal = position;
58 position += positions[i];
62 vertices[index] = vertex;
67template<
class IndexType>
68static void generateExtrusionIndices(
const unsigned int numSections,
const unsigned int numSegments, std::vector<IndexType> & indices)
70 const unsigned int numFaces = numSegments * (numSections - 1) * 2;
71 const unsigned int numIndices = numFaces * 3;
73 indices.resize(numIndices);
80 auto & meshManager =
context->meshManager;
82 for (
const auto & component :
pool) {
83 if (!component.active)
continue;
91 auto mesh = meshManager->get(meshComponent->meshHandle);
93 if (component.trajectory) {
94 updateExtrusion(component, mesh);
95 }
else if (component.extrusion && component.dataSet) {
96 updateLogExtrusion(component,
context, mesh);
97 }
else if (component.highlightTarget) {
98 updateHighlightExtrusion(component,
context, mesh);
109 if (!trajectoryData || !trajectoryData->positions.size())
return;
111 auto & data = getData<ExtrusionData>(&component);
113 if (component.
hasChanged() || trajectoryData->hasChanged()) {
114 std::vector<PositionNormalTexVertex> extrusionVertices;
116 if (component.coverEntireTrajectory) {
117 generateExtrusionVertices(component.radius * component.diameterScale, component.numSegments, trajectoryData->positions, extrusionVertices);
119 for (
size_t i = 0; i < trajectoryData->indexes.size(); ++i) {
120 for (
size_t j = 0; j < component.numSegments; ++j) {
121 extrusionVertices[i * component.numSegments + j].tex.y = trajectoryData->indexes[i];
125 auto & depthList = data.depthList;
128 SampleListGenerator::generateIndexedSamples(
129 component.startDepth,
131 trajectoryData->indexes.data(),
132 static_cast<int>(trajectoryData->indexes.size()),
135 data.basePositions.resize(depthList.size());
136 data.baseDirections.resize(depthList.size());
138 PathGenerator::generateLinearPath(depthList.data(),
139 static_cast<int>(depthList.size()),
140 trajectoryData->indexes.data(),
141 trajectoryData->positions.data(),
142 static_cast<int>(trajectoryData->indexes.size()),
143 data.basePositions.data(),
144 data.baseDirections.data());
146 generateExtrusionVertices(component.radius * component.diameterScale, component.numSegments, data.basePositions, extrusionVertices);
149 mesh->
setVertexData(extrusionVertices.data(), extrusionVertices.size());
151 std::vector<unsigned int> extrusionIndices;
153 generateExtrusionIndices(
static_cast<unsigned int>(component.coverEntireTrajectory ? trajectoryData->positions.size() : data.basePositions.size()), component.numSegments, extrusionIndices);
155 mesh->
setIndexes(std::move(extrusionIndices));
161void Cogs::Core::ExtrusionSystem::updateLogExtrusion(
const ExtrusionComponent & component, Context * context, Mesh * mesh)
163 const auto transform = component.getComponent<TransformComponent>();
164 const auto extrusion = component.extrusion->getComponent<ExtrusionComponent>();
165 const auto extrusionTransform = extrusion->getComponent<TransformComponent>();
166 const auto trajectory = extrusion->trajectory->getComponent<TrajectoryComponent>();
167 const auto dataSet = component.dataSet->getComponent<DataSetComponent>();
169 context->transformSystem->copyTransform(extrusionTransform, transform);
171 auto material = component.getComponent<MaterialComponent>();
173 auto colorMap = component.colorMap;
176 auto colorMapMaterial = colorMap->getComponent<MaterialComponent>();
178 if (material->diffuseMap != colorMapMaterial->diffuseMap) {
179 material->diffuseMap = colorMapMaterial->diffuseMap;
180 material->diffuseColor = glm::vec4(1, 1, 1, 1);
181 material->setChanged();
185 if (extrusion->hasChanged() ||
186 trajectory->hasChanged() ||
187 dataSet->hasChanged() ||
188 component.hasChanged()) {
189 auto & data = getData<ExtrusionData>(&component);
190 auto & logData = getData<ExtrusionLogData>(&component);
192 const float endDepth = component.coverEntireTrajectory ? std::min(dataSet->indexes[dataSet->indexes.size() - 1], trajectory->indexes[trajectory->indexes.size() - 1]) : component.startDepth;
193 const float startDepth = component.coverEntireTrajectory ? std::max(dataSet->indexes[0], trajectory->indexes[0]) : component.endDepth;
195 std::vector<float> & depthList = data.depthList;
198 SampleListGenerator::generateIndexedSamples<float>(
201 trajectory->indexes.data(),
202 static_cast<int>(trajectory->indexes.size()),
205 std::vector<float> & samples = data.samples;
208 SampleListGenerator::createUniqueVector(
211 dataSet->indexes.data(),
212 static_cast<int>(dataSet->indexes.size()),
217 std::vector<glm::vec3> & basePositions = data.basePositions;
218 basePositions.resize(samples.size());
220 std::vector<glm::vec3> & baseDirections = data.baseDirections;
221 baseDirections.resize(samples.size());
223 std::vector<float> & values = logData.values;
224 logData.values.resize(samples.size());
226 ValueQuery::getValuesAtDepths(samples.data(),
static_cast<int>(samples.size()), dataSet->indexes.data(), dataSet->values.data(),
static_cast<int>(dataSet->values.size()), values.data());
228 auto minMax = std::minmax_element(dataSet->values.begin(), dataSet->values.end());
230 SampleListGenerator::normalizeValues<float, true>(values.data(), values.data(),
static_cast<int>(values.size()), *minMax.first, *minMax.second);
232 PathGenerator::generateLinearPath(samples.data(),
static_cast<int>(samples.size()), trajectory->indexes.data(), trajectory->positions.data(),
static_cast<int>(trajectory->positions.size()), basePositions.data(), baseDirections.data());
234 logData.radius = extrusion->radius * extrusion->diameterScale * 1.05f;
236 std::vector<PositionNormalTexVertex> extrusionVertices;
238 generateExtrusionVertices(logData.radius, component.numSegments, data.basePositions, extrusionVertices);
240 const size_t numSamples = data.samples.size();
243 for (
size_t s = 0; s < numSamples; ++s) {
244 for (
size_t ss = 0; ss < component.numSegments; ++ss) {
245 extrusionVertices[texIdx++].tex = glm::vec2(logData.values[s], 0);
249 mesh->setVertexData(extrusionVertices.data(), extrusionVertices.size());
251 std::vector<unsigned int> extrusionIndices;
253 generateExtrusionIndices(
static_cast<unsigned int>(data.basePositions.size()), component.numSegments, extrusionIndices);
255 mesh->setIndexData(extrusionIndices.data(), extrusionIndices.size());
261void Cogs::Core::ExtrusionSystem::updateHighlightExtrusion(
const ExtrusionComponent & component, Context * context, Mesh * mesh)
263 const auto transform = component.getComponent<TransformComponent>();
264 const auto extrusionComponent = component.highlightTarget->getComponent<ExtrusionComponent>();
265 const auto extrusionTransform = extrusionComponent->getComponent<TransformComponent>();
267 if (!extrusionComponent->active)
return;
269 context->transformSystem->copyTransform(extrusionTransform, transform);
271 TrajectoryComponent * trajectory;
273 if (extrusionComponent->extrusion) {
275 auto well = extrusionComponent->extrusion->getComponent<ExtrusionComponent>();
276 trajectory = well->trajectory->getComponent<TrajectoryComponent>();
279 trajectory = extrusionComponent->trajectory->getComponent<TrajectoryComponent>();
282 const auto & targetData = getData<ExtrusionData>(extrusionComponent);
283 const auto & targetLogData = getData<ExtrusionLogData>(extrusionComponent);
284 auto & data = getData<ExtrusionData>(&component);
286 if (extrusionComponent->hasChanged() ||
287 trajectory->hasChanged() ||
288 component.hasChanged()) {
289 const float startDepth = std::max(component.highlightStart, trajectory->indexes[0]);
290 const float endDepth = std::min(component.highlightEnd, trajectory->indexes[trajectory->indexes.size() - 1]);
291 data.samples.clear();
293 SampleListGenerator::generateIndexedSamples<float>(
296 extrusionComponent->extrusion ? targetData.depthList.data() : trajectory->indexes.data(),
297 static_cast<int>(extrusionComponent->extrusion ? targetData.depthList.size() : trajectory->indexes.size()),
300 data.basePositions.resize(data.samples.size());
301 data.baseDirections.resize(data.samples.size());
303 PathGenerator::generateLinearPath(data.samples.data(),
static_cast<int>(data.samples.size()), trajectory->indexes.data(), trajectory->positions.data(),
static_cast<int>(trajectory->positions.size()), data.basePositions.data(), data.baseDirections.data());
305 if (data.samples.size() > 1) {
306 std::vector<PositionNormalTexVertex> extrusionVertices;
308 generateExtrusionVertices(extrusionComponent->extrusion ? targetLogData.radius * 1.05f : extrusionComponent->radius * 1.05f, component.numSegments, data.basePositions, extrusionVertices);
310 mesh->setVertexData(extrusionVertices.data(), extrusionVertices.size());
312 std::vector<unsigned int> extrusionIndices;
314 generateExtrusionIndices((
unsigned int) data.basePositions.size(), component.numSegments, extrusionIndices);
316 mesh->setIndexes(std::move(extrusionIndices));
318 auto materialComponent = component.getComponent<MaterialComponent>();
320 materialComponent->setChanged();
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.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
@ Add
Render with additive blending.
Contains geometry calculations and generation.
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
void setIndexes(std::span< const uint32_t > collection)
Set the index data to the collection given.
void setMeshFlag(MeshFlags::EMeshFlags flag)
Set the given mesh flag.
void setVertexData(Element *elements, size_t count)
Set vertex data.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
Data component defining a 3D trajectory, for example a Well trajectory.
static void generateTriangleIndices(int32_t *indices, int numSections, int numSegments, bool closed, bool useTexture, int32_t offset=0)
Generate legacy triangle extrusion indices.