1#include "AxisCubeComponent.h"
5#include "EntityStore.h"
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"
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"
21#include "Systems/Core/CameraSystem.h"
22#include "Systems/Core/TransformSystem.h"
23#include "Systems/Core/MeshSystem.h"
24#include "Systems/Core/RenderSystem.h"
26#include "Foundation/Geometry/BoundingBox.hpp"
41 } faceDefinitions[6] =
43 { { 4, 6, 7, 5 }, { glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f) } },
44 { { 0, 1, 3, 2 }, { glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f) } },
45 { { 0, 4, 5, 1 }, { glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f) } },
46 { { 2, 3, 7, 6 }, { glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f) } },
47 { { 1, 5, 7, 3 }, { glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f) } },
48 { { 0, 2, 6, 4 }, { glm::vec2(0.f, 0.f), glm::vec2(0.f, 1.f), glm::vec2(1.f, 0.f) } }
55 } edgeDefinitions[12] = {
57 { { 0, 1 }, { 2, 1 } },
58 { { 2, 3 }, { 1, 3 } },
59 { { 6, 7 }, { 3, 0 } },
60 { { 4, 5 }, { 0, 2 } },
62 { { 0, 2 }, { 5, 1 } },
63 { { 1, 3 }, { 1, 4 } },
64 { { 5, 7 }, { 4, 0 } },
65 { { 4, 6 }, { 0, 5 } },
67 { { 0, 4 }, { 5, 2 } },
68 { { 1, 5 }, { 2, 4 } },
69 { { 3, 7 }, { 4, 3 } },
70 { { 2, 6 }, { 3, 5 } }
74void Cogs::Core::AxisCubeComponent::registerType()
89 Field(
Name(
"tickSizeOffset"), &AxisCubeComponent::tickSizeOffset),
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)
102 Method(
Name(
"initialize"), &AxisCubeComponent::initialize),
103 Method(
Name(
"update"), &AxisCubeComponent::update),
106 DynamicComponent::registerDerivedType<AxisCubeComponent>()
108 .setMethods(methods);
111void Cogs::Core::AxisCubeComponent::initialize(Context * ctx)
116 gridMatInstH = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
117 MaterialInstance* lineMatInst = gridMatInstH.resolve();
118 lineMatInst->setBoolProperty(DefaultMaterial::EnableLighting,
false);
119 lineMatInst->setPermutation(
"Line");
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");
128 for (
int i = 0; i < 6; i++) {
129 PerFaceData& f = faces[i];
131 f.solid = context->store->createChildEntity(
"AxisCubeFace", getContainer());
133 MeshComponent* qMeshComp = f.solid->getComponent<MeshComponent>();
135 qMeshComp->meshHandle = context->meshManager->create();
138 f.grid = context->store->createChildEntity(
"SubMeshPart", getContainer());
140 MeshComponent* meshComp = f.grid->getComponent<MeshComponent>();
142 meshComp->meshHandle = context->meshManager->create();
144 auto meshRenderComp = f.grid->getComponent<SubMeshRenderComponent>();
146 meshRenderComp->setMaterial(gridMatInstH);
147 meshRenderComp->layer = renderLayer;
152 axisTitlesRightEntity = context->store->createChildEntity(
"Text", getContainer());
153 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
158 axisTitlesLeftEntity = context->store->createChildEntity(
"Text", getContainer());
159 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
164 for (
int i = 0; i < 12; i++) {
165 PerEdgeData& e = edges[i];
167 e.annotationEntity = context->store->createChildEntity(
"AxisCubeEdge", getContainer());
169 MeshComponent* meshComp = e.annotationEntity->getComponent<MeshComponent>();
171 meshComp->meshHandle = context->meshManager->create();
174 auto meshRenderComp = e.annotationEntity->getComponent<SubMeshRenderComponent>();
175 meshRenderComp->setMaterial(edgeMatInstH);
176 meshRenderComp->layer = renderLayer;
179 initialUpdate =
true;
182void Cogs::Core::AxisCubeComponent::update()
184 auto transformComponent = getComponent<TransformComponent>();
186 worldToLocal = glm::inverse(context->transformSystem->getLocalToWorld(transformComponent));
189 if (!unprocessedAutoNodes.empty()) {
190 auto bbox = Geometry::makeEmptyBoundingBox<Geometry::BoundingBox>();
192 for (
auto & entity : unprocessedAutoNodes){
193 auto transComp = entity->getComponent<TransformComponent>();
194 auto meshComp = entity->getComponent<MeshComponent>();
196 if (meshComp && transComp) {
198 const auto & bboxNode = context->renderSystem->getWorldBounds(entity->getComponent<MeshRenderComponent>());
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,
206 bbox += (1.f / pw.w) * glm::vec3(pw.x, pw.y, pw.z);
211 unprocessedAutoNodes.clear();
216 if (!isEmpty(bbox)) {
217 minCorner = bbox.min - autoAdjustMargin;
218 maxCorner = bbox.max + autoAdjustMargin;
227 if (!autoNodes.empty()) {
228 for (
auto & n : autoNodes) {
229 auto locked = n.lock();
232 unprocessedAutoNodes.push_back(locked);
238 if (initialUpdate || hasChanged()) {
239 if (glm::all(glm::lessThanEqual(minCorner, maxCorner))) {
240 updateAdjustedMinAndMax(minCorner, maxCorner);
246 updateQuadGeometry(0, topQuadMaterial);
247 updateQuadGeometry(1, bottomQuadMaterial);
248 updateQuadGeometry(2, frontQuadMaterial);
249 updateQuadGeometry(3, backQuadMaterial);
250 updateQuadGeometry(4, rightQuadMaterial);
251 updateQuadGeometry(5, leftQuadMaterial);
253 for (
int i = 0; i < 6; i++) {
254 updateGridGeometry(i);
257 updateAnnotationAxes();
259 updateFaceVisibilites(
true);
260 updateEdgeVisibilites(
true);
261 updateAxisLabels(
true);
263 updateFaceVisibilites(
false);
264 updateEdgeVisibilites(
false);
265 updateAxisLabels(
false);
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);
274 initialUpdate =
false;
277void Cogs::Core::AxisCubeComponent::updateAnnotationAxes()
279 for (
int i = 0; i < 12; i++) {
280 auto & edgeData = edges[i];
281 edgeData.visible = useAxisAnnotations;
283 auto text = edgeData.annotationEntity->getComponent<TextComponent>();
284 text->color = textColor;
285 text->getComponent<SpriteRenderComponent>()->setVisible(edgeData.visible);
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();
296 auto mesh = edgeData.annotationEntity->getComponent<MeshComponent>()->meshHandle;
298 std::array<uint32_t, 2> I = { 0, 1 };
299 mesh->setVertexData(V, 2);
300 mesh->clearIndexes();
304 if (!useAxisAnnotations)
return;
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]));
313 for (
int k = 0; k < 4; k++) {
317 auto aaComp = edges[i_].annotationEntity->getComponent<AnnotationAxisComponent>();
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);
323 for (
int i = l; i <= u; i++) {
325 float uu = tickSizes[a] * i;
326 p[a] = (uu* (a == 2 ? zScale : 1.f)) / unitScales[a];
329 o << uu << unitNames[a];
331 aaComp->positions.push_back(p);
332 aaComp->strings.push_back(o.str());
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]);
344void Cogs::Core::AxisCubeComponent::updateCorners()
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;
353void Cogs::Core::AxisCubeComponent::updateAdjustedMinAndMax(
const glm::vec3 & minCorner,
const glm::vec3 & maxCorner)
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);
362 adjustedMinCorner = minCorner;
363 adjustedMaxCorner = maxCorner;
367void Cogs::Core::AxisCubeComponent::updateTickSizes()
369 glm::vec3 l = adjustedMaxCorner - adjustedMinCorner;
370 tickProtrusion = std::min(100.f, tickSizeOffset*(0.5f / 3.f)*(l.x + l.y + l.z));
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);
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);
400void Cogs::Core::AxisCubeComponent::updateEdgeVisibilites(
bool forceUpdate)
402 for (
int i = 0; i < 12; i++) {
403 PerEdgeData& e = edges[i];
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);
413 TextComponent * text = e.annotationEntity->getComponent<TextComponent>();
414 text->getComponent<SpriteRenderComponent>()->setVisible(visible);
422void Cogs::Core::AxisCubeComponent::updateAxisLabels(
bool )
425 using std::accumulate;
426 using std::numeric_limits;
428 auto camComp = context->cameraSystem->getMainCamera();
429 auto & camData = context->cameraSystem->getData(camComp);
430 auto trComp = getComponent<TransformComponent>();
432 mat4 localToClip = camData.viewProjection * context->transformSystem->getLocalToWorld(trComp);
434 vec3 cubeMidLocal = (1.f/8.f)*accumulate(corners, corners + 8, vec3(0.f));
436 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
437 textRendLeftComp->color = textColor;
438 textRendLeftComp->texts.clear();
439 textRendLeftComp->positions.clear();
441 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
442 textRendRightComp->color = textColor;
443 textRendRightComp->texts.clear();
444 textRendRightComp->positions.clear();
446 vec3 viewXLocal(localToClip[0][0], localToClip[1][0], localToClip[2][0]);
447 vec3 viewZLocal(localToClip[0][2], localToClip[1][2], localToClip[2][2]);
449 axisTitles.resize(3);
450 for (
int i = 0; i < 3; i++) {
451 if (axisTitles[i].empty())
continue;
454 for (
int j = 0; j < 4; j++) {
456 if (faces[edgeDefinitions[e].nb[0]].visible != faces[edgeDefinitions[e].nb[1]].visible) {
459 vec3 edgeMidLocal = (1.f / 2.f)*(corners[edgeDefinitions[e].ix[0]] + corners[edgeDefinitions[e].ix[1]]);
460 vec3 edgeDirLocal = normalize(edgeMidLocal - cubeMidLocal);
463 vec3 edgeDirInViewPlaneLocal = edgeDirLocal - (dot(edgeDirLocal, viewZLocal) / dot(viewZLocal, viewZLocal))*viewZLocal;
466 if (dot(viewXLocal, edgeDirInViewPlaneLocal) < 0.f) {
467 textRendLeftComp->texts.push_back(axisTitles[i]);
468 textRendLeftComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
470 textRendRightComp->texts.push_back(axisTitles[i]);
471 textRendRightComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
477 textRendLeftComp->setChanged();
478 textRendRightComp->setChanged();
481void Cogs::Core::AxisCubeComponent::updateFaceVisibilites(
bool forceUpdate)
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);
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;
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;
512 refVec = viewDirLocalSpace;
517 for (
int face = 0; face < 6; face++) {
518 PerFaceData& f = faces[face];
520 bool visible = glm::dot(refVec, f.equation) >= 0.f;
522 if (forceUpdate || (f.visible != visible)) {
523 auto qMeshRC = f.solid->getComponent<RenderComponent>();
524 qMeshRC->setVisible(visible);
525 qMeshRC->setChanged();
527 auto lMeshRC = f.grid->getComponent<RenderComponent>();
528 lMeshRC->setVisible(visible);
529 lMeshRC->setChanged();
537void Cogs::Core::AxisCubeComponent::updateQuadGeometry(
int face,
EntityPtr material)
539 PerFaceData & f = faces[face];
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]];
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));
550 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
553 qMesh->setVertexData(V, 4);
555 auto materialComponent = f.solid->getComponent<MaterialComponent>();
556 materialComponent->material = material;
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;
565 masterMaterialComponent->depthBiasConstant = 2.0f;
566 masterMaterialComponent->depthBiasSlope = 2.0f;
569 qMesh->clearIndexes();
570 std::array<uint32_t, 4> I{ 0, 1, 3, 2 };
573 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
574 qMesh->clearIndexes();
578void Cogs::Core::AxisCubeComponent::updateGridGeometry(
int face)
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]];
584 glm::vec3 tap = -tickProtrusion*glm::normalize(glm::cross(p1 - p0, p2 - p0));
586 const glm::vec2 t0 = faceDefinitions[face].proj*p0;
587 const glm::vec2 t2 = faceDefinitions[face].proj*p2;
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)));
593 const glm::mat2x3 projTr = glm::transpose(faceDefinitions[face].proj);
595 std::vector<Cogs::Core::PositionVertex> V;
596 std::vector<unsigned int> I;
598 glm::ivec2 ll(glm::ceil(t0*scale / ticks));
599 glm::ivec2 ur(glm::floor(t2*scale / ticks));
601 for (
int k = 0; k < 2; k++) {
602 glm::vec3 keep = glm::vec3(1.f) - projTr[k];
605 if (ur[k] - ll[k] < 3)
continue;
607 for (
int i = ll[k] + 1; i <= ur[k] - 1; i++) {
608 int o =
static_cast<int>(V.size());
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 });
626 auto mesh = context->meshManager->get(faces[face].grid->getComponent<MeshComponent>()->meshHandle);
628 mesh->setVertexData(V.data(), V.size());
629 mesh->clearIndexes();
Field definition describing a single data member of a data structure.
Simple method definition.
@ World
Position given in world space coordinates.
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
@ 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.
@ TriangleStrip
Triangle strip.
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.
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.