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),
101 Method(
Name(
"initialize"), &AxisCubeComponent::initialize),
102 Method(
Name(
"update"), &AxisCubeComponent::update),
105 DynamicComponent::registerDerivedType<AxisCubeComponent>()
107 .setMethods(methods);
110void Cogs::Core::AxisCubeComponent::initialize(Context * ctx)
115 gridMatInstH = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
116 MaterialInstance* lineMatInst = gridMatInstH.resolve();
117 lineMatInst->setBoolProperty(DefaultMaterial::EnableLighting,
false);
118 lineMatInst->setPermutation(
"Line");
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");
127 for (
int i = 0; i < 6; i++) {
128 PerFaceData& f = faces[i];
130 f.solid = context->store->createChildEntity(
"AxisCubeFace", getContainer());
132 MeshComponent* qMeshComp = f.solid->getComponent<MeshComponent>();
134 qMeshComp->meshHandle = context->meshManager->create();
137 f.grid = context->store->createChildEntity(
"SubMeshPart", getContainer());
139 MeshComponent* meshComp = f.grid->getComponent<MeshComponent>();
141 meshComp->meshHandle = context->meshManager->create();
143 auto meshRenderComp = f.grid->getComponent<SubMeshRenderComponent>();
145 meshRenderComp->setMaterial(gridMatInstH);
146 meshRenderComp->layer = RenderLayers::Annotations;
151 axisTitlesRightEntity = context->store->createChildEntity(
"Text", getContainer());
152 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
157 axisTitlesLeftEntity = context->store->createChildEntity(
"Text", getContainer());
158 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
163 for (
int i = 0; i < 12; i++) {
164 PerEdgeData& e = edges[i];
166 e.annotationEntity = context->store->createChildEntity(
"AxisCubeEdge", getContainer());
168 MeshComponent* meshComp = e.annotationEntity->getComponent<MeshComponent>();
170 meshComp->meshHandle = context->meshManager->create();
173 auto meshRenderComp = e.annotationEntity->getComponent<SubMeshRenderComponent>();
174 meshRenderComp->setMaterial(edgeMatInstH);
175 meshRenderComp->layer = RenderLayers::Annotations;
178 initialUpdate =
true;
181void Cogs::Core::AxisCubeComponent::update()
183 auto transformComponent = getComponent<TransformComponent>();
185 worldToLocal = glm::inverse(context->transformSystem->getLocalToWorld(transformComponent));
188 if (!unprocessedAutoNodes.empty()) {
189 auto bbox = Geometry::makeEmptyBoundingBox<Geometry::BoundingBox>();
191 for (
auto & entity : unprocessedAutoNodes){
192 auto transComp = entity->getComponent<TransformComponent>();
193 auto meshComp = entity->getComponent<MeshComponent>();
195 if (meshComp && transComp) {
197 const auto & bboxNode = context->renderSystem->getWorldBounds(entity->getComponent<MeshRenderComponent>());
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,
205 bbox += (1.f / pw.w) * glm::vec3(pw.x, pw.y, pw.z);
210 unprocessedAutoNodes.clear();
215 if (!isEmpty(bbox)) {
216 minCorner = bbox.min - autoAdjustMargin;
217 maxCorner = bbox.max + autoAdjustMargin;
226 if (!autoNodes.empty()) {
227 for (
auto & n : autoNodes) {
228 auto locked = n.lock();
231 unprocessedAutoNodes.push_back(locked);
237 if (initialUpdate || hasChanged()) {
238 if (glm::all(glm::lessThanEqual(minCorner, maxCorner))) {
239 updateAdjustedMinAndMax(minCorner, maxCorner);
245 updateQuadGeometry(0, topQuadMaterial);
246 updateQuadGeometry(1, bottomQuadMaterial);
247 updateQuadGeometry(2, frontQuadMaterial);
248 updateQuadGeometry(3, backQuadMaterial);
249 updateQuadGeometry(4, rightQuadMaterial);
250 updateQuadGeometry(5, leftQuadMaterial);
252 for (
int i = 0; i < 6; i++) {
253 updateGridGeometry(i);
256 updateAnnotationAxes();
258 updateFaceVisibilites(
true);
259 updateEdgeVisibilites(
true);
260 updateAxisLabels(
true);
262 updateFaceVisibilites(
false);
263 updateEdgeVisibilites(
false);
264 updateAxisLabels(
false);
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);
273 initialUpdate =
false;
276void Cogs::Core::AxisCubeComponent::updateAnnotationAxes()
278 for (
int i = 0; i < 12; i++) {
279 auto & edgeData = edges[i];
280 edgeData.visible = useAxisAnnotations;
282 auto text = edgeData.annotationEntity->getComponent<TextComponent>();
283 text->color = textColor;
284 text->getComponent<SpriteRenderComponent>()->setVisible(edgeData.visible);
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();
295 auto mesh = edgeData.annotationEntity->getComponent<MeshComponent>()->meshHandle;
297 std::array<uint32_t, 2> I = { 0, 1 };
298 mesh->setVertexData(V, 2);
299 mesh->clearIndexes();
303 if (!useAxisAnnotations)
return;
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]));
312 for (
int k = 0; k < 4; k++) {
316 auto aaComp = edges[i_].annotationEntity->getComponent<AnnotationAxisComponent>();
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);
322 for (
int i = l; i <= u; i++) {
324 float uu = tickSizes[a] * i;
325 p[a] = (uu* (a == 2 ? zScale : 1.f)) / unitScales[a];
328 o << uu << unitNames[a];
330 aaComp->positions.push_back(p);
331 aaComp->strings.push_back(o.str());
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]);
343void Cogs::Core::AxisCubeComponent::updateCorners()
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;
352void Cogs::Core::AxisCubeComponent::updateAdjustedMinAndMax(
const glm::vec3 & minCorner,
const glm::vec3 & maxCorner)
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);
361 adjustedMinCorner = minCorner;
362 adjustedMaxCorner = maxCorner;
366void Cogs::Core::AxisCubeComponent::updateTickSizes()
368 glm::vec3 l = adjustedMaxCorner - adjustedMinCorner;
369 tickProtrusion = std::min(100.f, tickSizeOffset*(0.5f / 3.f)*(l.x + l.y + l.z));
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);
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);
399void Cogs::Core::AxisCubeComponent::updateEdgeVisibilites(
bool forceUpdate)
401 for (
int i = 0; i < 12; i++) {
402 PerEdgeData& e = edges[i];
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);
412 TextComponent * text = e.annotationEntity->getComponent<TextComponent>();
413 text->getComponent<SpriteRenderComponent>()->setVisible(visible);
421void Cogs::Core::AxisCubeComponent::updateAxisLabels(
bool )
424 using std::accumulate;
425 using std::numeric_limits;
427 auto camComp = context->cameraSystem->getMainCamera();
428 auto & camData = context->cameraSystem->getData(camComp);
429 auto trComp = getComponent<TransformComponent>();
431 mat4 localToClip = camData.viewProjection * context->transformSystem->getLocalToWorld(trComp);
433 vec3 cubeMidLocal = (1.f/8.f)*accumulate(corners, corners + 8, vec3(0.f));
435 auto textRendLeftComp = axisTitlesRightEntity->getComponent<TextComponent>();
436 textRendLeftComp->color = textColor;
437 textRendLeftComp->texts.clear();
438 textRendLeftComp->positions.clear();
440 auto textRendRightComp = axisTitlesLeftEntity->getComponent<TextComponent>();
441 textRendRightComp->color = textColor;
442 textRendRightComp->texts.clear();
443 textRendRightComp->positions.clear();
445 vec3 viewXLocal(localToClip[0][0], localToClip[1][0], localToClip[2][0]);
446 vec3 viewZLocal(localToClip[0][2], localToClip[1][2], localToClip[2][2]);
448 axisTitles.resize(3);
449 for (
int i = 0; i < 3; i++) {
450 if (axisTitles[i].empty())
continue;
453 for (
int j = 0; j < 4; j++) {
455 if (faces[edgeDefinitions[e].nb[0]].visible != faces[edgeDefinitions[e].nb[1]].visible) {
458 vec3 edgeMidLocal = (1.f / 2.f)*(corners[edgeDefinitions[e].ix[0]] + corners[edgeDefinitions[e].ix[1]]);
459 vec3 edgeDirLocal = normalize(edgeMidLocal - cubeMidLocal);
462 vec3 edgeDirInViewPlaneLocal = edgeDirLocal - (dot(edgeDirLocal, viewZLocal) / dot(viewZLocal, viewZLocal))*viewZLocal;
465 if (dot(viewXLocal, edgeDirInViewPlaneLocal) < 0.f) {
466 textRendLeftComp->texts.push_back(axisTitles[i]);
467 textRendLeftComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
469 textRendRightComp->texts.push_back(axisTitles[i]);
470 textRendRightComp->positions.push_back(edgeMidLocal + 8.f*tickProtrusion * edgeDirInViewPlaneLocal);
476 textRendLeftComp->setChanged();
477 textRendRightComp->setChanged();
480void Cogs::Core::AxisCubeComponent::updateFaceVisibilites(
bool forceUpdate)
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);
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;
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;
511 refVec = viewDirLocalSpace;
516 for (
int face = 0; face < 6; face++) {
517 PerFaceData& f = faces[face];
519 bool visible = glm::dot(refVec, f.equation) >= 0.f;
521 if (forceUpdate || (f.visible != visible)) {
522 auto qMeshRC = f.solid->getComponent<RenderComponent>();
523 qMeshRC->setVisible(visible);
524 qMeshRC->setChanged();
526 auto lMeshRC = f.grid->getComponent<RenderComponent>();
527 lMeshRC->setVisible(visible);
528 lMeshRC->setChanged();
536void Cogs::Core::AxisCubeComponent::updateQuadGeometry(
int face,
EntityPtr material)
538 PerFaceData & f = faces[face];
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]];
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));
549 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
552 qMesh->setVertexData(V, 4);
554 auto materialComponent = f.solid->getComponent<MaterialComponent>();
555 materialComponent->material = material;
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;
564 masterMaterialComponent->depthBiasConstant = 2.0f;
565 masterMaterialComponent->depthBiasSlope = 2.0f;
568 qMesh->clearIndexes();
569 std::array<uint32_t, 4> I{ 0, 1, 3, 2 };
572 auto qMesh = context->meshManager->get(f.solid->getComponent<MeshComponent>()->meshHandle);
573 qMesh->clearIndexes();
577void Cogs::Core::AxisCubeComponent::updateGridGeometry(
int face)
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]];
583 glm::vec3 tap = -tickProtrusion*glm::normalize(glm::cross(p1 - p0, p2 - p0));
585 const glm::vec2 t0 = faceDefinitions[face].proj*p0;
586 const glm::vec2 t2 = faceDefinitions[face].proj*p2;
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)));
592 const glm::mat2x3 projTr = glm::transpose(faceDefinitions[face].proj);
594 std::vector<Cogs::Core::PositionVertex> V;
595 std::vector<unsigned int> I;
597 glm::ivec2 ll(glm::ceil(t0*scale / ticks));
598 glm::ivec2 ur(glm::floor(t2*scale / ticks));
600 for (
int k = 0; k < 2; k++) {
601 glm::vec3 keep = glm::vec3(1.f) - projTr[k];
604 if (ur[k] - ll[k] < 3)
continue;
606 for (
int i = ll[k] + 1; i <= ur[k] - 1; i++) {
607 int o =
static_cast<int>(V.size());
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 });
625 auto mesh = context->meshManager->get(faces[face].grid->getComponent<MeshComponent>()->meshHandle);
627 mesh->setVertexData(V.data(), V.size());
628 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.
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.
@ TriangleStrip
Triangle strip.
Represents an unique name.