Newest state of the font renderer
This commit is contained in:
parent
2dae61adbf
commit
7a7d9c1fd0
|
@ -1,25 +1,27 @@
|
||||||
package speiger.src.coreengine;
|
package speiger.src.coreengine;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
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 com.google.gson.JsonObject;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
|
||||||
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.math.vector.matrix.Matrix4f;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.Font;
|
||||||
|
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.UnbakedGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.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.glyth.MissingGlyth;
|
||||||
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;
|
||||||
|
@ -32,6 +34,8 @@ import speiger.src.coreengine.rendering.models.buffers.VertexArray;
|
||||||
import speiger.src.coreengine.rendering.shader.Shader;
|
import speiger.src.coreengine.rendering.shader.Shader;
|
||||||
import speiger.src.coreengine.rendering.shader.SimpleShader;
|
import speiger.src.coreengine.rendering.shader.SimpleShader;
|
||||||
import speiger.src.coreengine.rendering.shader.uniform.base.TextureUniform;
|
import speiger.src.coreengine.rendering.shader.uniform.base.TextureUniform;
|
||||||
|
import speiger.src.coreengine.rendering.shader.uniform.vec.Matrix4fUniform;
|
||||||
|
import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder;
|
||||||
import speiger.src.coreengine.rendering.tesselation.buffer.VertexBuilder;
|
import speiger.src.coreengine.rendering.tesselation.buffer.VertexBuilder;
|
||||||
import speiger.src.coreengine.rendering.tesselation.format.VertexTypes;
|
import speiger.src.coreengine.rendering.tesselation.format.VertexTypes;
|
||||||
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
|
@ -48,7 +52,9 @@ public class NewInputTest {
|
||||||
EventBus bus = new EventBus();
|
EventBus bus = new EventBus();
|
||||||
WindowManager manager = new WindowManager();
|
WindowManager manager = new WindowManager();
|
||||||
AssetManager assets = new AssetManager(List.of(IAssetPackage.of(IOUtils.getBaseLocation())));
|
AssetManager assets = new AssetManager(List.of(IAssetPackage.of(IOUtils.getBaseLocation())));
|
||||||
|
FontManager fonts = new FontManager();
|
||||||
private Shader<TestShader> shaderTest = Shader.create(TestShader::new);
|
private Shader<TestShader> shaderTest = Shader.create(TestShader::new);
|
||||||
|
private Shader<GuiShader> guiShader = Shader.create(GuiShader::new);
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -65,15 +71,17 @@ public class NewInputTest {
|
||||||
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").build();
|
Window window = manager.builder().title("Testing Engine").build();
|
||||||
shaderTest.register();
|
shaderTest.register();
|
||||||
|
guiShader.register();
|
||||||
assets.addListener(GLStateTracker.instance().shaders);
|
assets.addListener(GLStateTracker.instance().shaders);
|
||||||
assets.addListener(GLStateTracker.TEXTURE_TRACKER);
|
assets.addListener(GLStateTracker.TEXTURE_TRACKER);
|
||||||
|
assets.addListener(fonts);
|
||||||
assets.reload();
|
assets.reload();
|
||||||
|
|
||||||
System.out.println("Testing: "+GL.getCapabilities().OpenGL46);
|
System.out.println("Testing: "+GL.getCapabilities().OpenGL46);
|
||||||
System.out.println("Testing: "+Integer.divideUnsigned(-1, 255));
|
System.out.println("Testing: "+Integer.divideUnsigned(-1, 255));
|
||||||
|
|
||||||
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/roboto/font.json"), assets);
|
IFontProvider provider = STBTrueTypeProvider.create(AssetLocation.of("font/roboto/font.json"), assets);
|
||||||
BitmapFontProvider bit = loadProvider(AssetLocation.of("font/roboto.json"), 18.5F);
|
guiShader.get().proView.set(new Matrix4f().ortho(0, 0, window.width(), window.height(), 1000, -1000));
|
||||||
|
|
||||||
int size = 512;
|
int size = 512;
|
||||||
int half = size >> 1;
|
int half = size >> 1;
|
||||||
|
@ -87,12 +95,10 @@ public class NewInputTest {
|
||||||
texture.fill(0, half, half, half, 0, 0, 255, 255);
|
texture.fill(0, half, half, half, 0, 0, 255, 255);
|
||||||
texture.process(true);
|
texture.process(true);
|
||||||
window.visible(true);
|
window.visible(true);
|
||||||
var instance = bit.getCharacter("C".codePointAt(0), false);
|
|
||||||
System.out.println("Testing: "+instance.getWidth()+","+instance.getHeight());
|
|
||||||
bus.register(KeyEvent.Key.class, T -> {
|
bus.register(KeyEvent.Key.class, T -> {
|
||||||
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, half, half);
|
Drawable drawable = new Drawable(GLTextureFormat.RGBA, half, half);
|
||||||
drawable.fill(0, 0, half, half, 255, 255, 0, 255);
|
drawable.fill(0, 0, half, half, 255, 255, 0, 255);
|
||||||
drawable.upload(base * 3, base * 3, base, base, base * 2, base * 2);
|
drawable.upload(base * 3, base * 3, base, base, base * 2, base * 2);
|
||||||
|
@ -101,8 +107,8 @@ public class NewInputTest {
|
||||||
else if(T.key() == GLFW.GLFW_KEY_Z) {
|
else if(T.key() == GLFW.GLFW_KEY_Z) {
|
||||||
T.cancel();
|
T.cancel();
|
||||||
System.out.println("Testing");
|
System.out.println("Testing");
|
||||||
texture.bind();
|
// texture.bind();
|
||||||
UnbakedGlyth data = provider.glythData("C".codePointAt(0), 0);
|
GlythData 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) {
|
||||||
|
@ -112,7 +118,20 @@ public class NewInputTest {
|
||||||
System.out.println("Test2: "+width+", "+height);
|
System.out.println("Test2: "+width+", "+height);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}, 1F, 1F);
|
});
|
||||||
|
}
|
||||||
|
else if(T.key() == GLFW.GLFW_KEY_U) {
|
||||||
|
MissingGlyth glyth = new MissingGlyth(18.5F, 4F);
|
||||||
|
glyth.bake(new GlythBaker() {
|
||||||
|
@Override
|
||||||
|
public Glyth bake(IGlythSheetInfo info) {
|
||||||
|
int width = info.width();
|
||||||
|
int height = info.height();
|
||||||
|
info.upload(half - (width >> 1), half - (height >> 1));
|
||||||
|
System.out.println("Test3: "+width+", "+height);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -125,7 +144,15 @@ 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(18.5F);
|
||||||
TestModel model = new TestModel(builder.getBytes());
|
TestModel model = new TestModel(builder.getBytes());
|
||||||
|
TestModel[] guiModel = new TestModel[1];
|
||||||
|
List<GLDraw> draws = new ObjectArrayList<>();
|
||||||
|
font.drawText("Testing my Text", 50, 50, -1, new TexturedBuffer((K, V) -> {
|
||||||
|
draws.addAll(K);
|
||||||
|
guiModel[0] = new TestModel(V);
|
||||||
|
System.out.println("Testing: "+V.length+" bytes, "+K.size());
|
||||||
|
}));
|
||||||
|
|
||||||
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
|
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
|
||||||
while(!window.shouldClose()) {
|
while(!window.shouldClose()) {
|
||||||
|
@ -136,8 +163,16 @@ public class NewInputTest {
|
||||||
shaderTest.get().texture.set(texture);
|
shaderTest.get().texture.set(texture);
|
||||||
model.bindArray();
|
model.bindArray();
|
||||||
GLStateTracker.drawArrays(GLMode.TRIANGLES.glValue(), 6);
|
GLStateTracker.drawArrays(GLMode.TRIANGLES.glValue(), 6);
|
||||||
|
|
||||||
model.unbindArray();
|
model.unbindArray();
|
||||||
|
guiModel[0].bindArray();
|
||||||
|
guiShader.bind();
|
||||||
|
for(GLDraw draw : draws) {
|
||||||
|
// System.out.println("Draw: "+draw.texture()+", "+draw.startVertex()+", "+draw.vertexCount());
|
||||||
|
guiShader.get().texture.set(draw.texture());
|
||||||
|
GLStateTracker.drawArrays(GLMode.TRIANGLES.glValue(), draw.startVertex(), draw.vertexCount());
|
||||||
|
}
|
||||||
|
guiModel[0].unbindArray();
|
||||||
|
|
||||||
window.handleInput();
|
window.handleInput();
|
||||||
window.finishFrame();
|
window.finishFrame();
|
||||||
try { Thread.sleep(100); }
|
try { Thread.sleep(100); }
|
||||||
|
@ -147,15 +182,56 @@ public class NewInputTest {
|
||||||
manager.destroy();
|
manager.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitmapFontProvider loadProvider(AssetLocation location, float desiredSize)
|
public static class TexturedBuffer implements Font.TexturedBuffer {
|
||||||
{
|
int previousId = -1;
|
||||||
try(IAsset asset = assets.getAsset(location))
|
int lastVertex = 0;
|
||||||
{
|
List<GLDraw> draws = new ObjectArrayList<>();
|
||||||
JsonObject obj = asset.json();
|
VertexBuilder builder;
|
||||||
return BitmapFontProvider.load(obj, desiredSize, null);
|
BiConsumer<List<GLDraw>, byte[]> callbacks;
|
||||||
|
|
||||||
|
public TexturedBuffer(BiConsumer<List<GLDraw>, byte[]> callbacks) {
|
||||||
|
this.callbacks = callbacks;
|
||||||
}
|
}
|
||||||
catch(Exception e) { e.printStackTrace(); }
|
|
||||||
return null;
|
@Override
|
||||||
|
public IVertexBuilder builderForTexture(int textureId) {
|
||||||
|
if(builder == null) {
|
||||||
|
builder = new VertexBuilder(100000);
|
||||||
|
builder.start(GLMode.TRIANGLES, VertexTypes.TESTING);
|
||||||
|
previousId = textureId;
|
||||||
|
System.out.println("Texture: "+textureId);
|
||||||
|
}
|
||||||
|
else if(previousId != textureId) {
|
||||||
|
int count = builder.size() - lastVertex;
|
||||||
|
draws.add(new GLDraw(previousId, lastVertex, count));
|
||||||
|
lastVertex+=count;
|
||||||
|
previousId = textureId;
|
||||||
|
System.out.println("Texture: "+textureId);
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
int count = builder.size() - lastVertex;
|
||||||
|
draws.add(new GLDraw(previousId, lastVertex, count));
|
||||||
|
callbacks.accept(draws, builder.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static record GLDraw(int texture, int startVertex, int vertexCount) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GuiShader extends SimpleShader {
|
||||||
|
public TextureUniform texture = uniforms.addTexture("texture", 0);
|
||||||
|
public Matrix4fUniform proView = uniforms.addMat("proViewMatrix", new Matrix4f());
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TestShader extends SimpleShader {
|
public static class TestShader extends SimpleShader {
|
||||||
|
|
|
@ -32,4 +32,8 @@ public record AssetFilter(String prefix, String extension) {
|
||||||
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
|
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<AssetLocation, MultiAsset> multiRoot(IAssetProvider provider) {
|
||||||
|
return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ public final class AssetLocation implements Comparable<AssetLocation> {
|
||||||
public boolean isInFolder() { return location.contains("/"); }
|
public boolean isInFolder() { return location.contains("/"); }
|
||||||
public boolean isInFolder(String prefix) { return location.indexOf("/", prefix.length()+1) >= 0; }
|
public boolean isInFolder(String prefix) { return location.indexOf("/", prefix.length()+1) >= 0; }
|
||||||
|
|
||||||
|
public AssetLocation prefix(String prefix) {
|
||||||
|
return of(domain, prefix+"/"+location);
|
||||||
|
}
|
||||||
|
|
||||||
public AssetLocation subAsset(String subPath) {
|
public AssetLocation subAsset(String subPath) {
|
||||||
return of(domain+":"+location+"/"+subPath);
|
return of(domain+":"+location+"/"+subPath);
|
||||||
}
|
}
|
||||||
|
@ -67,8 +71,40 @@ public final class AssetLocation implements Comparable<AssetLocation> {
|
||||||
return LOCATION.computeIfAbsent(location.indexOf(":") == -1 ? "base:"+location : location, AssetLocation::compute);
|
return LOCATION.computeIfAbsent(location.indexOf(":") == -1 ? "base:"+location : location, AssetLocation::compute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final AssetLocation tryOf(String location) {
|
||||||
|
try { return of(location); }
|
||||||
|
catch(Exception e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static final AssetLocation compute(String s) {
|
private static final AssetLocation compute(String s) {
|
||||||
int index = s.indexOf(":");
|
int index = s.indexOf(":");
|
||||||
return new AssetLocation(s.substring(0, index), s.substring(index + 1));
|
String domain = s.substring(0, index);
|
||||||
|
String path = s.substring(index + 1);
|
||||||
|
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
|
||||||
|
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||||
|
return new AssetLocation(domain, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidDomain(String s) {
|
||||||
|
for(int i = 0,m=s.length();i<m;i++) {
|
||||||
|
if(!isValidDomainChar(s.charAt(i))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidPath(String s) {
|
||||||
|
for(int i = 0,m=s.length();i<m;i++) {
|
||||||
|
if(!isValidPathChar(s.charAt(i))) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidPathChar(char c) {
|
||||||
|
return c == '/' || isValidDomainChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidDomainChar(char c) {
|
||||||
|
return c == '_' || c == '-' || c == '.' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package speiger.src.coreengine.assets.base;
|
package speiger.src.coreengine.assets.base;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
|
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
|
||||||
import speiger.src.collections.objects.collections.ObjectIterable;
|
import speiger.src.collections.objects.collections.ObjectIterable;
|
||||||
|
@ -37,6 +41,24 @@ public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
|
||||||
return assets.get(index);
|
return assets.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> Iterable<T> map(AssetMapper<T> mappingFunction, Supplier<T> defaultValue) {
|
||||||
|
return () -> new Iterator<T>() {
|
||||||
|
int index = 0;
|
||||||
|
int size = assets.size();
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() { return index < size; }
|
||||||
|
@Override
|
||||||
|
public T next() {
|
||||||
|
if(!hasNext()) throw new NoSuchElementException();
|
||||||
|
try { return mappingFunction.apply(assets.get(index++)); }
|
||||||
|
catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return defaultValue.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void forEach(Consumer<? super IAsset> action) {
|
public void forEach(Consumer<? super IAsset> action) {
|
||||||
assets.forEach(action);
|
assets.forEach(action);
|
||||||
|
@ -56,4 +78,8 @@ public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
|
||||||
public ObjectIterator<IAsset> iterator() {
|
public ObjectIterator<IAsset> iterator() {
|
||||||
return assets.iterator();
|
return assets.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface AssetMapper<T> {
|
||||||
|
public T apply(IAsset asset) throws IOException;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ public class FolderAssetPackage implements IAssetPackage {
|
||||||
@Override
|
@Override
|
||||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
||||||
try {
|
try {
|
||||||
Path start = baseFolder.resolve("assets");
|
Path start = baseFolder.resolve("assets/").resolve(domain);
|
||||||
for(Path path : IterableWrapper.wrap(Files.walk(start.resolve(domain)).filter(Files::isRegularFile).iterator())) {
|
for(Path path : IterableWrapper.wrap(Files.walk(start).filter(Files::isRegularFile).iterator())) {
|
||||||
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,39 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font;
|
package speiger.src.coreengine.rendering.gui.font;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
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.UnbakedGlyth.GlythBaker;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData.GlythBaker;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
|
||||||
|
import speiger.src.coreengine.rendering.tesselation.buffer.IVertexBuilder;
|
||||||
|
|
||||||
public class Font {
|
public class Font {
|
||||||
|
private static final AssetLocation DEFAULT = AssetLocation.of("default");
|
||||||
|
|
||||||
Map<AssetLocation, FontGroup> fonts;
|
Map<AssetLocation, FontGroup> fonts;
|
||||||
GlythBaker baker;
|
GlythBaker baker;
|
||||||
float size;
|
float size;
|
||||||
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;
|
||||||
|
|
||||||
protected Font(Map<AssetLocation, FontGroup> fonts, GlythBaker baker, float size, float oversample) {
|
protected Font(Map<AssetLocation, FontGroup> fonts, GlythBaker baker, float size, float oversample, Consumer<Runnable> clearing) {
|
||||||
this.fonts = fonts;
|
this.fonts = fonts;
|
||||||
this.baker = baker;
|
this.baker = baker;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.oversample = oversample;
|
this.oversample = oversample;
|
||||||
|
this.missingGlyth = new MissingGlyth(size, oversample * 2F);
|
||||||
|
clearing.accept(this::reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
for(int i = 0;i<4;i++) {
|
||||||
|
styledCache[i].reset();
|
||||||
|
}
|
||||||
|
missingGlyth.cleanCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData data(AssetLocation font, int codepoint, int style) {
|
public GlythData data(AssetLocation font, int codepoint, int style) {
|
||||||
|
@ -32,4 +47,39 @@ public class Font {
|
||||||
protected FontGroup font(AssetLocation font) {
|
protected FontGroup font(AssetLocation font) {
|
||||||
return fonts.get(font);
|
return fonts.get(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void drawText(String text, float x, float y, int color, TexturedBuffer buffer) {
|
||||||
|
int previousCodepoint = -1;
|
||||||
|
for(int i = 0,m=text.length();i<m;) {
|
||||||
|
int codepoint = text.codePointAt(i);
|
||||||
|
GlythData data = data(DEFAULT, codepoint, 0);
|
||||||
|
if(previousCodepoint != -1) {
|
||||||
|
x += data.kernling(previousCodepoint);
|
||||||
|
}
|
||||||
|
Glyth glyth = glyth(DEFAULT, codepoint, 0);
|
||||||
|
if(glyth.isValid()) {
|
||||||
|
float minX = glyth.left() + x;
|
||||||
|
float minY = glyth.top() + y;
|
||||||
|
float maxX = glyth.right() + x;
|
||||||
|
float maxY = glyth.bottom() + y;
|
||||||
|
|
||||||
|
IVertexBuilder builder = buffer.builderForTexture(glyth.texture());
|
||||||
|
builder.pos(minX, minY, 0F).tex(glyth.minU(), glyth.maxV()).rgba(-1).endVertex();
|
||||||
|
builder.pos(maxX, minY, 0F).tex(glyth.maxU(), glyth.maxV()).rgba(-1).endVertex();
|
||||||
|
builder.pos(maxX, maxY, 0F).tex(glyth.maxU(), glyth.minV()).rgba(-1).endVertex();
|
||||||
|
builder.pos(maxX, maxY, 0F).tex(glyth.maxU(), glyth.minV()).rgba(-1).endVertex();
|
||||||
|
builder.pos(minX, maxY, 0F).tex(glyth.minU(), glyth.minV()).rgba(-1).endVertex();
|
||||||
|
builder.pos(minX, minY, 0F).tex(glyth.minU(), glyth.maxV()).rgba(-1).endVertex();
|
||||||
|
}
|
||||||
|
x += data.advance();
|
||||||
|
i += Character.charCount(codepoint);
|
||||||
|
previousCodepoint = codepoint;
|
||||||
|
}
|
||||||
|
buffer.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface TexturedBuffer {
|
||||||
|
public IVertexBuilder builderForTexture(int textureId);
|
||||||
|
public void end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,49 +2,29 @@ package speiger.src.coreengine.rendering.gui.font;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
|
||||||
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.AssetLocation;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
|
|
||||||
public class FontGroup {
|
public class FontGroup {
|
||||||
AssetLocation locations;
|
AssetLocation locations;
|
||||||
List<IFontProvider> providers;
|
List<IFontProvider> providers;
|
||||||
StyledFont[] cache = new StyledFont[] {new StyledFont(0), new StyledFont(1), new StyledFont(2), new StyledFont(3)};
|
|
||||||
|
|
||||||
public FontGroup(AssetLocation locations, List<IFontProvider> providers) {
|
public FontGroup(AssetLocation locations, List<IFontProvider> providers) {
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
this.providers = providers;
|
this.providers = providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnbakedGlyth unbaked(int codepoint, int style) {
|
public GlythData data(int codepoint, int style, float size, float oversample) {
|
||||||
return cache[style & 0x3].unbaked(codepoint);
|
for(int i = 0,m=providers.size();i<m;i++) {
|
||||||
|
GlythData data = providers.get(i).glythData(codepoint, style, size, oversample);
|
||||||
|
if(data != null) return data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
providers.forEach(IFontProvider::close);
|
providers.forEach(IFontProvider::close);
|
||||||
providers.clear();
|
providers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledFont {
|
|
||||||
final int style;
|
|
||||||
Int2ObjectMap<UnbakedGlyth> dataGlyths = new Int2ObjectOpenHashMap<>();
|
|
||||||
|
|
||||||
public StyledFont(int style) {
|
|
||||||
this.style = style;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnbakedGlyth unbaked(int codepoint) {
|
|
||||||
return dataGlyths.computeIfAbsent(codepoint, this::compute);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnbakedGlyth compute(int codepoint) {
|
|
||||||
for(int i = 0,m=providers.size();i<m;i++) {
|
|
||||||
UnbakedGlyth data = providers.get(i).glythData(codepoint, style);
|
|
||||||
if(data != null) return data;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -2,39 +2,82 @@ package speiger.src.coreengine.rendering.gui.font;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
import speiger.src.collections.objects.lists.ObjectList;
|
||||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||||
|
import speiger.src.coreengine.assets.AssetFilter;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
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.base.IAssetProvider;
|
||||||
|
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.IFontProvider;
|
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
||||||
|
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||||
|
|
||||||
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, List<IFontProvider>>> {
|
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
|
||||||
private static final int TEXTURE_SIZE = 2048;
|
private static final int TEXTURE_SIZE = 2048;
|
||||||
|
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();
|
||||||
|
List<Runnable> listeners = new ObjectArrayList<>();
|
||||||
List<FontTexture> textures = new ObjectArrayList<>();
|
List<FontTexture> textures = new ObjectArrayList<>();
|
||||||
|
|
||||||
|
public FontManager() {
|
||||||
|
registerParser("stb-ttf", STBTrueTypeProvider::create);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
|
||||||
|
fontParsers.putIfAbsent(id, parser);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return null; }
|
public String getName() { return "Font Manager"; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<AssetLocation, ObjectList<IFontProvider>> prepare(IAssetProvider provider) {
|
||||||
|
Map<AssetLocation, IFontProvider> loadingCache = Object2ObjectMap.builder().linkedMap();
|
||||||
|
Object2ObjectMap<AssetLocation, ObjectList<IFontProvider>> providers = Object2ObjectMap.builder().linkedMap();
|
||||||
|
for(Entry<AssetLocation, MultiAsset> entry : FILTER.multiRoot(provider).entrySet()) {
|
||||||
|
AssetLocation id = entry.getKey();
|
||||||
|
for(JsonObject obj : entry.getValue().map(IAsset::json, JsonObject::new)) {
|
||||||
|
JsonUtil.iterateValues(obj.get("providers"), T -> {
|
||||||
|
AssetLocation location = AssetLocation.tryOf(T.getAsString());
|
||||||
|
if(location == null || !location.isInFolder()) return;
|
||||||
|
IFontProvider font = loadingCache.computeIfAbsent(location.prefix("font"), E -> getFont(E, provider));
|
||||||
|
if(font == null) return;
|
||||||
|
providers.supplyIfAbsent(FILTER.id(id), ObjectArrayList::new).add(font);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void apply(Map<AssetLocation, ObjectList<IFontProvider>> value, IAssetProvider provider) {
|
||||||
|
reset();
|
||||||
|
value.forEach((K, V) -> fonts.put(K, new FontGroup(K, V)));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
reset();
|
||||||
|
listeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void reset() {
|
||||||
protected Map<AssetLocation, List<IFontProvider>> prepare(IAssetProvider provider) {
|
listeners.forEach(Runnable::run);
|
||||||
return null;
|
textures.forEach(FontTexture::delete);
|
||||||
}
|
textures.clear();
|
||||||
|
fonts.values().forEach(FontGroup::close);
|
||||||
@Override
|
fonts.clear();
|
||||||
protected void apply(Map<AssetLocation, List<IFontProvider>> value, IAssetProvider provider) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font createFont(float size) {
|
public Font createFont(float size) {
|
||||||
|
@ -42,7 +85,7 @@ public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, List<
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font createFont(float size, float oversample) {
|
public Font createFont(float size, float oversample) {
|
||||||
return new Font(fonts, this::stitch, size, oversample);
|
return new Font(fonts, this::stitch, size, oversample, listeners::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Glyth stitch(IGlythSheetInfo info) {
|
private Glyth stitch(IGlythSheetInfo info) {
|
||||||
|
@ -55,4 +98,16 @@ public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, List<
|
||||||
Glyth glyth = texture.build(info);
|
Glyth glyth = texture.build(info);
|
||||||
return glyth;
|
return glyth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IFontProvider getFont(AssetLocation location, IAssetProvider provider) {
|
||||||
|
try(IAsset asset = provider.getAsset(location)) {
|
||||||
|
JsonObject obj = asset.json();
|
||||||
|
BiFunction<JsonObject, IAssetProvider, IFontProvider> builder = fontParsers.get(obj.get("type").getAsString());
|
||||||
|
return builder == null ? null : builder.apply(obj, provider);
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font;
|
package speiger.src.coreengine.rendering.gui.font;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
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.IGlythSheetInfo;
|
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||||
|
@ -43,7 +45,11 @@ public class FontTexture extends BaseTexture {
|
||||||
createTexture();
|
createTexture();
|
||||||
TextureMetadata metadata = metadataByColor(color);
|
TextureMetadata metadata = metadataByColor(color);
|
||||||
metadata.applyArguments(textureType());
|
metadata.applyArguments(textureType());
|
||||||
GLFunctions.upload2DImage(textureType(), 0, metadata, bounds, bounds, 0, 0L);
|
long allocate = MemoryUtil.nmemAlloc(bounds * bounds * formatByColor(color).components());
|
||||||
|
ITextureComponentFormat format = formatByColor(color);
|
||||||
|
GLFunctions.upload2DImage(textureType(), 0, format, bounds, bounds, 0, format, GLDataType.UNSIGNED_BYTE, allocate);
|
||||||
|
// GLFunctions.upload2DImage(textureType(), 0, metadata, bounds, bounds, 0, allocate);
|
||||||
|
MemoryUtil.nmemFree(allocate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Glyth build(IGlythSheetInfo info) {
|
public Glyth build(IGlythSheetInfo info) {
|
||||||
|
|
|
@ -19,6 +19,10 @@ public class GlythCache {
|
||||||
this.style = style;
|
this.style = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private FontCache cache(AssetLocation font) {
|
private FontCache cache(AssetLocation font) {
|
||||||
return cache.computeIfAbsent(font, FontCache::new);
|
return cache.computeIfAbsent(font, FontCache::new);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +43,7 @@ public class GlythCache {
|
||||||
public FontCache(AssetLocation fontId) {
|
public FontCache(AssetLocation fontId) {
|
||||||
this.fontId = fontId;
|
this.fontId = fontId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData data(int codepoint) {
|
public GlythData data(int codepoint) {
|
||||||
return data.computeIfAbsent(codepoint, this::compute);
|
return data.computeIfAbsent(codepoint, this::compute);
|
||||||
}
|
}
|
||||||
|
@ -49,12 +53,12 @@ public class GlythCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
private GlythData compute(int codepoint) {
|
private GlythData compute(int codepoint) {
|
||||||
return new GlythData(font.font(fontId).unbaked(codepoint, style), font.size);
|
GlythData data = font.font(fontId).data(codepoint, style, font.size, font.oversample);
|
||||||
|
return data == null ? font.missingGlyth : data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Glyth bake(int codepoint) {
|
private Glyth bake(int codepoint) {
|
||||||
return font.font(fontId).unbaked(codepoint, style).bake(font.baker, font.size, font.oversample);
|
return data(codepoint).bake(font.baker);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,4 +10,6 @@ public record Glyth(int texture, float minU, float minV, float maxU, float maxV,
|
||||||
public Glyth(int texture, float minU, float minV, float maxU, float maxV) {
|
public Glyth(int texture, float minU, float minV, float maxU, float maxV) {
|
||||||
this(texture, minU, minV, maxU, maxV, 0, 0, 0, 0);
|
this(texture, minU, minV, maxU, maxV, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isValid() { return texture != -1; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.glyth;
|
package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
import speiger.src.collections.ints.functions.function.Int2FloatFunction;
|
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 class GlythData {
|
public Glyth bake(GlythBaker baker);
|
||||||
float advance;
|
|
||||||
float shadowOffset;
|
|
||||||
Int2FloatMap kernlings = new Int2FloatOpenHashMap();
|
|
||||||
Int2FloatFunction kernling;
|
|
||||||
|
|
||||||
public GlythData(float advance, float shadowOffset, Int2FloatFunction kernling) {
|
|
||||||
this.advance = advance;
|
public static record EmptyGlythData(float advance) implements GlythData {
|
||||||
this.shadowOffset = shadowOffset;
|
@Override
|
||||||
this.kernling = kernling;
|
public Glyth bake(GlythBaker baker) { return Glyth.EMPTY; }
|
||||||
|
@Override
|
||||||
|
public float kernling(int codepoint) { return 0F; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlythData(UnbakedGlyth glyth, float size) {
|
public static interface GlythBaker {
|
||||||
this(glyth.advance(size), glyth.shadowOffset(), glyth::kernling);
|
Glyth bake(IGlythSheetInfo info);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public float advance() { return advance; }
|
|
||||||
public float shadowOffset() { return shadowOffset; }
|
|
||||||
public float kernling(int codepoint) { return kernlings.computeFloatIfAbsent(codepoint, kernling); }
|
|
||||||
}
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
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); }
|
||||||
|
}
|
|
@ -3,6 +3,15 @@ package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
public interface IGlythSheetInfo {
|
public interface IGlythSheetInfo {
|
||||||
public int width();
|
public int width();
|
||||||
public int height();
|
public int height();
|
||||||
|
public default float xOffset() { return 0F; }
|
||||||
|
public default float yOffset() { return 3F; }
|
||||||
|
public float oversample();
|
||||||
public boolean isColored();
|
public boolean isColored();
|
||||||
public void upload(int x, int y);
|
public void upload(int x, int y);
|
||||||
|
|
||||||
|
public default float left() { return xOffset(); }
|
||||||
|
public default float right() { return xOffset() + width() / oversample(); }
|
||||||
|
public default float top() { return yOffset(); }
|
||||||
|
public default float bottom() { return yOffset() + height() / oversample(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package speiger.src.coreengine.rendering.gui.font.glyth;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.math.MathUtils;
|
||||||
|
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||||
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
|
|
||||||
|
public class MissingGlyth implements GlythData {
|
||||||
|
private static final int WIDTH = 10;
|
||||||
|
private static final int HEIGHT = 57;
|
||||||
|
float size;
|
||||||
|
float oversample;
|
||||||
|
float advance;
|
||||||
|
float scale;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
Glyth cached;
|
||||||
|
|
||||||
|
public MissingGlyth(float size, float oversample) {
|
||||||
|
this.size = size;
|
||||||
|
this.oversample = oversample;
|
||||||
|
this.scale = (size * oversample) / HEIGHT;
|
||||||
|
this.advance = WIDTH * (size / HEIGHT);
|
||||||
|
this.width = (int)(WIDTH * scale);
|
||||||
|
this.height = (int)(HEIGHT * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanCache() {
|
||||||
|
cached = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float advance() { return advance; }
|
||||||
|
@Override
|
||||||
|
public float kernling(int codepoint) { return 0; }
|
||||||
|
@Override
|
||||||
|
public Glyth bake(GlythBaker baker) {
|
||||||
|
if(cached == null) {
|
||||||
|
cached = baker.bake(new IGlythSheetInfo() {
|
||||||
|
@Override
|
||||||
|
public int width() { return width; }
|
||||||
|
@Override
|
||||||
|
public int height() { return height; }
|
||||||
|
@Override
|
||||||
|
public void upload(int x, int y) {
|
||||||
|
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
||||||
|
draw(drawable);
|
||||||
|
drawable.upload(x, y, 0, 0, width, height);
|
||||||
|
drawable.close();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isColored() { return false; }
|
||||||
|
@Override
|
||||||
|
public float oversample() { return oversample; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void draw(Drawable texture) {
|
||||||
|
texture.fill(0, 0, width, height, 255);
|
||||||
|
int offset = MathUtils.ceil(width / 7.5F);
|
||||||
|
texture.fill(offset, offset, width - offset * 2, height - offset * 2, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.glyth;
|
|
||||||
|
|
||||||
public interface UnbakedGlyth {
|
|
||||||
public float advance(float size);
|
|
||||||
public float kernling(int codepoint);
|
|
||||||
public default float shadowOffset() { return 1F; }
|
|
||||||
public Glyth bake(GlythBaker baker, float size, float oversample);
|
|
||||||
|
|
||||||
|
|
||||||
public static record EmptyGlythData(float advance) implements UnbakedGlyth {
|
|
||||||
@Override
|
|
||||||
public Glyth bake(GlythBaker baker, float size, float oversample) { return Glyth.EMPTY; }
|
|
||||||
@Override
|
|
||||||
public float advance(float size) { return advance; }
|
|
||||||
@Override
|
|
||||||
public float kernling(int codepoint) { return 0F; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static interface GlythBaker {
|
|
||||||
Glyth bake(IGlythSheetInfo info);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
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.UnbakedGlyth;
|
|
||||||
|
|
||||||
public class BitmapProivder implements IFontProvider {
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UnbakedGlyth glythData(int codepoint, int style) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BitmapGlyth implements UnbakedGlyth {
|
|
||||||
int minX;
|
|
||||||
int minY;
|
|
||||||
int maxX;
|
|
||||||
int maxY;
|
|
||||||
int glyth;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Glyth bake(GlythBaker baker, float size, float oversample) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float advance(float size) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float kernling(int codepoint) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,14 @@
|
||||||
package speiger.src.coreengine.rendering.gui.font.providers;
|
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||||
|
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
|
|
||||||
public interface IFontProvider extends AutoCloseable {
|
public interface IFontProvider {
|
||||||
public static final int REGULAR = 0;
|
public static final int REGULAR = 0;
|
||||||
public static final int BOLD = 1;
|
public static final int BOLD = 1;
|
||||||
public static final int ITALIC = 2;
|
public static final int ITALIC = 2;
|
||||||
public static final int ITALIC_BOLD = 3;
|
public static final int ITALIC_BOLD = 3;
|
||||||
|
|
||||||
|
|
||||||
public UnbakedGlyth glythData(int codepoint, int style);
|
public GlythData glythData(int codepoint, int style, float size, float oversample);
|
||||||
@Override
|
public void close();
|
||||||
void close();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ 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.UnbakedGlyth;
|
import speiger.src.coreengine.rendering.gui.font.glyth.GlythData;
|
||||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
|
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.rendering.utils.values.textures.GLTextureFormat;
|
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||||
|
|
||||||
public class STBTrueTypeProvider implements IFontProvider {
|
public class STBTrueTypeProvider implements IFontProvider {
|
||||||
|
@ -53,7 +53,6 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
private static TrueTypeInstance create(int style, JsonObject obj, IAssetProvider provider) {
|
private static TrueTypeInstance create(int style, JsonObject obj, IAssetProvider provider) {
|
||||||
if(obj == null || !obj.has("file")) return null;
|
if(obj == null || !obj.has("file")) return null;
|
||||||
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
||||||
float size = JsonUtil.getOrDefault(obj, "size", 24F);
|
|
||||||
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
|
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
|
||||||
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
|
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
|
||||||
float xOff = 0;
|
float xOff = 0;
|
||||||
|
@ -74,7 +73,7 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
info.free();
|
info.free();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new TrueTypeInstance(style, MemoryUtil.memAddress(buffer), info, size, oversample, xOff, yOff, shadowOffset, builder.toString());
|
return new TrueTypeInstance(style, MemoryUtil.memAddress(buffer), info, oversample, xOff, yOff, shadowOffset, builder.toString());
|
||||||
}
|
}
|
||||||
catch(Exception e) {
|
catch(Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -91,10 +90,9 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
final float xOff;
|
final float xOff;
|
||||||
final float yOff;
|
final float yOff;
|
||||||
final float shadowOffset;
|
final float shadowOffset;
|
||||||
final float pointScale;
|
|
||||||
final float ascent;
|
final float ascent;
|
||||||
|
|
||||||
public TrueTypeInstance(int style, long data, STBTTFontinfo info, float size, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
public TrueTypeInstance(int style, long data, STBTTFontinfo info, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
||||||
this.style = style;
|
this.style = style;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
@ -103,10 +101,9 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
this.xOff = xOff;
|
this.xOff = xOff;
|
||||||
this.yOff = yOff;
|
this.yOff = yOff;
|
||||||
this.shadowOffset = shadowOffset;
|
this.shadowOffset = shadowOffset;
|
||||||
pointScale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
|
|
||||||
int[] ascent = new int[1];
|
int[] ascent = new int[1];
|
||||||
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
|
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
|
||||||
this.ascent = pointScale * ascent[0];
|
this.ascent = ascent[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void free() {
|
public void free() {
|
||||||
|
@ -116,37 +113,39 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
data = 0L;
|
data = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnbakedGlyth glythData(int codepoint) {
|
public GlythData 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;
|
||||||
|
oversample *= this.oversample;
|
||||||
|
float scale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
|
||||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||||
IntBuffer left = stack.mallocInt(1);
|
IntBuffer left = stack.mallocInt(1);
|
||||||
IntBuffer bottom = stack.mallocInt(1);
|
IntBuffer bottom = stack.mallocInt(1);
|
||||||
IntBuffer right = stack.mallocInt(1);
|
IntBuffer right = stack.mallocInt(1);
|
||||||
IntBuffer top = stack.mallocInt(1);
|
IntBuffer top = stack.mallocInt(1);
|
||||||
IntBuffer advance = stack.mallocInt(1);
|
IntBuffer advance = stack.mallocInt(1);
|
||||||
IntBuffer leftSideBearing = stack.mallocInt(1);
|
IntBuffer leftSideBearing = stack.mallocInt(1);
|
||||||
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
|
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
|
||||||
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, pointScale, pointScale, xOff, yOff, left, bottom, right, top);
|
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, scale, scale, xOff, yOff, left, bottom, right, top);
|
||||||
int minX = left.get(0);
|
int minX = left.get(0);
|
||||||
int minY = -top.get(0);
|
int minY = -top.get(0);
|
||||||
int maxX = right.get(0);
|
int maxX = right.get(0);
|
||||||
int maxY = -bottom.get(0);
|
int maxY = -bottom.get(0);
|
||||||
if(maxX - minX <= 0 || maxY - minY <= 0) return new EmptyGlythData(advance.get(0) * pointScale / oversample);
|
if(maxX - minX <= 0 || maxY - minY <= 0) return new EmptyGlythData(advance.get(0) * scale / oversample);
|
||||||
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0) * pointScale, leftSideBearing.get(0) * pointScale, glyth);
|
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0), leftSideBearing.get(0), scale, oversample, glyth);
|
||||||
}
|
}
|
||||||
catch(Throwable exception) {
|
catch(Exception e) {
|
||||||
exception.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UnbakedGlyth glythData(int codepoint, int style) {
|
public GlythData 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);
|
return instance == null ? null : instance.glythData(codepoint, size, oversample);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -159,48 +158,56 @@ public class STBTrueTypeProvider implements IFontProvider {
|
||||||
instances = null;
|
instances = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class STBGlyth implements UnbakedGlyth {
|
private static class STBGlyth implements GlythData {
|
||||||
final TrueTypeInstance owner;
|
final TrueTypeInstance owner;
|
||||||
|
final float xOffset;
|
||||||
|
final float yOffset;
|
||||||
final int width;
|
final int width;
|
||||||
final int height;
|
final int height;
|
||||||
|
final float oversample;
|
||||||
|
final float scale;
|
||||||
final float advance;
|
final float advance;
|
||||||
final int glyth;
|
final int glyth;
|
||||||
|
|
||||||
public STBGlyth(TrueTypeInstance 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, float scale, float oversample, 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.scale = scale;
|
||||||
|
this.oversample = oversample;
|
||||||
|
this.xOffset = ((leftPadding * scale) + minX + owner.xOff) / oversample;
|
||||||
|
this.yOffset = ((owner.ascent * scale) - maxY + owner.yOff) / oversample;
|
||||||
|
this.advance = advance * scale / oversample;
|
||||||
this.glyth = glyth;
|
this.glyth = glyth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float advance(float size) { return advance; }
|
public float advance() { return advance; }
|
||||||
@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); }
|
public float kernling(int codepoint) { return STBTruetype.stbtt_GetCodepointKernAdvance(owner.info, codepoint, glyth) * scale / oversample; }
|
||||||
@Override
|
@Override
|
||||||
public Glyth bake(GlythBaker baker, float size, float oversample) {
|
public Glyth bake(GlythBaker baker) {
|
||||||
return baker.bake(new IGlythSheetInfo() {
|
return baker.bake(new IGlythSheetInfo() {
|
||||||
|
@Override
|
||||||
|
public float xOffset() { return xOffset; }
|
||||||
|
@Override
|
||||||
|
public float yOffset() { return yOffset; }
|
||||||
@Override
|
@Override
|
||||||
public int width() { return width; }
|
public int width() { return width; }
|
||||||
@Override
|
@Override
|
||||||
public int height() { return height; }
|
public int height() { return height; }
|
||||||
@Override
|
@Override
|
||||||
|
public float oversample() { return oversample; }
|
||||||
|
@Override
|
||||||
public boolean isColored() { return false; }
|
public boolean isColored() { return false; }
|
||||||
@Override
|
@Override
|
||||||
public void upload(int x, int y) {
|
public void upload(int x, int y) {
|
||||||
|
System.out.println("Testing: "+GLStateTracker.instance().textures.getTextureId(0));
|
||||||
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
||||||
drawable.drawFont(owner.info, glyth, owner.xOff, owner.yOff, 0, 0, width, height, owner.pointScale, owner.pointScale);
|
drawable.drawFont(owner.info, glyth, owner.xOff, owner.yOff, 0, 0, width, height, scale, scale);
|
||||||
Drawable upload = new Drawable(GLTextureFormat.RGBA, width, height);
|
drawable.upload(x, y, 0, 0, width, height);
|
||||||
int pattern = Integer.divideUnsigned(-1, 255);
|
|
||||||
for(int i = 0,m=width*height;i<m;i++) {
|
|
||||||
upload.set(i, drawable.getR(i) * pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
upload.upload(x, y, 0, 0, width, height);
|
|
||||||
upload.close();
|
|
||||||
drawable.close();
|
drawable.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -129,9 +129,18 @@ public class Drawable implements IDrawable, AutoCloseable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fill(int x, int y, int width, int height, int data) {
|
public void fill(int x, int y, int width, int height, int data) {
|
||||||
if(components != 4) throw new IllegalStateException("Format has to be 4 components");
|
if(components != 4 && components != 1) throw new IllegalStateException("Format has to be 1 or 4 components");
|
||||||
ensureValid(x, y);
|
ensureValid(x, y);
|
||||||
ensureValid(x+width, y+height);
|
ensureValid(x+width, y+height);
|
||||||
|
if(components == 1) {
|
||||||
|
for(int xOff = 0;xOff<width;xOff++) {
|
||||||
|
for(int yOff = 0;yOff<height;yOff++) {
|
||||||
|
MemoryUtil.memPutByte(this.pixels + offset(x+xOff, y+yOff), (byte)(data & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(int xOff = 0;xOff<width;xOff++) {
|
for(int xOff = 0;xOff<width;xOff++) {
|
||||||
for(int yOff = 0;yOff<height;yOff++) {
|
for(int yOff = 0;yOff<height;yOff++) {
|
||||||
MemoryUtil.memPutInt(this.pixels + offset(x+xOff, y+yOff), data);
|
MemoryUtil.memPutInt(this.pixels + offset(x+xOff, y+yOff), data);
|
||||||
|
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"providers": [
|
||||||
|
"base:roboto/font.json"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec4 pass_color;
|
||||||
|
in vec2 pass_tex;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
|
||||||
|
uniform sampler2D texture;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 color = pass_color * texture2D(texture, pass_tex);
|
||||||
|
if(color.a < 0.2) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
frag_color = color;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#version 330
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 in_position;
|
||||||
|
layout(location = 1) in vec2 in_tex;
|
||||||
|
layout(location = 2) in vec4 in_color;
|
||||||
|
|
||||||
|
out vec4 pass_color;
|
||||||
|
out vec2 pass_tex;
|
||||||
|
|
||||||
|
uniform mat4 proViewMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = proViewMatrix * vec4(in_position, 1.0);
|
||||||
|
pass_color = in_color;
|
||||||
|
pass_tex = in_tex;
|
||||||
|
}
|
|
@ -9,5 +9,9 @@ uniform sampler2D texture;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
frag_color = pass_color * texture2D(texture, pass_tex);
|
vec4 color = pass_color * texture2D(texture, pass_tex);
|
||||||
|
if(color.a < 0.2) {
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
frag_color = color;
|
||||||
}
|
}
|
Loading…
Reference in New Issue