Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed Jun 28, 2024
1 parent e3da262 commit 6d0a16d
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import nz.net.ultraq.redhorizon.engine.graphics.VertexBufferLayout
import nz.net.ultraq.redhorizon.engine.resources.ResourceManager
import nz.net.ultraq.redhorizon.engine.scenegraph.GraphicsElement
import nz.net.ultraq.redhorizon.engine.scenegraph.Node
import nz.net.ultraq.redhorizon.engine.scenegraph.PartitionHint
import nz.net.ultraq.redhorizon.engine.scenegraph.Scene
import nz.net.ultraq.redhorizon.engine.scenegraph.nodes.Primitive
import nz.net.ultraq.redhorizon.filetypes.ColourFormat
Expand Down Expand Up @@ -269,6 +270,7 @@ class Map extends Node<Map> {
return scene.requestCreateOrGet(new SpriteSheetRequest(spriteWidth, spriteHeight, tileFile.format, imageData))
})
backgroundSprite.setPosition(boundary.minX, boundary.minY)
backgroundSprite.partitionHint = PartitionHint.LargeArea
addChild(backgroundSprite)
}
}
Expand All @@ -286,6 +288,8 @@ class Map extends Node<Map> {
*/
private class MapPack extends Node<MapPack> implements GraphicsElement {

PartitionHint partitionHint = PartitionHint.LargeArea

private final List<MapTile> mapTiles = []
private Mesh fullMesh
private Shader shader
Expand Down Expand Up @@ -471,6 +475,8 @@ class Map extends Node<Map> {
overlay.name = "${tile.name} - Variant ${imageVariant}"
overlay.initialFrame = imageVariant
overlay.position = new Vector2f(tilePos).asWorldCoords(1)
overlay.partitionHint = PartitionHint.SmallArea

addChild(overlay)

numTiles++
Expand Down Expand Up @@ -499,6 +505,7 @@ class Map extends Node<Map> {
var terrain = new PalettedSprite(terrainFile)
terrain.name = "Terrain ${terrainType}"
terrain.position = cellPosXY
terrain.partitionHint = PartitionHint.SmallArea
addChild(terrain)
}
}
Expand Down Expand Up @@ -644,6 +651,7 @@ class Map extends Node<Map> {
})
bibSprite.name = "Bib"
bibSprite.setPosition(0, -TILE_HEIGHT)
bibSprite.partitionHint = PartitionHint.SmallArea
structure.addChild(bibSprite, 0)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import nz.net.ultraq.redhorizon.classic.nodes.Rotatable
import nz.net.ultraq.redhorizon.engine.graphics.GraphicsRequests.SpriteSheetRequest
import nz.net.ultraq.redhorizon.engine.graphics.SpriteSheet
import nz.net.ultraq.redhorizon.engine.scenegraph.Node
import nz.net.ultraq.redhorizon.engine.scenegraph.PartitionHint
import nz.net.ultraq.redhorizon.engine.scenegraph.Scene
import nz.net.ultraq.redhorizon.engine.scenegraph.Temporal
import nz.net.ultraq.redhorizon.filetypes.ImagesFile
Expand All @@ -45,6 +46,8 @@ class Unit extends Node<Unit> implements FactionColours, Rotatable, Temporal {
*/
static final String DEFAULT_STATE = "default"

PartitionHint partitionHint = PartitionHint.SmallArea

// TODO: Should this type of file be renamed to better reflect its purpose?
final ImagesFile imagesFile
final UnitData unitData
Expand Down Expand Up @@ -179,6 +182,7 @@ class Unit extends Node<Unit> implements FactionColours, Rotatable, Temporal {
private class UnitBody extends PalettedSprite {

private final UnitData unitData
PartitionHint partitionHint = PartitionHint.SmallArea

UnitBody(ImagesFile imagesFile, UnitData unitData) {

Expand Down Expand Up @@ -222,6 +226,8 @@ class Unit extends Node<Unit> implements FactionColours, Rotatable, Temporal {
*/
private class UnitTurret extends PalettedSprite {

PartitionHint partitionHint = PartitionHint.SmallArea

UnitTurret(int width, int height, int numImages, SpriteSheetGenerator spriteSheetGenerator) {
super(width, height, numImages, spriteSheetGenerator)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ import nz.net.ultraq.redhorizon.engine.graphics.imgui.ChangeEvent
import nz.net.ultraq.redhorizon.engine.graphics.imgui.ImGuiLayer
import nz.net.ultraq.redhorizon.engine.input.InputEventStream
import nz.net.ultraq.redhorizon.engine.scenegraph.GraphicsElement
import nz.net.ultraq.redhorizon.engine.scenegraph.Node
import nz.net.ultraq.redhorizon.engine.scenegraph.Scene
import nz.net.ultraq.redhorizon.engine.scenegraph.nodes.Camera

import org.joml.FrustumIntersection
import org.joml.Matrix4f
import org.joml.primitives.Rectanglef
import org.slf4j.Logger
Expand Down Expand Up @@ -171,12 +169,8 @@ class RenderPipeline implements AutoCloseable {
private class SceneRenderPass implements RenderPass<Void> {

final Framebuffer framebuffer
private final boolean traverseScene = true
private final FrustumIntersection frustumIntersection = new FrustumIntersection()

Scene scene

// For object culling
private final List<GraphicsElement> visibleElements = []

SceneRenderPass(Framebuffer framebuffer) {
Expand All @@ -202,28 +196,11 @@ class RenderPipeline implements AutoCloseable {
// Cull the list of renderable items to those just visible in the scene
average('objectCulling', 1f, logger) { ->
visibleElements.clear()

if (traverseScene) {
frustumIntersection.set(camera.viewProjection, false)
scene.traverse { Node element ->
if (element.isVisible(frustumIntersection)) {
if (element instanceof GraphicsElement) {
element.update()
element.script?.update()
visibleElements << element
}
return true
}
return false
}
}
else {
scene.quadTree.query(camera.viewBox).each { Node element ->
if (element instanceof GraphicsElement) {
element.update()
element.script?.update()
visibleElements << element
}
scene.query(camera.viewBox).each { element ->
if (element instanceof GraphicsElement) {
element.update()
element.script?.update()
visibleElements << element
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ class Node<T extends Node> implements SceneEvents, Scriptable<T> {
Node parent
CopyOnWriteArrayList<Node> children = new CopyOnWriteArrayList<>()

/**
* A hint to the scenegraph to add this node to an appropriate data structure
* for performance purposes.
*/
PartitionHint partitionHint

private final Vector3f position = new Vector3f()
private final Vector3f scale = new Vector3f(1, 1, 1)
private final Matrix4f globalTransform = new Matrix4f()
Expand All @@ -52,8 +58,12 @@ class Node<T extends Node> implements SceneEvents, Scriptable<T> {
private final Rectanglef globalBounds = new Rectanglef()

/**
* Adds a child node to this node. If an index is specified, then this will
* shift any existing nodes at the given position to the right to make room.
* Adds a child node to this node.
*
* @param child
* @param index
* If specified, then this will shift any existing nodes at the given
* position to the right to make room.
*/
T addChild(Node child, int index = -1) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2024, Emanuel Rabina (http://www.ultraq.net.nz/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package nz.net.ultraq.redhorizon.engine.scenegraph

/**
* A hint to the scene to classify a node with the given partition type. This
* can then be used to add the node to specific data structures that excel in
* certain tasks and provide a performance boost.
*
* @author Emanuel Rabina
*/
enum PartitionHint {

/**
* An object which takes up a significant amount of 2D space.
*/
LargeArea,

/**
* An object which takes up a relatively small amount of 2D space. Nodes with
* this partition hint can end up in a quadtree data structure which is good
* for object culling.
*/
SmallArea
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory

import groovy.transform.TupleConstructor
import java.util.concurrent.CopyOnWriteArrayList

/**
* Entry point for the Red Horizon scene graph, holds all of the objects that
Expand Down Expand Up @@ -61,18 +62,26 @@ class Scene implements EventTarget {
@Delegate(includes = ['addChild', 'clear', 'findNode', 'leftShift', 'removeChild', 'traverse'], interfaces = false)
final Node root = new RootNode(this)

// Partition static objects in the quadTree to make culling queries faster
final QuadTree quadTree = new QuadTree(new Rectanglef(-1536, -1536, 1536, 1536))
// Partition objects in the following data structures to make queries faster
private final QuadTree quadTree = new QuadTree(new Rectanglef(-1536, -1536, 1536, 1536))
private final CopyOnWriteArrayList<Node> nodeList = []

Scene() {

on(NodeAddedEvent) { event ->
if (event.node instanceof GraphicsElement) {
quadTree.add(event.node)
var node = event.node
if (node.partitionHint == PartitionHint.SmallArea) {
quadTree.add(node)
}
else {
nodeList.add(node)
}
}
on(NodeRemovedEvent) { event ->
quadTree.remove(event.node)
var node = event.node
if (!quadTree.remove(node)) {
nodeList.remove(node)
}
}
}

Expand All @@ -99,7 +108,19 @@ class Scene implements EventTarget {
}
}

// List<Node> findAll()
/**
* Return all nodes that are within the bounding box of {@code range}.
*/
List<Node> query(Rectanglef range, List<Node> results = []) {

nodeList.each { node ->
if (range.containsRectangle(node.bounds) || range.intersectsRectangle(node.bounds)) {
results << node
}
}
quadTree.query(range, results)
return results
}

/**
* Select objects whose bounding volumes intersect the given ray.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class QuadTree {
private final QuadTree parent
private final Rectanglef area
private final int capacity
private BlockingQueue<Node> children // Needs a different name from the Node property
// TODO: Make this quadtree accept any element that can return a Vector2f position
private BlockingQueue<Node> children
private List<QuadTree> quadrants // Going from NW, NE, SE, SW

/**
Expand Down Expand Up @@ -135,7 +136,7 @@ class QuadTree {
/**
* Return all nodes that are within the bounding box of {@code range}.
*/
List<Node> query(Rectanglef range, List<Node> results = new ArrayList<>()) {
List<Node> query(Rectanglef range, List<Node> results = []) {

if (area.intersectsRectangle(range)) {
if (children) {
Expand All @@ -151,6 +152,8 @@ class QuadTree {
/**
* Removes a node from this quadtree. Nodes will attempt to rebalance
* themselves if quadrants can also be removed.
*
* @return {@code true} if the node was removed from the quadtree.
*/
synchronized boolean remove(Node node) {

Expand Down

0 comments on commit 6d0a16d

Please sign in to comment.