diff options
author | Sven Gothel <[email protected]> | 2014-03-17 16:14:44 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2014-03-17 16:14:44 +0100 |
commit | 6382ee094953fd4fef35a8e60a29b482ae1b79c3 (patch) | |
tree | ba1d0f4cc787d553346e854805f6df6433de56d9 /src | |
parent | 8e39433ee85835a0e4a8b1bdac6c31c2518ba5b4 (diff) |
Bug 801: GraphUI .. Fixed transformations, cleanup - All shape-object oriented actions.
http://jogamp.org/files/screenshots/graphui/01/
Diffstat (limited to 'src')
8 files changed, 685 insertions, 274 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 72c5d6a17..1d6162233 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,6 +1,9 @@ package com.jogamp.opengl.test.junit.graph.demos; +import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; @@ -17,15 +20,18 @@ import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontFactory; import com.jogamp.graph.geom.SVertex; import com.jogamp.newt.Window; +import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.MouseAdapter; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.math.FloatUtil; -import com.jogamp.opengl.math.Quaternion; +import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.test.junit.graph.demos.ui.CrossHair; import com.jogamp.opengl.test.junit.graph.demos.ui.Label; import com.jogamp.opengl.test.junit.graph.demos.ui.RIButton; import com.jogamp.opengl.test.junit.graph.demos.ui.SceneUIController; import com.jogamp.opengl.test.junit.graph.demos.ui.UIShape; +import com.jogamp.opengl.util.GLReadBufferUtil; import com.jogamp.opengl.util.glsl.ShaderState; public class GPUUISceneGLListener0A implements GLEventListener { @@ -41,6 +47,11 @@ public class GPUUISceneGLListener0A implements GLEventListener { int fontSet = FontFactory.UBUNTU; Font font; + + final float relTop = 5f/6f; + final float relRight = 2f/6f; + final float relLeft = 1f/6f; + final float buttonXSize = 84f; final float buttonYSize = buttonXSize/2.5f; final float fontSizeFixed = 12f; @@ -49,16 +60,19 @@ public class GPUUISceneGLListener0A implements GLEventListener { private int currentText = 0; + private String actionText = null; private Label[] labels = null; private String[] strings = null; - private RIButton[] buttons = null; + private final List<RIButton> buttons = new ArrayList<RIButton>(); private Label jogampLabel = null; private Label fpsLabel = null; - private final int numSelectable = 6; + private CrossHair crossHairCtr = null; private boolean ioAttached = false; private GLAutoDrawable cDrawable; + private final GLReadBufferUtil screenshot; + private final String jogamp = "JogAmp - Jogl Graph Module Demo"; public GPUUISceneGLListener0A() { @@ -82,52 +96,77 @@ public class GPUUISceneGLListener0A implements GLEventListener { ioe.printStackTrace(); } sceneUIController = new SceneUIController(); + screenshot = new GLReadBufferUtil(false, false); } - private void rotateButtons(MouseEvent e, float angdeg) { - for(int i=0; i<buttons.length; i++) { - rotateInstance(e, buttons[i].getRotation(), angdeg); + private void rotateButtons(float[] angdeg) { + angdeg = VectorUtil.scaleVec3(angdeg, angdeg, FloatUtil.PI / 180.0f); + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).getRotation().rotateByEuler( angdeg ); } } - private void rotateInstance(MouseEvent e, Quaternion quat, float angdeg) { - final float angrad = angdeg * FloatUtil.PI / 180.0f; - if( e.isControlDown() ) { - quat.rotateByAngleZ(angrad); - } else if( e.isShiftDown() ) { - quat.rotateByAngleX(angrad); - } else { - quat.rotateByAngleY(angrad); + private void translateButtons(float tx, float ty, float tz) { + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).translate(tx, ty, tz); + } + } + + private void setButtonsSpacing(float dx, float dy) { + for(int i=0; i<buttons.size(); i++) { + final float sx = buttons.get(i).getSpacingX()+dx, sy = buttons.get(i).getSpacingY()+dy; + System.err.println("Spacing: X "+sx+", Y "+sy); + buttons.get(i).setSpacing(sx, sy); + } + } + + private void setButtonsCorner(float dc) { + for(int i=0; i<buttons.size(); i++) { + final float c = buttons.get(i).getCorner()+dc; + System.err.println("Corner: "+c); + buttons.get(i).setCorner(c); + } + } + + private void resetButtons() { + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).getRotation().setIdentity(); + buttons.get(i).setCorner(RIButton.DEFAULT_CORNER); + buttons.get(i).setSpacing(RIButton.DEFAULT_SPACING_X, RIButton.DEFAULT_SPACING_Y); } } - private void initButtons() { - buttons = new RIButton[numSelectable]; + private void initButtons(final GL gl, final RegionRenderer renderer) { + final boolean pass2Mode = 0 != ( renderer.getRenderModes() & ( Region.VBAA_RENDERING_BIT | Region.MSAA_RENDERING_BIT ) ) ; + buttons.clear(); final float xstart = 0f; final float ystart = 0f; - final float diff = 1.5f * buttonYSize; + final float diffX = 1.2f * buttonXSize; + final float diffY = 1.5f * buttonYSize; - buttons[0] = new RIButton(SVertex.factory(), font, "Next Text", buttonXSize, buttonYSize); - buttons[0].translate(xstart,ystart, 0f); - buttons[0].setLabelColor(1.0f, 1.0f, 1.0f); - buttons[0].addMouseListener(new MouseAdapter() { + RIButton button = new RIButton(SVertex.factory(), font, "Next Text", buttonXSize, buttonYSize); + button.translate(xstart,ystart-diffY*buttons.size(), 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if( null != labels[currentText] ) { labels[currentText].setEnabled(false); } - currentText = (currentText+1)%3; + currentText = (currentText+1)%labels.length; if( null != labels[currentText] ) { labels[currentText].setEnabled(true); } } } ); - buttons[0].addMouseListener(new DragAndZoomListener(buttons[0])); - - buttons[1] = new RIButton(SVertex.factory(), font, "Show FPS", buttonXSize, buttonYSize); - buttons[1].translate(xstart,ystart - diff, 0f); - buttons[1].setToggleable(true); - buttons[1].setLabelColor(1.0f, 1.0f, 1.0f); - buttons[1].addMouseListener(new MouseAdapter() { + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new RIButton(SVertex.factory(), font, "Show FPS", buttonXSize, buttonYSize); + button.translate(xstart,ystart - diffY*buttons.size(), 0f); + button.setToggleable(true); + button.setPressed(fpsLabel.isEnabled()); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { final GLAnimatorControl a = cDrawable.getAnimator(); @@ -136,13 +175,15 @@ public class GPUUISceneGLListener0A implements GLEventListener { } fpsLabel.setEnabled(!fpsLabel.isEnabled()); } } ); - buttons[1].addMouseListener(new DragAndZoomListener(buttons[1])); - - buttons[2] = new RIButton(SVertex.factory(), font, "v-sync", buttonXSize, buttonYSize); - buttons[2].translate(xstart,ystart-diff*2, 0f); - buttons[2].setToggleable(true); - buttons[2].setLabelColor(1.0f, 1.0f, 1.0f); - buttons[2].addMouseListener(new MouseAdapter() { + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + button = new RIButton(SVertex.factory(), font, "v-sync", buttonXSize, buttonYSize); + button.translate(xstart,ystart - diffY*buttons.size(), 0f); + button.setToggleable(true); + button.setPressed(gl.getSwapInterval()>0); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { cDrawable.invoke(false, new GLRunnable() { @@ -158,56 +199,250 @@ public class GPUUISceneGLListener0A implements GLEventListener { } }); } } ); - buttons[2].addMouseListener(new DragAndZoomListener(buttons[2])); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); - buttons[3] = new RIButton(SVertex.factory(), font, "Tilt +Y", buttonXSize, buttonYSize); - buttons[3].translate(xstart,ystart-diff*3, 0f); - buttons[3].setLabelColor(1.0f, 1.0f, 1.0f); - buttons[3].addMouseListener(new MouseAdapter() { + button = new RIButton(SVertex.factory(), font, "< tilt >", buttonXSize, buttonYSize); + button.translate(xstart,ystart - diffY*buttons.size(), 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - rotateButtons(e, 5f); + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + if( shapeEvent.rotPosition[0] < shapeEvent.rotBounds.getCenter()[0] ) { + rotateButtons(new float[] { 0f, -5f, 0f}); // left-half pressed + } else { + rotateButtons(new float[] { 0f, 5f, 0f}); // right-half pressed + } + } + } + @Override + public void mouseWheelMoved(MouseEvent e) { + rotateButtons(new float[] { 0f, e.getRotation()[1], 0f}); } } ); - buttons[3].addMouseListener(new DragAndZoomListener(buttons[3])); + buttons.add(button); + + if( pass2Mode ) { // second column to the left + button = new RIButton(SVertex.factory(), font, "< samples >", buttonXSize, buttonYSize); + button.translate(xstart,ystart - diffY*buttons.size(), 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + int sampleCount = sceneUIController.getSampleCount(); + if( shapeEvent.rotPosition[0] < shapeEvent.rotBounds.getCenter()[0] ) { + // left-half pressed + if( sampleCount > 0 ) { + sampleCount-=1; + } + } else { + // right-half pressed + if( sampleCount < 8 ) { + sampleCount+=1; + } + } + sceneUIController.setSampleCount(sampleCount); + } + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + } - buttons[4] = new RIButton(SVertex.factory(), font, "Tilt -Y", buttonXSize, buttonYSize); - buttons[4].translate(xstart,ystart-diff*4, 0f); - buttons[4].setLabelColor(1.0f, 1.0f, 1.0f); - buttons[4].addMouseListener(new MouseAdapter() { + button = new RIButton(SVertex.factory(), font, "Quit", buttonXSize, buttonYSize); + button.translate(xstart,ystart - diffY*buttons.size(), 0f); + button.setColor(0.8f, 0.0f, 0.0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.setSelectedColor(0.8f, 0.8f, 0.8f); + button.setLabelSelectedColor(0.8f, 0.0f, 0.0f); + button.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - rotateButtons(e, -5f); + new Thread() { + public void run() { + if( null != cDrawable ) { + final GLAnimatorControl actrl = cDrawable.getAnimator(); + if( null != actrl ) { + actrl.stop(); + } + cDrawable.destroy(); + } + } }.start(); } } ); - buttons[4].addMouseListener(new DragAndZoomListener(buttons[4])); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + // second column to the left + { + int j = 1; // column + int k = 0; // row + button = new RIButton(SVertex.factory(), font, "y flip", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + rotateButtons(new float[] { 0f, 180f, 0f}); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + + k++; + button = new RIButton(SVertex.factory(), font, "x flip", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + rotateButtons(new float[] { 180f, 0f, 0f}); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + + button = new RIButton(SVertex.factory(), font, "+", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + // rel position to center + final float dx = shapeEvent.rotPosition[0] - shapeEvent.rotBounds.getCenter()[0] ; + final float dy = shapeEvent.rotPosition[1] - shapeEvent.rotBounds.getCenter()[1] ; + // per-cent position to center (remove dependency on dimension) + final float awdx = Math.abs(dx)/shapeEvent.rotBounds.getWidth(); + final float awdy = Math.abs(dy)/shapeEvent.rotBounds.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); + k++; + + button = new RIButton(SVertex.factory(), font, "< space >", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + final float dx, dy; + if( shapeEvent.rotPosition[0] < shapeEvent.rotBounds.getCenter()[0] ) { + dx=-0.01f; dy=-0.005f; + } else { + dx=0.01f; dy=0.005f; + } + setButtonsSpacing(dx, dy); + } + } + @Override + public void mouseWheelMoved(MouseEvent e) { + setButtonsSpacing(e.getRotation()[0]/100f, e.getRotation()[1]/200f); + } } ); + buttons.add(button); + k++; + + button = new RIButton(SVertex.factory(), font, "< corner >", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + final float dc; + if( shapeEvent.rotPosition[0] < shapeEvent.rotBounds.getCenter()[0] ) { + dc=-0.1f; + } else { + dc=0.1f; + } + setButtonsCorner(dc); + } - buttons[5] = new RIButton(SVertex.factory(), font, "Quit", buttonXSize, buttonYSize); - buttons[5].translate(xstart,ystart-diff*5, 0f); - buttons[5].setColor(0.8f, 0.0f, 0.0f); - buttons[5].setLabelColor(1.0f, 1.0f, 1.0f); + } + @Override + public void mouseWheelMoved(MouseEvent e) { + setButtonsCorner(e.getRotation()[1]/20f); + } } ); + buttons.add(button); + k++; + + button = new RIButton(SVertex.factory(), font, "reset", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + resetButtons(); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + + button = new RIButton(SVertex.factory(), font, "screenshot", buttonXSize, buttonYSize); + button.translate(xstart - diffX*j,ystart - diffY*k, 0f); + button.setLabelColor(1.0f, 1.0f, 1.0f); + button.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + cDrawable.invoke(false, new GLRunnable() { + @Override + public boolean run(GLAutoDrawable drawable) { + printScreen(drawable.getGL()); + return true; + } + }); + } } ); + button.addMouseListener(dragZoomRotateListener); + buttons.add(button); + k++; + } - buttons[5].setSelectedColor(0.8f, 0.8f, 0.8f); - buttons[5].setLabelSelectedColor(0.8f, 0.0f, 0.0f); - buttons[5].addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - cDrawable.destroy(); - } } ); - buttons[5].addMouseListener(new DragAndZoomListener(buttons[5])); } private void initTexts() { - strings = new String[3]; - - strings[0] = "Next Text\n"+ - "Show FPS\n"+ - "abcdefghijklmn\nopqrstuvwxyz\n"+ - "ABCDEFGHIJKL\n"+ - "MNOPQRSTUVWXYZ\n"+ - "0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; - - strings[1] = "The quick brown fox\njumps over the lazy\ndog"; - - strings[2] = + strings = new String[4]; + int i = 0; + + strings[i++] = + "- Mouse Scroll Over Object\n"+ + " - General\n"+ + " - Z Translation\n"+ + " - Ctrl: Y-Rotation (Shift: X-Rotation)\n"+ + " - Tilt, Space and Corner\n"+ + " - Their respective action via wheel (shift = other value)\n"+ + "\n"+ + "- Mouse Drag On Object\n"+ + " - Click on Object and drag mouse\n"+ + " - Notice current postion in status line at buttom\n"+ + "\n"+ + "- Tilt Button Rotate Whole Button Group\n"+ + "- Window Resize Shall Maintain Layout\n"; + + strings[i++] = "abcdefghijklmn\nopqrstuvwxyz\n"+ + "ABCDEFGHIJKL\n"+ + "MNOPQRSTUVWXYZ\n"+ + "0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]"; + + strings[i++] = "The quick brown fox\njumps over the lazy\ndog"; + + strings[i++] = "Lorem ipsum dolor sit amet, consectetur\n"+ "Ut purus odio, rhoncus sit amet com\n"+ "quam iaculis urna cursus ornare. Nullam\n"+ @@ -216,9 +451,12 @@ public class GPUUISceneGLListener0A implements GLEventListener { "Donec ut dolor et nulla tristique variu\n"+ "in lorem. Maecenas in ipsum ac justo sc\n"; - labels = new Label[3]; + labels = new Label[i]; } + + final boolean enableOthers = true; + @Override public void init(GLAutoDrawable drawable) { final Object upObj = drawable.getUpstreamWidget(); @@ -252,6 +490,7 @@ public class GPUUISceneGLListener0A implements GLEventListener { renderer = RegionRenderer.create(rs, renderModes, RegionRenderer.defaultBlendEnable, RegionRenderer.defaultBlendDisable); + gl.setSwapInterval(1); gl.glEnable(GL2ES2.GL_DEPTH_TEST); gl.glEnable(GL2ES2.GL_BLEND); @@ -259,27 +498,30 @@ public class GPUUISceneGLListener0A implements GLEventListener { renderer.setAlpha(gl, 1.0f); initTexts(); - initButtons(); sceneUIController.setRenderer(renderer); - sceneUIController.addShape(buttons[0]); - sceneUIController.addShape(buttons[1]); - sceneUIController.addShape(buttons[2]); - sceneUIController.addShape(buttons[3]); - sceneUIController.addShape(buttons[4]); - sceneUIController.addShape(buttons[5]); final float pixelSizeFixed = font.getPixelSize(fontSizeFixed, dpiH); jogampLabel = new Label(SVertex.factory(), font, pixelSizeFixed, jogamp); - jogampLabel.addMouseListener(new DragAndZoomListener(jogampLabel)); + jogampLabel.addMouseListener(dragZoomRotateListener); sceneUIController.addShape(jogampLabel); + jogampLabel.setEnabled(enableOthers); final float pixelSizeFPS = font.getPixelSize(fontSizeFPS, dpiH); fpsLabel = new Label(renderer.getRenderState().getVertexFactory(), font, pixelSizeFPS, "Nothing there yet"); - fpsLabel.translate(0f, 0f, 0f); // FIXME - fpsLabel.addMouseListener(new DragAndZoomListener(fpsLabel)); - fpsLabel.addMouseListener(new DragAndZoomListener(fpsLabel)); + fpsLabel.addMouseListener(dragZoomRotateListener); sceneUIController.addShape(fpsLabel); + fpsLabel.setEnabled(enableOthers); + + crossHairCtr = new CrossHair(renderer.getRenderState().getVertexFactory(), 100f, 100f, 2f); + crossHairCtr.addMouseListener(dragZoomRotateListener); + sceneUIController.addShape(crossHairCtr); + crossHairCtr.setEnabled(true); + + initButtons(gl, renderer); + for(int i=0; i<buttons.size(); i++) { + sceneUIController.addShape(buttons.get(i)); + } sceneUIController.init(drawable); @@ -303,10 +545,21 @@ public class GPUUISceneGLListener0A implements GLEventListener { GL2ES2 gl = drawable.getGL().getGL2ES2(); renderer.destroy(gl); + screenshot.dispose(gl); } - protected void setupPMV(GLAutoDrawable drawable) { - + private int shotCount = 0; + + public void printScreen(final GL gl) { + final String modeS = Region.getRenderModeString(renderer.getRenderModes()); + final String filename = String.format("GraphUIDemo-shot%03d-%03dx%03d-S_%s_%02d.png", + shotCount++, renderer.getWidth(), renderer.getHeight(), + modeS, sceneUIController.getSampleCount()); + gl.glFinish(); // just make sure rendering finished .. + if(screenshot.readPixels(gl, false)) { + screenshot.write(new File(filename)); + System.err.println("Wrote: "+filename); + } } @Override @@ -316,12 +569,13 @@ public class GPUUISceneGLListener0A implements GLEventListener { if(null == labels[currentText]) { final float pixelSizeFixed = font.getPixelSize(fontSizeFixed, dpiH); - float dx = drawable.getWidth() * 1f/3f; + final float dyTop = drawable.getHeight() * relTop; + final float dxRight = drawable.getWidth() * relRight; labels[currentText] = new Label(SVertex.factory(), font, pixelSizeFixed, strings[currentText]); labels[currentText].setColor(0, 0, 0); - labels[currentText].translate(dx, -3f * jogampLabel.getLineHeight(), 0f); - labels[currentText].setEnabled(true); - labels[currentText].addMouseListener(new DragAndZoomListener(labels[currentText])); + labels[currentText].setEnabled(enableOthers); + labels[currentText].translate(dxRight, dyTop - 1.5f * jogampLabel.getLineHeight(), 0f); + labels[currentText].addMouseListener(dragZoomRotateListener); sceneUIController.addShape(labels[currentText]); } if( fpsLabel.isEnabled() ) { @@ -337,29 +591,53 @@ public class GPUUISceneGLListener0A implements GLEventListener { td = 0f; } final String modeS = Region.getRenderModeString(renderer.getRenderModes()); - final String text = String.format("%03.1f/%03.1f fps, v-sync %d, fontSize %.1f, %s-samples %d, td %4.1f, blend %b, alpha-bits %d", + final String text; + if( null == actionText ) { + text = String.format("%03.1f/%03.1f fps, v-sync %d, fontSize %.1f, %s-samples %d, td %4.1f, blend %b, alpha-bits %d", lfps, tfps, gl.getSwapInterval(), fontSizeFixed, modeS, sceneUIController.getSampleCount(), td, renderer.getRenderState().isHintMaskSet(RenderState.BITHINT_BLENDING_ENABLED), drawable.getChosenGLCapabilities().getAlphaBits()); - fpsLabel.clear(gl, renderer); + } else { + text = String.format("%03.1f/%03.1f fps, v-sync %d, fontSize %.1f, %s", + lfps, tfps, gl.getSwapInterval(), fontSizeFixed, actionText); + } fpsLabel.setText(text); } sceneUIController.display(drawable); } + float lastWidth = 0f, lastHeight = 0f; + @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { System.err.println("GPUUISceneGLListener0A: reshape"); - float dx = width * 1f/3f; - jogampLabel.setTranslate(dx, 0f, 0f); - fpsLabel.setTranslate(0f, 0f, 0f); // FIXME + // + // Layout all shapes: Relational move regarding window coordinates + // + final float dw = width - lastWidth; + final float dh = height - lastHeight; + + final float dz = 0f; + final float dyTop = dh * relTop; + final float dxRight = dw * relRight; + final float dxLeft = dw * relLeft; + + for(int i=0; i<buttons.size(); i++) { + buttons.get(i).translate(dxLeft, dyTop, dz); + } + jogampLabel.translate(dxRight, dyTop, dz); + fpsLabel.translate(0f, 0f, 0f); if( null != labels[currentText] ) { - labels[currentText].setTranslate(dx, -3f * jogampLabel.getLineHeight(), 0f); + labels[currentText].translate(dxRight, dyTop, 0f); } + crossHairCtr.translate(dw/2f, dh/2f, 0f); sceneUIController.reshape(drawable, x, y, width, height); + + lastWidth = width; + lastHeight = height; } public void attachInputListenerTo(GLWindow window) { @@ -376,68 +654,73 @@ public class GPUUISceneGLListener0A implements GLEventListener { } } - private class DragAndZoomListener extends MouseAdapter { - final UIShape shape; - int lx=-1, ly=-1; - boolean first = false; - - public DragAndZoomListener(UIShape shape) { - this.shape = shape; - } + /** + * 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 MouseAdapter dragZoomRotateListener = new MouseAdapter() { + int dragLastX=-1, dragLastY=-1; + boolean dragFirst = false; @Override public void mousePressed(MouseEvent e) { - first = true; + dragFirst = true; } @Override public void mouseReleased(MouseEvent e) { - first = false; + dragFirst = false; + actionText = null; } @Override public void mouseDragged(MouseEvent e) { - if(e.getPointerCount()==2) { - // 2 pointers zoom .. - if(first) { - lx = Math.abs(e.getY(0)-e.getY(1)); - first=false; - return; - } - int nv = Math.abs(e.getY(0)-e.getY(1)); - int dy = nv - lx; - lx = nv; + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + if(e.getPointerCount()==2) { + // 2 pointers zoom .. + if(dragFirst) { + dragLastX = Math.abs(e.getY(0)-e.getY(1)); + dragFirst=false; + return; + } + int nv = Math.abs(e.getY(0)-e.getY(1)); + int dy = nv - dragLastX; + dragLastX = nv; - shape.translate(0f, 0f, 2 * Math.signum(dy)); - } else { - // 1 pointer drag - if(first) { - lx = e.getX(); - ly = e.getY(); - first=false; - return; - } - int nx = e.getX(); - int ny = e.getY(); - int dx = nx - lx; - int dy = ny - ly; - if(Math.abs(dx) > Math.abs(dy)){ - shape.translate(Math.signum(dx), 0f, 0f); + shapeEvent.shape.translate(0f, 0f, 2 * Math.signum(dy)); } else { - shape.translate(0f, -Math.signum(dy), 0f); + // 1 pointer drag + if(dragFirst) { + dragLastX = e.getX(); + dragLastY = e.getY(); + dragFirst=false; + return; + } + final int nx = e.getX(); + final int ny = e.getY(); + shapeEvent.shape.translate(nx-dragLastX, -(ny-dragLastY), 0f); + dragLastX = nx; + dragLastY = ny; + float[] tx = shapeEvent.shape.getTranslate(); + actionText = String.format("Pos %6.2f / %6.2f / %6.2f", tx[0], tx[1], tx[2]); } - lx = nx; - ly = ny; } } @Override public void mouseWheelMoved(MouseEvent e) { - if( !e.isShiftDown() ) { - float tz = 2f*e.getRotation()[1]; // vertical: wheel - System.err.println("tz.4 "+tz); - shape.translate(0f, 0f, tz); + final Object attachment = e.getAttachment(); + if( attachment instanceof UIShape.EventDetails ) { + final UIShape.EventDetails shapeEvent = (UIShape.EventDetails)attachment; + if( 0 == ( ~InputEvent.BUTTONALL_MASK & e.getModifiers() ) ) { + float tz = 2f*e.getRotation()[1]; // vertical: wheel + System.err.println("tz.4 "+tz); + shapeEvent.shape.translate(0f, 0f, tz); + } else if( e.isControlDown() ) { + shapeEvent.shape.getRotation().rotateByEuler( VectorUtil.scaleVec3(e.getRotation(), e.getRotation(), FloatUtil.PI / 180.0f) ); + } } - } - } + } }; }
\ No newline at end of file diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java index a371aa8b2..127d30aae 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo01.java @@ -33,7 +33,7 @@ public class GPUUISceneNewtDemo01 { textGLListener.attachInputListenerTo(window); final Animator animator = new Animator(); - animator.setUpdateFPSFrames(60, System.err); + animator.setUpdateFPSFrames(60, null);//System.err); animator.add(window); window.addWindowListener(new WindowAdapter() { diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java index 32c3a9439..61d833f59 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUUISceneNewtDemo02.java @@ -34,7 +34,7 @@ public class GPUUISceneNewtDemo02 { textGLListener.attachInputListenerTo(window); final Animator animator = new Animator(); - animator.setUpdateFPSFrames(60, System.err); + animator.setUpdateFPSFrames(60, null); // System.err); animator.add(window); window.addWindowListener(new WindowAdapter() { diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java index 16ee148e8..78c42b2d0 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/Label.java @@ -103,6 +103,8 @@ public class Label extends UIShape { @Override protected void createShape(GL2ES2 gl, RegionRenderer renderer) { TextRegionUtil.processString(shapeVisitor, new AffineTransform(), font, pixelSize, text); + final float[] ctr = box.getCenter(); + setRotationOrigin( ctr[0], ctr[1], ctr[2]); } @Override diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java index 83ca6bed0..cfce04dd0 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/RIButton.java @@ -41,19 +41,24 @@ import com.jogamp.opengl.math.geom.AABBox; * GPU based resolution independent Button impl */ public class RIButton extends UIShape { + /** {@value} */ + public static final float DEFAULT_SPACING_X = 0.08f; + /** {@value} */ + public static final float DEFAULT_SPACING_Y = 0.40f; + /** {@value} */ + public static final float DEFAULT_CORNER = 1f; + private float width, height; private final Label label; - /** 20 % to each side default */ - private float spacing = 0.2f; - private static final float spacingSx = 2f; - private static final float spacingSy = 2f; - private float corner = 1.0f; + private float spacingX = DEFAULT_SPACING_X; + private float spacingY = DEFAULT_SPACING_Y; + private float corner = DEFAULT_CORNER; private float labelZOffset = -0.05f; public RIButton(Factory<? extends Vertex> factory, Font labelFont, String labelText, float width, float height) { super(factory); - final float pixelSize = height * ( 1f - spacingSy*spacing ) ; + final float pixelSize = height * ( 1f - spacingY ) ; System.err.printf("RIButton: height %f -> pixelSize %f%n", height, pixelSize); this.label = new Label(factory, labelFont, pixelSize, labelText); this.label.setSelectedColor(this.color[0], this.color[1], this.color[2]); @@ -66,10 +71,10 @@ public class RIButton extends UIShape { public final float getWidth() { return width; } public final float getHeight() { return height; } - public float getCorner() { return corner; } - public Label getLabel() { return label; } + public final float getCorner() { return corner; } + public final Label getLabel() { return label; } - public void setDimension(int width, int height) { + public void setDimension(float width, float height) { this.width = width; this.height = height; dirty |= DIRTY_SHAPE | DIRTY_REGION; @@ -97,55 +102,63 @@ public class RIButton extends UIShape { @Override protected void createShape(GL2ES2 gl, RegionRenderer renderer) { + label.clear(gl, renderer); + + final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); + if(corner == 0.0f) { + createSharpOutline(shape); + } else { + createCurvedOutline(shape); + } + box.resize(shape.getBounds()); + // Precompute text-box size .. guessing pixelSize - final float lw = getWidth() * ( 1f - spacingSx*spacing ); - final float lh = getHeight() * ( 1f - spacingSy*spacing ); - final AABBox lbox0 = label.font.getStringBounds(label.text, lh); + final float lPixelSize0 = 10f; + final float lw = width * ( 1f - spacingX ) ; + final float lh = height * ( 1f - spacingY ) ; + final AABBox lbox0 = label.font.getStringBounds(label.text, lPixelSize0); final float lsx = lw / lbox0.getWidth(); final float lsy = lh / lbox0.getHeight(); + final float lPixelSize1 = lsx < lsy ? lPixelSize0 * lsx : lPixelSize0 * lsy; if( DRAW_DEBUG_BOX ) { - final float sx = getWidth() / ( ( spacingSx*spacing + 1f ) * lbox0.getWidth() * lsx ); - final float sy = getHeight() / ( ( spacingSy*spacing + 1f ) * lbox0.getHeight() * lsy ); - System.err.printf("RIButton: bsize %f x %f, lsize %f x %f, lbox0 %f x %f -> ls %f x %f, bs %f x %f .... %s%n", - getWidth(), getHeight(), lw, lh, lbox0.getWidth(), lbox0.getHeight(), lsx, lsy, sx, sy, this.label.text); + System.err.println("RIButton: spacing "+spacingX+", "+spacingY); + System.err.println("RIButton: bbox "+box); + System.err.println("RIButton: lbox "+lbox0); + System.err.println("RIButton: net-text "+lw+" x "+lh); + System.err.println("RIButton: lsx "+lsx+", lsy "+lsy+": pixelSize "+lPixelSize0+" -> "+lPixelSize1); } // Setting pixelSize based on actual text-box size - final float lPixelSize1 = lh * lsy; label.setPixelSize(lPixelSize1); label.createShape(gl, renderer); final AABBox lbox1 = label.getBounds(); if( DRAW_DEBUG_BOX ) { - final float lsx1 = lw / lbox1.getWidth(); - final float lsy1 = lh / lbox1.getHeight(); - System.err.printf("RIButton: ls %f x %f, lbox1 %s .... %s%n", - lsx1, lsy1, lbox1, this.label.text); - } - - final OutlineShape shape = new OutlineShape(renderer.getRenderState().getVertexFactory()); - if(corner == 0.0f) { - createSharpOutline(shape, lbox1); - } else { - createCurvedOutline(shape, lbox1); + System.err.printf("RIButton: lbox1 %s .... %s%n", lbox1, this.label.text); } - box.resize(shape.getBounds()); - // Center text .. + // Center text .. (share same center w/ button) final float[] lctr = lbox1.getCenter(); final float[] ctr = box.getCenter(); - label.translateShape( ctr[0] - lctr[0], ctr[1] - lctr[1] ); + final float[] ltx = new float[] { ctr[0] - lctr[0], ctr[1] - lctr[1], 0f }; + label.translateShape( ltx[0], ltx[1] ); + lbox1.translate( ltx ); + + // rotate center of button/label .. + label.setRotationOrigin( ctr[0], ctr[1], ctr[2]); + setRotationOrigin( ctr[0], ctr[1], ctr[2]); shapes.add(new OutlineShapeXForm(shape, null)); + if( DRAW_DEBUG_BOX ) { System.err.println("XXX.UIShape.RIButton: Added Shape: "+shape+", "+box); } } - private void createSharpOutline(OutlineShape shape, AABBox lbox) { - final float tw = getWidth(); // ( spacingSx*spacing + 1f ) * lbox.getWidth(); - final float th = getHeight(); // ( spacingSy*spacing + 1f ) * lbox.getHeight(); + private void createSharpOutline(OutlineShape shape) { + final float tw = getWidth(); + final float th = getHeight(); - final float minX = lbox.getMinX() - ( spacingSx / 2f * spacing * lbox.getWidth() ); - final float minY = lbox.getMinY() - ( spacingSy / 2f * spacing * lbox.getHeight() ); + final float minX = 0; + final float minY = 0; final float minZ = labelZOffset; shape.addVertex(minX, minY, minZ, true); @@ -154,33 +167,34 @@ public class RIButton extends UIShape { shape.addVertex(minX, minY + th, minZ, true); shape.closeLastOutline(true); } - private void createCurvedOutline(OutlineShape shape, AABBox lbox){ - final float tw = getWidth(); // ( spacingSx*spacing + 1f ) * lbox.getWidth(); - final float th = getHeight(); // ( spacingSy*spacing + 1f ) * lbox.getHeight(); - final float cw = 0.5f*corner*Math.min(tw, th); - final float ch = 0.5f*corner*Math.min(tw, th); + private void createCurvedOutline(OutlineShape shape) { + final float tw = getWidth(); + final float th = getHeight(); + final float dC = 0.5f*corner*Math.min(tw, th); - final float minX = lbox.getMinX() - ( spacingSx / 2f * spacing * getWidth() ); // lbox.getWidth() ); - final float minY = lbox.getMinY() - ( spacingSy / 2f * spacing * getHeight() ); // lbox.getHeight() ); + final float minX = 0; + final float minY = 0; final float minZ = labelZOffset; - shape.addVertex(minX, minY + ch, minZ, true); + shape.addVertex(minX, minY + dC, minZ, true); shape.addVertex(minX, minY, minZ, false); - shape.addVertex(minX + cw, minY, minZ, true); - - shape.addVertex(minX + tw - cw, minY, minZ, true); - shape.addVertex(minX + tw, minY, minZ, false); - shape.addVertex(minX + tw, minY + ch, minZ, true); - shape.addVertex(minX + tw, minY + th- ch, minZ, true); - shape.addVertex(minX + tw, minY + th, minZ, false); - shape.addVertex(minX + tw - cw, minY + th, minZ, true); - shape.addVertex(minX + cw, minY + th, minZ, true); - shape.addVertex(minX, minY + th, minZ, false); - shape.addVertex(minX, minY + th - ch, minZ, true); + shape.addVertex(minX + dC, minY, minZ, true); + + shape.addVertex(minX + tw - dC, minY, minZ, true); + shape.addVertex(minX + tw, minY, minZ, false); + shape.addVertex(minX + tw, minY + dC, minZ, true); + shape.addVertex(minX + tw, minY + th- dC, minZ, true); + shape.addVertex(minX + tw, minY + th, minZ, false); + shape.addVertex(minX + tw - dC, minY + th, minZ, true); + shape.addVertex(minX + dC, minY + th, minZ, true); + shape.addVertex(minX, minY + th, minZ, false); + shape.addVertex(minX, minY + th - dC, minZ, true); + shape.closeLastOutline(true); } + /** Set corner size, default is {@link #DEFAULT_CORNER} */ public void setCorner(float corner) { if(corner > 1.0f){ this.corner = 1.0f; @@ -202,18 +216,28 @@ public class RIButton extends UIShape { this.labelZOffset = -labelZOffset; dirty |= DIRTY_SHAPE | DIRTY_REGION; } - public float getSpacing() { - return spacing; - } + public final float getSpacingX() { return spacingX; } + public final float getSpacingY() { return spacingY; } - /** In percent of text label */ - public void setSpacing(float spacing) { - if ( spacing < 0.0f ) { - this.spacing = 0.0f; - } else if ( spacing > 1.0f ) { - this.spacing = 1.0f; + /** + * In percent of text label + * @param spacingX spacing in percent on X, default is {@link #DEFAULT_SPACING_X} + * @param spacingY spacing in percent on Y, default is {@link #DEFAULT_SPACING_Y} + */ + public void setSpacing(float spacingX, float spacingY) { + if ( spacingX < 0.0f ) { + this.spacingX = 0.0f; + } else if ( spacingX > 1.0f ) { + this.spacingX = 1.0f; + } else { + this.spacingX = spacingX; + } + if ( spacingY < 0.0f ) { + this.spacingY = 0.0f; + } else if ( spacingY > 1.0f ) { + this.spacingY = 1.0f; } else { - this.spacing = spacing; + this.spacingY = spacingY; } dirty |= DIRTY_SHAPE | DIRTY_REGION; } @@ -232,8 +256,8 @@ public class RIButton extends UIShape { @Override public String toString() { - return "RIButton [" + getWidth() + "x" + getHeight() + ", " - + getLabel() + ", " + "spacing: " + spacing - + ", " + "corner: " + corner + ", " + "shapeOffset: " + labelZOffset + " ]"; + return "RIButton [" + translate[0]+getWidth()/2f+" / "+translate[1]+getHeight()/2f+" "+getWidth() + "x" + getHeight() + ", " + + getLabel() + ", " + "spacing: " + spacingX+"/"+spacingY + + ", " + "corner: " + corner + ", " + "shapeOffset: " + labelZOffset + ", "+box+" ]"; } } 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 fbdc72a1f..2dab54277 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 @@ -13,15 +13,18 @@ import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseListener; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Matrix; +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; public class SceneUIController implements GLEventListener{ private final ArrayList<UIShape> shapes = new ArrayList<UIShape>(); - private float sceneStartX = 0f; - private float sceneStartY = 0f; + private final float sceneDist = 1000f; private RegionRenderer renderer; @@ -31,8 +34,8 @@ public class SceneUIController implements GLEventListener{ /** Describing the bounding box in model-coordinates of the near-plane parallel at distance one. */ private final AABBox nearPlane1Box = new AABBox(); private final int[] viewport = new int[] { 0, 0, 0, 0 }; - private float nearPlaneX0, nearPlaneY0, nearPlaneZ0, nearPlaneSx, nearPlaneSy; - float globMvTx, globMvTy, globMvTz; + private final float[] sceneScale = new float[3]; + private final float[] scenePlaneOrigin = new float[3]; private int activeId = -1; @@ -78,7 +81,16 @@ public class SceneUIController implements GLEventListener{ } public int getSampleCount() { return sampleCount[0]; } - public void setSampleCount(int v) { sampleCount[0]=v; } + public void setSampleCount(int v) { sampleCount[0]=v; markAllShapesDirty(); } + + public void markAllShapesDirty() { + for(int i=0; i<shapes.size(); i++) { + shapes.get(i).markDirty(); + } + } + + public final float[] getSceneScale() { return sceneScale; } + public final float[] getScenePlaneOrigin() { return scenePlaneOrigin; } @Override public void init(GLAutoDrawable drawable) { @@ -86,7 +98,7 @@ public class SceneUIController implements GLEventListener{ cDrawable = drawable; } - public int pickShape(final int winX, int winY) { + public int pickShape(final int glWinX, final int glWinY) { final float winZ0 = 0f; final float winZ1 = 0.3f; /** @@ -95,9 +107,6 @@ public class SceneUIController implements GLEventListener{ winZ1 = winZRB.get(0); // dir */ - // flip to GL window coordinates - winY = viewport[3] - winY; - final PMVMatrix pmv = renderer.getMatrix(); pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); @@ -109,13 +118,13 @@ public class SceneUIController implements GLEventListener{ pmv.glPushMatrix(); transformShape(pmv, uiShape); - pmv.gluUnProjectRay(winX, winY, winZ0, winZ1, viewport, 0, ray); - System.err.printf("Pick: mapped.0: [%d, %d, %f/%f] -> %s%n", winX, winY, winZ0, winZ1, ray); + pmv.gluUnProjectRay(glWinX, glWinY, winZ0, winZ1, viewport, 0, ray); + // System.err.printf("Pick: mapped.0: [%d, %d, %f/%f] -> %s%n", winX, winY, winZ0, winZ1, ray); pmv.glPopMatrix(); final AABBox box = shapes.get(i).getBounds(); final boolean hit = box.intersectsRay(ray); - System.err.println("Test: "+box+" -> hit "+hit+", shape: "+uiShape); + // System.err.println("Test: "+box+" -> hit "+hit+", shape: "+uiShape); if( hit ) { return i; } @@ -124,14 +133,35 @@ public class SceneUIController implements GLEventListener{ return -1; } + final Matrix m = new Matrix(); + private void transformShape(final PMVMatrix pmv, final UIShape uiShape) { final float[] uiTranslate = uiShape.getTranslate(); - float[] uiScale = uiShape.getScale(); - // System.err.printf("SceneUICtrl.render.1.0: scale.0: %f, %f, %f%n", uiScale[0], uiScale[1], uiScale[2]); - // System.err.printf("SceneUICtrl.render.1.0: translate.0: %f, %f, %f%n", uiTranslate[0], uiTranslate[1], uiTranslate[2]); - pmv.glRotate(uiShape.getRotation()); - pmv.glScalef(uiScale[0], uiScale[1], uiScale[2]); pmv.glTranslatef(uiTranslate[0], uiTranslate[1], uiTranslate[2]); + // 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); + } } @Override @@ -154,7 +184,6 @@ public class SceneUIController implements GLEventListener{ renderer.updateMatrix(gl); uiShape.drawShape(gl, renderer, sampleCount); pmv.glPopMatrix(); - // break; } } } @@ -173,16 +202,13 @@ public class SceneUIController implements GLEventListener{ pmv.gluUnProject(orthoX, orthoY, winZ[0], view, 0, objPos, 0); } - @Override + @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { viewport[0] = x; viewport[1] = y; viewport[2] = width; viewport[3] = height; - sceneStartX = width * 1f/6f; - sceneStartY = height - height/6f; - final GL2ES2 gl = drawable.getGL().getGL2ES2(); final PMVMatrix pmv = renderer.getMatrix(); renderer.reshapePerspective(gl, 45.0f, width, height, zNear, zFar); @@ -212,24 +238,20 @@ public class SceneUIController implements GLEventListener{ obj11Coord[2] );// hz System.err.printf("Reshape: dist1Box: %s%n", nearPlane1Box); } - final float dist = 100f; - nearPlaneX0 = nearPlane1Box.getMinX() * dist; - nearPlaneY0 = nearPlane1Box.getMinY() * dist; - nearPlaneZ0 = nearPlane1Box.getMinZ() * dist; - final float xd = nearPlane1Box.getWidth() * dist; - final float yd = nearPlane1Box.getHeight() * dist; - nearPlaneSx = xd / width; - nearPlaneSy = yd / height; - System.err.printf("Scale: [%f x %f] / [%d x %d] = [%f, %f]%n", xd, yd, width, height, nearPlaneSx, nearPlaneSy); - - // globMvTx=nearPlaneX0+(sceneStartX*nearPlaneSx); - // globMvTy=nearPlaneY0+(sceneStartY*nearPlaneSy); - globMvTx=nearPlaneX0; - globMvTy=nearPlaneY0; - globMvTz=nearPlaneZ0; - pmv.glTranslatef(globMvTx, globMvTy, globMvTz); - pmv.glScalef(nearPlaneSx, nearPlaneSy, 1f); - pmv.glTranslatef(sceneStartX, sceneStartY, 0f); + scenePlaneOrigin[0] = nearPlane1Box.getMinX() * sceneDist; + scenePlaneOrigin[1] = nearPlane1Box.getMinY() * sceneDist; + scenePlaneOrigin[2] = nearPlane1Box.getMinZ() * sceneDist; + sceneScale[0] = ( nearPlane1Box.getWidth() * sceneDist ) / width; + sceneScale[1] = ( nearPlane1Box.getHeight() * sceneDist ) / height; + sceneScale[2] = 1f; + System.err.printf("Scene Origin [%f, %f, %f]%n", scenePlaneOrigin[0], scenePlaneOrigin[1], scenePlaneOrigin[2]); + System.err.printf("Scene Scale %f * [%f x %f] / [%d x %d] = [%f, %f, %f]%n", + sceneDist, nearPlane1Box.getWidth(), nearPlane1Box.getHeight(), + width, height, + sceneScale[0], sceneScale[1], sceneScale[2]); + + pmv.glTranslatef(scenePlaneOrigin[0], scenePlaneOrigin[1], scenePlaneOrigin[2]); + pmv.glScalef(sceneScale[0], sceneScale[1], sceneScale[2]); renderer.updateMatrix(gl); } @@ -255,7 +277,7 @@ public class SceneUIController implements GLEventListener{ public void mouseClicked(MouseEvent e) { UIShape uiShape = getActiveUI(); if(uiShape != null){ - uiShape.dispatchMouseEvent(e); + uiShape.dispatchMouseEvent(e, e.getX(), viewport[3]-e.getY()); } clear(); release(); @@ -267,18 +289,22 @@ public class SceneUIController implements GLEventListener{ return; } + // flip to GL window coordinates + final int glWinX = e.getX(); + final int glWinY = viewport[3] - e.getY(); + // Avoid race condition w/ matrix instance, // even thought we do not require a GL operation! cDrawable.invoke(true, new GLRunnable() { @Override public boolean run(GLAutoDrawable drawable) { - activeId = pickShape(e.getX(), e.getY()); + activeId = pickShape(glWinX, glWinY); final UIShape uiShape = getActiveUI(); if(uiShape != null) { uiShape.setPressed(true); - uiShape.dispatchMouseEvent(e); + uiShape.dispatchMouseEvent(e, glWinX, glWinY); } - return false; + return true; } } ); } @@ -287,7 +313,7 @@ public class SceneUIController implements GLEventListener{ final UIShape uiShape = getActiveUI(); if(uiShape != null){ uiShape.setPressed(false); - uiShape.dispatchMouseEvent(e); + uiShape.dispatchMouseEvent(e, e.getX(), viewport[3]-e.getY()); } } @@ -295,21 +321,25 @@ public class SceneUIController implements GLEventListener{ public void mouseDragged(MouseEvent e) { final UIShape uiShape = getActiveUI(); if(uiShape != null) { - uiShape.dispatchMouseEvent(e); + uiShape.dispatchMouseEvent(e, e.getX(), viewport[3]-e.getY()); } } @Override public void mouseWheelMoved(final MouseEvent e) { + // flip to GL window coordinates + final int glWinX = lx; + final int glWinY = viewport[3] - ly; + cDrawable.invoke(true, new GLRunnable() { @Override public boolean run(GLAutoDrawable drawable) { - activeId = pickShape(lx, ly); + activeId = pickShape(glWinX, glWinY); final UIShape uiShape = getActiveUI(); if(uiShape != null) { - uiShape.dispatchMouseEvent(e); + uiShape.dispatchMouseEvent(e, glWinX, glWinY); } - return false; + return true; } } ); } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java index ecd22ef71..6c192e37d 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ui/UIListenerBase01.java @@ -258,12 +258,12 @@ public abstract class UIListenerBase01 implements GLEventListener { move(-1, 0); } else if(arg0.getKeyCode() == KeyEvent.VK_4){ - button.setSpacing(button.getSpacing()-0.01f); - System.err.println("Button Spacing: " + button.getSpacing()); + button.setSpacing(button.getSpacingX()-0.01f, button.getSpacingY()-0.005f); + System.err.println("Button Spacing: " + button.getSpacingX()); } else if(arg0.getKeyCode() == KeyEvent.VK_5){ - button.setSpacing(button.getSpacing()+0.01f); - System.err.println("Button Spacing: " + button.getSpacing()); + button.setSpacing(button.getSpacingX()+0.01f, button.getSpacingY()+0.005f); + System.err.println("Button Spacing: " + button.getSpacingX()); } else if(arg0.getKeyCode() == KeyEvent.VK_6){ button.setCorner(button.getCorner()-0.01f); 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 638e4465b..58c237e8c 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 @@ -42,9 +42,11 @@ import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.curve.opengl.RenderState; import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.newt.event.NEWTEvent; import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.MouseListener; import com.jogamp.opengl.math.Quaternion; +import com.jogamp.opengl.math.VectorUtil; import com.jogamp.opengl.math.geom.AABBox; public abstract class UIShape { @@ -61,6 +63,7 @@ public abstract class UIShape { protected final AABBox box; protected final float[] translate = new float[] { 0f, 0f, 0f }; protected final Quaternion rotation = new Quaternion(); + protected final float[] rotOrigin = new float[] { 0f, 0f, 0f }; protected final float[] scale = new float[] { 1f, 1f, 1f }; protected final float[] shapeTranslate2D = new float[] { 0f, 0f }; @@ -99,6 +102,9 @@ public abstract class UIShape { translate[1] = 0f; translate[2] = 0f; rotation.setIdentity(); + rotOrigin[0] = 0f; + rotOrigin[1] = 0f; + rotOrigin[2] = 0f; scale[0] = 1f; scale[1] = 1f; scale[2] = 1f; @@ -122,6 +128,9 @@ public abstract class UIShape { translate[1] = 0f; translate[2] = 0f; rotation.setIdentity(); + rotOrigin[0] = 0f; + rotOrigin[1] = 0f; + rotOrigin[2] = 0f; scale[0] = 1f; scale[1] = 1f; scale[2] = 1f; @@ -133,24 +142,32 @@ public abstract class UIShape { dirty = DIRTY_SHAPE | DIRTY_REGION; } - public final void setTranslate(float tx, float ty, float tz) { + public void setTranslate(float tx, float ty, float tz) { translate[0] = tx; translate[1] = ty; translate[2] = tz; + // System.err.println("UIShape.setTranslate: "+tx+"/"+ty+"/"+tz+": "+toString()); } - public final void translate(float tx, float ty, float tz) { + public void translate(float tx, float ty, float tz) { translate[0] += tx; translate[1] += ty; translate[2] += tz; + // System.err.println("UIShape.translate: "+tx+"/"+ty+"/"+tz+": "+toString()); } public final float[] getTranslate() { return translate; } public final Quaternion getRotation() { return rotation; } - public final void setScale(float sx, float sy, float sz) { + public final float[] getRotationOrigin() { return rotOrigin; } + public void setRotationOrigin(float rx, float ry, float rz) { + rotOrigin[0] = rx; + rotOrigin[1] = ry; + rotOrigin[2] = rz; + } + public void setScale(float sx, float sy, float sz) { scale[0] = sx; scale[1] = sy; scale[2] = sz; } - public final void scale(float sx, float sy, float sz) { + public void scale(float sx, float sy, float sz) { scale[0] *= sx; scale[1] *= sy; scale[2] *= sz; @@ -166,6 +183,9 @@ public abstract class UIShape { shapeScale2D[1] *= sy; } + public final void markDirty() { + dirty = DIRTY_SHAPE | DIRTY_REGION; + } public final boolean isShapeDirty() { return 0 != ( dirty & DIRTY_SHAPE ) ; } @@ -204,7 +224,7 @@ public abstract class UIShape { */ public void drawShape(GL2ES2 gl, RegionRenderer renderer, int[] sampleCount) { final float[] _color; - if( isPressed() || toggle ){ + if( isPressed() || toggle ) { _color = selectedColor; } else { _color = color; @@ -230,9 +250,9 @@ public abstract class UIShape { } dirty &= ~DIRTY_SHAPE; dirty |= DIRTY_REGION; - return true; + return false; } - return false; + return true; } private final void addToRegion(Region region) { @@ -285,7 +305,7 @@ public abstract class UIShape { } public String toString() { - return getClass().getSimpleName()+"[enabled "+enabled+", box "+box+"]"; + return getClass().getSimpleName()+"[enabled "+enabled+", "+translate[0]+" / "+translate[1]+", box "+box+"]"; } // @@ -331,8 +351,57 @@ public abstract class UIShape { mouseListeners = clonedListeners; } - public final void dispatchMouseEvent(MouseEvent e) { - e.setAttachment(this); + /** + * {@link UIShape} event details for propagated {@link NEWTEvent}s + * containing reference of {@link #shape the intended shape} as well as + * the {@link #rotPosition rotated relative position} and {@link #rotBounds bounding box}. + * The latter fields are also normalized to lower-left zero origin, allowing easier usage. + */ + public static class EventDetails { + /** The intended {@link UIShape} instance for this event */ + public final UIShape shape; + /** The {@link AABBox} of the intended {@link UIShape}, rotated about {@link UIShape#getRotation()} and normalized to lower-left zero origin.*/ + public final AABBox rotBounds; + /** The relative mouse pointer position inside the intended {@link UIShape}, rotated about {@link UIShape#getRotation()} and normalized to lower-left zero origin. */ + public final float[] rotPosition; + + EventDetails(final UIShape shape, final AABBox rotatedBounds, final float[] rotatedRelPos) { + this.shape = shape; + this.rotBounds = rotatedBounds; + this.rotPosition = rotatedRelPos; + } + + public String toString() { + return "EventDetails[pos "+rotPosition[0]+", "+rotPosition[1]+", "+rotPosition[2]+ + ", "+rotBounds+", "+shape+"]"; + } + } + + /** + * + * @param e original Newt {@link MouseEvent} + * @param glX x-position in OpenGL model space + * @param glY x-position in OpenGL model space + */ + public final void dispatchMouseEvent(final MouseEvent e, final int glX, final int glY) { + // rotate bounding box and normalize to 0/0 + final Quaternion rot = getRotation(); + final float[] bLow = new float[3]; + VectorUtil.copyVec3(bLow, 0, getBounds().getLow(), 0); + VectorUtil.scaleVec3(bLow, bLow, -1f); + final AABBox rbox = new AABBox(getBounds()); + rbox.translate(bLow); + rbox.rotate(rot); + + // get unrotated relative position within shape, rotate and normalize to 0/0 + final float[] relPos = new float[] { glX, glY, 0f }; + VectorUtil.subVec3(relPos, relPos, getTranslate()); + VectorUtil.addVec3(relPos, relPos, bLow); + rot.rotateVector(relPos, 0, relPos, 0); + + // set as attachment + e.setAttachment(new EventDetails(this, rbox, relPos)); + for(int i = 0; !e.isConsumed() && i < mouseListeners.size(); i++ ) { final MouseListener l = mouseListeners.get(i); switch(e.getEventType()) { @@ -346,9 +415,11 @@ public abstract class UIShape { l.mouseExited(e); break; case MouseEvent.EVENT_MOUSE_PRESSED: + markDirty(); l.mousePressed(e); break; case MouseEvent.EVENT_MOUSE_RELEASED: + markDirty(); l.mouseReleased(e); break; case MouseEvent.EVENT_MOUSE_MOVED: @@ -386,6 +457,7 @@ public abstract class UIShape { final float minY = box.getMinY(); final float z = 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); |