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