Package br.com.lbbento.glapp

Source Code of br.com.lbbento.glapp.GLFont

package br.com.lbbento.glapp;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.FontMetrics;
import java.awt.image.BufferedImage;

import org.lwjgl.opengl.GL11;

/**
* GLFont uses the Java Font class to create character sets and render text. 
* GLFont can generate text in nearly any size, and in any font that Java supports. 
* <P>
*/
public class GLFont {
  // the font that was used to generate character set
  Font font;
  // display list base for characters
  int fontListBase = -1;
  // texture containing a grid of 100 printable characters
  int fontTextureHandle = 0;
  // these will be set by getFontImageSize() and used by buildFont()
  int fontSize = 0;
  int textureSize = 0;
  // temp values for buildFont()
  static int[] charwidths = new int[100];
 
  /**
   * Dynamically create a texture mapped character set with the given Font. 
   * Text color will be white on a transparent background.
   *
   * @param f   Java Font object
   */
  public GLFont(Font f) {
    makeFont(f, new float[] {1,1,1,1}, new float[] {0,0,0,0} );
  }
 
  /**
   * Create a texture mapped character set with the given Font, 
   * Text color and background color.
   *
   * @param f        Java Font object
   * @param fgColor  foreground (text) color as rgb or rgba values in range 0-1
   * @param bgColor  background color as rgb or rgba values in range 0-1 (set alpha to 0 to make transparent)
   */
  public GLFont(Font f, float[] fgColor, float[] bgColor) {
    makeFont(f, fgColor, bgColor);
  }
 
  /**
   * Return the handle to the texture holding the character set.
   */
  public int getTexture() {
    return fontTextureHandle;
  }
 
  /**
   * Prepare a texture mapped character set with the given Font, text color and background color.
   * Characters will be textured onto quads and stored in display lists.  The base display
   * list id is stored in the fontListBase variable.  After makeFont() is run the print()
   * function can be used to render text in this font.
   *
   * @param f        the font to draw characters
   * @param fgColor  foreground (text) color as rgb or rgba values in range 0-1
   * @param bgColor  background color as rgb or rgba values in range 0-1 (set alpha to 0 to make transparent)
   *
   * @see createFontImage()
   * @see print()
   */
  public void makeFont(Font f, float[] fgColor, float[] bgColor) {
    int charsetTexture = 0;
    if ((charsetTexture=makeFontTexture(f,fgColor,bgColor)) > 0) {
      // create 100 display lists, one for each character
      // textureSize and fontSize are calculated by createFontImage()
      buildFont(charsetTexture, textureSize, fontSize);
      fontTextureHandle = charsetTexture;
      font = f;
    }
  }

  /**
   * Return a texture containing a character set with the given Font arranged in
    * a 10x10 grid of printable characters.
   *
   * @param f        the font to draw characters
   * @param fgColor  foreground (text) color as rgb or rgba values in range 0-1
   * @param bgColor  background color as rgb or rgba values in range 0-1 (set alpha to 0 to make transparent)
   * @see createFontImage()
   * @see print()
   */
  public int makeFontTexture(Font f, float[] fgColor, float[] bgColor) {
    int texture = 0;
    try {
      // Create a BufferedImage containing a 10x10 grid of printable characters
      BufferedImage image = createFontImage(
          f,          // the font
          fgColor,    // text color
          bgColor);   // background color
      // make a texture with the buffered image
      int[] pixelsARGB = GLImage.getImagePixels(image);
      texture = GLApp.makeTexture(pixelsARGB, image.getWidth(), image.getHeight(), false);
    }
    catch (Exception e) {
      System.out.println("makeChar(): exception " + e);
    }
    return texture;
  }

  /**
   * Return a texture containing the given single character with the Courier font. 
   * TO DO: pass Font as a parameter.
   *
   * @param onechar     character to draw into texture
   */
  public static int makeCharTexture(Font f, String onechar, float[] fgColor, float[] bgColor) {
    int texture = 0;
    try {
      // Create a BufferedImage with one character
      BufferedImage image = createCharImage(onechar,
          f,  // the font
          fgColor,       // text
          bgColor);      // background
      // make a texture from the image
      int[] pixelsARGB = GLImage.getImagePixels(image);
      texture = GLApp.makeTexture(pixelsARGB, image.getWidth(), image.getHeight(), false);
    }
    catch (Exception e) {
      System.out.println("makeChar(): exception " + e);
    }
    return texture;
  }
 
  /**
   * return a BufferedImage containing the given character drawn with the given font.
   * Character will be drawn on its baseline, and centered horizontally in the image.
   *
   * @param text     a single character to render
   * @param font     the font to render with
   * @param fgColor  foreground (text) color as rgb or rgba values in range 0-1
   * @param bgColor  background color as rgb or rgba values in range 0-1 (set alpha to 0 to make transparent)
   * @return
   */
  public static BufferedImage createCharImage(String text, Font font, float[] fgColor, float[] bgColor) {
    Color bg = bgColor==null? new Color(0,0,0,0) : (bgColor.length==3? new Color(bgColor[0],bgColor[1],bgColor[2],1) : new Color(bgColor[0],bgColor[1],bgColor[2],bgColor[3]));
    Color fg = fgColor==null? new Color(1,1,1,1) : (fgColor.length==3? new Color(fgColor[0],fgColor[1],fgColor[2],1) : new Color(fgColor[0],fgColor[1],fgColor[2],fgColor[3]));
    boolean isAntiAliased = true;
    boolean usesFractionalMetrics = false;

    // get size of texture image neaded to hold largest character of this font
    int maxCharSize = getFontSize(font);
    int imgSize = GLApp.getPowerOfTwoBiggerThan(maxCharSize);
    if (imgSize > 2048) {
      GLApp.err("GLFont.createCharImage(): texture size will be too big (" + imgSize + ") Make the font size smaller.");
      return null;
    }
   
    // we'll draw text into this image
    BufferedImage image = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
   
    // Clear image with background color (make transparent if color has alpha value)
    if (bg.getAlpha() < 255) {
      g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, (float)bg.getAlpha()/255f));
    }
    g.setColor(bg);
    g.fillRect(0,0,imgSize,imgSize);
   
    // prepare to draw character in foreground color
    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
    g.setColor(fg);
    g.setFont(font);
    g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, isAntiAliased? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, usesFractionalMetrics? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
   
    // place the character (on baseline, centered horizontally)
    FontMetrics fm = g.getFontMetrics();
    int cwidth = fm.charWidth(text.charAt(0));
    int height = fm.getHeight();
    int ascent = fm.getAscent();
    int vborder = (int) ((float)(imgSize - height) / 2f);
    int hborder = (int) ((float)(imgSize - cwidth) / 2f);
    g.drawString(text, hborder, vborder+ascent);
    g.dispose();
   
    return image;
  }
 
 
  /**
   * Return a BufferedImage containing 100 printable characters drawn with the given font.  Characters
   * will be arranged in a 10x10 grid.
   * @param text
   * @param font
   * @param imgSize  a power of two (32 64 256 etc)
   * @param fgColor  foreground (text) color as rgb or rgba values in range 0-1
   * @param bgColor  background color as rgb or rgba values in range 0-1 (set alpha to 0 to make transparent)
   * @return
   */
  public BufferedImage createFontImage(Font font, float[] fgColor, float[] bgColor) {
    Color bg = bgColor==null? new Color(0,0,0,0) : (bgColor.length==3? new Color(bgColor[0],bgColor[1],bgColor[2],1) : new Color(bgColor[0],bgColor[1],bgColor[2],bgColor[3]));
    Color fg = fgColor==null? new Color(1,1,1,1) : (fgColor.length==3? new Color(fgColor[0],fgColor[1],fgColor[2],1) : new Color(fgColor[0],fgColor[1],fgColor[2],fgColor[3]));
    boolean isAntiAliased = true;
    boolean usesFractionalMetrics = false;
   
    // get size of texture image neaded to hold 10x10 character grid
    fontSize = getFontSize(font);
    textureSize = GLApp.getPowerOfTwoBiggerThan(fontSize*10);
    GLApp.msg("GLFont.getFontImageSize(): build font with fontsize=" + fontSize + " gridsize=" + (fontSize*10) + " texturesize=" + textureSize);
    if (textureSize > 2048) {
      GLApp.err("GLFont.createFontImage(): texture size will be too big (" + textureSize + ") Make the font size smaller.");
      return null;
    }
   
    // create a buffered image to hold charset
    BufferedImage image = new BufferedImage(textureSize, textureSize, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
   
    // Clear image with background color (make transparent if color has alpha value)
    if (bg.getAlpha() < 255) {
      g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, (float)bg.getAlpha()/255f));
    }
    g.setColor(bg);
    g.fillRect(0,0,textureSize,textureSize);
   
    // prepare to draw characters in foreground color
    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
    g.setColor(fg);
    g.setFont(font);
    g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, isAntiAliased? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, usesFractionalMetrics? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
   
    // get font measurements
    FontMetrics fm = g.getFontMetrics();
    int ascent = fm.getMaxAscent();

    // draw the grid of 100 characters
    for (int r=0; r < 10; r++) {
      for (int c=0; c < 10; c++) {
        char ch = (char)(32 + ((r*10)+c));
        g.drawString( String.valueOf(ch), (c*fontSize), (r*fontSize)+ascent);
        charwidths[(r*10)+c] = fm.charWidth(ch);
      }
    }
    g.dispose();
   
    return image;
  }

  /**
   * Return the maximum character size of the given Font. This will be the max of
   * the vertical and horizontal font dimensions, so can be used to create a square
   * image large enough to hold any character rendered with this Font. 
   * <P>
   * Creates a BufferedImage and Graphics2D graphics context to get font sizes (is
   * there a more efficient way to do this?).
   * <P>
   * @param font  Font object describes the font to render with
   * @return  power-of-two texture size large enough to hold the character set
   */
  public static int getFontSize(Font font) {
    boolean isAntiAliased = true;
    boolean usesFractionalMetrics = false;
   
    // just a dummy image so we can get a graphics context
    BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
   
    // prepare to draw character
    g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
    g.setFont(font);
    g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, isAntiAliased? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
    g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, usesFractionalMetrics? RenderingHints.VALUE_FRACTIONALMETRICS_ON : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
    g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
   
    // get character measurements
    FontMetrics fm = g.getFontMetrics();
    int ascent = fm.getMaxAscent();
    int descent = fm.getMaxDescent();
    int advance = fm.charWidth('W')// width of widest char, more reliable than getMaxAdvance();
    int leading = fm.getLeading();
   
    // calculate size of 10x10 character grid
    int fontHeight = ascent+descent+(leading/2);
    int fontWidth = advance;
    int maxCharSize = Math.max(fontHeight,fontWidth);
    return maxCharSize;
  }
 
  /**
   * Build the character set display list from the given texture.  Creates
   * one quad for each character, with one letter textured onto each quad.
   * Assumes the texture is a 256x256 image containing every
   * character of the charset arranged in a 16x16 grid.  Each character
   * is 16x16 pixels.  Call destroyFont() to release the display list memory.
   *
   * Should be in ORTHO (2D) mode to render text (see setOrtho()).
   *
   * Special thanks to NeHe and Giuseppe D'Agata for the "2D Texture Font"
   * tutorial (http://nehe.gamedev.net).
   *
   * @param charSetImage   texture image containing 100 characters in a 10x10 grid
   * @param fontWidth      how many pixels to allow per character on screen
   *
   * @see       destroyFont()
   */
  public void buildFont(int fontTxtrHandle, int textureSize, int fontSize)
  {
    int unitSize = fontSize;          // pixel size of one block in 10x10 grid
    float usize = (float)unitSize / (float)(textureSize)// UV size of one block in grid
    float chU, chV;         // character UV position
   
    // Create 100 Display Lists
    fontListBase = GL11.glGenLists(100);
   
    // make a quad for each character in texture
    for (int i = 0; i < 100; i++) {
      int x = (i % 10)// column
      int y = (i / 10)// row
     
      // make character UV coordinate
      // the character V position is tricky because we have to invert the V coord
      // (char # 0 is at top of texture image, but V 0 is at bottom)
      chU = (float) (x*unitSize) / (float) textureSize;
      chV = (float) (textureSize-(y*unitSize)-unitSize) / (float) textureSize;
     
      GL11.glNewList(fontListBase + i, GL11.GL_COMPILE); // start display list
      {
        GL11.glBegin(GL11.GL_QUADS);           // Make A unitSize square quad
        {
          GL11.glTexCoord2f(chU, chV);          // Texture Coord (Bottom Left)
          GL11.glVertex2i(0, 0);
         
          GL11.glTexCoord2f(chU + usize, chV);      // Texture Coord (Bottom Right)
          GL11.glVertex2i(unitSize, 0);
         
          GL11.glTexCoord2f(chU + usize, chV + usize)// Texture Coord (Top Right)
          GL11.glVertex2i(unitSize, unitSize);
         
          GL11.glTexCoord2f(chU, chV + usize);     // Texture Coord (Top Left)
          GL11.glVertex2i(0, unitSize);
         
        }
        GL11.glEnd();                   
        GL11.glTranslatef(charwidths[i], 0, 0);   // shift right the width of the character
      }
      GL11.glEndList();    // done display list
    }
  }

  /**
   * Clean up the allocated display lists for the character set.
   */
  public void destroyFont()
  {
    if (fontListBase != -1) {
      GL11.glDeleteLists(fontListBase,256);
      fontListBase = -1;
    }
  }
 
  /**
   * Render a text string in 2D over the scene, using the character set created
   * by this GLFont object.
   *
   * @see makeFont()
   */
  public void print(int x, int y, String msg)
  {
    if (msg != null) {
      // preserve current GL settings
      GLApp.pushAttribOrtho();
      {
        // turn off lighting
        GL11.glDisable(GL11.GL_LIGHTING);
        // enable alpha blending, so character background is transparent
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        // enable the charset texture
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTextureHandle);
        // prepare to render in 2D
        GLApp.setOrthoOn();
        // draw the text
        GL11.glTranslatef(x, y, 0);        // Position The Text (in pixel coords)
        for(int i=0; i<msg.length(); i++) {
          GL11.glCallList(fontListBase + (msg.charAt(i)-32));
        }
        // restore the original positions and views
        GLApp.setOrthoOff();
      }
      GLApp.popAttrib()// restore previous settings
    }
  }
}
TOP

Related Classes of br.com.lbbento.glapp.GLFont

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.