More work on the font system
This commit is contained in:
parent
0139086858
commit
62b91f0f1d
|
@ -6,15 +6,20 @@ 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 com.google.gson.JsonObject;
|
||||||
|
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
import speiger.src.coreengine.assets.AssetManager;
|
import speiger.src.coreengine.assets.AssetManager;
|
||||||
|
import speiger.src.coreengine.assets.base.IAsset;
|
||||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||||
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.GlythBaker;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.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.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.rendering.guiOld.renderer.provider.BitmapFontProvider;
|
||||||
import speiger.src.coreengine.rendering.input.devices.FileDrop;
|
import speiger.src.coreengine.rendering.input.devices.FileDrop;
|
||||||
import speiger.src.coreengine.rendering.input.devices.Joystick;
|
import speiger.src.coreengine.rendering.input.devices.Joystick;
|
||||||
import speiger.src.coreengine.rendering.input.devices.Keyboard;
|
import speiger.src.coreengine.rendering.input.devices.Keyboard;
|
||||||
|
@ -62,18 +67,23 @@ public class NewInputTest {
|
||||||
shaderTest.register();
|
shaderTest.register();
|
||||||
assets.addListener(GLStateTracker.instance().shaders);
|
assets.addListener(GLStateTracker.instance().shaders);
|
||||||
assets.addListener(GLStateTracker.TEXTURE_TRACKER);
|
assets.addListener(GLStateTracker.TEXTURE_TRACKER);
|
||||||
assets.reload(Runnable::run, Runnable::run);
|
assets.reload();
|
||||||
|
|
||||||
System.out.println("Testing: "+GL.getCapabilities().OpenGL46);
|
System.out.println("Testing: "+GL.getCapabilities().OpenGL46);
|
||||||
|
System.out.println("Testing: "+Integer.divideUnsigned(-1, 255));
|
||||||
|
|
||||||
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/Roboto-Medium.ttf"), assets);
|
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/roboto/font.json"), assets);
|
||||||
|
BitmapFontProvider bit = loadProvider(AssetLocation.of("font/roboto.json"), 18.5F);
|
||||||
|
|
||||||
DynamicTexture texture = new DynamicTexture(512, 512, DynamicTexture.DEFAULT_PARAMETERS);
|
int size = 512;
|
||||||
texture.fill(0, 0, 512, 512, -1);
|
int half = size >> 1;
|
||||||
texture.fill(0, 0, 256, 256, 255, 0, 0, 255);
|
|
||||||
texture.fill(256, 0, 256, 256, 0, 255, 0, 255);
|
DynamicTexture texture = new DynamicTexture(size, size, DynamicTexture.DEFAULT_PARAMETERS);
|
||||||
texture.fill(256, 256, 256, 256, 255, 0, 0, 255);
|
texture.fill(0, 0, size, size, -1);
|
||||||
texture.fill(0, 256, 256, 256, 0, 0, 255, 255);
|
texture.fill(0, 0, half, half, 255, 0, 0, 255);
|
||||||
|
texture.fill(half, 0, half, half, 0, 255, 0, 255);
|
||||||
|
texture.fill(half, half, half, half, 255, 0, 0, 255);
|
||||||
|
texture.fill(0, half, half, half, 0, 0, 255, 255);
|
||||||
texture.process(true);
|
texture.process(true);
|
||||||
window.visible(true);
|
window.visible(true);
|
||||||
|
|
||||||
|
@ -81,23 +91,25 @@ public class NewInputTest {
|
||||||
if(T.key() == GLFW.GLFW_KEY_T) {
|
if(T.key() == GLFW.GLFW_KEY_T) {
|
||||||
T.cancel();
|
T.cancel();
|
||||||
texture.bind();
|
texture.bind();
|
||||||
Drawable drawable = new Drawable(GLTextureFormat.RGBA, 256, 256);
|
Drawable drawable = new Drawable(GLTextureFormat.RGBA, half, half);
|
||||||
drawable.fill(0, 0, 256, 256, 255, 255, 0, 255);
|
drawable.fill(0, 0, half, half, 255, 255, 0, 255);
|
||||||
drawable.upload(192, 192, 64, 64, 128, 128);
|
drawable.upload(192, 192, 64, 64, 128, 128);
|
||||||
drawable.close();
|
drawable.close();
|
||||||
}
|
}
|
||||||
else if(T.key() == GLFW.GLFW_KEY_Z) {
|
else if(T.key() == GLFW.GLFW_KEY_Z) {
|
||||||
T.cancel();
|
T.cancel();
|
||||||
texture.bind();
|
texture.bind();
|
||||||
provider.glythData("C".codePointAt(0), false).bake(new GlythBaker() {
|
GlythData data = provider.glythData("C".codePointAt(0), 0);
|
||||||
|
data.bake(new GlythBaker() {
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(IGlythSheetInfo info) {
|
public Glyth bake(IGlythSheetInfo info) {
|
||||||
int width = info.width();
|
int width = info.width();
|
||||||
int height = info.height();
|
int height = info.height();
|
||||||
info.upload(256 - (width >> 2), 256 - (height >> 2));
|
info.upload(half - (width >> 2), half - (height >> 2));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
System.out.println("Testing: "+data.advance()+", "+bit.getCharacter("C".codePointAt(0), false).getXAdvance());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -132,6 +144,17 @@ public class NewInputTest {
|
||||||
manager.destroy();
|
manager.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BitmapFontProvider loadProvider(AssetLocation location, float desiredSize)
|
||||||
|
{
|
||||||
|
try(IAsset asset = assets.getAsset(location))
|
||||||
|
{
|
||||||
|
JsonObject obj = asset.json();
|
||||||
|
return BitmapFontProvider.load(obj, desiredSize, null);
|
||||||
|
}
|
||||||
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static class TestShader extends SimpleShader {
|
public static class TestShader extends SimpleShader {
|
||||||
public TextureUniform texture = uniforms.addTexture("texture", 0);
|
public TextureUniform texture = uniforms.addTexture("texture", 0);
|
||||||
public TestShader(IAssetProvider provider) {
|
public TestShader(IAssetProvider provider) {
|
||||||
|
|
|
@ -42,10 +42,18 @@ public class AssetManager implements ICloseableAssetProvider
|
||||||
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
|
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AssetManager reload() {
|
||||||
|
return reload(Runnable::run, Runnable::run);
|
||||||
|
}
|
||||||
|
|
||||||
public AssetManager reload(Executor offthread, Executor syncer) {
|
public AssetManager reload(Executor offthread, Executor syncer) {
|
||||||
return reloadSelective(offthread, syncer, listeners);
|
return reloadSelective(offthread, syncer, listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
|
||||||
|
return reloadSelective(Runnable::run, Runnable::run, listeners);
|
||||||
|
}
|
||||||
|
|
||||||
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
|
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
|
||||||
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
|
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -4,63 +4,68 @@ import java.util.List;
|
||||||
|
|
||||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
||||||
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
|
||||||
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.IGlythSheetInfo;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.GlythBaker;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
|
|
||||||
public class FontGroup {
|
public class FontGroup {
|
||||||
private static final int BOLD_FLAG = 1<<31;
|
|
||||||
private static final int TEXTURE_SIZE = 2048;
|
|
||||||
AssetLocation locations;
|
AssetLocation locations;
|
||||||
List<IFontProvider> providers;
|
List<IFontProvider> providers;
|
||||||
Int2ObjectMap<Glyth> bakedGlyths = new Int2ObjectOpenHashMap<>();
|
GlythBaker baker;
|
||||||
Int2ObjectMap<GlythData> dataGlyths = new Int2ObjectOpenHashMap<>();
|
StyledFont[] cache = new StyledFont[] {new StyledFont(0), new StyledFont(1), new StyledFont(2), new StyledFont(3)};
|
||||||
List<FontTexture> textures = new ObjectArrayList<>();
|
|
||||||
|
|
||||||
public FontGroup(AssetLocation locations, List<IFontProvider> providers) {
|
public FontGroup(AssetLocation locations, List<IFontProvider> providers, GlythBaker baker) {
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
this.providers = providers;
|
this.providers = providers;
|
||||||
|
this.baker = baker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData data(int codepoint, boolean bold) {
|
public GlythData data(int codepoint, int style) {
|
||||||
return dataGlyths.computeIfAbsent(codepoint | (bold ? 0 : BOLD_FLAG), this::compute);
|
return cache[style & 0x3].data(codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Glyth glyth(int codepoint, boolean bold) {
|
public Glyth glyth(int codepoint, int style) {
|
||||||
return bakedGlyths.computeIfAbsent(codepoint | (bold ? 0 : BOLD_FLAG), this::bake);
|
return cache[style & 0x3].glyth(codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlythData compute(int codepoint) {
|
public void close() {
|
||||||
boolean bold = (codepoint & BOLD_FLAG) != 0;
|
providers.forEach(IFontProvider::close);
|
||||||
codepoint &= ~BOLD_FLAG;
|
providers.clear();
|
||||||
for(int i = 0,m=providers.size();i<m;i++) {
|
}
|
||||||
GlythData data = providers.get(i).glythData(codepoint, bold);
|
|
||||||
if(data != null) return data;
|
private class StyledFont {
|
||||||
|
final int style;
|
||||||
|
Int2ObjectMap<Glyth> bakedGlyths = new Int2ObjectOpenHashMap<>();
|
||||||
|
Int2ObjectMap<GlythData> dataGlyths = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public StyledFont(int style) {
|
||||||
|
this.style = style;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Glyth bake(int codepoint) {
|
public GlythData data(int codepoint) {
|
||||||
boolean bold = (codepoint & BOLD_FLAG) != 0;
|
return dataGlyths.computeIfAbsent(codepoint, this::compute);
|
||||||
codepoint &= ~BOLD_FLAG;
|
|
||||||
for(int i = 0,m=providers.size();i<m;i++) {
|
|
||||||
GlythData data = providers.get(i).glythData(codepoint, bold);
|
|
||||||
if(data != null) return data.bake(this::stitch);
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Glyth stitch(IGlythSheetInfo info) {
|
public Glyth glyth(int codepoint) {
|
||||||
for(int i = 0,m=textures.size();i<m;i++) {
|
return bakedGlyths.computeIfAbsent(codepoint, this::bake);
|
||||||
Glyth glyth = textures.get(i).build(info);
|
}
|
||||||
if(glyth != null) return glyth;
|
|
||||||
|
private GlythData compute(int codepoint) {
|
||||||
|
for(int i = 0,m=providers.size();i<m;i++) {
|
||||||
|
GlythData data = providers.get(i).glythData(codepoint, style);
|
||||||
|
if(data != null) return data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glyth bake(int codepoint) {
|
||||||
|
for(int i = 0,m=providers.size();i<m;i++) {
|
||||||
|
GlythData data = providers.get(i).glythData(codepoint, style);
|
||||||
|
if(data != null) return data.bake(baker);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
|
|
||||||
textures.add(texture);
|
|
||||||
Glyth glyth = texture.build(info);
|
|
||||||
return glyth;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,49 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font;
|
package speiger.src.coreengine.rendering.gui.font;
|
||||||
|
|
||||||
public class FontManager {
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
|
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||||
|
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
|
|
||||||
|
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, List<JsonObject>>> {
|
||||||
|
private static final int TEXTURE_SIZE = 2048;
|
||||||
|
List<FontTexture> textures = new ObjectArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return null; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<AssetLocation, List<JsonObject>> prepare(IAssetProvider provider) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void apply(Map<AssetLocation, List<JsonObject>> value, IAssetProvider provider) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glyth stitch(IGlythSheetInfo info) {
|
||||||
|
for(int i = 0,m=textures.size();i<m;i++) {
|
||||||
|
Glyth glyth = textures.get(i).build(info);
|
||||||
|
if(glyth != null) return glyth;
|
||||||
|
}
|
||||||
|
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
|
||||||
|
textures.add(texture);
|
||||||
|
Glyth glyth = texture.build(info);
|
||||||
|
return glyth;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.glyth;
|
package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
public record Glyth(int texture, float minU, float minV, float maxU, float maxV) {}
|
public record Glyth(int texture, float minU, float minV, float maxU, float maxV) {
|
||||||
|
public static final Glyth EMPTY = new Glyth(-1, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,15 @@ package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
public interface GlythData {
|
public interface GlythData {
|
||||||
public float advance();
|
public float advance();
|
||||||
|
public default float shadowOffset() { return 1F; }
|
||||||
public Glyth bake(GlythBaker baker);
|
public Glyth bake(GlythBaker baker);
|
||||||
|
|
||||||
|
|
||||||
|
public static record EmptyGlythData(float advance) implements GlythData {
|
||||||
|
@Override
|
||||||
|
public Glyth bake(GlythBaker baker) { return Glyth.EMPTY; }
|
||||||
|
}
|
||||||
|
|
||||||
public static interface GlythBaker {
|
public static interface GlythBaker {
|
||||||
Glyth bake(IGlythSheetInfo info);
|
Glyth bake(IGlythSheetInfo info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
|
|
||||||
|
public class BitmapProivder implements IFontProvider {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GlythData glythData(int codepoint, int style) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BitmapGlyth implements GlythData {
|
||||||
|
int minX;
|
||||||
|
int minY;
|
||||||
|
int maxX;
|
||||||
|
int maxY;
|
||||||
|
int glyth;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float advance() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Glyth bake(GlythBaker baker) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,13 @@ 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.GlythData;
|
||||||
|
|
||||||
public interface IFontProvider extends AutoCloseable {
|
public interface IFontProvider extends AutoCloseable {
|
||||||
public GlythData glythData(int codepoint, boolean bold);
|
public static final int REGULAR = 0;
|
||||||
|
public static final int BOLD = 1;
|
||||||
|
public static final int ITALIC = 2;
|
||||||
|
public static final int ITALIC_BOLD = 3;
|
||||||
|
|
||||||
|
|
||||||
|
public GlythData glythData(int codepoint, int style);
|
||||||
@Override
|
@Override
|
||||||
void close();
|
void close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import org.lwjgl.stb.STBTruetype;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
||||||
import speiger.src.collections.ints.sets.IntSet;
|
import speiger.src.collections.ints.sets.IntSet;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
|
@ -17,33 +19,51 @@ 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.GlythData;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.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;
|
||||||
|
|
||||||
public class STBTrueTypeProvider implements IFontProvider {
|
public class STBTrueTypeProvider implements IFontProvider {
|
||||||
long data;
|
TrueTypeInstance[] instances;
|
||||||
STBTTFontinfo info;
|
|
||||||
IntSet skip = new IntOpenHashSet();
|
|
||||||
float oversample;
|
|
||||||
float xOff;
|
|
||||||
float yOff;
|
|
||||||
float pointScale;
|
|
||||||
float ascent;
|
|
||||||
|
|
||||||
public STBTrueTypeProvider(long data, STBTTFontinfo info, float size, float oversample, float xOff, float yOff, String skip) {
|
public STBTrueTypeProvider(TrueTypeInstance[] instances) {
|
||||||
this.data = data;
|
this.instances = instances;
|
||||||
this.info = info;
|
|
||||||
skip.codePoints().forEach(this.skip::add);
|
|
||||||
this.oversample = oversample;
|
|
||||||
this.xOff = xOff;
|
|
||||||
this.yOff = yOff;
|
|
||||||
pointScale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
|
|
||||||
int[] ascent = new int[1];
|
|
||||||
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
|
|
||||||
this.ascent = pointScale * ascent[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
|
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
|
||||||
|
try(IAsset asset = provider.getAsset(location)) {
|
||||||
|
return create(asset.json(), provider);
|
||||||
|
}
|
||||||
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFontProvider create(JsonObject data, IAssetProvider provider) {
|
||||||
|
TrueTypeInstance[] instances = new TrueTypeInstance[4];
|
||||||
|
instances[0] = create(0, data.getAsJsonObject("regular"), provider);
|
||||||
|
if(instances[0] == null) return null;
|
||||||
|
instances[1] = create(1, data.getAsJsonObject("bold"), provider);
|
||||||
|
instances[2] = create(2, data.getAsJsonObject("italic"), provider);
|
||||||
|
instances[3] = create(3, data.getAsJsonObject("bold_italic"), provider);
|
||||||
|
return new STBTrueTypeProvider(instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TrueTypeInstance create(int style, JsonObject obj, IAssetProvider provider) {
|
||||||
|
if(obj == null || !obj.has("file")) return null;
|
||||||
|
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
||||||
|
float size = JsonUtil.getOrDefault(obj, "size", 24F);
|
||||||
|
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", 0);
|
||||||
|
yOff = JsonUtil.getOrDefault(shift, "y", 0);
|
||||||
|
}
|
||||||
|
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
|
||||||
try(IAsset asset = provider.getAsset(location)) {
|
try(IAsset asset = provider.getAsset(location)) {
|
||||||
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
|
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
|
||||||
STBTTFontinfo info = STBTTFontinfo.create();
|
STBTTFontinfo info = STBTTFontinfo.create();
|
||||||
|
@ -53,7 +73,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
info.free();
|
info.free();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new STBTrueTypeProvider(MemoryUtil.memAddress(buffer), info, 10.2F, 24F, 0, 0, "");
|
return new TrueTypeInstance(style, MemoryUtil.memAddress(buffer), info, size, oversample, xOff, yOff, shadowOffset, builder.toString());
|
||||||
}
|
}
|
||||||
catch(Exception e) {
|
catch(Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -61,60 +81,102 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static class TrueTypeInstance {
|
||||||
public GlythData glythData(int codepoint, boolean bold) {
|
final int style;
|
||||||
if(skip.contains(codepoint)) return null;
|
long data;
|
||||||
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
|
final STBTTFontinfo info;
|
||||||
if(glyth == 0) return null;
|
IntSet skip = new IntOpenHashSet();
|
||||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
final float oversample;
|
||||||
IntBuffer left = stack.mallocInt(1);
|
final float xOff;
|
||||||
IntBuffer bottom = stack.mallocInt(1);
|
final float yOff;
|
||||||
IntBuffer right = stack.mallocInt(1);
|
final float shadowOffset;
|
||||||
IntBuffer top = stack.mallocInt(1);
|
final float pointScale;
|
||||||
IntBuffer advance = stack.mallocInt(1);
|
final float ascent;
|
||||||
IntBuffer leftSideBearing = stack.mallocInt(1);
|
|
||||||
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
|
public TrueTypeInstance(int style, long data, STBTTFontinfo info, float size, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
||||||
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, pointScale, pointScale, xOff, yOff, left, bottom, right, top);
|
this.style = style;
|
||||||
int minX = left.get(0);
|
this.data = data;
|
||||||
int minY = -top.get(0);
|
this.info = info;
|
||||||
int maxX = right.get(0);
|
skip.codePoints().forEach(this.skip::add);
|
||||||
int maxY = -bottom.get(0);
|
this.oversample = oversample;
|
||||||
if(maxX - minX <= 0 || maxY - minY <= 0) return null;
|
this.xOff = xOff;
|
||||||
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0) * pointScale, leftSideBearing.get(0) * pointScale, glyth);
|
this.yOff = yOff;
|
||||||
|
this.shadowOffset = shadowOffset;
|
||||||
|
pointScale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
|
||||||
|
int[] ascent = new int[1];
|
||||||
|
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
|
||||||
|
this.ascent = pointScale * ascent[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
if(data == 0L) return;
|
||||||
|
info.free();
|
||||||
|
MemoryUtil.nmemFree(data);
|
||||||
|
data = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlythData glythData(int codepoint) {
|
||||||
|
if(skip.contains(codepoint)) return null;
|
||||||
|
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
|
||||||
|
if(glyth == 0) return null;
|
||||||
|
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
|
IntBuffer left = stack.mallocInt(1);
|
||||||
|
IntBuffer bottom = stack.mallocInt(1);
|
||||||
|
IntBuffer right = stack.mallocInt(1);
|
||||||
|
IntBuffer top = stack.mallocInt(1);
|
||||||
|
IntBuffer advance = stack.mallocInt(1);
|
||||||
|
IntBuffer leftSideBearing = stack.mallocInt(1);
|
||||||
|
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
|
||||||
|
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, pointScale, pointScale, xOff, yOff, left, bottom, right, top);
|
||||||
|
int minX = left.get(0);
|
||||||
|
int minY = -top.get(0);
|
||||||
|
int maxX = right.get(0);
|
||||||
|
int maxY = -bottom.get(0);
|
||||||
|
if(maxX - minX <= 0 || maxY - minY <= 0) return new EmptyGlythData(advance.get(0) * pointScale / oversample);
|
||||||
|
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0) * pointScale, leftSideBearing.get(0) * pointScale, glyth);
|
||||||
|
}
|
||||||
|
catch(Throwable exception) {
|
||||||
|
exception.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GlythData glythData(int codepoint, int style) {
|
||||||
|
TrueTypeInstance instance = instances[style & 0x3];
|
||||||
|
return instance == null ? null : instance.glythData(codepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if(data == 0L) return;
|
if(instances == null) return;
|
||||||
info.free();
|
for(int i = 0;i<4;i++) {
|
||||||
MemoryUtil.nmemFree(data);
|
if(instances[i] == null) continue;
|
||||||
data = 0L;
|
instances[i].free();
|
||||||
|
}
|
||||||
|
instances = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class STBGlyth implements GlythData {
|
private static class STBGlyth implements GlythData {
|
||||||
final STBTrueTypeProvider owner;
|
final TrueTypeInstance owner;
|
||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
// final float xOff;
|
|
||||||
// final float yOff;
|
|
||||||
final float advance;
|
final float advance;
|
||||||
final int glyth;
|
final int glyth;
|
||||||
|
|
||||||
public STBGlyth(STBTrueTypeProvider owner, int minX, int minY, int maxX, int maxY, float advance, float leftPadding, int glyth) {
|
public STBGlyth(TrueTypeInstance owner, int minX, int minY, int maxX, int maxY, float advance, float leftPadding, int glyth) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
this.width = maxX - minX;
|
this.width = maxX - minX;
|
||||||
this.height = maxY - minY;
|
this.height = maxY - minY;
|
||||||
this.advance = advance / owner.oversample;
|
this.advance = advance / owner.oversample;
|
||||||
// this.xOff = (leftPadding + minX + owner.xOff) / owner.oversample;
|
|
||||||
// this.yOff = (owner.ascent + maxY + owner.yOff) / owner.oversample;
|
|
||||||
this.glyth = glyth;
|
this.glyth = glyth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float advance() {
|
public float advance() { return advance; }
|
||||||
return advance;
|
@Override
|
||||||
}
|
public float shadowOffset() { return owner.shadowOffset; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(GlythBaker baker) {
|
public Glyth bake(GlythBaker baker) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class BitmapFontProvider implements IFontProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static IFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
|
public static BitmapFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
|
||||||
{
|
{
|
||||||
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
|
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
|
||||||
float multiplier = info.setDesiredHeight(desiredSize);
|
float multiplier = info.setDesiredHeight(desiredSize);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class STBTexture extends AbstractTexture
|
||||||
public STBTexture(AssetLocation location)
|
public STBTexture(AssetLocation location)
|
||||||
{
|
{
|
||||||
this.location = location;
|
this.location = location;
|
||||||
loadTexture();
|
// loadTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTexture()
|
private void loadTexture()
|
||||||
|
|
|
@ -70,6 +70,7 @@ public class JsonUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void iterateValues(JsonElement element, Consumer<JsonPrimitive> result) {
|
public static void iterateValues(JsonElement element, Consumer<JsonPrimitive> result) {
|
||||||
|
if(element == null) return;
|
||||||
if(element.isJsonPrimitive()) result.accept(element.getAsJsonPrimitive());
|
if(element.isJsonPrimitive()) result.accept(element.getAsJsonPrimitive());
|
||||||
else if(element.isJsonArray()) {
|
else if(element.isJsonArray()) {
|
||||||
JsonArray array = element.getAsJsonArray();
|
JsonArray array = element.getAsJsonArray();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"type": "stb-ttf",
|
||||||
|
"regular": {
|
||||||
|
"file": "font/roboto/Roboto-Medium.ttf",
|
||||||
|
"size": 18.5,
|
||||||
|
"oversample": 2,
|
||||||
|
"shadowOffset": 1,
|
||||||
|
"skip": "",
|
||||||
|
"offset": { "x": 0, "y": 0 }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue