diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java')
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java index 622ee1b79..46dc73003 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java @@ -41,6 +41,7 @@ package com.jogamp.opengl.util.awt; import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.util.*; import com.jogamp.opengl.util.packrect.*; import com.jogamp.opengl.util.texture.*; @@ -127,7 +128,12 @@ import jogamp.opengl.Debug; @author Kenneth Russell */ public class TextRenderer { - private static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.TextRenderer", true); + private static final boolean DEBUG; + + static { + Debug.initSingleton(); + DEBUG = Debug.isPropertyDefined("jogl.debug.TextRenderer", true); + } // These are occasionally useful for more in-depth debugging private static final boolean DISABLE_GLYPH_CACHE = false; @@ -153,20 +159,20 @@ public class TextRenderer { static final int kTotalBufferSizeBytesTex = kTotalBufferSizeCoordsTex * 4; static final int kSizeInBytes_OneVertices_VertexData = kCoordsPerVertVerts * 4; static final int kSizeInBytes_OneVertices_TexData = kCoordsPerVertTex * 4; - private Font font; - private boolean antialiased; - private boolean useFractionalMetrics; + private final Font font; + private final boolean antialiased; + private final boolean useFractionalMetrics; // Whether we're attempting to use automatic mipmap generation support private boolean mipmap; private RectanglePacker packer; private boolean haveMaxSize; - private RenderDelegate renderDelegate; + private final RenderDelegate renderDelegate; private TextureRenderer cachedBackingStore; private Graphics2D cachedGraphics; private FontRenderContext cachedFontRenderContext; - private Map /*<String,Rect>*/ stringLocations = new HashMap /*<String,Rect>*/(); - private GlyphProducer mGlyphProducer; + private final Map<String, Rect> stringLocations = new HashMap<String, Rect>(); + private final GlyphProducer mGlyphProducer; private int numRenderCycles; @@ -194,10 +200,10 @@ public class TextRenderer { // Debugging purposes only private boolean debugged; Pipelined_QuadRenderer mPipelinedQuadRenderer; - + //emzic: added boolean flag private boolean useVertexArrays = true; - + //emzic: added boolean flag private boolean isExtensionAvailable_GL_VERSION_1_5; private boolean checkFor_isExtensionAvailable_GL_VERSION_1_5; @@ -329,9 +335,9 @@ public class TextRenderer { is made to ensure an accurate bound. */ public Rectangle2D getBounds(CharSequence str) { // FIXME: this should be more optimized and use the glyph cache - Rect r = null; + Rect r = stringLocations.get(str); - if ((r = (Rect) stringLocations.get(str)) != null) { + if (r != null) { TextData data = (TextData) r.getUserData(); // Reconstitute the Java 2D results based on the cached values @@ -701,7 +707,7 @@ public class TextRenderer { /** * emzic: here the call to glBindBuffer crashes on certain graphicscard/driver combinations * this is why the ugly try-catch block has been added, which falls back to the old textrenderer - * + * * @param ortho * @throws GLException */ @@ -744,11 +750,12 @@ public class TextRenderer { } private void clearUnusedEntries() { - final java.util.List deadRects = new ArrayList /*<Rect>*/(); + final java.util.List<Rect> deadRects = new ArrayList<Rect>(); // Iterate through the contents of the backing store, removing // text strings that haven't been used recently packer.visit(new RectVisitor() { + @Override public void visit(Rect rect) { TextData data = (TextData) rect.getUserData(); @@ -760,8 +767,7 @@ public class TextRenderer { } }); - for (Iterator iter = deadRects.iterator(); iter.hasNext();) { - Rect r = (Rect) iter.next(); + for (Rect r : deadRects) { packer.remove(r); stringLocations.remove(((TextData) r.getUserData()).string()); @@ -800,9 +806,7 @@ public class TextRenderer { private void internal_draw3D(CharSequence str, float x, float y, float z, float scaleFactor) { - List/*<Glyph>*/ glyphs = mGlyphProducer.getGlyphs(str); - for (Iterator iter = glyphs.iterator(); iter.hasNext(); ) { - Glyph glyph = (Glyph) iter.next(); + for (Glyph glyph : mGlyphProducer.getGlyphs(str)) { float advance = glyph.draw3D(x, y, z, scaleFactor); x += advance * scaleFactor; } @@ -824,7 +828,7 @@ public class TextRenderer { } // Look up the string on the backing store - Rect rect = (Rect) stringLocations.get(curStr); + Rect rect = stringLocations.get(curStr); if (rect == null) { // Rasterize this string and place it on the backing store @@ -885,7 +889,7 @@ public class TextRenderer { data.markUsed(); Rectangle2D origRect = data.origRect(); - + // Align the leftmost point of the baseline to the (x, y, z) coordinate requested renderer.draw3DRect(x - (scaleFactor * data.origOriginX()), y - (scaleFactor * ((float) origRect.getHeight() - data.origOriginY())), z, @@ -901,18 +905,20 @@ public class TextRenderer { private void debug(GL gl) { dbgFrame = new Frame("TextRenderer Debug Output"); - GLCanvas dbgCanvas = new GLCanvas(new GLCapabilities(gl.getGLProfile()), null, - GLContext.getCurrent(), null); + GLCanvas dbgCanvas = new GLCanvas(new GLCapabilities(gl.getGLProfile())); + dbgCanvas.setSharedContext(GLContext.getCurrent()); dbgCanvas.addGLEventListener(new DebugListener(gl, dbgFrame)); dbgFrame.add(dbgCanvas); final FPSAnimator anim = new FPSAnimator(dbgCanvas, 10); dbgFrame.addWindowListener(new WindowAdapter() { + @Override public void windowClosing(WindowEvent e) { // Run this on another thread than the AWT event queue to // make sure the call to Animator.stop() completes before // exiting new Thread(new Runnable() { + @Override public void run() { anim.stop(); } @@ -1003,12 +1009,14 @@ public class TextRenderer { mCurrentIndex = 0; } + @Override public char last() { mCurrentIndex = Math.max(0, mLength - 1); return current(); } + @Override public char current() { if ((mLength == 0) || (mCurrentIndex >= mLength)) { return CharacterIterator.DONE; @@ -1017,36 +1025,43 @@ public class TextRenderer { return mSequence.charAt(mCurrentIndex); } + @Override public char next() { mCurrentIndex++; return current(); } + @Override public char previous() { mCurrentIndex = Math.max(mCurrentIndex - 1, 0); return current(); } + @Override public char setIndex(int position) { mCurrentIndex = position; return current(); } + @Override public int getBeginIndex() { return 0; } + @Override public int getEndIndex() { return mLength; } + @Override public int getIndex() { return mCurrentIndex; } + @Override public Object clone() { CharSequenceIterator iter = new CharSequenceIterator(mSequence); iter.mCurrentIndex = mCurrentIndex; @@ -1054,6 +1069,7 @@ public class TextRenderer { return iter; } + @Override public char first() { if (mLength == 0) { return CharacterIterator.DONE; @@ -1069,7 +1085,7 @@ public class TextRenderer { static class TextData { // Back-pointer to String this TextData describes, if it // represents a String rather than a single glyph - private String str; + private final String str; // If this TextData represents a single glyph, this is its // unicode ID @@ -1080,7 +1096,7 @@ public class TextRenderer { // 2D coordinate system) at which the string must be rasterized in // order to fit within the rectangle -- the leftmost point of the // baseline. - private Point origin; + private final Point origin; // This represents the pre-normalized rectangle, which fits // within the rectangle on the backing store. We keep a @@ -1088,7 +1104,7 @@ public class TextRenderer { // prevent bleeding of adjacent letters when using GL_LINEAR // filtering for rendering. The origin of this rectangle is // equivalent to the origin above. - private Rectangle2D origRect; + private final Rectangle2D origRect; private boolean used; // Whether this text was used recently @@ -1137,6 +1153,7 @@ public class TextRenderer { class Manager implements BackingStoreManager { private Graphics2D g; + @Override public Object allocateBackingStore(int w, int h) { // FIXME: should consider checking Font's attributes to see // whether we're likely to need to support a full RGBA backing @@ -1159,10 +1176,12 @@ public class TextRenderer { return renderer; } + @Override public void deleteBackingStore(Object backingStore) { ((TextureRenderer) backingStore).dispose(); } + @Override public boolean preExpand(Rect cause, int attemptNumber) { // Only try this one time; clear out potentially obsolete entries // NOTE: this heuristic and the fact that it clears the used bit @@ -1198,6 +1217,7 @@ public class TextRenderer { return false; } + @Override public boolean additionFailed(Rect cause, int attemptNumber) { // Heavy hammer -- might consider doing something different packer.clear(); @@ -1216,10 +1236,12 @@ public class TextRenderer { return false; } + @Override public boolean canCompact() { return true; } + @Override public void beginMovement(Object oldBackingStore, Object newBackingStore) { // Exit the begin / end pair if necessary if (inBeginEndPair) { @@ -1253,6 +1275,7 @@ public class TextRenderer { g = newRenderer.createGraphics(); } + @Override public void move(Object oldBackingStore, Rect oldLocation, Object newBackingStore, Rect newLocation) { TextureRenderer oldRenderer = (TextureRenderer) oldBackingStore; @@ -1274,6 +1297,7 @@ public class TextRenderer { } } + @Override public void endMovement(Object oldBackingStore, Object newBackingStore) { g.dispose(); @@ -1310,10 +1334,12 @@ public class TextRenderer { } public static class DefaultRenderDelegate implements RenderDelegate { + @Override public boolean intensityOnly() { return true; } + @Override public Rectangle2D getBounds(CharSequence str, Font font, FontRenderContext frc) { return getBounds(font.createGlyphVector(frc, @@ -1321,20 +1347,24 @@ public class TextRenderer { frc); } + @Override public Rectangle2D getBounds(String str, Font font, FontRenderContext frc) { return getBounds(font.createGlyphVector(frc, str), frc); } + @Override public Rectangle2D getBounds(GlyphVector gv, FontRenderContext frc) { return gv.getVisualBounds(); } + @Override public void drawGlyphVector(Graphics2D graphics, GlyphVector str, int x, int y) { graphics.drawGlyphVector(str, x, y); } + @Override public void draw(Graphics2D graphics, String str, int x, int y) { graphics.drawString(str, x, y); } @@ -1345,7 +1375,7 @@ public class TextRenderer { // // A temporary to prevent excessive garbage creation - private char[] singleUnicode = new char[1]; + private final char[] singleUnicode = new char[1]; /** A Glyph represents either a single unicode glyph or a substring of characters to be drawn. The reason for the dual @@ -1467,10 +1497,10 @@ public class TextRenderer { int width = (int) origRect.getWidth(); int height = (int) origRect.getHeight(); - float tx1 = xScale * (float) texturex / (float) renderer.getWidth(); + float tx1 = xScale * texturex / renderer.getWidth(); float ty1 = yScale * (1.0f - ((float) texturey / (float) renderer.getHeight())); - float tx2 = xScale * (float) (texturex + width) / (float) renderer.getWidth(); + float tx2 = xScale * (texturex + width) / renderer.getWidth(); float ty2 = yScale * (1.0f - ((float) (texturey + height) / (float) renderer.getHeight())); @@ -1555,9 +1585,9 @@ public class TextRenderer { class GlyphProducer { final int undefined = -2; FontRenderContext fontRenderContext; - List/*<Glyph>*/ glyphsOutput = new ArrayList/*<Glyph>*/(); - HashMap/*<String, GlyphVector>*/fullGlyphVectorCache = new HashMap/*<String, GlyphVector>*/(); - HashMap/*<Character, GlyphMetrics>*/glyphMetricsCache = new HashMap/*<Character, GlyphMetrics>*/(); + List<Glyph> glyphsOutput = new ArrayList<Glyph>(); + HashMap<String, GlyphVector> fullGlyphVectorCache = new HashMap<String, GlyphVector>(); + HashMap<Character, GlyphMetrics> glyphMetricsCache = new HashMap<Character, GlyphMetrics>(); // The mapping from unicode character to font-specific glyph ID int[] unicodes2Glyphs; // The mapping from glyph ID to Glyph @@ -1571,10 +1601,10 @@ public class TextRenderer { clearAllCacheEntries(); } - public List/*<Glyph>*/ getGlyphs(CharSequence inString) { + public List<Glyph> getGlyphs(CharSequence inString) { glyphsOutput.clear(); GlyphVector fullRunGlyphVector; - fullRunGlyphVector = (GlyphVector) fullGlyphVectorCache.get(inString.toString()); + fullRunGlyphVector = fullGlyphVectorCache.get(inString.toString()); if (fullRunGlyphVector == null) { iter.initFromCharSequence(inString); fullRunGlyphVector = font.createGlyphVector(getFontRenderContext(), iter); @@ -1591,7 +1621,7 @@ public class TextRenderer { int i = 0; while (i < lengthInGlyphs) { Character letter = CharacterCache.valueOf(inString.charAt(i)); - GlyphMetrics metrics = (GlyphMetrics) glyphMetricsCache.get(letter); + GlyphMetrics metrics = glyphMetricsCache.get(letter); if (metrics == null) { metrics = fullRunGlyphVector.getGlyphMetrics(i); glyphMetricsCache.put(letter, metrics); @@ -1709,7 +1739,7 @@ public class TextRenderer { return glyph; } } - + private static class CharacterCache { private CharacterCache() { } @@ -1799,7 +1829,7 @@ public class TextRenderer { GL2 gl = GLContext.getCurrentGL().getGL2(); TextureRenderer renderer = getBackingStore(); - Texture texture = renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? + renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? mVertCoords.rewind(); mTexCoords.rewind(); @@ -1842,7 +1872,7 @@ public class TextRenderer { private void drawIMMEDIATE() { if (mOutstandingGlyphsVerticesPipeline > 0) { TextureRenderer renderer = getBackingStore(); - Texture texture = renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? + renderer.getTexture(); // triggers texture uploads. Maybe this should be more obvious? GL2 gl = GLContext.getCurrentGL().getGL2(); gl.glBegin(GL2.GL_QUADS); @@ -1890,6 +1920,7 @@ public class TextRenderer { this.frame = frame; } + @Override public void display(GLAutoDrawable drawable) { GL2 gl = GLContext.getCurrentGL().getGL2(); gl.glClear(GL2.GL_DEPTH_BUFFER_BIT | GL2.GL_COLOR_BUFFER_BIT); @@ -1907,6 +1938,7 @@ public class TextRenderer { if ((frame.getWidth() != w) || (frame.getHeight() != h)) { EventQueue.invokeLater(new Runnable() { + @Override public void run() { frame.setSize(w, h); } @@ -1914,6 +1946,7 @@ public class TextRenderer { } } + @Override public void dispose(GLAutoDrawable drawable) { glu.destroy(); glu=null; @@ -1921,9 +1954,11 @@ public class TextRenderer { } // Unused methods + @Override public void init(GLAutoDrawable drawable) { } + @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { } @@ -1976,7 +2011,7 @@ public class TextRenderer { private final boolean is15Available(GL gl) { if (!checkFor_isExtensionAvailable_GL_VERSION_1_5) { - isExtensionAvailable_GL_VERSION_1_5 = gl.isExtensionAvailable("GL_VERSION_1_5"); + isExtensionAvailable_GL_VERSION_1_5 = gl.isExtensionAvailable(GLExtensions.VERSION_1_5); checkFor_isExtensionAvailable_GL_VERSION_1_5 = true; } return isExtensionAvailable_GL_VERSION_1_5; |