diff options
-rw-r--r-- | make/scripts/tests.sh | 8 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/GraphUIDemoArgs.java | 6 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo01b.java | 245 | ||||
-rw-r--r-- | src/graphui/classes/com/jogamp/graph/ui/Shape.java | 33 |
4 files changed, 276 insertions, 16 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index a53113be6..186a6ceba 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -585,8 +585,8 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4fMatrixMulNOUI $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4fProject01NOUI $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestMatrix4fProject02NOUI $* -#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix02NOUI $* +#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix02NOUI $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVMatrix03NOUI $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestPMVTransform01NOUI $* #testnoawt com.jogamp.opengl.test.junit.jogl.math.TestQuaternion01NOUI $* @@ -1024,9 +1024,9 @@ function testawtswt() { #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo00 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01 $* -#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01b $* +testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01b $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo02 $* -testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $* +#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03b $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo10 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo11 $* diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/GraphUIDemoArgs.java b/src/demos/com/jogamp/opengl/demos/graph/ui/GraphUIDemoArgs.java index bdd8f8d6b..c263e3d97 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/GraphUIDemoArgs.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/GraphUIDemoArgs.java @@ -36,6 +36,7 @@ public class GraphUIDemoArgs { public String glProfileName = GLProfile.GL2ES2; public boolean wait_to_start = false; public boolean keepRunning = false; + public boolean stayOpen = false; public int renderModes; public int sceneMSAASamples = 0; public float debugBoxThickness = 0f; @@ -80,6 +81,9 @@ public class GraphUIDemoArgs { wait_to_start = true; } else if (args[idx[0]].equals("-keep")) { keepRunning = true; + stayOpen = true; + } else if (args[idx[0]].equals("-stay")) { + stayOpen = true; } else if(args[idx[0]].equals("-gnone")) { sceneMSAASamples = 0; renderModes = 0; @@ -104,7 +108,7 @@ public class GraphUIDemoArgs { @Override public String toString() { return "Options{surface[width "+surface_width+" x "+surface_height+"], glp "+glProfileName+ - ", wait "+wait_to_start+", keep "+keepRunning+ + ", wait "+wait_to_start+", keep "+keepRunning+", stay "+stayOpen+ ", renderModes "+Region.getRenderModeString(renderModes)+ ", smsaa "+sceneMSAASamples+", dbgbox "+debugBoxThickness+"}"; } diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo01b.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo01b.java new file mode 100644 index 000000000..1e0fddb2b --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo01b.java @@ -0,0 +1,245 @@ +/** + * 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph.ui; + +import java.io.IOException; + +import com.jogamp.common.os.Clock; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.ui.Scene; +import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.Scene.PMVMatrixSetup; +import com.jogamp.graph.ui.shapes.Button; +import com.jogamp.graph.ui.shapes.GLButton; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.es2.GearsES2; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Recti; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * Res independent Shape, Scene attached to GLWindow showing simple linear Shape movement. + * <p> + * This variation of {@link UISceneDemo00} uses a {@link GLButton} shape with animating and rotating gears + * and sets up an own {@link Scene.PMVMatrixSetup} with a plane dimension of 100. + * </p> + * <p> + * Pass '-keep' to main-function to keep running after animation, + * then user can test Shape drag-move and drag-resize w/ 1-pointer. + * </p> + */ +public class UISceneDemo01b { + static GraphUIDemoArgs options = new GraphUIDemoArgs(1280, 720, Region.VBAA_RENDERING_BIT); + + public static void main(final String[] args) throws IOException { + if( 0 != args.length ) { + final int[] idx = { 0 }; + for(idx[0]=0; idx[0]<args.length; ++idx[0]) { + options.parse(args, idx); + } + } + System.err.println(options); + final GLProfile reqGLP = GLProfile.get(options.glProfileName); + System.err.println("GLProfile: "+reqGLP); + + // + // Resolution independent, no screen size + // + final Font font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF); + System.err.println("Font: "+font.getFullFamilyName()); + + final Shape shape; + { + final Button b = new Button(options.renderModes, font, "L", 1/8f, 1/8f/2.5f); // normalized: 1 is 100% surface size (width and/or height) + b.setCorner(0f); + shape = b; + } + shape.getRotation().rotateByAngleX(FloatUtil.PI); + shape.getRotation().rotateByAngleY(FloatUtil.PI); + System.err.println("Shape bounds "+shape.getBounds(reqGLP)); + System.err.println("Shape "+shape); + + final Scene scene = new Scene(); + scene.setClearParams(new float[] { 1f, 1f, 1f, 1f}, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); + scene.addShape(shape); + + final Animator animator = new Animator(); + + final GLCapabilities caps = new GLCapabilities(reqGLP); + caps.setAlphaBits(4); + System.out.println("Requested: " + caps); + + final GLWindow window = GLWindow.create(caps); + window.setSize(options.surface_width, options.surface_height); + window.setTitle(UISceneDemo01b.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.setVisible(true); + window.addGLEventListener(scene); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowResized(final WindowEvent e) { + window.setTitle(UISceneDemo01b.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + } + @Override + public void windowDestroyNotify(final WindowEvent e) { + animator.stop(); + } + }); + + scene.attachInputListenerTo(window); + + animator.setUpdateFPSFrames(1*60, null); // System.err); + animator.add(window); + animator.start(); + + // + // After initial display we can use screen resolution post initial Scene.reshape(..) + // However, in this example we merely use the resolution to + // - Compute the animation values with DPI + scene.waitUntilDisplayed(); + + final AABBox sceneBox = scene.getBounds(); + System.err.println("SceneBox "+sceneBox); + System.err.println("Shape "+shape); + shape.scale(sceneBox.getWidth(), sceneBox.getWidth(), 1f); + System.err.println("Shape "+shape); + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + + // + // Compute the metric animation values -> shape obj-velocity + // + final float min_obj = sceneBox.getMinX(); + final float max_obj = sceneBox.getMaxX() - shape.getScaledWidth(); + + final int[] shapeSizePx = shape.getSurfaceSize(scene, new PMVMatrix(), new int[2]); // [px] + final float[] pixPerShapeUnit = shape.getPixelPerShapeUnit(shapeSizePx, new float[2]); // [px]/[shapeUnit] + + final float pixPerMM = window.getPixelsPerMM(new float[2])[0]; // [px]/[mm] + final float dist_px = scene.getWidth() - shapeSizePx[0]; // [px] + final float dist_m = dist_px/pixPerMM/1e3f; // [m] + final float velocity = 50/1e3f; // [m]/[s] + final float velocity_px = velocity * 1e3f * pixPerMM; // [px]/[s] + final float velovity_obj = velocity_px / pixPerShapeUnit[0]; // [shapeUnit]/[s] + final float exp_dur_s = dist_m / velocity; // [s] + + System.err.println(); + System.err.printf("Shape: %d x %d [pixel], %.4f px/shape_unit%n", shapeSizePx[0], shapeSizePx[1], pixPerShapeUnit[0]); + System.err.printf("Shape: %s%n", shape); + System.err.println(); + System.err.printf("Distance: %.0f pixel @ %.3f px/mm, %.3f mm%n", dist_px, pixPerMM, dist_m*1e3f); + System.err.printf("Velocity: %.3f mm/s, %.3f px/s, %.6f obj/s, expected travel-duration %.3f s%n", + velocity*1e3f, velocity_px, velovity_obj, exp_dur_s); + + shape.addMouseListener( new Shape.MouseGestureAdapter() { + @Override + public void mouseMoved(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + System.err.println("MouseOver "+shapeEvent); + // System.err.println("MouseOver "+shape.getPosition()); + System.err.println(); + } + @Override + public void mouseWheelMoved(final MouseEvent e) { + if( !e.isShiftDown() ) { + final float rad = e.getRotation()[1] < 0f ? FloatUtil.adegToRad(-10f) : FloatUtil.adegToRad(10f); + if( e.isAltDown() ) { + shape.getRotation().rotateByAngleZ(rad); + } else if( e.isControlDown() ) { + shape.getRotation().rotateByAngleX(rad); + } else { + shape.getRotation().rotateByAngleY(rad); + } + System.err.println("Shape "+shape); + final PMVMatrix pmv = new PMVMatrix(); + shape.setTransform(pmv); + System.err.println("Shape "+pmv); + } + } + }); + final long t0_us = Clock.currentNanos() / 1000; // [us] + long t1_us = t0_us; + shape.moveTo(min_obj, 0f, 0f); // move shape to min start position + System.err.println("Shape Move: "+min_obj+" -> "+max_obj); + System.err.println("Shape Start Pos: "+shape); + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + while( shape.getPosition().x() < max_obj && window.isNativeValid() ) { + final long t2_us = Clock.currentNanos() / 1000; + final float dt_s = ( t2_us - t1_us ) / 1e6f; + t1_us = t2_us; + + final float dx = velovity_obj * dt_s; // [shapeUnit] + // System.err.println("move ") + + // Move on GL thread to have vsync for free + // Otherwise we would need to employ a sleep(..) w/ manual vsync + window.invoke(true, (drawable) -> { + shape.move(dx, 0f, 0f); + System.err.println("Moved: "+shape); + return true; + }); + } + final float has_dur_s = ( ( Clock.currentNanos() / 1000 ) - t0_us ) / 1e6f; // [us] + System.err.printf("Actual travel-duration %.3f s, delay %.3f s%n", has_dur_s, has_dur_s-exp_dur_s); + System.err.println("Shape End Pos: "+shape); + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + if( !options.stayOpen ) { + window.destroy(); + } + } + + static class MyPMVMatrixSetup implements PMVMatrixSetup { + @Override + public void set(final PMVMatrix pmv, final Recti viewport) { + final float ratio = (float)viewport.width()/(float)viewport.height(); + pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmv.glLoadIdentity(); + pmv.gluPerspective(Scene.DEFAULT_ANGLE, ratio, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR); + pmv.glTranslatef(0f, 0f, Scene.DEFAULT_SCENE_DIST); + + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + } + + @Override + public void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, final Recti viewport) { + Scene.getDefaultPMVMatrixSetup().setPlaneBox(planeBox, pmv, viewport); + } + }; +} diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java index 5e7201bdc..befee55c3 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java @@ -528,8 +528,8 @@ public abstract class Shape { if( pmv.gluProject(high, viewport, winCoordHigh) ) { if( pmv.gluProject(low, viewport, winCoordLow) ) { - surfaceSize[0] = (int)(winCoordHigh.x() - winCoordLow.x()); - surfaceSize[1] = (int)(winCoordHigh.y() - winCoordLow.y()); + surfaceSize[0] = (int)Math.abs(winCoordHigh.x() - winCoordLow.x()); + surfaceSize[1] = (int)Math.abs(winCoordHigh.y() - winCoordLow.y()); return surfaceSize; } } @@ -1003,7 +1003,7 @@ public abstract class Shape { @Override public String toString() { - return "EventDetails[winPos ["+winPos[0]+", "+winPos[1]+"], objPos ["+objPos+"], "+shape+"]"; + return "EventInfo[winPos ["+winPos[0]+", "+winPos[1]+"], objPos ["+objPos+"], "+shape+"]"; } } @@ -1045,6 +1045,15 @@ public abstract class Shape { } switch( eventType ) { case MouseEvent.EVENT_MOUSE_DRAGGED: { + // adjust for rotation + final Vec3f euler = rotation.toEuler(new Vec3f()); + final boolean x_flip, y_flip; + { + final float x_rot = Math.abs(euler.x()); + final float y_rot = Math.abs(euler.y()); + x_flip = 1f*FloatUtil.HALF_PI <= y_rot && y_rot <= 3f*FloatUtil.HALF_PI; + y_flip = 1f*FloatUtil.HALF_PI <= x_rot && x_rot <= 3f*FloatUtil.HALF_PI; + } // 1 pointer drag and potential drag-resize if(dragFirst) { objDraggedFirst.set(objPos); @@ -1052,8 +1061,8 @@ public abstract class Shape { winDraggedLast[1] = glWinY; dragFirst=false; - final float ix = objPos.x(); - final float iy = objPos.y(); + final float ix = x_flip ? box.getWidth() - objPos.x() : objPos.x(); + final float iy = y_flip ? box.getHeight() - objPos.y() : objPos.y(); final float minx_br = box.getMaxX() - box.getWidth() * resize_section; final float miny_br = box.getMinY(); final float maxx_br = box.getMaxX(); @@ -1078,14 +1087,16 @@ public abstract class Shape { } } if( DEBUG ) { - System.err.printf("DragFirst: drag %b, resize %d, obj[%s], drag +[%s]%n", - inMove, inResize, objPos, shapeEvent.objDrag); + System.err.printf("DragFirst: drag %b, resize %d, obj[%s], flip[x %b, y %b]%n", + inMove, inResize, objPos, x_flip, y_flip); System.err.printf("DragFirst: %s%n", this); } return; } shapeEvent.objDrag.set( objPos.x() - objDraggedFirst.x(), objPos.y() - objDraggedFirst.y() ); + shapeEvent.objDrag.scale(x_flip ? -1f : 1f, y_flip ? -1f : 1f); + shapeEvent.winDrag[0] = glWinX - winDraggedLast[0]; shapeEvent.winDrag[1] = glWinY - winDraggedLast[1]; winDraggedLast[0] = glWinX; @@ -1105,8 +1116,8 @@ public abstract class Shape { final float sy = scale.y() - sdy/bh; if( resize_sxy_min <= sx && resize_sxy_min <= sy ) { // avoid scale flip if( DEBUG ) { - System.err.printf("DragZoom: resize %d, win[%4d, %4d], obj[%s], dxy +[%s], sdxy +[%.4f, %.4f], scale [%s] -> [%.4f, %.4f]%n", - inResize, glWinX, glWinY, objPos, + System.err.printf("DragZoom: resize %d, win[%4d, %4d], , flip[x %b, y %b], obj[%s], dxy +[%s], sdxy +[%.4f, %.4f], scale [%s] -> [%.4f, %.4f]%n", + inResize, glWinX, glWinY, x_flip, y_flip, objPos, shapeEvent.objDrag, sdx, sdy, scale, sx, sy); } @@ -1120,9 +1131,9 @@ public abstract class Shape { return; // FIXME: pass through event? Issue zoom event? } else if( inMove ) { if( DEBUG ) { - System.err.printf("DragMove: win[%4d, %4d] +[%2d, %2d], obj[%s] +[%s]%n", + System.err.printf("DragMove: win[%4d, %4d] +[%2d, %2d], , flip[x %b, y %b], obj[%s] +[%s], rot %s%n", glWinX, glWinY, shapeEvent.winDrag[0], shapeEvent.winDrag[1], - objPos, shapeEvent.objDrag); + x_flip, y_flip, objPos, shapeEvent.objDrag, euler); } move( sdx, sdy, 0f); // FIXME: Pass through event? Issue move event? |