diff options
author | Kenneth Russel <[email protected]> | 2007-11-03 01:00:36 +0000 |
---|---|---|
committer | Kenneth Russel <[email protected]> | 2007-11-03 01:00:36 +0000 |
commit | 12461ad95b421694706e39ff15eba3bf15e9790b (patch) | |
tree | f007e03aecce0985a159f0fda336bf597d240f3e | |
parent | f58b77c498cd00273fdc4b9fb26a0df55c804476 (diff) |
Fixes from John Burkey:
1) Add segmenting for runs of glyphs that are going to blow the cache
(we track upload size)
a) upload handling
b) glyph run segmenting
2) Fix incorrect assumption that the glyph cached didn't change size.
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/jogl/trunk@1423 232f8b59-042b-4e1e-8c03-345bb8c30851
-rwxr-xr-x | src/classes/com/sun/opengl/util/j2d/TextRenderer.java | 170 |
1 files changed, 117 insertions, 53 deletions
diff --git a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java index 312c99c13..78b193fb7 100755 --- a/src/classes/com/sun/opengl/util/j2d/TextRenderer.java +++ b/src/classes/com/sun/opengl/util/j2d/TextRenderer.java @@ -816,17 +816,21 @@ public class TextRenderer { } } - //---------------------------------------------------------------------- - // Glyph-by-glyph rendering support - // private void internal_draw3D(CharSequence str, float x, float y, float z, float scaleFactor) { - GlyphsList glyphs = mGlyphProducer.getGlyphs(str); - - if (glyphs != null) { - drawGlyphs(glyphs, x, y, z, scaleFactor); - } else { - this.draw3D_ROBUST(str, x, y, z, scaleFactor); + int drawingState = DrawingState.fast; + + while (drawingState != DrawingState.finished) { + GlyphsList glyphs = mGlyphProducer.getGlyphs(str); + + if (drawingState == DrawingState.fast) { + x += drawGlyphs(glyphs, x, y, z, scaleFactor); + str = glyphs.remaining; + drawingState = glyphs.nextState; + } else if (drawingState == DrawingState.robust) { + this.draw3D_ROBUST(str, x, y, z, scaleFactor); + drawingState = DrawingState.finished; + } } } @@ -836,19 +840,19 @@ public class TextRenderer { } } - private void drawGlyphs(GlyphsList inGlyphs, float inX, float inY, float z, - float scaleFactor) { + private float drawGlyphs(GlyphsList inGlyphs, float inX, float inY, + float z, float scaleFactor) { + float xOffset = 0; + try { if (mPipelinedQuadRenderer == null) { mPipelinedQuadRenderer = new Pipelined_QuadRenderer(); } TextureRenderer renderer = getBackingStore(); - float xOffset = 0; for (int i = 0; i < inGlyphs.length; i++) { Rect rect = inGlyphs.textureSourceRect[i]; - TextData data = (TextData) rect.getUserData(); data.markUsed(); @@ -860,11 +864,12 @@ public class TextRenderer { int width = rect.w(); int height = rect.h(); - float tx1 = (float) texturex / (float) kSize; - float ty1 = 1.0f - ((float) texturey / (float) kSize); - float tx2 = (float) (texturex + width) / (float) kSize; + float tx1 = (float) texturex / (float) renderer.getWidth(); + float ty1 = 1.0f - + ((float) texturey / (float) renderer.getHeight()); + float tx2 = (float) (texturex + width) / (float) renderer.getWidth(); float ty2 = 1.0f - - ((float) (texturey + height) / (float) kSize); + ((float) (texturey + height) / (float) renderer.getHeight()); mPipelinedQuadRenderer.glTexCoord2f(tx1, ty1); mPipelinedQuadRenderer.glVertex3f(x, y, z); @@ -883,15 +888,16 @@ public class TextRenderer { } catch (Exception e) { e.printStackTrace(); } - } - private void drawGlyphsSIMPLE(GlyphsList inGlyphs, float x, float y, - float z, float scaleFactor) { // unused, for reference, debugging + return xOffset; + } + private float drawGlyphsSIMPLE(GlyphsList inGlyphs, float x, float y, + float z, float scaleFactor) // unused, for reference, debugging + { TextureRenderer renderer = getBackingStore(); - int xOffset = 0; - GL gl = GLU.getCurrentGL(); + int xOffset = 0; for (int i = 0; i < inGlyphs.length; i++) { Rect rect = inGlyphs.textureSourceRect[i]; @@ -910,6 +916,8 @@ public class TextRenderer { 0.5f); // note the advances.. I had to use this to get proper kerning. } } + + return xOffset; } private void draw3D_ROBUST(CharSequence str, float x, float y, float z, @@ -929,8 +937,7 @@ public class TextRenderer { if (rect == null) { // Rasterize this string and place it on the backing store Graphics2D g = getGraphics2D(); - Rectangle2D bbox = normalize(renderDelegate.getBounds( - curStr, font, getFontRenderContext())); + Rectangle2D bbox = normalize(renderDelegate.getBounds(curStr, font, getFontRenderContext())); Point origin = new Point((int) -bbox.getMinX(), (int) -bbox.getMinY()); rect = new Rect(0, 0, (int) bbox.getWidth(), @@ -1254,6 +1261,7 @@ public class TextRenderer { // Heavy hammer -- might consider doing something different packer.clear(); stringLocations.clear(); + mGlyphProducer.clearAllCacheEntries(); if (DEBUG) { System.err.println( @@ -1264,6 +1272,9 @@ public class TextRenderer { public void beginMovement(Object oldBackingStore, Object newBackingStore) { // Exit the begin / end pair if necessary if (inBeginEndPair) { + // Draw any outstanding glyphs + flush(); + GL gl = GLU.getCurrentGL(); // Pop client attrib bits used by the pipelined quad renderer @@ -1373,6 +1384,15 @@ public class TextRenderer { } } + //---------------------------------------------------------------------- + // Glyph-by-glyph rendering support + // + private static class DrawingState { + public static final int fast = 1; + public static final int robust = 2; + public static final int finished = 3; + } + class GlyphsUploadList { int numberOfNewGlyphs; GlyphVector[] glyphVector; @@ -1437,6 +1457,8 @@ public class TextRenderer { outList.textureSourceRect[this.renderIndex[i]] = mapper.glyphRectForTextureMapping[this.newGlyphs[i]]; } } + + this.numberOfNewGlyphs = 0; } public void allocateSpace(int inLength) { @@ -1453,7 +1475,10 @@ public class TextRenderer { } static class GlyphsList { + int /* DrawingState */ nextState; + CharSequence remaining; float[] advances; + float totalAdvance; Rect[] textureSourceRect; int length; @@ -1489,10 +1514,7 @@ public class TextRenderer { glyphRectForTextureMapping = new Rect[fontLengthInGlyphs]; unicodes2Glyphs = new int[512]; singleUnicode = new char[1]; - - for (int i = 0; i < unicodes2Glyphs.length; i++) { - unicodes2Glyphs[i] = undefined; - } + clearAllCacheEntries(); } } @@ -1500,6 +1522,12 @@ public class TextRenderer { unicodes2Glyphs[unicodeID] = undefined; } + public void clearAllCacheEntries() { + for (int i = 0; i < unicodes2Glyphs.length; i++) { + unicodes2Glyphs[i] = undefined; + } + } + public void allocateSpace(int length) { length = Math.max(length, 100); @@ -1514,27 +1542,40 @@ public class TextRenderer { float getGlyphPixelWidth(char unicodeID) { int glyphID = undefined; - if (unicodeID < unicodes2Glyphs.length) { // <--- could support the rare high unicode better later - glyphID = unicodes2Glyphs[unicodeID]; // Check to see if we have already encountered this unicode - } - - if (glyphID != undefined) { // if we haven't, we must get some its attributes, and prep for upload + if (unicodeID < unicodes2Glyphs.length) // <--- could support the rare high unicode better later + { + glyphID = unicodes2Glyphs[unicodeID]; // Check to see if we have already encountered this unicode + } - return advances[glyphID]; - } else { - tempChars[0] = unicodeID; + if (glyphID != undefined) // if we haven't, we must get some its attributes, and prep for upload + { + return advances[glyphID]; + } else { + tempChars[0] = unicodeID; - GlyphVector fullRunGlyphVector = font.createGlyphVector(fontRenderContext, - tempChars); + GlyphVector fullRunGlyphVector = font.createGlyphVector(fontRenderContext, + tempChars); - return fullRunGlyphVector.getGlyphMetrics(0).getAdvance(); - } + return fullRunGlyphVector.getGlyphMetrics(0).getAdvance(); + } // return -1; } + GlyphsList puntToRobust(CharSequence inString) { + glyphsOutput.nextState = DrawingState.robust; + glyphsOutput.remaining = inString; + + return glyphsOutput; + } + GlyphsList getGlyphs(CharSequence inString) { - glyphsToUpload.numberOfNewGlyphs = 0; + float fontSize = font.getSize(); + + if (fontSize > 128) { + glyphsOutput.nextState = DrawingState.robust; + glyphsOutput.remaining = inString; + } int length = inString.length(); allocateSpace(length); @@ -1547,43 +1588,66 @@ public class TextRenderer { int lengthInGlyphs = fullRunGlyphVector.getNumGlyphs(); if (complex) { - return null; + return puntToRobust(inString); } + TextureRenderer renderer = getBackingStore(); + + float totalAdvanceUploaded = 0; + float cacheSize = renderer.getWidth() * renderer.getHeight(); + for (int i = 0; i < lengthInGlyphs; i++) { + float advance; + char unicodeID = inString.charAt(i); if (unicodeID >= unicodes2Glyphs.length) { // <-- -could support these better - - return null; + return puntToRobust(inString); } int glyphID = unicodes2Glyphs[unicodeID]; // Check to see if we have already encountered this unicode if (glyphID == undefined) { // if we haven't, we must get some its attributes, and prep for upload - GlyphMetrics metrics = fullRunGlyphVector.getGlyphMetrics(i); singleUnicode[0] = unicodeID; GlyphVector gv = font.createGlyphVector(fontRenderContext, singleUnicode); // need this to get single bitmaps glyphID = gv.getGlyphCode(0); + advance = metrics.getAdvance(); + advances[glyphID] = advance; - glyphsToUpload.prepGlyphForUpload(unicodeID, - gv.getGlyphCode(0), - gv.getPixelBounds(fontRenderContext, 0, 0), i, gv); + glyphsToUpload.prepGlyphForUpload(unicodeID, glyphID, + gv.getVisualBounds(), i, gv); - advances[glyphID] = metrics.getAdvance(); + totalAdvanceUploaded += advance; } else { - glyphsOutput.textureSourceRect[i] = glyphRectForTextureMapping[glyphID]; + Rect r = glyphRectForTextureMapping[glyphID]; + glyphsOutput.textureSourceRect[i] = r; + + TextData data = (TextData) r.getUserData(); + data.markUsed(); + + advance = advances[glyphID]; } - glyphsOutput.advances[i] = advances[glyphID]; - } + glyphsOutput.advances[i] = advance; + glyphsOutput.totalAdvance += advance; - glyphsOutput.length = length; + if ((totalAdvanceUploaded * fontSize) > (0.25f * cacheSize)) // note -- if the incoming string is bigger than 1/4 the total font cache, start segmenting glyph stream into bite sized pieces + { + glyphsToUpload.uploadAnyNewGlyphs(glyphsOutput, this); + glyphsOutput.length = i + 1; + glyphsOutput.remaining = inString.subSequence(i + 1, length); + glyphsOutput.nextState = DrawingState.fast; + + return glyphsOutput; + } + } + glyphsOutput.length = lengthInGlyphs; glyphsToUpload.uploadAnyNewGlyphs(glyphsOutput, this); + glyphsOutput.nextState = DrawingState.finished; return glyphsOutput; } |