aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/CrossHair.java7
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/SceneUIController.java94
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShape.java176
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShapeDemo01.java339
4 files changed, 444 insertions, 172 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/CrossHair.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/CrossHair.java
index 209ce3e57..0c8595c70 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/CrossHair.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/CrossHair.java
@@ -35,7 +35,7 @@ import com.jogamp.graph.geom.Vertex;
import com.jogamp.graph.geom.Vertex.Factory;
/**
- * GPU based resolution independent Button impl
+ * GPU based resolution independent Crosshair
*/
public class CrossHair extends UIShape {
private float width, height, lineWidth;
@@ -70,11 +70,12 @@ public class CrossHair extends UIShape {
protected void addShapeToRegion(final GL2ES2 gl, final RegionRenderer renderer) {
final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory());
+ final float lwh = lineWidth/2f;
+
final float tw = getWidth();
final float th = getHeight();
final float twh = tw/2f;
final float thh = th/2f;
- final float lwh = lineWidth/2f;
final float ctrX = 0f, ctrY = 0f;
final float ctrZ = 0f;
@@ -86,8 +87,6 @@ public class CrossHair extends UIShape {
shape.lineTo(ctrX-lwh, ctrY+thh, ctrZ);
shape.closePath();
- // ctrZ -= 0.05f;
-
// middle horizontal (CCW!)
shape.moveTo(ctrX-twh, ctrY-lwh, ctrZ);
shape.lineTo(ctrX+twh, ctrY-lwh, ctrZ);
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 98ddc1db2..9de206cac 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
@@ -20,9 +20,7 @@ import com.jogamp.newt.event.PinchToZoomGesture;
import com.jogamp.newt.event.GestureHandler.GestureEvent;
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.VectorUtil;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.util.PMVMatrix;
@@ -130,35 +128,6 @@ public class SceneUIController implements GLEventListener{
cDrawable = drawable;
}
- private void transformShape(final PMVMatrix pmv, final UIShape uiShape) {
- final float[] uiTranslate = uiShape.getTranslate();
- pmv.glTranslatef(uiTranslate[0], uiTranslate[1], uiTranslate[2]);
- // final float dz = 100f;
-
- final Quaternion quat = uiShape.getRotation();
- final boolean rotate = !quat.isIdentity();
- final float[] uiScale = uiShape.getScale();
- final boolean scale = !VectorUtil.isVec3Equal(uiScale, 0, VectorUtil.VEC3_ONE, 0, FloatUtil.EPSILON);
- if( rotate || scale ) {
- final float[] rotOrigin = uiShape.getRotationOrigin();
- final boolean pivot = !VectorUtil.isVec3Zero(rotOrigin, 0, FloatUtil.EPSILON);
- // pmv.glTranslatef(0f, 0f, dz);
- if( pivot ) {
- pmv.glTranslatef(rotOrigin[0], rotOrigin[1], rotOrigin[2]);
- }
- if( scale ) {
- pmv.glScalef(uiScale[0], uiScale[1], uiScale[2]);
- }
- if( rotate ) {
- pmv.glRotate(quat);
- }
- if( pivot ) {
- pmv.glTranslatef(-rotOrigin[0], -rotOrigin[1], -rotOrigin[2]);
- }
- // pmv.glTranslatef(0f, 0f, -dz);
- }
- }
-
private static Comparator<UIShape> shapeZAscComparator = new Comparator<UIShape>() {
@Override
public int compare(final UIShape s1, final UIShape s2) {
@@ -198,7 +167,7 @@ public class SceneUIController implements GLEventListener{
if( uiShape.isEnabled() ) {
uiShape.validate(gl, renderer);
pmv.glPushMatrix();
- transformShape(pmv, uiShape);
+ uiShape.setTransform(pmv);
uiShape.drawShape(gl, renderer, sampleCount);
pmv.glPopMatrix();
}
@@ -243,7 +212,7 @@ public class SceneUIController implements GLEventListener{
if( uiShape.isEnabled() ) {
pmv.glPushMatrix();
- transformShape(pmv, uiShape);
+ uiShape.setTransform(pmv);
final boolean ok = pmv.gluUnProjectRay(glWinX, glWinY, winZ0, winZ1, viewport, 0, ray);
pmv.glPopMatrix();
if( ok ) {
@@ -265,6 +234,14 @@ public class SceneUIController implements GLEventListener{
private final float[] dpyTmp2V3 = new float[3];
private final float[] dpyTmp3V3 = new float[3];
+ /**
+ * Calling {@link UIShape#winToObjCoord(RegionRenderer, int, int, float[])}, retrieving its object position.
+ * @param activeShape
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ * @param objPos resulting object position
+ * @param runnable action
+ */
public void windowToShapeCoords(final UIShape activeShape, final int glWinX, final int glWinY, final float[] objPos, final Runnable runnable) {
if( null == cDrawable || null == activeShape ) {
return;
@@ -272,30 +249,12 @@ public class SceneUIController implements GLEventListener{
cDrawable.invoke(false, new GLRunnable() {
@Override
public boolean run(final GLAutoDrawable drawable) {
- if( windowToShapeCoordsImpl(activeShape, glWinX, glWinY, objPos) ) {
+ if( activeShape.winToObjCoord(renderer, glWinX, glWinY, objPos) ) {
runnable.run();
}
return true;
} } );
}
- private boolean windowToShapeCoordsImpl(final UIShape activeShape, final int glWinX, final int glWinY, final float[] objPos) {
- final PMVMatrix pmv = renderer.getMatrix();
- pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
-
- pmv.glPushMatrix();
- transformShape(pmv, activeShape);
- boolean res = false;
- final float[] ctr = activeShape.getBounds().getCenter();
- if( pmv.gluProject(ctr[0], ctr[1], ctr[2], viewport, 0, dpyTmp1V3, 0) ) {
- // System.err.printf("winToShapeCoords.0: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", shapeId, ctr[0], ctr[1], ctr[2], dpyTmp1V3[0], dpyTmp1V3[1], dpyTmp1V3[2]);
- if( pmv.gluUnProject(glWinX, glWinY, dpyTmp1V3[2], viewport, 0, objPos, 0) ) {
- // System.err.printf("winToShapeCoords.1: shape %d: win [%d, %d, %f] -> obj [%f, %f, %f]%n", shapeId, glWinX, glWinY, dpyTmp1V3[2], objPos[0], objPos[1], objPos[2]);
- res = true;
- }
- }
- pmv.glPopMatrix();
- return res;
- }
@Override
public void dispose(final GLAutoDrawable drawable) {
@@ -397,6 +356,7 @@ public class SceneUIController implements GLEventListener{
final float[] objPos = new float[3];
final UIShape shape = activeShape;
windowToShapeCoords(shape, glWinX, glWinY, objPos, new Runnable() {
+ @Override
public void run() {
shape.dispatchGestureEvent(gh, glWinX, glWinY, objPos);
} } );
@@ -405,6 +365,12 @@ public class SceneUIController implements GLEventListener{
}
}
+ /**
+ * Dispatch mouse event, either directly sending to activeShape or picking one
+ * @param e original Newt {@link MouseEvent}
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ */
final void dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY) {
if( null == activeShape ) {
dispatchMouseEventPickShape(e, glWinX, glWinY, true);
@@ -412,20 +378,36 @@ public class SceneUIController implements GLEventListener{
dispatchMouseEventForShape(activeShape, e, glWinX, glWinY);
}
}
+ /**
+ * Pick the shape using the event coordinates
+ * @param e original Newt {@link MouseEvent}
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ * @param setActive
+ */
final void dispatchMouseEventPickShape(final MouseEvent e, final int glWinX, final int glWinY, final boolean setActive) {
final float[] objPos = new float[3];
final UIShape[] shape = { null };
pickShape(glWinX, glWinY, objPos, shape, new Runnable() {
- public void run() {
+ @Override
+ public void run() {
if( setActive ) {
setActiveShape(shape[0]);
}
shape[0].dispatchMouseEvent(e, glWinX, glWinY, objPos);
} } );
}
+ /**
+ * Dispatch event to shape
+ * @param shape target active shape of event
+ * @param e original Newt {@link MouseEvent}
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ */
final void dispatchMouseEventForShape(final UIShape shape, final MouseEvent e, final int glWinX, final int glWinY) {
final float[] objPos = new float[3];
windowToShapeCoords(shape, glWinX, glWinY, objPos, new Runnable() {
+ @Override
public void run() {
shape.dispatchMouseEvent(e, glWinX, glWinY, objPos);
} } );
@@ -445,7 +427,7 @@ public class SceneUIController implements GLEventListener{
ly = e.getY();
lId = e.getPointerId(0);
}
- // flip to GL window coordinates
+ // flip to GL window coordinates, origin bottom-left
final int glWinX = e.getX();
final int glWinY = viewport[3] - e.getY() - 1;
dispatchMouseEvent(e, glWinX, glWinY);
@@ -453,7 +435,7 @@ public class SceneUIController implements GLEventListener{
@Override
public void mouseReleased(final MouseEvent e) {
- // flip to GL window coordinates
+ // flip to GL window coordinates, origin bottom-left
final int glWinX = e.getX();
final int glWinY = viewport[3] - e.getY() - 1;
dispatchMouseEvent(e, glWinX, glWinY);
@@ -484,7 +466,7 @@ public class SceneUIController implements GLEventListener{
ly = e.getY();
// dragged .. delegate to active shape!
- // flip to GL window coordinates
+ // flip to GL window coordinates, origin bottom-left
final int glWinX = lx;
final int glWinY = viewport[3] - ly - 1;
dispatchMouseEventForShape(activeShape, e, glWinX, glWinY);
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 4976c78e8..f8c04d4bf 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
@@ -31,7 +31,7 @@ import java.util.ArrayList;
import com.jogamp.nativewindow.NativeWindowException;
import com.jogamp.opengl.GL2ES2;
-
+import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
import com.jogamp.graph.curve.OutlineShape;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.curve.opengl.GLRegion;
@@ -44,11 +44,14 @@ import com.jogamp.newt.event.MouseAdapter;
import com.jogamp.newt.event.NEWTEvent;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
+import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.Quaternion;
+import com.jogamp.opengl.math.VectorUtil;
import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.util.PMVMatrix;
public abstract class UIShape {
- public static final boolean DRAW_DEBUG_BOX = true;
+ public static final boolean DRAW_DEBUG_BOX = false;
protected static final int DIRTY_SHAPE = 1 << 0 ;
protected static final int DIRTY_STATE = 1 << 1 ;
@@ -280,7 +283,7 @@ public abstract class UIShape {
region.clear(gl);
}
addShapeToRegion(gl, renderer);
- if( false && DRAW_DEBUG_BOX ) {
+ if( DRAW_DEBUG_BOX ) {
region.clear(gl);
final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory());
shape.setSharpness(shapesSharpness);
@@ -295,6 +298,124 @@ public abstract class UIShape {
}
}
+ public void setTransform(final PMVMatrix pmv) {
+ final float[] uiTranslate = getTranslate();
+ pmv.glTranslatef(uiTranslate[0], uiTranslate[1], uiTranslate[2]);
+
+ final Quaternion quat = getRotation();
+ final boolean rotate = !quat.isIdentity();
+ final float[] uiScale = getScale();
+ final boolean scale = !VectorUtil.isVec3Equal(uiScale, 0, VectorUtil.VEC3_ONE, 0, FloatUtil.EPSILON);
+ if( rotate || scale ) {
+ final float[] rotOrigin = getRotationOrigin();
+ final boolean pivot = !VectorUtil.isVec3Zero(rotOrigin, 0, FloatUtil.EPSILON);
+ if( pivot ) {
+ pmv.glTranslatef(rotOrigin[0], rotOrigin[1], rotOrigin[2]);
+ }
+ if( scale ) {
+ pmv.glScalef(uiScale[0], uiScale[1], uiScale[2]);
+ }
+ if( rotate ) {
+ pmv.glRotate(quat);
+ }
+ if( pivot ) {
+ pmv.glTranslatef(-rotOrigin[0], -rotOrigin[1], -rotOrigin[2]);
+ }
+ }
+ }
+
+ /**
+ * Retrieve window surface size of this shape
+ * @param renderer source of viewport and PMVMatrix
+ * @param surfaceSize target surface size
+ * @return true for successful gluProject(..) operation, otherwise false
+ */
+ public boolean getSurfaceSize(final RegionRenderer renderer, final int[/*2*/] surfaceSize) {
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+
+ pmv.glPushMatrix();
+ setTransform(pmv);
+ boolean res = false;
+ final int[/*4*/] viewport = renderer.getViewport(new int[4]);
+ // System.err.println("UIShape::getSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]);
+ final float[] winCoordHigh = new float[3];
+ final float[] winCoordLow = new float[3];
+ final float[] high = getBounds().getHigh();
+ final float[] low = getBounds().getLow();
+
+ if( pmv.gluProject(high[0], high[1], high[2], viewport, 0, winCoordHigh, 0) ) {
+ // System.err.printf("UIShape::surfaceSize.H: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), high[0], high[1], high[2], winCoordHigh[0], winCoordHigh[1], winCoordHigh[2]);
+ if( pmv.gluProject(low[0], low[1], low[2], viewport, 0, winCoordLow, 0) ) {
+ // System.err.printf("UIShape::surfaceSize.L: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), low[0], low[1], low[2], winCoordLow[0], winCoordLow[1], winCoordLow[2]);
+ surfaceSize[0] = (int)(winCoordHigh[0] - winCoordLow[0]);
+ surfaceSize[1] = (int)(winCoordHigh[1] - winCoordLow[1]);
+ // System.err.printf("UIShape::surfaceSize.S: shape %d: %f x %f -> %d x %d%n", getName(), winCoordHigh[0] - winCoordLow[0], winCoordHigh[1] - winCoordLow[1], surfaceSize[0], surfaceSize[1]);
+ res = true;
+ }
+ }
+ pmv.glPopMatrix();
+ return res;
+ }
+
+ /**
+ * Map given object coordinate relative to this shape to window coordinates
+ * @param renderer source of viewport and PMVMatrix
+ * @param objPos object position relative to this shape's center
+ * @param glWinPos target window position of objPos relative to this shape
+ * @return true for successful gluProject(..) operation, otherwise false
+ */
+ public boolean objToWinCoord(final RegionRenderer renderer, final float[/*3*/] objPos, final int[/*2*/] glWinPos) {
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+
+ pmv.glPushMatrix();
+ setTransform(pmv);
+ boolean res = false;
+ final int[/*4*/] viewport = renderer.getViewport(new int[4]);
+ // System.err.println("UIShape::objToWinCoordgetSurfaceSize.VP "+viewport[0]+"/"+viewport[1]+" "+viewport[2]+"x"+viewport[3]);
+ final float[] winCoord = new float[3];
+
+ if( pmv.gluProject(objPos[0], objPos[1], objPos[2], viewport, 0, winCoord, 0) ) {
+ // System.err.printf("UIShape::objToWinCoord.0: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), objPos[0], objPos[1], objPos[2], winCoord[0], winCoord[1], winCoord[2]);
+ glWinPos[0] = (int)(winCoord[0]);
+ glWinPos[1] = (int)(winCoord[1]);
+ // System.err.printf("UIShape::objToWinCoord.X: shape %d: %f / %f -> %d / %d%n", getName(), winCoord[0], winCoord[1], glWinPos[0], glWinPos[1]);
+ res = true;
+ }
+ pmv.glPopMatrix();
+ return res;
+ }
+
+ /**
+ * Map given gl-window-coordinates to object coordinates relative to this shape and its z-coordinate.
+ * @param renderer source of viewport and PMVMatrix
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ * @param objPos target object position of glWinX/glWinY relative to this shape
+ * @return @return true for successful gluProject(..) and gluUnProject(..) operations, otherwise false
+ */
+ public boolean winToObjCoord(final RegionRenderer renderer, final int glWinX, final int glWinY, final float[/*3*/] objPos) {
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+
+ pmv.glPushMatrix();
+ setTransform(pmv);
+ boolean res = false;
+ final float[] ctr = getBounds().getCenter();
+ final int[] viewport = renderer.getViewport(new int[4]);
+ final float[] tmp = new float[3];
+ if( pmv.gluProject(ctr[0], ctr[1], ctr[2], viewport, 0, tmp, 0) ) {
+ // System.err.printf("UIShape::winToObjCoord.0: shape %d: obj [%f, %f, %f] -> win [%f, %f, %f]%n", getName(), ctr[0], ctr[1], ctr[2], tmp[0], tmp[1], tmp[2]);
+ if( pmv.gluUnProject(glWinX, glWinY, tmp[2], viewport, 0, objPos, 0) ) {
+ // System.err.printf("UIShape::winToObjCoord.1: shape %d: win [%d, %d, %f] -> obj [%f, %f, %f]%n", getName(), glWinX, glWinY, tmp[2], objPos[0], objPos[1], objPos[2]);
+ res = true;
+ }
+ }
+ pmv.glPopMatrix();
+ return res;
+ }
+
public float[] getColor() {
return rgbaColor;
}
@@ -420,15 +541,22 @@ public abstract class UIShape {
* The latter fields are also normalized to lower-left zero origin, allowing easier usage.
*/
public static class PointerEventInfo {
- /** The intended {@link UIShape} instance for this event */
+ /** The associated {@link UIShape} for this event */
public final UIShape shape;
- /** The relative pointer position inside the intended {@link UIShape}. */
+ /** The relative object coordinate of glWinX/glWinY to the associated {@link UIShape}. */
public final float[] objPos;
- /** window x-position in OpenGL model space */
+ /** X-coordinate in GL window coordinates, origin bottom-left */
public final int glWinX;
- /** window y-position in OpenGL model space */
+ /** Y-coordinate in GL window coordinates, origin bottom-left */
public final int glWinY;
+ /**
+ * Ctor
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ * @param shape associated shape
+ * @param objPos relative object coordinate of glWinX/glWinY to the associated shape.
+ */
PointerEventInfo(final int glWinX, final int glWinY, final UIShape shape, final float[] objPos) {
this.glWinX = glWinX;
this.glWinY = glWinY;
@@ -455,10 +583,11 @@ public abstract class UIShape {
}
/**
- *
+ * Dispatch given NEWT mouse event to this shape
* @param e original Newt {@link MouseEvent}
- * @param glX x-position in OpenGL model space
- * @param glY y-position in OpenGL model space
+ * @param glWinX in GL window coordinates, origin bottom-left
+ * @param glWinY in GL window coordinates, origin bottom-left
+ * @param objPos object position of mouse event within this shape
*/
public final void dispatchMouseEvent(final MouseEvent e, final int glWinX, final int glWinY, final float[] objPos) {
e.setAttachment(new PointerEventInfo(glWinX, glWinY, this, objPos));
@@ -524,19 +653,26 @@ public abstract class UIShape {
//
protected OutlineShape createDebugOutline(final OutlineShape shape, final AABBox box) {
- final float tw = box.getWidth();
- final float th = box.getHeight();
+ final float d = 0.025f;
+ final float tw = box.getWidth() + d*2f;
+ final float th = box.getHeight() + d*2f;
- final float minX = box.getMinX();
- final float minY = box.getMinY();
- final float z = box.getMinZ() + 0.025f;
+ final float minX = box.getMinX() - d;
+ final float minY = box.getMinY() - d;
+ final float z = 0; // box.getMinZ() + 0.025f;
// CCW!
- shape.addVertex(minX, minY, z, true);
- shape.addVertex(minX+tw, minY, z, true);
- shape.addVertex(minX+tw, minY + th, z, true);
- shape.addVertex(minX, minY + th, z, true);
- shape.closeLastOutline(true);
+ shape.moveTo(minX, minY, z);
+ shape.lineTo(minX+tw, minY, z);
+ shape.lineTo(minX+tw, minY + th, z);
+ shape.lineTo(minX, minY + th, z);
+ shape.closePath();
+
+ // shape.addVertex(minX, minY, z, true);
+ // shape.addVertex(minX+tw, minY, z, true);
+ // shape.addVertex(minX+tw, minY + th, z, true);
+ // shape.addVertex(minX, minY + th, z, true);
+ // shape.closeLastOutline(true);
return shape;
}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShapeDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShapeDemo01.java
index f18491a2a..b9d249e19 100644
--- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShapeDemo01.java
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIShapeDemo01.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -37,27 +37,40 @@ import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLAnimatorControl;
import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLEventListener;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLPipelineFactory;
+import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.GLRunnable;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;
+import com.jogamp.opengl.math.FloatUtil;
+import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.test.junit.graph.demos.MSAATool;
+import com.jogamp.common.util.InterruptSource;
import com.jogamp.graph.curve.Region;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.graph.curve.opengl.RenderState;
+import com.jogamp.graph.curve.opengl.TextRegionUtil;
import com.jogamp.graph.font.Font;
import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.font.FontSet;
import com.jogamp.graph.geom.SVertex;
+import com.jogamp.newt.Window;
+import com.jogamp.newt.event.KeyAdapter;
import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.newt.event.MouseListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.GLReadBufferUtil;
import com.jogamp.opengl.util.PMVMatrix;
/**
+ * Basic UIShape and Type Rendering demo.
*
* Action Keys:
* - 1/2: zoom in/out
@@ -67,14 +80,77 @@ import com.jogamp.opengl.util.PMVMatrix;
* - v: toggle v-sync
* - s: screenshot
*/
-public class UIListener01 implements GLEventListener {
+public class UIShapeDemo01 implements GLEventListener {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(final String[] args) throws IOException {
+ Font font = null;
+ if( 0 != args.length ) {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-font")) {
+ i++;
+ font = FontFactory.get(new File(args[i]));
+ }
+ }
+ }
+ if( null == font ) {
+ font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF);
+ }
+ System.err.println("Font: "+font.getFullFamilyName());
+
+ final GLProfile glp = GLProfile.getGL2ES2();
+ final GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ System.out.println("Requested: " + caps);
+
+ final GLWindow window = GLWindow.create(caps);
+ // window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle(UIShapeDemo01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight());
+ final RenderState rs = RenderState.createRenderState(SVertex.factory());
+ final UIShapeDemo01 uiGLListener = new UIShapeDemo01(font, Region.COLORCHANNEL_RENDERING_BIT, rs, DEBUG, TRACE);
+ uiGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(uiGLListener);
+ window.setVisible(true);
+
+ final Animator animator = new Animator();
+ // animator.setUpdateFPSFrames(60, System.err);
+ animator.add(window);
+
+ window.addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyPressed(final KeyEvent arg0) {
+ if(arg0.getKeyCode() == KeyEvent.VK_F4) {
+ new InterruptSource.Thread() {
+ @Override
+ public void run() {
+ window.destroy();
+ } }.start();
+ }
+ }
+ });
+ window.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowDestroyed(final WindowEvent e) {
+ animator.stop();
+ }
+ });
+
+ animator.start();
+ }
+
+ private final Font font;
private final GLReadBufferUtil screenshot;
private final int renderModes;
private final RegionRenderer rRenderer;
private final boolean debug;
private final boolean trace;
- protected LabelButton button;
+ private final LabelButton button;
+ private final CrossHair crossHair;
private KeyAction keyAction;
private MouseAction mouseAction;
@@ -83,52 +159,39 @@ public class UIListener01 implements GLEventListener {
private final float[] position = new float[] {0,0,0};
- private float xTran = -10;
- private float yTran = 10;
- private float ang = 0f;
- private float zoom = -70f;
+ private static final float xTran = 0f;
+ private static final float yTran = 0f;
+ private static final float zTran = -1/5f;
+ private static final float zNear = 0.1f;
+ private static final float zFar = 7000.0f;
boolean ignoreInput = false;
- public UIListener01(final int renderModes, final RenderState rs, final boolean debug, final boolean trace) {
+ public UIShapeDemo01(final Font font, final int renderModes, final RenderState rs, final boolean debug, final boolean trace) {
+ this.font = font;
this.renderModes = renderModes;
this.rRenderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable);
this.debug = debug;
this.trace = trace;
this.screenshot = new GLReadBufferUtil(false, false);
- setMatrix(-4, -2, 0f, -10);
- try {
- final Font font = FontFactory.get(FontFactory.UBUNTU).getDefault();
- button = new LabelButton(SVertex.factory(), 0, font, "Click me!", 4f, 2f);
- button.translate(2,1,0);
- /** Button defaults !
+ button = new LabelButton(SVertex.factory(), renderModes, font, "Click me!", 1/8f, 1/16f);
+ button.setLabelColor(0.0f,0.0f,0.0f);
+ /** Button defaults !
button.setLabelColor(1.0f,1.0f,1.0f);
button.setButtonColor(0.6f,0.6f,0.6f);
button.setCorner(1.0f);
button.setSpacing(2.0f);
- */
- System.err.println(button);
- } catch (final IOException ex) {
- System.err.println("Caught: "+ex.getMessage());
- ex.printStackTrace();
- }
+ */
+ System.err.println(button);
+ crossHair = new CrossHair(SVertex.factory(), renderModes, 1/20f, 1/20f, 1/1000f);
+ crossHair.setColor(0f,0f,1f,1f);
+ crossHair.setEnabled(true);
}
public final RegionRenderer getRegionRenderer() { return rRenderer; }
- public final float getZoom() { return zoom; }
- public final float getXTran() { return xTran; }
- public final float getYTran() { return yTran; }
- public final float getAngle() { return ang; }
public final float[] getPosition() { return position; }
- public void setMatrix(final float xtrans, final float ytrans, final float angle, final int zoom) {
- this.xTran = xtrans;
- this.yTran = ytrans;
- this.ang = angle;
- this.zoom = zoom;
- }
-
@Override
public void init(final GLAutoDrawable drawable) {
autoDrawable = drawable;
@@ -153,8 +216,24 @@ public class UIListener01 implements GLEventListener {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
gl.glViewport(xstart, ystart, width, height);
- rRenderer.reshapePerspective(45.0f, width, height, 0.1f, 7000.0f);
- dumpMatrix();
+ rRenderer.reshapePerspective(45.0f, width, height, zNear, zFar);
+ // rRenderer.reshapeOrtho(width, height, zNear, zFar);
+
+ lastWidth = width;
+ lastHeight = height;
+ if( drawable instanceof Window ) {
+ ((Window)drawable).setTitle(UIShapeDemo01.class.getSimpleName()+": "+drawable.getSurfaceWidth()+" x "+drawable.getSurfaceHeight());
+ }
+ }
+ float lastWidth = 0f, lastHeight = 0f;
+
+ final int[] sampleCount = { 4 };
+
+ private void drawShape(final GL2ES2 gl, final PMVMatrix pmv, final RegionRenderer renderer, final UIShape shape) {
+ pmv.glPushMatrix();
+ shape.setTransform(pmv);
+ shape.drawShape(gl, renderer, sampleCount);
+ pmv.glPopMatrix();
}
@Override
@@ -164,49 +243,70 @@ public class UIListener01 implements GLEventListener {
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
- final int[] sampleCount = { 4 };
- final float[] translate = button.getTranslate();
-
- final RegionRenderer regionRenderer = getRegionRenderer();
- final PMVMatrix pmv = regionRenderer.getMatrix();
+ final RegionRenderer renderer = getRegionRenderer();
+ final PMVMatrix pmv = renderer.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);
- button.drawShape(gl, regionRenderer, sampleCount);
+ pmv.glTranslatef(xTran, yTran, zTran);
+ renderer.enable(gl, true);
+ drawShape(gl, pmv, renderer, button);
+ drawShape(gl, pmv, renderer, crossHair);
+ {
+ final String text = "Hello Origin.";
+ final float full_width_o;
+ {
+ final float orthoDist = -zTran; // assume orthogonal plane at -zTran
+ float glWinX = 0;
+ float glWinY = 0;
+ final float winZ = FloatUtil.getOrthoWinZ(orthoDist, zNear, zFar);
+ final float[] objCoord0 = new float[3];
+ final float[] objCoord1 = new float[3];
+ if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord0, 0) ) {
+ if( once ) {
+ System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord0[0], objCoord0[1], objCoord0[2]);
+ }
+ }
+ glWinX = drawable.getSurfaceWidth();
+ glWinY = drawable.getSurfaceHeight();
+ if( pmv.gluUnProject(glWinX, glWinY, winZ, renderer.getViewport(), 0, objCoord1, 0) ) {
+ if( once ) {
+ System.err.printf("winToObjCoord: win [%f, %f, %f] -> obj [%f, %f, %f]%n", glWinX, glWinY, winZ, objCoord1[0], objCoord1[1], objCoord1[2]);
+ }
+ }
+ full_width_o = objCoord1[0] - objCoord0[0];
+ }
+ final AABBox txt_box_em = font.getPointsBounds(null, text);
+ final float full_width_s = full_width_o / txt_box_em.getWidth();
+ final float txt_scale = full_width_s/2f;
+ pmv.glPushMatrix();
+ pmv.glScalef(txt_scale, txt_scale, 1f);
+ pmv.glTranslatef(-txt_box_em.getWidth(), 0f, 0f);
+ final AABBox txt_box_r = TextRegionUtil.drawString3D(gl, renderModes, renderer, font, text, new float[] { 0, 0, 0, 1 }, sampleCount);
+ if( once ) {
+ final AABBox txt_box_em2 = font.getPointsBounds2(null, text);
+ System.err.println("XXX: full_width: "+full_width_o+" / "+txt_box_em.getWidth()+" -> "+full_width_s);
+ System.err.println("XXX: txt_box_em "+txt_box_em);
+ System.err.println("XXX: txt_box_e2 "+txt_box_em2);
+ System.err.println("XXX: txt_box_rg "+txt_box_r);
+ once = false;
+ }
+ pmv.glPopMatrix();
+ }
+ renderer.enable(gl, false);
}
+ static boolean once = true;
@Override
public void dispose(final GLAutoDrawable drawable) {
final GL2ES2 gl = drawable.getGL().getGL2ES2();
button.destroy(gl, getRegionRenderer());
+ crossHair.destroy(gl, getRegionRenderer());
autoDrawable = null;
screenshot.dispose(gl);
rRenderer.destroy(gl);
}
- public void zoom(final int v){
- zoom += v;
- dumpMatrix();
- }
-
- public void move(final float x, final float y){
- xTran += x;
- yTran += y;
- dumpMatrix();
- }
- public void rotate(final float delta){
- ang += delta;
- ang %= 360.0f;
- dumpMatrix();
- }
-
- void dumpMatrix() {
- System.err.println("Matrix: " + xTran + "/" + yTran + " x"+zoom + " @"+ang);
- }
-
/** Attach the input listener to the window */
public void attachInputListenerTo(final GLWindow window) {
if ( null == keyAction ) {
@@ -234,7 +334,7 @@ public class UIListener01 implements GLEventListener {
public void printScreen(final GLAutoDrawable drawable, final String dir, final String tech, final String objName, final boolean exportAlpha) throws GLException, IOException {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
- pw.printf("-%03dx%03d-Z%04d-T%04d-%s", drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), (int)Math.abs(zoom), 0, objName);
+ pw.printf("-%03dx%03d-Z%04d-T%04d-%s", drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), (int)Math.abs(zTran), 0, objName);
final String filename = dir + tech + sw +".png";
if(screenshot.readPixels(drawable.getGL(), false)) {
@@ -268,14 +368,70 @@ public class UIListener01 implements GLEventListener {
@Override
public void mousePressed(final MouseEvent e) {
- button.setLabelColor(0.8f,0.8f,0.8f);
- button.setColor(0.1f, 0.1f, 0.1f, 1.0f);
+ autoDrawable.invoke(false, new GLRunnable() { // avoid data-race
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ System.err.println("\n\nMouse: "+e);
+
+ final RegionRenderer renderer = getRegionRenderer();
+ final PMVMatrix pmv = renderer.getMatrix();
+ pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmv.glLoadIdentity();
+ pmv.glTranslatef(xTran, yTran, zTran);
+
+ // flip to GL window coordinates, origin bottom-left
+ final int[] viewport = renderer.getViewport(new int[4]);
+ final int glWinX = e.getX();
+ final int glWinY = viewport[3] - e.getY() - 1;
+
+ {
+ final float[] objPos = new float[3];
+ System.err.println("\n\nButton: "+button);
+ button.winToObjCoord(renderer, glWinX, glWinY, objPos);
+ System.err.println("Button: Click: Win "+glWinX+"/"+glWinY+" -> Obj "+objPos[0]+"/"+objPos[1]+"/"+objPos[1]);
+
+ final int[] surfaceSize = new int[2];
+ button.getSurfaceSize(renderer, surfaceSize);
+ System.err.println("Button: Size: Pixel "+surfaceSize[0]+" x "+surfaceSize[1]);
+ }
+ {
+ final float[] objPosC = crossHair.getBounds().getCenter();
+ final int[] objWinPos = new int[2];
+ System.err.println("\n\nCrossHair: "+crossHair);
+ if( crossHair.objToWinCoord(renderer, objPosC, objWinPos) ) {
+ System.err.println("CrossHair: Obj: Obj "+objPosC[0]+"/"+objPosC[1]+"/"+objPosC[1]+" -> Win "+objWinPos[0]+"/"+objWinPos[1]);
+ }
+
+ final float[] objPos2 = new float[3];
+ crossHair.winToObjCoord(renderer, objWinPos[0], objWinPos[1], objPos2);
+ System.err.println("CrossHair: Obj: Win "+objWinPos[0]+"/"+objWinPos[1]+" -> Obj "+objPos2[0]+"/"+objPos2[1]+"/"+objPos2[1]);
+
+ final float[] winObjPos = new float[3];
+ if( crossHair.winToObjCoord(renderer, glWinX, glWinY, winObjPos) ) {
+ // final float[] translate = crossHair.getTranslate();
+ // final float[] objPosT = new float[] { objPosC[0]+translate[0], objPosC[1]+translate[1], objPosC[2]+translate[2] };
+ final float dx = winObjPos[0] - objPosC[0];
+ final float dy = winObjPos[1] - objPosC[1];
+ // final float dz = winObjPos[2] - objPosT[2];
+ if( !FloatUtil.isZero(dx, FloatUtil.EPSILON) || !FloatUtil.isZero(dy, FloatUtil.EPSILON) ) {
+ System.err.println("CrossHair: Move.1: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy);
+ crossHair.translate(dx, dy, 0f);
+ } else {
+ System.err.println("CrossHair: Move.0: Win "+glWinX+"/"+glWinY+" -> Obj "+winObjPos[0]+"/"+winObjPos[1]+"/"+winObjPos[1]+" -> diff "+dx+" / "+dy);
+ }
+ }
+
+ final int[] surfaceSize = new int[2];
+ crossHair.getSurfaceSize(renderer, surfaceSize);
+ System.err.println("CrossHair: Size: Pixel "+surfaceSize[0]+" x "+surfaceSize[1]);
+ }
+ return true;
+ } } );
+
}
@Override
public void mouseReleased(final MouseEvent e) {
- button.setLabelColor(1.0f,1.0f,1.0f);
- button.setColor(0.6f,0.6f,0.6f, 1.0f);
}
@Override
@@ -306,22 +462,22 @@ public class UIListener01 implements GLEventListener {
}
if(arg0.getKeyCode() == KeyEvent.VK_1){
- zoom(2);
+ button.translate(0f, 0f, -zTran/10f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_2){
- zoom(-2);
+ button.translate(0f, 0f, zTran/10f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_UP){
- move(0, 1);
+ button.translate(0f, button.getHeight()/10f, 0f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
- move(0, -1);
+ button.translate(0f, -button.getHeight()/10f, 0f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
- move(-1, 0);
+ button.translate(-button.getWidth()/10f, 0f, 0f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
- move(1, 0);
+ button.translate(button.getWidth()/10f, 0f, 0f);
}
else if(arg0.getKeyCode() == KeyEvent.VK_4){
button.setSpacing(button.getSpacingX()-0.01f, button.getSpacingY()-0.005f);
@@ -340,10 +496,10 @@ public class UIListener01 implements GLEventListener {
System.err.println("Button Corner: " + button.getCorner());
}
else if(arg0.getKeyCode() == KeyEvent.VK_0){
- rotate(1);
+ // rotate(1);
}
else if(arg0.getKeyCode() == KeyEvent.VK_9){
- rotate(-1);
+ // rotate(-1);
}
else if(arg0.getKeyCode() == KeyEvent.VK_V) {
if(null != autoDrawable) {
@@ -375,24 +531,23 @@ public class UIListener01 implements GLEventListener {
}
}
else if(arg0.getKeyCode() == KeyEvent.VK_S){
- rotate(-1);
- if(null != autoDrawable) {
- autoDrawable.invoke(false, new GLRunnable() {
- @Override
- public boolean run(final GLAutoDrawable drawable) {
- try {
- final String type = Region.getRenderModeString(renderModes);
- printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false);
- screenshot_num++;
- } catch (final GLException e) {
- e.printStackTrace();
- } catch (final IOException e) {
- e.printStackTrace();
- }
- return true;
+ if(null != autoDrawable) {
+ autoDrawable.invoke(false, new GLRunnable() {
+ @Override
+ public boolean run(final GLAutoDrawable drawable) {
+ try {
+ final String type = Region.getRenderModeString(renderModes);
+ printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false);
+ screenshot_num++;
+ } catch (final GLException e) {
+ e.printStackTrace();
+ } catch (final IOException e) {
+ e.printStackTrace();
}
- });
- }
+ return true;
+ }
+ });
+ }
}
}
@Override