diff --git a/pom.xml b/pom.xml
index 3636cb1..e90e156 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
virtual-cardboard
nengen
- 0.0.3
+ 0.0.4
1.8
@@ -200,6 +200,11 @@
lwjgl-stb
${lwjgl.natives}
+
+ org.lwjgl
+ lwjgl-freetype
+ 3.3.6
+
diff --git a/src/main/java/common/NengenFileUtil.java b/src/main/java/common/NengenFileUtil.java
index 00aac89..07240a3 100644
--- a/src/main/java/common/NengenFileUtil.java
+++ b/src/main/java/common/NengenFileUtil.java
@@ -7,6 +7,8 @@
import static org.lwjgl.stb.STBImage.stbi_failure_reason;
import static org.lwjgl.stb.STBImage.stbi_load;
import static org.lwjgl.stb.STBImage.stbi_set_flip_vertically_on_load;
+import static org.lwjgl.util.freetype.FreeType.FT_New_Face;
+import static visuals.rendering.text.GameFont.getFontIndex;
import java.io.File;
import java.io.FileInputStream;
@@ -14,11 +16,20 @@
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
+import org.lwjgl.PointerBuffer;
+import org.lwjgl.freetype.FT_Bitmap;
+import org.lwjgl.freetype.FT_Face;
+import org.lwjgl.freetype.FT_GlyphSlot;
+import org.lwjgl.freetype.FreeType;
import org.lwjgl.system.MemoryStack;
+import org.lwjgl.util.freetype.FT_Bitmap;
+import org.lwjgl.util.freetype.FT_Face;
+import org.lwjgl.util.freetype.FT_GlyphSlot;
+import org.lwjgl.util.freetype.FreeType;
+
+import javafx.scene.image.Image;
import visuals.lwjgl.render.Texture;
-import visuals.rendering.text.CharacterData;
import visuals.rendering.text.GameFont;
-import visuals.rendering.texture.Image;
public class NengenFileUtil {
@@ -94,7 +105,7 @@ public static GameFont loadFont(File font, Texture texture) {
DEBUG("Characters: " + numCharacters);
DEBUG("Kernings: " + kernings);
- GameFont gameFont = new GameFont(name, fontSize, texture);
+ GameFont gameFont = new GameFont(name, fontSize, texture, getFontIndex());
// Read characters
CharacterData[] characters = gameFont.getCharacterDatas();
@@ -111,7 +122,8 @@ public static GameFont loadFont(File font, Texture texture) {
short page = (short) fis.read();
CharacterData charData = new CharacterData(x, y, width, height, xOffset, yOffset, xAdvance, page);
DEBUG("=====================");
- DEBUG(c + " " + x + " " + y + " " + width + " " + height + " " + xOffset + " " + yOffset + " " + xAdvance + " " + page);
+ DEBUG(c + " " + x + " " + y + " " + width + " " + height + " " + xOffset + " " + yOffset + " "
+ + xAdvance + " " + page);
DEBUG("Character: " + (char) c);
DEBUG("X: " + x);
DEBUG("Y: " + y);
@@ -124,7 +136,8 @@ public static GameFont loadFont(File font, Texture texture) {
characters[c] = charData;
}
CharacterData space = characters[' '];
- characters['\t'] = new CharacterData(space.x(), space.y(), space.width(), space.height(), space.xOffset(), space.yOffset(), (short) (space.xAdvance() * 4), space.getPage());
+ characters['\t'] = new CharacterData(space.x(), space.y(), space.width(), space.height(), space.xOffset(),
+ space.yOffset(), (short) (space.xAdvance() * 4), space.getPage());
return gameFont;
} catch (IOException e) {
@@ -132,6 +145,56 @@ public static GameFont loadFont(File font, Texture texture) {
}
}
+ public static GameFont loadTTF(String ttfFile, int fontSize) {
+ PointerBuffer ftLibrary = PointerBuffer.allocateDirect(10000);
+ FT_Init_FreeType(ftLibrary);
+
+ PointerBuffer ftFaceBuffer = PointerBuffer.allocateDirect(1);
+ ByteBuffer ftFaceByteBuffer = ftFaceBuffer.getByteBuffer(0, 8);
+ FT_Face ftFace = new FT_Face(ftFaceByteBuffer);
+ FT_New_Face(ftLibrary.address(), ttfFile, getFontIndex(), ftFaceBuffer);
+
+ if (false) {
+ throw new RuntimeException("Failed to initialize FreeType library");
+ }
+
+ FreeType.FT_Set_Pixel_Sizes(ftFace, 0, fontSize);
+
+ GameFont gameFont = new GameFont(ttfFile, fontSize, new CharacterData[0], getFontIndex());
+ CharacterData[] characters = gameFont.getCharacterDatas();
+
+ for (int c = 0; c < 128; c++) {
+ if (FreeType.FT_Load_Char(ftFace, c, FreeType.FT_LOAD_RENDER) != 0) {
+ System.err.println("Failed to load Glyph for character: " + (char) c);
+ continue;
+ }
+
+ FT_GlyphSlot glyph = ftFace.glyph();
+ FT_Bitmap bitmap = glyph.bitmap();
+
+ Texture texture = new Texture().dimensions(bitmap.width(), bitmap.rows())
+ .image(new Image().data(bitmap.buffer(100))).load();
+
+ CharacterData charData = new CharacterData(
+ (short) glyph.bitmap_left(),
+ (short) glyph.bitmap_top(),
+ (short) bitmap.width(),
+ (short) bitmap.rows(),
+ (short) glyph.bitmap_left(),
+ (short) glyph.bitmap_top(),
+ (short) glyph.advance().x(),
+ texture);
+ characters[c] = charData;
+ }
+
+ gameFont.characterDatas(characters);
+
+ FreeType.FT_Done_Face(ftFace);
+ FreeType.FT_Done_FreeType(ftLibrary.address());
+
+ return gameFont;
+ }
+
private static short readShort(FileInputStream fis) throws IOException {
byte b1 = (byte) fis.read();
byte b2 = (byte) fis.read();
diff --git a/src/main/java/visuals/rendering/text/CharacterData.java b/src/main/java/visuals/rendering/text/CharacterData.java
index 456a49d..22548c9 100644
--- a/src/main/java/visuals/rendering/text/CharacterData.java
+++ b/src/main/java/visuals/rendering/text/CharacterData.java
@@ -1,7 +1,10 @@
package visuals.rendering.text;
+import visuals.lwjgl.render.Texture;
+
/**
- * Information about a character in a bitmap font. The fields are all in pixels, except for {@link CharacterData#page}.
+ * Information about a character in a bitmap font. The fields are all in pixels,
+ * except for {@link CharacterData#page}.
*
* @author Jay
*/
@@ -24,12 +27,14 @@ public final class CharacterData {
*/
private final int height;
/**
- * The horizontal offset of the character when it is displayed. This is usually a small number.
+ * The horizontal offset of the character when it is displayed. This is usually
+ * a small number.
*/
private final int xOffset;
/**
* The vertical offset of the character when it is displayed.
- * For example, the letter 'g' has a larger yOffset than 'l' because it is offset downwards.
+ * For example, the letter 'g' has a larger yOffset than 'l' because it is
+ * offset downwards.
*/
private final int yOffset;
/**
@@ -39,8 +44,18 @@ public final class CharacterData {
private final int xAdvance;
/**
* The index of the bitmap image that this character is on. This is usually 0.
+ *
+ *
+ * Mutually exclusive with {@link CharacterData#texture}.
+ */
+ private int page;
+ /**
+ * The texture that this character is on.
+ *
+ *
+ * Mutually exclusive with {@link CharacterData#page}.
*/
- private final int page;
+ private Texture texture;
public CharacterData(int x, int y, int width, int height, int xOffset, int yOffset, int xAdvance, int page) {
this.x = x;
@@ -53,10 +68,26 @@ public CharacterData(int x, int y, int width, int height, int xOffset, int yOffs
this.page = page;
}
- public CharacterData(short x, short y, short width, short height, short xOffset, short yOffset, short xAdvance, short page) {
+ public CharacterData(int x, int y, int width, int height, int xOffset, int yOffset, int xAdvance, Texture texture) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.xOffset = xOffset;
+ this.yOffset = yOffset;
+ this.xAdvance = xAdvance;
+ this.texture = texture;
+ }
+
+ public CharacterData(short x, short y, short width, short height, short xOffset, short yOffset, short xAdvance,
+ short page) {
this(x, y, width, height, xOffset, yOffset, xAdvance, (int) page);
}
+ public CharacterData(int x, int y, int width, int height, int xOffset, int yOffset, int xAdvance) {
+ this(x, y, width, height, xOffset, yOffset, xAdvance, 0);
+ }
+
public int x() {
return x;
}
diff --git a/src/main/java/visuals/rendering/text/GameFont.java b/src/main/java/visuals/rendering/text/GameFont.java
index 0618ef5..0656509 100644
--- a/src/main/java/visuals/rendering/text/GameFont.java
+++ b/src/main/java/visuals/rendering/text/GameFont.java
@@ -4,16 +4,39 @@
public final class GameFont {
+ public static long FONT_INDEX = 0;
+
+ /**
+ * The global index of the font.
+ */
+ private final long fontIndex;
+
private final String name;
private final int fontSize;
- private final CharacterData[] characterDatas;
+ private CharacterData[] characterDatas;
private final Texture texture;
- public GameFont(String name, int fontSize, Texture texture) {
+ public GameFont(String name, int fontSize, Texture texture, long fontIndex) {
this.name = name;
this.fontSize = fontSize;
characterDatas = new CharacterData[128];
this.texture = texture;
+ this.fontIndex = fontIndex;
+ }
+
+ public GameFont(String name, int fontSize, CharacterData[] characterDatas, long fontIndex) {
+ this.name = name;
+ this.fontSize = fontSize;
+ this.characterDatas = characterDatas;
+ this.texture = null;
+ this.fontIndex = fontIndex;
+ }
+
+ public GameFont(String name, int fontSize, CharacterData[] characterDatas) {
+ this.name = name;
+ this.fontSize = fontSize;
+ this.characterDatas = characterDatas;
+ this.texture = null;
}
public String getName() {
@@ -28,12 +51,22 @@ public CharacterData[] getCharacterDatas() {
return characterDatas;
}
+ public void characterDatas(CharacterData[] characterDatas) {
+ this.characterDatas = characterDatas;
+ }
+
public Texture texture() {
return texture;
}
public void delete() {
- texture.delete();
+ if (texture != null) {
+ texture.delete();
+ }
+ }
+
+ public static long getFontIndex() {
+ return FONT_INDEX++;
}
}