aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph/ui/shapes
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-03-31 11:06:44 +0200
committerSven Gothel <[email protected]>2023-03-31 11:06:44 +0200
commit4f32f3aba62a73cafecec8af461cff4d0d475882 (patch)
tree58f6e7f0800a1ca8b793966520d6008cc6f2080b /src/graphui/classes/com/jogamp/graph/ui/shapes
parent759a381963476e2e64b7afba0d6ef2bafeb35417 (diff)
GraphUI: Relocate com.jogamp.graph.ui.gl.* -> com.jogamp.graph.ui.*, resolve GL/VK abstraction at a later time differently
Actual GPU rendering toolkit dependency can be abstracted differently, i.e. GPU <- { GL, VK } etc.
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph/ui/shapes')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/Button.java208
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/CrossHair.java99
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/GLButton.java170
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/GlyphShape.java204
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/ImageButton.java68
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/Label.java225
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/MediaButton.java139
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java104
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/RoundButton.java129
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/shapes/TexSeqButton.java82
10 files changed, 1428 insertions, 0 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/Button.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/Button.java
new file mode 100644
index 000000000..ca726e30f
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/Button.java
@@ -0,0 +1,208 @@
+/**
+ * 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.shapes;
+
+import com.jogamp.opengl.GL2ES2;
+
+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.GraphShape;
+import com.jogamp.opengl.math.geom.AABBox;
+
+import jogamp.graph.ui.shapes.Label0;
+
+/**
+ * A GraphUI text labeled {@link RoundButton} {@link GraphShape}
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public class Button extends RoundButton {
+ /** {@value} */
+ public static final float DEFAULT_SPACING_X = 0.12f;
+ /** {@value} */
+ public static final float DEFAULT_SPACING_Y = 0.42f;
+
+ private static final float DEFAULT_2PASS_LABEL_ZOFFSET = -0.005f; // -0.05f;
+ private float twoPassLabelZOffset = DEFAULT_2PASS_LABEL_ZOFFSET;
+
+ private final Label0 label;
+ 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) {
+ super(renderModes | Region.COLORCHANNEL_RENDERING_BIT, width, height);
+ this.label = new Label0(labelFont, labelText, new float[] { 1.33f, 1.33f, 1.33f, 1.0f }); // 0.75 * 1.33 = 1.0
+ setColor(0.75f, 0.75f, 0.75f, 1.0f);
+ setPressedColorMod(0.9f, 0.9f, 0.9f, 0.7f);
+ setToggleOffColorMod(0.65f, 0.65f, 0.65f, 1.0f);
+ setToggleOnColorMod(0.85f, 0.85f, 0.85f, 1.0f);
+ }
+
+ public Font getFont() { return label.getFont(); }
+ public String getLaben() { return label.getText(); }
+
+ @Override
+ public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) {
+ // Setup poly offset for z-fighting
+ // gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
+ // gl.glPolygonOffset(0f, 1f);
+ super.draw(gl, renderer, sampleCount);
+ // gl.glDisable(GL.GL_POLYGON_OFFSET_FILL);
+ }
+
+ @Override
+ protected void addShapeToRegion() {
+ final OutlineShape shape = new OutlineShape(vertexFactory);
+ if(corner == 0.0f) {
+ createSharpOutline(shape, twoPassLabelZOffset);
+ } else {
+ createCurvedOutline(shape, twoPassLabelZOffset);
+ }
+ shape.setIsQuadraticNurbs();
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, null, rgbaColor);
+ box.resize(shape.getBounds());
+
+ // Precompute text-box size .. guessing pixelSize
+ final float lw = box.getWidth() * ( 1f - spacingX ) ;
+ final float lh = box.getHeight() * ( 1f - spacingY ) ;
+ final AABBox lbox0_em = label.getFont().getGlyphBounds(label.getText(), tempT1, tempT2);
+ final float lsx = lw / lbox0_em.getWidth();
+ final float lsy = lh / lbox0_em.getHeight();
+ final float lScale = lsx < lsy ? lsx : lsy;
+
+ // Setting left-corner transform using text-box in font em-size [0..1]
+ final AABBox lbox1_s = new AABBox(lbox0_em).scale2(lScale, new float[3]);
+ // Center text .. (share same center w/ button)
+ final float[] lctr = lbox1_s.getCenter();
+ final float[] ctr = box.getCenter();
+ final float[] ltxy = new float[] { ctr[0] - lctr[0], ctr[1] - lctr[1] };
+
+ if( DEBUG_DRAW ) {
+ System.err.println("Button: dim "+width+" x "+height+", spacing "+spacingX+", "+spacingY);
+ System.err.println("Button: net-text "+lw+" x "+lh);
+ System.err.println("Button: shape "+box);
+ System.err.println("Button: text_em "+lbox0_em+" em, "+label.getText());
+ System.err.println("Button: lscale "+lsx+" x "+lsy+" -> "+lScale);
+ System.err.printf ("Button: text_s %s%n", lbox1_s);
+ System.err.printf ("Button: ltxy %f / %f, %f / %f%n", ltxy[0], ltxy[1], ltxy[0] * lScale, ltxy[1] * lScale);
+ }
+
+ final AABBox lbox2 = label.addShapeToRegion(lScale, region, ltxy, tempT1, tempT2, tempT3);
+ if( DEBUG_DRAW ) {
+ System.err.printf("Button.X: lbox2 %s%n", lbox2);
+ }
+
+ setRotationPivot( ctr );
+
+ if( DEBUG_DRAW ) {
+ System.err.println("XXX.Button: Added Shape: "+shape+", "+box);
+ }
+ }
+
+ public float get2PassLabelZOffset() { return twoPassLabelZOffset; }
+
+ public void set2PassLabelZOffset(final float v) {
+ twoPassLabelZOffset = v;
+ markShapeDirty();
+ }
+
+ public final float getSpacingX() { return spacingX; }
+ public final float getSpacingY() { return spacingY; }
+
+ /**
+ * 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 final void setSpacing(final float spacingX, final 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.spacingY = spacingY;
+ }
+ markShapeDirty();
+ }
+
+ public final float[] getLabelColor() {
+ return label.getColor();
+ }
+
+ public final void setLabelColor(final float r, final float g, final float b) {
+ label.setColor(r, g, b, 1.0f);
+ markShapeDirty();
+ }
+
+ public final void setFont(final Font labelFont) {
+ if( !label.getFont().equals(labelFont) ) {
+ label.setFont(labelFont);
+ markShapeDirty();
+ }
+ }
+ public final void setLabel(final String labelText) {
+ if( !label.getText().equals(labelText) ) {
+ label.setText(labelText);
+ markShapeDirty();
+ }
+ }
+ public final void setLabel(final Font labelFont, final String labelText) {
+ if( !label.getText().equals(labelText) || !label.getFont().equals(labelFont) ) {
+ label.setFont(labelFont);
+ label.setText(labelText);
+ markShapeDirty();
+ }
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", "+ label + ", " + "spacing["+spacingX+", "+spacingY+"]";
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/CrossHair.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/CrossHair.java
new file mode 100644
index 000000000..3e36422a4
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/CrossHair.java
@@ -0,0 +1,99 @@
+/**
+ * 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.shapes;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.ui.GraphShape;
+
+/**
+ * A GraphUI Crosshair {@link GraphShape}
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ */
+public class CrossHair extends GraphShape {
+ private float width, height, lineWidth;
+
+ public CrossHair(final int renderModes, final float width, final float height, final float linewidth) {
+ super(renderModes);
+ this.width = width;
+ this.height = height;
+ this.lineWidth = linewidth;
+ }
+
+ public final float getWidth() { return width; }
+ public final float getHeight() { return height; }
+ public final float getLineWidth() { return lineWidth; }
+
+ public void setDimension(final float width, final float height, final float lineWidth) {
+ this.width = width;
+ this.height = height;
+ this.lineWidth = lineWidth;
+ markShapeDirty();
+ }
+
+ @Override
+ protected void addShapeToRegion() {
+ final OutlineShape shape = new OutlineShape(vertexFactory);
+
+ final float lwh = lineWidth/2f;
+
+ final float tw = getWidth();
+ final float th = getHeight();
+ final float twh = tw/2f;
+ final float thh = th/2f;
+
+ final float ctrX = 0f, ctrY = 0f;
+ final float ctrZ = 0f;
+
+ // middle vertical (CCW!)
+ shape.moveTo(ctrX-lwh, ctrY-thh, ctrZ);
+ shape.lineTo(ctrX+lwh, ctrY-thh, ctrZ);
+ shape.lineTo(ctrX+lwh, ctrY+thh, ctrZ);
+ shape.lineTo(ctrX-lwh, ctrY+thh, ctrZ);
+ shape.closePath();
+
+ // middle horizontal (CCW!)
+ shape.moveTo(ctrX-twh, ctrY-lwh, ctrZ);
+ shape.lineTo(ctrX+twh, ctrY-lwh, ctrZ);
+ shape.lineTo(ctrX+twh, ctrY+lwh, ctrZ);
+ shape.lineTo(ctrX-twh, ctrY+lwh, ctrZ);
+ shape.closePath();
+
+ shape.setIsQuadraticNurbs();
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, null, rgbaColor);
+
+ box.resize(shape.getBounds());
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", dim "+getWidth() + " x " + getHeight();
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/GLButton.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/GLButton.java
new file mode 100644
index 000000000..f11475b84
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/GLButton.java
@@ -0,0 +1,170 @@
+/**
+ * Copyright 2014-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.shapes;
+
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GL2ES2;
+import com.jogamp.opengl.GLCapabilities;
+import com.jogamp.opengl.GLCapabilitiesImmutable;
+import com.jogamp.opengl.GLContext;
+import com.jogamp.opengl.GLDrawable;
+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.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 GraphShape}.
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * The {@link GLEventListener} is rendered via an {@link GLOffscreenAutoDrawable.FBO} into an {@link ImageSequence}.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public class GLButton extends TexSeqButton {
+ private final GLEventListener glel;
+ private final boolean useAlpha;
+ private volatile int fboWidth = 200;
+ private volatile int fboHeight = 200;
+ private volatile GLOffscreenAutoDrawable.FBO fboGLAD = null;
+ private boolean animateGLEL = false;
+
+ public GLButton(final int renderModes, final float width, final float height,
+ final int textureUnit, final GLEventListener glel, final boolean useAlpha) {
+ super(renderModes, width, height, new ImageSequence(textureUnit, true));
+ this.glel = glel;
+ this.useAlpha = useAlpha;
+
+ setColor(0.95f, 0.95f, 0.95f, 1.0f);
+ setPressedColorMod(1f, 1f, 1f, 0.9f);
+ setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f);
+ setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f);
+
+ // fake surface-size, will be overriden in initial FBO setup @ display
+ this.fboWidth = 320;
+ this.fboHeight = Math.round( 640 * height / width );
+ }
+
+ public final void setAnimate(final boolean v) { animateGLEL = v; }
+ public final boolean getAnimate() { return animateGLEL; }
+
+ public final void setFBOSize(final int fboWidth, final int fboHeight) {
+ this.fboWidth = fboWidth;
+ this.fboHeight = fboHeight;
+ }
+
+ public final GLOffscreenAutoDrawable.FBO getFBOAutoDrawable() { return fboGLAD; }
+
+ @Override
+ protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) {
+ ((ImageSequence)texSeq).destroy(gl);
+ fboGLAD.destroy();
+ }
+
+ @Override
+ public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) {
+ final int[/*2*/] surfaceSize = getSurfaceSize(renderer.getMatrix(), renderer.getViewport(), new int[2]);
+ final boolean got_sz = null != surfaceSize && 0 < surfaceSize[0] && 0 < surfaceSize[1];
+
+ if( null == fboGLAD ) {
+ final ImageSequence imgSeq = (ImageSequence)texSeq;
+
+ final GLContext ctx = gl.getContext();
+ final GLDrawable drawable = ctx.getGLDrawable();
+ final GLCapabilitiesImmutable reqCaps = drawable.getRequestedGLCapabilities();
+ final GLCapabilities caps = (GLCapabilities) reqCaps.cloneMutable();
+ caps.setFBO(true);
+ caps.setDoubleBuffered(false);
+ if( !useAlpha ) {
+ caps.setAlphaBits(0);
+ }
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile());
+
+ // System.err.println("XXX FBO initSurfaceSize got_sz "+got_sz+", "+fboWidth+" x "+fboHeight+" -> "+surfaceSize[0]+" x "+surfaceSize[1]);
+ if( got_sz ) {
+ // override with real surface-size
+ fboWidth = surfaceSize[0];
+ fboHeight = surfaceSize[1];
+ }
+ fboGLAD = (GLOffscreenAutoDrawable.FBO) factory.createOffscreenAutoDrawable(
+ drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(),
+ caps, null, fboWidth, fboHeight);
+ fboWidth = 0;
+ fboHeight = 0;
+ fboGLAD.setSharedContext(ctx);
+ fboGLAD.setTextureUnit(imgSeq.getTextureUnit());
+ fboGLAD.addGLEventListener(glel);
+ fboGLAD.display(); // 1st init!
+
+ final FBObject.TextureAttachment texA01 = fboGLAD.getColorbuffer(GL.GL_FRONT).getTextureAttachment();
+ final Texture tex = new Texture(texA01.getName(), imgSeq.getTextureTarget(),
+ fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(),
+ false /* mustFlipVertically */);
+ imgSeq.addFrame(gl, tex);
+ markStateDirty();
+ } else if( 0 != fboWidth*fboHeight ) {
+ fboGLAD.setSurfaceSize(fboWidth, fboHeight);
+ fboWidth = 0;
+ fboHeight = 0;
+ markStateDirty();
+ } else if( got_sz && ( fboGLAD.getSurfaceWidth() != surfaceSize[0] || fboGLAD.getSurfaceHeight() != surfaceSize[1] ) ) {
+ // System.err.println("XXX FBO setSurfaceSize "+fboGLAD.getSurfaceWidth()+" x "+fboGLAD.getSurfaceHeight()+" -> "+surfaceSize[0]+" x "+surfaceSize[1]);
+ final ImageSequence imgSeq = (ImageSequence)texSeq;
+
+ fboGLAD.setSurfaceSize(surfaceSize[0], surfaceSize[1]);
+ fboGLAD.display(); // re-init!
+
+ imgSeq.destroy(gl);
+ final FBObject.TextureAttachment texA01 = fboGLAD.getColorbuffer(GL.GL_FRONT).getTextureAttachment();
+ final Texture tex = new Texture(texA01.getName(), imgSeq.getTextureTarget(),
+ fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(), fboGLAD.getSurfaceWidth(), fboGLAD.getSurfaceHeight(),
+ false /* mustFlipVertically */);
+ imgSeq.addFrame(gl, tex);
+ fboWidth = 0;
+ fboHeight = 0;
+ markStateDirty();
+ } else if( animateGLEL ) {
+ fboGLAD.display();
+ }
+
+ super.draw(gl, renderer, sampleCount);
+
+ if( animateGLEL ) {
+ markStateDirty(); // keep on going
+ }
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/GlyphShape.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/GlyphShape.java
new file mode 100644
index 000000000..568270073
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/GlyphShape.java
@@ -0,0 +1,204 @@
+/**
+ * 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.shapes;
+
+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.font.Font;
+import com.jogamp.graph.font.Font.Glyph;
+import com.jogamp.graph.geom.plane.AffineTransform;
+import com.jogamp.graph.ui.GraphShape;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.math.Vec3f;
+import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.opengl.util.texture.TextureSequence;
+
+/**
+ * Representing a single {@link Font.Glyph} as a {@link GraphShape}
+ *
+ * A GlyphShape is represented in font em-size [0..1] unscaled w/ bottom-left origin at 0/0
+ * while preserving an intended position, see {@link #getOrigPos()} and {@link #getOrigPos(float)}.
+ *
+ * Scaling, if any, should be applied via {@link #setScale(float, float, float)} etc.
+ */
+public class GlyphShape extends GraphShape {
+ private final char symbol;
+ private final Glyph glyph;
+ private final Vec3f origPos;
+
+ /**
+ * Creates a new GlyphShape
+ * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
+ * @param symbol the represented character
+ * @param glyph the {@link Font.Glyph}
+ * @param x the intended unscaled X position of this Glyph, e.g. if part of a string - otherwise use zero.
+ * @param y the intended unscaled Y position of this Glyph, e.g. if part of a string - otherwise use zero.
+ * @see #processString(List, int, Font, String)
+ */
+ public GlyphShape(final int renderModes, final char symbol, final Glyph glyph, final float x, final float y) {
+ super(renderModes);
+ this.symbol = symbol;
+ this.glyph = glyph;
+ this.origPos = new Vec3f(x, y, 0f);
+ if( glyph.isWhiteSpace() || null == glyph.getShape() ) {
+ setEnabled(false);
+ }
+ }
+
+ /**
+ * Creates a new GlyphShape
+ * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
+ * @param font the {@link Font} to lookup the symbol's {@link Font.Glyph}
+ * @param symbol the represented character
+ * @param x the intended unscaled X position of this Glyph, e.g. if part of a string - otherwise use zero.
+ * @param y the intended unscaled Y position of this Glyph, e.g. if part of a string - otherwise use zero.
+ */
+ public GlyphShape(final int renderModes, final Font font, final char symbol, final float x, final float y) {
+ super(renderModes);
+ this.symbol = symbol;
+ this.glyph = font.getGlyph( font.getGlyphID(symbol) );
+ this.origPos = new Vec3f(x, y, 0f);
+ if( glyph.isWhiteSpace() || null == glyph.getShape() ) {
+ setEnabled(false);
+ }
+ }
+
+ /** Returns the char symbol to be rendered. */
+ public char getSymbol() {
+ return symbol;
+ }
+
+ /**
+ * Returns the {@link Font.Glyph} to be rendered.
+ */
+ public Glyph getGlyph() {
+ return glyph;
+ }
+
+ /**
+ * Returns the {@link Font} used to render the text
+ */
+ public Font getFont() {
+ return glyph.getFont();
+ }
+
+ /**
+ * Returns the unscaled original position of this glyph, e.g. if part of a string, otherwise zero.
+ *
+ * Method borrows and returns the internal instance.
+ *
+ * @see #processString(List, int, Font, String)
+ */
+ public Vec3f getOrigPos() { return origPos; }
+
+ /**
+ * Returns the unscaled original position of this glyph, e.g. if part of a string, otherwise zero.
+ *
+ * @param s {@link Vec3f} storage to be returned
+ * @return storage containing the unscaled original position
+ * @see #processString(List, int, Font, String)
+ */
+ public Vec3f getOrigPos(final Vec3f s) { return s.set(origPos); }
+
+ /**
+ * Returns a copy of the scaled original position of this glyph, see {@link #getOrigPos(Vec3f)}
+ * @see #processString(List, int, Font, String)
+ */
+ public Vec3f getOrigPos(final float scale) { return origPos.mul(scale); }
+
+ /**
+ * Returns the scaled original position of this glyph, see {@link #getOrigPos(float)}
+ * @param s {@link Vec3f} storage to be returned
+ * @return storage containing the scaled original position
+ * @see #processString(List, int, Font, String)
+ */
+ public Vec3f getOrigPos(final Vec3f s, final float scale) { return s.set(origPos).scale(scale); }
+
+ /** Resets this Shape's position to the scaled original position, see {@link #getOrigPos(float)}. */
+ public void resetPos(final float scale) {
+ moveTo(origPos.x() * scale, origPos.y() * scale, 0f);
+ }
+
+ /** Resets this Shape's position to the scaled original position and {@link #setScale(float, float, float) set scale}, see {@link #resetPos(float)}. */
+ public void resetPosAndScale(final float scale) {
+ moveTo(origPos.x() * scale, origPos.y() * scale, 0f);
+ setScale(scale, scale, 1f);
+ }
+
+ /** Returns {@link Font#getLineHeight()}. */
+ public float getLineHeight() {
+ return glyph.getFont().getLineHeight();
+ }
+
+ /**
+ * Process the given text resulting in a list of {@link GlyphShape}s with stored original position {@link #getOrigX()} and {@link #getOrigY()} each at font em-size [0..1].
+ * @param res storage for resulting {@link GlyphShape}s.
+ * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
+ * @param font {@link Font} used
+ * @param text text to be represented
+ * @return the bounding box of the given string by taking each glyph's font em-sized [0..1] OutlineShape into account.
+ * @see #getOrigX()
+ * @see #getOrigY()
+ */
+ public static final AABBox processString(final List<GlyphShape> res, final int renderModes, final Font font, final String text) {
+ final Font.GlyphVisitor fgv = new Font.GlyphVisitor() {
+ @Override
+ public void visit(final char symbol, final Glyph glyph, final AffineTransform t) {
+ if( !glyph.isWhiteSpace() && null != glyph.getShape() ) {
+ res.add( new GlyphShape(renderModes, symbol, glyph, t.getTranslateX(), t.getTranslateY()) );
+ }
+ }
+ };
+ return font.processString(fgv, null, text, new AffineTransform(), new AffineTransform());
+ }
+
+ @Override
+ protected void addShapeToRegion() {
+ final OutlineShape shape = glyph.getShape();
+ box.reset();
+ if( null != shape ) {
+ final AABBox sbox = shape.getBounds();
+ final AffineTransform tmp = new AffineTransform();
+ // Enforce bottom-left origin @ 0/0 for good drag-zoom experience,
+ // but keep the underline (decline) intact!
+ tmp.setToTranslation(-sbox.getMinX(), -sbox.getMinY() + glyph.getBounds().getMinY());
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, tmp, rgbaColor);
+ setRotationPivot( sbox.getCenter() );
+ box.resize(tmp.transform(sbox, new AABBox()));
+ }
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", origPos " + origPos.x() + " / " + origPos.y() + ", '" + symbol + "'";
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/ImageButton.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/ImageButton.java
new file mode 100644
index 000000000..63b0b3eaf
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/ImageButton.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2014-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.shapes;
+
+import com.jogamp.opengl.GL2ES2;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.ui.GraphShape;
+import com.jogamp.opengl.util.texture.ImageSequence;
+
+/**
+ * A GraphUI {@link ImageSequence} based {@link TexSeqButton} {@link GraphShape}.
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public class ImageButton extends TexSeqButton {
+
+ public ImageButton(final int renderModes, final float width,
+ final float height, final ImageSequence texSeq) {
+ super(renderModes, width, height, texSeq);
+ setColor(0.95f, 0.95f, 0.95f, 1.0f);
+ setPressedColorMod(1f, 1f, 1f, 0.9f);
+ setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f);
+ setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+
+ public final void setCurrentIdx(final int idx) {
+ ((ImageSequence)texSeq).setCurrentIdx(idx);
+ markStateDirty();
+ }
+
+ @Override
+ public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) {
+ super.draw(gl, renderer, sampleCount);
+ if( !((ImageSequence)texSeq).getManualStepping() ) {
+ markStateDirty(); // keep on going
+ }
+ };
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/Label.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/Label.java
new file mode 100644
index 000000000..e7d89ade4
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/Label.java
@@ -0,0 +1,225 @@
+/**
+ * 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.shapes;
+
+import com.jogamp.opengl.GL2ES2;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.math.geom.AABBox;
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.GLRegion;
+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.GraphShape;
+
+/**
+ * A GraphUI text label {@link GraphShape}
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ */
+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 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
+ * @param text the text to render
+ */
+ public Label(final int renderModes, final Font font, final float fontScale, final String text) {
+ super(renderModes);
+ this.font = font;
+ this.fontScale = fontScale;
+ 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;
+ }
+
+ /**
+ * Set the text to be rendered. Shape update is pending until next {@link #draw(GL2ES2, RegionRenderer, int[])} or {@link #validate(GL2ES2)}.
+ * @param text the text to be set.
+ * @return true if text has been updated, false if unchanged.
+ */
+ public boolean setText(final String text) {
+ if( !this.text.equals(text) ) {
+ this.text = text;
+ markShapeDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set the text to be rendered and immediately updates the shape if necessary.
+ * @param gl {@link GL2ES2} to issue {@link #validate(GL2ES2)} in case text changed to immediately update shape and {@link #getBounds()}
+ * @param text the text to be set.
+ * @return true if text has been updated, false if unchanged.
+ */
+ public boolean setText(final GL2ES2 gl, final String text) {
+ if( setText(text) ) {
+ validate(gl);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Set the text to be rendered and immediately updates the shape if necessary.
+ * @param glp {@link GLProfile} to issue {@link #validate(GLProfile)} in case text changed to immediately update shape and {@link #getBounds()}
+ * @param text the text to be set.
+ * @return true if text has been updated, false if unchanged.
+ */
+ public boolean setText(final GLProfile glp, final String text) {
+ if( setText(text) ) {
+ validate(glp);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return the {@link Font} used to render the text
+ */
+ public Font getFont() {
+ return font;
+ }
+
+ /**
+ * Set the {@link Font} used to render the text
+ * @param font the font to be set.
+ * @return true if font has been updated, false if unchanged.
+ */
+ public boolean setFont(final Font font) {
+ if( !this.font.equals(font) ) {
+ this.font = font;
+ markShapeDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Gets the font-scale factor, by which the em-sized type glyphs shall be scaled.
+ */
+ public float getFontScale() {
+ return fontScale;
+ }
+
+ /** Returns {@link Font#getLineHeight()} * {@link #getFontScale()}. */
+ public float getLineHeight() {
+ return fontScale * font.getLineHeight();
+ }
+
+ /** Returns {@link Font#getLineHeight()} * {@link #getFontScale()} * {@link #getScaleY()}. */
+ public float getScaledLineHeight() {
+ return getScaleY() * fontScale * font.getLineHeight();
+ }
+
+ /**
+ * Sets the font-scale factor, by which the em-sized type glyphs shall be scaled.
+ * <p>
+ * This will lead to a recreate the shape's region in case fontScale differs.
+ * </p>
+ * <p>
+ * Use {@link #scale(float, float, float)} for non-expensive shape scaling.
+ * </p>
+ * @param fontScale font-scale factor, by which the em-sized type glyphs shall be scaled
+ * @return true if font-scale has been updated, false if unchanged.
+ */
+ public boolean setFontScale(final float fontScale) {
+ if( this.fontScale != fontScale ) {
+ this.fontScale = fontScale;
+ markShapeDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected GLRegion createGLRegion(final GLProfile glp) {
+ return GLRegion.create(glp, getRenderModes(), null, font, text);
+ }
+
+ private final Font.GlyphVisitor glyphVisitor = new Font.GlyphVisitor() {
+ @Override
+ public void visit(final char symbol, final Glyph glyph, final AffineTransform t) {
+ if( glyph.isWhiteSpace() ) {
+ return;
+ }
+ final OutlineShape shape = glyph.getShape();
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, t, rgbaColor);
+ }
+ };
+
+ @Override
+ protected void addShapeToRegion() {
+ AABBox fbox = font.getGlyphBounds(text, tempT2, tempT3);
+ tempT1.setToScale(fontScale, fontScale);
+ tempT1.translate(-fbox.getMinX(), -fbox.getMinY(), tempT2); // enforce bottom-left origin @ 0/0 for good drag-zoom experience
+ fbox = font.processString(glyphVisitor, tempT1, text, tempT2, tempT3);
+ setRotationPivot( fbox.getCenter() );
+ box.copy(fbox);
+ }
+
+ @Override
+ public String getSubString() {
+ final int m = Math.min(text.length(), 8);
+ return super.getSubString()+", fscale " + fontScale + ", '" + text.substring(0, m)+"'";
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/MediaButton.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/MediaButton.java
new file mode 100644
index 000000000..55a00aae4
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/MediaButton.java
@@ -0,0 +1,139 @@
+/**
+ * Copyright 2014-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.shapes;
+
+import com.jogamp.opengl.GL2ES2;
+import com.jogamp.common.util.InterruptSource;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.ui.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 GraphShape}.
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public class MediaButton extends TexSeqButton {
+ private boolean verbose = false;
+
+ /**
+ * @param renderModes
+ * @param width
+ * @param height
+ * @param mPlayer
+ * @param mPlayerListener
+ */
+ public MediaButton(final int renderModes, final float width,
+ final float height, final GLMediaPlayer mPlayer) {
+ super(renderModes, width, height, mPlayer);
+ setColor(0.8f, 0.8f, 0.8f, 1.0f);
+ setPressedColorMod(1.1f, 1.1f, 1.1f, 0.7f);
+ setToggleOffColorMod(0.8f, 0.8f, 0.8f, 1.0f);
+ setToggleOnColorMod(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+
+ public void setVerbose(final boolean v) { verbose = v; }
+
+ /**
+ * Add the default {@link GLMediaEventListener} to {@link #getGLMediaPlayer() this class's GLMediaPlayer}.
+ */
+ public void addDefaultEventListener() {
+ getGLMediaPlayer().addEventListener(defGLMediaEventListener);
+ }
+
+ public final GLMediaPlayer getGLMediaPlayer() { return (GLMediaPlayer)texSeq; }
+
+ private final GLMediaEventListener defGLMediaEventListener = new GLMediaEventListener() {
+ @Override
+ public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) {
+ // texButton.markStateDirty();
+ }
+
+ @Override
+ public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) {
+ if( verbose ) {
+ System.err.println("MediaButton AttributesChanges: events_mask 0x"+Integer.toHexString(event_mask)+", when "+when);
+ System.err.println("MediaButton State: "+mp);
+ }
+ if( 0 != ( GLMediaEventListener.EVENT_CHANGE_INIT & event_mask ) ) {
+ resetGL = true;
+ }
+ if( 0 != ( GLMediaEventListener.EVENT_CHANGE_SIZE & event_mask ) ) {
+ // FIXME: mPlayer.resetGLState();
+ }
+ if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) {
+ new InterruptSource.Thread() {
+ @Override
+ public void run() {
+ // loop for-ever ..
+ mp.seek(0);
+ mp.resume();
+ } }.start();
+ } else if( 0 != ( GLMediaEventListener.EVENT_CHANGE_ERR & event_mask ) ) {
+ final StreamException se = mp.getStreamException();
+ if( null != se ) {
+ se.printStackTrace();
+ }
+ }
+ } };
+
+
+ @Override
+ protected void destroyImpl(final GL2ES2 gl, final RegionRenderer renderer) {
+ ((GLMediaPlayer)texSeq).destroy(gl);
+ }
+
+ volatile boolean resetGL = true;
+
+ @Override
+ public void draw(final GL2ES2 gl, final RegionRenderer renderer, final int[] sampleCount) {
+ final GLMediaPlayer mPlayer = (GLMediaPlayer)texSeq;
+ if( resetGL ) {
+ resetGL = false;
+ try {
+ mPlayer.initGL(gl);
+ if( null != region ) {
+ region.markShapeDirty(); // reset texture data
+ }
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ super.draw(gl, renderer, sampleCount);
+ markStateDirty(); // keep on going
+ };
+
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java
new file mode 100644
index 000000000..a75bd0bc3
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java
@@ -0,0 +1,104 @@
+/**
+ * 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.shapes;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.ui.GraphShape;
+
+/**
+ * A GraphUI Rectangle {@link GraphShape}
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ */
+public class Rectangle extends GraphShape {
+ private float width, height, lineWidth;
+
+ public Rectangle(final int renderModes, final float width, final float height, final float linewidth) {
+ super(renderModes);
+ this.width = width;
+ this.height = height;
+ this.lineWidth = linewidth;
+ }
+
+ public final float getWidth() { return width; }
+ public final float getHeight() { return height; }
+ public final float getLineWidth() { return lineWidth; }
+
+ public void setDimension(final float width, final float height, final float lineWidth) {
+ this.width = width;
+ this.height = height;
+ this.lineWidth = lineWidth;
+ markShapeDirty();
+ }
+
+ @Override
+ protected void addShapeToRegion() {
+ final OutlineShape shape = new OutlineShape(vertexFactory);
+
+ final float lwh = lineWidth/2f;
+
+ final float tw = getWidth();
+ final float th = getHeight();
+
+ final float twh = tw/2f;
+ final float twh_o = twh+lwh;
+ final float twh_i = twh-lwh;
+ final float thh = th/2f;
+ final float thh_o = thh+lwh;
+ final float thh_i = thh-lwh;
+
+ final float ctrX = 0f, ctrY = 0f;
+ final float ctrZ = 0f;
+
+ // outer (CCW!)
+ shape.moveTo(ctrX-twh_o, ctrY-thh_o, ctrZ);
+ shape.lineTo(ctrX+twh_o, ctrY-thh_o, ctrZ);
+ shape.lineTo(ctrX+twh_o, ctrY+thh_o, ctrZ);
+ shape.lineTo(ctrX-twh_o, ctrY+thh_o, ctrZ);
+ shape.closePath();
+
+ // inner (CCW!)
+ shape.moveTo(ctrX-twh_i, ctrY-thh_i, ctrZ);
+ shape.lineTo(ctrX+twh_i, ctrY-thh_i, ctrZ);
+ shape.lineTo(ctrX+twh_i, ctrY+thh_i, ctrZ);
+ shape.lineTo(ctrX-twh_i, ctrY+thh_i, ctrZ);
+ shape.closePath();
+
+ shape.setIsQuadraticNurbs();
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, null, rgbaColor);
+
+ box.resize(shape.getBounds());
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", dim "+getWidth() + " x " + getHeight();
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/RoundButton.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/RoundButton.java
new file mode 100644
index 000000000..a2ab43ae1
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/RoundButton.java
@@ -0,0 +1,129 @@
+/**
+ * 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.shapes;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.ui.GraphShape;
+
+/**
+ * An abstract GraphUI round Button {@link GraphShape}
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public abstract class RoundButton extends GraphShape {
+
+ /** {@value} */
+ public static final float DEFAULT_CORNER = 1f;
+ protected float width;
+ protected float height;
+ protected float corner = DEFAULT_CORNER;
+
+ protected RoundButton(final int renderModes, final float width, final float height) {
+ super(renderModes);
+ this.width = width;
+ this.height = height;
+ }
+
+ public final float getWidth() { return width; }
+
+ public final float getHeight() { return height; }
+
+ public final float getCorner() { return corner; }
+
+ public void setSize(final float width, final float height) {
+ this.width = width;
+ this.height = height;
+ markShapeDirty();
+ }
+
+ protected void createSharpOutline(final OutlineShape shape, final float zOffset) {
+ final float tw = getWidth();
+ final float th = getHeight();
+
+ final float minX = 0;
+ final float minY = 0;
+ final float minZ = zOffset;
+
+ shape.addVertex(minX, minY, minZ, true);
+ shape.addVertex(minX+tw, minY, minZ, true);
+ shape.addVertex(minX+tw, minY + th, minZ, true);
+ shape.addVertex(minX, minY + th, minZ, true);
+ shape.closeLastOutline(true);
+ }
+
+ protected void createCurvedOutline(final OutlineShape shape, final float zOffset) {
+ final float tw = getWidth();
+ final float th = getHeight();
+ final float dC = 0.5f*corner*Math.min(tw, th);
+
+ final float minX = 0;
+ final float minY = 0;
+ final float minZ = zOffset;
+
+ shape.addVertex(minX, minY + dC, minZ, true);
+ shape.addVertex(minX, minY, minZ, false);
+
+ 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(final float corner) {
+ if(corner > 1.0f){
+ this.corner = 1.0f;
+ }
+ else if(corner < 0.01f){
+ this.corner = 0.0f;
+ }
+ else{
+ this.corner = corner;
+ }
+ markShapeDirty();
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", dim "+getWidth() + " x " + getHeight() + ", corner " + corner;
+ }
+}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/TexSeqButton.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/TexSeqButton.java
new file mode 100644
index 000000000..2f7d85198
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/TexSeqButton.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright 2014-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.shapes;
+
+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.GraphShape;
+import com.jogamp.opengl.util.texture.TextureSequence;
+
+/**
+ * An abstract GraphUI {@link TextureSequence} {@link RoundButton} {@link GraphShape}.
+ * <p>
+ * GraphUI is GPU based and resolution independent.
+ * </p>
+ * <p>
+ * This button is rendered with a round oval shape.
+ * To render it rectangular, {@link #setCorner(float)} to zero.
+ * </p>
+ */
+public abstract class TexSeqButton extends RoundButton {
+ protected final TextureSequence texSeq;
+
+ public TexSeqButton(final int renderModes, final float width,
+ final float height, final TextureSequence texSeq) {
+ super(renderModes | Region.COLORTEXTURE_RENDERING_BIT, width, height);
+ this.texSeq = texSeq;
+ }
+
+ @Override
+ protected GLRegion createGLRegion(final GLProfile glp) {
+ return GLRegion.create(glp, getRenderModes(), texSeq);
+ }
+
+ public final TextureSequence getTextureSequence() { return this.texSeq; }
+
+ @Override
+ protected void addShapeToRegion() {
+ final OutlineShape shape = new OutlineShape(vertexFactory);
+ if(corner == 0.0f) {
+ createSharpOutline(shape, 0f);
+ } else {
+ createCurvedOutline(shape, 0f);
+ }
+ shape.setIsQuadraticNurbs();
+ shape.setSharpness(oshapeSharpness);
+ region.addOutlineShape(shape, null, rgbaColor);
+ box.resize(shape.getBounds());
+
+ setRotationPivot( box.getCenter() );
+
+ if( DEBUG_DRAW ) {
+ System.err.println("XXX.UIShape.TextureSeqButton: Added Shape: "+shape+", "+box);
+ }
+ }
+}