aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-01-22 06:35:25 +0100
committerSven Göthel <[email protected]>2024-01-22 06:35:25 +0100
commit5f9fb7159fa33bc979e5050d384b6939658049bd (patch)
tree09bdadf5c05ad007435a6f97a6153fa22702cfc6 /src/graphui/classes/com/jogamp/graph
parentbf096870c73898963558bef5c9d75760f9f76290 (diff)
Bug 1489 - GraphUI Group: Resolve Performance Regression in Scene.pickShape(): Drop invisible and clipped shapes
After implementing Bug 1487 (Frustum Clipping/Culling) and using thousands of shapes within one Group mostly culled (outside of frustum), overall mouse Scene.pickShape() caused tremendous lagging. This is caused by Scene.pickShape() traversing through _all_ shapes, rendered ones, invisible ones and culled ones. +++ Solution is to have Scene and Group provide a pre-sorted list of actually rendered shapes, i.e. isVisible() and not culled. Scene.pickShape() can now use this reduced and pre-sorted list reducing the load considerably. +++ Further - cleanup TreeTool - rename Container methods: -- setFrustumCullingEnabled() -> setPMvCullingEnabled() -- isFrustumCullingEnabled() -> isPMvCullingEnabled() - supply Container with -- isCullingEnabled() -- List<Shape> getRenderedShapes() -- isOutside() -- isOutside2() -- forAllRendered()
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Container.java89
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Group.java108
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Scene.java75
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Shape.java22
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java35
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java4
6 files changed, 257 insertions, 76 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Container.java b/src/graphui/classes/com/jogamp/graph/ui/Container.java
index 545ceec60..82f2fda4f 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Container.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Container.java
@@ -32,6 +32,7 @@ import java.util.Comparator;
import java.util.List;
import com.jogamp.graph.ui.Shape.Visitor2;
+import com.jogamp.math.Matrix4f;
import com.jogamp.math.geom.AABBox;
import com.jogamp.math.util.PMVMatrix4f;
import com.jogamp.opengl.GL2ES2;
@@ -48,9 +49,29 @@ public interface Container {
/** Returns number of {@link Shape}s, see {@link #getShapes()}. */
int getShapeCount();
- /** Returns added {@link Shape}s, see {@link #addShape(Shape)}. */
+ /** Returns {@link #addShape(Shape) added} {@link Shape}s. */
List<Shape> getShapes();
+ /**
+ * Returns {@link #addShape(Shape) added shapes} which are rendered and sorted by z-axis in ascending order toward z-near.
+ * <p>
+ * The rendered shapes are {@link Shape#isVisible() visible} and not deemed outside of this container due to {@link #isCullingEnabled() culling}.
+ * </p>
+ * <p>
+ * Only rendered shapes are considered for picking/activation.
+ * </p>
+ * <p>
+ * The returned list is data-race free, i.e. won't be mutated by the rendering thread
+ * as it gets completely replace at each rendering loop using a local volatile reference.<br/>
+ * Only when disposing the container, the list gets cleared, hence {@Link List#size()} shall be used in the loop.
+ * </p>
+ * @see #addShape(Shape)
+ * @see #isCullingEnabled()
+ * @see Shape#isVisible()
+ * @see #isOutside(PMVMatrix4f, Shape)
+ */
+ List<Shape> getRenderedShapes();
+
/** Adds a {@link Shape}. */
void addShape(Shape s);
@@ -89,14 +110,46 @@ public interface Container {
/** Returns {@link AABBox} dimension of given {@link Shape} from this container's perspective, i.e. world-bounds if performing from the {@link Scene}. */
AABBox getBounds(final PMVMatrix4f pmv, Shape shape);
- /** Enable or disable {@link PMVMatrix4f#getFrustum()} culling per {@link Shape}. Default is disabled. */
- void setFrustumCullingEnabled(final boolean v);
+ /** Enable or disable {@link PMVMatrix4f#getFrustum() Project-Modelview (PMv) frustum} culling per {@link Shape} for this container. Default is disabled. */
+ void setPMvCullingEnabled(final boolean v);
+
+ /** Return whether {@link #setPMvCullingEnabled(boolean) Project-Modelview (PMv) frustum culling} is enabled for this container. */
+ boolean isPMvCullingEnabled();
+
+ /**
+ * Return whether {@link #setPMvCullingEnabled(boolean) Project-Modelview (PMv) frustum culling}
+ * or {@link Group#setClipMvFrustum(com.jogamp.math.geom.Frustum) Group's Modelview (Mv) frustum clipping}
+ * is enabled for this container. Default is disabled.
+ */
+ boolean isCullingEnabled();
+
+ /**
+ * Returns whether the given {@link Shape} is completely outside of this container.
+ * <p>
+ * Note: If method returns false, the box may only be partially inside, i.e. intersects with this container
+ * </p>
+ * @param pmv current {@link PMVMatrix4f} of this container
+ * @param shape the {@link Shape} to test
+ * @see #isOutside2(Matrix4f, Shape, PMVMatrix4f)
+ * @see Shape#isOutside()
+ */
+ public boolean isOutside(final PMVMatrix4f pmv, final Shape shape);
- /** Return whether {@link #setFrustumCullingEnabled(boolean) frustum culling} is enabled. */
- boolean isFrustumCullingEnabled();
+ /**
+ * Returns whether the given {@link Shape} is completely outside of this container.
+ * <p>
+ * Note: If method returns false, the box may only be partially inside, i.e. intersects with this container
+ * </p>
+ * @param mvCont copy of the model-view {@link Matrix4f) of this container
+ * @param shape the {@link Shape} to test
+ * @param pmvShape current {@link PMVMatrix4f} of the shape to test
+ * @see #isOutside(PMVMatrix4f, Shape)
+ * @see Shape#isOutside()
+ */
+ public boolean isOutside2(final Matrix4f mvCont, final Shape shape, final PMVMatrix4f pmvShape);
/**
- * Traverses through the graph up until {@code shape} and apply {@code action} on it.
+ * Traverses through the graph up until {@code shape} of {@link Container#getShapes()} and apply {@code action} on it.
* @param pmv
* @param shape
* @param action
@@ -105,14 +158,16 @@ public interface Container {
boolean forOne(final PMVMatrix4f pmv, final Shape shape, final Runnable action);
/**
- * Traverses through the graph and apply {@link Visitor1#visit(Shape)} for each, stop if it returns true.
+ * Traverses through the graph and apply {@link Visitor1#visit(Shape)} for each {@link Shape} of {@link Container#getShapes()},
+ * stops if it returns true.
* @param v
* @return true to signal operation complete and to stop traversal, i.e. {@link Visitor1#visit(Shape)} returned true, otherwise false
*/
boolean forAll(Visitor1 v);
/**
- * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix4f)} for each, stop if it returns true.
+ * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix4f)} for each {@link Shape} of {@link Container#getShapes()},
+ * stops if it returns true.
* @param pmv
* @param v
* @return true to signal operation complete and to stop traversal, i.e. {@link Visitor2#visit(Shape, PMVMatrix4f)} returned true, otherwise false
@@ -120,7 +175,8 @@ public interface Container {
boolean forAll(final PMVMatrix4f pmv, Visitor2 v);
/**
- * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix4f)} for each, stop if it returns true.
+ * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix4f)} for each {@link Shape} of {@link Container#getShapes()},
+ * stops if it returns true.
*
* Each {@link Container} level is sorted using {@code sortComp}
* @param sortComp
@@ -129,4 +185,17 @@ public interface Container {
* @return true to signal operation complete and to stop traversal, i.e. {@link Visitor2#visit(Shape, PMVMatrix4f)} returned true, otherwise false
*/
boolean forSortedAll(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v);
-} \ No newline at end of file
+
+ /**
+ * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix4f)} for each {@link Shape} of {@link Container#getRenderedShapes()},
+ * stops if it returns true.
+ * <p>
+ * Each {@link Container} level is sorted using {@code sortComp}
+ * </p>
+ * @param sortComp
+ * @param pmv
+ * @param v
+ * @return true to signal operation complete and to stop traversal, i.e. {@link Visitor2#visit(Shape, PMVMatrix4f)} returned true, otherwise false
+ */
+ public boolean forAllRendered(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v);
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java
index af07d4053..391c0170b 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Group.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java
@@ -82,6 +82,9 @@ public class Group extends Shape implements Container {
private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>();
private Shape[] drawShapeArray = new Shape[0]; // reduce memory re-alloc @ display
+ private final List<Shape> renderedShapesB0 = new ArrayList<Shape>();
+ private final List<Shape> renderedShapesB1 = new ArrayList<Shape>();
+ private volatile List<Shape> renderedShapes = renderedShapesB1;
/** Enforced fixed size. In case z-axis is NaN, its 3D z-axis will be adjusted. */
private final Vec3f fixedSize = new Vec3f();
private Layout layouter;
@@ -151,7 +154,7 @@ public class Group extends Shape implements Container {
public Group setFixedSize(final Vec3f v) { fixedSize.set(v); return this; }
/**
* Enforce size of this group to given 2 dimensions,
- * adjusting the 3D z-axis {@link #getBounds()} giving room for potential clipping via {@link #setClipOnBounds(boolean)} or {@link #setClipFrustum(Frustum)}.
+ * adjusting the 3D z-axis {@link #getBounds()} giving room for potential clipping via {@link #setClipOnBounds(boolean)} or {@link #setClipMvFrustum(Frustum)}.
* @see #setFixedSize(Vec3f)
*/
public Group setFixedSize(final Vec2f v) { fixedSize.set(v.x(), v.y(), Float.NaN); return this; }
@@ -161,13 +164,13 @@ public class Group extends Shape implements Container {
public Vec2f getFixedSize(final Vec2f out) { out.set(fixedSize.x(), fixedSize.y()); return out; }
/**
- * Enable {@link Frustum} clipping on {@link #getBounds()} for this group and its shapes as follows
+ * Enable Modelview (Mv) {@link Frustum} clipping on {@link #getBounds()} for this group and its shapes as follows
* <ul>
* <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
* <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
* </ul>
* <p>
- * {@link #setClipFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * {@link #setClipMvFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
* </p>
* <p>
* With clipping enabled, the 3D z-axis {@link #getBounds()} depth
@@ -175,7 +178,7 @@ public class Group extends Shape implements Container {
* </p>
* @param v boolean to toggle clipping
* @return this instance for chaining
- * @see #setClipFrustum(Frustum)
+ * @see #setClipMvFrustum(Frustum)
* @see #setFixedSize(Vec2f)
* @see #setFixedSize(Vec3f)
*/
@@ -184,14 +187,14 @@ public class Group extends Shape implements Container {
public boolean getClipOnBounds() { return clipOnBounds; }
/**
- * Enable {@link Frustum} clipping on explicit given pre-multiplied w/ Mv-matrix {@code clip-box}
+ * Enable Modelview (Mv) {@link Frustum} clipping on explicit given pre-multiplied w/ Mv-matrix {@code clip-box}
* for this group and its shapes as follows
* <ul>
* <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
* <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
* </ul>
* <p>
- * {@link #setClipFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * {@link #setClipMvFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
* </p>
* <p>
* With clipping enabled, the 3D z-axis {@link #getBounds()} depth
@@ -203,9 +206,9 @@ public class Group extends Shape implements Container {
* @see #setFixedSize(Vec2f)
* @see #setFixedSize(Vec3f)
*/
- public Group setClipFrustum(final Frustum v) { clipFrustum = v; return this; }
- /** Returns {@link #setClipFrustum(Frustum)} value */
- public Frustum getClipFrustum() { return clipFrustum; }
+ public Group setClipMvFrustum(final Frustum v) { clipFrustum = v; return this; }
+ /** Returns {@link #setClipMvFrustum(Frustum)} value */
+ public Frustum getClipMvFrustum() { return clipFrustum; }
@Override
public int getShapeCount() { return shapes.size(); }
@@ -214,6 +217,9 @@ public class Group extends Shape implements Container {
public List<Shape> getShapes() { return shapes; }
@Override
+ public List<Shape> getRenderedShapes() { return renderedShapes; }
+
+ @Override
public void addShape(final Shape s) {
shapes.add(s);
s.setParent(this);
@@ -305,6 +311,8 @@ public class Group extends Shape implements Container {
}
shapes.clear();
drawShapeArray = new Shape[0];
+ renderedShapesB0.clear();
+ renderedShapesB1.clear();
}
@Override
@@ -315,6 +323,8 @@ public class Group extends Shape implements Container {
}
shapes.clear();
drawShapeArray = new Shape[0];
+ renderedShapesB0.clear();
+ renderedShapesB1.clear();
if( null != border ) {
border.destroy(gl, renderer);
border = null;
@@ -324,10 +334,61 @@ public class Group extends Shape implements Container {
private boolean doFrustumCulling = false;
@Override
- public final void setFrustumCullingEnabled(final boolean v) { doFrustumCulling = v; }
+ public final void setPMvCullingEnabled(final boolean v) { doFrustumCulling = v; }
+
+ @Override
+ public final boolean isPMvCullingEnabled() { return doFrustumCulling; }
@Override
- public final boolean isFrustumCullingEnabled() { return doFrustumCulling; }
+ public final boolean isCullingEnabled() { return doFrustumCulling || clipOnBounds || null != clipFrustum; }
+
+ @Override
+ public final boolean isOutside(final PMVMatrix4f pmv, final Shape shape) {
+ final AABBox shapeBox = shape.getBounds();
+ final boolean useClipFrustum = null != clipFrustum;
+ if( useClipFrustum || clipOnBounds ) {
+ final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
+ pmv.pushMv();
+ shape.applyMatToMv(pmv);
+ final boolean res;
+ if( doFrustumCulling && pmv.getFrustum().isOutside( shapeBox ) ) {
+ res = true;
+ } else {
+ final Cube shapeMv = tempC01.set( shapeBox ).transform( pmv.getMv() );
+ res = frustumMv.isOutside( shapeMv );
+ }
+ pmv.popMv();
+ return res;
+ } else if( doFrustumCulling ){
+ pmv.pushMv();
+ shape.applyMatToMv(pmv);
+ final boolean res = pmv.getFrustum().isOutside( shapeBox );
+ pmv.popMv();
+ return res;
+ } else {
+ return false;
+ }
+ }
+ @Override
+ public boolean isOutside2(final Matrix4f mvCont, final Shape shape, final PMVMatrix4f pmvShape) {
+ final AABBox shapeBox = shape.getBounds();
+ final boolean useClipFrustum = null != clipFrustum;
+ if( useClipFrustum || clipOnBounds ) {
+ final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( mvCont ).updateFrustumPlanes(tempF00);
+ final boolean res;
+ if( doFrustumCulling && pmvShape.getFrustum().isOutside( shapeBox ) ) {
+ res = true;
+ } else {
+ final Cube shapeMv = tempC01.set( shapeBox ).transform( pmvShape.getMv() );
+ res = frustumMv.isOutside( shapeMv );
+ }
+ return res;
+ } else if( doFrustumCulling ){
+ return pmvShape.getFrustum().isOutside( shapeBox );
+ } else {
+ return false;
+ }
+ }
@Override
protected void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba) {
@@ -338,6 +399,9 @@ public class Group extends Shape implements Container {
drawShapeArray = shapeArray; // keep backup
Arrays.sort(shapeArray, 0, shapeCount, Shape.ZAscendingComparator);
+ final List<Shape> iShapes = renderedShapes == renderedShapesB0 ? renderedShapesB1 : renderedShapesB0;
+ iShapes.clear();
+
final boolean useClipFrustum = null != clipFrustum;
if( useClipFrustum || clipOnBounds ) {
final Frustum origClipFrustum = renderer.getClipFrustum();
@@ -358,6 +422,7 @@ public class Group extends Shape implements Container {
( !doFrustumCulling || !pmv.getFrustum().isOutside( shapeBox ) ) )
{
shape.draw(gl, renderer);
+ iShapes.add(shape);
}
pmv.popMv();
}
@@ -371,11 +436,13 @@ public class Group extends Shape implements Container {
shape.applyMatToMv(pmv);
if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) {
shape.draw(gl, renderer);
+ iShapes.add(shape);
}
pmv.popMv();
}
}
}
+ renderedShapes = iShapes;
if( null != border ) {
border.draw(gl, renderer);
}
@@ -594,7 +661,7 @@ public class Group extends Shape implements Container {
@Override
public boolean contains(final Shape s) {
- return TreeTool.contains(shapes, s);
+ return TreeTool.contains(this, s);
}
@Override
public Shape getShapeByIdx(final int id) {
@@ -605,11 +672,11 @@ public class Group extends Shape implements Container {
}
@Override
public Shape getShapeByID(final int id) {
- return TreeTool.getShapeByID(shapes, id);
+ return TreeTool.getShapeByID(this, id);
}
@Override
public Shape getShapeByName(final String name) {
- return TreeTool.getShapeByName(shapes, name);
+ return TreeTool.getShapeByName(this, name);
}
@Override
@@ -633,22 +700,27 @@ public class Group extends Shape implements Container {
@Override
public boolean forOne(final PMVMatrix4f pmv, final Shape shape, final Runnable action) {
- return TreeTool.forOne(shapes, pmv, shape, action);
+ return TreeTool.forOne(this, pmv, shape, action);
}
@Override
public boolean forAll(final Visitor1 v) {
- return TreeTool.forAll(shapes, v);
+ return TreeTool.forAll(this, v);
}
@Override
public boolean forAll(final PMVMatrix4f pmv, final Visitor2 v) {
- return TreeTool.forAll(shapes, pmv, v);
+ return TreeTool.forAll(this, pmv, v);
}
@Override
public boolean forSortedAll(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v) {
- return TreeTool.forSortedAll(sortComp, shapes, pmv, v);
+ return TreeTool.forSortedAll(this, sortComp, pmv, v);
+ }
+
+ @Override
+ public boolean forAllRendered(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v) {
+ return TreeTool.forAllRendered(this, pmv, v);
}
}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
index b3ae5c9a0..45f406ea0 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
@@ -131,6 +131,9 @@ public final class Scene implements Container, GLEventListener {
private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>();
private Shape[] displayShapeArray = new Shape[0]; // reduce memory re-alloc @ display
+ private final List<Shape> renderedShapesB0 = new ArrayList<Shape>();
+ private final List<Shape> renderedShapesB1 = new ArrayList<Shape>();
+ private volatile List<Shape> renderedShapes = renderedShapesB1;
private final AtomicReference<Tooltip> toolTipActive = new AtomicReference<Tooltip>();
private final AtomicReference<Shape> toolTipHUD = new AtomicReference<Shape>();
@@ -219,10 +222,13 @@ public final class Scene implements Container, GLEventListener {
public final int getClearMask() { return clearMask; }
@Override
- public final void setFrustumCullingEnabled(final boolean v) { doFrustumCulling = v; }
+ public final void setPMvCullingEnabled(final boolean v) { doFrustumCulling = v; }
@Override
- public final boolean isFrustumCullingEnabled() { return doFrustumCulling; }
+ public final boolean isPMvCullingEnabled() { return doFrustumCulling; }
+
+ @Override
+ public final boolean isCullingEnabled() { return doFrustumCulling; }
public synchronized void attachGLAutoDrawable(final GLAutoDrawable drawable) {
cDrawable = drawable;
@@ -270,6 +276,9 @@ public final class Scene implements Container, GLEventListener {
public List<Shape> getShapes() { return shapes; }
@Override
+ public List<Shape> getRenderedShapes() { return renderedShapes; }
+
+ @Override
public void addShape(final Shape s) {
shapes.add(s);
}
@@ -334,7 +343,7 @@ public final class Scene implements Container, GLEventListener {
@Override
public boolean contains(final Shape s) {
- return TreeTool.contains(shapes, s);
+ return TreeTool.contains(this, s);
}
@Override
public Shape getShapeByIdx(final int id) {
@@ -345,11 +354,11 @@ public final class Scene implements Container, GLEventListener {
}
@Override
public Shape getShapeByID(final int id) {
- return TreeTool.getShapeByID(shapes, id);
+ return TreeTool.getShapeByID(this, id);
}
@Override
public Shape getShapeByName(final String name) {
- return TreeTool.getShapeByName(shapes, name);
+ return TreeTool.getShapeByName(this, name);
}
/** Returns {@link RegionRenderer#getSampleCount()}. */
@@ -448,7 +457,27 @@ public final class Scene implements Container, GLEventListener {
pmvMatrixSetup.setPlaneBox(planeBox, renderer.getMatrix(), renderer.getViewport());
}
- @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ public final boolean isOutside(final PMVMatrix4f pmv, final Shape shape) {
+ if( doFrustumCulling ){
+ pmv.pushMv();
+ shape.applyMatToMv(pmv);
+ final boolean res = pmv.getFrustum().isOutside( shape.getBounds() );
+ pmv.popMv();
+ return res;
+ } else {
+ return false;
+ }
+ }
+ @Override
+ public boolean isOutside2(final Matrix4f mvCont, final Shape shape, final PMVMatrix4f pmvShape) {
+ if( doFrustumCulling ){
+ return pmvShape.getFrustum().isOutside( shape.getBounds() );
+ } else {
+ return false;
+ }
+ }
+
@Override
public void display(final GLAutoDrawable drawable) {
final int shapeCount = shapes.size();
@@ -457,6 +486,8 @@ public final class Scene implements Container, GLEventListener {
displayShapeArray = shapeArray; // keep backup
Arrays.sort(shapeArray, 0, shapeCount, Shape.ZAscendingComparator);
+ final List<Shape> iShapes = renderedShapes == renderedShapesB0 ? renderedShapesB1 : renderedShapesB0;
+ iShapes.clear();
final GL2ES2 gl = drawable.getGL().getGL2ES2();
@@ -476,10 +507,12 @@ public final class Scene implements Container, GLEventListener {
if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) {
shape.draw(gl, renderer);
+ iShapes.add(shape);
}
pmv.popMv();
}
}
+ renderedShapes = iShapes;
renderer.enable(gl, false);
synchronized ( syncDisplayedOnce ) {
displayedOnce = true;
@@ -573,6 +606,8 @@ public final class Scene implements Container, GLEventListener {
}
shapes.clear();
displayShapeArray = new Shape[0];
+ renderedShapesB0.clear();
+ renderedShapesB1.clear();
disposeActions.clear();
if( drawable == cDrawable ) {
cDrawable = null;
@@ -622,7 +657,7 @@ public final class Scene implements Container, GLEventListener {
final Ray ray = new Ray();
final Shape[] shape = { null };
final int[] shapeIdx = { -1 };
- forSortedAll(Shape.ZDescendingComparator, pmv, (final Shape s, final PMVMatrix4f pmv2) -> {
+ TreeTool.forAllRendered(this, pmv, (final Shape s, final PMVMatrix4f pmv2) -> {
shapeIdx[0]++;
final boolean ok = s.isInteractive() && pmv.mapWinToRay(glWinX, glWinY, winZ0, winZ1, viewport, ray);
if( ok ) {
@@ -777,7 +812,7 @@ public final class Scene implements Container, GLEventListener {
*/
@Override
public boolean forOne(final PMVMatrix4f pmv, final Shape shape, final Runnable action) {
- return TreeTool.forOne(shapes, pmv, shape, action);
+ return TreeTool.forOne(this, pmv, shape, action);
}
/**
@@ -788,7 +823,7 @@ public final class Scene implements Container, GLEventListener {
*/
@Override
public boolean forAll(final PMVMatrix4f pmv, final Visitor2 v) {
- return TreeTool.forAll(shapes, pmv, v);
+ return TreeTool.forAll(this, pmv, v);
}
/**
@@ -798,7 +833,7 @@ public final class Scene implements Container, GLEventListener {
*/
@Override
public boolean forAll(final Visitor1 v) {
- return TreeTool.forAll(shapes, v);
+ return TreeTool.forAll(this, v);
}
/**
@@ -812,20 +847,12 @@ public final class Scene implements Container, GLEventListener {
*/
@Override
public boolean forSortedAll(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v) {
- try {
- return TreeTool.forSortedAll(sortComp, shapes, pmv, v);
- } catch (final java.lang.IllegalArgumentException iae) {
- System.err.println("Caught: "+iae.getMessage());
- System.err.println("float[] descendingZValues = { ");
- for(final Shape s : shapes) {
- final int thisBits = Float.floatToIntBits(s.getAdjustedZ());
- System.err.println(" Float.intBitsToFloat(0x"+Integer.toHexString(thisBits)+"),");
- }
- System.err.println(" };");
- iae.printStackTrace();
- throw iae;
- // return true;
- }
+ return TreeTool.forSortedAll(this, sortComp, pmv, v);
+ }
+
+ @Override
+ public boolean forAllRendered(final Comparator<Shape> sortComp, final PMVMatrix4f pmv, final Visitor2 v) {
+ return TreeTool.forAllRendered(this, pmv, v);
}
/**
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java
index 1811d2f61..32d1402b0 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java
@@ -310,13 +310,21 @@ public abstract class Shape {
/** Returns true if this shape denotes a {@link Group}, otherwise false. */
public boolean isGroup() { return false; }
- /** Returns true if this shape is visible, otherwise false. */
+ /**
+ * Returns true if this shape is set {@link #setVisible(boolean) visible} by the user, otherwise false. Defaults to true.
+ * <p>
+ * Note that invisible shapes are not considered for picking/activation.
+ * </p>
+ * @see #isInteractive()
+ */
public final boolean isVisible() { return isIO(IO_VISIBLE); }
/**
- * Enable or disable this shape's visibility.
+ * Enable (default) or disable this shape's visibility.
+ * <p>
+ * Note that invisible shapes are not considered for picking/activation.
+ * </p>
* <p>
- * Note that invisible shapes are still considered for picking/activation.
- * To completely mute the shape, issue {@link #setInteractive(boolean)} as well.
+ * This visibility flag is toggled by the user only.
* </p>
*/
public final Shape setVisible(final boolean v) { return setIO(IO_VISIBLE, v); }
@@ -1567,7 +1575,7 @@ public abstract class Shape {
public Tooltip getTooltip() { return tooltip; }
/**
- * Set whether this shape is interactive,
+ * Set whether this shape is interactive in general,
* i.e. any user interaction like
* - {@link #isToggleable()}
* - {@link #isDraggable()}
@@ -1575,14 +1583,16 @@ public abstract class Shape {
* but excluding programmatic changes.
* @param v new value for {@link #isInteractive()}
* @see #isInteractive()
+ * @see #isVisible()
* @see #setDraggable(boolean)
* @see #setResizable(boolean)
* @see #setDragAndResizeable(boolean)
*/
public final Shape setInteractive(final boolean v) { return setIO(IO_INTERACTIVE, v); }
/**
- * Returns if this shape allows user interaction, see {@link #setInteractive(boolean)}
+ * Returns if this shape allows user interaction in general, see {@link #setInteractive(boolean)}
* @see #setInteractive(boolean)
+ * @see #isVisible()
*/
public final boolean isInteractive() { return isIO(IO_INTERACTIVE); }
diff --git a/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java b/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java
index 4c5a6d1f0..1e6a37be4 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java
@@ -115,7 +115,9 @@ public class MediaPlayer extends Widget {
final float ctrlCellWidth = (aratio-2*borderSzS)/ctrlCells;
final float ctrlCellHeight = ctrlCellWidth;
- final float ctrlSliderHeight = ctrlCellHeight/15f;
+ final float ctrlSliderHeightMin = ctrlCellHeight/15f; // bar-height
+ final float ctrlSliderHeightMax = 3f * ctrlSliderHeightMin; // knob-height
+ final float infoGroupHeight = 1/7f;
final Shape[] zoomReplacement = { null };
final Vec3f[] zoomOrigScale = { null };
@@ -131,11 +133,10 @@ public class MediaPlayer extends Widget {
final RangeSlider ctrlSlider;
{
- final float knobScale = 3f;
- final float knobHeight = ctrlSliderHeight * knobScale;
- ctrlSlider = new RangeSlider(renderModes, new Vec2f(aratio - knobHeight, ctrlSliderHeight), knobScale, new Vec2f(0, 100), 1, 0);
- final float dx = knobHeight / 2f;
- final float dy = ( knobHeight - ctrlSliderHeight ) * 0.5f;
+ final float knobScale = ctrlSliderHeightMax / ctrlSliderHeightMin;
+ ctrlSlider = new RangeSlider(renderModes, new Vec2f(aratio - ctrlSliderHeightMax, ctrlSliderHeightMin), knobScale, new Vec2f(0, 100), 1, 0);
+ final float dx = ctrlSliderHeightMax / 2f;
+ final float dy = ( ctrlSliderHeightMax - ctrlSliderHeightMin ) * 0.5f;
ctrlSlider.setPaddding(new Padding(0, dx, ctrlCellHeight-dy, dx));
}
ctrlSlider.setName("mp.slider");
@@ -210,11 +211,10 @@ public class MediaPlayer extends Widget {
infoGroup.setName("mp.info").setInteractive(false);
this.addShape( infoGroup.setVisible(false) );
{
- final float sz = 1/7f;
- final Rectangle rect = new Rectangle(renderModes & ~Region.AA_RENDERING_MASK, aratio, sz, 0);
+ final Rectangle rect = new Rectangle(renderModes & ~Region.AA_RENDERING_MASK, aratio, infoGroupHeight, 0);
rect.setName("mp.info.blend").setInteractive(false);
rect.setColor(0, 0, 0, alphaBlend);
- rect.setPaddding(new Padding(0, 0, 1f-sz, 0));
+ rect.setPaddding(new Padding(0, 0, 1f-infoGroupHeight, 0));
infoGroup.addShape(rect);
}
{
@@ -468,13 +468,6 @@ public class MediaPlayer extends Widget {
this.setBorderColor(borderColorA);
} else {
this.setBorderColor(borderColor);
- }
- if( ctrlGroup.isActive() || ctrlSlider.isActive() ) {
- ctrlSlider.setVisible(true);
- ctrlBlend.setVisible(true);
- ctrlGroup.setVisible(true);
- infoGroup.setVisible(true);
- } else {
ctrlSlider.setVisible(false);
ctrlBlend.setVisible(false);
ctrlGroup.setVisible(false);
@@ -483,6 +476,16 @@ public class MediaPlayer extends Widget {
});
this.addMouseListener(new Shape.MouseGestureAdapter() {
@Override
+ public void mouseMoved(final MouseEvent e) {
+ final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment();
+ final Vec3f p = shapeEvent.objPos;
+ final boolean c = ( ctrlCellHeight + ctrlSliderHeightMax ) > p.y() || p.y() > ( 1f - infoGroupHeight );
+ ctrlSlider.setVisible(c);
+ ctrlBlend.setVisible(c);
+ ctrlGroup.setVisible(c);
+ infoGroup.setVisible(c);
+ }
+ @Override
public void mouseReleased(final MouseEvent e) {
mButton.setPressedColorMod(1f, 1f, 1f, 1f);
}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
index 838a39254..9143a9431 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
@@ -171,9 +171,9 @@ public class RangedGroup extends Widget {
// Mv pre-multiplied Frustum, clippedContent is on same PMV
final Frustum clipFrustum = tempC00.set( clippedContent.getBounds() ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
- content.setClipFrustum(clipFrustum);
+ content.setClipMvFrustum(clipFrustum);
super.drawImpl0(gl, renderer, rgba);
- content.setClipFrustum(null);
+ content.setClipMvFrustum(null);
}
}
private final Frustum tempF00 = new Frustum(); // OK, synchronized