diff options
author | Sven Gothel <[email protected]> | 2023-03-28 04:41:10 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-03-28 04:41:10 +0200 |
commit | 55b552bb87fb1fefcf53dd7784a53d605969de96 (patch) | |
tree | a470a11d7327637202a6cbefdd564e96182e8c04 | |
parent | 34632c59b5f664c41ef52a4abb9e3e1b484657d4 (diff) |
GraphUI: Decouple GraphShape from Shape, i.e. allow future Shape w/o Graph/GLRegion
19 files changed, 469 insertions, 305 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 66a960869..69ff56d40 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -955,6 +955,7 @@ function testawtswt() { # # Graph # +#testnoawt com.jogamp.opengl.test.junit.graph.TestFontScale01NOUI $* #testnoawt com.jogamp.opengl.test.junit.graph.TestRegionRendererNEWT01 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestFontsNEWT00 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWTBugXXXX $* @@ -1011,10 +1012,11 @@ function testawtswt() { #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo00 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01 $* +#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo01b $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo02 $* -testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $* +#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo10 $* -#testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo20 $* +testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo20 $* #testnoawt com.jogamp.opengl.demos.av.MovieCube $* #testnoawt com.jogamp.opengl.demos.av.MovieSimple $* diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java index 433521933..82f09a38a 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java @@ -45,6 +45,7 @@ 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.ui.gl.GraphShape; import com.jogamp.graph.ui.gl.Scene; import com.jogamp.graph.ui.gl.Scene.PMVMatrixSetup; import com.jogamp.graph.ui.gl.Shape; @@ -264,6 +265,7 @@ public class UISceneDemo20 implements GLEventListener { private int renderModes; private final Font font; + private final Font fontButtons; private final Font fontFPS; private final Uri filmURL; @@ -363,7 +365,9 @@ public class UISceneDemo20 implements GLEventListener { } System.err.println("Font "+font.getFullFamilyName()); - fontFPS = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMonoBold.ttf", + fontButtons = FontFactory.get(FontFactory.UBUNTU).getDefault(); + + fontFPS = FontFactory.get(IOUtil.getResource("fonts/freefont/FreeMono.ttf", FontSetDemos.class.getClassLoader(), FontSetDemos.class).getInputStream(), true); System.err.println("Font FPS "+fontFPS.getFullFamilyName()); @@ -389,11 +393,6 @@ public class UISceneDemo20 implements GLEventListener { buttons.get(i).getRotation().rotateByEuler( angdeg ); } } - private void translateButtons(final float tx, final float ty, final float tz) { - for(int i=0; i<buttons.size(); i++) { - buttons.get(i).move(tx, ty, tz); - } - } private void setButtonsSpacing(final float dx, final float dy) { for(int i=0; i<buttons.size(); i++) { @@ -445,14 +444,14 @@ public class UISceneDemo20 implements GLEventListener { final float buttonYSize = buttonXSize / 2.5f; final float button2XSize = 2f*buttonXSize; final float button2YSize = 2f*buttonYSize; - System.err.println("Button Size: scale "+scale+", "+buttonXSize+" x "+buttonYSize); + System.err.println("Button Size: "+buttonXSize+" x "+buttonYSize+", scale "+scale); final float xStartLeft = 0f; // aligned to left edge w/ space via reshape final float xStartRight = -button2XSize - button2XSize/8f; // aligned to right edge via reshape final float yStartTop = 0f; // aligned to top edge w/ space via reshape final float diffX = 1.2f * buttonXSize; final float diffY = 1.5f * buttonYSize; - Button button = new Button(renderModes, font, "Next Text", buttonXSize, buttonYSize); + Button button = new Button(renderModes, fontButtons, " Next Text ", buttonXSize, buttonYSize); button.setName(BUTTON_NEXTTEXT); button.move(xStartLeft, yStartTop-diffY*buttons.size(), 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @@ -469,7 +468,7 @@ public class UISceneDemo20 implements GLEventListener { button.addMouseListener(dragZoomRotateListener); buttons.add(button); - button = new Button(renderModes, font, "Show FPS", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "Show fps", buttonXSize, buttonYSize); button.setName(BUTTON_FPS); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setToggleable(true); @@ -486,7 +485,7 @@ public class UISceneDemo20 implements GLEventListener { button.addMouseListener(dragZoomRotateListener); buttons.add(button); - button = new Button(renderModes, font, "V-Sync", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, " V-Sync ", buttonXSize, buttonYSize); button.setName(BUTTON_VSYNC); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setToggleable(true); @@ -510,7 +509,7 @@ public class UISceneDemo20 implements GLEventListener { button.addMouseListener(dragZoomRotateListener); buttons.add(button); - button = new Button(renderModes, font, "< Tilt >", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "< Tilt >", buttonXSize, buttonYSize); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -529,7 +528,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); if( pass2Mode ) { // second column to the left - button = new Button(renderModes, font, "< Samples >", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "< Samples >", buttonXSize, buttonYSize); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -548,32 +547,34 @@ public class UISceneDemo20 implements GLEventListener { button.addMouseListener(dragZoomRotateListener); buttons.add(button); - button = new Button(renderModes, font, "< Quality >", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "< Quality >", buttonXSize, buttonYSize); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override public void mouseClicked(final MouseEvent e) { final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); - int quality = shapeEvent.shape.getQuality(); + if( shapeEvent.shape instanceof GraphShape ) { + int quality = ((GraphShape)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++; + 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++; + } } + scene.setAllShapesQuality(quality); } - scene.setAllShapesQuality(quality); } } ); button.addMouseListener(dragZoomRotateListener); buttons.add(button); } - button = new Button(renderModes, font, "Quit", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "Quit", buttonXSize, buttonYSize); button.setName(BUTTON_QUIT); button.move(xStartLeft,yStartTop - diffY*buttons.size(), 0f); button.setColor(0.7f, 0.0f, 0.0f, 1.0f); @@ -601,7 +602,7 @@ public class UISceneDemo20 implements GLEventListener { { final int j = 1; // column int k = 0; // row - button = new Button(renderModes, font, "Y Flip", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "Y Flip", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -612,7 +613,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); k++; - button = new Button(renderModes, font, "X Flip", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "X Flip", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -623,7 +624,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); k++; - button = new Button(renderModes, font, "< Space >", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "< Space >", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -644,7 +645,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); k++; - button = new Button(renderModes, font, "< Corner >", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, "< Corner >", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -665,7 +666,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); k++; - button = new Button(renderModes, font, "Reset", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, " Reset ", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -676,7 +677,7 @@ public class UISceneDemo20 implements GLEventListener { buttons.add(button); k++; - button = new Button(renderModes, font, "Snapshot", buttonXSize, buttonYSize); + button = new Button(renderModes, fontButtons, " Snapshot ", buttonXSize, buttonYSize); button.move(xStartLeft - diffX*j,yStartTop - diffY*k, 0f); button.addMouseListener(new Shape.MouseGestureAdapter() { @Override @@ -727,8 +728,7 @@ public class UISceneDemo20 implements GLEventListener { } if( true ) { final ImageSequence imgSeq = new ImageSequence(texUnitImageButton, true); - final ImageButton imgButton = new ImageButton(renderModes, button2XSize, - button2YSize, imgSeq); + final ImageButton imgButton = new ImageButton(renderModes, button2XSize, button2YSize, imgSeq); try { imgSeq.addFrame(gl, UISceneDemo20.class, "button-released-145x53.png", TextureIO.PNG); imgSeq.addFrame(gl, UISceneDemo20.class, "button-pressed-145x53.png", TextureIO.PNG); @@ -777,9 +777,8 @@ public class UISceneDemo20 implements GLEventListener { System.err.println("Gears Anim: End"); } }).start(); - final GLButton b = new GLButton(renderModes, button2XSize, - button2YSize, texUnitGLELButton, - gears, false /* useAlpha */); + final GLButton b = new GLButton(renderModes, button2XSize, button2YSize, + texUnitGLELButton, gears, false /* useAlpha */); b.setName(BUTTON_GLEL); b.setToggleable(true); b.setToggle(false); // toggle == true -> animation @@ -833,44 +832,27 @@ public class UISceneDemo20 implements GLEventListener { private static final boolean enableOthers = true; - private void setupUI(final GLAutoDrawable drawable, final AABBox sceneBox) { - final float[/*2*/] sceneSize = { 0f, 0f }; - scene.surfaceToPlaneSize(new int[] { 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight()}, sceneSize); - - final float modelSizeFixed = fontSizeFixedNorm * sceneSize[1]; - jogampLabel = new Label(renderModes, font, modelSizeFixed, jogamp); + private void initLabels(final GL2ES2 gl) { + jogampLabel = new Label(renderModes, font, fontSizeFixedNorm, jogamp); jogampLabel.addMouseListener(dragZoomRotateListener); - scene.addShape(jogampLabel); jogampLabel.setEnabled(enableOthers); + scene.addShape(jogampLabel); - final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); - final float modelSize10Pt = pixelSize10Pt / drawable.getSurfaceHeight() * sceneSize[1]; - System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" ppi -> "+pixelSize10Pt+" pixe-size, "+modelSize10Pt+" model-size"); - truePtSizeLabel = new Label(renderModes, font, modelSize10Pt, truePtSize); - scene.addShape(truePtSizeLabel); + truePtSizeLabel = new Label(renderModes, font, truePtSize); truePtSizeLabel.setEnabled(enableOthers); - truePtSizeLabel.move(0, - 1.5f * jogampLabel.getLineHeight(), 0f); truePtSizeLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); + scene.addShape(truePtSizeLabel); /** * * [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 = fontSizeFpsNorm * drawable.getSurfaceHeight(); - final float modelSizeFPS = pixelSizeFPS / drawable.getSurfaceHeight() * sceneSize[1]; - fpsLabel = new Label(renderModes, fontFPS, modelSizeFPS, "Nothing there yet"); + fpsLabel = new Label(renderModes, fontFPS, "Nothing there yet"); fpsLabel.addMouseListener(dragZoomRotateListener); - scene.addShape(fpsLabel); fpsLabel.setEnabled(enableOthers); fpsLabel.setColor(0.1f, 0.1f, 0.1f, 1.0f); - fpsLabel.move(0f, modelSizeFPS * (fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent()), 0f); - - final float sx = sceneBox.getWidth(); - final float sy = sceneBox.getHeight(); - final float sxy = sx > sy ? sx : sy; - initButtons(drawable.getGL().getGL2ES2(), sxy); - scene.addShapes(buttons); + scene.addShape(fpsLabel); } @Override @@ -920,6 +902,7 @@ public class UISceneDemo20 implements GLEventListener { gl.glEnable(GL.GL_BLEND); initTexts(); + initLabels(gl); scene.init(drawable); @@ -937,20 +920,24 @@ public class UISceneDemo20 implements GLEventListener { // Layout all shapes: Relational move regarding object coordinates // System.err.println("Reshape: Scene Plane.0 "+scene.getBounds()); - final float lastWidth = scene.getBounds().getWidth(); - final float lastHeight = scene.getBounds().getHeight(); - System.err.println("Reshape: Scene Plane.0 "+lastWidth+" x "+lastHeight); + final float lastSceneWidth = scene.getBounds().getWidth(); + final float lastSceneHeight = scene.getBounds().getHeight(); + System.err.println("Reshape: Scene Plane.0 "+lastSceneWidth+" x "+lastSceneHeight); scene.reshape(drawable, x, y, width, height); final AABBox sceneBox = scene.getBounds(); System.err.println("Reshape: Scene Plane.1 "+sceneBox); - if( scene.getShapes().isEmpty() ) { - setupUI(drawable, sceneBox); + final float sceneWidth = sceneBox.getWidth(); + final float sceneHeight = sceneBox.getHeight(); + final float button_sxy = sceneWidth > sceneHeight ? sceneWidth : sceneHeight; + if( buttons.isEmpty() ) { + initButtons(drawable.getGL().getGL2ES2(), button_sxy); + scene.addShapes(buttons); } - final float dw = sceneBox.getWidth() - lastWidth; - final float dh = sceneBox.getHeight() - lastHeight; + final float dw = sceneWidth - lastSceneWidth; + final float dh = sceneHeight - lastSceneHeight; final float dz = 0f; final float dyTop = dh * relTop; @@ -970,16 +957,33 @@ public class UISceneDemo20 implements GLEventListener { // System.err.println("Button["+i+"].RM: "+buttons.get(i)); } - final float dxMiddleAbs = sceneBox.getWidth() * relMiddle; - final float dyTopLabelAbs = sceneBox.getHeight() - 2f*jogampLabel.getLineHeight(); - jogampLabel.moveTo(dxMiddleAbs, dyTopLabelAbs, dz); - truePtSizeLabel.moveTo(dxMiddleAbs, dyTopLabelAbs, dz); - truePtSizeLabel.moveTo(dxMiddleAbs, dyTopLabelAbs - 1.5f * jogampLabel.getLineHeight(), 0f); - fpsLabel.move(0f, 0f, 0f); + jogampLabel.setScale(sceneHeight, sceneHeight, 1f); + + final float dxMiddleAbs = sceneWidth * relMiddle; + final float dyTopLabelAbs = sceneHeight - jogampLabel.getScaledLineHeight(); + jogampLabel.moveTo(dxMiddleAbs, dyTopLabelAbs - jogampLabel.getScaledLineHeight(), dz); + { + final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); + final float scale = pixelSize10Pt / height * sceneHeight; // normalize with dpi / surfaceHeight + System.err.println("10Pt PixelSize: Display "+dpiV+" dpi, fontSize "+fontSizePt+" pt, "+FontScale.ptToMM(fontSizePt)+" mm -> "+pixelSize10Pt+" pixels, "+scale+" scene-size"); + truePtSizeLabel.setScale(scale, scale, 1f); + truePtSizeLabel.moveTo(dxMiddleAbs, dyTopLabelAbs - jogampLabel.getScaledLineHeight() - truePtSizeLabel.getScaledLineHeight(), dz); + } + { + final AABBox fbox = fontFPS.getGlyphBounds(scene.getStatusText(drawable, renderModes, fpsLabel.getQuality(), dpiV)); + final float scale = sceneWidth / ( 1.4f * fbox.getWidth() ); // add 40% width + fpsLabel.setScale(scale, scale, 1f); + fpsLabel.moveTo(sceneBox.getMinX(), sceneBox.getMinY() + scale * ( fontFPS.getMetrics().getLineGap() - fontFPS.getMetrics().getDescent() ), 0f); + fpsLabel.validate(drawable.getGL().getGL2ES2()); + System.err.println("StatusLabel Scale: " + scale + " = " + sceneWidth + " / " + fbox.getWidth() + ", " + fbox); + System.err.println("StatusLabel: " + fpsLabel); + } if( null != labels[currentText] ) { + labels[currentText].setScale(sceneHeight, sceneHeight, 1f); labels[currentText].moveTo(dxMiddleAbs, - dyTopLabelAbs - 1.5f * jogampLabel.getLineHeight() - - 1.5f * truePtSizeLabel.getLineHeight(), 0f); + dyTopLabelAbs - jogampLabel.getScaledLineHeight() + - 1.5f * truePtSizeLabel.getScaledLineHeight() + - labels[currentText].getScaledHeight(), 0f); System.err.println("Label["+currentText+"] MOVE: "+labels[currentText]); System.err.println("Label["+currentText+"] MOVE: "+Arrays.toString(labels[currentText].getPosition())); } @@ -1017,15 +1021,19 @@ public class UISceneDemo20 implements GLEventListener { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); if(null == labels[currentText]) { - final float pixelSizeFixed = fontSizeFixedNorm * scene.getBounds().getHeight(); - final float dyTop = scene.getBounds().getHeight() - 2f*jogampLabel.getLineHeight(); - final float dxMiddle = scene.getBounds().getWidth() * relMiddle; - labels[currentText] = new Label(renderModes, font, pixelSizeFixed, strings[currentText]); + final AABBox sbox = scene.getBounds(); + final float sceneHeight = sbox.getHeight(); + final float dyTop = sbox.getHeight() - jogampLabel.getScaledLineHeight(); + final float dxMiddle = sbox.getWidth() * relMiddle; + labels[currentText] = new Label(renderModes, font, fontSizeFixedNorm, strings[currentText]); + labels[currentText].setScale(sceneHeight, sceneHeight, 1f); labels[currentText].setColor(0.1f, 0.1f, 0.1f, 1.0f); labels[currentText].setEnabled(enableOthers); + labels[currentText].validate(gl); labels[currentText].move(dxMiddle, - dyTop - 1.5f * jogampLabel.getLineHeight() - - 1.5f * truePtSizeLabel.getLineHeight(), 0f); + dyTop - jogampLabel.getScaledLineHeight() + - 1.5f * truePtSizeLabel.getScaledLineHeight() + - labels[currentText].getScaledHeight(), 0f); labels[currentText].addMouseListener(dragZoomRotateListener); scene.addShape(labels[currentText]); System.err.println("Label["+currentText+"] CTOR: "+labels[currentText]); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java index f467b7a9d..6d6b69063 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph01UbuntuLight_o.java @@ -29,14 +29,14 @@ package com.jogamp.opengl.demos.graph.ui.testshapes; import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.geom.plane.Winding; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** * GPU based resolution independent test object * - Ubuntu-Light, lower case 'o' * - TTF Shape for Glyph 82 */ -public class Glyph01UbuntuLight_o extends Shape { +public class Glyph01UbuntuLight_o extends GraphShape { public Glyph01UbuntuLight_o(final int renderModes) { super(renderModes); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java index 92284060f..2ee21a9f6 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph02UbuntuLight_ae.java @@ -28,14 +28,14 @@ package com.jogamp.opengl.demos.graph.ui.testshapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** * GPU based resolution independent test object * - Ubuntu-Light, lower case 'æ' * - TTF Shape for Glyph 193 */ -public class Glyph02UbuntuLight_ae extends Shape { +public class Glyph02UbuntuLight_ae extends GraphShape { public Glyph02UbuntuLight_ae(final int renderModes) { super(renderModes); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java index 266d96c93..8d8fd2133 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph03FreeMonoRegular_M.java @@ -28,14 +28,14 @@ package com.jogamp.opengl.demos.graph.ui.testshapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** * GPU based resolution independent test object * - FreeMono-Regular, capital case 'M' * - TTF Shape for Glyph 48 */ -public class Glyph03FreeMonoRegular_M extends Shape { +public class Glyph03FreeMonoRegular_M extends GraphShape { public Glyph03FreeMonoRegular_M(final int renderModes) { super(renderModes); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java index 4f89d14f1..8bab9d5c7 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph04FreeSans_0.java @@ -28,14 +28,14 @@ package com.jogamp.opengl.demos.graph.ui.testshapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** * GPU based resolution independent test object * - FreeSans, '0' * - TTF Shape for Glyph 19 */ -public class Glyph04FreeSans_0 extends Shape { +public class Glyph04FreeSans_0 extends GraphShape { public Glyph04FreeSans_0(final int renderModes) { super(renderModes); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java index 726565129..ed461d0b8 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/testshapes/Glyph05FreeSerifBoldItalic_ae.java @@ -28,14 +28,14 @@ package com.jogamp.opengl.demos.graph.ui.testshapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** * GPU based resolution independent test object * - FreeSans, '0' * - TTF Shape for Glyph 19 */ -public class Glyph05FreeSerifBoldItalic_ae extends Shape { +public class Glyph05FreeSerifBoldItalic_ae extends GraphShape { public Glyph05FreeSerifBoldItalic_ae(final int renderModes) { super(renderModes); diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java new file mode 100644 index 000000000..85037ccd4 --- /dev/null +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/GraphShape.java @@ -0,0 +1,179 @@ +/** + * 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.graph.ui.gl; + +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.opengl.GLRegion; +import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.Vertex.Factory; +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.geom.AABBox; + +/** + * Graph based {@link GLRegion} UI {@link Shape} + * <p> + * GraphUI is GPU based and resolution independent. + * </p> + * <p> + * GraphUI is intended to become an immediate- and retained-mode API. + * </p> + * @see Scene + */ +public abstract class GraphShape extends Shape { + protected final Factory<? extends Vertex> vertexFactory; + + protected final int renderModes; + protected GLRegion region = null; + protected float oshapeSharpness = OutlineShape.DEFAULT_SHARPNESS; + private int regionQuality = Region.MAX_QUALITY; + private final List<GLRegion> dirtyRegions = new ArrayList<GLRegion>(); + + public GraphShape(final int renderModes) { + super(); + this.vertexFactory = OutlineShape.getDefaultVertexFactory(); + this.renderModes = renderModes; + } + + public final int getRenderModes() { return renderModes; } + + public final int getQuality() { return regionQuality; } + public final void setQuality(final int q) { + this.regionQuality = q; + if( null != region ) { + region.setQuality(q); + } + } + public final void setSharpness(final float sharpness) { + this.oshapeSharpness = sharpness; + markShapeDirty(); + } + public final float getSharpness() { + return oshapeSharpness; + } + + @Override + public boolean hasColorChannel() { + return Region.hasColorChannel(renderModes) || Region.hasColorTexture(renderModes); + } + + private final void clearDirtyRegions(final GL2ES2 gl) { + for(final GLRegion r : dirtyRegions) { + r.destroy(gl); + } + dirtyRegions.clear(); + } + + @Override + protected final void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer) { + clearImpl(gl, renderer); + clearDirtyRegions(gl); + if( null != region ) { + region.clear(gl); + } + } + + @Override + protected final void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer) { + destroyImpl(gl, renderer); + clearDirtyRegions(gl); + if( null != region ) { + region.destroy(gl); + region = null; + } + } + + @Override + protected final void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, final float[] rgba) { + if( null != rgba ) { + renderer.getRenderState().setColorStatic(rgba); + } + region.draw(gl, renderer, sampleCount); + } + + protected GLRegion createGLRegion(final GLProfile glp) { + return GLRegion.create(glp, renderModes, null); + } + + @Override + protected final void validateImpl(final GLProfile glp, final GL2ES2 gl) { + if( null != gl ) { + clearDirtyRegions(gl); + } + if( isShapeDirty() || null == region ) { + if( null == region ) { + region = createGLRegion(glp); + } else if( null == gl ) { + dirtyRegions.add(region); + region = createGLRegion(glp); + } else { + region.clear(gl); + } + addShapeToRegion(); + region.setQuality(regionQuality); + } else if( isStateDirty() ) { + region.markStateDirty(); + } + } + + protected OutlineShape createDebugOutline(final OutlineShape shape, final AABBox box) { + final float d = 0.025f; + final float tw = box.getWidth() + d*2f; + final float th = box.getHeight() + d*2f; + + final float minX = box.getMinX() - d; + final float minY = box.getMinY() - d; + final float z = 0; // box.getMinZ() + 0.025f; + + // CCW! + shape.moveTo(minX, minY, z); + shape.lineTo(minX+tw, minY, z); + shape.lineTo(minX+tw, minY + th, z); + shape.lineTo(minX, minY + th, z); + shape.closePath(); + + // shape.addVertex(minX, minY, z, true); + // shape.addVertex(minX+tw, minY, z, true); + // shape.addVertex(minX+tw, minY + th, z, true); + // shape.addVertex(minX, minY + th, z, true); + // shape.closeLastOutline(true); + + return shape; + } + + protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + + protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + + +} diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java index e40152a02..16f695a2f 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/Scene.java @@ -246,12 +246,18 @@ public final class Scene implements GLEventListener { public void setAllShapesQuality(final int q) { for(int i=0; i<shapes.size(); i++) { - shapes.get(i).setQuality(q); + final Shape shape = shapes.get(i); + if( shape instanceof GraphShape ) { + ((GraphShape)shape).setQuality(q); + } } } public void setAllShapesSharpness(final float sharpness) { for(int i=0; i<shapes.size(); i++) { - shapes.get(i).setSharpness(sharpness); + final Shape shape = shapes.get(i); + if( shape instanceof GraphShape ) { + ((GraphShape)shape).setSharpness(sharpness); + } } } public void markAllShapesDirty() { @@ -351,7 +357,7 @@ public final class Scene implements GLEventListener { // FIXME // System.err.printf("drawGL: color %f, index %d of [0..%d[%n", color, i, shapeCount); renderer.getRenderState().setColorStatic(color, color, color, 1f); - shape.drawGLSelect(gl, renderer, sampleCount0); + shape.drawToSelect(gl, renderer, sampleCount0); } else { shape.draw(gl, renderer, sampleCount0); } diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java index 9a91b7649..94fc471f2 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java @@ -28,19 +28,12 @@ package com.jogamp.graph.ui.gl; import java.util.ArrayList; -import java.util.List; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.curve.Region; -import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Vertex.Factory; -import com.jogamp.graph.geom.plane.AffineTransform; import com.jogamp.newt.event.GestureHandler.GestureEvent; import com.jogamp.newt.event.GestureHandler.GestureListener; import com.jogamp.newt.event.MouseAdapter; @@ -55,13 +48,16 @@ import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.util.PMVMatrix; /** - * GraphUI Shape + * Generic UI Shape, potentially using a Graph via {@link GraphShape} or other means of representing content. * <p> * A shape includes the following build-in user-interactions * - drag shape w/ 1-pointer click, see {@link #setDraggable(boolean)} * - resize shape w/ 1-pointer click and drag in 1/4th bottom-left and bottom-right corner, see {@link #setResizable(boolean)}. * </p> * <p> + * A shape is expected to have its 0/0 origin in its bottom-left corner, otherwise the drag-zoom sticky-edge will not work as expected. + * </p> + * <p> * GraphUI is GPU based and resolution independent. * </p> * <p> @@ -79,25 +75,13 @@ public abstract class Shape { private static final int DIRTY_SHAPE = 1 << 0 ; private static final int DIRTY_STATE = 1 << 1 ; - protected final Factory<? extends Vertex> vertexFactory; - private final int renderModes; protected final AABBox box; - protected final AffineTransform tempT1 = new AffineTransform(); - protected final AffineTransform tempT2 = new AffineTransform(); - protected final AffineTransform tempT3 = new AffineTransform(); - protected final AffineTransform tempT4 = new AffineTransform(); - private final float[] position = new float[] { 0f, 0f, 0f }; private final Quaternion rotation = new Quaternion(); private final float[] rotOrigin = new float[] { 0f, 0f, 0f }; private final float[] scale = new float[] { 1f, 1f, 1f }; - protected GLRegion region = null; - protected float oshapeSharpness = OutlineShape.DEFAULT_SHARPNESS; - private int regionQuality = Region.MAX_QUALITY; - private final List<GLRegion> dirtyRegions = new ArrayList<GLRegion>(); - private volatile int dirty = DIRTY_SHAPE | DIRTY_STATE; private final Object dirtySync = new Object(); @@ -122,9 +106,7 @@ public abstract class Shape { private Listener onMoveListener = null; - public Shape(final int renderModes) { - this.vertexFactory = OutlineShape.getDefaultVertexFactory(); - this.renderModes = renderModes; + public Shape() { this.box = new AABBox(); } @@ -138,36 +120,27 @@ public abstract class Shape { /** Enable or disable this shape, i.e. its visibility. */ public final void setEnabled(final boolean v) { enabled = v; } - private final void clearDirtyRegions(final GL2ES2 gl) { - for(final GLRegion r : dirtyRegions) { - r.destroy(gl); - } - dirtyRegions.clear(); - } - /** * Clears all data and reset all states as if this instance was newly created * @param gl TODO * @param renderer TODO */ public final void clear(final GL2ES2 gl, final RegionRenderer renderer) { - clearImpl(gl, renderer); - clearDirtyRegions(gl); - if( null != region ) { - region.clear(gl); + synchronized ( dirtySync ) { + clearImpl0(gl, renderer); + position[0] = 0f; + position[1] = 0f; + position[2] = 0f; + rotation.setIdentity(); + rotOrigin[0] = 0f; + rotOrigin[1] = 0f; + rotOrigin[2] = 0f; + scale[0] = 1f; + scale[1] = 1f; + scale[2] = 1f; + box.reset(); + markShapeDirty(); } - position[0] = 0f; - position[1] = 0f; - position[2] = 0f; - rotation.setIdentity(); - rotOrigin[0] = 0f; - rotOrigin[1] = 0f; - rotOrigin[2] = 0f; - scale[0] = 1f; - scale[1] = 1f; - scale[2] = 1f; - box.reset(); - markShapeDirty(); } /** @@ -176,12 +149,7 @@ public abstract class Shape { * @param renderer */ public final void destroy(final GL2ES2 gl, final RegionRenderer renderer) { - destroyImpl(gl, renderer); - clearDirtyRegions(gl); - if( null != region ) { - region.destroy(gl); - region = null; - } + destroyImpl0(gl, renderer); position[0] = 0f; position[1] = 0f; position[2] = 0f; @@ -198,6 +166,7 @@ public abstract class Shape { public final void onMove(final Listener l) { onMoveListener = l; } + /** Move to scaled position. Position ends up in PMVMatrix w/o scaling. */ public final void moveTo(final float tx, final float ty, final float tz) { position[0] = tx; position[1] = ty; @@ -207,40 +176,58 @@ public abstract class Shape { } // System.err.println("Shape.setTranslate: "+tx+"/"+ty+"/"+tz+": "+toString()); } - public final void move(final float tx, final float ty, final float tz) { - position[0] += tx; - position[1] += ty; - position[2] += tz; + + /** Move about scaled distance. Position ends up in PMVMatrix w/o scaling. */ + public final void move(final float dtx, final float dty, final float dtz) { + position[0] += dtx; + position[1] += dty; + position[2] += dtz; if( null != onMoveListener ) { onMoveListener.run(this); } // System.err.println("Shape.translate: "+tx+"/"+ty+"/"+tz+": "+toString()); } - /** Returns float[3] position, i.e. translation. */ + /** Returns float[3] position, i.e. unscaled translation. */ public final float[] getPosition() { return position; } - /** Returns float[3] rotation in degrees. */ + + /** Returns {@link Quaternion} for rotation. */ public final Quaternion getRotation() { return rotation; } - public final float[] getRotationOrigin() { return rotOrigin; } - public final void setRotationOrigin(final float rx, final float ry, final float rz) { + /** Return float[3] unscaled rotation origin, aka pivot. */ + public final float[] getRotationPivot() { return rotOrigin; } + /** Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GLProfile, GL2ES2)}. */ + public final void setRotationPivot(final float rx, final float ry, final float rz) { rotOrigin[0] = rx; rotOrigin[1] = ry; rotOrigin[2] = rz; } + /** + * Set unscaled rotation origin, aka pivot. Usually the {@link #getBounds()} center and should be set while {@link #validateImpl(GLProfile, GL2ES2)}. + * @param pivot float[3] rotation origin + */ + public final void setRotationPivot(final float[/*3*/] pivot) { + System.arraycopy(pivot, 0, rotOrigin, 0, 3); + } + + /** Set scale factor to given scale. */ public final void setScale(final float sx, final float sy, final float sz) { scale[0] = sx; scale[1] = sy; scale[2] = sz; } + /** Multiply current scale factor by given scale. */ public final void scale(final float sx, final float sy, final float sz) { scale[0] *= sx; scale[1] *= sy; scale[2] *= sz; } - /** Returns float[3] scale factors */ + /** Returns float[3] scale factors. */ public final float[] getScale() { return scale; } + /** Returns X-axis scale factor. */ public final float getScaleX() { return scale[0]; } + /** Returns Y-axis scale factor. */ public final float getScaleY() { return scale[1]; } + /** Returns Z-axis scale factor. */ public final float getScaleZ() { return scale[2]; } /** @@ -263,10 +250,10 @@ public abstract class Shape { } } - private final boolean isShapeDirty() { + protected final boolean isShapeDirty() { return 0 != ( dirty & DIRTY_SHAPE ) ; } - private final boolean isStateDirty() { + protected final boolean isStateDirty() { return 0 != ( dirty & DIRTY_STATE ) ; } @@ -321,94 +308,72 @@ public abstract class Shape { return box; } - public final int getRenderModes() { return renderModes; } - - public GLRegion getRegion(final GL2ES2 gl) { - validate(gl); - return region; - } - - /** Experimental OpenGL selection draw command used by {@link Scene}. */ - public void drawGLSelect(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { + /** Experimental selection draw command used by {@link Scene}. */ + public void drawToSelect(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { synchronized ( dirtySync ) { validate(gl); - region.draw(gl, renderer, sampleCount); + drawImpl0(gl, renderer, sampleCount, null); } } + private final float[] rgba_tmp = { 0, 0, 0, 1 }; + /** - * Renders {@link OutlineShape} using local {@link GLRegion} which might be cached or updated. + * Renders the shape. * <p> - * No matrix operations (translate, scale, ..) are performed. + * {@link #setTransform(PMVMatrix)} is expected to be completed beforehand. * </p> * @param gl the current GL object - * @param renderer the used {@link RegionRenderer}, also source of {@link RegionRenderer#getMatrix()} and {@link RegionRenderer#getViewport()}. + * @param renderer {@link RegionRenderer} which might be used for Graph Curve Rendering, also source of {@link RegionRenderer#getMatrix()} and {@link RegionRenderer#getViewport()}. * @param sampleCount sample count if used by Graph renderModes */ public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) { - final float r, g, b, a; final boolean isPressed = isPressed(), isToggleOn = isToggleOn(); - final boolean modBaseColor = !Region.hasColorChannel( renderModes ) && !Region.hasColorTexture( renderModes ); - if( modBaseColor ) { + final float[] rgba; + if( hasColorChannel() ) { if( isPressed ) { - r = rgbaColor[0]*pressedRGBAModulate[0]; - g = rgbaColor[1]*pressedRGBAModulate[1]; - b = rgbaColor[2]*pressedRGBAModulate[2]; - a = rgbaColor[3]*pressedRGBAModulate[3]; + rgba = pressedRGBAModulate; } else if( isToggleable() ) { if( isToggleOn ) { - r = rgbaColor[0]*toggleOnRGBAModulate[0]; - g = rgbaColor[1]*toggleOnRGBAModulate[1]; - b = rgbaColor[2]*toggleOnRGBAModulate[2]; - a = rgbaColor[3]*toggleOnRGBAModulate[3]; + rgba = toggleOnRGBAModulate; } else { - r = rgbaColor[0]*toggleOffRGBAModulate[0]; - g = rgbaColor[1]*toggleOffRGBAModulate[1]; - b = rgbaColor[2]*toggleOffRGBAModulate[2]; - a = rgbaColor[3]*toggleOffRGBAModulate[3]; + rgba = toggleOffRGBAModulate; } } else { - r = rgbaColor[0]; - g = rgbaColor[1]; - b = rgbaColor[2]; - a = rgbaColor[3]; + rgba = rgbaColor; } } else { + rgba = rgba_tmp; if( isPressed ) { - r = pressedRGBAModulate[0]; - g = pressedRGBAModulate[1]; - b = pressedRGBAModulate[2]; - a = pressedRGBAModulate[3]; + rgba[0] = rgbaColor[0]*pressedRGBAModulate[0]; + rgba[1] = rgbaColor[1]*pressedRGBAModulate[1]; + rgba[2] = rgbaColor[2]*pressedRGBAModulate[2]; + rgba[3] = rgbaColor[3]*pressedRGBAModulate[3]; } else if( isToggleable() ) { if( isToggleOn ) { - r = toggleOnRGBAModulate[0]; - g = toggleOnRGBAModulate[1]; - b = toggleOnRGBAModulate[2]; - a = toggleOnRGBAModulate[3]; + rgba[0] = rgbaColor[0]*toggleOnRGBAModulate[0]; + rgba[1] = rgbaColor[1]*toggleOnRGBAModulate[1]; + rgba[2] = rgbaColor[2]*toggleOnRGBAModulate[2]; + rgba[3] = rgbaColor[3]*toggleOnRGBAModulate[3]; } else { - r = toggleOffRGBAModulate[0]; - g = toggleOffRGBAModulate[1]; - b = toggleOffRGBAModulate[2]; - a = toggleOffRGBAModulate[3]; + rgba[0] = rgbaColor[0]*toggleOffRGBAModulate[0]; + rgba[1] = rgbaColor[1]*toggleOffRGBAModulate[1]; + rgba[2] = rgbaColor[2]*toggleOffRGBAModulate[2]; + rgba[3] = rgbaColor[3]*toggleOffRGBAModulate[3]; } } else { - r = rgbaColor[0]; - g = rgbaColor[1]; - b = rgbaColor[2]; - a = rgbaColor[3]; + rgba[0] = rgbaColor[0]; + rgba[1] = rgbaColor[1]; + rgba[2] = rgbaColor[2]; + rgba[3] = rgbaColor[3]; } } - renderer.getRenderState().setColorStatic(r, g, b, a); synchronized ( dirtySync ) { validate(gl); - region.draw(gl, renderer, sampleCount); + drawImpl0(gl, renderer, sampleCount, rgba); } } - protected GLRegion createGLRegion(final GLProfile glp) { - return GLRegion.create(glp, renderModes, null); - } - /** * Validates the shape's underlying {@link GLRegion}. * <p> @@ -418,8 +383,15 @@ public abstract class Shape { * @see #validate(GLProfile) */ public final void validate(final GL2ES2 gl) { - validateImpl(gl.getGLProfile(), gl); + synchronized ( dirtySync ) { + if( isShapeDirty() ) { + box.reset(); + } + validateImpl(gl.getGLProfile(), gl); + dirty = 0; + } } + /** * Validates the shape's underlying {@link GLRegion} w/o a current {@link GL2ES2} object * <p> @@ -429,30 +401,12 @@ public abstract class Shape { * @see #validate(GL2ES2) */ public final void validate(final GLProfile glp) { - validateImpl(glp, null); - } - private final void validateImpl(final GLProfile glp, final GL2ES2 gl) { synchronized ( dirtySync ) { - if( null != gl ) { - clearDirtyRegions(gl); - } - if( isShapeDirty() || null == region ) { + if( isShapeDirty() ) { box.reset(); - if( null == region ) { - region = createGLRegion(glp); - } else if( null == gl ) { - dirtyRegions.add(region); - region = createGLRegion(glp); - } else { - region.clear(gl); - } - addShapeToRegion(); - region.setQuality(regionQuality); - dirty &= ~(DIRTY_SHAPE|DIRTY_STATE); - } else if( isStateDirty() ) { - region.markStateDirty(); - dirty &= ~DIRTY_STATE; } + validateImpl(glp, null); + dirty = 0; } } @@ -769,21 +723,6 @@ public abstract class Shape { return rgbaColor; } - public final int getQuality() { return regionQuality; } - public final void setQuality(final int q) { - this.regionQuality = q; - if( null != region ) { - region.setQuality(q); - } - } - public final void setSharpness(final float sharpness) { - this.oshapeSharpness = sharpness; - markShapeDirty(); - } - public final float getSharpness() { - return oshapeSharpness; - } - /** * Set base color. * <p> @@ -842,9 +781,27 @@ public abstract class Shape { } public String getSubString() { + final String pivotS; + if( !VectorUtil.isVec3Zero(rotOrigin, 0, FloatUtil.EPSILON) ) { + pivotS = "pivot["+rotOrigin[0]+", "+rotOrigin[1]+", "+rotOrigin[2]+"], "; + } else { + pivotS = ""; + } + final String scaleS; + if( !VectorUtil.isVec3Equal(scale, 0, VectorUtil.VEC3_ONE, 0, FloatUtil.EPSILON) ) { + scaleS = "scale["+scale[0]+", "+scale[1]+", "+scale[2]+"], "; + } else { + scaleS = "scale 1, "; + } + final String rotateS; + if( !rotation.isIdentity() ) { + rotateS = "rot "+rotation+", "; + } else { + rotateS = ""; + } return "enabled "+enabled+", toggle[able "+toggleable+", state "+toggle+"], pos["+position[0]+", "+position[1]+", "+position[2]+ - "], scale["+scale[0]+", "+scale[1]+", "+scale[2]+ - "], box "+box; + "], "+pivotS+scaleS+rotateS+ + "box "+box; } // @@ -1187,39 +1144,25 @@ public abstract class Shape { // // - protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + protected abstract void validateImpl(final GLProfile glp, final GL2ES2 gl); + + protected abstract void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount, float[] rgba); + + protected abstract void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer); - protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) { } + protected abstract void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer); protected abstract void addShapeToRegion(); + /** + * Returns true if implementation uses an extra color channel or texture + * which will be modulated with the passed rgba color {@link #drawImpl0(GL2ES2, RegionRenderer, int[], float[])}. + * + * Otherwise the base color will be modulated and passed to {@link #drawImpl0(GL2ES2, RegionRenderer, int[], float[])}. + */ + public abstract boolean hasColorChannel(); + // // // - - protected OutlineShape createDebugOutline(final OutlineShape shape, final AABBox box) { - final float d = 0.025f; - final float tw = box.getWidth() + d*2f; - final float th = box.getHeight() + d*2f; - - final float minX = box.getMinX() - d; - final float minY = box.getMinY() - d; - final float z = 0; // box.getMinZ() + 0.025f; - - // CCW! - shape.moveTo(minX, minY, z); - shape.lineTo(minX+tw, minY, z); - shape.lineTo(minX+tw, minY + th, z); - shape.lineTo(minX, minY + th, z); - shape.closePath(); - - // shape.addVertex(minX, minY, z, true); - // shape.addVertex(minX+tw, minY, z, true); - // shape.addVertex(minX+tw, minY + th, z, true); - // shape.addVertex(minX, minY + th, z, true); - // shape.closeLastOutline(true); - - return shape; - } - } diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java index 88d6f04c7..90cd11b71 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Button.java @@ -33,12 +33,14 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.font.Font; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.ui.gl.GraphShape; import com.jogamp.opengl.math.geom.AABBox; import jogamp.graph.ui.shapes.Label0; /** - * A GraphUI text labeled {@link RoundButton} {@link Shape} + * A GraphUI text labeled {@link RoundButton} {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> @@ -60,6 +62,10 @@ public class Button extends RoundButton { private float spacingX = DEFAULT_SPACING_X; private float spacingY = DEFAULT_SPACING_Y; + private final AffineTransform tempT1 = new AffineTransform(); + private final AffineTransform tempT2 = new AffineTransform(); + private final AffineTransform tempT3 = new AffineTransform(); + public Button(final int renderModes, final Font labelFont, final String labelText, final float width, final float height) { @@ -126,7 +132,7 @@ public class Button extends RoundButton { System.err.printf("Button.X: lbox2 %s%n", lbox2); } - setRotationOrigin( ctr[0], ctr[1], ctr[2]); + setRotationPivot( ctr ); if( DRAW_DEBUG_BOX ) { System.err.println("XXX.Button: Added Shape: "+shape+", "+box); diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java index e8ec28d36..534e6fc7b 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/CrossHair.java @@ -28,15 +28,15 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** - * A GraphUI Crosshair {@link Shape} + * A GraphUI Crosshair {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> */ -public class CrossHair extends Shape { +public class CrossHair extends GraphShape { private float width, height, lineWidth; public CrossHair(final int renderModes, final float width, final float height, final float linewidth) { diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java index 0d51ff09b..5fdb7991b 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GLButton.java @@ -37,12 +37,13 @@ import com.jogamp.opengl.GLDrawableFactory; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLOffscreenAutoDrawable; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.gl.GraphShape; import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.texture.ImageSequence; import com.jogamp.opengl.util.texture.Texture; /** - * A GraphUI {@link GLEventListener} based {@link TexSeqButton} {@link Shape}. + * A GraphUI {@link GLEventListener} based {@link TexSeqButton} {@link GraphShape}. * <p> * GraphUI is GPU based and resolution independent. * </p> diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java index bbc4975bf..d5718d98a 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/ImageButton.java @@ -29,10 +29,11 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.opengl.GL2ES2; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.gl.GraphShape; import com.jogamp.opengl.util.texture.ImageSequence; /** - * A GraphUI {@link ImageSequence} based {@link TexSeqButton} {@link Shape}. + * A GraphUI {@link ImageSequence} based {@link TexSeqButton} {@link GraphShape}. * <p> * GraphUI is GPU based and resolution independent. * </p> diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java index 65371875d..cad8689ec 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Label.java @@ -29,6 +29,7 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.opengl.GLRegion; @@ -36,21 +37,25 @@ import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.font.Font; import com.jogamp.graph.font.Font.Glyph; import com.jogamp.graph.geom.plane.AffineTransform; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** - * A GraphUI text label {@link Shape} + * A GraphUI text label {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> */ -public class Label extends Shape { - protected Font font; - protected float fontScale; - protected String text; +public class Label extends GraphShape { + private Font font; + private float fontScale; + private String text; + + private final AffineTransform tempT1 = new AffineTransform(); + private final AffineTransform tempT2 = new AffineTransform(); + private final AffineTransform tempT3 = new AffineTransform(); /** - * Label ctor + * Label ctor using a separate {@code fontScale} to scale the em-sized type glyphs * @param renderModes region renderModes * @param font the font * @param fontScale font-scale factor, by which the em-sized type glyphs shall be scaled @@ -63,6 +68,19 @@ public class Label extends Shape { this.text = text; } + /** + * Label ctor using em-size type glyphs + * @param renderModes region renderModes + * @param font the font + * @param text the text to render + */ + public Label(final int renderModes, final Font font, final String text) { + super(renderModes); + this.font = font; + this.fontScale = 1f; + this.text = text; + } + /** Return the text to be rendered. */ public String getText() { return text; diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java index 8f9ccda3e..6b26c58b8 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/MediaButton.java @@ -30,13 +30,14 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.opengl.GL2ES2; import com.jogamp.common.util.InterruptSource; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.gl.GraphShape; import com.jogamp.opengl.util.av.GLMediaPlayer; import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener; import com.jogamp.opengl.util.av.GLMediaPlayer.StreamException; import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; /** - * A GraphUI {@link GLMediaPlayer} based {@link TexSeqButton} {@link Shape}. + * A GraphUI {@link GLMediaPlayer} based {@link TexSeqButton} {@link GraphShape}. * <p> * GraphUI is GPU based and resolution independent. * </p> diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java index f027d92bc..4a8c29f2a 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/Rectangle.java @@ -28,15 +28,15 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** - * A GraphUI Rectangle {@link Shape} + * A GraphUI Rectangle {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> */ -public class Rectangle extends Shape { +public class Rectangle extends GraphShape { private float width, height, lineWidth; public Rectangle(final int renderModes, final float width, final float height, final float linewidth) { diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java index 8dde441d9..93ba4f0dc 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/RoundButton.java @@ -28,10 +28,10 @@ package com.jogamp.graph.ui.gl.shapes; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; /** - * An abstract GraphUI round Button {@link Shape} + * An abstract GraphUI round Button {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> @@ -40,7 +40,7 @@ import com.jogamp.graph.ui.gl.Shape; * To render it rectangular, {@link #setCorner(float)} to zero. * </p> */ -public abstract class RoundButton extends Shape { +public abstract class RoundButton extends GraphShape { /** {@value} */ public static final float DEFAULT_CORNER = 1f; diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java index 19d9a228a..5afe1c373 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java +++ b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/TexSeqButton.java @@ -31,11 +31,11 @@ import com.jogamp.opengl.GLProfile; import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; -import com.jogamp.graph.ui.gl.Shape; +import com.jogamp.graph.ui.gl.GraphShape; import com.jogamp.opengl.util.texture.TextureSequence; /** - * An abstract GraphUI {@link TextureSequence} {@link RoundButton} {@link Shape}. + * An abstract GraphUI {@link TextureSequence} {@link RoundButton} {@link GraphShape}. * <p> * GraphUI is GPU based and resolution independent. * </p> @@ -73,8 +73,7 @@ public abstract class TexSeqButton extends RoundButton { region.addOutlineShape(shape, null, rgbaColor); box.resize(shape.getBounds()); - final float[] ctr = box.getCenter(); - setRotationOrigin( ctr[0], ctr[1], ctr[2]); + setRotationPivot( box.getCenter() ); if( DRAW_DEBUG_BOX ) { System.err.println("XXX.UIShape.TextureSeqButton: Added Shape: "+shape+", "+box); |