diff --git a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java index 247272eca68..d887329c29d 100644 --- a/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java +++ b/engine/src/main/java/org/terasology/engine/subsystem/headless/renderer/HeadlessWorldRenderer.java @@ -294,5 +294,4 @@ public int compare(RenderableChunk o1, RenderableChunk o2) { return distance2 > distance ? -1 : 1; } } - } diff --git a/engine/src/main/java/org/terasology/rendering/dag/AbstractNode.java b/engine/src/main/java/org/terasology/rendering/dag/AbstractNode.java index fff2c1d4847..3bbc336c36e 100644 --- a/engine/src/main/java/org/terasology/rendering/dag/AbstractNode.java +++ b/engine/src/main/java/org/terasology/rendering/dag/AbstractNode.java @@ -36,6 +36,8 @@ public abstract class AbstractNode implements Node { protected static final Logger logger = LoggerFactory.getLogger(AbstractNode.class); + private SimpleUri nodeUri; + private Set desiredStateChanges = Sets.newLinkedHashSet(); private Map fboUsages = Maps.newHashMap(); private boolean enabled = true; @@ -95,6 +97,19 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + @Override + public void setUri(SimpleUri nodeUri) { + this.nodeUri = nodeUri; + } + + @Override + public SimpleUri getUri() { + return nodeUri; + } + + @Override + public void handleCommand(String command, String... arguments) { } + /** * Utility method to conveniently retrieve materials from the Assets system, * hiding the relative complexity of the exception handling. diff --git a/engine/src/main/java/org/terasology/rendering/dag/Node.java b/engine/src/main/java/org/terasology/rendering/dag/Node.java index 2674acc9237..36cc1045ffa 100644 --- a/engine/src/main/java/org/terasology/rendering/dag/Node.java +++ b/engine/src/main/java/org/terasology/rendering/dag/Node.java @@ -17,6 +17,8 @@ //TODO: consider removing the word "Node" from the name of all Node implementations now that they are in the dag.nodes package. +import org.terasology.engine.SimpleUri; + import java.util.Set; /** @@ -31,4 +33,10 @@ public interface Node extends RenderPipelineTask { boolean isEnabled(); void setEnabled(boolean enabled); + + void setUri(SimpleUri nodeUri); + + SimpleUri getUri(); + + void handleCommand(String command, String... arguments); } diff --git a/engine/src/main/java/org/terasology/rendering/dag/RenderGraph.java b/engine/src/main/java/org/terasology/rendering/dag/RenderGraph.java index 6c8bbed5c8b..a474cbde9a4 100644 --- a/engine/src/main/java/org/terasology/rendering/dag/RenderGraph.java +++ b/engine/src/main/java/org/terasology/rendering/dag/RenderGraph.java @@ -16,6 +16,8 @@ package org.terasology.rendering.dag; import com.google.common.collect.Lists; +import org.terasology.engine.SimpleUri; + import java.util.List; /** @@ -28,9 +30,24 @@ public RenderGraph() { nodes = Lists.newArrayList(); } - public String addNode(Node node, String suggestedId) { + public SimpleUri addNode(Node node, String suggestedUri) { nodes.add(node); - return suggestedId; // TODO: for instance if "blur" present make id "blur1" and return it + + // TODO: make sure URIs are actually unique: if "myModule:blur" is present the node gets the uri "myModule:blur2" instead. + // TODO: make sure the namespace in the uri is engine-assigned, so that only engine nodes can have the "engine:" namespace - everything else gets the namespace of the module. + SimpleUri nodeUri = new SimpleUri("engine:" + suggestedUri); + node.setUri(nodeUri); + return nodeUri; + } + + public Node findNode(SimpleUri nodeUri) { + for (Node node: nodes) { + if (node.getUri().equals(nodeUri)) { + return node; + } + } + + return null; } // TODO: add remove, get, addEdge, removeEdge methods here diff --git a/engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToHMDNode.java b/engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToHMDNode.java similarity index 96% rename from engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToHMDNode.java rename to engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToHMDNode.java index 0d019436fbd..b5dda0a920b 100644 --- a/engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToHMDNode.java +++ b/engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToHMDNode.java @@ -40,7 +40,7 @@ import static org.terasology.rendering.opengl.ScalingFactors.FULL_SCALE; import static org.terasology.rendering.opengl.fbms.DisplayResolutionDependentFBOs.FINAL_BUFFER; -public class CopyImageToHMDNode extends ConditionDependentNode { +public class OutputToHMDNode extends ConditionDependentNode { private static final SimpleUri LEFT_EYE_FBO_URI = new SimpleUri("engine:fbo.leftEye"); private static final SimpleUri RIGHT_EYE_FBO_URI = new SimpleUri("engine:fbo.rightEye"); private static final ResourceUrn DEFAULT_TEXTURED_MATERIAL_URN = new ResourceUrn("engine:prog.defaultTextured"); @@ -57,7 +57,7 @@ public class CopyImageToHMDNode extends ConditionDependentNode { * Constructs an instance of this node. Specifically, initialize the vrProvider and pass the frame buffer * information for the vrProvider to use. */ - public CopyImageToHMDNode(Context context) { + public OutputToHMDNode(Context context) { super(context); vrProvider = context.get(OpenVRProvider.class); @@ -89,7 +89,7 @@ public CopyImageToHMDNode(Context context) { */ @Override public void process() { - PerformanceMonitor.startActivity("rendering/copyImageToHMD"); + PerformanceMonitor.startActivity("rendering/outputToHMD"); finalFbo.bindTexture(); renderFinalStereoImage(worldRenderer.getCurrentRenderStage()); PerformanceMonitor.endActivity(); diff --git a/engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToScreenNode.java b/engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToScreenNode.java similarity index 50% rename from engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToScreenNode.java rename to engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToScreenNode.java index 3d4a4b51a1d..b06b9ba2a68 100644 --- a/engine/src/main/java/org/terasology/rendering/dag/nodes/CopyImageToScreenNode.java +++ b/engine/src/main/java/org/terasology/rendering/dag/nodes/OutputToScreenNode.java @@ -18,12 +18,14 @@ import org.lwjgl.opengl.Display; import org.terasology.assets.ResourceUrn; import org.terasology.context.Context; +import org.terasology.engine.SimpleUri; import org.terasology.monitoring.PerformanceMonitor; import org.terasology.rendering.dag.ConditionDependentNode; +import org.terasology.rendering.dag.StateChange; import org.terasology.rendering.dag.stateChanges.EnableMaterial; import org.terasology.rendering.dag.stateChanges.SetInputTextureFromFbo; import org.terasology.rendering.opengl.FBO; -import org.terasology.rendering.opengl.FBOManagerSubscriber; +import org.terasology.rendering.opengl.SwappableFBO; import org.terasology.rendering.opengl.fbms.DisplayResolutionDependentFBOs; import org.terasology.rendering.world.WorldRenderer; @@ -34,24 +36,39 @@ import static org.terasology.rendering.world.WorldRenderer.RenderingStage.LEFT_EYE; import static org.terasology.rendering.world.WorldRenderer.RenderingStage.MONO; -public class CopyImageToScreenNode extends ConditionDependentNode { +public class OutputToScreenNode extends ConditionDependentNode { private static final ResourceUrn DEFAULT_TEXTURED_MATERIAL_URN = new ResourceUrn("engine:prog.defaultTextured"); - public CopyImageToScreenNode(Context context) { + private DisplayResolutionDependentFBOs displayResolutionDependentFBOs; + private WorldRenderer worldRenderer; + + private FBO lastUpdatedGBuffer; + private FBO staleGBuffer; + + private StateChange bindFbo; + + public OutputToScreenNode(Context context) { super(context); + displayResolutionDependentFBOs = context.get(DisplayResolutionDependentFBOs.class); + worldRenderer = context.get(WorldRenderer.class); + WorldRenderer worldRenderer = context.get(WorldRenderer.class); requiresCondition(() -> worldRenderer.getCurrentRenderStage() == MONO || worldRenderer.getCurrentRenderStage() == LEFT_EYE); addDesiredStateChange(new EnableMaterial(DEFAULT_TEXTURED_MATERIAL_URN)); - addDesiredStateChange(new SetInputTextureFromFbo(0, FINAL_BUFFER, ColorTexture, - context.get(DisplayResolutionDependentFBOs.class), DEFAULT_TEXTURED_MATERIAL_URN, "texture")); + bindFbo = new SetInputTextureFromFbo(0, FINAL_BUFFER, ColorTexture, displayResolutionDependentFBOs, DEFAULT_TEXTURED_MATERIAL_URN, "texture"); + addDesiredStateChange(bindFbo); + + SwappableFBO gBufferPair = displayResolutionDependentFBOs.getGBufferPair(); + lastUpdatedGBuffer = gBufferPair.getLastUpdatedFbo(); + staleGBuffer = gBufferPair.getStaleFbo(); } @Override public void process() { - PerformanceMonitor.startActivity("rendering/copyImageToScreen"); + PerformanceMonitor.startActivity("rendering/outputToScreen"); // The way things are set-up right now, we can have FBOs that are not the same size as the display (if scale != 100%). // However, when drawing the final image to the screen, we always want the viewport to match the size of display, // and not that of some FBO. Hence, we are manually setting the viewport via glViewport over here. @@ -59,4 +76,45 @@ public void process() { renderFullscreenQuad(); PerformanceMonitor.endActivity(); } + + @Override + public void handleCommand(String command, String... arguments) { + switch (command) { + case "setFbo": + if (arguments.length != 1) { + throw new RuntimeException("Invalid number of arguments; expected 1, received " + arguments.length + "!"); + } + + FBO fbo; + switch (arguments[0]) { + case "engine:fbo.gBuffer": + case "engine:fbo.lastUpdatedGBuffer": + fbo = lastUpdatedGBuffer; + break; + case "engine:fbo.staleGBuffer": + fbo = staleGBuffer; + break; + default: + fbo = displayResolutionDependentFBOs.get(new SimpleUri(arguments[0])); + + if (fbo == null) { + throw new RuntimeException(("No FBO is associated with URI '" + arguments[0] + "'")); + } + + break; + } + setFbo(fbo); + + break; + default: + throw new RuntimeException("Unrecognized command: '" + command + "'"); + } + } + + private void setFbo(FBO fbo) { + removeDesiredStateChange(bindFbo); + bindFbo = new SetInputTextureFromFbo(0, fbo, ColorTexture, displayResolutionDependentFBOs, DEFAULT_TEXTURED_MATERIAL_URN, "texture"); + addDesiredStateChange(bindFbo); + worldRenderer.requestTaskListRefresh(); + } } diff --git a/engine/src/main/java/org/terasology/rendering/opengl/fbms/DisplayResolutionDependentFBOs.java b/engine/src/main/java/org/terasology/rendering/opengl/fbms/DisplayResolutionDependentFBOs.java index b7fff743f0d..c5d56ad4156 100644 --- a/engine/src/main/java/org/terasology/rendering/opengl/fbms/DisplayResolutionDependentFBOs.java +++ b/engine/src/main/java/org/terasology/rendering/opengl/fbms/DisplayResolutionDependentFBOs.java @@ -31,8 +31,6 @@ * TODO: Better naming */ public class DisplayResolutionDependentFBOs extends AbstractFBOsManager { - public static final SimpleUri READONLY_GBUFFER = new SimpleUri("engine:fbo.readOnlyGBuffer"); - public static final SimpleUri WRITEONLY_GBUFFER = new SimpleUri("engine:fbo.writeOnlyGBuffer"); public static final SimpleUri FINAL_BUFFER = new SimpleUri("engine:fbo.finalBuffer"); private SwappableFBO gBufferPair; @@ -50,13 +48,13 @@ public DisplayResolutionDependentFBOs(RenderingConfig renderingConfig, ScreenGra } private void generateDefaultFBOs() { - FBO readOnlyGBuffer = generateWithDimensions(new FBOConfig(READONLY_GBUFFER, FULL_SCALE, FBO.Type.HDR) + FBO gBuffer1 = generateWithDimensions(new FBOConfig(new SimpleUri("engine:fbo.gBuffer1"), FULL_SCALE, FBO.Type.HDR) .useDepthBuffer().useNormalBuffer().useLightBuffer().useStencilBuffer(), fullScale); - FBO writeOnlyGBuffer = generateWithDimensions(new FBOConfig(WRITEONLY_GBUFFER, FULL_SCALE, FBO.Type.HDR) + FBO gBuffer2 = generateWithDimensions(new FBOConfig(new SimpleUri("engine:fbo.gBuffer2"), FULL_SCALE, FBO.Type.HDR) .useDepthBuffer().useNormalBuffer().useLightBuffer().useStencilBuffer(), fullScale); generateWithDimensions(new FBOConfig(FINAL_BUFFER, FULL_SCALE, FBO.Type.DEFAULT), fullScale); - gBufferPair = new SwappableFBO(readOnlyGBuffer, writeOnlyGBuffer); + gBufferPair = new SwappableFBO(gBuffer1, gBuffer2); } @Override diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java b/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java index cc101304d46..e72bd176c65 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRenderer.java @@ -15,6 +15,7 @@ */ package org.terasology.rendering.world; +import org.terasology.entitySystem.systems.ComponentSystem; import org.terasology.math.geom.Vector3f; import org.terasology.math.geom.Vector3i; import org.terasology.rendering.assets.material.Material; diff --git a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java index e769464914e..21aded71b84 100644 --- a/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java +++ b/engine/src/main/java/org/terasology/rendering/world/WorldRendererImpl.java @@ -18,8 +18,14 @@ import org.terasology.config.Config; import org.terasology.config.RenderingConfig; import org.terasology.context.Context; +import org.terasology.engine.SimpleUri; import org.terasology.engine.subsystem.lwjgl.GLBufferPool; import org.terasology.engine.subsystem.lwjgl.LwjglGraphics; +import org.terasology.entitySystem.systems.ComponentSystem; +import org.terasology.entitySystem.systems.RegisterSystem; +import org.terasology.logic.console.commandSystem.annotations.Command; +import org.terasology.logic.console.commandSystem.annotations.CommandParam; +import org.terasology.logic.permission.PermissionManager; import org.terasology.logic.players.LocalPlayerSystem; import org.terasology.math.TeraMath; import org.terasology.math.geom.Vector3f; @@ -43,8 +49,6 @@ import org.terasology.rendering.dag.nodes.BloomBlurNode; import org.terasology.rendering.dag.nodes.BlurredAmbientOcclusionNode; import org.terasology.rendering.dag.nodes.BufferClearingNode; -import org.terasology.rendering.dag.nodes.CopyImageToHMDNode; -import org.terasology.rendering.dag.nodes.CopyImageToScreenNode; import org.terasology.rendering.dag.nodes.DeferredMainLightNode; import org.terasology.rendering.dag.nodes.DeferredPointLightsNode; import org.terasology.rendering.dag.nodes.DownSamplerForExposureNode; @@ -58,6 +62,8 @@ import org.terasology.rendering.dag.nodes.OpaqueBlocksNode; import org.terasology.rendering.dag.nodes.OpaqueObjectsNode; import org.terasology.rendering.dag.nodes.OutlineNode; +import org.terasology.rendering.dag.nodes.OutputToHMDNode; +import org.terasology.rendering.dag.nodes.OutputToScreenNode; import org.terasology.rendering.dag.nodes.OverlaysNode; import org.terasology.rendering.dag.nodes.PrePostCompositeNode; import org.terasology.rendering.dag.nodes.RefractiveReflectiveBlocksNode; @@ -99,8 +105,6 @@ import static org.terasology.rendering.opengl.ScalingFactors.ONE_32TH_SCALE; import static org.terasology.rendering.opengl.ScalingFactors.ONE_8TH_SCALE; import static org.terasology.rendering.opengl.ScalingFactors.QUARTER_SCALE; -import static org.terasology.rendering.opengl.fbms.DisplayResolutionDependentFBOs.READONLY_GBUFFER; -import static org.terasology.rendering.opengl.fbms.DisplayResolutionDependentFBOs.WRITEONLY_GBUFFER; /** * Renders the 3D world, including background, overlays and first person/in hand objects. 2D UI elements are dealt with elsewhere. @@ -112,7 +116,8 @@ * TODO: update this section to include new, relevant objects * - a RenderableWorld instance, providing acceleration structures caching blocks requiring different rendering treatments
*/ -public final class WorldRendererImpl implements WorldRenderer { +@RegisterSystem +public final class WorldRendererImpl implements WorldRenderer, ComponentSystem { private boolean isFirstRenderingStageForCurrentFrame; private final RenderQueuesHelper renderQueues; @@ -152,6 +157,24 @@ public final class WorldRendererImpl implements WorldRenderer { private DisplayResolutionDependentFBOs displayResolutionDependentFBOs; private ShadowMapResolutionDependentFBOs shadowMapResolutionDependentFBOs; + private static RenderGraph renderGraph = new RenderGraph(); // TODO: Try making this non-static + + // Required for ComponentSystem to register the system (via @RegisterSystem). + // @RegisterSystem requires a default constructor, and since we have final variables in the class, + // it was essential to set them to some value (in this case, null) in this constructor. + // Note that this constructor shouldn't be actually used normally anywhere in code. + public WorldRendererImpl() { + renderingConfig = null; + vrProvider = null; + renderQueues = null; + context = null; + backdropProvider = null; + worldProvider = null; + renderableWorld = null; + shaderManager = null; + playerCamera = null; + } + /** * Instantiates a WorldRenderer implementation. * @@ -229,8 +252,6 @@ private void initRenderingSupport() { } private void initRenderGraph() { - RenderGraph renderGraph = new RenderGraph(); - addShadowMapNodes(renderGraph); addReflectionNodes(renderGraph); @@ -249,7 +270,7 @@ private void initRenderGraph() { addPostProcessingNodes(renderGraph); - addCopyOutputNodes(renderGraph); + addOutputNodes(renderGraph); renderTaskListGenerator = new RenderTaskListGenerator(); List orderedNodes = renderGraph.getNodesInTopologicalOrder(); @@ -282,14 +303,14 @@ private void addSkyNodes(RenderGraph renderGraph) { BufferClearingNode reflectedRefractedClearingNode = new BufferClearingNode(reflectedRefractedBufferConfig, displayResolutionDependentFBOs, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderGraph.addNode(reflectedRefractedClearingNode, "reflectedRefractedClearingNode"); - FBOConfig lastUpdatedGBufferConfig = displayResolutionDependentFBOs.getFboConfig(READONLY_GBUFFER); - FBOConfig staleGBufferConfig = displayResolutionDependentFBOs.getFboConfig(WRITEONLY_GBUFFER); + FBOConfig gBuffer1Config = displayResolutionDependentFBOs.getFboConfig(new SimpleUri("engine:fbo.gBuffer1")); // TODO: Remove the hard coded value here + FBOConfig gBuffer2Config = displayResolutionDependentFBOs.getFboConfig(new SimpleUri("engine:fbo.gBuffer2")); // TODO: Remove the hard coded value here - BufferClearingNode lastUpdatedGBufferClearingNode = new BufferClearingNode(lastUpdatedGBufferConfig, displayResolutionDependentFBOs, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - renderGraph.addNode(lastUpdatedGBufferClearingNode, "lastUpdatedGBufferClearingNode"); + BufferClearingNode lastUpdatedGBufferClearingNode = new BufferClearingNode(gBuffer1Config, displayResolutionDependentFBOs, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + renderGraph.addNode(lastUpdatedGBufferClearingNode, "gBuffer1ClearingNode"); - BufferClearingNode staleGBufferClearingNode = new BufferClearingNode(staleGBufferConfig, displayResolutionDependentFBOs, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - renderGraph.addNode(staleGBufferClearingNode, "staleGBufferClearingNode"); + BufferClearingNode staleGBufferClearingNode = new BufferClearingNode(gBuffer2Config, displayResolutionDependentFBOs, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + renderGraph.addNode(staleGBufferClearingNode, "gBuffer2ClearingNode"); Node backdropNode = new BackdropNode(context); renderGraph.addNode(backdropNode, "backdropNode"); @@ -299,15 +320,16 @@ private void addSkyNodes(RenderGraph renderGraph) { FBOConfig hazeIntermediateConfig = new FBOConfig(HazeNode.INTERMEDIATE_HAZE_FBO_URI, ONE_16TH_SCALE, FBO.Type.DEFAULT); FBO hazeIntermediateFbo = displayResolutionDependentFBOs.request(hazeIntermediateConfig); - String label = "hazeIntermediateNode"; + String label = "hazeIntermediate"; HazeNode hazeIntermediateNode = new HazeNode(context, displayResolutionDependentFBOs.getGBufferPair().getLastUpdatedFbo(), hazeIntermediateFbo, label); - renderGraph.addNode(hazeIntermediateNode, label); + renderGraph.addNode(hazeIntermediateNode, label + "Node"); FBOConfig hazeFinalConfig = new FBOConfig(HazeNode.FINAL_HAZE_FBO_URI, ONE_32TH_SCALE, FBO.Type.DEFAULT); FBO hazeFinalFbo = displayResolutionDependentFBOs.request(hazeFinalConfig); + label = "hazeFinal"; HazeNode hazeFinalNode = new HazeNode(context, hazeIntermediateFbo, hazeFinalFbo, label); - renderGraph.addNode(hazeFinalNode, "hazeFinalNode"); + renderGraph.addNode(hazeFinalNode, label + "Node"); } private void addWorldRenderingNodes(RenderGraph renderGraph) { @@ -374,26 +396,26 @@ private void addPostProcessingNodes(RenderGraph renderGraph) { Node initialPostProcessingNode = new InitialPostProcessingNode(context); renderGraph.addNode(initialPostProcessingNode, "initialPostProcessingNode"); - FBOConfig writeOnlyGBufferConfig = displayResolutionDependentFBOs.getFboConfig(WRITEONLY_GBUFFER); + FBOConfig gBuffer2Config = displayResolutionDependentFBOs.getFboConfig(new SimpleUri("engine:fbo.gBuffer2")); // TODO: Remove the hard coded value here String label = "downSampling_gBuffer_to_16x16px_forExposure"; - DownSamplerForExposureNode exposureDownSamplerTo16pixels = new DownSamplerForExposureNode(context, writeOnlyGBufferConfig, displayResolutionDependentFBOs, FBO_16X16_CONFIG, immutableFBOs, label); - renderGraph.addNode(exposureDownSamplerTo16pixels, label); + DownSamplerForExposureNode exposureDownSamplerTo16pixels = new DownSamplerForExposureNode(context, gBuffer2Config, displayResolutionDependentFBOs, FBO_16X16_CONFIG, immutableFBOs, label); + renderGraph.addNode(exposureDownSamplerTo16pixels, label + "Node"); label = "downSampling_16x16px_to_8x8px_forExposure"; DownSamplerForExposureNode exposureDownSamplerTo8pixels = new DownSamplerForExposureNode(context, FBO_16X16_CONFIG, immutableFBOs, FBO_8X8_CONFIG, immutableFBOs, label); - renderGraph.addNode(exposureDownSamplerTo8pixels, label); + renderGraph.addNode(exposureDownSamplerTo8pixels, label + "Node"); label = "downSampling_8x8px_to_4x4px_forExposure"; DownSamplerForExposureNode exposureDownSamplerTo4pixels = new DownSamplerForExposureNode(context, FBO_8X8_CONFIG, immutableFBOs, FBO_4X4_CONFIG, immutableFBOs, label); - renderGraph.addNode(exposureDownSamplerTo4pixels, label); + renderGraph.addNode(exposureDownSamplerTo4pixels, label + "Node"); label = "downSampling_4x4px_to_2x2px_forExposure"; DownSamplerForExposureNode exposureDownSamplerTo2pixels = new DownSamplerForExposureNode(context, FBO_4X4_CONFIG, immutableFBOs, FBO_2X2_CONFIG, immutableFBOs, label); - renderGraph.addNode(exposureDownSamplerTo2pixels, label); + renderGraph.addNode(exposureDownSamplerTo2pixels, label + "Node"); label = "downSampling_2x2px_to_1x1px_forExposure"; DownSamplerForExposureNode exposureDownSamplerTo1pixel = new DownSamplerForExposureNode(context, FBO_2X2_CONFIG, immutableFBOs, FBO_1X1_CONFIG, immutableFBOs, label); - renderGraph.addNode(exposureDownSamplerTo1pixel, label); + renderGraph.addNode(exposureDownSamplerTo1pixel, label + "Node"); Node updateExposureNode = new UpdateExposureNode(context); renderGraph.addNode(updateExposureNode, "updateExposureNode"); @@ -412,47 +434,47 @@ private void addPostProcessingNodes(RenderGraph renderGraph) { label = "halfScaleBlurredBloom"; BloomBlurNode halfScaleBlurredBloom = new BloomBlurNode(context, displayResolutionDependentFBOs.get(HighPassNode.HIGH_PASS_FBO_URI), halfScaleBloomFbo, label); - renderGraph.addNode(halfScaleBlurredBloom, label); + renderGraph.addNode(halfScaleBlurredBloom, label + "Node"); FBOConfig quarterScaleBloomConfig = new FBOConfig(BloomBlurNode.QUARTER_SCALE_FBO_URI, QUARTER_SCALE, FBO.Type.DEFAULT); FBO quarterScaleBloomFbo = displayResolutionDependentFBOs.request(quarterScaleBloomConfig); label = "quarterScaleBlurredBloom"; BloomBlurNode quarterScaleBlurredBloom = new BloomBlurNode(context, halfScaleBloomFbo, quarterScaleBloomFbo, label); - renderGraph.addNode(quarterScaleBlurredBloom, label); + renderGraph.addNode(quarterScaleBlurredBloom, label + "Node"); FBOConfig one8thScaleBloomConfig = new FBOConfig(BloomBlurNode.ONE_8TH_SCALE_FBO_URI, ONE_8TH_SCALE, FBO.Type.DEFAULT); FBO one8thScaleBloomFbo = displayResolutionDependentFBOs.request(one8thScaleBloomConfig); label = "one8thScaleBlurredBloom"; BloomBlurNode one8thScaleBlurredBloom = new BloomBlurNode(context, quarterScaleBloomFbo, one8thScaleBloomFbo, label); - renderGraph.addNode(one8thScaleBlurredBloom, label); + renderGraph.addNode(one8thScaleBlurredBloom, label + "Node"); // Late Blur nodes: assisting Motion Blur and Depth-of-Field effects FBOConfig firstLateBlurConfig = new FBOConfig(FIRST_LATE_BLUR_FBO_URI, HALF_SCALE, FBO.Type.DEFAULT); FBO firstLateBlurFbo = displayResolutionDependentFBOs.request(firstLateBlurConfig); - label = "firstLateBlurNode"; + label = "firstLateBlur"; LateBlurNode firstLateBlurNode = new LateBlurNode(context, displayResolutionDependentFBOs.get(ToneMappingNode.TONE_MAPPING_FBO_URI), firstLateBlurFbo, label); - renderGraph.addNode(firstLateBlurNode, label); + renderGraph.addNode(firstLateBlurNode, label + "Node"); FBOConfig secondLateBlurConfig = new FBOConfig(SECOND_LATE_BLUR_FBO_URI, HALF_SCALE, FBO.Type.DEFAULT); FBO secondLateBlurFbo = displayResolutionDependentFBOs.request(secondLateBlurConfig); - label = "secondLateBlurNode"; + label = "secondLateBlur"; LateBlurNode secondLateBlurNode = new LateBlurNode(context, firstLateBlurFbo, secondLateBlurFbo, label); - renderGraph.addNode(secondLateBlurNode, label); + renderGraph.addNode(secondLateBlurNode, label + "Node"); Node finalPostProcessingNode = new FinalPostProcessingNode(context); renderGraph.addNode(finalPostProcessingNode, "finalPostProcessingNode"); } - private void addCopyOutputNodes(RenderGraph renderGraph) { - Node copyToVRFrameBufferNode = new CopyImageToHMDNode(context); - renderGraph.addNode(copyToVRFrameBufferNode, "copyToVRFrameBufferNode"); + private void addOutputNodes(RenderGraph renderGraph) { + Node copyToVRFrameBufferNode = new OutputToHMDNode(context); + renderGraph.addNode(copyToVRFrameBufferNode, "outputToVRFrameBufferNode"); - Node copyImageToScreenNode = new CopyImageToScreenNode(context); - renderGraph.addNode(copyImageToScreenNode, "copyImageToScreenNode"); + Node copyImageToScreenNode = new OutputToScreenNode(context); + renderGraph.addNode(copyImageToScreenNode, "outputToScreenNode"); } @Override @@ -486,7 +508,6 @@ public void update(float deltaInSeconds) { secondsSinceLastFrame += deltaInSeconds; } - private void resetStats() { statChunkMeshEmpty = 0; statChunkNotReady = 0; @@ -598,7 +619,7 @@ public void dispose() { renderableWorld.dispose(); worldProvider.dispose(); // TODO: Shift this to a better place, after a RenderGraph class has been implemented. - SetViewportToSizeOf.disposeDefaultInstance(); + SetViewportToSizeOf.disposeDefaultInstance(); } @Override @@ -677,4 +698,31 @@ public RenderingStage getCurrentRenderStage() { public void recompileShaders() { shaderManager.recompileAllShaders(); } + + @Override + public void initialise() { } + + @Override + public void preBegin() { } + + @Override + public void postBegin() { } + + @Override + public void preSave() { } + + @Override + public void postSave() { } + + @Override + public void shutdown() { } + + @Command(shortDescription = "Debugging command for DAG.", requiredPermission = PermissionManager.NO_PERMISSION) + public void dagNodeCommand(@CommandParam("nodeUri") final String nodeUri, @CommandParam("command") final String command, @CommandParam(value= "arguments") final String... arguments) { + Node node = renderGraph.findNode(new SimpleUri(nodeUri)); + if (node == null) { + throw new RuntimeException(("No node is associated with URI '" + nodeUri + "'")); + } + node.handleCommand(command, arguments); + } }