diff --git a/Test.java b/Test.java index e269725..9b9758b 100644 --- a/Test.java +++ b/Test.java @@ -8,9 +8,10 @@ public class Test { var tex2 = window.loadTexture("C:\\art\\pixel stuff.png"); var tileset = window.loadTextureArray("C:\\stream\\coding\\rlc\\tilemap.png", new Vec2i(16, 16)); var font = window.loadFontTileset("EGA8x14.png"); + var font2 = window.loadFontTTF("fonts\\LiberationSans-Regular.ttf", 16*8.f); //img.drawImage(img2, Vec2i.ZERO); var tex = window.loadTexture(img); - window.setDebug(false); + window.setDebug(true); while(!window.shouldClose()) { window.tick(); @@ -30,6 +31,7 @@ public class Test { ); renderContext.drawString(new Vec2i(100, 100), "hello world mew", font); + renderContext.drawString(new Vec2i(710, 140), "hello world mew", font2); window.renderFinish(renderContext); } } diff --git a/com/danitheskunk/skunkworks/BaseRenderContext.java b/com/danitheskunk/skunkworks/BaseRenderContext.java index aff9d46..4645961 100644 --- a/com/danitheskunk/skunkworks/BaseRenderContext.java +++ b/com/danitheskunk/skunkworks/BaseRenderContext.java @@ -17,8 +17,9 @@ abstract class BaseRenderContext implements IRenderContext { for(int i = 0; i < string.length(); ++i) { int ch = buf.get(i); var tex = font.getTexture(ch); - drawTextureRectangle(new Recti(new Vec2i(x, y), tex.getSize()), tex); - x += font.getCharWidth(ch); + var off = font.getOffset(ch); + drawTextureRectangle(new Recti(Vec2i.add(new Vec2i(x, y), off), tex.getSize()), tex); + x += font.getXAdvance(ch); } } } diff --git a/com/danitheskunk/skunkworks/BaseWindow.java b/com/danitheskunk/skunkworks/BaseWindow.java index 75e8e08..418ade3 100644 --- a/com/danitheskunk/skunkworks/BaseWindow.java +++ b/com/danitheskunk/skunkworks/BaseWindow.java @@ -1,5 +1,8 @@ package com.danitheskunk.skunkworks; +import org.lwjgl.stb.STBTTFontinfo; +import static org.lwjgl.stb.STBTruetype.*; + abstract class BaseWindow implements IWindow { protected final Engine engine; @@ -7,6 +10,12 @@ abstract class BaseWindow implements IWindow { this.engine = engine; } + @Override + public Engine getEngine() { + return engine; + } + + @Override public IFont loadFontTileset(String path) { var img = engine.loadImage(path); var charSize = Vec2i.div(img.getSize(), 16); @@ -14,4 +23,12 @@ abstract class BaseWindow implements IWindow { assert tex.size() == 256; return new FontTileset(tex); } + + @Override + public IFont loadFontTTF(String path, float size) { + var bytes = engine.loadBytes(path); + + return new FontTTF(bytes, size, this); + } + } diff --git a/com/danitheskunk/skunkworks/FontTTF.java b/com/danitheskunk/skunkworks/FontTTF.java new file mode 100644 index 0000000..1d3c3d7 --- /dev/null +++ b/com/danitheskunk/skunkworks/FontTTF.java @@ -0,0 +1,111 @@ +package com.danitheskunk.skunkworks; + +import org.lwjgl.BufferUtils; +import org.lwjgl.stb.STBTTFontinfo; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; + +import static org.lwjgl.stb.STBTruetype.*; +import static org.lwjgl.stb.STBTruetype.stbtt_ScaleForPixelHeight; + +public class FontTTF implements IFont { + HashMap chars; + int lineHeight; + float size; + float unscaled_size; + STBTTFontinfo info; + IWindow window; + + FontTTF(ByteBuffer buffer, float size, IWindow window) { + int[] ascent = {0}; + int[] descent = {0}; + int[] lineGap = {0}; + + this.window = window; + this.chars = new HashMap<>(); + this.info = STBTTFontinfo.create(); + + if(!stbtt_InitFont(info, buffer)) { + throw new IllegalStateException("Failed to initialize font information."); + } + //todo: save these + stbtt_GetFontVMetrics(info, ascent, descent, lineGap); + lineHeight = lineGap[0]; + this.unscaled_size = size; + this.size = stbtt_ScaleForPixelHeight(info, size); + + //precache ascii characters + for(int i = 32; i < 128; ++i) + cacheChar(i); + } + + void cacheChar(int ch) { + if(chars.containsKey(ch)) + return; + + int[] width = {0}; + int[] height = {0}; + int[] xoff = {0}; + int[] yoff = {0}; + int[] advanceWidth = {0}; + int[] leftSideBearing = {0}; + ITexture tex; + + var bufmono = stbtt_GetCodepointBitmap(info, size, size, ch, width, height, xoff, yoff); + if(bufmono != null) { + var buf = ByteBuffer.allocate(bufmono.remaining() * 4); + while(bufmono.hasRemaining()) { + var b = bufmono.get(); + buf.put((byte) 0xff); + buf.put((byte) 0xff); + buf.put((byte) 0xff); + buf.put(b); + } + buf.flip(); + tex = window.loadTexture(new Image(buf, new Vec2i(width[0], height[0]))); + } else { + tex = window.loadTexture(new Image(Vec2i.ZERO)); + } + stbtt_GetCodepointHMetrics(info, ch, advanceWidth, leftSideBearing); + var c = new Char(tex, (int)(advanceWidth[0] * size), new Vec2i(xoff[0], yoff[0])); + chars.put(ch, c); + } + + @Override + public int getXAdvance(int ch) { + cacheChar(ch); + return chars.get(ch).advance; + } + + @Override + public int getLineHeight(int ch) { + cacheChar(ch); + return lineHeight; + } + + @Override + public Vec2i getOffset(int ch) { + cacheChar(ch); + return chars.get(ch).off; + } + + @Override + public ITexture getTexture(int ch) { + cacheChar(ch); + return chars.get(ch).tex; + } + + private class Char { + ITexture tex; + int advance; + Vec2i off; + Char(ITexture tex, int advance, Vec2i off) { + this.tex = tex; + this.advance = advance; + this.off = off; + } + } +} diff --git a/com/danitheskunk/skunkworks/FontTileset.java b/com/danitheskunk/skunkworks/FontTileset.java index 419f51c..d1b06df 100644 --- a/com/danitheskunk/skunkworks/FontTileset.java +++ b/com/danitheskunk/skunkworks/FontTileset.java @@ -12,7 +12,7 @@ class FontTileset implements IFont { } @Override - public int getCharWidth(int ch) { + public int getXAdvance(int ch) { return charSize.getX(); } @@ -21,6 +21,11 @@ class FontTileset implements IFont { return charSize.getY(); } + @Override + public Vec2i getOffset(int ch) { + return Vec2i.ZERO; + } + @Override public ITexture getTexture(int ch) { if(ch >= 256 || ch < 0) { diff --git a/com/danitheskunk/skunkworks/IFont.java b/com/danitheskunk/skunkworks/IFont.java index 7803025..b440b04 100644 --- a/com/danitheskunk/skunkworks/IFont.java +++ b/com/danitheskunk/skunkworks/IFont.java @@ -1,7 +1,8 @@ package com.danitheskunk.skunkworks; public interface IFont { - int getCharWidth(int ch); int getLineHeight(int ch); + Vec2i getOffset(int ch); ITexture getTexture(int ch); + int getXAdvance(int ch); } diff --git a/com/danitheskunk/skunkworks/IWindow.java b/com/danitheskunk/skunkworks/IWindow.java index 56fff5c..1e89e77 100644 --- a/com/danitheskunk/skunkworks/IWindow.java +++ b/com/danitheskunk/skunkworks/IWindow.java @@ -3,7 +3,9 @@ package com.danitheskunk.skunkworks; import java.util.List; public interface IWindow { + Engine getEngine(); IFont loadFontTileset(String path); + IFont loadFontTTF(String path, float size); ITexture loadTexture(Image image); ITexture loadTexture(String path); List loadTextureArray(Image image, Vec2i tileSize); diff --git a/com/danitheskunk/skunkworks/Image.java b/com/danitheskunk/skunkworks/Image.java index cb62cf4..5afd7b9 100644 --- a/com/danitheskunk/skunkworks/Image.java +++ b/com/danitheskunk/skunkworks/Image.java @@ -9,7 +9,7 @@ public class Image { private final Vec2i size; //constructors - Image(ByteBuffer buffer) { + Image(ByteBuffer buffer) { //png or similar //todo: resource system int[] x = {0}, y = {0}, n = {0}; var img = STBImage.stbi_load_from_memory(buffer, x, y, n, 4); @@ -24,6 +24,12 @@ public class Image { data = new byte[size.getX() * size.getY() * 4]; } + Image(ByteBuffer buffer, Vec2i size) { + data = new byte[buffer.remaining()]; + buffer.get(data); + this.size = size; + } + //getters public byte[] getData() { return data; diff --git a/fonts/LiberationSans-Bold.ttf b/fonts/LiberationSans-Bold.ttf new file mode 100644 index 0000000..dc5d57f Binary files /dev/null and b/fonts/LiberationSans-Bold.ttf differ diff --git a/fonts/LiberationSans-BoldItalic.ttf b/fonts/LiberationSans-BoldItalic.ttf new file mode 100644 index 0000000..158488a Binary files /dev/null and b/fonts/LiberationSans-BoldItalic.ttf differ diff --git a/fonts/LiberationSans-Italic.ttf b/fonts/LiberationSans-Italic.ttf new file mode 100644 index 0000000..25970d9 Binary files /dev/null and b/fonts/LiberationSans-Italic.ttf differ diff --git a/fonts/LiberationSans-Regular.ttf b/fonts/LiberationSans-Regular.ttf new file mode 100644 index 0000000..e633985 Binary files /dev/null and b/fonts/LiberationSans-Regular.ttf differ