From 4f6c6d5a5820a1c10caa368cba3b8e8ac3818d5d Mon Sep 17 00:00:00 2001 From: Emanuel Rabina Date: Wed, 7 Feb 2024 23:42:16 +1300 Subject: [PATCH] Calculate and return global transforms --- .../graphics/pipeline/RenderPipeline.groovy | 7 ++-- .../redhorizon/engine/scenegraph/Node.groovy | 41 ++++++++++++++++++- .../engine/scenegraph/nodes/Sprite.groovy | 9 ++-- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/pipeline/RenderPipeline.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/pipeline/RenderPipeline.groovy index 28752707..e3f99c0e 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/pipeline/RenderPipeline.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/graphics/pipeline/RenderPipeline.groovy @@ -31,6 +31,7 @@ import nz.net.ultraq.redhorizon.engine.graphics.imgui.ChangeEvent import nz.net.ultraq.redhorizon.engine.graphics.imgui.ControlsOverlayRenderPass import nz.net.ultraq.redhorizon.engine.graphics.imgui.ImGuiLayer import nz.net.ultraq.redhorizon.engine.input.InputEventStream +import nz.net.ultraq.redhorizon.engine.scenegraph.Node import nz.net.ultraq.redhorizon.engine.scenegraph.Scene import org.joml.FrustumIntersection @@ -211,9 +212,9 @@ class RenderPipeline implements AutoCloseable { // Cull the list of renderable items to those just visible in the scene averageNanos('objectCulling', 1f, logger) { -> visibleElements.clear() - def frustumIntersection = new FrustumIntersection(camera.projection * camera.view) - scene.accept { element -> - if (element instanceof GraphicsElement && frustumIntersection.testPlaneXY(element.bounds)) { + var frustumIntersection = new FrustumIntersection(camera.projection * camera.view) + scene.accept { Node element -> + if (element instanceof GraphicsElement && frustumIntersection.testPlaneXY(element.globalBounds)) { visibleElements << element } } diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy index 9be55c07..eabf8533 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/Node.groovy @@ -34,7 +34,12 @@ class Node implements SceneEvents, Scriptable, Visitable { final Rectanglef bounds = new Rectanglef() protected Node parent - protected final List children = [] + protected List children = [] + + private final Rectanglef globalBounds = new Rectanglef() + private final Matrix4f globalTransform = new Matrix4f() + private final Vector3f globalScale = new Vector3f() + private final Vector3f globalTranslate = new Vector3f() @Override void accept(SceneVisitor visitor) { @@ -56,6 +61,40 @@ class Node implements SceneEvents, Scriptable, Visitable { return this } + /** + * Return the world-space bounds of this node. ie: the local bounds, then + * taking into account local and all parent/ancestor transforms along the path + * to this node. + * + * @return + */ + // TODO: Surely this is inefficient having to calculate this each time? 🤔 + Rectanglef getGlobalBounds() { + + getGlobalTransform() + var scale = globalTransform.getScale(globalScale) + var translate = globalTransform.getTranslation(globalTranslate) + return globalBounds.set(bounds) + .scale(scale.x, scale.y) + .translate(translate.x, translate.y) + } + + /** + * Get the world-space transform of this node. ie: the local transform, then + * modified by all of the ancestor transforms along the path to this node. + * The result is stored in the private {@code globalTransform} property, and + * returned. + * + * @return + */ + // TODO: Surely this is inefficient having to calculate this each time? 🤔 + private Matrix4f getGlobalTransform() { + + return parent != null ? + globalTransform.mul(parent.globalTransform) : + globalTransform.set(transform) + } + /** * An alias for {@link #addChild(Node)} * diff --git a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Sprite.groovy b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Sprite.groovy index 69e00727..cbe96916 100644 --- a/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Sprite.groovy +++ b/redhorizon-engine/source/nz/net/ultraq/redhorizon/engine/scenegraph/nodes/Sprite.groovy @@ -31,8 +31,6 @@ import nz.net.ultraq.redhorizon.filetypes.ImageFile import org.joml.primitives.Rectanglef -import groovy.transform.TupleConstructor - /** * A simple 2D sprite node. Contains a texture and coordinate data for what * parts of that texture to render (ie: the texture represents a larger sprite @@ -40,7 +38,6 @@ import groovy.transform.TupleConstructor * * @author Emanuel Rabina */ -@TupleConstructor(includes = ['imageFile']) class Sprite extends Node implements GraphicsElement { final ImageFile imageFile @@ -50,6 +47,12 @@ class Sprite extends Node implements GraphicsElement { private Material material private Rectanglef region + Sprite(ImageFile imageFile) { + + bounds.set(0, 0, imageFile.width, imageFile.height) + this.imageFile = imageFile + } + @Override void delete(GraphicsRenderer renderer) { }