aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph/ui/Scene.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph/ui/Scene.java')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Scene.java180
1 files changed, 126 insertions, 54 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
index 831a9d334..ac3bbe146 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
@@ -49,6 +49,8 @@ import com.jogamp.common.nio.Buffers;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.graph.curve.opengl.RenderState;
+import com.jogamp.graph.ui.Shape.Visitor2;
+import com.jogamp.graph.ui.Shape.Visitor1;
import com.jogamp.newt.event.GestureHandler;
import com.jogamp.newt.event.InputEvent;
import com.jogamp.newt.event.MouseEvent;
@@ -58,11 +60,14 @@ import com.jogamp.newt.event.GestureHandler.GestureEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.Ray;
+import com.jogamp.opengl.math.Vec3f;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.util.GLPixelStorageModes;
import com.jogamp.opengl.util.GLReadBufferUtil;
import com.jogamp.opengl.util.PMVMatrix;
+import jogamp.graph.ui.TreeTool;
+
/**
* GraphUI Scene
* <p>
@@ -86,7 +91,7 @@ import com.jogamp.opengl.util.PMVMatrix;
* </p>
* @see Shape
*/
-public final class Scene implements GLEventListener {
+public final class Scene implements Container, GLEventListener {
/** Default scene distance on z-axis to projection is -1/5f. */
public static final float DEFAULT_SCENE_DIST = -1/5f;
/** Default projection angle in degrees value is 45.0. */
@@ -201,14 +206,16 @@ public final class Scene implements GLEventListener {
}
}
+ @Override
public List<Shape> getShapes() {
return shapes;
}
+ @Override
public void addShape(final Shape s) {
s.setDebugBox(dbgbox_thickness);
shapes.add(s);
}
- /** Removes given shape, keeps it alive. */
+ @Override
public void removeShape(final Shape s) {
s.setDebugBox(0f);
shapes.remove(s);
@@ -219,12 +226,13 @@ public final class Scene implements GLEventListener {
shapes.remove(s);
s.destroy(gl, renderer);
}
+ @Override
public void addShapes(final Collection<? extends Shape> shapes) {
for(final Shape s : shapes) {
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);
@@ -236,6 +244,10 @@ public final class Scene implements GLEventListener {
removeShape(gl, s);
}
}
+ @Override
+ public boolean contains(final Shape s) {
+ return false;
+ }
public Shape getShapeByIdx(final int id) {
if( 0 > id ) {
return null;
@@ -449,17 +461,9 @@ public final class Scene implements GLEventListener {
* @param runnable the action to perform if {@link Shape} was found
* @return picked Shape if any or null as stored in {@code shape}
*/
- public Shape pickShape(final PMVMatrix pmv, final int glWinX, final int glWinY, final float[] objPos, final Shape[] shape, final Runnable runnable) {
+ public Shape pickShape(final PMVMatrix pmv, final int glWinX, final int glWinY, final Vec3f objPos, final Shape[] shape, final Runnable runnable) {
setupMatrix(pmv);
- final Shape pick = pickShapeImpl(pmv, glWinX, glWinY, objPos);
- shape[0] = pick;
- if( null != pick ) {
- runnable.run();
- }
- return pick;
- }
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private Shape pickShapeImpl(final PMVMatrix pmv, final int glWinX, final int glWinY, final float[] objPos) {
+
final float winZ0 = 0f;
final float winZ1 = 0.3f;
/**
@@ -467,34 +471,28 @@ public final class Scene implements GLEventListener {
gl.glReadPixels( x, y, 1, 1, GL2ES2.GL_DEPTH_COMPONENT, GL.GL_FLOAT, winZRB);
winZ1 = winZRB.get(0); // dir
*/
-
+ final int[] viewport = getViewport();
final Ray ray = new Ray();
-
- final Object[] shapesS = shapes.toArray();
- Arrays.sort(shapesS, (Comparator)Shape.ZAscendingComparator);
-
- for(int i=shapesS.length-1; i>=0; i--) {
- final Shape uiShape = (Shape)shapesS[i];
-
- if( uiShape.isEnabled() ) {
- pmv.glPushMatrix();
- uiShape.setTransform(pmv);
- final boolean ok = pmv.gluUnProjectRay(glWinX, glWinY, winZ0, winZ1, getViewport(), 0, ray);
- if( ok ) {
- final AABBox sbox = uiShape.getBounds();
- if( sbox.intersectsRay(ray) ) {
- // System.err.printf("Pick.0: shape %d, [%d, %d, %f/%f] -> %s%n", i, glWinX, glWinY, winZ0, winZ1, ray);
- if( null == sbox.getRayIntersection(objPos, ray, FloatUtil.EPSILON, true, dpyTmp1V3, dpyTmp2V3, dpyTmp3V3) ) {
- throw new InternalError("Ray "+ray+", box "+sbox);
- }
- // System.err.printf("Pick.1: shape %d @ [%f, %f, %f], within %s%n", i, objPos[0], objPos[1], objPos[2], uiShape.getBounds());
- return uiShape;
+ shape[0] = null;
+
+ forSortedAll(Shape.ZAscendingComparator, pmv, (final Shape s, final PMVMatrix pmv2) -> {
+ final boolean ok = pmv.gluUnProjectRay(glWinX, glWinY, winZ0, winZ1, viewport, ray);
+ if( ok ) {
+ final AABBox sbox = s.getBounds();
+ if( sbox.intersectsRay(ray) ) {
+ // System.err.printf("Pick.0: shape %d, [%d, %d, %f/%f] -> %s%n", i, glWinX, glWinY, winZ0, winZ1, ray);
+ if( null == sbox.getRayIntersection(objPos, ray, FloatUtil.EPSILON, true) ) {
+ throw new InternalError("Ray "+ray+", box "+sbox);
}
+ // System.err.printf("Pick.1: shape %d @ [%f, %f, %f], within %s%n", i, objPos[0], objPos[1], objPos[2], uiShape.getBounds());
+ shape[0] = s;
+ runnable.run();
+ return true;
}
- pmv.glPopMatrix(); // we leave the stack open if picked above, allowing the modelview shape transform to be reused
}
- }
- return null;
+ return false;
+ });
+ return shape[0];
}
private final float[] dpyTmp1V3 = new float[3];
private final float[] dpyTmp2V3 = new float[3];
@@ -514,7 +512,7 @@ public final class Scene implements GLEventListener {
* @param shape storage for found {@link Shape} or null
* @param runnable the action to perform if {@link Shape} was found
*/
- public void pickShapeGL(final int glWinX, final int glWinY, final float[] objPos, final Shape[] shape, final Runnable runnable) {
+ public void pickShapeGL(final int glWinX, final int glWinY, final Vec3f objPos, final Shape[] shape, final Runnable runnable) {
if( null == cDrawable ) {
return;
}
@@ -586,10 +584,79 @@ public final class Scene implements GLEventListener {
* @param objPos resulting object position
* @param runnable action
*/
- public void winToShapeCoord(final Shape shape, final int glWinX, final int glWinY, final PMVMatrix pmv, final float[] objPos, final Runnable runnable) {
- if( null != shape && null != shape.winToShapeCoord(pmvMatrixSetup, renderer.getViewport(), glWinX, glWinY, pmv, objPos) ) {
- runnable.run();
+ public void winToShapeCoord(final Shape shape, final int glWinX, final int glWinY, final PMVMatrix pmv, final Vec3f objPos, final Runnable runnable) {
+ if( null == shape ) {
+ return;
}
+ final int[] viewport = getViewport();
+ setupMatrix(pmv);
+ forOne(pmv, shape, () -> {
+ if( null != shape.winToShapeCoord(pmv, viewport, glWinX, glWinY, objPos) ) {
+ runnable.run();
+ }
+ });
+ }
+
+ @Override
+ public AABBox getBounds(final PMVMatrix pmv, final Shape shape) {
+ final AABBox res = new AABBox();
+ if( null == shape ) {
+ return res;
+ }
+ setupMatrix(pmv);
+ forOne(pmv, shape, () -> {
+ shape.getBounds().transformMv(res, pmv, new float[3], new float[3]);
+ });
+ return res;
+ }
+
+ /**
+ * Traverses through the graph up until {@code shape} and apply {@code action} on it.
+ * @param pmv
+ * @param shape
+ * @param action
+ * @return true to signal operation complete, i.e. {@code shape} found, otherwise false
+ */
+ @Override
+ public boolean forOne(final PMVMatrix pmv, final Shape shape, final Runnable action) {
+ setupMatrix(pmv);
+ return TreeTool.forOne(shapes, pmv, shape, action);
+ }
+
+ /**
+ * Traverses through the graph and apply {@link Visitor2#visit(Shape, PMVMatrix)} for each, stop if it returns true.
+ * @param pmv
+ * @param v
+ * @return true to signal operation complete and to stop traversal, i.e. {@link Visitor2#visit(Shape, PMVMatrix)} returned true, otherwise false
+ */
+ @Override
+ public boolean forAll(final PMVMatrix pmv, final Visitor2 v) {
+ setupMatrix(pmv);
+ return TreeTool.forAll(shapes, pmv, v);
+ }
+
+ /**
+ * Traverses through the graph and apply {@link Visitor1#visit(Shape)} for each, stop 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
+ */
+ @Override
+ public boolean forAll(final Visitor1 v) {
+ return TreeTool.forAll(shapes, v);
+ }
+
+ /**
+ * Traverses through the graph and apply {@link Visitor#visit(Shape, PMVMatrix)} for each, stop if it returns true.
+ *
+ * Each {@link Container} level is sorted using {@code sortComp}
+ * @param sortComp
+ * @param pmv
+ * @param v
+ * @return true to signal operation complete and to stop traversal, i.e. {@link Visitor2#visit(Shape, PMVMatrix)} returned true, otherwise false
+ */
+ @Override
+ public boolean forSortedAll(final Comparator<Shape> sortComp, final PMVMatrix pmv, final Visitor2 v) {
+ return TreeTool.forSortedAll(sortComp, shapes, pmv, v);
}
/**
@@ -788,16 +855,18 @@ public final class Scene implements GLEventListener {
// gesture .. delegate to active shape!
final InputEvent orig = gh.getTrigger();
if( orig instanceof MouseEvent ) {
- final MouseEvent e = (MouseEvent) orig;
- // flip to GL window coordinates
- final int glWinX = e.getX();
- final int glWinY = getHeight() - e.getY() - 1;
- final PMVMatrix pmv = new PMVMatrix();
- final float[] objPos = new float[3];
final Shape shape = activeShape;
- winToShapeCoord(shape, glWinX, glWinY, pmv, objPos, () -> {
- shape.dispatchGestureEvent(gh, glWinX, glWinY, pmv, renderer.getViewport(), objPos);
- });
+ if( shape.isInteractive() ) {
+ final MouseEvent e = (MouseEvent) orig;
+ // flip to GL window coordinates
+ final int glWinX = e.getX();
+ final int glWinY = getHeight() - e.getY() - 1;
+ final PMVMatrix pmv = new PMVMatrix();
+ final Vec3f objPos = new Vec3f();
+ winToShapeCoord(shape, glWinX, glWinY, pmv, objPos, () -> {
+ shape.dispatchGestureEvent(gh, glWinX, glWinY, pmv, renderer.getViewport(), objPos);
+ });
+ }
}
}
}
@@ -812,7 +881,7 @@ public final class Scene implements GLEventListener {
final void dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY) {
if( null == activeShape ) {
dispatchMouseEventPickShape(e, glWinX, glWinY);
- } else {
+ } else if( activeShape.isInteractive() ) {
dispatchMouseEventForShape(activeShape, e, glWinX, glWinY);
}
}
@@ -824,11 +893,13 @@ public final class Scene implements GLEventListener {
*/
final void dispatchMouseEventPickShape(final MouseEvent e, final int glWinX, final int glWinY) {
final PMVMatrix pmv = new PMVMatrix();
- final float[] objPos = new float[3];
+ final Vec3f objPos = new Vec3f();
final Shape[] shape = { null };
if( null == pickShape(pmv, glWinX, glWinY, objPos, shape, () -> {
setActiveShape(shape[0]);
- shape[0].dispatchMouseEvent(e, glWinX, glWinY, objPos);
+ if( shape[0].isInteractive() ) {
+ shape[0].dispatchMouseEvent(e, glWinX, glWinY, objPos);
+ }
} ) )
{
releaseActiveShape();
@@ -843,7 +914,7 @@ public final class Scene implements GLEventListener {
*/
final void dispatchMouseEventForShape(final Shape shape, final MouseEvent e, final int glWinX, final int glWinY) {
final PMVMatrix pmv = new PMVMatrix();
- final float[] objPos = new float[3];
+ final Vec3f objPos = new Vec3f();
winToShapeCoord(shape, glWinX, glWinY, pmv, objPos, () -> { shape.dispatchMouseEvent(e, glWinX, glWinY, objPos); });
}
@@ -1059,4 +1130,5 @@ public final class Scene implements GLEventListener {
}
};
private PMVMatrixSetup pmvMatrixSetup = defaultPMVMatrixSetup;
+
}