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;
}
}