diff options
Diffstat (limited to 'src')
7 files changed, 818 insertions, 297 deletions
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 c1ef5f7fd..311099169 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 @@ -1,3 +1,30 @@ +/** + * 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.test.junit.graph.demos; import java.io.File; @@ -37,7 +64,6 @@ import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.VectorUtil; import com.jogamp.opengl.test.junit.graph.FontSet01; -import com.jogamp.opengl.test.junit.graph.demos.ui.CrossHair; import com.jogamp.opengl.test.junit.graph.demos.ui.GLEventListenerButton; import com.jogamp.opengl.test.junit.graph.demos.ui.Label; import com.jogamp.opengl.test.junit.graph.demos.ui.LabelButton; @@ -47,7 +73,6 @@ import com.jogamp.opengl.test.junit.graph.demos.ui.SceneUIController; import com.jogamp.opengl.test.junit.graph.demos.ui.ImageSeqButton; import com.jogamp.opengl.test.junit.graph.demos.ui.UIShape; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; -import com.jogamp.opengl.test.junit.jogl.demos.es2.RedSquareES2; import com.jogamp.opengl.util.GLReadBufferUtil; import com.jogamp.opengl.util.av.GLMediaPlayer; import com.jogamp.opengl.util.av.GLMediaPlayerFactory; @@ -60,12 +85,10 @@ public class GPUUISceneGLListener0A implements GLEventListener { private boolean trace = false; private final float noAADPIThreshold; - private final RenderState rs; - private final SceneUIController sceneUIController; + private final SceneUIController sceneUICntrl; /** -1 == AUTO, TBD @ init(..) */ private int renderModes; - private RegionRenderer renderer; private final Font font; private final Font fontFPS; @@ -85,7 +108,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { private final float fontSizeFixedPVP = 0.04f; /** Proportional Font Size to Window Height for FPS Status Line, per-vertical-pixels [PVP] */ private final float fontSizeFpsPVP = 0.03f; - private float dpiH = 96; + private float dpiV = 96; /** * Default DPI threshold value to disable {@link Region#VBAA_RENDERING_BIT VBAA}: {@value} dpi @@ -104,9 +127,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { private Label truePtSizeLabel = null; private Label jogampLabel = null; private Label fpsLabel = null; - private CrossHair crossHairCtr = null; - private boolean ioAttached = false; private GLAutoDrawable cDrawable; private final GLReadBufferUtil screenshot; @@ -156,7 +177,6 @@ public class GPUUISceneGLListener0A implements GLEventListener { private GPUUISceneGLListener0A(final String fontfilename, final float noAADPIThreshold, final int renderModes, final boolean debug, final boolean trace) { this.noAADPIThreshold = noAADPIThreshold; - this.rs = RenderState.createRenderState(SVertex.factory()); this.debug = debug; this.trace = trace; @@ -178,8 +198,15 @@ public class GPUUISceneGLListener0A implements GLEventListener { } catch (final IOException ioe) { throw new RuntimeException(ioe); } - sceneUIController = new SceneUIController(sceneDist, zNear, zFar); - // sceneUIController.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? + { + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final RegionRenderer renderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + // renderer = RegionRenderer.create(rs, null, null); + + sceneUICntrl = new SceneUIController(renderer, sceneDist, zNear, zFar); + // sceneUIController.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? + } screenshot = new GLReadBufferUtil(false, false); } @@ -226,7 +253,18 @@ public class GPUUISceneGLListener0A implements GLEventListener { } } - private void initButtons(final GL2ES2 gl, final int width, final int height, final RegionRenderer renderer) { + public static final int BUTTON_NEXTTEXT = 100; + public static final int BUTTON_FPS = 101; + public static final int BUTTON_VSYNC = 102; + public static final int BUTTON_QUIT = 102; + public static final int BUTTON_MOVIE = 200; + public static final int BUTTON_GLEL = 200; + + public UIShape getShapeByName(final int name) { + return sceneUICntrl.getShapeByName(name); + } + + private void initButtons(final GL2ES2 gl, final int width, final int height) { final boolean pass2Mode = Region.isTwoPass( renderModes ) ; buttons.clear(); @@ -240,6 +278,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { final float diffY = 1.5f * buttonYSize; LabelButton button = new LabelButton(SVertex.factory(), renderModes, font, "Next Text", buttonXSize, buttonYSize); + button.setName(BUTTON_NEXTTEXT); button.translate(xStartLeft,yStartTop-diffY*buttons.size(), 0f); button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override @@ -256,7 +295,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { buttons.add(button); button = new LabelButton(SVertex.factory(), renderModes, font, "Show FPS", buttonXSize, buttonYSize); - button.setName(100); // FIXME: DEBUG tag + button.setName(BUTTON_FPS); button.translate(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setToggleable(true); button.setToggle(fpsLabel.isEnabled()); @@ -273,6 +312,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { buttons.add(button); button = new LabelButton(SVertex.factory(), renderModes, font, "V-Sync", buttonXSize, buttonYSize); + button.setName(BUTTON_VSYNC); button.translate(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setToggleable(true); button.setToggle(gl.getSwapInterval()>0); @@ -300,14 +340,11 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { - rotateButtons(new float[] { 0f, -5f, 0f}); // left-half pressed - } else { - rotateButtons(new float[] { 0f, 5f, 0f}); // right-half pressed - } + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + rotateButtons(new float[] { 0f, -5f, 0f}); // left-half pressed + } else { + rotateButtons(new float[] { 0f, 5f, 0f}); // right-half pressed } } @Override @@ -322,19 +359,16 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - int sampleCount = sceneUIController.getSampleCount(); - if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { - // left-half pressed - sampleCount--; - } else { - // right-half pressed - sampleCount++; - } - sampleCount = sceneUIController.setSampleCount(sampleCount); // validated / clipped + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + int sampleCount = sceneUICntrl.getSampleCount(); + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + // left-half pressed + sampleCount--; + } else { + // right-half pressed + sampleCount++; } + sampleCount = sceneUICntrl.setSampleCount(sampleCount); // validated / clipped } } ); button.addMouseListener(dragZoomRotateListener); buttons.add(button); @@ -344,30 +378,28 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - int quality = shapeEvent.shape.getQuality(); - - if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { - // left-half pressed - if( quality > 0 ) { - quality--; - } - } else { - // right-half pressed - if( quality < Region.MAX_QUALITY ) { - quality++; - } + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + int quality = shapeEvent.shape.getQuality(); + + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + // left-half pressed + if( quality > 0 ) { + quality--; + } + } else { + // right-half pressed + if( quality < Region.MAX_QUALITY ) { + quality++; } - sceneUIController.setAllShapesQuality(quality); } + sceneUICntrl.setAllShapesQuality(quality); } } ); button.addMouseListener(dragZoomRotateListener); buttons.add(button); } button = new LabelButton(SVertex.factory(), renderModes, font, "Quit", buttonXSize, buttonYSize); + button.setName(BUTTON_QUIT); button.translate(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setColor(0.7f, 0.0f, 0.0f, 1.0f); button.setLabelColor(1.2f, 1.2f, 1.2f); @@ -421,23 +453,20 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - // rel position to center - final float dx = shapeEvent.objPos[0] - shapeEvent.shape.getBounds().getCenter()[0] ; - final float dy = shapeEvent.objPos[1] - shapeEvent.shape.getBounds().getCenter()[1] ; - // per-cent position to center (remove dependency on dimension) - final float awdx = Math.abs(dx)/shapeEvent.shape.getBounds().getWidth(); - final float awdy = Math.abs(dy)/shapeEvent.shape.getBounds().getHeight(); - float tx = 0, ty = 0; - if ( awdx > awdy ) { - tx = dx < 0 ? -5 : 5; - } else { - ty = dy < 0 ? -5 : 5; - } - translateButtons(tx, ty, 0f); + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + // rel position to center + final float dx = shapeEvent.objPos[0] - shapeEvent.shape.getBounds().getCenter()[0] ; + final float dy = shapeEvent.objPos[1] - shapeEvent.shape.getBounds().getCenter()[1] ; + // per-cent position to center (remove dependency on dimension) + final float awdx = Math.abs(dx)/shapeEvent.shape.getBounds().getWidth(); + final float awdy = Math.abs(dy)/shapeEvent.shape.getBounds().getHeight(); + float tx = 0, ty = 0; + if ( awdx > awdy ) { + tx = dx < 0 ? -5 : 5; + } else { + ty = dy < 0 ? -5 : 5; } + translateButtons(tx, ty, 0f); } } ); button.addMouseListener(dragZoomRotateListener); buttons.add(button); @@ -448,17 +477,14 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - final float dx, dy; - if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { - dx=-0.01f; dy=-0.005f; - } else { - dx=0.01f; dy=0.005f; - } - setButtonsSpacing(dx, dy); + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + final float dx, dy; + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + dx=-0.01f; dy=-0.005f; + } else { + dx=0.01f; dy=0.005f; } + setButtonsSpacing(dx, dy); } @Override public void mouseWheelMoved(final MouseEvent e) { @@ -472,18 +498,14 @@ public class GPUUISceneGLListener0A implements GLEventListener { button.addMouseListener(new UIShape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - final float dc; - if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { - dc=-0.1f; - } else { - dc=0.1f; - } - setButtonsCorner(dc); + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + final float dc; + if( shapeEvent.objPos[0] < shapeEvent.shape.getBounds().getCenter()[0] ) { + dc=-0.1f; + } else { + dc=0.1f; } - + setButtonsCorner(dc); } @Override public void mouseWheelMoved(final MouseEvent e) { @@ -527,11 +549,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { final float button2YSize = 2f*buttonYSize; final float xStartRight = -button2XSize - 8f; // aligned to right edge via reshape final int texUnitMediaPlayer, texUnitImageButton, texUnitGLELButton; - if( false ) { - texUnitMediaPlayer=0; - texUnitImageButton=0; - texUnitGLELButton=0; - } else { + { // works - but not required .. texUnitMediaPlayer=1; texUnitImageButton=2; @@ -541,8 +559,9 @@ public class GPUUISceneGLListener0A implements GLEventListener { if( true ) { final GLMediaPlayer mPlayer = GLMediaPlayerFactory.createDefault(); mPlayer.setTextureUnit(texUnitMediaPlayer); - final MediaPlayerButton mPlayerButton = new MediaPlayerButton(renderer.getRenderState().getVertexFactory(), renderModes, + final MediaPlayerButton mPlayerButton = new MediaPlayerButton(sceneUICntrl.getVertexFactory(), renderModes, button2XSize, button2YSize, mPlayer); + mPlayerButton.setName(BUTTON_MOVIE); mPlayerButton.setVerbose(true); mPlayerButton.addDefaultEventListener(); mPlayerButton.translate(xStartRight, yStartTop - diffY*1, 0f); @@ -565,7 +584,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { } if( true ) { final ImageSequence imgSeq = new ImageSequence(texUnitImageButton, true); - final ImageSeqButton imgButton = new ImageSeqButton(renderer.getRenderState().getVertexFactory(), renderModes, + final ImageSeqButton imgButton = new ImageSeqButton(sceneUICntrl.getVertexFactory(), renderModes, button2XSize, button2YSize, imgSeq); try { imgSeq.addFrame(gl, GPUUISceneGLListener0A.class, "button-released-145x53.png", TextureIO.PNG); @@ -592,41 +611,17 @@ public class GPUUISceneGLListener0A implements GLEventListener { // Issues w/ OSX and NewtCanvasAWT when rendering / animating // Probably related to CALayer - FBO - FBO* (of this button) final GLEventListener glel; - if( true ) { + { final GearsES2 gears = new GearsES2(0); gears.setVerbose(false); gears.setClearColor(new float[] { 0.9f, 0.9f, 0.9f, 1f } ); glel = gears; - } else if( false ) { - glel = new RedSquareES2(0); - } else { - glel = new GLEventListener() { - @Override - public void init(final GLAutoDrawable drawable) { - } - - @Override - public void dispose(final GLAutoDrawable drawable) { - } - - @Override - public void display(final GLAutoDrawable drawable) { - final GL2ES2 gl = drawable.getGL().getGL2ES2(); - gl.glClearColor(0.0f, 0.0f, 1.0f, 0.0f); - // gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); - gl.glClear(GL.GL_COLOR_BUFFER_BIT); - } - - @Override - public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { - } - - }; } - final GLEventListenerButton glelButton = new GLEventListenerButton(renderer.getRenderState().getVertexFactory(), renderModes, + final GLEventListenerButton glelButton = new GLEventListenerButton(sceneUICntrl.getVertexFactory(), renderModes, button2XSize, button2YSize, texUnitGLELButton, glel, false /* useAlpha */, (int)(button2XSize), (int)(button2YSize)); + glelButton.setName(BUTTON_GLEL); glelButton.setToggleable(true); glelButton.setToggle(false); // toggle == true -> animation glelButton.setAnimate(false); @@ -675,20 +670,20 @@ public class GPUUISceneGLListener0A implements GLEventListener { private static final boolean enableOthers = true; - private static final boolean reshape_resize = false; // incomplete: button positioning + private static final boolean reshape_ui = false; // incomplete: button positioning private void setupUI(final GLAutoDrawable drawable) { final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); - jogampLabel = new Label(renderer.getRenderState().getVertexFactory(), renderModes, font, pixelSizeFixed, jogamp); + jogampLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, jogamp); jogampLabel.addMouseListener(dragZoomRotateListener); - sceneUIController.addShape(jogampLabel); + sceneUICntrl.addShape(jogampLabel); jogampLabel.setEnabled(enableOthers); - final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiH); - System.err.println("10Pt PixelSize: Display "+dpiH+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); - truePtSizeLabel = new Label(renderer.getRenderState().getVertexFactory(), renderModes, font, pixelSize10Pt, truePtSize); - sceneUIController.addShape(truePtSizeLabel); + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + truePtSizeLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSize10Pt, truePtSize); + sceneUICntrl.addShape(truePtSizeLabel); truePtSizeLabel.setEnabled(enableOthers); truePtSizeLabel.translate(0, - 1.5f * jogampLabel.getLineHeight(), 0f); truePtSizeLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); @@ -699,33 +694,25 @@ public class GPUUISceneGLListener0A implements GLEventListener { * [FPS] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 15.679012 */ final float pixelSizeFPS = fontSizeFpsPVP * drawable.getSurfaceHeight(); - fpsLabel = new Label(renderer.getRenderState().getVertexFactory(), renderModes, fontFPS, pixelSizeFPS, "Nothing there yet"); + fpsLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, fontFPS, pixelSizeFPS, "Nothing there yet"); fpsLabel.addMouseListener(dragZoomRotateListener); - sceneUIController.addShape(fpsLabel); + sceneUICntrl.addShape(fpsLabel); fpsLabel.setEnabled(enableOthers); fpsLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); fpsLabel.translate(0f, pixelSizeFPS * (fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent()), 0f); - if( false ) { - crossHairCtr = new CrossHair(renderer.getRenderState().getVertexFactory(), 0, 100f, 100f, 2f); - crossHairCtr.addMouseListener(dragZoomRotateListener); - sceneUIController.addShape(crossHairCtr); - crossHairCtr.setEnabled(true); - crossHairCtr.translate(0f, 0f, -1f); - } - - initButtons(drawable.getGL().getGL2ES2(), drawable.getSurfaceWidth(), drawable.getSurfaceHeight(), renderer); + initButtons(drawable.getGL().getGL2ES2(), drawable.getSurfaceWidth(), drawable.getSurfaceHeight()); for(int i=0; i<buttons.size(); i++) { - sceneUIController.addShape(buttons.get(i)); + sceneUICntrl.addShape(buttons.get(i)); } } - private void resetUI(final GLAutoDrawable drawable) { + private void reshapeUI(final GLAutoDrawable drawable) { final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); jogampLabel.setPixelSize(pixelSizeFixed); - final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiH); - System.err.println("10Pt PixelSize: Display "+dpiH+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); truePtSizeLabel.setPixelSize(pixelSize10Pt); /** @@ -762,27 +749,27 @@ public class GPUUISceneGLListener0A implements GLEventListener { final Object upObj = drawable.getUpstreamWidget(); if( upObj instanceof Window ) { final Window upWin = (Window)upObj; - final MonitorDevice mm = upWin.getMainMonitor(); - final float[] monitorDPI = FontScale.perMMToPerInch( mm.getPixelsPerMM(new float[2]) ); - final float[] sDPI = FontScale.perMMToPerInch( upWin.getPixelsPerMM(new float[2]) ); - dpiH = sDPI[1]; - System.err.println("Monitor detected: "+mm); + final MonitorDevice monitor = upWin.getMainMonitor(); + final float[] monitorDPI = MonitorDevice.perMMToPerInch( monitor.getPixelsPerMM(new float[2]) ); + final float[] sDPI = MonitorDevice.perMMToPerInch( upWin.getPixelsPerMM(new float[2]) ); + dpiV = sDPI[1]; + System.err.println("Monitor detected: "+monitor); System.err.println("Monitor dpi: "+monitorDPI[0]+" x "+monitorDPI[1]); System.err.println("Surface scale: native "+Arrays.toString(upWin.getMaximumSurfaceScale(new float[2]))+", current "+Arrays.toString(upWin.getCurrentSurfaceScale(new float[2]))); System.err.println("Surface dpi "+sDPI[0]+" x "+sDPI[1]); } else { - System.err.println("Using default DPI of "+dpiH); + System.err.println("Using default DPI of "+dpiV); } if( 0 == renderModes && !FloatUtil.isZero(noAADPIThreshold, FloatUtil.EPSILON)) { - final boolean noAA = dpiH >= noAADPIThreshold; + final boolean noAA = dpiV >= noAADPIThreshold; final String noAAs = noAA ? " >= " : " < "; - System.err.println("AUTO RenderMode: dpi "+dpiH+noAAs+noAADPIThreshold+" -> noAA "+noAA); + System.err.println("AUTO RenderMode: dpi "+dpiV+noAAs+noAADPIThreshold+" -> noAA "+noAA); renderModes = noAA ? 0 : Region.VBAA_RENDERING_BIT; } if(drawable instanceof GLWindow) { System.err.println("GPUUISceneGLListener0A: init (1)"); final GLWindow glw = (GLWindow) drawable; - attachInputListenerTo(glw); + sceneUICntrl.attachInputListenerTo(glw); } else { System.err.println("GPUUISceneGLListener0A: init (0)"); } @@ -799,21 +786,13 @@ public class GPUUISceneGLListener0A implements GLEventListener { System.err.println("Chosen: "+drawable.getChosenGLCapabilities()); MSAATool.dump(drawable); - renderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); - rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); - // renderer = RegionRenderer.create(rs, null, null); - gl.setSwapInterval(1); gl.glEnable(GL.GL_DEPTH_TEST); gl.glEnable(GL.GL_BLEND); - renderer.init(gl, renderModes); - initTexts(); - sceneUIController.setRenderer(renderer); - - sceneUIController.init(drawable); + sceneUICntrl.init(drawable); final GLAnimatorControl a = drawable.getAnimator(); if( null != a ) { @@ -838,8 +817,8 @@ public class GPUUISceneGLListener0A implements GLEventListener { final float dxLeft = dw * relLeft; final float dxRight = dw; - if( reshape_resize ) { - resetUI(drawable); + if( reshape_ui ) { + reshapeUI(drawable); } for(int i=0; i<buttons.size() && i<buttonsLeftCount; i++) { buttons.get(i).translate(dxLeft, dyTop, dz); @@ -862,11 +841,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { System.err.println("Label["+currentText+"] MOVE: "+Arrays.toString(labels[currentText].getTranslate())); } - if( false ) { - crossHairCtr.translate(dw/2f, dh/2f, 0f); - } - - sceneUIController.reshape(drawable, x, y, width, height); + sceneUICntrl.reshape(drawable, x, y, width, height); lastWidth = width; lastHeight = height; @@ -875,28 +850,22 @@ public class GPUUISceneGLListener0A implements GLEventListener { @Override public void dispose(final GLAutoDrawable drawable) { - if(drawable instanceof GLWindow) { - System.err.println("GPUUISceneGLListener0A: dispose (1)"); - final GLWindow glw = (GLWindow) drawable; - detachInputListenerFrom(glw); - } else { - System.err.println("GPUUISceneGLListener0A: dispose (0)"); - } + System.err.println("GPUUISceneGLListener0A: dispose"); - sceneUIController.dispose(drawable); // disposes all registered UIShapes + sceneUICntrl.dispose(drawable); // disposes all registered UIShapes final GL2ES2 gl = drawable.getGL().getGL2ES2(); - renderer.destroy(gl); screenshot.dispose(gl); } private int shotCount = 0; public void printScreen(final GL gl) { + final RegionRenderer renderer = sceneUICntrl.getRenderer(); final String modeS = Region.getRenderModeString(jogampLabel.getRenderModes()); final String filename = String.format((Locale)null, "GraphUIDemo-shot%03d-%03dx%03d-S_%s_%02d.png", shotCount++, renderer.getWidth(), renderer.getHeight(), - modeS, sceneUIController.getSampleCount()); + modeS, sceneUICntrl.getSampleCount()); gl.glFinish(); // just make sure rendering finished .. if(screenshot.readPixels(gl, false)) { screenshot.write(new File(filename)); @@ -907,66 +876,44 @@ public class GPUUISceneGLListener0A implements GLEventListener { @Override public void display(final GLAutoDrawable drawable) { // System.err.println("GPUUISceneGLListener0A: display"); - final GL2ES2 gl = drawable.getGL().getGL2ES2(); if(null == labels[currentText]) { final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); final float dyTop = drawable.getSurfaceHeight() - 2f*jogampLabel.getLineHeight(); final float dxMiddle = drawable.getSurfaceWidth() * relMiddle; - labels[currentText] = new Label(renderer.getRenderState().getVertexFactory(), renderModes, font, pixelSizeFixed, strings[currentText]); + labels[currentText] = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, strings[currentText]); labels[currentText].setColor(0.1f, 0.1f, 0.1f, 1.0f); labels[currentText].setEnabled(enableOthers); labels[currentText].translate(dxMiddle, dyTop - 1.5f * jogampLabel.getLineHeight() - 1.5f * truePtSizeLabel.getLineHeight(), 0f); labels[currentText].addMouseListener(dragZoomRotateListener); - sceneUIController.addShape(labels[currentText]); + sceneUICntrl.addShape(labels[currentText]); System.err.println("Label["+currentText+"] CTOR: "+labels[currentText]); System.err.println("Label["+currentText+"] CTOR: "+Arrays.toString(labels[currentText].getTranslate())); } if( fpsLabel.isEnabled() ) { - final float lfps, tfps, td; - final GLAnimatorControl animator = drawable.getAnimator(); - if( null != animator ) { - lfps = animator.getLastFPS(); - tfps = animator.getTotalFPS(); - td = (float)animator.getLastFPSPeriod() / (float)animator.getUpdateFPSFrames(); - } else { - lfps = 0f; - tfps = 0f; - td = 0f; - } - final String modeS = Region.getRenderModeString(renderModes); final String text; if( null == actionText ) { - text = String.format("%03.1f/%03.1f fps, %.1f ms/f, v-sync %d, dpi %.1f, %s-samples %d, q %d, msaa %d, blend %b, alpha %d", - lfps, tfps, td, gl.getSwapInterval(), dpiH, modeS, sceneUIController.getSampleCount(), fpsLabel.getQuality(), - drawable.getChosenGLCapabilities().getNumSamples(), - renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED), - drawable.getChosenGLCapabilities().getAlphaBits()); + text = sceneUICntrl.getStatusText(drawable, renderModes, fpsLabel.getQuality(), dpiV); + } else if( null != drawable.getAnimator() ) { + text = SceneUIController.getStatusText(drawable.getAnimator())+", "+actionText; } else { - text = String.format("%03.1f/%03.1f fps, v-sync %d, %s", - lfps, tfps, gl.getSwapInterval(), actionText); + text = actionText; } if( fpsLabel.setText(text) ) { // marks dirty only if text differs. - System.err.println(text); + // System.err.println(text); } } - sceneUIController.display(drawable); + sceneUICntrl.display(drawable); } public void attachInputListenerTo(final GLWindow window) { - if ( !ioAttached ) { - ioAttached = true; - sceneUIController.attachInputListenerTo(window); - } + sceneUICntrl.attachInputListenerTo(window); } public void detachInputListenerFrom(final GLWindow window) { - if ( ioAttached ) { - ioAttached = false; - sceneUIController.detachInputListenerFrom(window); - } + sceneUICntrl.detachInputListenerFrom(window); } /** @@ -974,79 +921,48 @@ public class GPUUISceneGLListener0A implements GLEventListener { * since only mouse action / gesture is complete for a single one (press, drag, released and click). */ private final UIShape.MouseGestureAdapter dragZoomRotateListener = new UIShape.MouseGestureAdapter() { - float dragFirstX=-1f, dragFirstY=-1f; - boolean dragFirst = false; - - @Override - public void mousePressed(final MouseEvent e) { - dragFirst = true; - } - @Override public void mouseReleased(final MouseEvent e) { - dragFirst = false; actionText = null; } @Override public void mouseDragged(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - if( e.getPointerCount() == 1 ) { - // 1 pointer drag - if(dragFirst) { - dragFirstX = shapeEvent.objPos[0]; // e.getX(); - dragFirstY = shapeEvent.objPos[1]; // e.getY(); - dragFirst=false; - return; - } - final float nx = shapeEvent.objPos[0]; // e.getX(); - final float ny = shapeEvent.objPos[1]; // e.getY(); - final float dx = nx - dragFirstX; - final float dy = ny - dragFirstY; - // final float dy = -(ny - dragLastY); - shapeEvent.shape.translate(dx, dy, 0f); - final float[] tx = shapeEvent.shape.getTranslate(); - actionText = String.format((Locale)null, "Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); - } + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + if( e.getPointerCount() == 1 ) { + final float[] tx = shapeEvent.shape.getTranslate(); + actionText = String.format((Locale)null, "Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); } } @Override public void mouseWheelMoved(final MouseEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - final boolean isOnscreen = PointerClass.Onscreen == e.getPointerType(0).getPointerClass(); - if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) && !isOnscreen ) { - // offscreen vertical mouse wheel zoom - final float tz = 100f*e.getRotation()[1]; // vertical: wheel - System.err.println("Rotate.Zoom.W: "+tz); - shapeEvent.shape.translate(0f, 0f, tz); - } else if( isOnscreen || e.isControlDown() ) { - final float[] rot = VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f); - if( isOnscreen ) { - System.err.println("XXX: "+e); - // swap axis for onscreen rotation matching natural feel - final float tmp = rot[0]; rot[0] = rot[1]; rot[1] = tmp; - VectorUtil.scaleVec3(rot, rot, 2f); - } - shapeEvent.shape.getRotation().rotateByEuler( rot ); + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + final boolean isOnscreen = PointerClass.Onscreen == e.getPointerType(0).getPointerClass(); + if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) && !isOnscreen ) { + // offscreen vertical mouse wheel zoom + final float tz = 100f*e.getRotation()[1]; // vertical: wheel + System.err.println("Rotate.Zoom.W: "+tz); + shapeEvent.shape.translate(0f, 0f, tz); + } else if( isOnscreen || e.isControlDown() ) { + final float[] rot = VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f); + if( isOnscreen ) { + System.err.println("XXX: "+e); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot[0]; rot[0] = rot[1]; rot[1] = tmp; + VectorUtil.scaleVec3(rot, rot, 2f); } + shapeEvent.shape.getRotation().rotateByEuler( rot ); } } @Override public void gestureDetected(final GestureEvent e) { - final Object attachment = e.getAttachment(); - if( attachment instanceof UIShape.PointerEventInfo ) { - final UIShape.PointerEventInfo shapeEvent = (UIShape.PointerEventInfo)attachment; - if( e instanceof PinchToZoomGesture.ZoomEvent ) { - final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; - final float tz = ze.getDelta() * ze.getScale(); - System.err.println("Rotate.Zoom.G: "+tz); - shapeEvent.shape.translate(0f, 0f, tz); - } + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + if( e instanceof PinchToZoomGesture.ZoomEvent ) { + final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; + final float tz = ze.getDelta() * ze.getScale(); + System.err.println("Rotate.Zoom.G: "+tz); + shapeEvent.shape.translate(0f, 0f, tz); } } }; } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java index de571ec82..4ca8401dc 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtCanvasAWTDemo.java @@ -1,3 +1,30 @@ +/** + * 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.test.junit.graph.demos; import java.awt.Component; diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java index e1868a74e..b4fd16796 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo.java @@ -1,3 +1,30 @@ +/** + * 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.test.junit.graph.demos; import com.jogamp.nativewindow.ScalableSurface; @@ -37,7 +64,6 @@ public class GPUUISceneNewtDemo { String fontfilename = null; int width = 1280, height = 720; - int x = 10, y = 10; boolean forceES2 = false; boolean forceES3 = false; @@ -74,12 +100,6 @@ public class GPUUISceneNewtDemo { } else if(args[i].equals("-height")) { i++; height = MiscUtils.atoi(args[i], height); - } else if(args[i].equals("-x")) { - i++; - x = MiscUtils.atoi(args[i], x); - } else if(args[i].equals("-y")) { - i++; - y = MiscUtils.atoi(args[i], y); } else if(args[i].equals("-pixelScale")) { i++; final float pS = MiscUtils.atof(args[i], reqSurfacePixelScale[0]); @@ -101,7 +121,6 @@ public class GPUUISceneNewtDemo { System.err.println("forceGL3 "+forceGL3); System.err.println("forceGLDef "+forceGLDef); System.err.println("Desired win size "+width+"x"+height); - System.err.println("Desired win pos "+x+"/"+y); System.err.println("Scene MSAA Samples "+SceneMSAASamples); System.err.println("Graph MSAA Mode "+GraphMSAAMode); System.err.println("Graph VBAA Mode "+GraphVBAAMode); @@ -146,7 +165,6 @@ public class GPUUISceneNewtDemo { if( 0 == SceneMSAASamples ) { window.setCapabilitiesChooser(new NonFSAAGLCapsChooser(true)); } - window.setPosition(x, y); window.setSize(width, height); window.setTitle("GraphUI Newt Demo: graph["+Region.getRenderModeString(rmode)+"], msaa "+SceneMSAASamples); window.setSurfaceScale(reqSurfacePixelScale); diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneTextAnim01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneTextAnim01.java new file mode 100644 index 000000000..e9bbfc0fb --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneTextAnim01.java @@ -0,0 +1,350 @@ +/** + * 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.test.junit.graph.demos; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; + +import com.jogamp.common.util.IOUtil; +import com.jogamp.graph.curve.Region; +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.font.FontScale; +import com.jogamp.graph.geom.SVertex; +import com.jogamp.newt.MonitorDevice; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.GestureHandler.GestureEvent; +import com.jogamp.newt.event.InputEvent; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseEvent.PointerClass; +import com.jogamp.newt.event.PinchToZoomGesture; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLAnimatorControl; +import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLEventListener; +import com.jogamp.opengl.GLPipelineFactory; +import com.jogamp.opengl.JoglVersion; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.test.junit.graph.FontSet01; +import com.jogamp.opengl.test.junit.graph.demos.ui.Label; +import com.jogamp.opengl.test.junit.graph.demos.ui.SceneUIController; +import com.jogamp.opengl.test.junit.graph.demos.ui.UIShape; +import com.jogamp.opengl.util.GLReadBufferUtil; + +public class GPUUISceneTextAnim01 implements GLEventListener { + + private boolean debug = false; + private boolean trace = false; + + private final float noAADPIThreshold; + private final SceneUIController sceneUICntrl; + + /** -1 == AUTO, TBD @ init(..) */ + private int renderModes; + + private final Font font; + private final Font fontFPS; + + private final float sceneDist = 3000f; + private final float zNear = 0.1f, zFar = 7000f; + + // private final float relTop = 80f/100f; + private final float relMiddle = 22f/100f; + // private final float relLeft = 11f/100f; + + private final float fontSizePt = 10f; + /** Proportional Font Size to Window Height for Main Text, per-vertical-pixels [PVP] */ + private final float fontSizeFixedPVP = 0.04f; + /** Proportional Font Size to Window Height for FPS Status Line, per-vertical-pixels [PVP] */ + private final float fontSizeFpsPVP = 0.03f; + private float dpiV = 96; + + /** + * Default DPI threshold value to disable {@link Region#VBAA_RENDERING_BIT VBAA}: {@value} dpi + * @see #GPUUISceneGLListener0A(float) + * @see #GPUUISceneGLListener0A(float, boolean, boolean) + */ + public static final float DefaultNoAADPIThreshold = 200f; + + private String actionText = null; + private Label jogampLabel = null; + private Label fpsLabel = null; + + // private GLAutoDrawable cDrawable; + + private final GLReadBufferUtil screenshot; + + private final String jogamp = "JogAmp - Jogl Graph Module Demo"; + + // private final String longText = "JOGL: Java™ Binding for the OpenGL® API."; + + public GPUUISceneTextAnim01(final String fontfilename, final float noAADPIThreshold, final int renderModes, final boolean debug, final boolean trace) { + this.noAADPIThreshold = noAADPIThreshold; + this.debug = debug; + this.trace = trace; + + this.renderModes = renderModes; + + try { + if( null == fontfilename ) { + font = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeSerif.ttf", + FontSet01.class.getClassLoader(), FontSet01.class).getInputStream(), true); + } else { + font = FontFactory.get( new File( fontfilename ) ); + } + System.err.println("Font "+font.getFullFamilyName()); + + fontFPS = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + FontSet01.class.getClassLoader(), FontSet01.class).getInputStream(), true); + System.err.println("Font FPS "+fontFPS.getFullFamilyName()); + + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } + + { + final RenderState rs = RenderState.createRenderState(SVertex.factory()); + final RegionRenderer renderer = RegionRenderer.create(rs, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + rs.setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); + // renderer = RegionRenderer.create(rs, null, null); + + sceneUICntrl = new SceneUIController(renderer, sceneDist, zNear, zFar); + // sceneUIController.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? + } + screenshot = new GLReadBufferUtil(false, false); + } + + private void setupUI(final GLAutoDrawable drawable) { + final float pixelSizeFixed = fontSizeFixedPVP * drawable.getSurfaceHeight(); + jogampLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, font, pixelSizeFixed, jogamp); + jogampLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(jogampLabel); + jogampLabel.setEnabled(true); + + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixel-size"); + + /** + * + * [Label] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 18.814816 + * [FPS] Display 112.88889 dpi, fontSize 12.0 ppi -> pixelSize 15.679012 + */ + final float pixelSizeFPS = fontSizeFpsPVP * drawable.getSurfaceHeight(); + fpsLabel = new Label(sceneUICntrl.getVertexFactory(), renderModes, fontFPS, pixelSizeFPS, "Nothing there yet"); + fpsLabel.addMouseListener(dragZoomRotateListener); + sceneUICntrl.addShape(fpsLabel); + fpsLabel.setEnabled(true); + fpsLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); + fpsLabel.translate(0f, pixelSizeFPS * (fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent()), 0f); + } + + @Override + public void init(final GLAutoDrawable drawable) { + final Object upObj = drawable.getUpstreamWidget(); + if( upObj instanceof Window ) { + final Window upWin = (Window)upObj; + final MonitorDevice monitor = upWin.getMainMonitor(); + final float[] monitorDPI = MonitorDevice.perMMToPerInch( monitor.getPixelsPerMM(new float[2]) ); + final float[] sDPI = MonitorDevice.perMMToPerInch( upWin.getPixelsPerMM(new float[2]) ); + dpiV = sDPI[1]; + System.err.println("Monitor detected: "+monitor); + System.err.println("Monitor dpi: "+monitorDPI[0]+" x "+monitorDPI[1]); + System.err.println("Surface scale: native "+Arrays.toString(upWin.getMaximumSurfaceScale(new float[2]))+", current "+Arrays.toString(upWin.getCurrentSurfaceScale(new float[2]))); + System.err.println("Surface dpi "+sDPI[0]+" x "+sDPI[1]); + } else { + System.err.println("Using default DPI of "+dpiV); + } + if( 0 == renderModes && !FloatUtil.isZero(noAADPIThreshold, FloatUtil.EPSILON)) { + final boolean noAA = dpiV >= noAADPIThreshold; + final String noAAs = noAA ? " >= " : " < "; + System.err.println("AUTO RenderMode: dpi "+dpiV+noAAs+noAADPIThreshold+" -> noAA "+noAA); + renderModes = noAA ? 0 : Region.VBAA_RENDERING_BIT; + } + if(drawable instanceof GLWindow) { + System.err.println("GPUUISceneGLListener0A: init (1)"); + final GLWindow glw = (GLWindow) drawable; + sceneUICntrl.attachInputListenerTo(glw); + } else { + System.err.println("GPUUISceneGLListener0A: init (0)"); + } + // cDrawable = drawable; + GL2ES2 gl = drawable.getGL().getGL2ES2(); + if(debug) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) ).getGL2ES2(); + } + if(trace) { + gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); + } + System.err.println(JoglVersion.getGLInfo(gl, null, false /* withCapsAndExts */).toString()); + System.err.println("VSync Swap Interval: "+gl.getSwapInterval()); + System.err.println("Chosen: "+drawable.getChosenGLCapabilities()); + MSAATool.dump(drawable); + + gl.setSwapInterval(1); + gl.glEnable(GL.GL_DEPTH_TEST); + gl.glEnable(GL.GL_BLEND); + + sceneUICntrl.init(drawable); + + final GLAnimatorControl a = drawable.getAnimator(); + if( null != a ) { + a.resetFPSCounter(); + } + + setupUI(drawable); + } + + @Override + public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { + System.err.println("GPUUISceneGLListener0A: reshape"); + + // + // Layout all shapes: Relational move regarding window coordinates + // + final float dz = 0f; + + final float dxMiddleAbs = width * relMiddle; + final float dyTopLabelAbs = drawable.getSurfaceHeight() - 2f*jogampLabel.getLineHeight(); + jogampLabel.setTranslate(dxMiddleAbs, dyTopLabelAbs, dz); + fpsLabel.translate(0f, 0f, 0f); + + sceneUICntrl.reshape(drawable, x, y, width, height); + + lastWidth = width; + lastHeight = height; + } + float lastWidth = 0f, lastHeight = 0f; + + @Override + public void dispose(final GLAutoDrawable drawable) { + System.err.println("GPUUISceneGLListener0A: dispose"); + + sceneUICntrl.dispose(drawable); // disposes all registered UIShapes + + final GL2ES2 gl = drawable.getGL().getGL2ES2(); + screenshot.dispose(gl); + } + + private int shotCount = 0; + + public void printScreen(final GL gl) { + final RegionRenderer renderer = sceneUICntrl.getRenderer(); + final String modeS = Region.getRenderModeString(jogampLabel.getRenderModes()); + final String filename = String.format((Locale)null, "GraphUIDemo-shot%03d-%03dx%03d-S_%s_%02d.png", + shotCount++, renderer.getWidth(), renderer.getHeight(), + modeS, sceneUICntrl.getSampleCount()); + gl.glFinish(); // just make sure rendering finished .. + if(screenshot.readPixels(gl, false)) { + screenshot.write(new File(filename)); + System.err.println("Wrote: "+filename); + } + } + + @Override + public void display(final GLAutoDrawable drawable) { + if( fpsLabel.isEnabled() ) { + final String text; + if( null == actionText ) { + text = sceneUICntrl.getStatusText(drawable, renderModes, fpsLabel.getQuality(), dpiV); + } else if( null != drawable.getAnimator() ) { + text = SceneUIController.getStatusText(drawable.getAnimator())+", "+actionText; + } else { + text = actionText; + } + if( fpsLabel.setText(text) ) { // marks dirty only if text differs. + System.err.println(text); + } + } + sceneUICntrl.display(drawable); + } + + public void attachInputListenerTo(final GLWindow window) { + sceneUICntrl.attachInputListenerTo(window); + } + + public void detachInputListenerFrom(final GLWindow window) { + sceneUICntrl.detachInputListenerFrom(window); + } + + /** + * We can share this instance w/ all UI elements, + * since only mouse action / gesture is complete for a single one (press, drag, released and click). + */ + private final UIShape.MouseGestureAdapter dragZoomRotateListener = new UIShape.MouseGestureAdapter() { + @Override + public void mouseReleased(final MouseEvent e) { + actionText = null; + } + + @Override + public void mouseDragged(final MouseEvent e) { + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + if( e.getPointerCount() == 1 ) { + final float[] tx = shapeEvent.shape.getTranslate(); + actionText = String.format((Locale)null, "Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); + } + } + + @Override + public void mouseWheelMoved(final MouseEvent e) { + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + final boolean isOnscreen = PointerClass.Onscreen == e.getPointerType(0).getPointerClass(); + if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) && !isOnscreen ) { + // offscreen vertical mouse wheel zoom + final float tz = 100f*e.getRotation()[1]; // vertical: wheel + System.err.println("Rotate.Zoom.W: "+tz); + shapeEvent.shape.translate(0f, 0f, tz); + } else if( isOnscreen || e.isControlDown() ) { + final float[] rot = VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f); + if( isOnscreen ) { + System.err.println("XXX: "+e); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot[0]; rot[0] = rot[1]; rot[1] = tmp; + VectorUtil.scaleVec3(rot, rot, 2f); + } + shapeEvent.shape.getRotation().rotateByEuler( rot ); + } + } + @Override + public void gestureDetected(final GestureEvent e) { + final UIShape.UIShapeEvent shapeEvent = (UIShape.UIShapeEvent) e.getAttachment(); + if( e instanceof PinchToZoomGesture.ZoomEvent ) { + final PinchToZoomGesture.ZoomEvent ze = (PinchToZoomGesture.ZoomEvent) e; + final float tz = ze.getDelta() * ze.getScale(); + System.err.println("Rotate.Zoom.G: "+tz); + shapeEvent.shape.translate(0f, 0f, tz); + } + } }; +} diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/UIShapeDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/UIShapeDemo01.java index 63c147cdd..656345694 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/UIShapeDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/UIShapeDemo01.java @@ -207,7 +207,7 @@ public class UIShapeDemo01 implements GLEventListener { gl = gl.getContext().setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2(); } gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - getRegionRenderer().init(gl, renderModes); + getRegionRenderer().init(gl); gl.setSwapInterval(1); gl.glEnable(GL.GL_DEPTH_TEST); 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 9757c3df9..196447a23 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,17 +1,48 @@ +/** + * 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.test.junit.graph.demos.ui; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import com.jogamp.opengl.FPSCounter; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLAutoDrawable; +import com.jogamp.opengl.GLCapabilitiesImmutable; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLRunnable; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; - +import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.curve.opengl.RenderState; +import com.jogamp.graph.geom.Vertex; import com.jogamp.newt.event.GestureHandler; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.MouseEvent; @@ -60,9 +91,25 @@ public class SceneUIController implements GLEventListener{ this.sampleCount[0] = 4; } + /** Returns the associated RegionRenderer */ + public RegionRenderer getRenderer() { return renderer; } + /** Sets the associated RegionRenderer, may set to null to avoid its destruction when {@link #dispose(GLAutoDrawable)} this instance. */ public void setRenderer(final RegionRenderer renderer) { this.renderer = renderer; } + /** Returns the associated RegionRenderer's RenderState, may be null. */ + public RenderState getRenderState() { + if( null != renderer ) { + return renderer.getRenderState(); + } + return null; + } + public final Vertex.Factory<? extends Vertex> getVertexFactory() { + if( null != renderer ) { + return renderer.getRenderState().getVertexFactory(); + } + return null; + } public void attachInputListenerTo(final GLWindow window) { if(null == sbcMouseListener) { @@ -95,6 +142,20 @@ public class SceneUIController implements GLEventListener{ public void removeShape(final UIShape b) { shapes.remove(b); } + public final UIShape getShapeByIdx(final int id) { + if( 0 > id ) { + return null; + } + return shapes.get(id); + } + public UIShape getShapeByName(final int name) { + for(final UIShape b : shapes) { + if(b.getName() == name ) { + return b; + } + } + return null; + } public int getSampleCount() { return sampleCount[0]; } public int setSampleCount(final int v) { @@ -126,6 +187,9 @@ public class SceneUIController implements GLEventListener{ public void init(final GLAutoDrawable drawable) { System.err.println("SceneUIController: init"); cDrawable = drawable; + if( null != renderer ) { + renderer.init(drawable.getGL().getGL2ES2()); + } } private static Comparator<UIShape> shapeZAscComparator = new Comparator<UIShape>() { @@ -265,15 +329,32 @@ public class SceneUIController implements GLEventListener{ } } ); } + /** + * Disposes all {@link #addShape(UIShape) added} {@link UIShape}s. + * <p> + * Implementation also issues {@link RegionRenderer#destroy(GL2ES2)} if set + * and {@link #detachInputListenerFrom(GLWindow)} in case the drawable is of type {@link GLWindow}. + * </p> + * <p> + * {@inheritDoc} + * </p> + */ @Override public void dispose(final GLAutoDrawable drawable) { System.err.println("SceneUIController: dispose"); + if( drawable instanceof GLWindow ) { + final GLWindow glw = (GLWindow) drawable; + detachInputListenerFrom(glw); + } final GL2ES2 gl = drawable.getGL().getGL2ES2(); for(int i=0; i<shapes.size(); i++) { shapes.get(i).destroy(gl, renderer); } shapes.clear(); cDrawable = null; + if( null != renderer ) { + renderer.destroy(gl); + } } public static void mapWin2ObjectCoords(final PMVMatrix pmv, final int[] view, @@ -334,12 +415,6 @@ public class SceneUIController implements GLEventListener{ pmv.glScalef(sceneScale[0], sceneScale[1], sceneScale[2]); } - public final UIShape getShape(final int id) { - if( 0 > id ) { - return null; - } - return shapes.get(id); - } public final UIShape getActiveShape() { return activeShape; } @@ -506,4 +581,46 @@ public class SceneUIController implements GLEventListener{ clear(); } } -}
\ No newline at end of file + + /** + * Return a formatted status string containing avg fps and avg frame duration. + * @param glad GLAutoDrawable instance for FPSCounter, its chosen GLCapabilities and its GL's swap-interval + * @param renderModes render modes for {@link Region#getRenderModeString(int)} + * @param quality the Graph-Curve quality setting + * @param dpi the monitor's DPI (vertical preferred) + * @return formatted status string + */ + public String getStatusText(final GLAutoDrawable glad, final int renderModes, final int quality, final float dpi) { + final FPSCounter fpsCounter = glad.getAnimator(); + final float lfps, tfps, td; + if( null != fpsCounter ) { + lfps = fpsCounter.getLastFPS(); + tfps = fpsCounter.getTotalFPS(); + td = (float)fpsCounter.getLastFPSPeriod() / (float)fpsCounter.getUpdateFPSFrames(); + } else { + lfps = 0f; + tfps = 0f; + td = 0f; + } + final String modeS = Region.getRenderModeString(renderModes); + final GLCapabilitiesImmutable caps = glad.getChosenGLCapabilities(); + return String.format("%03.1f/%03.1f fps, %.1f ms/f, v-sync %d, dpi %.1f, %s-samples %d, q %d, msaa %d, blend %b, alpha %d", + lfps, tfps, td, glad.getGL().getSwapInterval(), dpi, modeS, getSampleCount(), quality, + caps.getNumSamples(), + getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED), + caps.getAlphaBits()); + } + + /** + * Return a formatted status string containing avg fps and avg frame duration. + * @param fpsCounter the counter, must not be null + * @return formatted status string + */ + public static String getStatusText(final FPSCounter fpsCounter) { + final float lfps = fpsCounter.getLastFPS(); + final float tfps = fpsCounter.getTotalFPS(); + final float td = (float)fpsCounter.getLastFPSPeriod() / (float)fpsCounter.getUpdateFPSFrames(); + return String.format("%03.1f/%03.1f fps, %.1f ms/f", lfps, tfps, td); + } + +} 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 62e6e0753..1ef54304f 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 @@ -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: @@ -54,6 +54,7 @@ import com.jogamp.opengl.util.PMVMatrix; public abstract class UIShape { public static final boolean DRAW_DEBUG_BOX = false; + private static final boolean DEBUG = false; protected static final int DIRTY_SHAPE = 1 << 0 ; protected static final int DIRTY_STATE = 1 << 1 ; @@ -92,6 +93,7 @@ public abstract class UIShape { private boolean down = false; private boolean toggle = false; private boolean toggleable = false; + private boolean draggable = true; private boolean enabled = true; private ArrayList<MouseGestureListener> mouseListeners = new ArrayList<MouseGestureListener>(); @@ -101,12 +103,16 @@ public abstract class UIShape { this.box = new AABBox(); } + /** Set a symbolic name for this shape for identification. Default is -1 for noname. */ public void setName(final int name) { this.name = name; } + /** Return the optional symbolic name for this shape. */ public int getName() { return this.name; } public final Vertex.Factory<? extends Vertex> getVertexFactory() { return vertexFactory; } + /** Returns true if this shape is enabled and hence visible, otherwise false. */ public boolean isEnabled() { return enabled; } + /** Enable or disable this shape, i.e. its visibility. */ public void setEnabled(final boolean v) { enabled = v; } /** @@ -444,24 +450,51 @@ public abstract class UIShape { return shapesSharpness; } + /** + * Set base color. + * <p> + * Default base-color w/o color channel, will be modulated w/ pressed- and toggle color + * </p> + */ public final void setColor(final float r, final float g, final float b, final float a) { this.rgbaColor[0] = r; this.rgbaColor[1] = g; this.rgbaColor[2] = b; this.rgbaColor[3] = a; } + + /** + * Set pressed color. + * <p> + * Default pressed color-factor w/o color channel, modulated base-color. 0.75 * 1.2 = 0.9 + * </p> + */ public final void setPressedColorMod(final float r, final float g, final float b, final float a) { this.pressedRGBAModulate[0] = r; this.pressedRGBAModulate[1] = g; this.pressedRGBAModulate[2] = b; this.pressedRGBAModulate[3] = a; } + + /** + * Set toggle-on color. + * <p> + * Default toggle-on color-factor w/o color channel, modulated base-color. 0.75 * 1.13 ~ 0.85 + * </p> + */ public final void setToggleOnColorMod(final float r, final float g, final float b, final float a) { this.toggleOnRGBAModulate[0] = r; this.toggleOnRGBAModulate[1] = g; this.toggleOnRGBAModulate[2] = b; this.toggleOnRGBAModulate[3] = a; } + + /** + * Set toggle-off color. + * <p> + * Default toggle-off color-factor w/o color channel, modulated base-color. 0.75 * 0.86 ~ 0.65 + * </p> + */ public final void setToggleOffColorMod(final float r, final float g, final float b, final float a) { this.toggleOffRGBAModulate[0] = r; this.toggleOffRGBAModulate[1] = g; @@ -493,6 +526,10 @@ public abstract class UIShape { public void setToggleable(final boolean toggleable) { this.toggleable = toggleable; } + /** + * Returns true if this shape is toggable, + * i.e. rendered w/ {@link #setToggleOnColorMod(float, float, float, float)} or {@link #setToggleOffColorMod(float, float, float, float)}. + */ public boolean isToggleable() { return toggleable; } @@ -508,6 +545,20 @@ public abstract class UIShape { } public boolean isToggleOn() { return toggle; } + /** + * Set whether this shape is draggable, + * i.e. translated by 1-pointer-click and drag. + * <p> + * Default is draggable on. + * </p> + */ + public void setDraggable(final boolean draggable) { + this.draggable = draggable; + } + public boolean isDraggable() { + return draggable; + } + public final void addMouseListener(final MouseGestureListener l) { if(l == null) { return; @@ -546,18 +597,20 @@ public abstract class UIShape { /** * {@link UIShape} event details for propagated {@link NEWTEvent}s * containing reference of {@link #shape the intended shape} as well as - * the {@link #objPos rotated relative position} and {@link #rotBounds bounding box}. - * The latter fields are also normalized to lower-left zero origin, allowing easier usage. + * the {@link #objPos rotated relative position}. + * The latter is normalized to lower-left zero origin, allowing easier usage. */ - public static class PointerEventInfo { + public static class UIShapeEvent { /** The associated {@link UIShape} for this event */ public final UIShape shape; /** The relative object coordinate of glWinX/glWinY to the associated {@link UIShape}. */ public final float[] objPos; - /** X-coordinate in GL window coordinates, origin bottom-left */ - public final int glWinX; - /** Y-coordinate in GL window coordinates, origin bottom-left */ - public final int glWinY; + /** The GL window coordinates, origin bottom-left */ + public final int[] winPos; + /** The drag delta of the relative object coordinate of glWinX/glWinY to the associated {@link UIShape}. */ + public final float[] objDrag = { 0f, 0f }; + /** The drag delta of GL window coordinates, origin bottom-left */ + public final int[] winDrag = { 0, 0 }; /** * Ctor @@ -566,16 +619,15 @@ public abstract class UIShape { * @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; + UIShapeEvent(final int glWinX, final int glWinY, final UIShape shape, final float[] objPos) { + this.winPos = new int[] { glWinX, glWinY }; this.shape = shape; this.objPos = objPos; } @Override public String toString() { - return "EventDetails[winPos ["+glWinX+", "+glWinY+"], objPos ["+objPos[0]+", "+objPos[1]+", "+objPos[2]+"], "+shape+"]"; + return "EventDetails[winPos ["+winPos[0]+", "+winPos[1]+"], objPos ["+objPos[0]+", "+objPos[1]+", "+objPos[2]+"], "+shape+"]"; } } @@ -585,12 +637,16 @@ public abstract class UIShape { * @param glWinY y-position in OpenGL model space */ public final void dispatchGestureEvent(final GestureEvent e, final int glWinX, final int glWinY, final float[] objPos) { - e.setAttachment(new PointerEventInfo(glWinX, glWinY, this, objPos)); + e.setAttachment(new UIShapeEvent(glWinX, glWinY, this, objPos)); for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) { mouseListeners.get(i).gestureDetected(e); } } + boolean dragFirst = false; + float[] objDraggedFirst = { 0f, 0f }; // b/c its relative to UIShape and we stick to it + int[] winDraggedLast = { 0, 0 }; // b/c its absolute window pos + /** * Dispatch given NEWT mouse event to this shape * @param e original Newt {@link MouseEvent} @@ -599,7 +655,8 @@ public abstract class UIShape { * @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)); + final UIShape.UIShapeEvent shapeEvent = new UIShapeEvent(glWinX, glWinY, this, objPos); + e.setAttachment(shapeEvent); final short eventType = e.getEventType(); if( 1 == e.getPointerCount() ) { @@ -615,6 +672,42 @@ public abstract class UIShape { break; } } + switch( eventType ) { + case MouseEvent.EVENT_MOUSE_PRESSED: + dragFirst = true; + break; + case MouseEvent.EVENT_MOUSE_RELEASED: + dragFirst = false; + break; + case MouseEvent.EVENT_MOUSE_DRAGGED: { + // 1 pointer drag + if(dragFirst) { + objDraggedFirst[0] = objPos[0]; + objDraggedFirst[1] = objPos[1]; + winDraggedLast[0] = glWinX; + winDraggedLast[1] = glWinY; + dragFirst=false; + return; + } + shapeEvent.objDrag[0] = objPos[0] - objDraggedFirst[0]; + shapeEvent.objDrag[1] = objPos[1] - objDraggedFirst[1]; + shapeEvent.winDrag[0] = glWinX - winDraggedLast[0]; + shapeEvent.winDrag[1] = glWinY - winDraggedLast[1]; + winDraggedLast[0] = glWinX; + winDraggedLast[1] = glWinY; + if( draggable && e.getPointerCount() == 1 ) { + translate(shapeEvent.objDrag[0], shapeEvent.objDrag[1], 0f); + } + if( DEBUG ) { + System.err.printf("Dragged: win %4d/%4d + %2d/%2d; obj %.3f/%.3f + %.3f/%.3f%n", + shapeEvent.winPos[0], shapeEvent.winPos[1], + shapeEvent.winDrag[0], shapeEvent.winDrag[1], + shapeEvent.objPos[0], shapeEvent.objPos[1], + shapeEvent.objDrag[0], shapeEvent.objDrag[1]); + } + } + break; + } for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) { final MouseGestureListener l = mouseListeners.get(i); |