From f26add9748f3d83d6e7ee05ed26f8d47c9f4b76d Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Fri, 27 Jun 2025 13:20:13 +0200 Subject: [PATCH] Update RenderManager.java --- .../java/com/jme3/renderer/RenderManager.java | 253 ++++++++---------- 1 file changed, 119 insertions(+), 134 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java index c59ffd9084..5d2c190534 100644 --- a/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java +++ b/jme3-core/src/main/java/com/jme3/renderer/RenderManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 jMonkeyEngine + * Copyright (c) 2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,37 +77,30 @@ import java.util.logging.Logger; /** - * A high-level rendering interface that is - * above the Renderer implementation. RenderManager takes care - * of rendering the scene graphs attached to each viewport and - * handling SceneProcessors. - * - * @see SceneProcessor - * @see ViewPort - * @see Spatial + * The `RenderManager` is a high-level rendering interface that manages + * {@link ViewPort}s, {@link SceneProcessor}s, and the overall rendering pipeline. + * It is responsible for orchestrating the rendering of scenes into various + * viewports and handling post-processing effects. */ public class RenderManager { private static final Logger logger = Logger.getLogger(RenderManager.class.getName()); + private final Renderer renderer; private final UniformBindingManager uniformBindingManager = new UniformBindingManager(); private final ArrayList preViewPorts = new ArrayList<>(); private final ArrayList viewPorts = new ArrayList<>(); private final ArrayList postViewPorts = new ArrayList<>(); - private final HashMap contexts = new HashMap<>(); + private final HashMap, PipelineContext> contexts = new HashMap<>(); private final LinkedList usedContexts = new LinkedList<>(); - private final LinkedList usedPipelines = new LinkedList<>(); - private RenderPipeline defaultPipeline = new ForwardPipeline(); + private final LinkedList> usedPipelines = new LinkedList<>(); + private RenderPipeline defaultPipeline = new ForwardPipeline(); private Camera prevCam = null; private Material forcedMaterial = null; private String forcedTechnique = null; private RenderState forcedRenderState = null; - private final SafeArrayList forcedOverrides - = new SafeArrayList<>(MatParamOverride.class); - private int viewX; - private int viewY; - private int viewWidth; - private int viewHeight; + private final SafeArrayList forcedOverrides = new SafeArrayList<>(MatParamOverride.class); + private final Matrix4f orthoMatrix = new Matrix4f(); private final LightList filteredLightList = new LightList(null); private boolean handleTranslucentBucket = true; @@ -115,7 +108,7 @@ public class RenderManager { private LightFilter lightFilter = new DefaultLightFilter(); private TechniqueDef.LightMode preferredLightMode = TechniqueDef.LightMode.MultiPass; private int singlePassLightBatchSize = 1; - private MatParamOverride boundDrawBufferId=new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0); + private final MatParamOverride boundDrawBufferId = new MatParamOverride(VarType.Int, "BoundDrawBuffer", 0); private Predicate renderFilter; @@ -123,7 +116,7 @@ public class RenderManager { * Creates a high-level rendering interface over the * low-level rendering interface. * - * @param renderer (alias created) + * @param renderer The low-level renderer implementation. */ public RenderManager(Renderer renderer) { this.renderer = renderer; @@ -131,59 +124,61 @@ public RenderManager(Renderer renderer) { // register default pipeline context contexts.put(PipelineContext.class, new DefaultPipelineContext()); } - + /** * Gets the default pipeline used when a ViewPort does not have a * pipeline already assigned to it. - * - * @return + * + * @return The default {@link RenderPipeline}, which is {@link ForwardPipeline} by default. */ - public RenderPipeline getPipeline() { + public RenderPipeline getPipeline() { return defaultPipeline; } - + /** * Sets the default pipeline used when a ViewPort does not have a * pipeline already assigned to it. *

* default={@link ForwardPipeline} - * - * @param pipeline default pipeline (not null) + * + * @param pipeline The default rendering pipeline (not null). */ - public void setPipeline(RenderPipeline pipeline) { + public void setPipeline(RenderPipeline pipeline) { assert pipeline != null; this.defaultPipeline = pipeline; } - + /** * Gets the default pipeline context registered under - * {@link PipelineContext#getClass()}. - * - * @return + * {@link PipelineContext}. + * + * @return The default {@link PipelineContext}. */ public PipelineContext getDefaultContext() { return getContext(PipelineContext.class); } - + /** - * Gets the pipeline context registered under the class. - * - * @param - * @param type - * @return registered context or null + * Gets the pipeline context registered under the given class type. + * + * @param type The class type of the context to retrieve. + * @param The type of the {@link PipelineContext}. + * @return The registered context instance, or null if not found. */ + @SuppressWarnings("unchecked") public T getContext(Class type) { - return (T)contexts.get(type); + return (T) contexts.get(type); } - + /** * Gets the pipeline context registered under the class or creates * and registers a new context from the supplier. - * - * @param - * @param type - * @param supplier interface for creating a new context if necessary - * @return registered or newly created context + * + * @param The type of the {@link PipelineContext}. + * @param type The class type under which the context is registered. + * @param supplier A function interface for creating a new context + * if one is not already registered under the given type. + * @return The registered or newly created context. */ public T getOrCreateContext(Class type, Supplier supplier) { T c = getContext(type); @@ -193,15 +188,16 @@ public T getOrCreateContext(Class type, Supplier< } return c; } - + /** * Gets the pipeline context registered under the class or creates * and registers a new context from the function. - * - * @param - * @param type - * @param function interface for creating a new context if necessary - * @return registered or newly created context + * + * @param The type of the {@link PipelineContext}. + * @param type The class type under which the context is registered. + * @param function A function interface for creating a new context, taking the {@code RenderManager} as an argument, + * if one is not already registered under the given type. + * @return The registered or newly created context. */ public T getOrCreateContext(Class type, Function function) { T c = getContext(type); @@ -211,16 +207,16 @@ public T getOrCreateContext(Class type, Function< } return c; } - + /** - * Registers the pipeline context under the class. + * Registers a pipeline context under the given class type. *

* If another context is already registered under the class, that * context will be replaced by the given context. - * - * @param - * @param type class type to register the context under (not null) - * @param context context to register (not null) + * + * @param type The class type under which the context is registered. + * @param context The context instance to register. + * @param The type of the {@link PipelineContext}. */ public void registerContext(Class type, T context) { assert type != null; @@ -229,11 +225,11 @@ public void registerContext(Class type, T context } contexts.put(type, context); } - + /** * Gets the application profiler. - * - * @return + * + * @return The {@link AppProfiler} instance, or null if none is set. */ public AppProfiler getProfiler() { return prof; @@ -248,9 +244,9 @@ public AppProfiler getProfiler() { * @see #createPreView(java.lang.String, com.jme3.renderer.Camera) */ public ViewPort getPreView(String viewName) { - for (int i = 0; i < preViewPorts.size(); i++) { - if (preViewPorts.get(i).getName().equals(viewName)) { - return preViewPorts.get(i); + for (ViewPort preViewPort : preViewPorts) { + if (preViewPort.getName().equals(viewName)) { + return preViewPort; } } return null; @@ -342,9 +338,9 @@ public boolean removeMainView(ViewPort view) { * @see #createPostView(java.lang.String, com.jme3.renderer.Camera) */ public ViewPort getPostView(String viewName) { - for (int i = 0; i < postViewPorts.size(); i++) { - if (postViewPorts.get(i).getName().equals(viewName)) { - return postViewPorts.get(i); + for (ViewPort postViewPort : postViewPorts) { + if (postViewPort.getName().equals(viewName)) { + return postViewPort; } } return null; @@ -522,7 +518,7 @@ public void notifyRescale(float x, float y) { for (ViewPort vp : preViewPorts) { notifyRescale(vp, x, y); } - for (ViewPort vp : viewPorts) { + for (ViewPort vp : viewPorts) { notifyRescale(vp, x, y); } for (ViewPort vp : postViewPorts) { @@ -531,22 +527,19 @@ public void notifyRescale(float x, float y) { } /** - * Sets the material to use to render all future objects. - * This overrides the material set on the geometry and renders - * with the provided material instead. - * Use null to clear the material and return renderer to normal - * functionality. + * Sets a material that will be forced on all rendered geometries. + * This can be used for debugging (e.g., solid color) or special effects. * - * @param mat The forced material to set, or null to return to normal + * @param forcedMaterial The material to force, or null to disable forcing. */ - public void setForcedMaterial(Material mat) { - forcedMaterial = mat; + public void setForcedMaterial(Material forcedMaterial) { + this.forcedMaterial = forcedMaterial; } - + /** - * Gets the forced material. - * - * @return + * Gets the forced material that overrides materials set on geometries. + * + * @return The forced {@link Material}, or null if no material is forced. */ public Material getForcedMaterial() { return forcedMaterial; @@ -597,10 +590,9 @@ public void setAppProfiler(AppProfiler prof) { } /** - * Returns the forced technique name set. - * - * @return the forced technique name set. + * Returns the name of the forced technique. * + * @return The name of the forced technique, or null if none is forced. * @see #setForcedTechnique(java.lang.String) */ public String getForcedTechnique() { @@ -616,9 +608,7 @@ public String getForcedTechnique() { * If a forced material is not set and the forced technique name cannot * be found on the material, the geometry will not be rendered. * - * @param forcedTechnique The forced technique name to use, set to null - * to return to normal functionality. - * + * @param forcedTechnique The technique to force, or null to disable forcing. * @see #renderGeometry(com.jme3.scene.Geometry) */ public void setForcedTechnique(String forcedTechnique) { @@ -627,13 +617,12 @@ public void setForcedTechnique(String forcedTechnique) { /** * Adds a forced material parameter to use when rendering geometries. - * - *

The provided parameter takes precedence over parameters set on the + *

+ * The provided parameter takes precedence over parameters set on the * material or any overrides that exist in the scene graph that have the * same name. * - * @param override The override to add - * @see MatParamOverride + * @param override The material parameter override to add. * @see #removeForcedMatParam(com.jme3.material.MatParamOverride) */ public void addForcedMatParam(MatParamOverride override) { @@ -641,9 +630,9 @@ public void addForcedMatParam(MatParamOverride override) { } /** - * Removes a forced material parameter previously added. + * Removes a material parameter override. * - * @param override The override to remove. + * @param override The material parameter override to remove. * @see #addForcedMatParam(com.jme3.material.MatParamOverride) */ public void removeForcedMatParam(MatParamOverride override) { @@ -757,33 +746,35 @@ public void updateUniformBindings(Shader shader) { * @see com.jme3.material.Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) */ public void renderGeometry(Geometry geom) { - + if (renderFilter != null && !renderFilter.test(geom)) { return; } - + LightList lightList = geom.getWorldLightList(); if (lightFilter != null) { filteredLightList.clear(); lightFilter.filterLights(geom, filteredLightList); lightList = filteredLightList; } - + renderGeometry(geom, lightList); - } - + /** - * - * @param geom - * @param lightList + * Renders a single {@link Geometry} with a specific list of lights. + * This method applies the world transform, handles forced materials and techniques, + * and manages the `BoundDrawBuffer` parameter for multi-target frame buffers. + * + * @param geom The {@link Geometry} to render. + * @param lightList The {@link LightList} containing the lights that affect this geometry. */ public void renderGeometry(Geometry geom, LightList lightList) { - + if (renderFilter != null && !renderFilter.test(geom)) { return; } - + this.renderer.pushDebugGroup(geom.getName()); if (geom.isIgnoreTransform()) { setWorldMatrix(Matrix4f.IDENTITY); @@ -818,8 +809,7 @@ public void renderGeometry(Geometry geom, LightList lightList) { RenderState tmpRs = forcedRenderState; if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) { //forcing forced technique renderState - forcedRenderState - = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); + forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState(); } // use geometry's material material.render(geom, lightList, this); @@ -902,7 +892,7 @@ public void preloadScene(Spatial scene) { } } } - + /** * Flattens the given scene graph into the ViewPort's RenderQueue, * checking for culling as the call goes down the graph recursively. @@ -1079,10 +1069,9 @@ public int getSinglePassLightBatchSize() { */ public void setSinglePassLightBatchSize(int singlePassLightBatchSize) { // Ensure the batch size is no less than 1 - this.singlePassLightBatchSize = singlePassLightBatchSize < 1 ? 1 : singlePassLightBatchSize; + this.singlePassLightBatchSize = Math.max(singlePassLightBatchSize, 1); } - /** * Renders the given viewport queues. * @@ -1126,7 +1115,6 @@ public void renderViewPortQueues(ViewPort vp, boolean flush) { depthRangeChanged = true; } - // transparent objects are last because they require blending with the // rest of the scene's objects. Consequently, they are sorted // back-to-front. @@ -1184,12 +1172,12 @@ public void renderTranslucentQueue(ViewPort vp) { private void setViewPort(Camera cam) { // this will make sure to clearReservations viewport only if needed if (cam != prevCam || cam.isViewportChanged()) { - viewX = (int) (cam.getViewPortLeft() * cam.getWidth()); - viewY = (int) (cam.getViewPortBottom() * cam.getHeight()); + int viewX = (int) (cam.getViewPortLeft() * cam.getWidth()); + int viewY = (int) (cam.getViewPortBottom() * cam.getHeight()); int viewX2 = (int) (cam.getViewPortRight() * cam.getWidth()); int viewY2 = (int) (cam.getViewPortTop() * cam.getHeight()); - viewWidth = viewX2 - viewX; - viewHeight = viewY2 - viewY; + int viewWidth = viewX2 - viewX; + int viewHeight = viewY2 - viewY; uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight); renderer.setViewPort(viewX, viewY, viewWidth, viewHeight); renderer.setClipRect(viewX, viewY, viewWidth, viewHeight); @@ -1266,8 +1254,8 @@ public void renderViewPortRaw(ViewPort vp) { /** * Applies the ViewPort's Camera and FrameBuffer in preparation * for rendering. - * - * @param vp + * + * @param vp The ViewPort to apply. */ public void applyViewPort(ViewPort vp) { renderer.setFrameBuffer(vp.getOutputFrameBuffer()); @@ -1279,7 +1267,7 @@ public void applyViewPort(ViewPort vp) { renderer.clearBuffers(vp.isClearColor(), vp.isClearDepth(), vp.isClearStencil()); } } - + /** * Renders the {@link ViewPort} using the ViewPort's {@link RenderPipeline}. *

@@ -1294,7 +1282,7 @@ public void applyViewPort(ViewPort vp) { public void renderViewPort(ViewPort vp, float tpf) { if (!vp.isEnabled()) { return; - } + } RenderPipeline pipeline = vp.getPipeline(); if (pipeline == null) { pipeline = defaultPipeline; @@ -1333,14 +1321,13 @@ public void render(float tpf, boolean mainFrameBufferActive) { if (renderer instanceof NullRenderer) { return; } - + uniformBindingManager.newFrame(); if (prof != null) { prof.appStep(AppStep.RenderPreviewViewPorts); } - for (int i = 0; i < preViewPorts.size(); i++) { - ViewPort vp = preViewPorts.get(i); + for (ViewPort vp : preViewPorts) { if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) { renderViewPort(vp, tpf); } @@ -1349,8 +1336,7 @@ public void render(float tpf, boolean mainFrameBufferActive) { if (prof != null) { prof.appStep(AppStep.RenderMainViewPorts); } - for (int i = 0; i < viewPorts.size(); i++) { - ViewPort vp = viewPorts.get(i); + for (ViewPort vp : viewPorts) { if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) { renderViewPort(vp, tpf); } @@ -1359,23 +1345,21 @@ public void render(float tpf, boolean mainFrameBufferActive) { if (prof != null) { prof.appStep(AppStep.RenderPostViewPorts); } - for (int i = 0; i < postViewPorts.size(); i++) { - ViewPort vp = postViewPorts.get(i); + for (ViewPort vp : postViewPorts) { if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive) { renderViewPort(vp, tpf); } } - + // cleanup for used render pipelines and pipeline contexts only for (PipelineContext c : usedContexts) { c.endContextRenderFrame(this); } - for (RenderPipeline p : usedPipelines) { + for (RenderPipeline p : usedPipelines) { p.endRenderFrame(this); } usedContexts.clear(); usedPipelines.clear(); - } /** @@ -1390,10 +1374,10 @@ public boolean getPassDrawBufferTargetIdToShaders() { /** * Enable or disable passing the draw buffer target id to the shaders. This * is needed to handle FrameBuffer.setTargetIndex correctly in some - * backends. + * backends. When enabled, a material parameter named "BoundDrawBuffer" of + * type Int will be added to forced material parameters. * - * @param v - * True to enable, false to disable (default is true) + * @param v True to enable, false to disable (default is true) */ public void setPassDrawBufferTargetIdToShaders(boolean v) { if (v) { @@ -1404,21 +1388,22 @@ public void setPassDrawBufferTargetIdToShaders(boolean v) { this.forcedOverrides.remove(boundDrawBufferId); } } - + /** * Set a render filter. Every geometry will be tested against this filter * before rendering and will only be rendered if the filter returns true. - * - * @param filter the render filter + * This allows for custom culling or selective rendering based on geometry properties. + * + * @param filter The render filter to apply, or null to remove any existing filter. */ public void setRenderFilter(Predicate filter) { renderFilter = filter; } /** - * Returns the render filter that the RenderManager is currently using - * - * @return the render filter + * Returns the render filter that the RenderManager is currently using. + * + * @return The currently active render filter, or null if no filter is set. */ public Predicate getRenderFilter() { return renderFilter;