summaryrefslogtreecommitdiffstats
path: root/src/test/com/jogamp/opengl
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-03-16 06:07:07 +0100
committerSven Gothel <[email protected]>2014-03-16 06:07:07 +0100
commit5e728baa72517865d602580b920d9bdfdfb26c65 (patch)
tree7d9429bab13e5122c610e73bc3742570a55eaeb0 /src/test/com/jogamp/opengl
parent8352cb7c5d8cc971c87f13fe9f61e346c4d2c541 (diff)
Bug 801: Revisit UIShape/SceneController (Ray-Picking, Full Object/Model driven, ..) TODO: Transformations
SceneUIController handles shapes generic: Rendering, selecting and event traversing. All data (transforms ..) are provided by UIShape. UIShape: - Dispatching NEWT MouseEvent's on MouseEventListener - Separates the 2d-transforms for shape/region and 3d transform, scale and rotation GPUUISceneGLListener0A Demo code merely aggregates the shapes and attaches listener, hence includes the 'application logic'. Working: - picking any shape - dragging, zooming, actions TODO: - Fix transformations, actually the rotations (button) look odd probably due to 'unlucky' rotation center and axis. +++ RegionRenderer: Removed Matrix ops, which shall be applied on PMVMatrix
Diffstat (limited to 'src/test/com/jogamp/opengl')
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java10
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java12
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java11
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java4
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java19
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java321
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java8
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java351
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIGLListener01.java37
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java192
10 files changed, 514 insertions, 451 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java
index d109ba1cc..f89ce101c 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRendererNEWT10.java
@@ -34,6 +34,7 @@ import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLProfile;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import org.junit.Assert;
import org.junit.BeforeClass;
@@ -50,6 +51,7 @@ import com.jogamp.graph.geom.SVertex;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.test.junit.util.NEWTGLContext;
import com.jogamp.opengl.test.junit.util.UITestCase;
+import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.glsl.ShaderState;
@@ -190,8 +192,12 @@ public class TestTextRendererNEWT10 extends UITestCase {
AABBox textBox = font.getStringBounds(text, fontSize);
dx += font.getAdvanceWidth('X', fontSize) * column;
dy -= (int)textBox.getHeight() * ( row + 1 );
- textRenderUtil.renderer.resetModelview(null);
- textRenderUtil.renderer.translate(gl, dx, dy, z0);
+
+ final PMVMatrix pmv = textRenderUtil.renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+ pmv.glTranslatef(dx, dy, z0);
+ textRenderUtil.renderer.updateMatrix(gl);
textRenderUtil.drawString3D(gl, font, fontSize, text, texSize);
lastRow = row;
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
index 6dd86e10c..feab048ea 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
@@ -31,11 +31,13 @@ package com.jogamp.opengl.test.junit.graph.demos;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.opengl.GLRegion;
import com.jogamp.graph.curve.opengl.RenderState;
import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.opengl.util.PMVMatrix;
/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
* These Outlines are not necessary connected or contained.
@@ -115,10 +117,12 @@ public class GPURegionGLListener01 extends GPURegionRendererListenerBase01 {
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
final RegionRenderer regionRenderer = getRenderer();
-
- regionRenderer.resetModelview(null);
- regionRenderer.translate(null, getXTran(), getYTran(), getZTran());
- regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+ final PMVMatrix pmv = regionRenderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+ pmv.glTranslatef(getXTran(), getYTran(), getZTran());
+ pmv.glRotatef(getAngle(), 0, 1, 0);
+ regionRenderer.updateMatrix(gl);
if( weight != regionRenderer.getWeight()) {
regionRenderer.setWeight(gl, weight);
}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
index d0afc8ad0..8fbc73522 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
@@ -34,11 +34,13 @@ import java.util.List;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.opengl.GLRegion;
import com.jogamp.graph.curve.opengl.RenderState;
import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.opengl.util.PMVMatrix;
/** Demonstrate the rendering of multiple OutlineShapes
* into one region
@@ -118,9 +120,12 @@ public class GPURegionGLListener02 extends GPURegionRendererListenerBase01 {
final RegionRenderer regionRenderer = getRenderer();
- regionRenderer.resetModelview(null);
- regionRenderer.translate(null, getXTran(), getYTran(), getZTran());
- regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+ final PMVMatrix pmv = regionRenderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+ pmv.glTranslatef(getXTran(), getYTran(), getZTran());
+ pmv.glRotatef(getAngle(), 0, 1, 0);
+ regionRenderer.updateMatrix(gl);
if( weight != regionRenderer.getWeight()) {
regionRenderer.setWeight(gl, weight);
}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
index 03f04a752..30c6bdea5 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
@@ -41,6 +41,7 @@ import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.GLPipelineFactory;
import javax.media.opengl.GLRunnable;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.curve.opengl.GLRegion;
@@ -148,7 +149,8 @@ public abstract class GPURendererListenerBase01 implements GLEventListener {
final PMVMatrix pmv = renderer.getMatrix();
renderer.reshapePerspective(null, 45.0f, width, height, zNear, zFar);
- renderer.resetModelview(null);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
renderer.updateMatrix(gl);
System.err.printf("Reshape: zNear %f, zFar %f%n", zNear, zFar);
System.err.printf("Reshape: Frustum: %s%n", pmv.glGetFrustum());
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
index 7fcb9a848..a74fd407a 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
@@ -34,6 +34,7 @@ import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLException;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.curve.opengl.GLRegion;
@@ -213,7 +214,8 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
final RegionRenderer renderer = getRenderer();
final PMVMatrix pmv = renderer.getMatrix();
- renderer.resetModelview(null);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
renderer.setColorStatic(gl, 0.0f, 0.0f, 0.0f);
if( renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED) ) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -242,7 +244,6 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
drawable.getChosenGLCapabilities().getAlphaBits());
// bottom, half line up
- renderer.resetModelview(null);
pmv.glTranslatef(nearPlaneX0, nearPlaneY0+(nearPlaneS * pixelSizeFPS / 2f), nearPlaneZ0);
renderer.updateMatrix(gl);
@@ -253,7 +254,8 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
float dx = width-fontNameBox.getWidth()-2f;
float dy = height - 10f;
- renderer.resetModelview(null);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0);
renderer.updateMatrix(gl);
System.err.printf("FontN: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy));
@@ -263,7 +265,8 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
dy += -fontNameBox.getHeight() - 10f;
if(null != headtext) {
- renderer.resetModelview(null);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
System.err.printf("Head: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy));
pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0);
// pmv.glTranslatef(x0, y1, z0);
@@ -273,11 +276,13 @@ public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerB
dy += -headbox.getHeight() - font.getLineHeight(pixelSizeBottom);
- renderer.resetModelview(null);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
pmv.glTranslatef(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy), nearPlaneZ0);
System.err.printf("Bottom: [%f %f] -> [%f %f]%n", dx, dy, nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+(dy*nearPlaneSy));
- renderer.translate(null, getXTran(), getYTran(), getZTran());
- renderer.rotate(gl, getAngle(), 0, 1, 0);
+ pmv.glTranslatef(getXTran(), getYTran(), getZTran());
+ pmv.glRotatef(getAngle(), 0, 1, 0);
+ renderer.updateMatrix(gl);
renderer.setColorStatic(gl, 1.0f, 0.0f, 0.0f);
if( renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED) ) {
gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java
index 1102f2d7d..72c5d6a17 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneGLListener0A.java
@@ -20,11 +20,12 @@ import com.jogamp.newt.Window;
import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.opengl.GLWindow;
-import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.test.junit.graph.demos.ui.Label;
import com.jogamp.opengl.test.junit.graph.demos.ui.RIButton;
import com.jogamp.opengl.test.junit.graph.demos.ui.SceneUIController;
-import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.test.junit.graph.demos.ui.UIShape;
import com.jogamp.opengl.util.glsl.ShaderState;
public class GPUUISceneGLListener0A implements GLEventListener {
@@ -33,28 +34,19 @@ public class GPUUISceneGLListener0A implements GLEventListener {
private boolean trace = false;
private final int renderModes;
- private final int[] sampleCount = new int[1];
- private final int[] texSize2 = new int[1];
private final RenderState rs;
private final SceneUIController sceneUIController;
- protected final float zNear = 0.1f, zFar = 7000f;
- /** Describing the bounding box in model-coordinates of the near-plane parallel at distance one. */
- protected final AABBox nearPlane1Box;
private RegionRenderer renderer;
int fontSet = FontFactory.UBUNTU;
Font font;
+ final float buttonXSize = 84f;
+ final float buttonYSize = buttonXSize/2.5f;
final float fontSizeFixed = 12f;
final float fontSizeFPS = 10f;
float dpiH = 96;
- private float xTran = 0f;
- private float yTran = 0;
- private float zTran = 0f;
- private float rotButtonsY = 0f;
- private float rotTextY = 0f;
- private final float zoomText = 1f;
private int currentText = 0;
private Label[] labels = null;
@@ -64,8 +56,7 @@ public class GPUUISceneGLListener0A implements GLEventListener {
private Label fpsLabel = null;
private final int numSelectable = 6;
- private MultiTouchListener multiTouchListener = null;
- private boolean showFPS = true;
+ private boolean ioAttached = false;
private GLAutoDrawable cDrawable;
private final String jogamp = "JogAmp - Jogl Graph Module Demo";
@@ -81,8 +72,6 @@ public class GPUUISceneGLListener0A implements GLEventListener {
public GPUUISceneGLListener0A(RenderState rs, int renderModes, boolean debug, boolean trace) {
this.rs = rs;
this.renderModes = renderModes;
- this.sampleCount[0] = 4;
- this.texSize2[0] = 0;
this.debug = debug;
this.trace = trace;
@@ -93,11 +82,23 @@ public class GPUUISceneGLListener0A implements GLEventListener {
ioe.printStackTrace();
}
sceneUIController = new SceneUIController();
- nearPlane1Box = new AABBox();
}
- final float buttonXSize = 84f;
- final float buttonYSize = buttonXSize/2.5f;
+ private void rotateButtons(MouseEvent e, float angdeg) {
+ for(int i=0; i<buttons.length; i++) {
+ rotateInstance(e, buttons[i].getRotation(), angdeg);
+ }
+ }
+ private void rotateInstance(MouseEvent e, Quaternion quat, float angdeg) {
+ final float angrad = angdeg * FloatUtil.PI / 180.0f;
+ if( e.isControlDown() ) {
+ quat.rotateByAngleZ(angrad);
+ } else if( e.isShiftDown() ) {
+ quat.rotateByAngleX(angrad);
+ } else {
+ quat.rotateByAngleY(angrad);
+ }
+ }
private void initButtons() {
buttons = new RIButton[numSelectable];
@@ -106,32 +107,44 @@ public class GPUUISceneGLListener0A implements GLEventListener {
final float ystart = 0f;
final float diff = 1.5f * buttonYSize;
- buttons[0] = new RIButton(SVertex.factory(), font, "Next Text", buttonXSize, buttonYSize){
- @Override
- public void onClick(MouseEvent e) {
- currentText = (currentText+1)%3;
- }
- };
- buttons[0].translate(xstart,ystart);
+ buttons[0] = new RIButton(SVertex.factory(), font, "Next Text", buttonXSize, buttonYSize);
+ buttons[0].translate(xstart,ystart, 0f);
buttons[0].setLabelColor(1.0f, 1.0f, 1.0f);
+ buttons[0].addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ if( null != labels[currentText] ) {
+ labels[currentText].setEnabled(false);
+ }
+ currentText = (currentText+1)%3;
+ if( null != labels[currentText] ) {
+ labels[currentText].setEnabled(true);
+ }
+ } } );
+ buttons[0].addMouseListener(new DragAndZoomListener(buttons[0]));
- buttons[1] = new RIButton(SVertex.factory(), font, "Show FPS", buttonXSize, buttonYSize){
+ buttons[1] = new RIButton(SVertex.factory(), font, "Show FPS", buttonXSize, buttonYSize);
+ buttons[1].translate(xstart,ystart - diff, 0f);
+ buttons[1].setToggleable(true);
+ buttons[1].setLabelColor(1.0f, 1.0f, 1.0f);
+ buttons[1].addMouseListener(new MouseAdapter() {
@Override
- public void onClick(MouseEvent e) {
+ public void mouseClicked(MouseEvent e) {
final GLAnimatorControl a = cDrawable.getAnimator();
if( null != a ) {
a.resetFPSCounter();
}
- showFPS = !showFPS;
- }
- };
- buttons[1].translate(xstart,ystart - diff);
- buttons[1].setToggleable(true);
- buttons[1].setLabelColor(1.0f, 1.0f, 1.0f);
+ fpsLabel.setEnabled(!fpsLabel.isEnabled());
+ } } );
+ buttons[1].addMouseListener(new DragAndZoomListener(buttons[1]));
- buttons[2] = new RIButton(SVertex.factory(), font, "v-sync", buttonXSize, buttonYSize){
+ buttons[2] = new RIButton(SVertex.factory(), font, "v-sync", buttonXSize, buttonYSize);
+ buttons[2].translate(xstart,ystart-diff*2, 0f);
+ buttons[2].setToggleable(true);
+ buttons[2].setLabelColor(1.0f, 1.0f, 1.0f);
+ buttons[2].addMouseListener(new MouseAdapter() {
@Override
- public void onClick(MouseEvent e) {
+ public void mouseClicked(MouseEvent e) {
cDrawable.invoke(false, new GLRunnable() {
@Override
public boolean run(GLAutoDrawable drawable) {
@@ -144,50 +157,42 @@ public class GPUUISceneGLListener0A implements GLEventListener {
return true;
}
});
- }
- };
- buttons[2].translate(xstart,ystart-diff*2);
- buttons[2].setToggleable(true);
- buttons[2].setLabelColor(1.0f, 1.0f, 1.0f);
+ } } );
+ buttons[2].addMouseListener(new DragAndZoomListener(buttons[2]));
- buttons[3] = new RIButton(SVertex.factory(), font, "Tilt +Y", buttonXSize, buttonYSize) {
- @Override
- public void onClick(MouseEvent e) {
- if( e.isShiftDown() ) {
- rotButtonsY+=5;
- } else {
- rotTextY+=5f;
- }
- }
- };
- buttons[3].translate(xstart,ystart-diff*3);
+ buttons[3] = new RIButton(SVertex.factory(), font, "Tilt +Y", buttonXSize, buttonYSize);
+ buttons[3].translate(xstart,ystart-diff*3, 0f);
buttons[3].setLabelColor(1.0f, 1.0f, 1.0f);
-
- buttons[4] = new RIButton(SVertex.factory(), font, "Tilt -Y", buttonXSize, buttonYSize){
+ buttons[3].addMouseListener(new MouseAdapter() {
@Override
- public void onClick(MouseEvent e) {
- if( e.isShiftDown() ) {
- rotButtonsY-=5f;
- } else {
- rotTextY-=5f;
- }
- }
- };
- buttons[4].translate(xstart,ystart-diff*4);
- buttons[4].setLabelColor(1.0f, 1.0f, 1.0f);
+ public void mouseClicked(MouseEvent e) {
+ rotateButtons(e, 5f);
+ } } );
+ buttons[3].addMouseListener(new DragAndZoomListener(buttons[3]));
- buttons[5] = new RIButton(SVertex.factory(), font, "Quit", buttonXSize, buttonYSize){
+ buttons[4] = new RIButton(SVertex.factory(), font, "Tilt -Y", buttonXSize, buttonYSize);
+ buttons[4].translate(xstart,ystart-diff*4, 0f);
+ buttons[4].setLabelColor(1.0f, 1.0f, 1.0f);
+ buttons[4].addMouseListener(new MouseAdapter() {
@Override
- public void onClick(MouseEvent e) {
- cDrawable.destroy();
- }
- };
- buttons[5].translate(xstart,ystart-diff*5);
+ public void mouseClicked(MouseEvent e) {
+ rotateButtons(e, -5f);
+ } } );
+ buttons[4].addMouseListener(new DragAndZoomListener(buttons[4]));
+
+ buttons[5] = new RIButton(SVertex.factory(), font, "Quit", buttonXSize, buttonYSize);
+ buttons[5].translate(xstart,ystart-diff*5, 0f);
buttons[5].setColor(0.8f, 0.0f, 0.0f);
buttons[5].setLabelColor(1.0f, 1.0f, 1.0f);
buttons[5].setSelectedColor(0.8f, 0.8f, 0.8f);
buttons[5].setLabelSelectedColor(0.8f, 0.0f, 0.0f);
+ buttons[5].addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ cDrawable.destroy();
+ } } );
+ buttons[5].addMouseListener(new DragAndZoomListener(buttons[5]));
}
private void initTexts() {
@@ -252,22 +257,32 @@ public class GPUUISceneGLListener0A implements GLEventListener {
renderer.init(gl);
renderer.setAlpha(gl, 1.0f);
- renderer.setColorStatic(gl, 0.0f, 0.0f, 0.0f);
initTexts();
initButtons();
- sceneUIController.setRenderer(renderer, renderModes, sampleCount);
+ sceneUIController.setRenderer(renderer);
sceneUIController.addShape(buttons[0]);
sceneUIController.addShape(buttons[1]);
sceneUIController.addShape(buttons[2]);
sceneUIController.addShape(buttons[3]);
sceneUIController.addShape(buttons[4]);
sceneUIController.addShape(buttons[5]);
- sceneUIController.init(drawable);
final float pixelSizeFixed = font.getPixelSize(fontSizeFixed, dpiH);
jogampLabel = new Label(SVertex.factory(), font, pixelSizeFixed, jogamp);
+ jogampLabel.addMouseListener(new DragAndZoomListener(jogampLabel));
+ sceneUIController.addShape(jogampLabel);
+
+ final float pixelSizeFPS = font.getPixelSize(fontSizeFPS, dpiH);
+ fpsLabel = new Label(renderer.getRenderState().getVertexFactory(), font, pixelSizeFPS, "Nothing there yet");
+ fpsLabel.translate(0f, 0f, 0f); // FIXME
+ fpsLabel.addMouseListener(new DragAndZoomListener(fpsLabel));
+ fpsLabel.addMouseListener(new DragAndZoomListener(fpsLabel));
+ sceneUIController.addShape(fpsLabel);
+
+ sceneUIController.init(drawable);
+
final GLAnimatorControl a = drawable.getAnimator();
if( null != a ) {
a.resetFPSCounter();
@@ -290,56 +305,26 @@ public class GPUUISceneGLListener0A implements GLEventListener {
renderer.destroy(gl);
}
+ protected void setupPMV(GLAutoDrawable drawable) {
+
+ }
+
@Override
public void display(GLAutoDrawable drawable) {
// System.err.println("GPUUISceneGLListener0A: display");
final GL2ES2 gl = drawable.getGL().getGL2ES2();
- final int width = drawable.getWidth();
- final int height = drawable.getHeight();
-
- gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
- gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
-
- final float pixelSizeFixed = font.getPixelSize(fontSizeFixed, dpiH);
-
- float dx = width * 1f/6f;
- float dy = height - height/6f;
-
- renderer.resetModelview(null);
- // Keep Buttons static ..
- // sceneUIController.setTranslate(nearPlaneX0+xTran+(dx*nearPlaneSx), nearPlaneY0+yTran+((dy-buttonYSize)*nearPlaneSy), nearPlaneZ0+zTran);
- sceneUIController.setTranslate(nearPlaneX0+(dx*nearPlaneSx), nearPlaneY0+((dy-buttonYSize)*nearPlaneSy), nearPlaneZ0);
- sceneUIController.setScale(nearPlaneSx, nearPlaneSy, 1f);
- sceneUIController.setRotation(0, rotButtonsY, 0);
- sceneUIController.display(drawable);
-
- dx = width * 1f/3f;
-
- renderer.resetModelview(null);
- renderer.translate(null, nearPlaneX0+xTran+(dx*nearPlaneSx), nearPlaneY0+yTran+(dy*nearPlaneSy), nearPlaneZ0+zTran);
- renderer.rotate(null, rotTextY , 0, 1, 0);
- renderer.scale(null, nearPlaneSx*zoomText, nearPlaneSy*zoomText, 1f);
- renderer.updateMatrix(gl);
- renderer.setColorStatic(gl, 0.0f, 1.0f, 0.0f);
- jogampLabel.drawShape(gl, renderer, sampleCount, false);
- dy -= 3f * jogampLabel.getLineHeight();
if(null == labels[currentText]) {
+ final float pixelSizeFixed = font.getPixelSize(fontSizeFixed, dpiH);
+ float dx = drawable.getWidth() * 1f/3f;
labels[currentText] = new Label(SVertex.factory(), font, pixelSizeFixed, strings[currentText]);
labels[currentText].setColor(0, 0, 0);
+ labels[currentText].translate(dx, -3f * jogampLabel.getLineHeight(), 0f);
+ labels[currentText].setEnabled(true);
+ labels[currentText].addMouseListener(new DragAndZoomListener(labels[currentText]));
+ sceneUIController.addShape(labels[currentText]);
}
- labels[currentText].validate(gl, renderer);
-
- renderer.resetModelview(null);
- renderer.translate(null, nearPlaneX0+xTran+(dx*nearPlaneSx), nearPlaneY0+yTran+(dy*nearPlaneSy), nearPlaneZ0+zTran);
- renderer.rotate(null, rotTextY, 0, 1, 0);
- renderer.scale(null, nearPlaneSx*zoomText, nearPlaneSy*zoomText, 1f);
- renderer.updateMatrix(gl);
- renderer.setColorStatic(gl, 0.0f, 0.0f, 0.0f);
- labels[currentText].drawShape(gl, renderer, sampleCount, false);
-
- if( showFPS ) {
- final float pixelSizeFPS = font.getPixelSize(fontSizeFPS, dpiH);
+ if( fpsLabel.isEnabled() ) {
final float lfps, tfps, td;
final GLAnimatorControl animator = drawable.getAnimator();
if( null != animator ) {
@@ -353,98 +338,53 @@ public class GPUUISceneGLListener0A implements GLEventListener {
}
final String modeS = Region.getRenderModeString(renderer.getRenderModes());
final String text = String.format("%03.1f/%03.1f fps, v-sync %d, fontSize %.1f, %s-samples %d, td %4.1f, blend %b, alpha-bits %d",
- lfps, tfps, gl.getSwapInterval(), fontSizeFixed, modeS, sampleCount[0], td,
+ lfps, tfps, gl.getSwapInterval(), fontSizeFixed, modeS, sceneUIController.getSampleCount(), td,
renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED),
drawable.getChosenGLCapabilities().getAlphaBits());
- if(null != fpsLabel) {
- fpsLabel.clear(gl, renderer);
- fpsLabel.setText(text);
- } else {
- fpsLabel = new Label(renderer.getRenderState().getVertexFactory(), font, pixelSizeFPS, text);
- }
- renderer.resetModelview(null);
- renderer.translate(null, nearPlaneX0, nearPlaneY0+(nearPlaneSy * pixelSizeFPS / 2f), nearPlaneZ0);
- renderer.scale(null, nearPlaneSx, nearPlaneSy, 1f);
- renderer.updateMatrix(gl);
- fpsLabel.drawShape(gl, renderer, sampleCount, false);
+ fpsLabel.clear(gl, renderer);
+ fpsLabel.setText(text);
}
+ sceneUIController.display(drawable);
}
- public static void mapWin2ObjectCoords(final PMVMatrix pmv, final int[] view,
- final float zNear, final float zFar,
- float orthoX, float orthoY, float orthoDist,
- final float[] winZ, final float[] objPos) {
- winZ[0] = (1f/zNear-1f/orthoDist)/(1f/zNear-1f/zFar);
- pmv.gluUnProject(orthoX, orthoY, winZ[0], view, 0, objPos, 0);
- }
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
System.err.println("GPUUISceneGLListener0A: reshape");
- GL2ES2 gl = drawable.getGL().getGL2ES2();
- final PMVMatrix pmv = renderer.getMatrix();
- renderer.reshapePerspective(gl, 45.0f, width, height, zNear, zFar);
- renderer.resetModelview(null);
- renderer.updateMatrix(gl);
- System.err.printf("Reshape: zNear %f, zFar %f%n", zNear, zFar);
- System.err.printf("Reshape: Frustum: %s%n", pmv.glGetFrustum());
- {
- final float orthoDist = 1f;
- final float[] obj00Coord = new float[3];
- final float[] obj11Coord = new float[3];
- final float[] winZ = new float[1];
- final int[] view = new int[] { 0, 0, width, height };
-
- mapWin2ObjectCoords(pmv, view, zNear, zFar, 0f, 0f, orthoDist, winZ, obj00Coord);
- System.err.printf("Reshape: mapped.00: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", 0f, 0f, orthoDist, winZ[0], obj00Coord[0], obj00Coord[1], obj00Coord[2]);
-
- mapWin2ObjectCoords(pmv, view, zNear, zFar, width, height, orthoDist, winZ, obj11Coord);
- System.err.printf("Reshape: mapped.11: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", (float)width, (float)height, orthoDist, winZ[0], obj11Coord[0], obj11Coord[1], obj11Coord[2]);
-
- nearPlane1Box.setSize( obj00Coord[0], // lx
- obj00Coord[1], // ly
- obj00Coord[2], // lz
- obj11Coord[0], // hx
- obj11Coord[1], // hy
- obj11Coord[2] );// hz
- System.err.printf("Reshape: dist1Box: %s%n", nearPlane1Box);
+ float dx = width * 1f/3f;
+ jogampLabel.setTranslate(dx, 0f, 0f);
+ fpsLabel.setTranslate(0f, 0f, 0f); // FIXME
+ if( null != labels[currentText] ) {
+ labels[currentText].setTranslate(dx, -3f * jogampLabel.getLineHeight(), 0f);
}
- sceneUIController.reshape(drawable, x, y, width, height);
- final float dist = 100f;
- nearPlaneX0 = nearPlane1Box.getMinX() * dist;
- nearPlaneY0 = nearPlane1Box.getMinY() * dist;
- nearPlaneZ0 = nearPlane1Box.getMinZ() * dist;
- final float xd = nearPlane1Box.getWidth() * dist;
- final float yd = nearPlane1Box.getHeight() * dist;
- nearPlaneSx = xd / width;
- nearPlaneSy = yd / height;
- System.err.printf("Scale: [%f x %f] / [%d x %d] = [%f, %f]%n", xd, yd, width, height, nearPlaneSx, nearPlaneSy);
- }
- float nearPlaneX0, nearPlaneY0, nearPlaneZ0, nearPlaneSx, nearPlaneSy;
+ sceneUIController.reshape(drawable, x, y, width, height);
+ }
public void attachInputListenerTo(GLWindow window) {
- if ( null == multiTouchListener ) {
- multiTouchListener = new MultiTouchListener();
- window.addMouseListener(multiTouchListener);
+ if ( !ioAttached ) {
+ ioAttached = true;
sceneUIController.attachInputListenerTo(window);
}
}
public void detachInputListenerFrom(GLWindow window) {
- if ( null != multiTouchListener ) {
- window.removeMouseListener(multiTouchListener);
+ if ( ioAttached ) {
+ ioAttached = false;
sceneUIController.detachInputListenerFrom(window);
}
}
- private class MultiTouchListener extends MouseAdapter {
- int lx = 0;
- int ly = 0;
-
+ private class DragAndZoomListener extends MouseAdapter {
+ final UIShape shape;
+ int lx=-1, ly=-1;
boolean first = false;
+ public DragAndZoomListener(UIShape shape) {
+ this.shape = shape;
+ }
+
@Override
public void mousePressed(MouseEvent e) {
first = true;
@@ -457,7 +397,6 @@ public class GPUUISceneGLListener0A implements GLEventListener {
@Override
public void mouseDragged(MouseEvent e) {
- System.err.println("demo:mousedragged "+e);
if(e.getPointerCount()==2) {
// 2 pointers zoom ..
if(first) {
@@ -467,10 +406,9 @@ public class GPUUISceneGLListener0A implements GLEventListener {
}
int nv = Math.abs(e.getY(0)-e.getY(1));
int dy = nv - lx;
-
- zTran += 2 * Math.signum(dy);
-
lx = nv;
+
+ shape.translate(0f, 0f, 2 * Math.signum(dy));
} else {
// 1 pointer drag
if(first) {
@@ -484,10 +422,9 @@ public class GPUUISceneGLListener0A implements GLEventListener {
int dx = nx - lx;
int dy = ny - ly;
if(Math.abs(dx) > Math.abs(dy)){
- xTran += Math.signum(dx);
- }
- else {
- yTran -= Math.signum(dy);
+ shape.translate(Math.signum(dx), 0f, 0f);
+ } else {
+ shape.translate(0f, -Math.signum(dy), 0f);
}
lx = nx;
ly = ny;
@@ -497,7 +434,9 @@ public class GPUUISceneGLListener0A implements GLEventListener {
@Override
public void mouseWheelMoved(MouseEvent e) {
if( !e.isShiftDown() ) {
- zTran += 2f*e.getRotation()[1]; // vertical: wheel
+ float tz = 2f*e.getRotation()[1]; // vertical: wheel
+ System.err.println("tz.4 "+tz);
+ shape.translate(0f, 0f, tz);
}
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java
index 7e4d5ec62..83ca6bed0 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java
@@ -40,7 +40,7 @@ import com.jogamp.opengl.math.geom.AABBox;
/**
* GPU based resolution independent Button impl
*/
-public abstract class RIButton extends UIShape {
+public class RIButton extends UIShape {
private float width, height;
private final Label label;
/** 20 % to each side default */
@@ -86,13 +86,13 @@ public abstract class RIButton extends UIShape {
}
@Override
- public void drawShape(GL2ES2 gl, RegionRenderer renderer, int[] sampleCount, boolean select) {
+ public void drawShape(GL2ES2 gl, RegionRenderer renderer, int[] sampleCount) {
gl.glEnable(GL2ES2.GL_POLYGON_OFFSET_FILL);
gl.glPolygonOffset(0.0f, 1f);
- super.drawShape(gl, renderer, sampleCount, select);
+ super.drawShape(gl, renderer, sampleCount);
gl.glDisable(GL2ES2.GL_POLYGON_OFFSET_FILL);
- label.drawShape(gl, renderer, sampleCount, select);
+ label.drawShape(gl, renderer, sampleCount);
}
@Override
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java
index c1149227f..fbdc72a1f 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java
@@ -1,8 +1,5 @@
package com.jogamp.opengl.test.junit.graph.demos.ui;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.IntBuffer;
import java.util.ArrayList;
import javax.media.opengl.GL;
@@ -12,28 +9,30 @@ import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLRunnable;
import javax.media.opengl.fixedfunc.GLMatrixFunc;
-import com.jogamp.common.nio.Buffers;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.opengl.GLWindow;
-import com.jogamp.opengl.math.FloatUtil;
-import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.Ray;
+import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.util.PMVMatrix;
public class SceneUIController implements GLEventListener{
private final ArrayList<UIShape> shapes = new ArrayList<UIShape>();
- private int count = 0;
- private int renderModes;
- private int[] sampleCount;
+ private float sceneStartX = 0f;
+ private float sceneStartY = 0f;
+
private RegionRenderer renderer;
- private final float[] translate = new float[3];
- private final float[] scale = new float[3];
- private final Quaternion quaternion = new Quaternion();
+ private final int[] sampleCount = new int[1];
- private final float[] sceneClearColor = new float[]{0,0,0,0};
+ private final float zNear = 0.1f, zFar = 7000f;
+ /** Describing the bounding box in model-coordinates of the near-plane parallel at distance one. */
+ private final AABBox nearPlane1Box = new AABBox();
+ private final int[] viewport = new int[] { 0, 0, 0, 0 };
+ private float nearPlaneX0, nearPlaneY0, nearPlaneZ0, nearPlaneSx, nearPlaneSy;
+ float globMvTx, globMvTy, globMvTz;
private int activeId = -1;
@@ -42,22 +41,16 @@ public class SceneUIController implements GLEventListener{
private GLAutoDrawable cDrawable = null;
public SceneUIController() {
- this(null, 0, null);
+ this(null);
}
- public SceneUIController(RegionRenderer renderer, int renderModes, int[] sampleCount) {
+ public SceneUIController(RegionRenderer renderer) {
this.renderer = renderer;
- this.renderModes = renderModes;
- this.sampleCount = sampleCount;
- setScale(1f, 1f, 1f);
- setTranslate(0f, 0f, 0f);
- setRotation(0f, 0f, 0f);
+ this.sampleCount[0] = 4;
}
- public void setRenderer(RegionRenderer renderer, int renderModes, int[] sampleCount) {
+ public void setRenderer(RegionRenderer renderer) {
this.renderer = renderer;
- this.renderModes = renderModes;
- this.sampleCount = sampleCount;
}
public void attachInputListenerTo(GLWindow window) {
@@ -78,29 +71,92 @@ public class SceneUIController implements GLEventListener{
}
public void addShape(UIShape b) {
shapes.add(b);
- count++;
}
public void removeShape(UIShape b) {
- boolean found = shapes.remove(b);
- if(found) {
- count--;
- }
+ shapes.remove(b);
}
+ public int getSampleCount() { return sampleCount[0]; }
+ public void setSampleCount(int v) { sampleCount[0]=v; }
+
@Override
public void init(GLAutoDrawable drawable) {
System.err.println("SceneUIController: init");
cDrawable = drawable;
}
+
+ public int pickShape(final int winX, int winY) {
+ final float winZ0 = 0f;
+ final float winZ1 = 0.3f;
+ /**
+ final FloatBuffer winZRB = Buffers.newDirectFloatBuffer(1);
+ gl.glReadPixels( x, y, 1, 1, GL2ES2.GL_DEPTH_COMPONENT, GL.GL_FLOAT, winZRB);
+ winZ1 = winZRB.get(0); // dir
+ */
+
+ // flip to GL window coordinates
+ winY = viewport[3] - winY;
+
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+
+ final Ray ray = new Ray();
+ final int shapeCount = shapes.size();
+ for(int i=0; i<shapeCount; i++) {
+ final UIShape uiShape = shapes.get(i);
+ if( uiShape.isEnabled() ) {
+ pmv.glPushMatrix();
+ transformShape(pmv, uiShape);
+
+ pmv.gluUnProjectRay(winX, winY, winZ0, winZ1, viewport, 0, ray);
+ System.err.printf("Pick: mapped.0: [%d, %d, %f/%f] -> %s%n", winX, winY, winZ0, winZ1, ray);
+
+ pmv.glPopMatrix();
+ final AABBox box = shapes.get(i).getBounds();
+ final boolean hit = box.intersectsRay(ray);
+ System.err.println("Test: "+box+" -> hit "+hit+", shape: "+uiShape);
+ if( hit ) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ private void transformShape(final PMVMatrix pmv, final UIShape uiShape) {
+ final float[] uiTranslate = uiShape.getTranslate();
+ float[] uiScale = uiShape.getScale();
+ // System.err.printf("SceneUICtrl.render.1.0: scale.0: %f, %f, %f%n", uiScale[0], uiScale[1], uiScale[2]);
+ // System.err.printf("SceneUICtrl.render.1.0: translate.0: %f, %f, %f%n", uiTranslate[0], uiTranslate[1], uiTranslate[2]);
+ pmv.glRotate(uiShape.getRotation());
+ pmv.glScalef(uiScale[0], uiScale[1], uiScale[2]);
+ pmv.glTranslatef(uiTranslate[0], uiTranslate[1], uiTranslate[2]);
+ }
+
@Override
public void display(GLAutoDrawable drawable) {
- // System.err.println("SceneUIController: display");
- final int width = drawable.getWidth();
- final int height = drawable.getHeight();
- GL2ES2 gl = drawable.getGL().getGL2ES2();
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
- render(gl, width, height, renderModes, sampleCount, false);
+ final int shapeCount = shapes.size();
+ for(int i=0; i<shapeCount; i++) {
+ final UIShape uiShape = shapes.get(i);
+ if( uiShape.isEnabled() ) {
+ uiShape.validate(gl, renderer);
+ pmv.glPushMatrix();
+ transformShape(pmv, uiShape);
+ renderer.updateMatrix(gl);
+ uiShape.drawShape(gl, renderer, sampleCount);
+ pmv.glPopMatrix();
+ // break;
+ }
+ }
}
@Override
@@ -109,24 +165,78 @@ public class SceneUIController implements GLEventListener{
cDrawable = null;
}
+ public static void mapWin2ObjectCoords(final PMVMatrix pmv, final int[] view,
+ final float zNear, final float zFar,
+ float orthoX, float orthoY, float orthoDist,
+ final float[] winZ, final float[] objPos) {
+ winZ[0] = (1f/zNear-1f/orthoDist)/(1f/zNear-1f/zFar);
+ pmv.gluUnProject(orthoX, orthoY, winZ[0], view, 0, objPos, 0);
+ }
+
@Override
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
- }
+ viewport[0] = x;
+ viewport[1] = y;
+ viewport[2] = width;
+ viewport[3] = height;
- public UIShape getShape(GLAutoDrawable drawable,int x, int y) {
- final int width = drawable.getWidth();
- final int height = drawable.getHeight();
- GL2ES2 gl = drawable.getGL().getGL2ES2();
+ sceneStartX = width * 1f/6f;
+ sceneStartY = height - height/6f;
- int index = checkSelection(gl, x, y, width, height);
- if(index == -1)
- return null;
- return shapes.get(index);
+ final GL2ES2 gl = drawable.getGL().getGL2ES2();
+ final PMVMatrix pmv = renderer.getMatrix();
+ renderer.reshapePerspective(gl, 45.0f, width, height, zNear, zFar);
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+
+ System.err.printf("Reshape: zNear %f, zFar %f%n", zNear, zFar);
+ System.err.printf("Reshape: Frustum: %s%n", pmv.glGetFrustum());
+ {
+ final float orthoDist = 1f;
+ final float[] obj00Coord = new float[3];
+ final float[] obj11Coord = new float[3];
+ final float[] winZ = new float[1];
+ final int[] view = new int[] { 0, 0, width, height };
+
+ mapWin2ObjectCoords(pmv, view, zNear, zFar, 0f, 0f, orthoDist, winZ, obj00Coord);
+ System.err.printf("Reshape: mapped.00: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", 0f, 0f, orthoDist, winZ[0], obj00Coord[0], obj00Coord[1], obj00Coord[2]);
+
+ mapWin2ObjectCoords(pmv, view, zNear, zFar, width, height, orthoDist, winZ, obj11Coord);
+ System.err.printf("Reshape: mapped.11: [%f, %f, %f], winZ %f -> [%f, %f, %f]%n", (float)width, (float)height, orthoDist, winZ[0], obj11Coord[0], obj11Coord[1], obj11Coord[2]);
+
+ nearPlane1Box.setSize( obj00Coord[0], // lx
+ obj00Coord[1], // ly
+ obj00Coord[2], // lz
+ obj11Coord[0], // hx
+ obj11Coord[1], // hy
+ obj11Coord[2] );// hz
+ System.err.printf("Reshape: dist1Box: %s%n", nearPlane1Box);
+ }
+ final float dist = 100f;
+ nearPlaneX0 = nearPlane1Box.getMinX() * dist;
+ nearPlaneY0 = nearPlane1Box.getMinY() * dist;
+ nearPlaneZ0 = nearPlane1Box.getMinZ() * dist;
+ final float xd = nearPlane1Box.getWidth() * dist;
+ final float yd = nearPlane1Box.getHeight() * dist;
+ nearPlaneSx = xd / width;
+ nearPlaneSy = yd / height;
+ System.err.printf("Scale: [%f x %f] / [%d x %d] = [%f, %f]%n", xd, yd, width, height, nearPlaneSx, nearPlaneSy);
+
+ // globMvTx=nearPlaneX0+(sceneStartX*nearPlaneSx);
+ // globMvTy=nearPlaneY0+(sceneStartY*nearPlaneSy);
+ globMvTx=nearPlaneX0;
+ globMvTy=nearPlaneY0;
+ globMvTz=nearPlaneZ0;
+ pmv.glTranslatef(globMvTx, globMvTy, globMvTz);
+ pmv.glScalef(nearPlaneSx, nearPlaneSy, 1f);
+ pmv.glTranslatef(sceneStartX, sceneStartY, 0f);
+ renderer.updateMatrix(gl);
}
public UIShape getActiveUI() {
- if(activeId == -1)
+ if( 0 > activeId ) {
return null;
+ }
return shapes.get(activeId);
}
@@ -134,145 +244,86 @@ public class SceneUIController implements GLEventListener{
activeId = -1;
}
- private int checkSelection(GL2ES2 gl,int x, int y, int width, int height) {
- gl.glPixelStorei(GL2ES2.GL_PACK_ALIGNMENT, 4);
- gl.glPixelStorei(GL2ES2.GL_UNPACK_ALIGNMENT, 4);
- gl.glClearColor(sceneClearColor[0], sceneClearColor[1], sceneClearColor[2], sceneClearColor[3]);
- gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
-
- render(gl, width, height, 0, null, true);
- ByteBuffer pixel = Buffers.newDirectByteBuffer(4);
- pixel.order(ByteOrder.nativeOrder());
- IntBuffer viewport = IntBuffer.allocate(4);
- gl.glGetIntegerv(GL2ES2.GL_VIEWPORT, viewport);
- gl.glReadPixels(x, viewport.get(3) - y, 1, 1, GL2ES2.GL_RGBA,
- GL2ES2.GL_UNSIGNED_BYTE, pixel);
-
- int qp = pixel.get(0) & 0xFF;
- int index = Math.round(((qp/255.0f)*(count+2))-1);
- if(index < 0 || index >= count)
- return -1;
- return index;
- }
+ private class SBCMouseListener implements MouseListener {
+ int lx=-1, ly=-1;
- private void render(GL2ES2 gl, int width, int height, int renderModes, int[/*1*/] sampleCount, boolean select) {
- final PMVMatrix pmv = renderer.getMatrix();
- pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
- pmv.glLoadIdentity();
- // System.err.printf("SceneUICtrl.render.1.0: scale.0: %f, %f, %f%n", scale[0], scale[1], scale[2]);
- // System.err.printf("SceneUICtrl.render.1.0: translate.0: %f, %f, %f%n", translate[0], translate[1], translate[2]);
- pmv.glTranslatef(translate[0], translate[1], translate[2]);
- pmv.glRotate(quaternion);
- pmv.glScalef(scale[0], scale[1], scale[2]);
-
- for(int index=0; index < count;index++){
- if(select) {
- float color= index+1;
- renderer.setColorStatic(gl, color/(count+2), color/(count+2), color/(count+2));
- }
- final UIShape uiShape = shapes.get(index);
- uiShape.validate(gl, renderer);
- final float[] uiTranslate = uiShape.getTranslate();
-
- pmv.glPushMatrix();
- // System.err.printf("SceneUICtrl.render.1.0: translate.1: %f, %f%n", uiTranslate[0], uiTranslate[1]);
- pmv.glTranslatef(uiTranslate[0], uiTranslate[1], 0f);
- renderer.updateMatrix(gl);
- uiShape.drawShape(gl, renderer, sampleCount, select);
- pmv.glPopMatrix();
+ void clear() {
+ lx = -1; ly = -1;
}
- }
-
- public void setTranslate(float x, float y, float z) {
- this.translate[0] = x;
- this.translate[1] = y;
- this.translate[2] = z;
- }
-
- public void setScale(float x, float y, float z) {
- this.scale[0] = x;
- this.scale[1] = y;
- this.scale[2] = z;
- }
-
- public void setRotation(float x, float y, float z) {
- quaternion.setFromEuler(x * FloatUtil.PI / 180.0f,
- y * FloatUtil.PI / 180.0f,
- z * FloatUtil.PI / 180.0f);
- }
- public float[] getSceneClearColor() {
- return sceneClearColor;
- }
-
- public void setSceneClearColor(float r, float g, float b, float a) {
- this.sceneClearColor[0] = r;
- this.sceneClearColor[1] = g;
- this.sceneClearColor[2] = b;
- this.sceneClearColor[3] = a;
- }
-
- private class SBCMouseListener implements MouseListener {
- int mouseX = -1;
- int mouseY = -1;
@Override
public void mouseClicked(MouseEvent e) {
UIShape uiShape = getActiveUI();
if(uiShape != null){
- uiShape.onClick(e);
+ uiShape.dispatchMouseEvent(e);
}
+ clear();
+ release();
}
@Override
- public void mousePressed(MouseEvent e) {
+ public void mousePressed(final MouseEvent e) {
if(null==cDrawable) {
return;
}
- mouseX = e.getX();
- mouseY = e.getY();
- GLRunnable runnable = new GLRunnable() {
+ // Avoid race condition w/ matrix instance,
+ // even thought we do not require a GL operation!
+ cDrawable.invoke(true, new GLRunnable() {
@Override
public boolean run(GLAutoDrawable drawable) {
- UIShape s = getShape(drawable, mouseX, mouseY);
- if(null != s) {
- activeId = getShapes().indexOf(s);
- }
- else {
- activeId = -1;
+ activeId = pickShape(e.getX(), e.getY());
+ final UIShape uiShape = getActiveUI();
+ if(uiShape != null) {
+ uiShape.setPressed(true);
+ uiShape.dispatchMouseEvent(e);
}
return false;
- }
- };
- cDrawable.invoke(true, runnable);
-
- UIShape uiShape = getActiveUI();
-
- if(uiShape != null) {
- uiShape.setPressed(true);
- uiShape.onPressed(e);
- }
+ } } );
}
@Override
public void mouseReleased(MouseEvent e) {
- UIShape uiShape = getActiveUI();
+ final UIShape uiShape = getActiveUI();
if(uiShape != null){
uiShape.setPressed(false);
- uiShape.onRelease(e);
+ uiShape.dispatchMouseEvent(e);
}
}
@Override
- public void mouseMoved(MouseEvent e) { }
+ public void mouseDragged(MouseEvent e) {
+ final UIShape uiShape = getActiveUI();
+ if(uiShape != null) {
+ uiShape.dispatchMouseEvent(e);
+ }
+ }
+
@Override
- public void mouseEntered(MouseEvent e) { }
+ public void mouseWheelMoved(final MouseEvent e) {
+ cDrawable.invoke(true, new GLRunnable() {
+ @Override
+ public boolean run(GLAutoDrawable drawable) {
+ activeId = pickShape(lx, ly);
+ final UIShape uiShape = getActiveUI();
+ if(uiShape != null) {
+ uiShape.dispatchMouseEvent(e);
+ }
+ return false;
+ } } );
+ }
+
@Override
- public void mouseExited(MouseEvent e) { }
+ public void mouseMoved(MouseEvent e) {
+ lx = e.getX();
+ ly = e.getY();
+ }
@Override
- public void mouseDragged(MouseEvent e) { }
+ public void mouseEntered(MouseEvent e) { }
@Override
- public void mouseWheelMoved(MouseEvent e) { }
-
+ public void mouseExited(MouseEvent e) {
+ release();
+ clear();
+ }
}
} \ No newline at end of file
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIGLListener01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIGLListener01.java
index 65d8baa01..d8b28c518 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIGLListener01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIGLListener01.java
@@ -33,14 +33,15 @@ import java.io.IOException;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.graph.curve.opengl.RenderState;
import com.jogamp.graph.font.Font;
import com.jogamp.graph.font.FontFactory;
import com.jogamp.graph.geom.SVertex;
-import com.jogamp.newt.event.MouseEvent;
import com.jogamp.opengl.test.junit.graph.demos.MSAATool;
+import com.jogamp.opengl.util.PMVMatrix;
public class UIGLListener01 extends UIListenerBase01 {
@@ -49,19 +50,8 @@ public class UIGLListener01 extends UIListenerBase01 {
setMatrix(-20, 00, 0f, -50);
try {
final Font font = FontFactory.get(FontFactory.UBUNTU).getDefault();
- button = new RIButton(SVertex.factory(), font, "Click me!", 4f, 3f){
- @Override
- public void onClick(MouseEvent e) {
- }
- @Override
- public void onPressed(MouseEvent e) {
- }
- @Override
- public void onRelease(MouseEvent e) {
- }
-
- };
- button.translate(2,1);
+ button = new RIButton(SVertex.factory(), font, "Click me!", 4f, 3f);
+ button.translate(2,1,0);
/** Button defaults !
button.setLabelColor(1.0f,1.0f,1.0f);
button.setButtonColor(0.6f,0.6f,0.6f);
@@ -95,17 +85,18 @@ public class UIGLListener01 extends UIListenerBase01 {
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
- final RegionRenderer regionRenderer = getRegionRenderer();
-
- regionRenderer.resetModelview(null);
-
- regionRenderer.translate(null, getXTran(), getYTran(), getZoom());
- regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
-
final int[] sampleCount = { 4 };
final float[] translate = button.getTranslate();
- regionRenderer.translate(gl, translate[0], translate[1], 0);
- button.drawShape(gl, regionRenderer, sampleCount, false);
+
+ final RegionRenderer regionRenderer = getRegionRenderer();
+ final PMVMatrix pmv = regionRenderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+ pmv.glTranslatef(getXTran(), getYTran(), getZoom());
+ pmv.glRotatef(getAngle(), 0, 1, 0);
+ pmv.glTranslatef(translate[0], translate[1], 0);
+ regionRenderer.updateMatrix(gl);
+ button.drawShape(gl, regionRenderer, sampleCount);
}
@Override
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java
index 715beecca..638e4465b 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java
@@ -29,6 +29,7 @@ package com.jogamp.opengl.test.junit.graph.demos.ui;
import java.util.ArrayList;
+import javax.media.nativewindow.NativeWindowException;
import javax.media.opengl.GL2ES2;
import jogamp.graph.geom.plane.AffineTransform;
@@ -42,6 +43,8 @@ import com.jogamp.graph.curve.opengl.RenderState;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.graph.geom.Vertex.Factory;
import com.jogamp.newt.event.MouseEvent;
+import com.jogamp.newt.event.MouseListener;
+import com.jogamp.opengl.math.Quaternion;
import com.jogamp.opengl.math.geom.AABBox;
public abstract class UIShape {
@@ -52,14 +55,16 @@ public abstract class UIShape {
protected final ArrayList<OutlineShapeXForm> shapes;
protected static final int DIRTY_SHAPE = 1 << 0 ;
- protected static final int DIRTY_POSITION = 1 << 1 ;
protected static final int DIRTY_REGION = 1 << 2 ;
- protected int dirty = DIRTY_SHAPE | DIRTY_POSITION | DIRTY_REGION;
+ protected int dirty = DIRTY_SHAPE | DIRTY_REGION;
protected final AABBox box;
- protected final float[] translate = new float[] { 0f, 0f };
- protected final float[] shapeTranslate = new float[] { 0f, 0f };
- protected final float[] shapeScale = new float[] { 1f, 1f };
+ protected final float[] translate = new float[] { 0f, 0f, 0f };
+ protected final Quaternion rotation = new Quaternion();
+ protected final float[] scale = new float[] { 1f, 1f, 1f };
+
+ protected final float[] shapeTranslate2D = new float[] { 0f, 0f };
+ protected final float[] shapeScale2D = new float[] { 1f, 1f };
private GLRegion region = null;
protected final float[] color = {0.6f, 0.6f, 0.6f};
@@ -68,6 +73,8 @@ public abstract class UIShape {
private boolean down = false;
private boolean toggle =false;
private boolean toggleable = false;
+ private boolean enabled = true;
+ private ArrayList<MouseListener> mouseListeners = new ArrayList<MouseListener>();
public UIShape(Factory<? extends Vertex> factory) {
this.vertexFactory = factory;
@@ -77,6 +84,9 @@ public abstract class UIShape {
public final Vertex.Factory<? extends Vertex> getVertexFactory() { return vertexFactory; }
+ public boolean isEnabled() { return enabled; }
+ public void setEnabled(boolean v) { enabled = v; }
+
/**
* Clears all data and reset all states as if this instance was newly created
* @param gl TODO
@@ -87,12 +97,17 @@ public abstract class UIShape {
shapes.clear();
translate[0] = 0f;
translate[1] = 0f;
- shapeTranslate[0] = 0f;
- shapeTranslate[1] = 0f;
- shapeScale[0] = 1f;
- shapeScale[1] = 1f;
+ translate[2] = 0f;
+ rotation.setIdentity();
+ scale[0] = 1f;
+ scale[1] = 1f;
+ scale[2] = 1f;
+ shapeTranslate2D[0] = 0f;
+ shapeTranslate2D[1] = 0f;
+ shapeScale2D[0] = 1f;
+ shapeScale2D[1] = 1f;
box.reset();
- dirty = DIRTY_SHAPE | DIRTY_POSITION | DIRTY_REGION;
+ dirty = DIRTY_SHAPE | DIRTY_REGION;
}
/**
@@ -105,43 +120,56 @@ public abstract class UIShape {
shapes.clear();
translate[0] = 0f;
translate[1] = 0f;
- shapeTranslate[0] = 0f;
- shapeTranslate[1] = 0f;
- shapeScale[0] = 1f;
- shapeScale[1] = 1f;
+ translate[2] = 0f;
+ rotation.setIdentity();
+ scale[0] = 1f;
+ scale[1] = 1f;
+ scale[2] = 1f;
+ shapeTranslate2D[0] = 0f;
+ shapeTranslate2D[1] = 0f;
+ shapeScale2D[0] = 1f;
+ shapeScale2D[1] = 1f;
box.reset();
- dirty = DIRTY_SHAPE | DIRTY_POSITION | DIRTY_REGION;
+ dirty = DIRTY_SHAPE | DIRTY_REGION;
}
- public final void translate(float tx, float ty) {
+ public final void setTranslate(float tx, float ty, float tz) {
+ translate[0] = tx;
+ translate[1] = ty;
+ translate[2] = tz;
+ }
+ public final void translate(float tx, float ty, float tz) {
translate[0] += tx;
translate[1] += ty;
- dirty |= DIRTY_POSITION;
+ translate[2] += tz;
}
- public final float[] getTranslate() {
- if( !isShapeDirty() ) {
- validatePosition();
- }
- return translate;
+ public final float[] getTranslate() { return translate; }
+ public final Quaternion getRotation() { return rotation; }
+ public final void setScale(float sx, float sy, float sz) {
+ scale[0] = sx;
+ scale[1] = sy;
+ scale[2] = sz;
}
+ public final void scale(float sx, float sy, float sz) {
+ scale[0] *= sx;
+ scale[1] *= sy;
+ scale[2] *= sz;
+ }
+ public final float[] getScale() { return scale; }
public final void translateShape(float tx, float ty) {
- shapeTranslate[0] += tx;
- shapeTranslate[1] += ty;
+ shapeTranslate2D[0] += tx;
+ shapeTranslate2D[1] += ty;
}
public final void scaleShape(float sx, float sy) {
- shapeScale[0] *= sx;
- shapeScale[1] *= sy;
+ shapeScale2D[0] *= sx;
+ shapeScale2D[1] *= sy;
}
public final boolean isShapeDirty() {
return 0 != ( dirty & DIRTY_SHAPE ) ;
}
- public final boolean isPositionDirty() {
- return 0 != ( dirty & DIRTY_POSITION ) ;
- }
-
public final boolean isRegionDirty() {
return 0 != ( dirty & DIRTY_REGION ) ;
}
@@ -173,9 +201,8 @@ public abstract class UIShape {
* @param gl
* @param renderer
* @param sampleCount
- * @param select
*/
- public void drawShape(GL2ES2 gl, RegionRenderer renderer, int[] sampleCount, boolean select) {
+ public void drawShape(GL2ES2 gl, RegionRenderer renderer, int[] sampleCount) {
final float[] _color;
if( isPressed() || toggle ){
_color = selectedColor;
@@ -183,23 +210,15 @@ public abstract class UIShape {
_color = color;
}
- if(!select){
- if( renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED) ) {
- gl.glClearColor(_color[0], _color[1], _color[2], 0.0f);
- }
- renderer.setColorStatic(gl, _color[0], _color[1], _color[2]);
+ if( renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED) ) {
+ gl.glClearColor(_color[0], _color[1], _color[2], 0.0f);
}
+ renderer.setColorStatic(gl, _color[0], _color[1], _color[2]);
+
getRegion(gl, renderer).draw(gl, renderer, sampleCount);
}
public final boolean validate(GL2ES2 gl, RegionRenderer renderer) {
- if( !validateShape(gl, renderer) ) {
- return validatePosition();
- }
- return true;
- }
-
- private final boolean validateShape(GL2ES2 gl, RegionRenderer renderer) {
if( isShapeDirty() ) {
shapes.clear();
box.reset();
@@ -211,39 +230,24 @@ public abstract class UIShape {
}
dirty &= ~DIRTY_SHAPE;
dirty |= DIRTY_REGION;
- validatePosition();
- return true;
- }
- return false;
- }
- private final boolean validatePosition () {
- if( isPositionDirty() && !isShapeDirty() ) {
- // Subtract the bbox minx/miny from position, i.e. the shape's offset.
- final AABBox box = getBounds();
- final float minX = box.getMinX();
- final float minY = box.getMinY();
- // System.err.println("XXX.UIShape: Position pre: " + translate[0] + " " + translate[1] + ", sbox "+box);
- translate(-minX, -minY);
- // System.err.println("XXX.UIShape: Position post: " + translate[0] + " " + translate[1] + ", sbox "+box);
- dirty &= ~DIRTY_POSITION;
return true;
}
return false;
}
private final void addToRegion(Region region) {
- final boolean hasLocTrans = 0f != shapeTranslate[0] || 0f != shapeTranslate[1];
- final boolean hasLocScale = 1f != shapeScale[0] || 1f != shapeScale[1];
+ final boolean hasLocTrans = 0f != shapeTranslate2D[0] || 0f != shapeTranslate2D[1];
+ final boolean hasLocScale = 1f != shapeScale2D[0] || 1f != shapeScale2D[1];
final AffineTransform t;
if( hasLocScale || hasLocTrans ) {
// System.err.printf("UIShape.addToRegion: locTranslate %f x %f, locScale %f x %f%n",
// shapeTranslate[0], shapeTranslate[1], shapeScale[0], shapeScale[1]);
t = new AffineTransform();
if( hasLocTrans ) {
- t.translate(shapeTranslate[0], shapeTranslate[1]);
+ t.translate(shapeTranslate2D[0], shapeTranslate2D[1]);
}
if( hasLocScale ) {
- t.scale(shapeScale[0], shapeScale[1]);
+ t.scale(shapeScale2D[0], shapeScale2D[1]);
}
} else {
t = null;
@@ -280,6 +284,10 @@ public abstract class UIShape {
this.selectedColor[2] = b;
}
+ public String toString() {
+ return getClass().getSimpleName()+"[enabled "+enabled+", box "+box+"]";
+ }
+
//
// Input
//
@@ -303,9 +311,60 @@ public abstract class UIShape {
this.toggleable = toggleable;
}
- public void onClick(MouseEvent e) { }
- public void onPressed(MouseEvent e) { }
- public void onRelease(MouseEvent e) { }
+ public final void addMouseListener(MouseListener l) {
+ if(l == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ ArrayList<MouseListener> clonedListeners = (ArrayList<MouseListener>) mouseListeners.clone();
+ clonedListeners.add(l);
+ mouseListeners = clonedListeners;
+ }
+
+ public final void removeMouseListener(MouseListener l) {
+ if (l == null) {
+ return;
+ }
+ @SuppressWarnings("unchecked")
+ ArrayList<MouseListener> clonedListeners = (ArrayList<MouseListener>) mouseListeners.clone();
+ clonedListeners.remove(l);
+ mouseListeners = clonedListeners;
+ }
+
+ public final void dispatchMouseEvent(MouseEvent e) {
+ e.setAttachment(this);
+ for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) {
+ final MouseListener l = mouseListeners.get(i);
+ switch(e.getEventType()) {
+ case MouseEvent.EVENT_MOUSE_CLICKED:
+ l.mouseClicked(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_ENTERED:
+ l.mouseEntered(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_EXITED:
+ l.mouseExited(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_PRESSED:
+ l.mousePressed(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_RELEASED:
+ l.mouseReleased(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_MOVED:
+ l.mouseMoved(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_DRAGGED:
+ l.mouseDragged(e);
+ break;
+ case MouseEvent.EVENT_MOUSE_WHEEL_MOVED:
+ l.mouseWheelMoved(e);
+ break;
+ default:
+ throw new NativeWindowException("Unexpected mouse event type " + e.getEventType());
+ }
+ }
+ }
//
//
@@ -332,6 +391,7 @@ public abstract class UIShape {
shape.addVertex(minX+tw, minY + th, z, true);
shape.addVertex(minX, minY + th, z, true);
shape.closeLastOutline(true);
+
return shape;
}