diff options
author | Sven Göthel <[email protected]> | 2024-01-07 04:44:01 +0100 |
---|---|---|
committer | Sven Göthel <[email protected]> | 2024-01-07 04:44:01 +0100 |
commit | 259fce6ca0fa4fe92e6dc2266d442c62723eb73c (patch) | |
tree | 4f8df2aab6ada68736e0976e5facc06f5b0dcbc5 /src | |
parent | 6af37910eac365ed2b5ac957276337fe71f7e56b (diff) |
GraphUI Cleanup: Simplify Shape.draw*() and Container.{add,remove*}Shape[s](); Remove Scene.setDebugBorderBox()
Simplify Shape/Scene
- Split scene.display()/shape.drawImpl0() and scene.displayGLSelect()/shape.drawToSelectImpl0()
Simplify Container (Scene/Group)
- {add,remove*}Shape[s](), i.e. drop unusual removeShape*() and simplify implementation
Scene
- Remove setDebugBorderBox()
Diffstat (limited to 'src')
8 files changed, 144 insertions, 154 deletions
diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java index 061cc4de1..a520711de 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java @@ -182,7 +182,6 @@ public class UISceneDemo03 { final Scene scene = new Scene(options.graphAASamples); scene.setClearParams(new float[] { 1f, 1f, 1f, 1f }, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - scene.setDebugBorderBox(options.debugBoxThickness); final AnimGroup animGroup = new AnimGroup(null); scene.addShape(animGroup); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java index 6d03212e4..eaff6bf78 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java @@ -314,7 +314,6 @@ public class UISceneDemo20 implements GLEventListener { scene.setPMVMatrixSetup(new Scene.DefaultPMVMatrixSetup(-1f)); scene.getRenderer().setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); // scene.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? - scene.setDebugBorderBox(options.debugBoxThickness); scene.addShape(buttonsLeft); scene.addShape(buttonsRight); } diff --git a/src/demos/com/jogamp/opengl/demos/util/CommandlineOptions.java b/src/demos/com/jogamp/opengl/demos/util/CommandlineOptions.java index 21ea23a10..9eeb01f45 100644 --- a/src/demos/com/jogamp/opengl/demos/util/CommandlineOptions.java +++ b/src/demos/com/jogamp/opengl/demos/util/CommandlineOptions.java @@ -37,7 +37,6 @@ public class CommandlineOptions { public int sceneMSAASamples = 0; /** Sample count for Graph Region AA {@link Region#getRenderModes() render-modes}: {@link Region#VBAA_RENDERING_BIT} or {@link Region#MSAA_RENDERING_BIT} */ public int graphAASamples = 0; - public float debugBoxThickness = 0f; public boolean exclusiveContext = false; public boolean wait_to_start = false; public boolean keepRunning = false; @@ -126,9 +125,6 @@ public class CommandlineOptions { graphAASamples = MiscUtils.atoi(args[idx[0]], 4); renderModes &= ~Region.AA_RENDERING_MASK; renderModes |= Region.VBAA_RENDERING_BIT; - } else if (args[idx[0]].equals("-dbgbox")) { - ++idx[0]; - debugBoxThickness = MiscUtils.atof(args[idx[0]], debugBoxThickness); } else if(args[idx[0]].equals("-exclusiveContext")) { exclusiveContext = true; } else if(args[idx[0]].equals("-wait")) { @@ -150,7 +146,7 @@ public class CommandlineOptions { public String toString() { return "Options{surface[width "+surface_width+" x "+surface_height+"], glp "+glProfileName+ ", renderModes "+Region.getRenderModeString(renderModes)+ - ", smsaa "+sceneMSAASamples+", dbgbox "+debugBoxThickness+ + ", smsaa "+sceneMSAASamples+ ", exclusiveContext "+exclusiveContext+", wait "+wait_to_start+", keep "+keepRunning+", stay "+stayOpen+", dur "+total_duration+"s"+ "}"; } diff --git a/src/graphui/classes/com/jogamp/graph/ui/Container.java b/src/graphui/classes/com/jogamp/graph/ui/Container.java index dd8fe99f9..545ceec60 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Container.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Container.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 JogAmp Community. All rights reserved. + * Copyright 2023-2024 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -34,6 +34,8 @@ import java.util.List; import com.jogamp.graph.ui.Shape.Visitor2; import com.jogamp.math.geom.AABBox; import com.jogamp.math.util.PMVMatrix4f; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.ui.Shape.Visitor1; /** @@ -53,25 +55,30 @@ public interface Container { void addShape(Shape s); /** - * Removes given shape, w/o {@link Shape#destroy(com.jogamp.opengl.GL2ES2, com.jogamp.graph.curve.opengl.RegionRenderer) destroying} them. + * Removes given shape, w/o {@link Shape#destroy(GL2ES2, RegionRenderer)}. * @return the removed shape or null if not contained */ - Shape removeShape(Shape s); + Shape removeShape(final Shape s); + + /** Removes all given shapes, w/o {@link Shape#destroy(GL2ES2, RegionRenderer)}. */ + void removeShapes(Collection<? extends Shape> shapes); /** - * Removes shape at given index, w/o {@link Shape#destroy(com.jogamp.opengl.GL2ES2, com.jogamp.graph.curve.opengl.RegionRenderer) destroying} them. - * @return the removed shape - * @throws IndexOutOfBoundsException if index is out of bounds, i.e. (index < 0 || index >= size()) + * Removes given shape with {@link Shape#destroy(GL2ES2, RegionRenderer)}, if contained. + * @param gl GL2ES2 context + * @param renderer + * @param s the shape to be removed + * @return true if given Shape is removed and destroyed */ - Shape removeShape(final int idx); + boolean removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s); void addShapes(Collection<? extends Shape> shapes); - /** Removes all given shapes, w/o {@link Shape#destroy(com.jogamp.opengl.GL2ES2, com.jogamp.graph.curve.opengl.RegionRenderer) destroying} them. */ - void removeShapes(Collection<? extends Shape> shapes); + /** Removes all given shapes with {@link Shape#destroy(GL2ES2, RegionRenderer)}. */ + void removeShapes(final GL2ES2 gl, final RegionRenderer renderer, final Collection<? extends Shape> shapes); - /** Removes all contained shapes, w/o {@link Shape#destroy(com.jogamp.opengl.GL2ES2, com.jogamp.graph.curve.opengl.RegionRenderer) destroying} them. */ - void removeAllShapes(); + /** Removes all contained shapes with {@link Shape#destroy(GL2ES2, RegionRenderer)}. */ + void removeAllShapes(final GL2ES2 gl, final RegionRenderer renderer); boolean contains(Shape s); diff --git a/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java b/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java index b05c2bf11..869d63ec7 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java @@ -167,9 +167,12 @@ public abstract class GraphShape extends Shape { @Override protected final void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, final Vec4f rgba) { - if( null != rgba ) { - renderer.setColorStatic(rgba); - } + renderer.setColorStatic(rgba); + region.draw(gl, renderer, sampleCount); + } + + @Override + protected final void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { region.draw(gl, renderer, sampleCount); } diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java index b96291128..9dca781b1 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Group.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java @@ -1,5 +1,5 @@ /** - * Copyright 2023 JogAmp Community. All rights reserved. + * Copyright 2023-2024 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -123,18 +123,6 @@ public class Group extends Shape implements Container { markShapeDirty(); } - /** Removes given shape, keeps it alive. */ - @Override - public Shape removeShape(final Shape s) { - if( shapes.remove(s) ) { - s.setParent(null); - markShapeDirty(); - return s; - } else { - return null; - } - } - /** * Atomic replacement of the given {@link Shape} {@code remove} with {@link Shape} {@code replacement}. * @param remove the shape to be replaced @@ -157,22 +145,24 @@ public class Group extends Shape implements Container { } @Override - public Shape removeShape(final int idx) { - final Shape r = shapes.remove(idx); - if( null != r ) { - r.setParent(null); + public Shape removeShape(final Shape s) { + if( shapes.remove(s) ) { + s.setParent(null); markShapeDirty(); + return s; + } else { + return null; } - return r; } - /** - * Removes given shape and destroy it, if contained. - * @param gl GL2ES2 context - * @param renderer - * @param s the shape to be removed - * @return true if given Shape is removed and destroyed - */ + @Override + public void removeShapes(final Collection<? extends Shape> shapes) { + for(final Shape s : shapes) { + removeShape(s); + } + } + + @Override public boolean removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s) { if( shapes.remove(s) ) { s.setParent(null); @@ -190,14 +180,7 @@ public class Group extends Shape implements Container { addShape(s); } } - /** Removes all given shapes, keeps them alive. */ @Override - public void removeShapes(final Collection<? extends Shape> shapes) { - for(final Shape s : shapes) { - removeShape(s); - } - } - /** Removes all given shapes and destroys them. */ public void removeShapes(final GL2ES2 gl, final RegionRenderer renderer, final Collection<? extends Shape> shapes) { for(final Shape s : shapes) { removeShape(gl, renderer, s); @@ -205,14 +188,6 @@ public class Group extends Shape implements Container { } @Override - public void removeAllShapes() { - final int count = shapes.size(); - for(int i=count-1; i>=0; --i) { - removeShape(i); - } - } - - /** Removes all given shapes and destroys them. */ public void removeAllShapes(final GL2ES2 gl, final RegionRenderer renderer) { final int count = shapes.size(); for(int i=count-1; i>=0; --i) { @@ -268,22 +243,38 @@ public class Group extends Shape implements Container { shape.setTransformMv(pmv); if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { - if( null == rgba ) { - shape.drawToSelect(gl, renderer, sampleCount); - } else { - shape.draw(gl, renderer, sampleCount); - } + shape.draw(gl, renderer, sampleCount); } pmv.popMv(); } } if( null != border ) { - if( null == rgba ) { - border.drawToSelect(gl, renderer, sampleCount); - } else { - border.draw(gl, renderer, sampleCount); + border.draw(gl, renderer, sampleCount); + } + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected final void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { + final PMVMatrix4f pmv = renderer.getMatrix(); + final Object[] shapesS = shapes.toArray(); + Arrays.sort(shapesS, (Comparator)Shape.ZAscendingComparator); + + final int shapeCount = shapesS.length; + for(int i=0; i<shapeCount; i++) { + final Shape shape = (Shape) shapesS[i]; + if( shape.isVisible() ) { + pmv.pushMv(); + shape.setTransformMv(pmv); + + if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + shape.drawToSelect(gl, renderer, sampleCount); + } + pmv.popMv(); } } + if( null != border ) { + border.drawToSelect(gl, renderer, sampleCount); + } } private boolean relayoutOnDirtyShapes = true; diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java index 101bc70e2..6d3f77971 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java @@ -1,5 +1,5 @@ /** - * Copyright 2010-2023 JogAmp Community. All rights reserved. + * Copyright 2010-2024 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -129,11 +129,10 @@ public final class Scene implements Container, GLEventListener { /** Maximum sample count {@value} for Graph Region AA {@link Region#getRenderModes() render-modes}: {@link Region#VBAA_RENDERING_BIT} or {@link Region#MSAA_RENDERING_BIT}. */ public static final int MAX_SAMPLE_COUNT = 8; - @SuppressWarnings("unused") private static final boolean DEBUG = false; private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>(); - private float dbgBorderThickness = 0f; + private boolean doFrustumCulling = false; private float[] clearColor = null; @@ -272,44 +271,39 @@ public final class Scene implements Container, GLEventListener { @Override public void addShape(final Shape s) { - if( !s.hasBorder() && !FloatUtil.isZero(dbgBorderThickness) ) { - s.setBorder(dbgBorderThickness); - } shapes.add(s); } + @Override public Shape removeShape(final Shape s) { if( shapes.remove(s) ) { - s.setBorder(0f); return s; } else { return null; } } + @Override - public Shape removeShape(final int idx) { - final Shape r = shapes.remove(idx); - if( null != r ) { - r.setBorder(0f); + public void removeShapes(final Collection<? extends Shape> shapes) { + for(final Shape s : shapes) { + removeShape(s); } - return r; } - /** - * Removes given shape and destroy it, if contained. - * @param gl GL2ES2 context - * @param s the shape to be removed - * @return true if given Shape is removed and destroyed - */ - public boolean removeShape(final GL2ES2 gl, final Shape s) { + @Override + public boolean removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s) { if( shapes.remove(s) ) { - s.setBorder(0f); s.destroy(gl, renderer); return true; } else { return false; } } + + /** Removes given shape and destroy it, if contained - convenient call for {@link #removeShape(GL2ES2, RegionRenderer, Shape)}. */ + public boolean removeShape(final GL2ES2 gl, final Shape s) { + return removeShape(gl, renderer, s); + } @Override public void addShapes(final Collection<? extends Shape> shapes) { for(final Shape s : shapes) { @@ -317,32 +311,25 @@ public final class Scene implements Container, GLEventListener { } } @Override - public void removeShapes(final Collection<? extends Shape> shapes) { + public void removeShapes(final GL2ES2 gl, final RegionRenderer renderer, final Collection<? extends Shape> shapes) { for(final Shape s : shapes) { - removeShape(s); + removeShape(gl, renderer, s); } } - /** Removes all given shapes and destroys them. */ + /** Removes all given shapes and destroys them, convenient call for {@link #removeShape(GL2ES2, RegionRenderer, Shape)} */ public void removeShapes(final GL2ES2 gl, final Collection<? extends Shape> shapes) { - for(final Shape s : shapes) { - removeShape(gl, s); - } + removeShapes(gl, renderer, shapes); } @Override - public void removeAllShapes() { + public void removeAllShapes(final GL2ES2 gl, final RegionRenderer renderer) { final int count = shapes.size(); for(int i=count-1; i>=0; --i) { - final Shape s = shapes.get(i); - s.setBorder(0f); - shapes.remove(s); + removeShape(gl, renderer, shapes.get(i)); } } - /** Removes all given shapes and destroys them. */ + /** Removes all given shapes and destroys them, convenient call for {@link #removeAllShapes(GL2ES2, RegionRenderer)}. */ public void removeAllShapes(final GL2ES2 gl) { - final int count = shapes.size(); - for(int i=count-1; i>=0; --i) { - removeShape(gl, shapes.get(i)); - } + removeAllShapes(gl, renderer); } @Override @@ -411,17 +398,6 @@ public final class Scene implements Container, GLEventListener { } } - /** - * Sets the debug {@link Shape#setBorder(float) border} thickness for all existing or added shapes, zero for no debug border (default). - * @param v thickness debug border, zero for no border - */ - public final void setDebugBorderBox(final float v) { - dbgBorderThickness = v; - for(int i=0; i<shapes.size(); i++) { - shapes.get(i).setBorder(v); - } - } - @Override public void init(final GLAutoDrawable drawable) { if( null == cDrawable ) { @@ -487,64 +463,75 @@ public final class Scene implements Container, GLEventListener { final Object[] shapesS = shapes.toArray(); Arrays.sort(shapesS, (Comparator)Shape.ZAscendingComparator); - display(drawable, shapesS, false); + display(drawable, shapesS); } private static final int[] sampleCountGLSelect = { -1 }; - private void display(final GLAutoDrawable drawable, final Object[] shapes, final boolean glSelect) { + private void display(final GLAutoDrawable drawable, final Object[] shapes) { final GL2ES2 gl = drawable.getGL().getGL2ES2(); final int[] sampleCount0; - if( glSelect ) { - gl.glClearColor(0f, 0f, 0f, 1f); - sampleCount0 = sampleCountGLSelect; - gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - } else { - if( null != clearColor ) { - gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - gl.glClear(clearMask); - } - sampleCount0 = sampleCount; + if( null != clearColor ) { + gl.glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + gl.glClear(clearMask); } + sampleCount0 = sampleCount; final PMVMatrix4f pmv = renderer.getMatrix(); - if( glSelect ) { - renderer.enable(gl, true, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); - } else { - renderer.enable(gl, true); - } + renderer.enable(gl, true); - //final int shapeCount = shapes.size(); final int shapeCount = shapes.length; for(int i=0; i<shapeCount; i++) { - // final Shape shape = shapes.get(i); final Shape shape = (Shape)shapes[i]; - // System.err.println("Id "+i+": "+uiShape); if( shape.isVisible() ) { pmv.pushMv(); shape.setTransformMv(pmv); if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { - if( glSelect ) { - final float color = ( i + 1f ) / ( shapeCount + 2f ); - // FIXME - // System.err.printf("drawGL: color %f, index %d of [0..%d[%n", color, i, shapeCount); - renderer.setColorStatic(color, color, color, 1f); - shape.drawToSelect(gl, renderer, sampleCount0); - } else { - shape.draw(gl, renderer, sampleCount0); - } + shape.draw(gl, renderer, sampleCount0); } pmv.popMv(); } } - if( glSelect ) { - renderer.enable(gl, false, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); - } else { - renderer.enable(gl, false); + renderer.enable(gl, false); + synchronized ( syncDisplayedOnce ) { + displayedOnce = true; + syncDisplayedOnce.notifyAll(); + } + } + + private void displayGLSelect(final GLAutoDrawable drawable, final Object[] shapes) { + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final int[] sampleCount0; + gl.glClearColor(0f, 0f, 0f, 1f); + sampleCount0 = sampleCountGLSelect; + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + final PMVMatrix4f pmv = renderer.getMatrix(); + + renderer.enable(gl, true, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); + + final int shapeCount = shapes.length; + for(int i=0; i<shapeCount; i++) { + final Shape shape = (Shape)shapes[i]; + if( shape.isVisible() ) { + pmv.pushMv(); + shape.setTransformMv(pmv); + + if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + final float color = ( i + 1f ) / ( shapeCount + 2f ); + // FIXME + // System.err.printf("drawGL: color %f, index %d of [0..%d[%n", color, i, shapeCount); + renderer.setColorStatic(color, color, color, 1f); + shape.drawToSelect(gl, renderer, sampleCount0); + } + pmv.popMv(); + } } + renderer.enable(gl, false, RegionRenderer.defaultBlendDisable, RegionRenderer.defaultBlendDisable); synchronized ( syncDisplayedOnce ) { displayedOnce = true; syncDisplayedOnce.notifyAll(); @@ -727,7 +714,7 @@ public final class Scene implements Container, GLEventListener { final GL2ES2 gl = drawable.getGL().getGL2ES2(); - display(drawable, shapesS, true); + displayGLSelect(drawable, shapesS); psm.setPackAlignment(gl, 4); // psm.setUnpackAlignment(gl, 4); diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java index 0bdb9f985..e3a1f0e74 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java @@ -1,5 +1,5 @@ /** - * Copyright 2010-2023 JogAmp Community. All rights reserved. + * Copyright 2010-2024 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -583,7 +583,7 @@ public abstract class Shape { public void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { synchronized ( dirtySync ) { validate(gl); - drawImpl0(gl, renderer, sampleCount, null); + drawToSelectImpl0(gl, renderer, sampleCount); } } @@ -1751,14 +1751,22 @@ public abstract class Shape { protected abstract void validateImpl(final GLProfile glp, final GL2ES2 gl); /** - * Actual draw implementation + * Actual draw implementation, called by {@link #draw(GL2ES2, RegionRenderer, int[])} * @param gl * @param renderer * @param sampleCount - * @param rgba if null, caller is {@link #drawToSelect(GL2ES2, RegionRenderer, int[])}, otherwise regular {@#link #draw(GL2ES2, RegionRenderer, int[])} + * @param rgba */ protected abstract void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, Vec4f rgba); + /** + * Actual draw implementation, called by {@link #drawToSelect(GL2ES2, RegionRenderer, int[])} + * @param gl + * @param renderer + * @param sampleCount + */ + protected abstract void drawToSelectImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount); + /** Custom {@link #clear(GL2ES2, RegionRenderer)} task, called 1st. */ protected abstract void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer); |