jogl
  1. jogl
  2. JOGL-344

Serious TextRenderer problems involving large fonts & unicode characters

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: current
    • Fix Version/s: milestone 1
    • Component/s: jogl
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      344

      Description

      There are issues with the TextRenderer utility class which causes problems
      involving large fonts and/or long strings of text.

      issue 1) Artifacts appear which distort/obscure the text, and cause the text to
      flip back and forth.

      issue 2) Unicode characters cause the program the crash.

      For a screenshot of issue one, check out this thread:
      http://www.javagaming.org/forums/index.php?topic=18177.0
      (note that this isn't a screen shot of the test code below, but it also exhibits
      the strange behavior).

      Here is some test code (modified from TextCube.java in the JOGL demos). There
      are two cases (uncomment one or the other in the constructor). The first case
      shows that unicode characters crash JOGL if large fonts are used. The second
      case shows the weird artifacts that flip back and forth when using large fonts
      (and no unicode characters).

      import java.awt.BorderLayout;
      import java.awt.Color;
      import java.awt.Font;
      import java.awt.Frame;
      import java.awt.event.*;
      import java.awt.geom.*;

      import javax.media.opengl.*;
      import javax.media.opengl.glu.*;
      import com.sun.opengl.util.*;
      import com.sun.opengl.util.j2d.*;

      /** Test Code adapted from TextCube.java (in JOGL demos) */

      public class WeirdFontTest implements GLEventListener
      {
      GLU glu = new GLU();
      TextRenderer renderer;

      float textScaleFactor;
      String text;
      Font font;
      boolean useMipMaps;

      public WeirdFontTest()

      { //test 1 - unicode hangs program with a large font & long string //font = new Font("default", Font.PLAIN, 200); //text = "\u201Cabcdefghijklmnopqrstuvwxyz\u201D"; //test 2 - weird artifacts appear with a large font & long string font = new Font("default", Font.PLAIN, 200); text = "abcdefghijklmnopqrstuvwxyz1234567890"; useMipMaps = true; //false }

      public static void main(String[] args)
      {
      Frame frame = new Frame("WeirdFontTest");
      frame.setLayout(new BorderLayout());

      GLCanvas canvas = new GLCanvas();
      final WeirdFontTest demo = new WeirdFontTest();

      canvas.addGLEventListener(demo);
      frame.add(canvas, BorderLayout.CENTER);

      frame.setSize(512, 512);
      final Animator animator = new Animator(canvas);
      frame.addWindowListener(new WindowAdapter()
      {
      public void windowClosing(WindowEvent e)
      {
      new Thread(new Runnable()
      {
      public void run()

      { animator.stop(); System.exit(0); }

      }).start();
      }
      });
      frame.show();
      animator.start();
      }

      public void init(GLAutoDrawable drawable)

      { GL gl = drawable.getGL(); gl.glEnable(GL.GL_DEPTH_TEST); renderer = new TextRenderer(font, useMipMaps); Rectangle2D bounds = renderer.getBounds(text); float w = (float) bounds.getWidth(); float h = (float) bounds.getHeight(); textScaleFactor = 2.0f / (w * 1.1f); gl.setSwapInterval(0); }

      public void display(GLAutoDrawable drawable)

      { GL gl = drawable.getGL(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); glu.gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0); renderer.begin3DRendering(); Rectangle2D bounds = renderer.getBounds(text); float w = (float) bounds.getWidth(); float h = (float) bounds.getHeight(); renderer.draw3D(text, w / -2.0f * textScaleFactor, h / -2.0f * textScaleFactor, 3f, textScaleFactor); renderer.end3DRendering(); }

      public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)

      { GL gl = drawable.getGL(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(15, (float) width / (float) height, 5, 15); }

      public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
      boolean deviceChanged)
      {
      }
      }

        Activity

        Hide
        qwerty999 added a comment -

        (changed description slightly)

        Show
        qwerty999 added a comment - (changed description slightly)
        Hide
        kbr added a comment -

        Thanks for the test case. Fixing this is going to require a large reorganization
        of the code in the TextRenderer. I will promote 1.1.1-rc7 with the current code
        and fix this for 1.1.1-rc8.

        Show
        kbr added a comment - Thanks for the test case. Fixing this is going to require a large reorganization of the code in the TextRenderer. I will promote 1.1.1-rc7 with the current code and fix this for 1.1.1-rc8.
        Hide
        kbr added a comment -

        The glyph-based rendering algorithm for the TextRenderer was
        performing rendering in two steps: glyph preparation and upload, and
        rendering. This structure doesn't work in the context of the
        RectanglePacker, which can reorganize the backing store during any
        upload.

        Restructured the glyph cache in the TextRenderer in terms of flyweight
        Glyph objects which know how to upload and render themselves. During
        any upload, the outstanding glyphs not yet rendered to the screen may
        thereby be flushed. Improved the code path which falls back to the
        string-by-string algorithm for complex Unicode characters so that
        incoming strings can be segmented into multiple parts which are
        rendered either using the glyph cache or the string-by-string
        algorithm.

        Also tinkered with the bounds of glyphs and strings on the backing
        store to try to more definitively eliminate bleed-over between
        adjacent characters on the backing store, and to ensure that all of
        the pixels of glyphs are drawn. Some heuristics are unfortunately
        involved but the new code appears to work well with both very large
        and very small fonts.

        Added a few more test cases for the TextRenderer based on the bug
        report. Tested with the previous test cases as well.

        This fix will be in tomorrow's nightly build as well as the forthcoming
        JOGL 1.1.1-rc8.

        Show
        kbr added a comment - The glyph-based rendering algorithm for the TextRenderer was performing rendering in two steps: glyph preparation and upload, and rendering. This structure doesn't work in the context of the RectanglePacker, which can reorganize the backing store during any upload. Restructured the glyph cache in the TextRenderer in terms of flyweight Glyph objects which know how to upload and render themselves. During any upload, the outstanding glyphs not yet rendered to the screen may thereby be flushed. Improved the code path which falls back to the string-by-string algorithm for complex Unicode characters so that incoming strings can be segmented into multiple parts which are rendered either using the glyph cache or the string-by-string algorithm. Also tinkered with the bounds of glyphs and strings on the backing store to try to more definitively eliminate bleed-over between adjacent characters on the backing store, and to ensure that all of the pixels of glyphs are drawn. Some heuristics are unfortunately involved but the new code appears to work well with both very large and very small fonts. Added a few more test cases for the TextRenderer based on the bug report. Tested with the previous test cases as well. This fix will be in tomorrow's nightly build as well as the forthcoming JOGL 1.1.1-rc8.

          People

          • Assignee:
            jogl-issues
            Reporter:
            qwerty999
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: