Cogs.Core
AxisCubeComponent.cpp
1#include "AxisCubeComponent.h"
2
3#include "Types.h"
4#include "Context.h"
5#include "EntityStore.h"
6
7#include "Resources/Mesh.h"
8#include "Resources/MeshManager.h"
9#include "Resources/MaterialManager.h"
10#include "Resources/DefaultMaterial.h"
11#include "Resources/VertexFormats.h"
12#include "Resources/FontManager.h"
13
14#include "Components/Core/MeshComponent.h"
15#include "Components/Core/SubMeshRenderComponent.h"
16#include "Components/Core/TextComponent.h"
17#include "Components/Core/TransformComponent.h"
18#include "../Components/AnnotationAxisComponent.h"
19#include "Components/Appearance/MaterialComponent.h"
20
21#include "Systems/Core/CameraSystem.h"
22#include "Systems/Core/TransformSystem.h"
23#include "Systems/Core/MeshSystem.h"
24#include "Systems/Core/RenderSystem.h"
25
26#include "Foundation/Geometry/BoundingBox.hpp"
27
28#include <sstream>
29#include <numeric>
30#include <array>
31
32using namespace Cogs::Reflection;
33using namespace Cogs::Geometry;
34
35namespace
36{
37 struct
38 {
39 unsigned int ix[4]; // Quad triangle strip indices.
40 glm::mat3x2 proj; // Projection from R^3 corners to R^2 parameter plane.
41 } faceDefinitions[6] =
42 {
43 { { 4, 6, 7, 5 }, { glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f) } }, // Top
44 { { 0, 1, 3, 2 }, { glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f) } }, // Bottom
45 { { 0, 4, 5, 1 }, { glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f) } }, // Front
46 { { 2, 3, 7, 6 }, { glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f) } }, // Back
47 { { 1, 5, 7, 3 }, { glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f) } }, // right
48 { { 0, 2, 6, 4 }, { glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f) } } // left
49 };
50
51 struct
52 {
53 int ix[2]; // Edge end corner indices
54 int nb[2]; // Neighbor quads (references into faceDefinition array)
55 } edgeDefinitions[12] = {
56 // Edges parallel to x-axis
57 { { 0, 1 }, { 2, 1 } },
58 { { 2, 3 }, { 1, 3 } },
59 { { 6, 7 }, { 3, 0 } },
60 { { 4, 5 }, { 0, 2 } },
61 // Edges parallel to y-axis
62 { { 0, 2 }, { 5, 1 } },
63 { { 1, 3 }, { 1, 4 } },
64 { { 5, 7 }, { 4, 0 } },
65 { { 4, 6 }, { 0, 5 } },
66 // Edges parallel to z-axis
67 { { 0, 4 }, { 5, 2 } },
68 { { 1, 5 }, { 2, 4 } },
69 { { 3, 7 }, { 4, 3 } },
70 { { 2, 6 }, { 3, 5 } }
71 };
72}
73
74void Cogs::Core::AxisCubeComponent::registerType()
75{
76 Field fields[] = {
84 Field(Name("useAxisAnnotations"), &AxisCubeComponent::useAxisAnnotations),
85 Field(Name("autoAdjustToLargestDimension"), &AxisCubeComponent::autoAdjustToLargestDimension),
86
88 Field(Name("autoAdjustMargin"), &AxisCubeComponent::autoAdjustMargin),
89 Field(Name("tickSizeOffset"), &AxisCubeComponent::tickSizeOffset),
91
92 Field(Name("topQuadMaterial"), &AxisCubeComponent::topQuadMaterial),
93 Field(Name("bottomQuadMaterial"), &AxisCubeComponent::bottomQuadMaterial),
94 Field(Name("frontQuadMaterial"), &AxisCubeComponent::frontQuadMaterial),
95 Field(Name("backQuadMaterial"), &AxisCubeComponent::backQuadMaterial),
96 Field(Name("rightQuadMaterial"), &AxisCubeComponent::rightQuadMaterial),
97 Field(Name("leftQuadMaterial"), &AxisCubeComponent::leftQuadMaterial),
98 };
99
100 Method methods[] = {
101 Method(Name("initialize"), &AxisCubeComponent::initialize),
102 Method(Name("update"), &AxisCubeComponent::update),
103 };
104
105 DynamicComponent::registerDerivedType<AxisCubeComponent>()
106 .setFields(fields)
107 .setMethods(methods);
108}
109
110void Cogs::Core::AxisCubeComponent::initialize(Context * ctx)
111{
112 context = ctx;
113
114 // Material used for grid lines
115 gridMatInstH = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
116 MaterialInstance* lineMatInst = gridMatInstH.resolve();
117 lineMatInst->setBoolProperty(DefaultMaterial::EnableLighting, false);
118 lineMatInst->setPermutation("Line");
119
120 // Material used for box edges
121 edgeMatInstH = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
122 MaterialInstance* edgeMatInst = edgeMatInstH.resolve();
123 edgeMatInst->setBoolProperty(DefaultMaterial::EnableLighting, false);
124 edgeMatInst->setFloatProperty(DefaultMaterial::LineWidth, 2.0f);
125 edgeMatInst->setPermutation("Line");
126
127 for (int i = 0; i < 6; i++) {
128 PerFaceData& f = faces[i];
129
130 f.solid = context->store->createChildEntity("AxisCubeFace", getContainer());
131
132 MeshComponent* qMeshComp = f.solid->getComponent<MeshComponent>();
133 if (qMeshComp->meshHandle == MeshHandle::NoHandle) {
134 qMeshComp->meshHandle = context->meshManager->create();
135 }
136
137 f.grid = context->store->createChildEntity("SubMeshPart", getContainer());
138
139 MeshComponent* meshComp = f.grid->getComponent<MeshComponent>();
140 if (meshComp->meshHandle == MeshHandle::NoHandle) {
141 meshComp->meshHandle = context->meshManager->create();
142 }
143 auto meshRenderComp = f.grid->getComponent<SubMeshRenderComponent>();
144 //meshRenderComp->material = gridMatInstH;
145 meshRenderComp->setMaterial(gridMatInstH);
146 meshRenderComp->layer = RenderLayers::Annotations;
147
148 f.visible = true;
149 }
150
151 axisTitlesRightEntity = context->store->createChildEntity("Text", getContainer());
152 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
153 textRendLeftComp->positionMode = PositionMode::World;
154 textRendLeftComp->horizontalJustification = HorizontalJustification::Right;
155 textRendLeftComp->verticalAlignment = VerticalAlignment::Center;
156
157 axisTitlesLeftEntity = context->store->createChildEntity("Text", getContainer());
158 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
159 textRendRightComp->positionMode = PositionMode::World;
160 textRendRightComp->horizontalJustification = HorizontalJustification::Left;
161 textRendRightComp->verticalAlignment = VerticalAlignment::Center;
162
163 for (int i = 0; i < 12; i++) {
164 PerEdgeData& e = edges[i];
165
166 e.annotationEntity = context->store->createChildEntity("AxisCubeEdge", getContainer());
167
168 MeshComponent* meshComp = e.annotationEntity->getComponent<MeshComponent>();
169 if (meshComp->meshHandle == MeshHandle::NoHandle) {
170 meshComp->meshHandle = context->meshManager->create();
171 }
172
173 auto meshRenderComp = e.annotationEntity->getComponent<SubMeshRenderComponent>();
174 meshRenderComp->setMaterial(edgeMatInstH);
175 meshRenderComp->layer = RenderLayers::Annotations;
176 e.visible = true;
177 }
178 initialUpdate = true;
179}
180
181void Cogs::Core::AxisCubeComponent::update()
182{
183 auto transformComponent = getComponent<TransformComponent>();
184
185 worldToLocal = glm::inverse(context->transformSystem->getLocalToWorld(transformComponent));
186
187 // Determine extent of autonodes. See below for notes wrt populating this array
188 if (!unprocessedAutoNodes.empty()) {
189 auto bbox = Geometry::makeEmptyBoundingBox<Geometry::BoundingBox>();
190
191 for (auto & entity : unprocessedAutoNodes){
192 auto transComp = entity->getComponent<TransformComponent>();
193 auto meshComp = entity->getComponent<MeshComponent>();
194
195 if (meshComp && transComp) {
196 // Get world space bounds of entity.
197 const auto & bboxNode = context->renderSystem->getWorldBounds(entity->getComponent<MeshRenderComponent>());
198
199 for (int i = 0; i < 8; i++) {
200 const glm::vec4 pw = worldToLocal * glm::vec4((i & 1) == 0 ? bboxNode.min.x : bboxNode.max.x,
201 (i & 2) == 0 ? bboxNode.min.y : bboxNode.max.y,
202 (i & 4) == 0 ? bboxNode.min.z : bboxNode.max.z,
203 1.f);
204
205 bbox += (1.f / pw.w) * glm::vec3(pw.x, pw.y, pw.z);
206 }
207 }
208 }
209
210 unprocessedAutoNodes.clear();
211
212 // If we got a non-empty bounding box, update min and max-corner properties,
213 // and trigger a change. This will be picked up further down and adjusted
214 // corners will be set there.
215 if (!isEmpty(bbox)) {
216 minCorner = bbox.min - autoAdjustMargin;
217 maxCorner = bbox.max + autoAdjustMargin;
218 setChanged();
219 }
220 }
221
222 // If entities has been added to autonodes, append them on the list of
223 // entities that define the extent of the cube. Actually determining
224 // the size of the cube will be done in the next frame, when all the
225 // geometry of the entities has been created and extents defined.
226 if (!autoNodes.empty()) {
227 for (auto & n : autoNodes) {
228 auto locked = n.lock();
229
230 if (locked) {
231 unprocessedAutoNodes.push_back(locked);
232 }
233 }
234 autoNodes.clear();
235 }
236
237 if (initialUpdate || hasChanged()) {
238 if (glm::all(glm::lessThanEqual(minCorner, maxCorner))) {
239 updateAdjustedMinAndMax(minCorner, maxCorner);
240 }
241
242 updateTickSizes();
243 updateCorners();
244
245 updateQuadGeometry(0, topQuadMaterial);
246 updateQuadGeometry(1, bottomQuadMaterial);
247 updateQuadGeometry(2, frontQuadMaterial);
248 updateQuadGeometry(3, backQuadMaterial);
249 updateQuadGeometry(4, rightQuadMaterial);
250 updateQuadGeometry(5, leftQuadMaterial);
251
252 for (int i = 0; i < 6; i++) {
253 updateGridGeometry(i);
254 }
255
256 updateAnnotationAxes();
257
258 updateFaceVisibilites(true);
259 updateEdgeVisibilites(true);
260 updateAxisLabels(true);
261 } else {
262 updateFaceVisibilites(false);
263 updateEdgeVisibilites(false);
264 updateAxisLabels(false);
265 }
266
267 auto matComp = getComponent<MaterialComponent>();
268 if (initialUpdate || matComp->hasChanged()) {
269 gridMatInstH->setVec4Property(DefaultMaterial::DiffuseColor, glm::vec4(glm::vec3(matComp->diffuseColor * 0.7f), 1.0f));
270 edgeMatInstH->setVec4Property(DefaultMaterial::DiffuseColor, matComp->diffuseColor);
271 }
272
273 initialUpdate = false;
274}
275
276void Cogs::Core::AxisCubeComponent::updateAnnotationAxes()
277{
278 for (int i = 0; i < 12; i++) {
279 auto & edgeData = edges[i];
280 edgeData.visible = useAxisAnnotations;
281
282 auto text = edgeData.annotationEntity->getComponent<TextComponent>();
283 text->color = textColor;
284 text->getComponent<SpriteRenderComponent>()->setVisible(edgeData.visible);
285 text->setChanged();
286
287 auto aaComp = edgeData.annotationEntity->getComponent<AnnotationAxisComponent>();
288 aaComp->visible = edgeData.visible;
289 aaComp->positions.clear();
290 aaComp->strings.clear();
291 aaComp->distance = annotationGap;
292 aaComp->setChanged();
293
294 // We store the edge mesh in the annotation axis entity to get the directional visibility toggle.
295 auto mesh = edgeData.annotationEntity->getComponent<MeshComponent>()->meshHandle;
296 Cogs::Core::PositionVertex V[2] = { { corners[edgeDefinitions[i].ix[0]] }, { corners[edgeDefinitions[i].ix[1]] } };
297 std::array<uint32_t, 2> I = { 0, 1 };
298 mesh->setVertexData(V, 2);
299 mesh->clearIndexes();
300 mesh->addSubMesh(std::span(I), Cogs::PrimitiveType::LineList);
301 }
302
303 if (!useAxisAnnotations) return;
304
305 unitNames.resize(3);
306
307 std::stringstream o;
308 for (int a = 0; a < 3; a++) {
309 int l = int(glm::ceil((adjustedMinCorner[a] * (a == 2 ? 1.f / zScale : 1.f)) * unitScales[a] / tickSizes[a]));
310 int u = int(glm::floor((adjustedMaxCorner[a] * (a == 2 ? 1.f / zScale : 1.f)) * unitScales[a] / tickSizes[a]));
311
312 for (int k = 0; k < 4; k++) {
313 int i_ = 4 * a + k;
314
315 // Update annotation labels
316 auto aaComp = edges[i_].annotationEntity->getComponent<AnnotationAxisComponent>();
317
318 glm::vec4 t = faces[edgeDefinitions[i_].nb[0]].equation
319 + faces[edgeDefinitions[i_].nb[1]].equation;
320 glm::vec3 p = corners[edgeDefinitions[i_].ix[0]] - tickProtrusion*glm::vec3(t.x, t.y, t.z);
321
322 for (int i = l; i <= u; i++) {
323
324 float uu = tickSizes[a] * i; // value at tick
325 p[a] = (uu* (a == 2 ? zScale : 1.f)) / unitScales[a]; // value scaled to local coordinate system
326
327 o.str("");
328 o << uu << unitNames[a];
329
330 aaComp->positions.push_back(p);
331 aaComp->strings.push_back(o.str());
332 }
333
334 aaComp->viewDependentAnchor = true;
335 aaComp->viewDependentAnchorReference = -glm::normalize(corners[edgeDefinitions[i_].ix[0]] +
336 corners[edgeDefinitions[i_].ix[1]] -
337 adjustedMinCorner[a] -
338 adjustedMaxCorner[a]);
339 }
340 }
341}
342
343void Cogs::Core::AxisCubeComponent::updateCorners()
344{
345 for (int i = 0; i < 8; i++) {
346 corners[i].x = (i & 1) == 0 ? adjustedMinCorner.x : adjustedMaxCorner.x;
347 corners[i].y = (i & 2) == 0 ? adjustedMinCorner.y : adjustedMaxCorner.y;
348 corners[i].z = (i & 4) == 0 ? adjustedMinCorner.z : adjustedMaxCorner.z;
349 }
350}
351
352void Cogs::Core::AxisCubeComponent::updateAdjustedMinAndMax(const glm::vec3 & minCorner, const glm::vec3 & maxCorner)
353{
354 if (autoAdjustToLargestDimension) {
355 glm::vec3 d = maxCorner - minCorner;
356 float h = 0.5f * glm::max(glm::max(d.x, d.y), d.z);
357 glm::vec3 o = 0.5f * (minCorner + maxCorner);
358 adjustedMinCorner = o - glm::vec3(h);
359 adjustedMaxCorner = o + glm::vec3(h);
360 } else {
361 adjustedMinCorner = minCorner;
362 adjustedMaxCorner = maxCorner;
363 }
364}
365
366void Cogs::Core::AxisCubeComponent::updateTickSizes()
367{
368 glm::vec3 l = adjustedMaxCorner - adjustedMinCorner;
369 tickProtrusion = std::min(100.f, tickSizeOffset*(0.5f / 3.f)*(l.x + l.y + l.z));
370
371 for (int i = 0; i < 3; i++) {
372 float local_d = std::max(std::numeric_limits<float>::epsilon(), adjustedMaxCorner[i] - adjustedMinCorner[i]);
373 float d = local_d*(i == 2 ? 1.f / zScale : 1.f)*unitScales[i];
374 float a = float(std::max(1, maxAxisValues));
375 float d_over_a = std::max(std::numeric_limits<float>::epsilon(), d / a);
376
377 // We want tick-sizes that have the correct magnitude, and we allow that
378 // size to be subdivided into halfs or quarters. In other words, we seek
379 //
380 // d/a <= 2^q 10^m, q \in {0,-1,-2}, m \in Z,
381 //
382 // thus if,
383 //
384 // l = log10(d/a)
385 //
386 // m = ceil( l ),
387 //
388 // q = round( log2( (d/a)/10^m ) )
389 // = round( log2( d/a ) - log2(10^m) )
390 // = round( log10( d/a )log2(10) - m log2(10) )
391 // = round( log2(10)( l - m) ) ).
392 float l_ = std::log10(d_over_a);
393 float m = std::ceil(l_);
394 float q = std::round(std::log2(10.f)*(l_ - m));
395 tickSizes[i] = std::exp2(q)*std::pow(10.f, m);
396 }
397}
398
399void Cogs::Core::AxisCubeComponent::updateEdgeVisibilites(bool forceUpdate)
400{
401 for (int i = 0; i < 12; i++) {
402 PerEdgeData& e = edges[i];
403
404 // An edge is visible if at least one of the two adjacent faces are visible.
405 bool visible = faces[edgeDefinitions[i].nb[0]].visible ||
406 faces[edgeDefinitions[i].nb[1]].visible;
407 if (forceUpdate || (e.visible != visible)) {
408 auto mesh = e.annotationEntity->getComponent<RenderComponent>();
409 mesh->setVisible(visible);
410 mesh->setChanged();
411
412 TextComponent * text = e.annotationEntity->getComponent<TextComponent>();
413 text->getComponent<SpriteRenderComponent>()->setVisible(visible);
414 text->setChanged();
415
416 e.visible = visible;
417 }
418 }
419}
420
421void Cogs::Core::AxisCubeComponent::updateAxisLabels(bool /*forceUpdate*/)
422{
423 using namespace glm;
424 using std::accumulate;
425 using std::numeric_limits;
426
427 auto camComp = context->cameraSystem->getMainCamera();
428 auto & camData = context->cameraSystem->getData(camComp);
429 auto trComp = getComponent<TransformComponent>();
430
431 mat4 localToClip = camData.viewProjection * context->transformSystem->getLocalToWorld(trComp);
432
433 vec3 cubeMidLocal = (1.f/8.f)*accumulate(corners, corners + 8, vec3(0.f));
434
435 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
436 textRendLeftComp->color = textColor;
437 textRendLeftComp->texts.clear();
438 textRendLeftComp->positions.clear();
439
440 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
441 textRendRightComp->color = textColor;
442 textRendRightComp->texts.clear();
443 textRendRightComp->positions.clear();
444
445 vec3 viewXLocal(localToClip[0][0], localToClip[1][0], localToClip[2][0]);
446 vec3 viewZLocal(localToClip[0][2], localToClip[1][2], localToClip[2][2]);
447
448 axisTitles.resize(3);
449 for (int i = 0; i < 3; i++) {
450 if (axisTitles[i].empty()) continue;
451
452 // Add label to all edges that have a visible and an invisible quad abutting
453 for (int j = 0; j < 4; j++) {
454 int e = 4 * i + j;
455 if (faces[edgeDefinitions[e].nb[0]].visible != faces[edgeDefinitions[e].nb[1]].visible) {
456
457 // direction from cube center to edge midpoint
458 vec3 edgeMidLocal = (1.f / 2.f)*(corners[edgeDefinitions[e].ix[0]] + corners[edgeDefinitions[e].ix[1]]);
459 vec3 edgeDirLocal = normalize(edgeMidLocal - cubeMidLocal);
460
461 // Project direction into view plane
462 vec3 edgeDirInViewPlaneLocal = edgeDirLocal - (dot(edgeDirLocal, viewZLocal) / dot(viewZLocal, viewZLocal))*viewZLocal;
463
464 // Determine if label should be left- or right-adjusted.
465 if (dot(viewXLocal, edgeDirInViewPlaneLocal) < 0.f) {
466 textRendLeftComp->texts.push_back(axisTitles[i]);
467 textRendLeftComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
468 } else {
469 textRendRightComp->texts.push_back(axisTitles[i]);
470 textRendRightComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
471 }
472 }
473 }
474 }
475
476 textRendLeftComp->setChanged();
477 textRendRightComp->setChanged();
478}
479
480void Cogs::Core::AxisCubeComponent::updateFaceVisibilites(bool forceUpdate)
481{
482 // --- Get reference vector to use for visibility tests --------------------
483 //
484 // If the projection is a perspective projection, we compute the local
485 // coords position of the view-point, and do a half-plane check for each of
486 // the cube sides. If the view-point is inside the corresponding half-space,
487 // the front-facing test succeeds.
488 //
489 // On the other hand, if the projection is an orthographic projection, the
490 // actual view-point has been pushed to infinity. In this case, we just use
491 // the view-direction transformed to local space.
492
493 glm::vec4 refVec;
494 const auto camComp = context->cameraSystem->getMainCamera();
495 const auto & cameraData = context->cameraSystem->getData(camComp);
496 auto transform = getComponent<TransformComponent>();
497 glm::vec4 viewDirWorldSpace = glm::vec4(0.f, 0.f, 1.f, 0.f)*cameraData.viewMatrix;
498 glm::vec4 viewDirLocalSpace = viewDirWorldSpace * context->transformSystem->getLocalToWorld(transform);
499
500 glm::bvec3 newMarkerFaces = glm::lessThan(glm::vec3(viewDirLocalSpace.x, viewDirLocalSpace.y, viewDirLocalSpace.z), glm::vec3(0.f));
501 if (glm::any(glm::notEqual(markerFaces, newMarkerFaces))) {
502 markerFaces = newMarkerFaces;
503 setChanged();
504 }
505
506 if (camComp->projectionMode == ProjectionMode::Perspective) {
507 glm::vec4 viewPointWorldCoords = cameraData.inverseViewMatrix * glm::vec4(0.f, 0.f, 0.f, 1.f);
508 glm::vec4 viewPointLocalCoords = glm::inverse(context->transformSystem->getLocalToWorld(transform)) * viewPointWorldCoords;
509 refVec = viewPointLocalCoords;
510 } else {
511 refVec = viewDirLocalSpace;
512 refVec.w = 0.f;
513 }
514
515 // --- Check visibility and update -----------------------------------------
516 for (int face = 0; face < 6; face++) {
517 PerFaceData& f = faces[face];
518
519 bool visible = glm::dot(refVec, f.equation) >= 0.f;
520
521 if (forceUpdate || (f.visible != visible)) {
522 auto qMeshRC = f.solid->getComponent<RenderComponent>();
523 qMeshRC->setVisible(visible);
524 qMeshRC->setChanged();
525
526 auto lMeshRC = f.grid->getComponent<RenderComponent>();
527 lMeshRC->setVisible(visible);
528 lMeshRC->setChanged();
529
530 setChanged();
531 }
532 f.visible = visible;
533 }
534}
535
536void Cogs::Core::AxisCubeComponent::updateQuadGeometry(int face, EntityPtr material)
537{
538 PerFaceData & f = faces[face];
539
540 const glm::vec3 & p0 = corners[faceDefinitions[face].ix[0]];
541 const glm::vec3 & p1 = corners[faceDefinitions[face].ix[1]];
542 const glm::vec3 & p2 = corners[faceDefinitions[face].ix[2]];
543 const glm::vec3 & p3 = corners[faceDefinitions[face].ix[3]];
544
545 glm::vec3 n = glm::normalize(glm::cross(p1 - p0, p3 - p0));
546 f.equation = glm::vec4(n.x, n.y, n.z, -glm::dot(n, p0));
547
548 if (material) {
549 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
550
551 Cogs::Core::PositionNormalVertex V[4] = { { p0, n }, { p1, n }, { p2, n }, { p3, n } };
552 qMesh->setVertexData(V, 4);
553
554 auto materialComponent = f.solid->getComponent<MaterialComponent>();
555 materialComponent->material = material;
556
557 auto masterMaterialComponent = material->getComponent<MaterialComponent>();
558 masterMaterialComponent->depthBiasEnable = true;
559 if(context->variables->get("renderer.reverseDepth", false)){
560 masterMaterialComponent->depthBiasConstant = -2.0f;
561 masterMaterialComponent->depthBiasSlope = -2.0f;
562 }
563 else{
564 masterMaterialComponent->depthBiasConstant = 2.0f;
565 masterMaterialComponent->depthBiasSlope = 2.0f;
566 }
567
568 qMesh->clearIndexes();
569 std::array<uint32_t, 4> I{ 0, 1, 3, 2 };
570 qMesh->addSubMesh(std::span(I), Cogs::PrimitiveType::TriangleStrip);
571 } else {
572 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
573 qMesh->clearIndexes();
574 }
575}
576
577void Cogs::Core::AxisCubeComponent::updateGridGeometry(int face)
578{
579 const glm::vec3& p0 = corners[faceDefinitions[face].ix[0]];
580 const glm::vec3& p1 = corners[faceDefinitions[face].ix[1]];
581 const glm::vec3& p2 = corners[faceDefinitions[face].ix[2]];
582
583 glm::vec3 tap = -tickProtrusion*glm::normalize(glm::cross(p1 - p0, p2 - p0));
584
585 const glm::vec2 t0 = faceDefinitions[face].proj*p0;
586 const glm::vec2 t2 = faceDefinitions[face].proj*p2;
587
588 const glm::vec2 ticks = faceDefinitions[face].proj*tickSizes;
589 const glm::vec2 scale = faceDefinitions[face].proj*unitScales
590 * glm::mix(glm::vec2(1.f), glm::vec2(1.f / zScale), glm::notEqual(faceDefinitions[face].proj[2], glm::vec2(0.f)));
591
592 const glm::mat2x3 projTr = glm::transpose(faceDefinitions[face].proj);
593
594 std::vector<Cogs::Core::PositionVertex> V;
595 std::vector<unsigned int> I;
596
597 glm::ivec2 ll(glm::ceil(t0*scale / ticks));
598 glm::ivec2 ur(glm::floor(t2*scale / ticks));
599
600 for (int k = 0; k < 2; k++) {
601 glm::vec3 keep = glm::vec3(1.f) - projTr[k];
602
603 // Skip if no inner edges present.
604 if (ur[k] - ll[k] < 3) continue;
605
606 for (int i = ll[k] + 1; i <= ur[k] - 1; i++) {
607 int o = static_cast<int>(V.size());
608 I.push_back(o);
609 I.push_back(o + 1);
610
611 I.push_back(o + 1);
612 I.push_back(o + 2);
613
614 I.push_back(o + 2);
615 I.push_back(o + 3);
616
617 float u = ticks[k] * i;
618 V.push_back({ keep*p0 + (u / scale[k])*projTr[k] + tap });
619 V.push_back({ keep*p0 + (u / scale[k])*projTr[k] });
620 V.push_back({ keep*p2 + (u / scale[k])*projTr[k] });
621 V.push_back({ keep*p2 + (u / scale[k])*projTr[k] + tap });
622 }
623 }
624
625 auto mesh = context->meshManager->get(faces[face].grid->getComponent<MeshComponent>()->meshHandle);
626
627 mesh->setVertexData(V.data(), V.size());
628 mesh->clearIndexes();
629 mesh->addSubMesh(std::span(I), Cogs::PrimitiveType::LineList);
630}
Field definition describing a single data member of a data structure.
Definition: Field.h:68
Simple method definition.
Definition: Method.h:72
@ World
Position given in world space coordinates.
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
@ Right
The rightmost character is placed to the left of the screen position.
@ Left
The leftmost character is placed to the right of the screen position.
@ Perspective
Perspective projection.
@ Center
Center the text on the screen position.
Contains geometry calculations and generation.
Contains reflection support.
Definition: Component.h:11
void setChanged(Cogs::Core::Context *context, Cogs::ComponentModel::Component *component, Reflection::FieldId fieldId)
Must be Called after changing a Component field. Mark field changed. Request engine update.
Definition: FieldSetter.h:25
glm::vec3 autoAdjustMargin
A margin applied to the bounding box of the encased Entity, this property only works alongside autoNo...
glm::vec3 unitScales
Size of unit coordinate axis in unitname-units.
glm::vec3 minCorner
Minimum corner of the cube.
std::vector< std::string > unitNames
Name of the x,y,z-axis units.
glm::vec3 maxCorner
Maximum corner of the cube.
int maxAxisValues
The maximum number of axis annotation values to use.
bool useAxisAnnotations
If the axis cube should create axis annotation text.
std::vector< WeakEntityPtr > autoNodes
Entities(Nodes) that are to be encased by this AxisCube.
glm::vec4 textColor
Color of text, to be forwarded to children.
bool autoAdjustToLargestDimension
If the auto adjustment should make the box equal in size along all axes.
float zScale
Amount to scale the z-axis.
std::vector< std::string > axisTitles
Titles for the x,y,z-axises.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ LineList
List of lines.
Definition: Common.h:120
@ TriangleStrip
Triangle strip.
Definition: Common.h:118
Represents an unique name.
Definition: Name.h:70