aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-03-30 04:41:51 +0200
committerSven Gothel <[email protected]>2023-03-30 04:41:51 +0200
commitd959e28119a5a973968d47a988d3dd4b6320db87 (patch)
tree200f7e776d39a1735a495768131575285bd74714 /src/graphui/classes
parent901df212f75db8cf51349f53abeaed6ef62b61d3 (diff)
GraphUI: Add GlyphShape representing a single Font.Glyph as a GraphShape; Use w/ UISceneDemo03 Type Animation...
A list of GlyphShape can be created via GlyphShape.processString(..), which preserves all details incl. intended original unscaled position and its kerning. Whitespace or contourless Glyphs are dropped. A GlyphShape is represented in font em-size [0..1] unscaled. +++ UISceneDemo03 Type Animation - Using GlyphShape and apply scaling via its Shape.setScale() - Recalc fontScale per used text - Refined 'arrival' criteria and smoothing out near target w/ speed-up rotation - Using GraphUIDemoArgs to parse common commandline demo options
Diffstat (limited to 'src/graphui/classes')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java18
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java204
2 files changed, 219 insertions, 3 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java
index 509479cc9..43d174916 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/gl/Shape.java
@@ -209,19 +209,31 @@ public abstract class Shape {
System.arraycopy(pivot, 0, rotPivot, 0, 3);
}
- /** Set scale factor to given scale. */
+ /**
+ * Set scale factor to given scale.
+ * @see #scale(float, float, float)
+ * @see #getScale()
+ */
public final void setScale(final float sx, final float sy, final float sz) {
scale[0] = sx;
scale[1] = sy;
scale[2] = sz;
}
- /** Multiply current scale factor by given scale. */
+ /**
+ * Multiply current scale factor by given scale.
+ * @see #setScale(float, float, float)
+ * @see #getScale()
+ */
public final void scale(final float sx, final float sy, final float sz) {
scale[0] *= sx;
scale[1] *= sy;
scale[2] *= sz;
}
- /** Returns float[3] scale factors. */
+ /**
+ * Returns float[3] scale factors.
+ * @see #setScale(float, float, float)
+ * @see #scale(float, float, float)
+ */
public final float[] getScale() { return scale; }
/** Returns X-axis scale factor. */
public final float getScaleX() { return scale[0]; }
diff --git a/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java b/src/graphui/classes/com/jogamp/graph/ui/gl/shapes/GlyphShape.java
new file mode 100644
index 000000000..07c8ae0de
--- /dev/null
+++ b/src/graphui/classes/com/jogamp/graph/ui/gl/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.gl.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.gl.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 + "'";
+ }
+}