All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.lessvoid.nifty.renderer.jogl.render.font.Font Maven / Gradle / Ivy

The newest version!
package de.lessvoid.nifty.renderer.jogl.render.font;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;

import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GLContext;
import com.jogamp.opengl.fixedfunc.GLMatrixFunc;

import de.lessvoid.nifty.elements.tools.FontHelper;
import de.lessvoid.nifty.renderer.jogl.render.JoglRenderImage;
import de.lessvoid.nifty.tools.Color;
import de.lessvoid.nifty.tools.ColorValueParser;
import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;

/**
 * OpenGL display list based Font.
 *
 * @author void
 */
public class Font {
  /**
   * the font reader.
   */
  @Nonnull
  private final AngelCodeFont font;

  /**
   * textures.
   */
  @Nonnull
  private final JoglRenderImage[] textures;

  private int selectionStart;

  private int selectionEnd;

  private float selectionBackgroundR;

  private float selectionBackgroundG;

  private float selectionBackgroundB;

  private float selectionBackgroundA;

  private float selectionR;

  private float selectionG;

  private float selectionB;

  private float selectionA;

  @Nonnull
  private final Map displayListMap = new HashMap();

  @Nonnull
  private final ColorValueParser colorValueParser = new ColorValueParser();

  /**
   * construct the font.
   */
  public Font(@Nonnull final String filename, @Nonnull final NiftyResourceLoader resourceLoader) {
    selectionStart = -1;
    selectionEnd = -1;
    selectionR = 1.0f;
    selectionG = 0.0f;
    selectionB = 0.0f;
    selectionA = 1.0f;
    selectionBackgroundR = 0.0f;
    selectionBackgroundG = 1.0f;
    selectionBackgroundB = 0.0f;
    selectionBackgroundA = 1.0f;

    // get the angel code font from file
    font = new AngelCodeFont(resourceLoader);
    if (!font.load(filename)) {
      textures = new JoglRenderImage[0];
      return;
    }

    // load textures of font into array
    textures = new JoglRenderImage[font.getTextures().length];
    for (int i = 0; i < font.getTextures().length; i++) {
      textures[i] = new JoglRenderImage(extractPath(filename) + font.getTextures()[i], true, resourceLoader);
    }

    // now build open gl display lists for every character in the font
    initDisplayList();
  }

  /**
   * has selection.
   *
   * @return true or false
   */
  private boolean isSelection() {
    return !(selectionStart == -1 && selectionEnd == -1);
  }

  /**
   * extract the path from the given filename.
   *
   * @param filename file
   * @return path
   */
  @Nonnull
  private String extractPath(@Nonnull final String filename) {
    int idx = filename.lastIndexOf("/");
    if (idx == -1) {
      return "";
    } else {
      return filename.substring(0, idx) + "/";
    }
  }


  private void initDisplayList() {
    displayListMap.clear();
    final GL2 gl = GLContext.getCurrentGL().getGL2();
    // create new list
        /*
      display list id.
     */
    int listId = gl.glGenLists(font.getChars().size());
    Tools.checkGLError("glGenLists");

    // create the list
    int i = 0;
    for (Map.Entry entry : font.getChars().entrySet()) {
      displayListMap.put(entry.getKey(), listId + i);
      gl.glNewList(listId + i, GL2.GL_COMPILE);
      Tools.checkGLError("glNewList");
      CharacterInfo charInfo = entry.getValue();
      if (charInfo != null) {
        gl.glBegin(GL2.GL_QUADS);
        Tools.checkGLError("glBegin");

        float u0 = charInfo.getX() / (float) font.getWidth();
        float v0 = charInfo.getY() / (float) font.getHeight();
        float u1 = (charInfo.getX() + charInfo.getWidth()) / (float) font.getWidth();
        float v1 = (charInfo.getY() + charInfo.getHeight()) / (float) font.getHeight();

        gl.glTexCoord2f(u0, v0);
        gl.glVertex2f(charInfo.getXoffset(), charInfo.getYoffset());

        gl.glTexCoord2f(u0, v1);
        gl.glVertex2f(charInfo.getXoffset(), charInfo.getYoffset() + charInfo.getHeight());

        gl.glTexCoord2f(u1, v1);
        gl.glVertex2f(charInfo.getXoffset() + charInfo.getWidth(), charInfo.getYoffset()
            + charInfo.getHeight());

        gl.glTexCoord2f(u1, v0);
        gl.glVertex2f(charInfo.getXoffset() + charInfo.getWidth(), charInfo.getYoffset());

        gl.glEnd();
        Tools.checkGLError("glEnd");
      }

      // end list
      gl.glEndList();
      Tools.checkGLError("glEndList");
      i++;
    }
  }

  public void drawString(int x, int y, @Nonnull String text) {
    // enableBlend();
    internalRenderText(x, y, text, 1.0f, 1.0f, 1.0f);
    // disableBlend();
  }

  public void drawStringWithSize(int x, int y, @Nonnull String text, float sizeX, float sizeY) {
    // enableBlend();
    internalRenderText(x, y, text, sizeX, sizeY, 1.0f);
    // disableBlend();
  }

  public void renderWithSizeAndColor(
      int x, int y, @Nonnull String text, float sizeX, float sizeY, float r, float g,
      float b, float a) {
    final GL2 gl = GLContext.getCurrentGL().getGL2();
    // enableBlend();
    gl.glColor4f(r, g, b, a);
    internalRenderText(x, y, text, sizeX, sizeY, a);
    // disableBlend();
  }

  private void internalRenderText(
      final int xPos,
      final int yPos,
      @Nonnull final String text,
      final float sizeX,
      final float sizeY,
      final float alpha) {
    final GL2 gl = GLContext.getCurrentGL().getGL2();
    gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
    gl.glPushMatrix();
    gl.glLoadIdentity();

    float normHeightScale = getHeight() * sizeY;
    int x = xPos;

    int activeTextureIdx = -1;

    for (int i = 0; i < text.length(); i++) {
      colorValueParser.isColor(text, i);
      while (colorValueParser.isColor()) {
        Color color = colorValueParser.getColor();
        assert color != null;
        gl.glColor4f(color.getRed(), color.getGreen(), color.getBlue(), alpha);
        i = colorValueParser.getNextIndex();
        if (i >= text.length()) {
          break;
        }
        colorValueParser.isColor(text, i);
      }
      if (i >= text.length()) {
        break;
      }

      char currentc = text.charAt(i);
      char nextc = FontHelper.getNextCharacter(text, i);
      CharacterInfo charInfoC = font.getChar(currentc);

      float characterWidth;
      if (charInfoC != null) {
        int texId = charInfoC.getPage();
        if (activeTextureIdx != texId) {
          activeTextureIdx = texId;
          textures[activeTextureIdx].bind();
        }

        characterWidth = getCharacterWidth(currentc, nextc, sizeX);

        gl.glLoadIdentity();
        gl.glTranslatef(x, yPos, 0.0f);
        gl.glScalef(sizeX, sizeY, 1.0f);

        boolean characterDone = false;
        if (isSelection()) {
          if (i >= selectionStart && i < selectionEnd) {
            gl.glPushAttrib(GL2.GL_CURRENT_BIT);

            disableBlend();
            gl.glDisable(GL.GL_TEXTURE_2D);

            gl.glColor4f(selectionBackgroundR, selectionBackgroundG,
                selectionBackgroundB, selectionBackgroundA);
            gl.glBegin(GL2.GL_QUADS);

            gl.glVertex2i(0, 0);
            gl.glVertex2i((int) characterWidth, 0);
            gl.glVertex2i((int) characterWidth, (int) normHeightScale);
            gl.glVertex2i(0, (int) normHeightScale);

            gl.glEnd();
            gl.glEnable(GL.GL_TEXTURE_2D);
            enableBlend();

            gl.glColor4f(selectionR, selectionG, selectionB, selectionA);
            gl.glCallList(displayListMap.get(currentc));
            Tools.checkGLError("glCallList");
            gl.glPopAttrib();

            characterDone = true;
          }
        }

        if (!characterDone) {
          gl.glCallList(displayListMap.get(currentc));
          Tools.checkGLError("glCallList");
        }

        x += characterWidth;
      }
    }

    gl.glPopMatrix();
  }

  /**
   *
   */
  private void disableBlend() {
    final GL gl = GLContext.getCurrentGL();
    gl.glDisable(GL.GL_BLEND);
  }

  /**
   *
   */
  private void enableBlend() {
    final GL gl = GLContext.getCurrentGL();
    gl.glEnable(GL.GL_BLEND);
    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
  }

  public int getStringWidth(@Nonnull final String text, final float size) {
    return getStringWidthInternal(text, size);
  }

  public int getStringWidth(@Nonnull String text) {
    return getStringWidthInternal(text, 1.0f);
  }

  /**
   * @param text text
   * @param size size
   * @return length
   */
  private int getStringWidthInternal(@Nonnull final String text, final float size) {
    int length = 0;

    for (int i = 0; i < text.length(); i++) {
      colorValueParser.isColor(text, i);
      if (colorValueParser.isColor()) {
        i = colorValueParser.getNextIndex();
        if (i >= text.length()) {
          break;
        }
      }
      char currentCharacter = text.charAt(i);
      char nextCharacter = FontHelper.getNextCharacter(text, i);

      length += getCharacterWidth(currentCharacter, nextCharacter, size);
    }
    return length;
  }

  public int getHeight() {
    return font.getLineHeight();
  }

  public void setSelectionStart(int selectionStart) {
    this.selectionStart = selectionStart;
  }

  public void setSelectionEnd(int selectionEnd) {
    this.selectionEnd = selectionEnd;
  }

  public void setSelectionColor(
      final float selectionR, final float selectionG,
      final float selectionB, final float selectionA) {
    this.selectionR = selectionR;
    this.selectionG = selectionG;
    this.selectionB = selectionB;
    this.selectionA = selectionA;
  }

  public void setSelectionBackgroundColor(
      final float selectionR, final float selectionG,
      final float selectionB, final float selectionA) {
    this.selectionBackgroundR = selectionR;
    this.selectionBackgroundG = selectionG;
    this.selectionBackgroundB = selectionB;
    this.selectionBackgroundA = selectionA;
  }

  /**
   * get character information.
   *
   * @param character char
   * @return CharacterInfo
   */
  public CharacterInfo getChar(final char character) {
    return font.getChar(character);
  }

  /**
   * Return the width of the given character including kerning information.
   *
   * @param currentCharacter current character
   * @param nextCharacter    next character
   * @param size             font size
   * @return width of the character
   */
  public int getCharacterWidth(
      final char currentCharacter, final char nextCharacter,
      final float size) {
    CharacterInfo currentCharacterInfo = font.getChar(currentCharacter);
    if (currentCharacterInfo == null) {
      return 0;
    } else {
      return (int) (currentCharacterInfo.getXadvance() * size + getKerning(
          currentCharacterInfo, nextCharacter));
    }
  }

  public static int getKerning(@Nonnull final CharacterInfo charInfoC, final char nextc) {
    Integer kern = charInfoC.getKerning().get(nextc);
    if (kern != null) {
      return kern;
    }
    return 0;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy