Finishing up the fonts \o/
This commit is contained in:
parent
5fd1ff4904
commit
96d3c5b345
|
@ -63,6 +63,7 @@ dependencies {
|
||||||
implementation "org.lwjgl:lwjgl-stb"
|
implementation "org.lwjgl:lwjgl-stb"
|
||||||
implementation "org.lwjgl:lwjgl-nfd"
|
implementation "org.lwjgl:lwjgl-nfd"
|
||||||
implementation "org.lwjgl:lwjgl-freetype"
|
implementation "org.lwjgl:lwjgl-freetype"
|
||||||
|
implementation "org.lwjgl:lwjgl-harfbuzz"
|
||||||
implementation "org.lwjgl:lwjgl-nanovg"
|
implementation "org.lwjgl:lwjgl-nanovg"
|
||||||
implementation "org.lwjgl:lwjgl::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl::$lwjglNatives"
|
||||||
implementation "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||||
|
@ -72,6 +73,7 @@ dependencies {
|
||||||
implementation "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||||
implementation "org.lwjgl:lwjgl-nfd::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl-nfd::$lwjglNatives"
|
||||||
implementation "org.lwjgl:lwjgl-freetype::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl-freetype::$lwjglNatives"
|
||||||
|
implementation "org.lwjgl:lwjgl-harfbuzz::$lwjglNatives"
|
||||||
implementation "org.lwjgl:lwjgl-nanovg::$lwjglNatives"
|
implementation "org.lwjgl:lwjgl-nanovg::$lwjglNatives"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ import java.util.function.BiConsumer;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
import org.lwjgl.opengl.GL;
|
import org.lwjgl.opengl.GL;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.system.Configuration;
|
||||||
|
import org.lwjgl.util.freetype.FreeType;
|
||||||
|
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
|
@ -16,8 +18,8 @@ import speiger.src.coreengine.math.vector.matrix.Matrix4f;
|
||||||
import speiger.src.coreengine.rendering.gui.font.Font;
|
import speiger.src.coreengine.rendering.gui.font.Font;
|
||||||
import speiger.src.coreengine.rendering.gui.font.FontManager;
|
import speiger.src.coreengine.rendering.gui.font.FontManager;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.GlythBaker;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.GlythBaker;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
|
@ -62,6 +64,7 @@ public class NewInputTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Configuration.HARFBUZZ_LIBRARY_NAME.set(FreeType.getLibrary());
|
||||||
GLFW.glfwInit();
|
GLFW.glfwInit();
|
||||||
manager.initialize();
|
manager.initialize();
|
||||||
Mouse.INSTANCE.init(bus);
|
Mouse.INSTANCE.init(bus);
|
||||||
|
@ -69,7 +72,7 @@ public class NewInputTest {
|
||||||
Joystick.INSTANCE.init(manager, bus);
|
Joystick.INSTANCE.init(manager, bus);
|
||||||
FileDrop.INSTANCE.init(bus);
|
FileDrop.INSTANCE.init(bus);
|
||||||
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
|
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
|
||||||
Window window = manager.builder().title("Testing Engine").antialis(16).build();
|
Window window = manager.builder().title("Testing Engine").antialis(1).build();
|
||||||
shaderTest.register();
|
shaderTest.register();
|
||||||
guiShader.register();
|
guiShader.register();
|
||||||
assets.addListener(GLStateTracker.instance().shaders);
|
assets.addListener(GLStateTracker.instance().shaders);
|
||||||
|
@ -82,7 +85,6 @@ public class NewInputTest {
|
||||||
|
|
||||||
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/roboto/font.json"), assets);
|
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/roboto/font.json"), assets);
|
||||||
guiShader.get().proView.set(new Matrix4f().ortho(0, 0, window.width(), window.height(), 1000, -1000));
|
guiShader.get().proView.set(new Matrix4f().ortho(0, 0, window.width(), window.height(), 1000, -1000));
|
||||||
guiShader.get().model.set(new Matrix4f().scale(1.1F));
|
|
||||||
|
|
||||||
int size = 512;
|
int size = 512;
|
||||||
int half = size >> 1;
|
int half = size >> 1;
|
||||||
|
@ -109,7 +111,7 @@ public class NewInputTest {
|
||||||
T.cancel();
|
T.cancel();
|
||||||
System.out.println("Testing");
|
System.out.println("Testing");
|
||||||
// texture.bind();
|
// texture.bind();
|
||||||
GlythData data = provider.glythData("C".codePointAt(0), 0, 18.5F, 2F);
|
UnbakedGlyth data = provider.glythData("C".codePointAt(0), 0, 18.5F, 2F);
|
||||||
data.bake(new GlythBaker() {
|
data.bake(new GlythBaker() {
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(IGlythSheetInfo info) {
|
public Glyth bake(IGlythSheetInfo info) {
|
||||||
|
@ -145,27 +147,28 @@ public class NewInputTest {
|
||||||
builder.pos(-0.5F, 0.5F, 0).tex(0F, 0F).rgba(-1).endVertex();
|
builder.pos(-0.5F, 0.5F, 0).tex(0F, 0F).rgba(-1).endVertex();
|
||||||
builder.pos(-0.5F, -0.5F, 0).tex(0F, 1F).rgba(-1).endVertex();
|
builder.pos(-0.5F, -0.5F, 0).tex(0F, 1F).rgba(-1).endVertex();
|
||||||
|
|
||||||
Font font = fonts.createFont(18F, 4F);
|
Font font = fonts.createFont(18F, 1F);
|
||||||
TestModel model = new TestModel(builder.getBytes());
|
TestModel model = new TestModel(builder.getBytes());
|
||||||
TestModel[] guiModel = new TestModel[1];
|
TestModel[] guiModel = new TestModel[1];
|
||||||
List<GLDraw> draws = new ObjectArrayList<>();
|
List<GLDraw> draws = new ObjectArrayList<>();
|
||||||
font.drawText("Testing my Text", 50, 50, -1, new TexturedBuffer((K, V) -> {
|
font.drawText("The Quick brown fox Jumps over the Lazy dog", 50, 50, -1, new TexturedBuffer((K, V) -> {
|
||||||
draws.addAll(K);
|
draws.addAll(K);
|
||||||
guiModel[0] = new TestModel(V);
|
guiModel[0] = new TestModel(V);
|
||||||
System.out.println("Testing: "+V.length+" bytes, "+K.size());
|
System.out.println("Testing: "+V.length+" bytes, "+K.size());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
GLStateTracker tracker = GLStateTracker.instance();
|
GLStateTracker tracker = GLStateTracker.instance();
|
||||||
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
|
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
|
||||||
while(!window.shouldClose()) {
|
while(!window.shouldClose()) {
|
||||||
GLFW.glfwPollEvents();
|
GLFW.glfwPollEvents();
|
||||||
window.beginFrame();
|
window.beginFrame();
|
||||||
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||||
// texture.bind();
|
texture.bind();
|
||||||
// shaderTest.bind();
|
shaderTest.bind();
|
||||||
// model.bindArray();
|
model.bindArray();
|
||||||
// GLStateTracker.drawArrays(GLMode.TRIANGLES.glValue(), 6);
|
GLStateTracker.drawArrays(GLMode.TRIANGLES.glValue(), 6);
|
||||||
// model.unbindArray();
|
model.unbindArray();
|
||||||
guiModel[0].bindArray();
|
guiModel[0].bindArray();
|
||||||
guiShader.bind();
|
guiShader.bind();
|
||||||
for(GLDraw draw : draws) {
|
for(GLDraw draw : draws) {
|
||||||
|
@ -206,7 +209,6 @@ public class NewInputTest {
|
||||||
draws.add(new GLDraw(previousId, lastVertex, count));
|
draws.add(new GLDraw(previousId, lastVertex, count));
|
||||||
lastVertex+=count;
|
lastVertex+=count;
|
||||||
previousId = textureId;
|
previousId = textureId;
|
||||||
System.out.println("Texture: "+textureId);
|
|
||||||
}
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
@ -228,7 +230,6 @@ public class NewInputTest {
|
||||||
public static class GuiShader extends SimpleShader {
|
public static class GuiShader extends SimpleShader {
|
||||||
public TextureUniform texture = uniforms.addTexture("texture", 0);
|
public TextureUniform texture = uniforms.addTexture("texture", 0);
|
||||||
public Matrix4fUniform proView = uniforms.addMat("proViewMatrix", new Matrix4f());
|
public Matrix4fUniform proView = uniforms.addMat("proViewMatrix", new Matrix4f());
|
||||||
public Matrix4fUniform model = uniforms.addMat("modelmatrix", new Matrix4f());
|
|
||||||
|
|
||||||
public GuiShader(IAssetProvider provider) {
|
public GuiShader(IAssetProvider provider) {
|
||||||
super(provider, "gui_shader", AssetLocation.of("shader/testGui/vertex.vs"), AssetLocation.of("shader/testGui/fragment.fs"), "in_position", "in_tex", "in_color");
|
super(provider, "gui_shader", AssetLocation.of("shader/testGui/vertex.vs"), AssetLocation.of("shader/testGui/fragment.fs"), "in_position", "in_tex", "in_color");
|
||||||
|
|
|
@ -6,8 +6,8 @@ import java.util.function.Consumer;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.GlythBaker;
|
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.GlythBaker;
|
||||||
import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder;
|
import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder;
|
||||||
|
|
||||||
public class Font {
|
public class Font {
|
||||||
|
@ -19,6 +19,7 @@ public class Font {
|
||||||
float oversample;
|
float oversample;
|
||||||
GlythCache[] styledCache = new GlythCache[] {new GlythCache(this, 0), new GlythCache(this, 1), new GlythCache(this, 2), new GlythCache(this, 3)};
|
GlythCache[] styledCache = new GlythCache[] {new GlythCache(this, 0), new GlythCache(this, 1), new GlythCache(this, 2), new GlythCache(this, 3)};
|
||||||
MissingGlyth missingGlyth;
|
MissingGlyth missingGlyth;
|
||||||
|
GlythData missingData;
|
||||||
|
|
||||||
protected Font(Map<AssetLocation, FontGroup> fonts, GlythBaker baker, float size, float oversample, Consumer<Runnable> clearing) {
|
protected Font(Map<AssetLocation, FontGroup> fonts, GlythBaker baker, float size, float oversample, Consumer<Runnable> clearing) {
|
||||||
this.fonts = fonts;
|
this.fonts = fonts;
|
||||||
|
@ -26,6 +27,7 @@ public class Font {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.oversample = oversample;
|
this.oversample = oversample;
|
||||||
this.missingGlyth = new MissingGlyth(size, oversample * 2F);
|
this.missingGlyth = new MissingGlyth(size, oversample * 2F);
|
||||||
|
missingData = new GlythData(missingGlyth);
|
||||||
clearing.accept(this::reset);
|
clearing.accept(this::reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@ public class Font {
|
||||||
styledCache[i].reset();
|
styledCache[i].reset();
|
||||||
}
|
}
|
||||||
missingGlyth.cleanCache();
|
missingGlyth.cleanCache();
|
||||||
|
missingData.cleanCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData data(AssetLocation font, int codepoint, int style) {
|
public GlythData data(AssetLocation font, int codepoint, int style) {
|
||||||
|
@ -54,7 +57,7 @@ public class Font {
|
||||||
int codepoint = text.codePointAt(i);
|
int codepoint = text.codePointAt(i);
|
||||||
GlythData data = data(DEFAULT, codepoint, 0);
|
GlythData data = data(DEFAULT, codepoint, 0);
|
||||||
if(previousCodepoint != -1) {
|
if(previousCodepoint != -1) {
|
||||||
x += data.kernling(previousCodepoint);
|
x -= data.kerning(previousCodepoint);
|
||||||
}
|
}
|
||||||
Glyth glyth = glyth(DEFAULT, codepoint, 0);
|
Glyth glyth = glyth(DEFAULT, codepoint, 0);
|
||||||
if(glyth.isValid()) {
|
if(glyth.isValid()) {
|
||||||
|
@ -63,8 +66,6 @@ public class Font {
|
||||||
float maxX = glyth.right() + x;
|
float maxX = glyth.right() + x;
|
||||||
float maxY = glyth.bottom() + y;
|
float maxY = glyth.bottom() + y;
|
||||||
|
|
||||||
// System.out.println("Test: MinX="+minX+", MinY="+minY+", MaxX="+maxX+", MaxY="+maxY+", MinU="+glyth.minU()+", MinV="+glyth.minV()+", MaxU="+glyth.maxU()+", MaxV="+glyth.maxV());
|
|
||||||
|
|
||||||
IVertexBuilder builder = buffer.builderForTexture(glyth.texture());
|
IVertexBuilder builder = buffer.builderForTexture(glyth.texture());
|
||||||
builder.pos(minX, minY, 0F).tex(glyth.minU(), glyth.minV()).rgba(-1).endVertex();
|
builder.pos(minX, minY, 0F).tex(glyth.minU(), glyth.minV()).rgba(-1).endVertex();
|
||||||
builder.pos(maxX, minY, 0F).tex(glyth.maxU(), glyth.minV()).rgba(-1).endVertex();
|
builder.pos(maxX, minY, 0F).tex(glyth.maxU(), glyth.minV()).rgba(-1).endVertex();
|
||||||
|
|
|
@ -3,7 +3,7 @@ package speiger.src.coreengine.rendering.gui.font;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
|
|
||||||
public class FontGroup {
|
public class FontGroup {
|
||||||
|
@ -15,9 +15,9 @@ public class FontGroup {
|
||||||
this.providers = providers;
|
this.providers = providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData data(int codepoint, int style, float size, float oversample) {
|
public UnbakedGlyth data(int codepoint, int style, float size, float oversample) {
|
||||||
for(int i = 0,m=providers.size();i<m;i++) {
|
for(int i = 0,m=providers.size();i<m;i++) {
|
||||||
GlythData data = providers.get(i).glythData(codepoint, style, size, oversample);
|
UnbakedGlyth data = providers.get(i).glythData(codepoint, style, size, oversample);
|
||||||
if(data != null) return data;
|
if(data != null) return data;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -18,12 +18,13 @@ import speiger.src.coreengine.assets.base.MultiAsset;
|
||||||
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
|
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.providers.FreeTypeProvider;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
||||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||||
|
|
||||||
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
|
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
|
||||||
private static final int TEXTURE_SIZE = 512;
|
private static final int TEXTURE_SIZE = 4096;
|
||||||
private static final AssetFilter FILTER = AssetFilter.json("font");
|
private static final AssetFilter FILTER = AssetFilter.json("font");
|
||||||
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
|
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
|
||||||
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
|
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
|
||||||
|
@ -32,6 +33,7 @@ public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, Objec
|
||||||
|
|
||||||
public FontManager() {
|
public FontManager() {
|
||||||
registerParser("stb-ttf", STBTrueTypeProvider::create);
|
registerParser("stb-ttf", STBTrueTypeProvider::create);
|
||||||
|
registerParser("free-ttf", FreeTypeProvider::load);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
|
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
|
||||||
|
|
|
@ -63,7 +63,6 @@ public class FontTexture extends BaseTexture {
|
||||||
float maxU = (float)((result.x) + info.width()) / (float)bounds;
|
float maxU = (float)((result.x) + info.width()) / (float)bounds;
|
||||||
float minV = (float)(result.y) / (float)bounds;
|
float minV = (float)(result.y) / (float)bounds;
|
||||||
float maxV = (float)((result.y) + info.height()) / (float)bounds;
|
float maxV = (float)((result.y) + info.height()) / (float)bounds;
|
||||||
System.out.println("Baking: MinU="+minU+", MinV="+minV+", MaxU="+maxU+", MaxV="+maxV+", "+result.x+", "+result.y);
|
|
||||||
return new Glyth(id(), minU, minV, maxU, maxV, info.left(), info.right(), info.top(), info.bottom());
|
return new Glyth(id(), minU, minV, maxU, maxV, info.left(), info.right(), info.top(), info.bottom());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
|
|
||||||
public class GlythCache {
|
public class GlythCache {
|
||||||
private Font font;
|
private Font font;
|
||||||
|
@ -53,12 +54,12 @@ public class GlythCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlythData compute(int codepoint) {
|
private GlythData compute(int codepoint) {
|
||||||
GlythData data = font.font(fontId).data(codepoint, style, font.size, font.oversample);
|
UnbakedGlyth data = font.font(fontId).data(codepoint, style, font.size, font.oversample);
|
||||||
return data == null ? font.missingGlyth : data;
|
return data == null ? font.missingData : new GlythData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Glyth bake(int codepoint) {
|
private Glyth bake(int codepoint) {
|
||||||
return data(codepoint).bake(font.baker);
|
return data(codepoint).unbaked().bake(font.baker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,20 +1,19 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.glyth;
|
package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
public interface GlythData {
|
import speiger.src.collections.ints.maps.impl.hash.Int2FloatOpenHashMap;
|
||||||
public float advance();
|
import speiger.src.collections.ints.maps.interfaces.Int2FloatMap;
|
||||||
public float kernling(int codepoint);
|
|
||||||
public default float shadowOffset() { return 1F; }
|
|
||||||
public Glyth bake(GlythBaker baker);
|
|
||||||
|
|
||||||
|
public class GlythData {
|
||||||
|
UnbakedGlyth data;
|
||||||
|
Int2FloatMap kernings = new Int2FloatOpenHashMap();
|
||||||
|
|
||||||
public static record EmptyGlythData(float advance) implements GlythData {
|
public GlythData(UnbakedGlyth data) {
|
||||||
@Override
|
this.data = data;
|
||||||
public Glyth bake(GlythBaker baker) { return Glyth.EMPTY; }
|
|
||||||
@Override
|
|
||||||
public float kernling(int codepoint) { return 0F; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface GlythBaker {
|
public float advance() { return data.advance(); }
|
||||||
Glyth bake(IGlythSheetInfo info);
|
public float shadowOffset() { return data.shadowOffset(); }
|
||||||
}
|
public float kerning(int codepoint) { return kernings.computeFloatIfAbsent(codepoint, data::kerning); }
|
||||||
|
public UnbakedGlyth unbaked() { return data; }
|
||||||
|
public void cleanCache() { kernings.clear(); }
|
||||||
}
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.glyth;
|
|
||||||
|
|
||||||
import speiger.src.collections.ints.functions.function.Int2FloatFunction;
|
|
||||||
import speiger.src.collections.ints.maps.impl.hash.Int2FloatOpenHashMap;
|
|
||||||
import speiger.src.collections.ints.maps.interfaces.Int2FloatMap;
|
|
||||||
|
|
||||||
public class GlythDataOld {
|
|
||||||
float advance;
|
|
||||||
float shadowOffset;
|
|
||||||
Int2FloatMap kernlings = new Int2FloatOpenHashMap();
|
|
||||||
Int2FloatFunction kernling;
|
|
||||||
|
|
||||||
public GlythDataOld(float advance, float shadowOffset, Int2FloatFunction kernling) {
|
|
||||||
this.advance = advance;
|
|
||||||
this.shadowOffset = shadowOffset;
|
|
||||||
this.kernling = kernling;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GlythDataOld(GlythData glyth) {
|
|
||||||
this(glyth.advance(), glyth.shadowOffset(), glyth::kernling);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float advance() { return advance; }
|
|
||||||
public float shadowOffset() { return shadowOffset; }
|
|
||||||
public float kernling(int codepoint) { return kernlings.computeFloatIfAbsent(codepoint, kernling); }
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import speiger.src.coreengine.math.MathUtils;
|
||||||
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||||
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
|
|
||||||
public class MissingGlyth implements GlythData {
|
public class MissingGlyth implements UnbakedGlyth {
|
||||||
private static final int WIDTH = 10;
|
private static final int WIDTH = 10;
|
||||||
private static final int HEIGHT = 57;
|
private static final int HEIGHT = 57;
|
||||||
float size;
|
float size;
|
||||||
|
@ -31,7 +31,7 @@ public class MissingGlyth implements GlythData {
|
||||||
@Override
|
@Override
|
||||||
public float advance() { return advance; }
|
public float advance() { return advance; }
|
||||||
@Override
|
@Override
|
||||||
public float kernling(int codepoint) { return 0; }
|
public float kerning(int codepoint) { return 0; }
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(GlythBaker baker) {
|
public Glyth bake(GlythBaker baker) {
|
||||||
if(cached == null) {
|
if(cached == null) {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
|
public interface UnbakedGlyth {
|
||||||
|
public float advance();
|
||||||
|
public float kerning(int codepoint);
|
||||||
|
public default float shadowOffset() { return 1F; }
|
||||||
|
public Glyth bake(GlythBaker baker);
|
||||||
|
|
||||||
|
|
||||||
|
public static record EmptyGlythData(float advance) implements UnbakedGlyth {
|
||||||
|
@Override
|
||||||
|
public Glyth bake(GlythBaker baker) { return Glyth.EMPTY; }
|
||||||
|
@Override
|
||||||
|
public float kerning(int codepoint) { return 0F; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface GlythBaker {
|
||||||
|
Glyth bake(IGlythSheetInfo info);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +1,297 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.providers;
|
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||||
|
|
||||||
import org.lwjgl.util.freetype.FreeType;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import org.lwjgl.PointerBuffer;
|
||||||
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
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.FT_Vector;
|
||||||
|
import org.lwjgl.util.freetype.FreeType;
|
||||||
|
import org.lwjgl.util.harfbuzz.HarfBuzz;
|
||||||
|
import org.lwjgl.util.harfbuzz.hb_glyph_position_t;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
||||||
|
import speiger.src.collections.ints.sets.IntSet;
|
||||||
|
import speiger.src.collections.longs.misc.pairs.LongObjectPair;
|
||||||
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
|
import speiger.src.coreengine.assets.base.IAsset;
|
||||||
|
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||||
|
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
|
||||||
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
|
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||||
|
|
||||||
public class FreeTypeProvider implements IFontProvider {
|
public class FreeTypeProvider implements IFontProvider {
|
||||||
|
|
||||||
public void test() {
|
FreeTypeInstance[] instance;
|
||||||
|
|
||||||
|
public FreeTypeProvider(FreeTypeInstance[] instance) {
|
||||||
|
this.instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
|
||||||
|
try(IAsset asset = provider.getAsset(location)) {
|
||||||
|
return load(asset.json(), provider);
|
||||||
|
}
|
||||||
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFontProvider load(JsonObject data, IAssetProvider provider) {
|
||||||
|
long library = FreeTypeLibrary.get();
|
||||||
|
if(library == 0L) return null;
|
||||||
|
FreeTypeInstance[] instances = new FreeTypeInstance[4];
|
||||||
|
instances[0] = create(library, 0, data.getAsJsonObject("regular"), provider);
|
||||||
|
if(instances[0] == null) return null;
|
||||||
|
instances[1] = create(library, 1, data.getAsJsonObject("bold"), provider);
|
||||||
|
instances[2] = create(library, 2, data.getAsJsonObject("italic"), provider);
|
||||||
|
instances[3] = create(library, 3, data.getAsJsonObject("bold_italic"), provider);
|
||||||
|
return new FreeTypeProvider(instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FreeTypeInstance create(long library, int style, JsonObject obj, IAssetProvider provider) {
|
||||||
|
if(obj == null || !obj.has("file")) return null;
|
||||||
|
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
||||||
|
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
|
||||||
|
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
|
||||||
|
float xOff = 0;
|
||||||
|
float yOff = 0;
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
JsonObject shift = obj.getAsJsonObject("offset");
|
||||||
|
if(shift != null) {
|
||||||
|
xOff = JsonUtil.getOrDefault(shift, "x", 0F);
|
||||||
|
yOff = JsonUtil.getOrDefault(shift, "y", 0F);
|
||||||
|
}
|
||||||
|
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
|
||||||
|
LongObjectPair<FT_Face> value = parse(location, provider, library);
|
||||||
|
if(value == null) return null;
|
||||||
|
return new FreeTypeInstance(style, value.getLongKey(), value.getValue(), oversample, xOff, yOff, shadowOffset, builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LongObjectPair<FT_Face> parse(AssetLocation location, IAssetProvider provider, long library) {
|
||||||
|
try(IAsset asset = provider.getAsset(location); MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
|
||||||
|
PointerBuffer facePointer = stack.mallocPointer(1);
|
||||||
|
if(FreeTypeLibrary.parseError(FreeType.FT_New_Memory_Face(library, buffer, 0L, facePointer), "Creating Font Face")) {
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FT_Face face = FT_Face.create(facePointer.get());
|
||||||
|
String s = FreeType.FT_Get_Font_Format(face);
|
||||||
|
if(!"TrueType".equals(s)) {
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
throw new IllegalStateException("Font type ["+s+"] is not true type");
|
||||||
|
}
|
||||||
|
if(FreeTypeLibrary.parseError(FreeType.FT_Select_Charmap(face, FreeType.FT_ENCODING_UNICODE), "Applying Unicode Encoding")) {
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return LongObjectPair.of(MemoryUtil.memAddress(buffer), face);
|
||||||
|
}
|
||||||
|
catch(Exception exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlythData glythData(int codepoint, int style, float size, float oversample) {
|
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
|
||||||
return null;
|
return instance[style & 0x3].gylthData(codepoint, size, oversample);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
for(int i = 0;i<4;i++) {
|
||||||
|
if(instance[i] != null) {
|
||||||
|
instance[i].free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FreeTypeGlyth implements UnbakedGlyth {
|
||||||
|
final FT_Face face;
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final float xOff;
|
||||||
|
final float yOff;
|
||||||
|
final float oversample;
|
||||||
|
private final float advance;
|
||||||
|
final int glyth;
|
||||||
|
final int glythCodepoint;
|
||||||
|
final long harfBuzzFont;
|
||||||
|
|
||||||
|
public FreeTypeGlyth(FT_Face face, long harfBuzzFont, float xOff, float yOff, int width, int height, float advance, float oversample, int glyth, int glythCodepoint) {
|
||||||
|
this.face = face;
|
||||||
|
this.harfBuzzFont = harfBuzzFont;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.oversample = oversample;
|
||||||
|
this.advance = advance / oversample;
|
||||||
|
this.xOff = xOff / oversample;
|
||||||
|
this.yOff = yOff / oversample;
|
||||||
|
this.glyth = glyth;
|
||||||
|
this.glythCodepoint = glythCodepoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float advance() {
|
||||||
|
return advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float kerning(int codepoint) {
|
||||||
|
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||||
|
if(index == 0) return 0;
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(Character.toChars(codepoint));
|
||||||
|
builder.append(Character.toChars(glythCodepoint));
|
||||||
|
float hbresult = (getAdvance(Character.toString(codepoint)) - getAdvance(builder.toString())) / 64F;
|
||||||
|
return hbresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getAdvance(String adv) {
|
||||||
|
long id = HarfBuzz.hb_buffer_create();
|
||||||
|
try {
|
||||||
|
HarfBuzz.hb_buffer_add_utf8(id, adv, 0, adv.length());
|
||||||
|
HarfBuzz.hb_buffer_guess_segment_properties(id);
|
||||||
|
HarfBuzz.hb_shape(harfBuzzFont, id, null);
|
||||||
|
hb_glyph_position_t.Buffer positions = HarfBuzz.hb_buffer_get_glyph_positions(id);
|
||||||
|
float result = positions.hasRemaining() ? positions.x_advance() : 0F;
|
||||||
|
HarfBuzz.hb_buffer_destroy(positions.address());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
HarfBuzz.hb_buffer_destroy(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Glyth bake(GlythBaker baker) {
|
||||||
|
return baker.bake(new IGlythSheetInfo() {
|
||||||
|
@Override
|
||||||
|
public float xOffset() { return xOff; }
|
||||||
|
@Override
|
||||||
|
public float yOffset() { return yOff; }
|
||||||
|
@Override
|
||||||
|
public int width() { return width; }
|
||||||
|
@Override
|
||||||
|
public int height() { return height; }
|
||||||
|
@Override
|
||||||
|
public float oversample() { return oversample; }
|
||||||
|
@Override
|
||||||
|
public void upload(int texture, int x, int y) {
|
||||||
|
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
||||||
|
if(drawable.drawFont(face, glyth)) {
|
||||||
|
drawable.upload(texture, x, y, 0, 0, width, height);
|
||||||
|
}
|
||||||
|
drawable.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isColored() { return false; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class FreeTypeInstance {
|
||||||
|
final int style;
|
||||||
|
long data;
|
||||||
|
final FT_Face face;
|
||||||
|
IntSet skip = new IntOpenHashSet();
|
||||||
|
final float oversample;
|
||||||
|
final float xOff;
|
||||||
|
final float yOff;
|
||||||
|
final float shadowOffset;
|
||||||
|
final long harfBuzzFont;
|
||||||
|
|
||||||
|
public FreeTypeInstance(int style, long data, FT_Face face, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
||||||
|
this.style = style;
|
||||||
|
this.data = data;
|
||||||
|
this.face = face;
|
||||||
|
this.harfBuzzFont = HarfBuzz.hb_ft_font_create_referenced(face.address());
|
||||||
|
skip.codePoints().forEach(this.skip::add);
|
||||||
|
this.oversample = oversample;
|
||||||
|
this.xOff = xOff;
|
||||||
|
this.yOff = yOff;
|
||||||
|
this.shadowOffset = shadowOffset;
|
||||||
|
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
FT_Vector ft_vector = FT_Vector.malloc(stack).set(Math.round(oversample * xOff * 64F), Math.round(oversample * -yOff * 64F));
|
||||||
|
FreeType.FT_Set_Transform(face, null, ft_vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
if(data == 0L) return;
|
||||||
|
FreeType.FT_Done_Face(face);
|
||||||
|
MemoryUtil.nmemFree(data);
|
||||||
|
data = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnbakedGlyth gylthData(int codepoint, float size, float oversample) {
|
||||||
|
if(skip.contains(codepoint)) return null;
|
||||||
|
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||||
|
if(index == 0) return null;
|
||||||
|
oversample *= this.oversample;
|
||||||
|
int pixels = Math.round(size * oversample);
|
||||||
|
if(FreeTypeLibrary.parseError(FreeType.FT_Set_Pixel_Sizes(face, pixels, pixels), "Set Pixel Size")) return null;
|
||||||
|
|
||||||
|
if(FreeTypeLibrary.parseError(FreeType.FT_Load_Glyph(face, index, FreeType.FT_LOAD_NO_BITMAP | FreeType.FT_LOAD_BITMAP_METRICS_ONLY), "Loading Glyth")) return null;
|
||||||
|
FT_GlyphSlot slot = face.glyph();
|
||||||
|
if(slot == null) {
|
||||||
|
System.out.println("Glyth didn't load for some reason");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
float advance = slot.advance().x() / 64F;
|
||||||
|
FT_Bitmap bitmap = slot.bitmap();
|
||||||
|
|
||||||
|
int left = slot.bitmap_left();
|
||||||
|
int top = slot.bitmap_top();
|
||||||
|
int width = bitmap.width();
|
||||||
|
int height = bitmap.rows();
|
||||||
|
if(width > 0 && height > 0) return new FreeTypeGlyth(face, harfBuzzFont, left, -top, width, height, advance, oversample, index, codepoint);
|
||||||
|
return new EmptyGlythData(advance / oversample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FreeTypeLibrary {
|
||||||
|
private static long pointer = 0L;
|
||||||
|
|
||||||
|
public static long get() {
|
||||||
|
if(pointer == 0L) {
|
||||||
|
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
PointerBuffer pointBuffer = stack.callocPointer(1);
|
||||||
|
int result = FreeType.FT_Init_FreeType(pointBuffer);
|
||||||
|
if(result != 0) {
|
||||||
|
throw new IllegalStateException(FreeType.FT_Error_String(result));
|
||||||
|
}
|
||||||
|
pointer = pointBuffer.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean parseError(int result, String action) {
|
||||||
|
if(result == 0) return false;
|
||||||
|
String error = FreeType.FT_Error_String(result);
|
||||||
|
System.out.println("Couldn't do ["+action+"] because of "+error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void close() {
|
||||||
|
if(pointer == 0L) return;
|
||||||
|
FreeType.FT_Done_Library(pointer);
|
||||||
|
pointer = 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.providers;
|
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||||
|
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
|
|
||||||
public interface IFontProvider {
|
public interface IFontProvider {
|
||||||
public static final int REGULAR = 0;
|
public static final int REGULAR = 0;
|
||||||
|
@ -9,6 +9,6 @@ public interface IFontProvider {
|
||||||
public static final int ITALIC_BOLD = 3;
|
public static final int ITALIC_BOLD = 3;
|
||||||
|
|
||||||
|
|
||||||
public GlythData glythData(int codepoint, int style, float size, float oversample);
|
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample);
|
||||||
public void close();
|
public void close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||||
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
|
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
|
||||||
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.EmptyGlythData;
|
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||||
|
@ -112,7 +112,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
data = 0L;
|
data = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData glythData(int codepoint, float size, float oversample) {
|
public UnbakedGlyth glythData(int codepoint, float size, float oversample) {
|
||||||
if(skip.contains(codepoint)) return null;
|
if(skip.contains(codepoint)) return null;
|
||||||
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
|
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
|
||||||
if(glyth == 0) return null;
|
if(glyth == 0) return null;
|
||||||
|
@ -142,7 +142,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlythData glythData(int codepoint, int style, float size, float oversample) {
|
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
|
||||||
TrueTypeInstance instance = instances[style & 0x3];
|
TrueTypeInstance instance = instances[style & 0x3];
|
||||||
return instance == null ? null : instance.glythData(codepoint, size, oversample);
|
return instance == null ? null : instance.glythData(codepoint, size, oversample);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
instances = null;
|
instances = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class STBGlyth implements GlythData {
|
private static class STBGlyth implements UnbakedGlyth {
|
||||||
final TrueTypeInstance owner;
|
final TrueTypeInstance owner;
|
||||||
final float xOffset;
|
final float xOffset;
|
||||||
final float yOffset;
|
final float yOffset;
|
||||||
|
@ -185,7 +185,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
@Override
|
@Override
|
||||||
public float shadowOffset() { return owner.shadowOffset; }
|
public float shadowOffset() { return owner.shadowOffset; }
|
||||||
@Override
|
@Override
|
||||||
public float kernling(int codepoint) { return STBTruetype.stbtt_GetCodepointKernAdvance(owner.info, codepoint, glyth) * scale / oversample; }
|
public float kerning(int codepoint) { return STBTruetype.stbtt_GetCodepointKernAdvance(owner.info, codepoint, glyth) * scale / oversample; }
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(GlythBaker baker) {
|
public Glyth bake(GlythBaker baker) {
|
||||||
return baker.bake(new IGlythSheetInfo() {
|
return baker.bake(new IGlythSheetInfo() {
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
package speiger.src.coreengine.rendering.textures.custom;
|
package speiger.src.coreengine.rendering.textures.custom;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.lwjgl.stb.STBImage;
|
import org.lwjgl.stb.STBImage;
|
||||||
import org.lwjgl.stb.STBTTFontinfo;
|
import org.lwjgl.stb.STBTTFontinfo;
|
||||||
import org.lwjgl.stb.STBTruetype;
|
import org.lwjgl.stb.STBTruetype;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
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 speiger.src.coreengine.math.misc.ColorSpaces;
|
import speiger.src.coreengine.math.misc.ColorSpaces;
|
||||||
import speiger.src.coreengine.rendering.utils.GLFunctions;
|
import speiger.src.coreengine.rendering.utils.GLFunctions;
|
||||||
|
@ -64,6 +71,21 @@ public class Drawable implements IDrawable, AutoCloseable {
|
||||||
if(pixels == 0L) throw new IllegalStateException("Pixel Data doesn't exist");
|
if(pixels == 0L) throw new IllegalStateException("Pixel Data doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean drawFont(FT_Face face, int glyth) {
|
||||||
|
ensureValid(0);
|
||||||
|
if(components != 1) throw new IllegalStateException("Format has to be 1 component");
|
||||||
|
if(FreeType.FT_Load_Glyph(face, glyth, 4) != 0) return false;
|
||||||
|
|
||||||
|
FT_GlyphSlot slot = Objects.requireNonNull(face.glyph());
|
||||||
|
FT_Bitmap map = slot.bitmap();
|
||||||
|
if(map.pixel_mode() != FreeType.FT_PIXEL_MODE_GRAY) throw new IllegalStateException("Pixel isn't a grayscale picture");
|
||||||
|
if(map.width() != width() || map.rows() != height()) throw new IllegalStateException("Bounds do not match");
|
||||||
|
int size = map.width() * map.rows();
|
||||||
|
ByteBuffer buffer = Objects.requireNonNull(map.buffer(size));
|
||||||
|
MemoryUtil.memCopy(MemoryUtil.memAddress(buffer), pixels(), size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void drawFont(STBTTFontinfo info, int glyth, float sourceX, float sourceY, int targetX, int targetY, int width, int height, float scaleX, float scaleY) {
|
public void drawFont(STBTTFontinfo info, int glyth, float sourceX, float sourceY, int targetX, int targetY, int width, int height, float scaleX, float scaleY) {
|
||||||
ensureValid(targetX, targetY);
|
ensureValid(targetX, targetY);
|
||||||
ensureValid(targetX + width, targetY + height);
|
ensureValid(targetX + width, targetY + height);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"type": "stb-ttf",
|
"type": "free-ttf",
|
||||||
"regular": {
|
"regular": {
|
||||||
"file": "font/roboto/Roboto-Medium.ttf",
|
"file": "font/roboto/Roboto-Medium.ttf",
|
||||||
"oversample": 1,
|
"oversample": 3,
|
||||||
"shadowOffset": 1,
|
"shadowOffset": 1,
|
||||||
"skip": "",
|
"skip": "",
|
||||||
"offset": { "x": 0, "y": 0 }
|
"offset": { "x": 0, "y": 0 }
|
||||||
|
|
|
@ -8,7 +8,6 @@ out vec4 pass_color;
|
||||||
out vec2 pass_tex;
|
out vec2 pass_tex;
|
||||||
|
|
||||||
uniform mat4 proViewMatrix;
|
uniform mat4 proViewMatrix;
|
||||||
uniform mat4 modelmatrix;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue