diff options
author | Sven Gothel <[email protected]> | 2023-03-31 11:06:44 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-03-31 11:06:44 +0200 |
commit | 4f32f3aba62a73cafecec8af461cff4d0d475882 (patch) | |
tree | 58f6e7f0800a1ca8b793966520d6008cc6f2080b /src/graphui/classes/com/jogamp/graph/ui/shapes | |
parent | 759a381963476e2e64b7afba0d6ef2bafeb35417 (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')
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); + } + } +} |