Reworked a couple systems.

-Added: STBImage support.
-Added: Dynamic Font Loader that supports Bitmap/TTF fonts (ttf using java not STB, because small deadline)
-Added: NativeMemory Loader as optional parser into asset loading.
-Reworked: How Images are made reloadable.
-Added: A dynamic AtlasBuilder
This commit is contained in:
Speiger 2021-09-28 01:35:07 +02:00
parent 9c947c4898
commit 4763e62b53
56 changed files with 1976 additions and 653 deletions

View File

@ -64,5 +64,5 @@ dependencies {
compile 'com.google.code.gson:gson:2.8.6' compile 'com.google.code.gson:gson:2.8.6'
//Primitive Collections //Primitive Collections
compile 'de.speiger:Primitive-Collections:0.3.5' compile 'de.speiger:Primitive-Collections:0.4.0'
} }

View File

@ -1,6 +1,7 @@
package speiger.src.coreengine.application; package speiger.src.coreengine.application;
import java.io.File; import java.io.File;
import java.nio.ByteBuffer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
import java.util.function.ObjLongConsumer; import java.util.function.ObjLongConsumer;
@ -11,6 +12,7 @@ import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.reloader.ResourceReloader; import speiger.src.coreengine.assets.reloader.ResourceReloader;
import speiger.src.coreengine.rendering.gui.GuiManager; import speiger.src.coreengine.rendering.gui.GuiManager;
import speiger.src.coreengine.rendering.gui.base.DebugOverlay; import speiger.src.coreengine.rendering.gui.base.DebugOverlay;
import speiger.src.coreengine.rendering.gui.renderer.provider.FontManager;
import speiger.src.coreengine.rendering.input.Keyboard; import speiger.src.coreengine.rendering.input.Keyboard;
import speiger.src.coreengine.rendering.input.Mouse; import speiger.src.coreengine.rendering.input.Mouse;
import speiger.src.coreengine.rendering.input.camera.Camera; import speiger.src.coreengine.rendering.input.camera.Camera;
@ -18,7 +20,8 @@ import speiger.src.coreengine.rendering.input.window.Window;
import speiger.src.coreengine.rendering.input.window.WindowProvider; import speiger.src.coreengine.rendering.input.window.WindowProvider;
import speiger.src.coreengine.rendering.shader.ProjectionBuffer; import speiger.src.coreengine.rendering.shader.ProjectionBuffer;
import speiger.src.coreengine.rendering.shader.ShaderTracker; import speiger.src.coreengine.rendering.shader.ShaderTracker;
import speiger.src.coreengine.rendering.textures.TextureManager; import speiger.src.coreengine.rendering.textures.base.NativeMemoryParser;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
import speiger.src.coreengine.rendering.utils.Cursor; import speiger.src.coreengine.rendering.utils.Cursor;
import speiger.src.coreengine.utils.counters.timers.FPSTimer; import speiger.src.coreengine.utils.counters.timers.FPSTimer;
import speiger.src.coreengine.utils.eventbus.EventBus; import speiger.src.coreengine.utils.eventbus.EventBus;
@ -41,6 +44,7 @@ public abstract class Application
protected ResourceReloader reloader = new ResourceReloader(); protected ResourceReloader reloader = new ResourceReloader();
protected AssetManager assetManager; protected AssetManager assetManager;
protected FontManager fonts = new FontManager();
protected ProjectionBuffer projectionBuffer; protected ProjectionBuffer projectionBuffer;
protected GuiManager uiManager; protected GuiManager uiManager;
@ -49,10 +53,11 @@ public abstract class Application
GLFWErrorCallback.createPrint(System.err).set(); GLFWErrorCallback.createPrint(System.err).set();
if(!GLFW.glfwInit()) throw new IllegalStateException("OpenGL can't be loaded"); if(!GLFW.glfwInit()) throw new IllegalStateException("OpenGL can't be loaded");
provider.init(); provider.init();
boolean initEarly = earlyUILoad();
try try
{ {
mainWindow = createWindow(provider); mainWindow = createWindow(provider);
mainWindow.finishWindow(); if(initEarly) mainWindow.finishWindow();
} }
catch(Exception e) catch(Exception e)
{ {
@ -68,6 +73,7 @@ public abstract class Application
file = file.getName().endsWith(".jar") ? file : new File("bin/main"); file = file.getName().endsWith(".jar") ? file : new File("bin/main");
internalInit(file); internalInit(file);
init(file); init(file);
if(!initEarly) mainWindow.finishWindow();
executor.start(mainWindow); executor.start(mainWindow);
mainWindow.destroy(); mainWindow.destroy();
reloader.deleteResources(); reloader.deleteResources();
@ -78,8 +84,12 @@ public abstract class Application
protected void internalInit(File file) protected void internalInit(File file)
{ {
assetManager = reloader.addReloadableResource(new AssetManager(file), true); assetManager = reloader.addReloadableResource(new AssetManager(file), true);
assetManager.registerAssetParser(ByteBuffer.class, new NativeMemoryParser());
reloader.addReloadableResource(fonts);
fonts.setAssetManager(assetManager);
ShaderTracker.INSTANCE.init(assetManager); ShaderTracker.INSTANCE.init(assetManager);
TextureManager.INSTANCE.init(assetManager); TextureManager.INSTANCE.init(assetManager);
preinit();
reloader.addReloadableResource(ShaderTracker.INSTANCE); reloader.addReloadableResource(ShaderTracker.INSTANCE);
reloader.addReloadableResource(TextureManager.INSTANCE); reloader.addReloadableResource(TextureManager.INSTANCE);
camera = new Camera(mainWindow); camera = new Camera(mainWindow);
@ -95,8 +105,10 @@ public abstract class Application
public void addExtraTickRates(IntConsumer ticks) {}; public void addExtraTickRates(IntConsumer ticks) {};
public void addExtraTimers(ObjLongConsumer<String> profiler) {}; public void addExtraTimers(ObjLongConsumer<String> profiler) {};
public boolean initUI() { return true; } public boolean initUI() { return true; }
public boolean earlyUILoad() { return true; }
public DebugOverlay createCustomDebug() { return null; } public DebugOverlay createCustomDebug() { return null; }
public abstract Window createWindow(WindowProvider provider) throws Exception; public abstract Window createWindow(WindowProvider provider) throws Exception;
public void preinit() {}
public abstract void init(File file); public abstract void init(File file);
public abstract void update(); public abstract void update();
public abstract void render(float particalTicks); public abstract void render(float particalTicks);

View File

@ -13,7 +13,7 @@ public class BaseUIManager extends GuiManager
public BaseUIManager(Application application) public BaseUIManager(Application application)
{ {
super(application.mainWindow, application.eventBus); super(application.mainWindow, application.eventBus, application.fonts);
this.application = application; this.application = application;
} }

View File

@ -7,9 +7,9 @@ import java.util.function.Function;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap; import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps; import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
public final class AssetLocation public final class AssetLocation implements Comparable<AssetLocation>
{ {
static final Map<String, AssetLocation> LOCATION = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<String, AssetLocation>()); static final Map<String, AssetLocation> LOCATION = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>());
static final Function<String, AssetLocation> BUILDER = AssetLocation::compute; static final Function<String, AssetLocation> BUILDER = AssetLocation::compute;
final String domain; final String domain;
final String location; final String location;
@ -74,6 +74,13 @@ public final class AssetLocation
return false; return false;
} }
@Override
public int compareTo(AssetLocation o)
{
int result = domain.compareToIgnoreCase(o.domain);
return result != 0 ? result : location.compareToIgnoreCase(location);
}
public boolean matches(AssetLocation location) public boolean matches(AssetLocation location)
{ {
return location.domain.equals(domain) && location.location.equals(this.location); return location.domain.equals(domain) && location.location.equals(this.location);

View File

@ -5,21 +5,25 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap; import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap; import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap.Entry;
import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.impl.FolderAssetPackage; import speiger.src.coreengine.assets.impl.FolderAssetPackage;
import speiger.src.coreengine.assets.impl.ZipAssetPackage; import speiger.src.coreengine.assets.impl.ZipAssetPackage;
import speiger.src.coreengine.assets.reloader.IReloadableResource; import speiger.src.coreengine.assets.reloader.IReloadableResource;
public class AssetManager implements IReloadableResource public class AssetManager implements IReloadableResource
{ {
Map<String, DomainAssets> domains = new Object2ObjectLinkedOpenHashMap<>(); Object2ObjectMap<String, DomainAssets> domains = new Object2ObjectLinkedOpenHashMap<>();
Object2ObjectMap<Class<?>, IAssetParser<?>> parsers = new Object2ObjectLinkedOpenHashMap<>(); Object2ObjectMap<Class<?>, IAssetParser<?>> parsers = new Object2ObjectLinkedOpenHashMap<>();
Path path; Path path;
@ -121,11 +125,21 @@ public class AssetManager implements IReloadableResource
DomainAssets asset = domains.get(location.getDomain()); DomainAssets asset = domains.get(location.getDomain());
if(asset == null) if(asset == null)
{ {
throw new FileNotFoundException("File["+location.toString()+"] not found"); throw new FileNotFoundException("Domain & File["+location.toString()+"] not found");
} }
return asset.getAllAssets(location); return asset.getAllAssets(location);
} }
public Collection<AssetLocation> gatherAssets(String location, int maxDepth, Predicate<String> filter)
{
Set<AssetLocation> result = new ObjectLinkedOpenHashSet<>();
for(Entry<String, DomainAssets> asset : Object2ObjectMaps.fastIterable(domains))
{
asset.getValue().gatherAssets(AssetLocation.of(asset.getKey(), location), maxDepth, filter, result);
}
return result;
}
protected boolean isZipFile(Path file) protected boolean isZipFile(Path file)
{ {
try(ZipFile zip = new ZipFile(file.toFile())) { return true; } try(ZipFile zip = new ZipFile(file.toFile())) { return true; }
@ -185,5 +199,13 @@ public class AssetManager implements IReloadableResource
} }
return new MultiAsset(assets.toArray(new IAsset[assets.size()])); return new MultiAsset(assets.toArray(new IAsset[assets.size()]));
} }
public void gatherAssets(AssetLocation folder, int maxDepth, Predicate<String> filter, Collection<AssetLocation> result)
{
for(IAssetPackage entry : packages)
{
entry.getAllAssets(folder, filter, maxDepth, result);
}
}
} }
} }

View File

@ -5,6 +5,7 @@ import java.io.BufferedReader;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
@ -16,11 +17,13 @@ public interface IAsset extends Closeable
public InputStream getStream() throws IOException; public InputStream getStream() throws IOException;
public BufferedImage getTexture() throws Exception; public ByteBuffer getBytes() throws IOException;
public BufferedReader getStringReader() throws IOException; public BufferedReader getStringReader() throws IOException;
public JsonObject getJsonObject() throws IOException; public JsonObject getJsonObject() throws IOException;
public BufferedImage getTexture() throws Exception;
public <T> T getCustom(Class<T> clz) throws IOException; public <T> T getCustom(Class<T> clz) throws IOException;
} }

View File

@ -1,11 +1,14 @@
package speiger.src.coreengine.assets; package speiger.src.coreengine.assets;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
public interface IAssetPackage public interface IAssetPackage
{ {
public void setParsers(Function<Class<?>, IAssetParser<?>> parsers); public void setParsers(Function<Class<?>, IAssetParser<?>> parsers);
public List<String> getDomains(); public List<String> getDomains();
public IAsset getAsset(AssetLocation location); public IAsset getAsset(AssetLocation location);
public void getAllAssets(AssetLocation folder, Predicate<String> fileNames, int maxDepth, Collection<AssetLocation> result);
} }

View File

@ -1,10 +1,11 @@
package speiger.src.coreengine.assets; package speiger.src.coreengine.assets;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.function.Consumer; import java.util.function.Consumer;
public interface IAssetParser<T> public interface IAssetParser<T>
{ {
public T parseAsset(Path path, Consumer<Closeable> autoCloser); public T parseAsset(Path path, Consumer<Closeable> autoCloser) throws IOException;
} }

View File

@ -5,6 +5,7 @@ import java.io.BufferedReader;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
@ -76,6 +77,12 @@ public class FolderAsset implements IAsset
return markClosed(Files.newInputStream(path)); return markClosed(Files.newInputStream(path));
} }
@Override
public ByteBuffer getBytes() throws IOException
{
return ByteBuffer.wrap(Files.readAllBytes(path));
}
@Override @Override
public BufferedImage getTexture() throws Exception public BufferedImage getTexture() throws Exception
{ {

View File

@ -5,14 +5,18 @@ import java.io.IOException;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset; import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.assets.IAssetPackage; import speiger.src.coreengine.assets.IAssetPackage;
import speiger.src.coreengine.assets.IAssetParser; import speiger.src.coreengine.assets.IAssetParser;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class FolderAssetPackage implements IAssetPackage public class FolderAssetPackage implements IAssetPackage
{ {
@ -59,4 +63,22 @@ public class FolderAssetPackage implements IAssetPackage
Path path = baseFolder.resolve(location.getActualLocation()); Path path = baseFolder.resolve(location.getActualLocation());
return Files.exists(path) ? new FolderAsset(location, path, parsers) : null; return Files.exists(path) ? new FolderAsset(location, path, parsers) : null;
} }
@Override
public void getAllAssets(AssetLocation folder, Predicate<String> fileNames, int maxDepth, Collection<AssetLocation> result)
{
Path start = baseFolder.resolve(folder.getActualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start, maxDepth).filter(Files::isRegularFile).filter(T -> fileNames.test(T.getFileName().toString())))
{
for(Path path : IterableWrapper.wrap(stream.iterator()))
{
result.add(folder.subAsset(start.relativize(path).toString()));
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
} }

View File

@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.function.Function; import java.util.function.Function;
@ -71,6 +72,12 @@ public class ZipAsset implements IAsset
return Files.newInputStream(path); return Files.newInputStream(path);
} }
@Override
public ByteBuffer getBytes() throws IOException
{
return ByteBuffer.wrap(Files.readAllBytes(path));
}
@Override @Override
public BufferedImage getTexture() throws Exception public BufferedImage getTexture() throws Exception
{ {

View File

@ -7,15 +7,19 @@ import java.nio.file.FileSystem;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset; import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.assets.IAssetPackage; import speiger.src.coreengine.assets.IAssetPackage;
import speiger.src.coreengine.assets.IAssetParser; import speiger.src.coreengine.assets.IAssetParser;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class ZipAssetPackage implements IAssetPackage public class ZipAssetPackage implements IAssetPackage
{ {
@ -90,4 +94,23 @@ public class ZipAssetPackage implements IAssetPackage
} }
catch(Exception e) { return null; } catch(Exception e) { return null; }
} }
@Override
public void getAllAssets(AssetLocation folder, Predicate<String> fileNames, int maxDepth, Collection<AssetLocation> result)
{
try(FileSystem system = FileSystems.newFileSystem(baseFolder, null))
{
Path start = system.getPath(folder.getActualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start, maxDepth).filter(Files::isRegularFile).filter(T -> fileNames.test(T.getFileName().toString())))
{
for(Path path : IterableWrapper.wrap(stream.iterator()))
{
result.add(folder.subAsset(start.relativize(path).toString()));
}
}
catch(IOException e) { e.printStackTrace(); }
}
catch(Exception e) { e.printStackTrace(); }
}
} }

View File

@ -6,7 +6,7 @@ import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
public class ResourceReloader public class ResourceReloader
{ {
Set<IReloadableResource> resources = new ObjectLinkedOpenHashSet<IReloadableResource>(); Set<IReloadableResource> resources = new ObjectLinkedOpenHashSet<>();
boolean globalRemoval = false; boolean globalRemoval = false;
boolean reloading = false; boolean reloading = false;

View File

@ -316,6 +316,16 @@ public class ColorObject
return "Color[r=" + getRedFloat() + ", g=" + getGreenFloat() + ", b=" + getBlueFloat() + ", a=" + getAlphaFloat() + "]"; return "Color[r=" + getRedFloat() + ", g=" + getGreenFloat() + ", b=" + getBlueFloat() + ", a=" + getAlphaFloat() + "]";
} }
public static byte[] toByteArray(int color, boolean alpha)
{
byte[] data = new byte[alpha ? 4 : 3];
data[0] = (byte)((color >> 16) & 0xFF);
data[1] = (byte)((color >> 8) & 0xFF);
data[2] = (byte)(color & 0xFF);
if(alpha) data[3] = (byte)((color >> 24) & 0xFF);
return data;
}
public static void pack(int color, boolean alpha, ByteBuffer buffer) public static void pack(int color, boolean alpha, ByteBuffer buffer)
{ {
buffer.put((byte)((color >> 16) & 0xFF)).put((byte)((color >> 8) & 0xFF)).put((byte)(color & 0xFF)); buffer.put((byte)((color >> 16) & 0xFF)).put((byte)((color >> 8) & 0xFF)).put((byte)(color & 0xFF));

View File

@ -1,118 +0,0 @@
package speiger.src.coreengine.rendering.gui;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;
import speiger.src.collections.chars.maps.impl.hash.Char2ObjectOpenHashMap;
import speiger.src.collections.chars.maps.interfaces.Char2ObjectMap;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.rendering.gui.renderer.FontRenderer;
import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.textures.SimpleTexture;
import speiger.src.coreengine.rendering.textures.TextureManager;
public class FontLoader
{
public static FontRenderer createFont(AssetLocation location, String name)
{
return createFont(location, name, 0.35F);
}
public static FontRenderer createFont(AssetLocation location, String name, float scale)
{
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location.subAsset(name+".fnt")))
{
Char2ObjectMap<CharInstance>[] maps = new Char2ObjectMap[]{new Char2ObjectOpenHashMap<CharInstance>(), new Char2ObjectOpenHashMap<CharInstance>()};
BufferedReader reader = asset.getStringReader();
FontInfo info = new FontInfo(convert(reader.readLine().split(", ")));
String value = null;
while((value = getNextValidLine(reader)) != null)
{
Map<String, Integer> dataMap = convert(value.split(", "));
CharInstance instance = createChar(dataMap, info);
instance.scale(scale);
maps[instance.isBold() ? 1 : 0].putIfAbsent(instance.getCharacter(), instance);
}
info.scale(scale);
return new FontRenderer(maps, new SimpleTexture(location.subAsset(name+"-Texture.png")), info.fontHeight, info.lineHeight);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
static String getNextValidLine(BufferedReader reader) throws Exception
{
String line = reader.readLine();
if(line == null)
{
return null;
}
else if(line.isEmpty() || line.startsWith("//"))
{
return getNextValidLine(reader);
}
return line;
}
static CharInstance createChar(Map<String, Integer> data, FontInfo info)
{
char character = (char)data.get("letter").intValue();
int minX = data.get("minX");
int minY = data.get("minY");
int maxX = data.get("maxX");
int maxY = data.get("maxY");
return new CharInstance(character, maxX - minX, maxY - minY, info.getTextureU(minX), info.getTextureV(minY), info.getTextureU(maxX), info.getTextureV(maxY), maxX - minX, data.getOrDefault("bold", 0).intValue() == 1);
}
static Map<String, Integer> convert(String[] data)
{
Map<String, Integer> map = new HashMap<String, Integer>();
for(String s : data)
{
int index = s.indexOf("=");
if(index != -1)
{
String[] split = s.split("=");
map.put(split[0], Integer.parseInt(split[1]));
}
}
return map;
}
public static class FontInfo
{
int height;
int width;
float fontHeight;
float lineHeight;
public FontInfo(Map<String, Integer> data)
{
width = data.get("textureWidth");
height = data.get("textureHeight");
fontHeight = data.get("fontHeight");
lineHeight = data.get("base");
}
public void scale(float scale)
{
fontHeight *= scale;
lineHeight *= scale;
}
public float getTextureU(float value)
{
return value / width;
}
public float getTextureV(float value)
{
return value / height;
}
}
}

View File

@ -8,6 +8,7 @@ import speiger.src.coreengine.rendering.gui.base.DebugOverlay;
import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; import speiger.src.coreengine.rendering.gui.renderer.FontRenderer;
import speiger.src.coreengine.rendering.gui.renderer.GuiShader; import speiger.src.coreengine.rendering.gui.renderer.GuiShader;
import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; import speiger.src.coreengine.rendering.gui.renderer.UIRenderer;
import speiger.src.coreengine.rendering.gui.renderer.provider.FontManager;
import speiger.src.coreengine.rendering.input.events.KeyEvent.CharTypeEvent; import speiger.src.coreengine.rendering.input.events.KeyEvent.CharTypeEvent;
import speiger.src.coreengine.rendering.input.events.KeyEvent.KeyPressEvent; import speiger.src.coreengine.rendering.input.events.KeyEvent.KeyPressEvent;
import speiger.src.coreengine.rendering.input.events.MouseEvent; import speiger.src.coreengine.rendering.input.events.MouseEvent;
@ -31,12 +32,13 @@ public abstract class GuiManager implements IWindowListener
protected ScaledResolution res; protected ScaledResolution res;
protected long globalClock = 0L; protected long globalClock = 0L;
protected boolean isReloading = false; protected boolean isReloading = false;
protected FontRenderer font = FontLoader.createFont(AssetLocation.of("font"), "Roboto-Font"); protected FontRenderer font;
protected GuiShader shader = ShaderTracker.INSTANCE.register(GuiShader::create, T -> shader = T); protected GuiShader shader = ShaderTracker.INSTANCE.register(GuiShader::create, T -> shader = T);
public GuiManager(Window window, EventBus bus) public GuiManager(Window window, EventBus bus, FontManager manager)
{ {
this.window = window; this.window = window;
font = manager.loadFont(AssetLocation.of("font/roboto.json"), 18.5F);
bus.register(MouseEvent.class, this::onMouseEvent); bus.register(MouseEvent.class, this::onMouseEvent);
bus.register(KeyPressEvent.class, (T) -> T.setCanceled(onKeyPressed(T.key))); bus.register(KeyPressEvent.class, (T) -> T.setCanceled(onKeyPressed(T.key)));
bus.register(CharTypeEvent.class, (T) -> T.setCanceled(onCharTyped(T.character, T.codePoint))); bus.register(CharTypeEvent.class, (T) -> T.setCanceled(onCharTyped(T.character, T.codePoint)));

View File

@ -1,19 +1,24 @@
package speiger.src.coreengine.rendering.gui; package speiger.src.coreengine.rendering.gui;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.rendering.textures.SimpleTexture;
public class UITextures public class UITextures
{ {
public static final AssetLocation TEXTURE_LOCATION = AssetLocation.of("textures"); public static final AssetLocation TEXTURE_LOCATION = AssetLocation.of("textures");
// public static final ITexture OK_SYMBOL = new SimpleTexture(sub("okSymbol.png")); public static final ITexture COLOR_WHEEL = ITexture.simple(sub("colorWheel.png")).makeReloadable();
// public static final ITexture CANCLE_SYMBOL = new SimpleTexture(sub("cancelSymbol.png"));
public static final ITexture COLOR_WHEEL = new SimpleTexture(sub("colorWheel.png"));
public static AssetLocation sub(String name)
{ public static ITexture createReloadable(String name) {
return ITexture.simple(sub(name)).makeReloadable();
}
public static ITexture create(String name) {
return ITexture.simple(sub(name));
}
public static AssetLocation sub(String name) {
return TEXTURE_LOCATION.subAsset(name); return TEXTURE_LOCATION.subAsset(name);
} }
} }

View File

@ -2,7 +2,7 @@ package speiger.src.coreengine.rendering.gui.components;
import speiger.src.coreengine.math.misc.ColorObject; import speiger.src.coreengine.math.misc.ColorObject;
import speiger.src.coreengine.rendering.gui.GuiComponent; import speiger.src.coreengine.rendering.gui.GuiComponent;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
public class IconComponent extends GuiComponent public class IconComponent extends GuiComponent
{ {

View File

@ -52,6 +52,7 @@ public class ListComponent<T extends IListEntry> extends GuiComponent
protected int selectionMode = 1; protected int selectionMode = 1;
protected int updateMode = 1; protected int updateMode = 1;
protected float entryHeight; protected float entryHeight;
protected float cachedWidth = 0F;
protected ScrollBarComponent verticalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY); protected ScrollBarComponent verticalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY);
protected ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY).setHorizontal(true); protected ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY).setHorizontal(true);
protected Vec2i lastMouse = Vec2i.newMutable(); protected Vec2i lastMouse = Vec2i.newMutable();
@ -416,6 +417,11 @@ public class ListComponent<T extends IListEntry> extends GuiComponent
return rangeIterator(start, MathUtils.clamp(0, entries.size() - 1, start + getIndexWidth())); return rangeIterator(start, MathUtils.clamp(0, entries.size() - 1, start + getIndexWidth()));
} }
public float getCachedWidth()
{
return cachedWidth;
}
@Override @Override
protected void repaint() protected void repaint()
{ {
@ -434,6 +440,7 @@ public class ListComponent<T extends IListEntry> extends GuiComponent
{ {
width = Math.max(width, entries.get(i).getWidth()); width = Math.max(width, entries.get(i).getWidth());
} }
this.cachedWidth = width;
boolean lastVertical = this.verticalBar.isInUse(); boolean lastVertical = this.verticalBar.isInUse();
boolean lastHorizontal = this.horizontalBar.isInUse(); boolean lastHorizontal = this.horizontalBar.isInUse();
verticalBar.setScrollMax(MathUtils.ceil(this.entries.size() * entryHeight)); verticalBar.setScrollMax(MathUtils.ceil(this.entries.size() * entryHeight));

View File

@ -2,7 +2,7 @@ package speiger.src.coreengine.rendering.gui.components.icon;
import speiger.src.coreengine.math.misc.ColorObject; import speiger.src.coreengine.math.misc.ColorObject;
import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; import speiger.src.coreengine.rendering.gui.renderer.UIRenderer;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
public class TexturedIcon implements IIcon public class TexturedIcon implements IIcon
{ {

View File

@ -0,0 +1,241 @@
package speiger.src.coreengine.rendering.gui.helper;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.textures.custom.TextureAtlas;
import speiger.src.coreengine.rendering.textures.custom.TextureAtlas.AtlasEntry;
import speiger.src.coreengine.rendering.textures.custom.TextureAtlas.Builder;
public class FontBuilder
{
public static final int LITERAL = 1;
public static final int PLAIN = 2;
public static final int BOLD = 4;
public static ObjectObjectPair<BufferedImage, JsonObject> createBitmapFont(InputStream stream, float size)
{
ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> result = createBitmapFont(stream, "ISO-8859-1", PLAIN | BOLD, size);
if(result == null) return null;
JsonArray array = new JsonArray();
result.getValue().forEach(T -> array.add(T.seralize()));
JsonObject info = new JsonObject();
ObjectObjectPair<Vec2i, BufferedImage> key = result.getKey();
info.addProperty("width", key.getValue().getWidth());
info.addProperty("height", key.getValue().getHeight());
info.addProperty("base", key.getKey().getX());
info.addProperty("charHeight", key.getKey().getY());
info.addProperty("tabs", 4);
JsonObject data = new JsonObject();
data.addProperty("type", "bitmap");
data.addProperty("file", "?");
data.add("info", info);
data.add("chars", array);
return ObjectObjectPair.of(key.getValue(), data);
}
public static ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> createBitmapFont(InputStream ttf, String characters, int flags, float size)
{
try
{
Map<AssetLocation, CharData> toDraw = new Object2ObjectLinkedOpenHashMap<>();
Builder builder = TextureAtlas.create();
Consumer<CharData> data = T -> {
AssetLocation location = T.asLocation();
toDraw.put(location, T);
if(T.width > 0 && !builder.add(location, T.width, T.getExtraY(T.height))) throw new IllegalStateException("Character: " + location + " isnt Accepted, W=" + T.width + ", H=" + T.height);
};
Font font = Font.createFont(Font.TRUETYPE_FONT, ttf).deriveFont(size);
String validChars = (flags & LITERAL) != 0 ? characters : getChars(characters, font);
if((flags & PLAIN) != 0) loadFontData(font, validChars, data);
if((flags & BOLD) != 0) loadFontData(font.deriveFont(Font.BOLD), validChars, data);
ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> result = ObjectObjectPair.mutableValue(new ObjectArrayList<>());
builder.buildHollow((K, V) -> {
BufferedImage image = new BufferedImage(K.getX(), K.getY(), BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = image.createGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
graphics.setFont(font);
FontMetrics metric = graphics.getFontMetrics();
int extra = 0;
for(AtlasEntry entry : V)
{
CharData pair = toDraw.remove(entry.getLocation());
extra = pair.extraY;
graphics.setFont(pair.getFont());
graphics.setColor(Color.WHITE);
graphics.drawString(Character.toString(pair.getLetter()), entry.getX()-pair.xOffset, pair.getExtraY(entry.getY()+metric.getAscent()));
result.getValue().add(new WrittenChar(pair.getLetter(), entry.getX(), entry.getY(), entry.getWidth(), entry.getHeight(), pair.isBold()));
}
toDraw.values().forEach(T -> result.getValue().add(new WrittenChar(T.getLetter(), 0, 0, 0, 0, T.isBold())));
result.setKey(ObjectObjectPair.of(Vec2i.newVec(metric.getAscent()+extra, metric.getHeight()+extra), image));
graphics.dispose();
});
return result;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
private static float convert(float pos, float width)
{
return pos / width;
}
private static String getChars(String s, Font font)
{
CharsetEncoder encoder = Charset.forName(s).newEncoder();
StringBuilder builder = new StringBuilder();
for(char c = 0;c < Character.MAX_VALUE;c++)
{
if(encoder.canEncode(c) && font.canDisplay(c)) builder.append(c);
}
return builder.toString();
}
private static void loadFontData(Font font, String chars, Consumer<CharData> listener)
{
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = (Graphics2D)image.getGraphics();
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics.setFont(font);
FontMetrics metric = graphics.getFontMetrics();
int extraHeight = 0;
List<CharData> data = new ObjectArrayList<>();
for(char letter : chars.toCharArray())
{
Rectangle rect = font.layoutGlyphVector(graphics.getFontRenderContext(), new char[] {letter }, 0, 1, 0).getGlyphPixelBounds(0, graphics.getFontRenderContext(), 0.0F, 0.0F);
extraHeight = Math.min(extraHeight, rect.y);
data.add(new CharData(font, letter, rect, metric.charWidth(letter), metric.getHeight(), font.isBold()));
}
extraHeight = -(extraHeight+metric.getAscent());
for(int i = 0,m=data.size();i<m;listener.accept(data.get(i++).offset(extraHeight)));
graphics.dispose();
}
public static class WrittenChar
{
char letter;
int x;
int y;
int width;
int height;
boolean bold;
public WrittenChar(char letter, int x, int y, int width, int height, boolean bold)
{
this.letter = letter;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.bold = bold;
}
public JsonObject seralize()
{
JsonObject obj = new JsonObject();
obj.addProperty("char", (int)letter);
obj.addProperty("minX", x);
obj.addProperty("minY", y);
obj.addProperty("maxX", x+width);
obj.addProperty("maxY", y+height);
obj.addProperty("bold", bold);
return obj;
}
public CharInstance create(int textureWidth, int textureHeight)
{
return new CharInstance(letter, width, height, convert(x, textureWidth), convert(y, textureHeight), convert(x+width, textureWidth), convert(y+height, textureHeight), width, bold);
}
}
private static class CharData
{
Font font;
char letter;
int xOffset;
int width;
int height;
boolean bold;
int extraY = 0;
public CharData(Font font, char letter, Rectangle bounds, int width, int height, boolean bold)
{
this.font = font;
this.letter = letter;
if(bounds.x >= 0) this.width = width;
else
{
this.width = bounds.width == 0 ? width : bounds.width;
xOffset = bounds.x;
}
this.height = height;
this.bold = bold;
}
private CharData offset(int offset)
{
extraY += offset;
return this;
}
public boolean isBold()
{
return bold;
}
public Font getFont()
{
return font;
}
public int getExtraY(int asent)
{
return extraY + asent;
}
public char getLetter()
{
return letter;
}
public AssetLocation asLocation()
{
return AssetLocation.of("base", font.getFontName().replaceAll(" ", "_") + (bold ? "_Bold" : "") + "_" + ((int)letter));
}
}
}

View File

@ -7,6 +7,7 @@ public class TextFilter
public static final Predicate<String> INTEGER_ONLY = T -> { public static final Predicate<String> INTEGER_ONLY = T -> {
try { try {
if(T == null || T.isEmpty()); if(T == null || T.isEmpty());
else if(T.length() == 1 && T.charAt(0) == '-');
else Integer.parseInt(T); else Integer.parseInt(T);
return true; return true;
} }
@ -16,6 +17,7 @@ public class TextFilter
public static final Predicate<String> FLOAT_ONLY = T -> { public static final Predicate<String> FLOAT_ONLY = T -> {
try { try {
if(T == null || T.isEmpty()); if(T == null || T.isEmpty());
else if(T.length() == 1 && T.charAt(0) == '-');
else Float.parseFloat(T); else Float.parseFloat(T);
return true; return true;
} }

View File

@ -5,7 +5,6 @@ import java.util.Locale;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import speiger.src.collections.chars.maps.interfaces.Char2ObjectMap;
import speiger.src.collections.floats.lists.FloatArrayList; import speiger.src.collections.floats.lists.FloatArrayList;
import speiger.src.collections.floats.lists.FloatList; import speiger.src.collections.floats.lists.FloatList;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
@ -20,11 +19,12 @@ import speiger.src.coreengine.rendering.gui.renderer.lexer.Line;
import speiger.src.coreengine.rendering.gui.renderer.lexer.TextContext; import speiger.src.coreengine.rendering.gui.renderer.lexer.TextContext;
import speiger.src.coreengine.rendering.gui.renderer.lexer.TextContext.WordContext; import speiger.src.coreengine.rendering.gui.renderer.lexer.TextContext.WordContext;
import speiger.src.coreengine.rendering.gui.renderer.lexer.TextLexer; import speiger.src.coreengine.rendering.gui.renderer.lexer.TextLexer;
import speiger.src.coreengine.rendering.gui.renderer.provider.IFontProvider;
import speiger.src.coreengine.rendering.models.DrawCall; import speiger.src.coreengine.rendering.models.DrawCall;
import speiger.src.coreengine.rendering.tesselation.IVertexBuilder; import speiger.src.coreengine.rendering.tesselation.IVertexBuilder;
import speiger.src.coreengine.rendering.tesselation.Tesselator; import speiger.src.coreengine.rendering.tesselation.Tesselator;
import speiger.src.coreengine.rendering.tesselation.VertexType; import speiger.src.coreengine.rendering.tesselation.VertexType;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.utils.helpers.TextUtil; import speiger.src.coreengine.utils.helpers.TextUtil;
public class FontRenderer implements IFontRenderer public class FontRenderer implements IFontRenderer
@ -36,45 +36,51 @@ public class FontRenderer implements IFontRenderer
public static final char LINE_SEPERATOR = '\n'; public static final char LINE_SEPERATOR = '\n';
Tesselator bufferBuilder = new Tesselator(655340); Tesselator bufferBuilder = new Tesselator(655340);
IFontProvider provider;
final TextLexer lexer = new TextLexer(this); final TextLexer lexer = new TextLexer(this);
final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer(); final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer();
final Char2ObjectMap<CharInstance>[] chars;
final ITexture texture;
final float height;
final float baseLine;
final float space;
public FontRenderer(Char2ObjectMap<CharInstance>[] chars, ITexture texture, float height, float baseLine) public void setProvider(IFontProvider provider)
{ {
this.chars = chars; this.provider = provider;
this.texture = texture;
this.height = height;
this.baseLine = baseLine;
space = chars[0].get(' ').getXAdvance();
} }
@Override @Override
public CharInstance getInstance(char letter, boolean isBold) public CharInstance getInstance(char letter, boolean isBold)
{ {
return chars[isBold ? 1 : 0].get(letter); return provider.getCharacter(letter, isBold);
} }
@Override @Override
public float getFontHeight() public float getFontHeight()
{ {
return height; return provider.getFontHeight();
} }
@Override @Override
public float getBaseLine() public float getBaseLine()
{ {
return baseLine; return provider.getBaseLine();
} }
@Override @Override
public ITexture getTexture() public ITexture getTexture()
{ {
return texture; return provider.getTexture();
}
public IFontProvider getProvider()
{
return provider;
}
public void destory()
{
if(provider != null)
{
provider.destroy();
provider = null;
}
} }
public List<DrawCall> renderText(String text, float x, float y, float z) public List<DrawCall> renderText(String text, float x, float y, float z)
@ -96,12 +102,12 @@ public class FontRenderer implements IFontRenderer
{ {
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true); xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
} }
yOffset += height * context.getScale(); yOffset += getFontHeight() * context.getScale();
} }
bufferBuilder.finishData(); bufferBuilder.finishData();
if(bufferBuilder.getVertexCount() > 0) if(bufferBuilder.getVertexCount() > 0)
{ {
drawCalls.add(bufferBuilder.getDrawCall(texture.getTextureID())); drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureID()));
} }
bufferBuilder.setOffset(0F, 0F, 0F); bufferBuilder.setOffset(0F, 0F, 0F);
return drawCalls; return drawCalls;
@ -125,8 +131,8 @@ public class FontRenderer implements IFontRenderer
return; return;
} }
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.UI); bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.UI);
int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (height * context.getScale())), lines.size()) : lines.size(); int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (getFontHeight() * context.getScale())), lines.size()) : lines.size();
float maxHeight = maxLanes * height * context.getScale(); float maxHeight = maxLanes * getFontHeight() * context.getScale();
float maxWidth = 0F; float maxWidth = 0F;
float yOffset = component.getVertical().align(boxHeight, maxHeight); float yOffset = component.getVertical().align(boxHeight, maxHeight);
float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth()); float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth());
@ -182,11 +188,11 @@ public class FontRenderer implements IFontRenderer
{ {
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false); addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
} }
yOffset += height * context.getScale(); yOffset += getFontHeight() * context.getScale();
component.getMetadata().addLine(lines.get(i)); component.getMetadata().addLine(lines.get(i));
} }
maxWidth /= 2; maxWidth /= 2;
buffer.finishShape(texture.getTextureID(), bufferBuilder); buffer.finishShape(getTexture().getTextureID(), bufferBuilder);
if(lineBuffer.hasData()) if(lineBuffer.hasData())
{ {
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F); Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F);
@ -201,9 +207,9 @@ public class FontRenderer implements IFontRenderer
switch(instance.getCharacter()) switch(instance.getCharacter())
{ {
case TAB: case TAB:
return space * 4 * scale; return provider.getTabWidth() * scale;
case SPACE: case SPACE:
return space * scale; return provider.getSpaceWidth() * scale;
} }
if(instance.getXAdvance() <= 0F) if(instance.getXAdvance() <= 0F)
{ {
@ -231,7 +237,7 @@ public class FontRenderer implements IFontRenderer
{ {
float lineWidth = lines.get(i).getWidth(); float lineWidth = lines.get(i).getWidth();
float xOffset = align.align(width, lineWidth); float xOffset = align.align(width, lineWidth);
float maxY = flipPos ? yPos - height : yPos + height; float maxY = flipPos ? yPos - getFontHeight() : yPos + getFontHeight();
tes.pos(xOffset, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex(); tes.pos(xOffset, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex(); tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex(); tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
@ -244,12 +250,12 @@ public class FontRenderer implements IFontRenderer
protected void addUnderline(float xStart, float width, float yStart, ColorObject color, IVertexBuilder buffer, boolean flipPos) protected void addUnderline(float xStart, float width, float yStart, ColorObject color, IVertexBuilder buffer, boolean flipPos)
{ {
float minY = yStart + baseLine + 0.5F; float minY = yStart + getBaseLine() + 0.5F;
float maxY = yStart + baseLine + 1.5F; float maxY = yStart + getBaseLine() + 1.5F;
if(flipPos) if(flipPos)
{ {
minY = yStart - baseLine - 0.5F; minY = yStart - getBaseLine() - 0.5F;
maxY = yStart - baseLine - 1.5F; maxY = yStart - getBaseLine() - 1.5F;
} }
buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex(); buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex(); buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
@ -261,8 +267,8 @@ public class FontRenderer implements IFontRenderer
protected void addStrikeThrough(float xStart, float width, float yStart, ColorObject color, IVertexBuilder buffer) protected void addStrikeThrough(float xStart, float width, float yStart, ColorObject color, IVertexBuilder buffer)
{ {
float minY = yStart + height / 2.0F; float minY = yStart + getFontHeight() / 2.0F;
float maxY = yStart + height / 2.0F + 1.4F; float maxY = yStart + getFontHeight() / 2.0F + 1.4F;
buffer.pos(xStart, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex(); buffer.pos(xStart, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex(); buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex(); buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
@ -301,9 +307,9 @@ public class FontRenderer implements IFontRenderer
switch(letter) switch(letter)
{ {
case SPACE: case SPACE:
return space; return provider.getSpaceWidth();
case TAB: case TAB:
return space * 4; return provider.getTabWidth();
default: default:
CharInstance instance = getInstance(letter, bold); CharInstance instance = getInstance(letter, bold);
return instance == null ? 0F : instance.getXAdvance(); return instance == null ? 0F : instance.getXAdvance();
@ -321,7 +327,7 @@ public class FontRenderer implements IFontRenderer
char character = text.charAt(i); char character = text.charAt(i);
if(LINE_SEPERATOR == character) if(LINE_SEPERATOR == character)
{ {
result = Math.max(result, current += space); result = Math.max(result, current += provider.getSpaceWidth());
current = 0.0F; current = 0.0F;
continue; continue;
} }
@ -391,13 +397,13 @@ public class FontRenderer implements IFontRenderer
@Override @Override
public float getTextHeight(String text, int flags) public float getTextHeight(String text, int flags)
{ {
return getTextLengths(text, flags).length - 1 * height; return getTextLengths(text, flags).length - 1 * getFontHeight();
} }
@Override @Override
public boolean isCharValid(char letter) public boolean isCharValid(char letter)
{ {
return chars[0].containsKey(letter); return provider.isCharacterValid(letter);
} }
@Override @Override

View File

@ -1,7 +1,7 @@
package speiger.src.coreengine.rendering.gui.renderer; package speiger.src.coreengine.rendering.gui.renderer;
import speiger.src.coreengine.rendering.gui.components.TextComponent; import speiger.src.coreengine.rendering.gui.components.TextComponent;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
public interface IFontRenderer public interface IFontRenderer
{ {
@ -62,6 +62,12 @@ public interface IFontRenderer
float xAdvance; float xAdvance;
boolean bold; boolean bold;
public CharInstance(char character, boolean bold)
{
this.character = character;
this.bold = bold;
}
public CharInstance(char character, int width, int height, float minU, float minV, float maxU, float maxV, int xAdvance, boolean bold) public CharInstance(char character, int width, int height, float minU, float minV, float maxU, float maxV, int xAdvance, boolean bold)
{ {
this.character = character; this.character = character;

View File

@ -28,8 +28,8 @@ import speiger.src.coreengine.rendering.shader.uniforms.UniformVec2f;
import speiger.src.coreengine.rendering.tesselation.GLCall; import speiger.src.coreengine.rendering.tesselation.GLCall;
import speiger.src.coreengine.rendering.tesselation.Tesselator; import speiger.src.coreengine.rendering.tesselation.Tesselator;
import speiger.src.coreengine.rendering.tesselation.VertexType; import speiger.src.coreengine.rendering.tesselation.VertexType;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.rendering.textures.TextureManager; import speiger.src.coreengine.rendering.textures.base.TextureManager;
import speiger.src.coreengine.rendering.utils.GLUtils; import speiger.src.coreengine.rendering.utils.GLUtils;
import speiger.src.coreengine.utils.collections.pools.SimplePool; import speiger.src.coreengine.utils.collections.pools.SimplePool;

View File

@ -0,0 +1,141 @@
package speiger.src.coreengine.rendering.gui.renderer.provider;
import java.awt.image.BufferedImage;
import java.util.List;
import com.google.gson.JsonObject;
import speiger.src.collections.chars.maps.impl.hash.Char2ObjectOpenHashMap;
import speiger.src.collections.chars.maps.interfaces.Char2ObjectMap;
import speiger.src.collections.chars.utils.maps.Char2ObjectMaps;
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.gui.helper.FontBuilder;
import speiger.src.coreengine.rendering.gui.helper.FontBuilder.WrittenChar;
import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class BitmapFontProvider implements IFontProvider
{
FontInfo info;
ITexture texture;
Char2ObjectMap<CharInstance>[] instances;
float space;
public BitmapFontProvider(FontInfo info, ITexture texture, Char2ObjectMap<CharInstance>[] instances)
{
this.info = info;
this.texture = texture;
this.instances = instances;
if(instances[0].containsKey(' ')) space = instances[0].get(' ').getXAdvance();
else if(instances[1].containsKey(' ')) space = instances[1].get(' ').getXAdvance();
}
@Override
public void destroy()
{
if(texture != null)
{
texture.destroy();
texture = null;
}
}
@Override
public ITexture getTexture()
{
return texture;
}
@Override
public boolean isCharacterValid(char value)
{
return instances[0].containsKey(value) || instances[1].containsKey(value);
}
@Override
public CharInstance getCharacter(char value, boolean bold)
{
Char2ObjectMap<CharInstance> map = instances[bold ? 1 : 0];
return (map.isEmpty() ? instances[bold ? 0 : 1] : map).get(value);
}
@Override
public float getFontHeight()
{
return info.fontHeight;
}
@Override
public float getBaseLine()
{
return info.fontBase;
}
@Override
public float getSpaceWidth()
{
return space;
}
@Override
public float getTabWidth()
{
return space * info.tabs;
}
public static IFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
{
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
float multiplier = info.setDesiredHeight(desiredSize);
Char2ObjectMap<CharInstance>[] maps = new Char2ObjectMap[]{new Char2ObjectOpenHashMap<CharInstance>(), new Char2ObjectOpenHashMap<CharInstance>()};
JsonUtil.iterate(object.get("chars"), T -> {
CharInstance instance = info.create(T);
instance.scale(multiplier);
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
});
if(maps[0].isEmpty()) maps[0] = Char2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Char2ObjectMaps.empty();
return new BitmapFontProvider(info, ITexture.simple(AssetLocation.of(object.get("file").getAsString())), maps);
}
public static IFontProvider create(JsonObject object, float desiredSize, AssetManager manager)
{
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(AssetLocation.of(object.get("file").getAsString())))
{
JsonObject info = object.getAsJsonObject("info");
int tabs = JsonUtil.getOrDefault(info, "tabs", 4);
boolean literal = JsonUtil.getOrDefault(info, "literal", false);
boolean plain = JsonUtil.getOrDefault(info, "plain", true);
boolean bold = JsonUtil.getOrDefault(info, "bold", true);
if(!plain && !bold) throw new IllegalStateException("You need a plain or bold font at the very least");
int flags = (literal ? FontBuilder.LITERAL : 0) | (plain ? FontBuilder.PLAIN : 0) | (bold ? FontBuilder.BOLD : 0);
ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> written = FontBuilder.createBitmapFont(asset.getStream(), info.get("charset").getAsString(), flags, info.get("size").getAsFloat());
BufferedImage image = written.getKey().getValue();
Vec2i size = written.getKey().getKey();
FontInfo fontInfo = new FontInfo(image.getWidth(), image.getHeight(), size.getY(), size.getX(), tabs);
float mulitplier = fontInfo.setDesiredHeight(desiredSize);
Char2ObjectMap<CharInstance>[] maps = new Char2ObjectMap[]{new Char2ObjectOpenHashMap<CharInstance>(), new Char2ObjectOpenHashMap<CharInstance>()};
for(WrittenChar entry : written.getValue())
{
CharInstance instance = entry.create(fontInfo.textureWidth, fontInfo.textureHeight);
instance.scale(mulitplier);
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
}
if(maps[0].isEmpty()) maps[0] = Char2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Char2ObjectMaps.empty();
return new BitmapFontProvider(fontInfo, ITexture.direct(image), maps);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,100 @@
package speiger.src.coreengine.rendering.gui.renderer.provider;
import java.util.List;
import java.util.Map;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2FloatLinkedOpenHashMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap;
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap.Entry;
import speiger.src.collections.objects.utils.maps.Object2FloatMaps;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.rendering.gui.renderer.FontRenderer;
public class FontManager implements IReloadableResource
{
Map<AssetLocation, FontRenderer> fontRenders = new Object2ObjectLinkedOpenHashMap<>();
Object2FloatMap<AssetLocation> fontSizes = new Object2FloatLinkedOpenHashMap<>();
Map<String, IFontLoader> loaders = new Object2ObjectOpenHashMap<>();
AssetManager manager;
public FontManager()
{
registerFontLoader("bitmap", BitmapFontProvider::load);
registerFontLoader("java-ttf", BitmapFontProvider::create);
}
public void setAssetManager(AssetManager manager)
{
this.manager = manager;
}
public void registerFontLoader(String id, IFontLoader provider)
{
loaders.put(id, provider);
}
public FontRenderer loadFont(AssetLocation location, float desiredSize)
{
FontRenderer render = fontRenders.get(location);
if(render == null)
{
IFontProvider provider = loadProvider(location, desiredSize);
if(provider != null)
{
render = new FontRenderer();
render.setProvider(provider);
fontRenders.put(location, render);
fontSizes.putIfAbsent(location, desiredSize);
}
}
return render;
}
private IFontProvider loadProvider(AssetLocation location, float desiredSize)
{
try(IAsset asset = manager.getAsset(location))
{
JsonObject obj = asset.getJsonObject();
IFontLoader loader = loaders.get(obj.get("type").getAsString());
if(loader == null) return null;
return loader.create(obj, desiredSize, manager);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static interface IFontLoader
{
public IFontProvider create(JsonObject obj, float desiredSize, AssetManager loader);
}
@Override
public void reload()
{
List<IFontProvider> providers = new ObjectArrayList<>();
for(Entry<AssetLocation> entry : Object2FloatMaps.fastIterable(fontSizes))
{
AssetLocation location = entry.getKey();
FontRenderer font = fontRenders.get(location);
providers.add(font.getProvider());
font.setProvider(loadProvider(location, entry.getFloatValue()));
}
for(int i = 0,m=providers.size();i<m;providers.get(i++).destroy());
}
@Override
public void destroy()
{
fontRenders.values().forEach(FontRenderer::destory);
fontRenders.clear();
}
}

View File

@ -0,0 +1,72 @@
package speiger.src.coreengine.rendering.gui.renderer.provider;
import com.google.gson.JsonObject;
import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public interface IFontProvider
{
public ITexture getTexture();
public boolean isCharacterValid(char value);
public CharInstance getCharacter(char value, boolean bold);
public float getFontHeight();
public float getBaseLine();
public float getSpaceWidth();
public float getTabWidth();
public void destroy();
public static class FontInfo
{
public int textureWidth;
public int textureHeight;
public float fontHeight;
public float fontBase;
public int tabs;
public FontInfo(JsonObject obj)
{
this(obj.get("width").getAsInt(), obj.get("height").getAsInt(), obj.get("charHeight").getAsInt(), obj.get("base").getAsInt(), JsonUtil.getOrDefault(obj, "tabs", 4));
}
public FontInfo(int textureWidth, int textureHeight, float fontHeight, float fontBase, int tabs)
{
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
this.fontHeight = fontHeight;
this.fontBase = fontBase;
this.tabs = tabs;
}
public float setDesiredHeight(float desired)
{
float multiplier = desired / fontHeight;
fontHeight *= multiplier;
fontBase *= multiplier;
return multiplier;
}
public CharInstance create(JsonObject obj)
{
return create((char)obj.get("char").getAsInt(), obj.get("minX").getAsInt(), obj.get("minY").getAsInt(), obj.get("maxX").getAsInt(), obj.get("maxY").getAsInt(), JsonUtil.getOrDefault(obj, "bold", false));
}
public CharInstance create(char character, int minX, int minY, int maxX, int maxY, boolean bold)
{
return new CharInstance(character, maxX - minX, maxY - minY, getTextureU(minX), getTextureV(minY), getTextureU(maxX), getTextureV(maxY), maxX - minX, bold);
}
public float getTextureU(float value)
{
return value / textureWidth;
}
public float getTextureV(float value)
{
return value / textureHeight;
}
}
}

View File

@ -0,0 +1,53 @@
package speiger.src.coreengine.rendering.models;
import java.util.Map;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
public enum DataType
{
BYTE("byte", 1),
SHORT("short", 2),
INT("int", 4),
LONG("long", 8),
FLOAT("float", 4),
DOUBLE("double", 8);
static final Map<String, DataType> BY_ID = new Object2ObjectOpenHashMap<>();
final String type;
final int byteSize;
private DataType(String type, int byteSize)
{
this.type = type;
this.byteSize = byteSize;
}
public String getType()
{
return type;
}
public int getByteSize()
{
return byteSize;
}
public boolean isFloatingPoint()
{
return this == FLOAT || this == DOUBLE;
}
public static DataType byID(String id)
{
return BY_ID.get(id);
}
static
{
for(DataType type : values())
{
BY_ID.put(type.getType(), type);
}
}
}

View File

@ -1,42 +1,56 @@
package speiger.src.coreengine.rendering.models; package speiger.src.coreengine.rendering.models;
import java.util.Map;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL30;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
public class GLDataType public class GLDataType
{ {
static final Int2ObjectMap<GLDataType> ID_TO_TYPE = new Int2ObjectOpenHashMap<>();
static final Map<String, GLDataType> NAME_TO_TYPE = new Object2ObjectOpenHashMap<>();
//Normal Types //Normal Types
public static final GLDataType BYTE = new GLDataType(GL11.GL_BYTE, 1); public static final GLDataType BYTE = new GLDataType(GL11.GL_BYTE, DataType.BYTE, "byte");
public static final GLDataType UNSIGNED_BYTE = new GLDataType(GL11.GL_UNSIGNED_BYTE, 1); public static final GLDataType UNSIGNED_BYTE = new GLDataType(GL11.GL_UNSIGNED_BYTE, DataType.BYTE, "u_byte");
public static final GLDataType SHORT = new GLDataType(GL11.GL_SHORT, 2); public static final GLDataType SHORT = new GLDataType(GL11.GL_SHORT, DataType.SHORT, "short");
public static final GLDataType UNSIGNED_SHORT = new GLDataType(GL11.GL_UNSIGNED_SHORT, 2); public static final GLDataType UNSIGNED_SHORT = new GLDataType(GL11.GL_UNSIGNED_SHORT, DataType.SHORT, "u_short");
public static final GLDataType INT = new GLDataType(GL11.GL_INT, 4); public static final GLDataType INT = new GLDataType(GL11.GL_INT, DataType.INT, "int");
public static final GLDataType UNSIGNED_INT = new GLDataType(GL11.GL_UNSIGNED_INT, 4); public static final GLDataType UNSIGNED_INT = new GLDataType(GL11.GL_UNSIGNED_INT, DataType.INT, "u_int");
public static final GLDataType FLOAT = new GLDataType(GL11.GL_FLOAT, 4); public static final GLDataType FLOAT = new GLDataType(GL11.GL_FLOAT, DataType.FLOAT, "float");
public static final GLDataType DOUBLE = new GLDataType(GL11.GL_DOUBLE, DataType.DOUBLE, "double");
//Compression Types //Compression Types
public static final GLDataType UNSIGNED_INT_10_10_10_2 = new GLDataType(GL12.GL_UNSIGNED_INT_10_10_10_2, 4, true); public static final GLDataType UNSIGNED_INT_10_10_10_2 = new GLDataType(GL12.GL_UNSIGNED_INT_10_10_10_2, DataType.INT, true, "u_int_10_10_10_2");
public static final GLDataType UNSIGNED_INT_2_10_10_10_REV = new GLDataType(GL12.GL_UNSIGNED_INT_2_10_10_10_REV, 4, true); public static final GLDataType UNSIGNED_INT_2_10_10_10_REV = new GLDataType(GL12.GL_UNSIGNED_INT_2_10_10_10_REV, DataType.INT, true, "u_int_2_10_10_10_rev");
//Special Types //Special Types
public static final GLDataType UNSIGNED_INT_10F_11F_11F_REV = new GLDataType(GL30.GL_UNSIGNED_INT_10F_11F_11F_REV, 4, true); public static final GLDataType UNSIGNED_INT_10F_11F_11F_REV = new GLDataType(GL30.GL_UNSIGNED_INT_10F_11F_11F_REV, DataType.INT, true, "u_int_10_11_11_rev");
public static final GLDataType UNSIGNED_INT_5_9_9_9_REV = new GLDataType(GL30.GL_UNSIGNED_INT_5_9_9_9_REV, 4, true); public static final GLDataType UNSIGNED_INT_5_9_9_9_REV = new GLDataType(GL30.GL_UNSIGNED_INT_5_9_9_9_REV, DataType.INT, true, "u_int_5_9_9_9_rev");
final int glType; final int glType;
final int byteSize; final DataType dataType;
final boolean ignoreAttributeSize; final boolean ignoreAttributeSize;
final String name;
public GLDataType(int glType, int byteSize) public GLDataType(int glType, DataType dataType, String name)
{ {
this(glType, byteSize, false); this(glType, dataType, false, name);
} }
public GLDataType(int glType, int byteSize, boolean ignoreAttributeSize) public GLDataType(int glType, DataType dataType, boolean ignoreAttributeSize, String name)
{ {
this.glType = glType; this.glType = glType;
this.byteSize = byteSize; this.dataType = dataType;
this.ignoreAttributeSize = ignoreAttributeSize; this.ignoreAttributeSize = ignoreAttributeSize;
this.name = name;
ID_TO_TYPE.put(glType, this);
NAME_TO_TYPE.put(name, this);
} }
public int getGLType() public int getGLType()
@ -44,13 +58,28 @@ public class GLDataType
return glType; return glType;
} }
public String getName()
{
return name;
}
public int getByteSize() public int getByteSize()
{ {
return byteSize; return dataType.getByteSize();
}
public boolean isSpecialType()
{
return ignoreAttributeSize;
}
public DataType getDataType()
{
return dataType;
} }
public int calulateSize(int attributeSize) public int calulateSize(int attributeSize)
{ {
return ignoreAttributeSize ? byteSize : attributeSize * byteSize; return ignoreAttributeSize ? dataType.getByteSize() : attributeSize * dataType.getByteSize();
} }
} }

View File

@ -9,7 +9,7 @@ import java.util.function.Consumer;
import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL15;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry; import speiger.src.collections.ints.misc.pairs.IntObjectPair;
import speiger.src.coreengine.rendering.utils.AllocationTracker; import speiger.src.coreengine.rendering.utils.AllocationTracker;
import speiger.src.coreengine.utils.io.GameLog; import speiger.src.coreengine.utils.io.GameLog;
@ -213,12 +213,12 @@ public class VertexBuffer
return this; return this;
} }
public VertexBuffer fillBuffer(List<Entry<byte[]>> data) public VertexBuffer fillBuffer(List<IntObjectPair<byte[]>> data)
{ {
return fillBuffer(0, data); return fillBuffer(0, data);
} }
public VertexBuffer fillBuffer(int byteOffset, List<Entry<byte[]>> data) public VertexBuffer fillBuffer(int byteOffset, List<IntObjectPair<byte[]>> data)
{ {
if(data.isEmpty()) if(data.isEmpty())
{ {
@ -228,7 +228,7 @@ public class VertexBuffer
ByteBuffer buffer = GL15.glMapBuffer(bufferType, GL15.GL_WRITE_ONLY); ByteBuffer buffer = GL15.glMapBuffer(bufferType, GL15.GL_WRITE_ONLY);
for(int i = 0,m=data.size();i<m;i++) for(int i = 0,m=data.size();i<m;i++)
{ {
Entry<byte[]> entry = data.get(i); IntObjectPair<byte[]> entry = data.get(i);
buffer.position(entry.getIntKey()+byteOffset); buffer.position(entry.getIntKey()+byteOffset);
buffer.put(entry.getValue()); buffer.put(entry.getValue());
totalData += entry.getValue().length; totalData += entry.getValue().length;

View File

@ -7,7 +7,7 @@ import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import speiger.src.coreengine.rendering.textures.TextureManager; import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class TextureAttachment implements IFrameAttachment public class TextureAttachment implements IFrameAttachment
{ {

View File

@ -1,7 +1,7 @@
package speiger.src.coreengine.rendering.shader.uniforms; package speiger.src.coreengine.rendering.shader.uniforms;
import speiger.src.coreengine.rendering.textures.ITexture; import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.rendering.textures.TextureManager; import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class UniformTexture extends UniformInt public class UniformTexture extends UniformInt
{ {

View File

@ -1,22 +0,0 @@
package speiger.src.coreengine.rendering.textures;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
public interface ITexture extends IReloadableResource
{
public int getTextureID();
public void bindTexture();
public void deleteTexture();
public int getWidth();
public int getHeight();
public float getUMin();
public float getVMin();
public float getUMax();
public float getVMax();
public default float getInterpolatedU(float u){return getUMin() + ((getUMax() - getUMin()) * u);}
public default float getINterpolatedV(float v){return getUMin() + ((getUMax() - getUMin()) * v);}
}

View File

@ -1,12 +1,14 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.base;
public abstract class AbstractTexture implements ITexture public abstract class AbstractTexture implements ITexture
{ {
int textureID; protected int textureID;
public AbstractTexture() @Override
public ITexture makeReloadable()
{ {
TextureManager.INSTANCE.addTexture(this); TextureManager.INSTANCE.addTexture(this);
return this;
} }
public void setTextureID(int textureID) public void setTextureID(int textureID)

View File

@ -0,0 +1,56 @@
package speiger.src.coreengine.rendering.textures.base;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.rendering.textures.normal.DirectTexture;
import speiger.src.coreengine.rendering.textures.normal.SimpleTexture;
import speiger.src.coreengine.rendering.textures.stb.STBDirectTexture;
import speiger.src.coreengine.rendering.textures.stb.STBTexture;
public interface ITexture extends IReloadableResource
{
public int getTextureID();
public void bindTexture();
public void deleteTexture();
public int getWidth();
public int getHeight();
public float getUMin();
public float getVMin();
public float getUMax();
public float getVMax();
public ITexture makeReloadable();
public default float getInterpolatedU(float u){return getUMin() + ((getUMax() - getUMin()) * u);}
public default float getInterpolatedV(float v){return getUMin() + ((getUMax() - getUMin()) * v);}
public static ITexture simple(AssetLocation location) {
return new STBTexture(location);
}
public static ITexture direct(ByteBuffer stbImageData, int width, int height) {
return new STBDirectTexture(stbImageData, width, height);
}
public static ITexture direct(long stbImageData, int width, int height) {
return new STBDirectTexture(stbImageData, width, height);
}
public static ITexture direct(BufferedImage imageData) {
return new STBDirectTexture(imageData);
}
public static ITexture awtSimple(AssetLocation location) {
return new SimpleTexture(location);
}
public static ITexture awtDirect(BufferedImage imageData) {
return new DirectTexture(imageData);
}
}

View File

@ -0,0 +1,27 @@
package speiger.src.coreengine.rendering.textures.base;
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Consumer;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.IAssetParser;
public class NativeMemoryParser implements IAssetParser<ByteBuffer>
{
@Override
public ByteBuffer parseAsset(Path path, Consumer<Closeable> autoCloser) throws IOException
{
byte[] data = Files.readAllBytes(path);
ByteBuffer buffer = MemoryUtil.memAlloc(data.length);
buffer.put(data);
buffer.flip();
return buffer;
}
}

View File

@ -1,4 +1,4 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.base;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -13,6 +13,8 @@ import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.IAsset; import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource; import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.assets.reloader.ResourceReloader; import speiger.src.coreengine.assets.reloader.ResourceReloader;
import speiger.src.coreengine.rendering.textures.base.ITexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
import speiger.src.coreengine.rendering.utils.GLUtils; import speiger.src.coreengine.rendering.utils.GLUtils;
import speiger.src.coreengine.rendering.utils.states.GLState; import speiger.src.coreengine.rendering.utils.states.GLState;
import speiger.src.coreengine.utils.io.GameLog; import speiger.src.coreengine.utils.io.GameLog;

View File

@ -1,4 +1,4 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.base;
public class WrappedTexture implements ITexture public class WrappedTexture implements ITexture
{ {
@ -8,7 +8,13 @@ public class WrappedTexture implements ITexture
{ {
this.textureId = textureId; this.textureId = textureId;
} }
@Override
public ITexture makeReloadable()
{
return this;
}
@Override @Override
public void reload() public void reload()
{ {

View File

@ -1,4 +1,4 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.custom;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
@ -16,6 +16,8 @@ import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps; import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
import speiger.src.collections.utils.ITrimmable; import speiger.src.collections.utils.ITrimmable;
import speiger.src.coreengine.math.BitUtil; import speiger.src.coreengine.math.BitUtil;
import speiger.src.coreengine.rendering.textures.base.AbstractTexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
import speiger.src.coreengine.rendering.utils.AllocationTracker; import speiger.src.coreengine.rendering.utils.AllocationTracker;
public class DynamicTexture extends AbstractTexture public class DynamicTexture extends AbstractTexture
@ -132,8 +134,9 @@ public class DynamicTexture extends AbstractTexture
@Override @Override
public void reload() public void reload()
{ {
TextureManager.INSTANCE.removeTexture(getTextureID()); int old = getTextureID();
setTextureID(GL11.glGenTextures()); setTextureID(GL11.glGenTextures());
TextureManager.INSTANCE.removeTexture(old);
dirtyChunks.clear(); dirtyChunks.clear();
first = true; first = true;
updateData(); updateData();

View File

@ -0,0 +1,304 @@
package speiger.src.coreengine.rendering.textures.custom;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
import speiger.src.collections.objects.sets.ObjectOpenHashSet;
import speiger.src.collections.objects.utils.ObjectIterators;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.textures.custom.TextureAtlas;
/**
* Inspired by: <a href=https://github.com/lukaszdk/texture-atlas-generator/blob/master/AtlasGenerator.java>AtlasGenerator</a>
*/
public class TextureAtlas
{
int width;
int height;
Object2ObjectMap<AssetLocation, AtlasEntry> textures;
protected TextureAtlas(Vec2i bounds, Object2ObjectMap<AssetLocation, AtlasEntry> textures)
{
width = bounds.getX();
height = bounds.getY();
this.textures = textures;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public AtlasEntry getTexture(AssetLocation texture)
{
return textures.getObject(texture);
}
public Iterator<AtlasEntry> getContents()
{
return ObjectIterators.unmodifiable(textures.values().iterator());
}
public static Builder create()
{
return new Builder();
}
public static class Builder
{
Set<AssetLocation> names = new ObjectOpenHashSet<>();
List<Record> records = new ObjectArrayList<>();
int pixelsUsed = 0;
public boolean add(AssetLocation location, int width, int height)
{
return add(location, width, height, 0);
}
public boolean add(AssetLocation location, int width, int height, int padding)
{
if(location == null || width <= 0 || height <= 0 || padding < 0 || !names.add(location)) return false;
records.add(new Record(location, width, height, padding));
pixelsUsed += (width + padding) * (height + padding);
return true;
}
private ObjectObjectPair<Vec2i, Object2ObjectMap<AssetLocation, AtlasEntry>> stitch()
{
int textureWidth = 2;
int textureHeight = 2;
boolean height = false;
for(;textureHeight * textureWidth <= pixelsUsed;height = !height)
{
if(height) textureHeight *= 2;
else textureWidth *= 2;
}
records.sort(null);
int attempts = 0;
while(attempts < 50)
{
Slot slot = new Slot(0, 0, textureWidth, textureHeight);
boolean failed = false;
for(int i = 0,m=records.size();i<m;i++)
{
if(slot.addRecord(records.get(i))) continue;
failed = true;
break;
}
if(failed)
{
if(height) textureHeight *= 2;
else textureWidth *= 2;
attempts++;
height = !height;
continue;
}
Object2ObjectMap<AssetLocation, AtlasEntry> entries = new Object2ObjectLinkedOpenHashMap<>();
slot.build(entries::put);
return ObjectObjectPair.of(Vec2i.newVec(textureWidth, textureHeight), entries);
}
throw new IllegalStateException("Couldn't fit Texture Atlas after growing it 5 Times");
}
public void buildHollow(BiConsumer<Vec2i, Iterable<AtlasEntry>> builder)
{
ObjectObjectPair<Vec2i, Object2ObjectMap<AssetLocation, AtlasEntry>> pairs = stitch();
builder.accept(pairs.getKey(), pairs.getValue().values());
}
public TextureAtlas build(BiConsumer<Vec2i, Iterable<AtlasEntry>> builder)
{
ObjectObjectPair<Vec2i, Object2ObjectMap<AssetLocation, AtlasEntry>> pairs = stitch();
builder.accept(pairs.getKey(), pairs.getValue().values());
return new TextureAtlas(pairs.getKey(), pairs.getValue());
}
public TextureAtlas build()
{
ObjectObjectPair<Vec2i, Object2ObjectMap<AssetLocation, AtlasEntry>> pairs = stitch();
return new TextureAtlas(pairs.getKey(), pairs.getValue());
}
}
public static class AtlasEntry
{
AssetLocation location;
int x;
int y;
int width;
int height;
private AtlasEntry(Slot slot)
{
Record record = slot.record;
location = record == null ? null : record.getLocation();
x = slot.x;
y = slot.y;
width = record == null ? slot.width : record.width;
height = record == null ? slot.height : record.height;
}
public AssetLocation getLocation()
{
return location;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
}
private static class Slot
{
int x;
int y;
int width;
int height;
Record record;
Slot[] children = null;
public Slot(int x, int y, int width, int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public boolean isLeaf()
{
return children == null;
}
public void build(BiConsumer<AssetLocation, AtlasEntry> builder)
{
if(!isLeaf())
{
for(int i = 0,m=children.length;i<m;i++)
{
children[i].build(builder);
}
return;
}
if(record == null) return;
builder.accept(record.getLocation(), new AtlasEntry(this));
}
public boolean addRecord(Record record)
{
if(isLeaf())
{
int rw = record.getWidth();
int rh = record.getHeight();
if(this.record != null || rw > width || rh > height) return false;
if(rw == width && rh == height)
{
this.record = record;
return true;
}
int p = record.getPadding();
int dw = width - rw;
int dh = height - rh;
children = new Slot[dw > 0 && dh > 0 ? 3 : 2];
children[0] = new Slot(x, y, rw, rh);
if(dw > 0 && dh > 0)
{
if(dw > dh)
{
children[1] = new Slot(x + rw + p, y, dw - p, rh);
children[2] = new Slot(x, y + rh + p, width, dh - p);
}
else
{
children[1] = new Slot(x, y + rh + p, rw, dh - p);
children[2] = new Slot(x + rw + p, y, dw - p, height);
}
}
else if(dw == 0) children[1] = new Slot(x, y + rh + p, rw, dh - p);
else if(dh == 0) children[1] = new Slot(x + rw + p, y, dw - p, rh);
return children[0].addRecord(record);
}
for(int i = 0,m=children.length;i<m;i++)
{
if(children[i].addRecord(record)) return true;
}
return false;
}
}
private static class Record implements Comparable<Record>
{
AssetLocation location;
int width;
int height;
int padding;
public Record(AssetLocation location, int width, int height, int padding)
{
this.location = location;
this.width = width;
this.height = height;
this.padding = padding;
}
public int getHeight()
{
return height;
}
public int getWidth()
{
return width;
}
public int getPadding()
{
return padding;
}
public AssetLocation getLocation()
{
return location;
}
private int getPixelCount()
{
return (width + padding) * (height + padding);
}
@Override
public int compareTo(Record o)
{
int result = Integer.compare(o.getPixelCount(), getPixelCount());
return result == 0 ? getLocation().compareTo(o.getLocation()) : result;
}
}
}

View File

@ -1,4 +1,4 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.normal;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -8,6 +8,9 @@ import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.rendering.textures.base.AbstractTexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class DirectTexture extends AbstractTexture public class DirectTexture extends AbstractTexture
{ {
BufferedImage image; BufferedImage image;
@ -93,7 +96,8 @@ public class DirectTexture extends AbstractTexture
@Override @Override
public void reload() public void reload()
{ {
TextureManager.INSTANCE.removeTexture(textureID); int old = textureID;
loadTexture(); loadTexture();
TextureManager.INSTANCE.removeTexture(old);
} }
} }

View File

@ -1,4 +1,4 @@
package speiger.src.coreengine.rendering.textures; package speiger.src.coreengine.rendering.textures.normal;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -10,6 +10,8 @@ import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset; import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.rendering.textures.base.AbstractTexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class SimpleTexture extends AbstractTexture public class SimpleTexture extends AbstractTexture
{ {
@ -66,8 +68,9 @@ public class SimpleTexture extends AbstractTexture
@Override @Override
public void reload() public void reload()
{ {
TextureManager.INSTANCE.removeTexture(textureID); int old = textureID;
loadTexture(); loadTexture();
TextureManager.INSTANCE.removeTexture(old);
} }
@Override @Override

View File

@ -0,0 +1,109 @@
package speiger.src.coreengine.rendering.textures.stb;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.rendering.textures.base.AbstractTexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class STBDirectTexture extends AbstractTexture
{
long imageData;
int width;
int height;
public STBDirectTexture(BufferedImage imageData)
{
this(convert(imageData), imageData.getWidth(), imageData.getHeight());
}
public STBDirectTexture(ByteBuffer imageData, int width, int height)
{
this(MemoryUtil.memAddress(imageData), width, height);
}
public STBDirectTexture(long imageData, int width, int height)
{
this.imageData = imageData;
this.width = width;
this.height = height;
loadTexture();
}
protected void loadTexture()
{
setTextureID(GL11.glGenTextures());
bindTexture();
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageData);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
}
@Override
public int getWidth()
{
return width;
}
@Override
public int getHeight()
{
return height;
}
@Override
public void reload()
{
int old = textureID;
loadTexture();
TextureManager.INSTANCE.removeTexture(old);
}
@Override
public void deleteTexture()
{
if(imageData != 0)
{
STBImage.nstbi_image_free(imageData);
imageData = 0;
}
super.deleteTexture();
}
private static ByteBuffer convert(BufferedImage image)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try
{
ImageIO.write(image, "png", stream);
ByteBuffer buffer = MemoryUtil.memAlloc(stream.size());
buffer.put(stream.toByteArray());
buffer.flip();
ByteBuffer result = STBImage.stbi_load_from_memory(buffer, new int[1], new int[1], new int[1], 4);
if(result == null) {
MemoryUtil.memFree(buffer);
throw new IOException("Could not load image: " + STBImage.stbi_failure_reason());
}
MemoryUtil.memFree(buffer);
return result;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,98 @@
package speiger.src.coreengine.rendering.textures.stb;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.IAsset;
import speiger.src.coreengine.rendering.textures.base.AbstractTexture;
import speiger.src.coreengine.rendering.textures.base.TextureManager;
public class STBTexture extends AbstractTexture
{
AssetLocation location;
long imageData;
int width;
int height;
public STBTexture(AssetLocation location)
{
this.location = location;
loadTexture();
}
private void loadTexture()
{
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location))
{
ByteBuffer buffer = asset.getCustom(ByteBuffer.class);
int[] width = new int[1];
int[] height = new int[1];
int[] fileChannels = new int[1];
ByteBuffer image = STBImage.stbi_load_from_memory(buffer, width, height, fileChannels, 4);
if(image == null) {
MemoryUtil.memFree(buffer);
throw new IOException("Could not load image: " + STBImage.stbi_failure_reason());
}
imageData = MemoryUtil.memAddress(image);
this.width = width[0];
this.height = height[0];
MemoryUtil.memFree(buffer);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
setTextureID(GL11.glGenTextures());
bindTexture();
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageData);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
}
@Override
public int getWidth()
{
return width;
}
@Override
public int getHeight()
{
return height;
}
@Override
public void reload()
{
if(imageData != 0)
{
STBImage.nstbi_image_free(imageData);
imageData = 0;
}
int old = textureID;
loadTexture();
TextureManager.INSTANCE.removeTexture(old);
}
@Override
public void deleteTexture()
{
super.deleteTexture();
if(imageData != 0)
{
STBImage.nstbi_image_free(imageData);
imageData = 0;
}
}
}

View File

@ -12,7 +12,7 @@ import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.reloader.IReloadableResource; import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.rendering.input.window.Window; import speiger.src.coreengine.rendering.input.window.Window;
import speiger.src.coreengine.rendering.textures.TextureManager; import speiger.src.coreengine.rendering.textures.base.TextureManager;
public final class Cursor implements IReloadableResource public final class Cursor implements IReloadableResource
{ {

View File

@ -37,7 +37,7 @@ public class CollectionUtils
List<T>[] list = new List[size]; List<T>[] list = new List[size];
for(int i = 0;i<size;i++) for(int i = 0;i<size;i++)
{ {
list[i] = new ObjectArrayList<T>(); list[i] = new ObjectArrayList<>();
} }
return list; return list;
} }

View File

@ -6,10 +6,9 @@ import java.util.Set;
import speiger.src.collections.ints.collections.IntIterator; import speiger.src.collections.ints.collections.IntIterator;
import speiger.src.collections.ints.maps.abstracts.AbstractInt2IntMap.BasicEntry; import speiger.src.collections.ints.maps.abstracts.AbstractInt2IntMap.BasicEntry;
import speiger.src.collections.ints.maps.abstracts.AbstractInt2ObjectMap;
import speiger.src.collections.ints.maps.interfaces.Int2IntMap; import speiger.src.collections.ints.maps.interfaces.Int2IntMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap; import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry; import speiger.src.collections.ints.misc.pairs.IntObjectPair;
import speiger.src.collections.ints.sets.IntAVLTreeSet; import speiger.src.collections.ints.sets.IntAVLTreeSet;
import speiger.src.collections.ints.sets.IntSet; import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.lists.ObjectArrayList;
@ -166,7 +165,7 @@ public class DynamicDataManager<T>
} }
return; return;
} }
List<Entry<byte[]>> list = new ObjectArrayList<>(); List<IntObjectPair<byte[]>> list = new ObjectArrayList<>();
while(!changedSlots.isEmpty()) while(!changedSlots.isEmpty())
{ {
DataSlot start = null; DataSlot start = null;
@ -196,7 +195,7 @@ public class DynamicDataManager<T>
bytesAllocated += start.getUsedBytes(); bytesAllocated += start.getUsedBytes();
start = start.next; start = start.next;
} }
list.add(new AbstractInt2ObjectMap.BasicEntry<>(byteOffset, data)); list.add(IntObjectPair.of(byteOffset, data));
} }
if(!list.isEmpty()) if(!list.isEmpty())
{ {

View File

@ -2,10 +2,10 @@ package speiger.src.coreengine.utils.collections.managers.dynamic;
import java.util.List; import java.util.List;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry; import speiger.src.collections.ints.misc.pairs.IntObjectPair;
public interface IDynamicDataHandler<T> public interface IDynamicDataHandler<T>
{ {
public byte[] toBytes(T entry); public byte[] toBytes(T entry);
public void uploadBytes(List<Entry<byte[]>> list, int newArraySize); public void uploadBytes(List<IntObjectPair<byte[]>> list, int newArraySize);
} }

View File

@ -10,10 +10,9 @@ import speiger.src.collections.ints.collections.IntIterator;
import speiger.src.collections.ints.functions.IntComparator; import speiger.src.collections.ints.functions.IntComparator;
import speiger.src.collections.ints.lists.IntArrayList; import speiger.src.collections.ints.lists.IntArrayList;
import speiger.src.collections.ints.lists.IntList; import speiger.src.collections.ints.lists.IntList;
import speiger.src.collections.ints.maps.abstracts.AbstractInt2ObjectMap.BasicEntry;
import speiger.src.collections.ints.maps.impl.hash.Int2IntOpenHashMap; import speiger.src.collections.ints.maps.impl.hash.Int2IntOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2IntMap; import speiger.src.collections.ints.maps.interfaces.Int2IntMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry; import speiger.src.collections.ints.misc.pairs.IntObjectPair;
import speiger.src.collections.ints.sets.IntAVLTreeSet; import speiger.src.collections.ints.sets.IntAVLTreeSet;
import speiger.src.collections.ints.sets.IntLinkedOpenHashSet; import speiger.src.collections.ints.sets.IntLinkedOpenHashSet;
import speiger.src.collections.ints.sets.IntSet; import speiger.src.collections.ints.sets.IntSet;
@ -284,7 +283,7 @@ public class FixedDataManager
{ {
ObjectArrays.quickSort(slots); ObjectArrays.quickSort(slots);
List<FixedSlot> fixed = new ObjectArrayList<FixedSlot>(); List<FixedSlot> fixed = new ObjectArrayList<FixedSlot>();
List<Entry<byte[]>> data = new ObjectArrayList<Entry<byte[]>>(); List<IntObjectPair<byte[]>> data = new ObjectArrayList<>();
FixedSlot first = null; FixedSlot first = null;
FixedSlot last = null; FixedSlot last = null;
for(int i = 0,m=slots.length;i<m;i++) for(int i = 0,m=slots.length;i<m;i++)
@ -304,7 +303,7 @@ public class FixedDataManager
ByteBuffer buffer = ByteBuffer.allocate(fixed.size() * bytes).order(ByteOrder.nativeOrder()); ByteBuffer buffer = ByteBuffer.allocate(fixed.size() * bytes).order(ByteOrder.nativeOrder());
handler.createData(buffer, fixed.size(), fixed); handler.createData(buffer, fixed.size(), fixed);
fixed.clear(); fixed.clear();
data.add(new BasicEntry<byte[]>(first.index * bytes, buffer.array())); data.add(IntObjectPair.of(first.index * bytes, buffer.array()));
i--; i--;
first = last = null; first = last = null;
} }
@ -313,7 +312,7 @@ public class FixedDataManager
ByteBuffer buffer = ByteBuffer.allocate(fixed.size() * bytes).order(ByteOrder.nativeOrder()); ByteBuffer buffer = ByteBuffer.allocate(fixed.size() * bytes).order(ByteOrder.nativeOrder());
handler.createData(buffer, fixed.size(), fixed); handler.createData(buffer, fixed.size(), fixed);
fixed.clear(); fixed.clear();
data.add(new BasicEntry<byte[]>(first.index * bytes, buffer.array())); data.add(IntObjectPair.of(first.index * bytes, buffer.array()));
} }
SLOTS.accept(slots); SLOTS.accept(slots);
return new FinishingTask(handler, data, size); return new FinishingTask(handler, data, size);
@ -339,10 +338,10 @@ public class FixedDataManager
static class FinishingTask implements Runnable static class FinishingTask implements Runnable
{ {
IFixedDataHandler handler; IFixedDataHandler handler;
List<Entry<byte[]>> data; List<IntObjectPair<byte[]>> data;
int size; int size;
public FinishingTask(IFixedDataHandler handler, List<Entry<byte[]>> data, int size) public FinishingTask(IFixedDataHandler handler, List<IntObjectPair<byte[]>> data, int size)
{ {
this.handler = handler; this.handler = handler;
this.data = data; this.data = data;

View File

@ -3,11 +3,11 @@ package speiger.src.coreengine.utils.collections.managers.fixed;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap.Entry; import speiger.src.collections.ints.misc.pairs.IntObjectPair;
public interface IFixedDataHandler public interface IFixedDataHandler
{ {
public void createData(ByteBuffer data, int size, List<FixedSlot> slots); public void createData(ByteBuffer data, int size, List<FixedSlot> slots);
public void updateData(List<Entry<byte[]>> list, int newSize); public void updateData(List<IntObjectPair<byte[]>> list, int newSize);
} }

View File

@ -8,6 +8,8 @@ import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -55,6 +57,32 @@ public class JsonUtil
} }
} }
public static void iterate(JsonElement element, Consumer<JsonObject> listener)
{
if(element.isJsonObject()) listener.accept(element.getAsJsonObject());
else if(element.isJsonArray())
{
JsonArray array = element.getAsJsonArray();
for(int i = 0,m=array.size();i<m;i++)
{
iterate(array.get(i), listener);
}
}
}
public static <T> void iterate(JsonElement element, T input, BiConsumer<JsonObject, T> listener)
{
if(element.isJsonObject()) listener.accept(element.getAsJsonObject(), input);
else if(element.isJsonArray())
{
JsonArray array = element.getAsJsonArray();
for(int i = 0,m=array.size();i<m;i++)
{
iterate(array.get(i), input, listener);
}
}
}
public static boolean getOrDefault(JsonObject obj, String name, boolean defaultValue) public static boolean getOrDefault(JsonObject obj, String name, boolean defaultValue)
{ {
JsonElement el = obj.get(name); JsonElement el = obj.get(name);
@ -103,6 +131,7 @@ public class JsonUtil
return el == null ? defaultValue : el.getAsString(); return el == null ? defaultValue : el.getAsString();
} }
public static JsonArray toArray(byte[] values) public static JsonArray toArray(byte[] values)
{ {
JsonArray array = new JsonArray(); JsonArray array = new JsonArray();
@ -113,7 +142,28 @@ public class JsonUtil
return array; return array;
} }
public static byte[] parseArray(JsonArray array) public static JsonArray toArray(float[] values)
{
JsonArray array = new JsonArray();
for(int i = 0,m=values.length;i<m;i++)
{
array.add(values[i]);
}
return array;
}
public static JsonArray toArray(Number[] values)
{
JsonArray array = new JsonArray();
for(int i = 0,m=values.length;i<m;i++)
{
array.add(values[i]);
}
return array;
}
public static byte[] parseByteArray(JsonArray array)
{ {
byte[] data = new byte[array.size()]; byte[] data = new byte[array.size()];
for(int i = 0,m=data.length;i<m;i++) for(int i = 0,m=data.length;i<m;i++)
@ -122,4 +172,14 @@ public class JsonUtil
} }
return data; return data;
} }
public static float[] parseFloatArray(JsonArray array)
{
float[] data = new float[array.size()];
for(int i = 0,m=data.length;i<m;i++)
{
data[i] = array.get(i).getAsFloat();
}
return data;
}
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1,395 +0,0 @@
textureWidth=1024, textureHeight=512, base=39, fontHeight=50
letter=0, minX=0, minY=0, maxX=0, maxY=50, bold=0
letter=2, minX=0, minY=0, maxX=0, maxY=50, bold=0
letter=9, minX=0, minY=0, maxX=0, maxY=50, bold=0
letter=10, minX=0, minY=0, maxX=0, maxY=50, bold=0
letter=13, minX=0, minY=0, maxX=0, maxY=50, bold=0
letter=32, minX=0, minY=0, maxX=10, maxY=50, bold=0
letter=33, minX=10, minY=0, maxX=21, maxY=50, bold=0
letter=34, minX=21, minY=0, maxX=35, maxY=50, bold=0
letter=35, minX=35, minY=0, maxX=61, maxY=50, bold=0
letter=36, minX=61, minY=0, maxX=85, maxY=50, bold=0
letter=37, minX=85, minY=0, maxX=116, maxY=50, bold=0
letter=38, minX=116, minY=0, maxX=143, maxY=50, bold=0
letter=39, minX=143, minY=0, maxX=150, maxY=50, bold=0
letter=40, minX=150, minY=0, maxX=165, maxY=50, bold=0
letter=41, minX=165, minY=0, maxX=180, maxY=50, bold=0
letter=42, minX=180, minY=0, maxX=199, maxY=50, bold=0
letter=43, minX=199, minY=0, maxX=222, maxY=50, bold=0
letter=44, minX=222, minY=0, maxX=231, maxY=50, bold=0
letter=45, minX=231, minY=0, maxX=245, maxY=50, bold=0
letter=46, minX=245, minY=0, maxX=257, maxY=50, bold=0
letter=47, minX=257, minY=0, maxX=274, maxY=50, bold=0
letter=48, minX=274, minY=0, maxX=298, maxY=50, bold=0
letter=49, minX=298, minY=0, maxX=322, maxY=50, bold=0
letter=50, minX=322, minY=0, maxX=346, maxY=50, bold=0
letter=51, minX=346, minY=0, maxX=370, maxY=50, bold=0
letter=52, minX=370, minY=0, maxX=394, maxY=50, bold=0
letter=53, minX=394, minY=0, maxX=418, maxY=50, bold=0
letter=54, minX=418, minY=0, maxX=442, maxY=50, bold=0
letter=55, minX=442, minY=0, maxX=466, maxY=50, bold=0
letter=56, minX=466, minY=0, maxX=490, maxY=50, bold=0
letter=57, minX=490, minY=0, maxX=514, maxY=50, bold=0
letter=58, minX=514, minY=0, maxX=525, maxY=50, bold=0
letter=59, minX=525, minY=0, maxX=535, maxY=50, bold=0
letter=60, minX=535, minY=0, maxX=556, maxY=50, bold=0
letter=61, minX=556, minY=0, maxX=580, maxY=50, bold=0
letter=62, minX=580, minY=0, maxX=602, maxY=50, bold=0
letter=63, minX=602, minY=0, maxX=622, maxY=50, bold=0
letter=64, minX=622, minY=0, maxX=660, maxY=50, bold=0
letter=65, minX=660, minY=0, maxX=688, maxY=50, bold=0
letter=66, minX=688, minY=0, maxX=715, maxY=50, bold=0
letter=67, minX=715, minY=0, maxX=742, maxY=50, bold=0
letter=68, minX=742, minY=0, maxX=769, maxY=50, bold=0
letter=69, minX=769, minY=0, maxX=793, maxY=50, bold=0
letter=70, minX=793, minY=0, maxX=816, maxY=50, bold=0
letter=71, minX=816, minY=0, maxX=845, maxY=50, bold=0
letter=72, minX=845, minY=0, maxX=875, maxY=50, bold=0
letter=73, minX=875, minY=0, maxX=887, maxY=50, bold=0
letter=74, minX=887, minY=0, maxX=910, maxY=50, bold=0
letter=75, minX=910, minY=0, maxX=936, maxY=50, bold=0
letter=76, minX=936, minY=0, maxX=959, maxY=50, bold=0
letter=77, minX=959, minY=0, maxX=996, maxY=50, bold=0
letter=78, minX=0, minY=51, maxX=30, maxY=101, bold=0
letter=79, minX=30, minY=51, maxX=59, maxY=101, bold=0
letter=80, minX=59, minY=51, maxX=86, maxY=101, bold=0
letter=81, minX=86, minY=51, maxX=115, maxY=101, bold=0
letter=82, minX=115, minY=51, maxX=141, maxY=101, bold=0
letter=83, minX=141, minY=51, maxX=166, maxY=101, bold=0
letter=84, minX=166, minY=51, maxX=191, maxY=101, bold=0
letter=85, minX=191, minY=51, maxX=218, maxY=101, bold=0
letter=86, minX=218, minY=51, maxX=245, maxY=101, bold=0
letter=87, minX=245, minY=51, maxX=282, maxY=101, bold=0
letter=88, minX=282, minY=51, maxX=309, maxY=101, bold=0
letter=89, minX=309, minY=51, maxX=335, maxY=101, bold=0
letter=90, minX=335, minY=51, maxX=360, maxY=101, bold=0
letter=91, minX=360, minY=51, maxX=372, maxY=101, bold=0
letter=92, minX=372, minY=51, maxX=390, maxY=101, bold=0
letter=93, minX=390, minY=51, maxX=402, maxY=101, bold=0
letter=94, minX=402, minY=51, maxX=420, maxY=101, bold=0
letter=95, minX=420, minY=51, maxX=439, maxY=101, bold=0
letter=96, minX=439, minY=51, maxX=453, maxY=101, bold=0
letter=97, minX=453, minY=51, maxX=476, maxY=101, bold=0
letter=98, minX=476, minY=51, maxX=500, maxY=101, bold=0
letter=99, minX=500, minY=51, maxX=522, maxY=101, bold=0
letter=100, minX=522, minY=51, maxX=546, maxY=101, bold=0
letter=101, minX=546, minY=51, maxX=569, maxY=101, bold=0
letter=102, minX=569, minY=51, maxX=584, maxY=101, bold=0
letter=103, minX=584, minY=51, maxX=608, maxY=101, bold=0
letter=104, minX=608, minY=51, maxX=631, maxY=101, bold=0
letter=105, minX=631, minY=51, maxX=642, maxY=101, bold=0
letter=32, minX=642, minY=51, maxX=652, maxY=101, bold=0
letter=106, minX=652, minY=51, maxX=663, maxY=101, bold=0
letter=107, minX=663, minY=51, maxX=685, maxY=101, bold=0
letter=108, minX=685, minY=51, maxX=696, maxY=101, bold=0
letter=109, minX=696, minY=51, maxX=733, maxY=101, bold=0
letter=110, minX=733, minY=51, maxX=756, maxY=101, bold=0
letter=111, minX=756, minY=51, maxX=780, maxY=101, bold=0
letter=112, minX=780, minY=51, maxX=804, maxY=101, bold=0
letter=113, minX=804, minY=51, maxX=828, maxY=101, bold=0
letter=114, minX=828, minY=51, maxX=843, maxY=101, bold=0
letter=115, minX=843, minY=51, maxX=865, maxY=101, bold=0
letter=116, minX=865, minY=51, maxX=879, maxY=101, bold=0
letter=117, minX=879, minY=51, maxX=902, maxY=101, bold=0
letter=118, minX=902, minY=51, maxX=923, maxY=101, bold=0
letter=119, minX=923, minY=51, maxX=954, maxY=101, bold=0
letter=120, minX=954, minY=51, maxX=975, maxY=101, bold=0
letter=121, minX=975, minY=51, maxX=995, maxY=101, bold=0
letter=122, minX=995, minY=51, maxX=1016, maxY=101, bold=0
letter=123, minX=0, minY=102, maxX=14, maxY=152, bold=0
letter=124, minX=14, minY=102, maxX=25, maxY=152, bold=0
letter=125, minX=25, minY=102, maxX=39, maxY=152, bold=0
letter=126, minX=39, minY=102, maxX=67, maxY=152, bold=0
letter=160, minX=67, minY=102, maxX=77, maxY=152, bold=0
letter=161, minX=77, minY=102, maxX=88, maxY=152, bold=0
letter=162, minX=88, minY=102, maxX=112, maxY=152, bold=0
letter=163, minX=112, minY=102, maxX=137, maxY=152, bold=0
letter=164, minX=137, minY=102, maxX=166, maxY=152, bold=0
letter=165, minX=166, minY=102, maxX=188, maxY=152, bold=0
letter=166, minX=188, minY=102, maxX=198, maxY=152, bold=0
letter=167, minX=198, minY=102, maxX=224, maxY=152, bold=0
letter=168, minX=224, minY=102, maxX=242, maxY=152, bold=0
letter=169, minX=242, minY=102, maxX=275, maxY=152, bold=0
letter=170, minX=275, minY=102, maxX=294, maxY=152, bold=0
letter=171, minX=294, minY=102, maxX=314, maxY=152, bold=0
letter=172, minX=314, minY=102, maxX=337, maxY=152, bold=0
letter=173, minX=337, minY=102, maxX=351, maxY=152, bold=0
letter=174, minX=351, minY=102, maxX=384, maxY=152, bold=0
letter=175, minX=384, minY=102, maxX=404, maxY=152, bold=0
letter=176, minX=404, minY=102, maxX=420, maxY=152, bold=0
letter=177, minX=420, minY=102, maxX=443, maxY=152, bold=0
letter=178, minX=443, minY=102, maxX=459, maxY=152, bold=0
letter=179, minX=459, minY=102, maxX=475, maxY=152, bold=0
letter=180, minX=475, minY=102, maxX=489, maxY=152, bold=0
letter=181, minX=489, minY=102, maxX=514, maxY=152, bold=0
letter=182, minX=514, minY=102, maxX=535, maxY=152, bold=0
letter=183, minX=535, minY=102, maxX=547, maxY=152, bold=0
letter=184, minX=547, minY=102, maxX=558, maxY=152, bold=0
letter=185, minX=558, minY=102, maxX=574, maxY=152, bold=0
letter=186, minX=574, minY=102, maxX=593, maxY=152, bold=0
letter=187, minX=593, minY=102, maxX=613, maxY=152, bold=0
letter=188, minX=613, minY=102, maxX=644, maxY=152, bold=0
letter=189, minX=644, minY=102, maxX=676, maxY=152, bold=0
letter=190, minX=676, minY=102, maxX=709, maxY=152, bold=0
letter=191, minX=709, minY=102, maxX=729, maxY=152, bold=0
letter=192, minX=729, minY=102, maxX=757, maxY=152, bold=0
letter=193, minX=757, minY=102, maxX=785, maxY=152, bold=0
letter=194, minX=785, minY=102, maxX=813, maxY=152, bold=0
letter=195, minX=813, minY=102, maxX=841, maxY=152, bold=0
letter=196, minX=841, minY=102, maxX=869, maxY=152, bold=0
letter=197, minX=869, minY=102, maxX=897, maxY=152, bold=0
letter=198, minX=897, minY=102, maxX=936, maxY=152, bold=0
letter=199, minX=936, minY=102, maxX=963, maxY=152, bold=0
letter=200, minX=963, minY=102, maxX=987, maxY=152, bold=0
letter=201, minX=987, minY=102, maxX=1011, maxY=152, bold=0
letter=202, minX=0, minY=153, maxX=24, maxY=203, bold=0
letter=203, minX=24, minY=153, maxX=48, maxY=203, bold=0
letter=204, minX=48, minY=153, maxX=60, maxY=203, bold=0
letter=205, minX=60, minY=153, maxX=72, maxY=203, bold=0
letter=206, minX=72, minY=153, maxX=84, maxY=203, bold=0
letter=207, minX=84, minY=153, maxX=96, maxY=203, bold=0
letter=208, minX=96, minY=153, maxX=124, maxY=203, bold=0
letter=209, minX=124, minY=153, maxX=154, maxY=203, bold=0
letter=210, minX=154, minY=153, maxX=183, maxY=203, bold=0
letter=211, minX=183, minY=153, maxX=212, maxY=203, bold=0
letter=212, minX=212, minY=153, maxX=241, maxY=203, bold=0
letter=213, minX=241, minY=153, maxX=270, maxY=203, bold=0
letter=214, minX=270, minY=153, maxX=299, maxY=203, bold=0
letter=215, minX=299, minY=153, maxX=321, maxY=203, bold=0
letter=216, minX=321, minY=153, maxX=350, maxY=203, bold=0
letter=217, minX=350, minY=153, maxX=377, maxY=203, bold=0
letter=218, minX=377, minY=153, maxX=404, maxY=203, bold=0
letter=219, minX=404, minY=153, maxX=431, maxY=203, bold=0
letter=220, minX=431, minY=153, maxX=458, maxY=203, bold=0
letter=221, minX=458, minY=153, maxX=484, maxY=203, bold=0
letter=222, minX=484, minY=153, maxX=509, maxY=203, bold=0
letter=223, minX=509, minY=153, maxX=535, maxY=203, bold=0
letter=224, minX=535, minY=153, maxX=558, maxY=203, bold=0
letter=225, minX=558, minY=153, maxX=581, maxY=203, bold=0
letter=226, minX=581, minY=153, maxX=604, maxY=203, bold=0
letter=227, minX=604, minY=153, maxX=627, maxY=203, bold=0
letter=228, minX=627, minY=153, maxX=650, maxY=203, bold=0
letter=229, minX=650, minY=153, maxX=673, maxY=203, bold=0
letter=230, minX=673, minY=153, maxX=708, maxY=203, bold=0
letter=231, minX=708, minY=153, maxX=730, maxY=203, bold=0
letter=232, minX=730, minY=153, maxX=753, maxY=203, bold=0
letter=233, minX=753, minY=153, maxX=776, maxY=203, bold=0
letter=234, minX=776, minY=153, maxX=799, maxY=203, bold=0
letter=235, minX=799, minY=153, maxX=822, maxY=203, bold=0
letter=236, minX=822, minY=153, maxX=833, maxY=203, bold=0
letter=237, minX=833, minY=153, maxX=844, maxY=203, bold=0
letter=238, minX=844, minY=153, maxX=855, maxY=203, bold=0
letter=239, minX=855, minY=153, maxX=866, maxY=203, bold=0
letter=240, minX=866, minY=153, maxX=890, maxY=203, bold=0
letter=241, minX=890, minY=153, maxX=913, maxY=203, bold=0
letter=242, minX=913, minY=153, maxX=937, maxY=203, bold=0
letter=243, minX=937, minY=153, maxX=961, maxY=203, bold=0
letter=244, minX=961, minY=153, maxX=985, maxY=203, bold=0
letter=245, minX=985, minY=153, maxX=1009, maxY=203, bold=0
letter=246, minX=0, minY=204, maxX=24, maxY=254, bold=0
letter=247, minX=24, minY=204, maxX=48, maxY=254, bold=0
letter=248, minX=48, minY=204, maxX=72, maxY=254, bold=0
letter=249, minX=72, minY=204, maxX=95, maxY=254, bold=0
letter=250, minX=95, minY=204, maxX=118, maxY=254, bold=0
letter=251, minX=118, minY=204, maxX=141, maxY=254, bold=0
letter=252, minX=141, minY=204, maxX=164, maxY=254, bold=0
letter=253, minX=164, minY=204, maxX=184, maxY=254, bold=0
letter=254, minX=184, minY=204, maxX=208, maxY=254, bold=0
letter=255, minX=208, minY=204, maxX=228, maxY=254, bold=0
letter=0, minX=0, minY=0, maxX=0, maxY=50, bold=1
letter=2, minX=0, minY=0, maxX=0, maxY=50, bold=1
letter=9, minX=0, minY=0, maxX=0, maxY=50, bold=1
letter=10, minX=0, minY=0, maxX=0, maxY=50, bold=1
letter=13, minX=0, minY=0, maxX=0, maxY=50, bold=1
letter=32, minX=228, minY=204, maxX=240, maxY=254, bold=1
letter=33, minX=240, minY=204, maxX=253, maxY=254, bold=1
letter=34, minX=253, minY=204, maxX=269, maxY=254, bold=1
letter=35, minX=269, minY=204, maxX=297, maxY=254, bold=1
letter=36, minX=297, minY=204, maxX=323, maxY=254, bold=1
letter=37, minX=323, minY=204, maxX=356, maxY=254, bold=1
letter=38, minX=356, minY=204, maxX=385, maxY=254, bold=1
letter=39, minX=385, minY=204, maxX=394, maxY=254, bold=1
letter=40, minX=394, minY=204, maxX=411, maxY=254, bold=1
letter=41, minX=411, minY=204, maxX=428, maxY=254, bold=1
letter=42, minX=428, minY=204, maxX=449, maxY=254, bold=1
letter=43, minX=449, minY=204, maxX=474, maxY=254, bold=1
letter=44, minX=474, minY=204, maxX=485, maxY=254, bold=1
letter=45, minX=485, minY=204, maxX=501, maxY=254, bold=1
letter=46, minX=501, minY=204, maxX=515, maxY=254, bold=1
letter=47, minX=515, minY=204, maxX=534, maxY=254, bold=1
letter=48, minX=534, minY=204, maxX=560, maxY=254, bold=1
letter=49, minX=560, minY=204, maxX=586, maxY=254, bold=1
letter=50, minX=586, minY=204, maxX=612, maxY=254, bold=1
letter=51, minX=612, minY=204, maxX=638, maxY=254, bold=1
letter=52, minX=638, minY=204, maxX=664, maxY=254, bold=1
letter=53, minX=664, minY=204, maxX=690, maxY=254, bold=1
letter=54, minX=690, minY=204, maxX=716, maxY=254, bold=1
letter=55, minX=716, minY=204, maxX=742, maxY=254, bold=1
letter=56, minX=742, minY=204, maxX=768, maxY=254, bold=1
letter=57, minX=768, minY=204, maxX=794, maxY=254, bold=1
letter=58, minX=794, minY=204, maxX=807, maxY=254, bold=1
letter=59, minX=807, minY=204, maxX=819, maxY=254, bold=1
letter=60, minX=819, minY=204, maxX=842, maxY=254, bold=1
letter=61, minX=842, minY=204, maxX=868, maxY=254, bold=1
letter=62, minX=868, minY=204, maxX=892, maxY=254, bold=1
letter=63, minX=892, minY=204, maxX=914, maxY=254, bold=1
letter=64, minX=914, minY=204, maxX=954, maxY=254, bold=1
letter=65, minX=954, minY=204, maxX=984, maxY=254, bold=1
letter=66, minX=984, minY=204, maxX=1013, maxY=254, bold=1
letter=67, minX=0, minY=255, maxX=29, maxY=305, bold=1
letter=68, minX=29, minY=255, maxX=58, maxY=305, bold=1
letter=69, minX=58, minY=255, maxX=84, maxY=305, bold=1
letter=70, minX=84, minY=255, maxX=109, maxY=305, bold=1
letter=71, minX=109, minY=255, maxX=140, maxY=305, bold=1
letter=72, minX=140, minY=255, maxX=172, maxY=305, bold=1
letter=73, minX=172, minY=255, maxX=186, maxY=305, bold=1
letter=74, minX=186, minY=255, maxX=211, maxY=305, bold=1
letter=75, minX=211, minY=255, maxX=239, maxY=305, bold=1
letter=76, minX=239, minY=255, maxX=264, maxY=305, bold=1
letter=77, minX=264, minY=255, maxX=303, maxY=305, bold=1
letter=78, minX=303, minY=255, maxX=335, maxY=305, bold=1
letter=79, minX=335, minY=255, maxX=366, maxY=305, bold=1
letter=80, minX=366, minY=255, maxX=395, maxY=305, bold=1
letter=81, minX=395, minY=255, maxX=426, maxY=305, bold=1
letter=82, minX=426, minY=255, maxX=454, maxY=305, bold=1
letter=83, minX=454, minY=255, maxX=481, maxY=305, bold=1
letter=84, minX=481, minY=255, maxX=508, maxY=305, bold=1
letter=85, minX=508, minY=255, maxX=537, maxY=305, bold=1
letter=86, minX=537, minY=255, maxX=566, maxY=305, bold=1
letter=87, minX=566, minY=255, maxX=605, maxY=305, bold=1
letter=88, minX=605, minY=255, maxX=634, maxY=305, bold=1
letter=89, minX=634, minY=255, maxX=662, maxY=305, bold=1
letter=90, minX=662, minY=255, maxX=689, maxY=305, bold=1
letter=91, minX=689, minY=255, maxX=703, maxY=305, bold=1
letter=92, minX=703, minY=255, maxX=723, maxY=305, bold=1
letter=93, minX=723, minY=255, maxX=737, maxY=305, bold=1
letter=94, minX=737, minY=255, maxX=757, maxY=305, bold=1
letter=95, minX=757, minY=255, maxX=778, maxY=305, bold=1
letter=96, minX=778, minY=255, maxX=794, maxY=305, bold=1
letter=97, minX=794, minY=255, maxX=819, maxY=305, bold=1
letter=98, minX=819, minY=255, maxX=845, maxY=305, bold=1
letter=99, minX=845, minY=255, maxX=869, maxY=305, bold=1
letter=100, minX=869, minY=255, maxX=895, maxY=305, bold=1
letter=101, minX=895, minY=255, maxX=920, maxY=305, bold=1
letter=102, minX=920, minY=255, maxX=937, maxY=305, bold=1
letter=103, minX=937, minY=255, maxX=963, maxY=305, bold=1
letter=104, minX=963, minY=255, maxX=988, maxY=305, bold=1
letter=105, minX=988, minY=255, maxX=1001, maxY=305, bold=1
letter=32, minX=1001, minY=255, maxX=1013, maxY=305, bold=1
letter=106, minX=0, minY=306, maxX=13, maxY=356, bold=1
letter=107, minX=13, minY=306, maxX=37, maxY=356, bold=1
letter=108, minX=37, minY=306, maxX=50, maxY=356, bold=1
letter=109, minX=50, minY=306, maxX=89, maxY=356, bold=1
letter=110, minX=89, minY=306, maxX=114, maxY=356, bold=1
letter=111, minX=114, minY=306, maxX=140, maxY=356, bold=1
letter=112, minX=140, minY=306, maxX=166, maxY=356, bold=1
letter=113, minX=166, minY=306, maxX=192, maxY=356, bold=1
letter=114, minX=192, minY=306, maxX=209, maxY=356, bold=1
letter=115, minX=209, minY=306, maxX=233, maxY=356, bold=1
letter=116, minX=233, minY=306, maxX=249, maxY=356, bold=1
letter=117, minX=249, minY=306, maxX=274, maxY=356, bold=1
letter=118, minX=274, minY=306, maxX=297, maxY=356, bold=1
letter=119, minX=297, minY=306, maxX=330, maxY=356, bold=1
letter=120, minX=330, minY=306, maxX=353, maxY=356, bold=1
letter=121, minX=353, minY=306, maxX=375, maxY=356, bold=1
letter=122, minX=375, minY=306, maxX=398, maxY=356, bold=1
letter=123, minX=398, minY=306, maxX=414, maxY=356, bold=1
letter=124, minX=414, minY=306, maxX=427, maxY=356, bold=1
letter=125, minX=427, minY=306, maxX=443, maxY=356, bold=1
letter=126, minX=443, minY=306, maxX=473, maxY=356, bold=1
letter=160, minX=473, minY=306, maxX=485, maxY=356, bold=1
letter=161, minX=485, minY=306, maxX=498, maxY=356, bold=1
letter=162, minX=498, minY=306, maxX=524, maxY=356, bold=1
letter=163, minX=524, minY=306, maxX=551, maxY=356, bold=1
letter=164, minX=551, minY=306, maxX=582, maxY=356, bold=1
letter=165, minX=582, minY=306, maxX=606, maxY=356, bold=1
letter=166, minX=606, minY=306, maxX=618, maxY=356, bold=1
letter=167, minX=618, minY=306, maxX=646, maxY=356, bold=1
letter=168, minX=646, minY=306, maxX=666, maxY=356, bold=1
letter=169, minX=666, minY=306, maxX=701, maxY=356, bold=1
letter=170, minX=701, minY=306, maxX=722, maxY=356, bold=1
letter=171, minX=722, minY=306, maxX=744, maxY=356, bold=1
letter=172, minX=744, minY=306, maxX=769, maxY=356, bold=1
letter=173, minX=769, minY=306, maxX=785, maxY=356, bold=1
letter=174, minX=785, minY=306, maxX=820, maxY=356, bold=1
letter=175, minX=820, minY=306, maxX=842, maxY=356, bold=1
letter=176, minX=842, minY=306, maxX=860, maxY=356, bold=1
letter=177, minX=860, minY=306, maxX=885, maxY=356, bold=1
letter=178, minX=885, minY=306, maxX=903, maxY=356, bold=1
letter=179, minX=903, minY=306, maxX=921, maxY=356, bold=1
letter=180, minX=921, minY=306, maxX=937, maxY=356, bold=1
letter=181, minX=937, minY=306, maxX=964, maxY=356, bold=1
letter=182, minX=964, minY=306, maxX=987, maxY=356, bold=1
letter=183, minX=987, minY=306, maxX=1001, maxY=356, bold=1
letter=184, minX=1001, minY=306, maxX=1014, maxY=356, bold=1
letter=185, minX=0, minY=357, maxX=18, maxY=407, bold=1
letter=186, minX=18, minY=357, maxX=39, maxY=407, bold=1
letter=187, minX=39, minY=357, maxX=61, maxY=407, bold=1
letter=188, minX=61, minY=357, maxX=94, maxY=407, bold=1
letter=189, minX=94, minY=357, maxX=128, maxY=407, bold=1
letter=190, minX=128, minY=357, maxX=163, maxY=407, bold=1
letter=191, minX=163, minY=357, maxX=185, maxY=407, bold=1
letter=192, minX=185, minY=357, maxX=215, maxY=407, bold=1
letter=193, minX=215, minY=357, maxX=245, maxY=407, bold=1
letter=194, minX=245, minY=357, maxX=275, maxY=407, bold=1
letter=195, minX=275, minY=357, maxX=305, maxY=407, bold=1
letter=196, minX=305, minY=357, maxX=335, maxY=407, bold=1
letter=197, minX=335, minY=357, maxX=365, maxY=407, bold=1
letter=198, minX=365, minY=357, maxX=406, maxY=407, bold=1
letter=199, minX=406, minY=357, maxX=435, maxY=407, bold=1
letter=200, minX=435, minY=357, maxX=461, maxY=407, bold=1
letter=201, minX=461, minY=357, maxX=487, maxY=407, bold=1
letter=202, minX=487, minY=357, maxX=513, maxY=407, bold=1
letter=203, minX=513, minY=357, maxX=539, maxY=407, bold=1
letter=204, minX=539, minY=357, maxX=553, maxY=407, bold=1
letter=205, minX=553, minY=357, maxX=567, maxY=407, bold=1
letter=206, minX=567, minY=357, maxX=581, maxY=407, bold=1
letter=207, minX=581, minY=357, maxX=595, maxY=407, bold=1
letter=208, minX=595, minY=357, maxX=625, maxY=407, bold=1
letter=209, minX=625, minY=357, maxX=657, maxY=407, bold=1
letter=210, minX=657, minY=357, maxX=688, maxY=407, bold=1
letter=211, minX=688, minY=357, maxX=719, maxY=407, bold=1
letter=212, minX=719, minY=357, maxX=750, maxY=407, bold=1
letter=213, minX=750, minY=357, maxX=781, maxY=407, bold=1
letter=214, minX=781, minY=357, maxX=812, maxY=407, bold=1
letter=215, minX=812, minY=357, maxX=836, maxY=407, bold=1
letter=216, minX=836, minY=357, maxX=867, maxY=407, bold=1
letter=217, minX=867, minY=357, maxX=896, maxY=407, bold=1
letter=218, minX=896, minY=357, maxX=925, maxY=407, bold=1
letter=219, minX=925, minY=357, maxX=954, maxY=407, bold=1
letter=220, minX=954, minY=357, maxX=983, maxY=407, bold=1
letter=221, minX=983, minY=357, maxX=1011, maxY=407, bold=1
letter=222, minX=0, minY=408, maxX=27, maxY=458, bold=1
letter=223, minX=27, minY=408, maxX=55, maxY=458, bold=1
letter=224, minX=55, minY=408, maxX=80, maxY=458, bold=1
letter=225, minX=80, minY=408, maxX=105, maxY=458, bold=1
letter=226, minX=105, minY=408, maxX=130, maxY=458, bold=1
letter=227, minX=130, minY=408, maxX=155, maxY=458, bold=1
letter=228, minX=155, minY=408, maxX=180, maxY=458, bold=1
letter=229, minX=180, minY=408, maxX=205, maxY=458, bold=1
letter=230, minX=205, minY=408, maxX=242, maxY=458, bold=1
letter=231, minX=242, minY=408, maxX=266, maxY=458, bold=1
letter=232, minX=266, minY=408, maxX=291, maxY=458, bold=1
letter=233, minX=291, minY=408, maxX=316, maxY=458, bold=1
letter=234, minX=316, minY=408, maxX=341, maxY=458, bold=1
letter=235, minX=341, minY=408, maxX=366, maxY=458, bold=1
letter=236, minX=366, minY=408, maxX=379, maxY=458, bold=1
letter=237, minX=379, minY=408, maxX=392, maxY=458, bold=1
letter=238, minX=392, minY=408, maxX=405, maxY=458, bold=1
letter=239, minX=405, minY=408, maxX=418, maxY=458, bold=1
letter=240, minX=418, minY=408, maxX=444, maxY=458, bold=1
letter=241, minX=444, minY=408, maxX=469, maxY=458, bold=1
letter=242, minX=469, minY=408, maxX=495, maxY=458, bold=1
letter=243, minX=495, minY=408, maxX=521, maxY=458, bold=1
letter=244, minX=521, minY=408, maxX=547, maxY=458, bold=1
letter=245, minX=547, minY=408, maxX=573, maxY=458, bold=1
letter=246, minX=573, minY=408, maxX=599, maxY=458, bold=1
letter=247, minX=599, minY=408, maxX=625, maxY=458, bold=1
letter=248, minX=625, minY=408, maxX=651, maxY=458, bold=1
letter=249, minX=651, minY=408, maxX=676, maxY=458, bold=1
letter=250, minX=676, minY=408, maxX=701, maxY=458, bold=1
letter=251, minX=701, minY=408, maxX=726, maxY=458, bold=1
letter=252, minX=726, minY=408, maxX=751, maxY=458, bold=1
letter=253, minX=751, minY=408, maxX=773, maxY=458, bold=1
letter=254, minX=773, minY=408, maxX=799, maxY=458, bold=1
letter=255, minX=799, minY=408, maxX=821, maxY=458, bold=1

View File

@ -0,0 +1,405 @@
{
"type": "bitmap",
"file": "base:font/roboto_texture.png",
"info": {
"width": 2048,
"height": 1024,
"base": 80,
"charHeight": 100,
"tabs": 4
},
"chars": [
{"char": 198, "minX": 0, "minY": 0, "maxX": 79, "maxY": 100, "bold": true},
{"char": 64, "minX": 79, "minY": 0, "maxX": 154, "maxY": 100, "bold": true},
{"char": 109, "minX": 154, "minY": 0, "maxX": 227, "maxY": 100, "bold": true},
{"char": 87, "minX": 227, "minY": 0, "maxX": 300, "maxY": 100, "bold": true},
{"char": 77, "minX": 300, "minY": 0, "maxX": 373, "maxY": 100, "bold": true},
{"char": 198, "minX": 373, "minY": 0, "maxX": 448, "maxY": 96, "bold": false},
{"char": 64, "minX": 448, "minY": 0, "maxX": 520, "maxY": 96, "bold": false},
{"char": 109, "minX": 520, "minY": 0, "maxX": 590, "maxY": 96, "bold": false},
{"char": 87, "minX": 590, "minY": 0, "maxX": 660, "maxY": 96, "bold": false},
{"char": 77, "minX": 660, "minY": 0, "maxX": 730, "maxY": 96, "bold": false},
{"char": 230, "minX": 730, "minY": 0, "maxX": 798, "maxY": 96, "bold": false},
{"char": 190, "minX": 798, "minY": 0, "maxX": 861, "maxY": 96, "bold": false},
{"char": 174, "minX": 861, "minY": 0, "maxX": 924, "maxY": 96, "bold": false},
{"char": 169, "minX": 924, "minY": 0, "maxX": 987, "maxY": 96, "bold": false},
{"char": 189, "minX": 987, "minY": 0, "maxX": 1049, "maxY": 96, "bold": false},
{"char": 119, "minX": 1049, "minY": 0, "maxX": 1108, "maxY": 96, "bold": false},
{"char": 37, "minX": 1108, "minY": 0, "maxX": 1167, "maxY": 96, "bold": false},
{"char": 188, "minX": 1167, "minY": 0, "maxX": 1225, "maxY": 96, "bold": false},
{"char": 209, "minX": 1225, "minY": 0, "maxX": 1282, "maxY": 96, "bold": false},
{"char": 72, "minX": 1282, "minY": 0, "maxX": 1339, "maxY": 96, "bold": false},
{"char": 78, "minX": 1339, "minY": 0, "maxX": 1396, "maxY": 96, "bold": false},
{"char": 164, "minX": 1396, "minY": 0, "maxX": 1452, "maxY": 96, "bold": false},
{"char": 210, "minX": 1452, "minY": 0, "maxX": 1507, "maxY": 96, "bold": false},
{"char": 211, "minX": 1507, "minY": 0, "maxX": 1562, "maxY": 96, "bold": false},
{"char": 212, "minX": 1562, "minY": 0, "maxX": 1617, "maxY": 96, "bold": false},
{"char": 213, "minX": 1617, "minY": 0, "maxX": 1672, "maxY": 96, "bold": false},
{"char": 214, "minX": 1672, "minY": 0, "maxX": 1727, "maxY": 96, "bold": false},
{"char": 216, "minX": 1727, "minY": 0, "maxX": 1782, "maxY": 96, "bold": false},
{"char": 79, "minX": 1782, "minY": 0, "maxX": 1837, "maxY": 96, "bold": false},
{"char": 81, "minX": 1837, "minY": 0, "maxX": 1892, "maxY": 96, "bold": false},
{"char": 71, "minX": 1892, "minY": 0, "maxX": 1946, "maxY": 96, "bold": false},
{"char": 196, "minX": 1946, "minY": 0, "maxX": 1999, "maxY": 96, "bold": false},
{"char": 221, "minX": 1999, "minY": 0, "maxX": 2048, "maxY": 96, "bold": false},
{"char": 230, "minX": 0, "minY": 100, "maxX": 71, "maxY": 200, "bold": true},
{"char": 190, "minX": 71, "minY": 100, "maxX": 137, "maxY": 200, "bold": true},
{"char": 174, "minX": 137, "minY": 100, "maxX": 203, "maxY": 200, "bold": true},
{"char": 169, "minX": 203, "minY": 100, "maxX": 269, "maxY": 200, "bold": true},
{"char": 189, "minX": 269, "minY": 100, "maxX": 334, "maxY": 200, "bold": true},
{"char": 119, "minX": 334, "minY": 100, "maxX": 396, "maxY": 200, "bold": true},
{"char": 37, "minX": 396, "minY": 100, "maxX": 458, "maxY": 200, "bold": true},
{"char": 188, "minX": 458, "minY": 100, "maxX": 519, "maxY": 200, "bold": true},
{"char": 209, "minX": 519, "minY": 100, "maxX": 579, "maxY": 200, "bold": true},
{"char": 72, "minX": 579, "minY": 100, "maxX": 639, "maxY": 200, "bold": true},
{"char": 78, "minX": 639, "minY": 100, "maxX": 699, "maxY": 200, "bold": true},
{"char": 164, "minX": 699, "minY": 100, "maxX": 758, "maxY": 200, "bold": true},
{"char": 210, "minX": 758, "minY": 100, "maxX": 816, "maxY": 200, "bold": true},
{"char": 211, "minX": 816, "minY": 100, "maxX": 874, "maxY": 200, "bold": true},
{"char": 212, "minX": 874, "minY": 100, "maxX": 932, "maxY": 200, "bold": true},
{"char": 213, "minX": 932, "minY": 100, "maxX": 990, "maxY": 200, "bold": true},
{"char": 214, "minX": 990, "minY": 100, "maxX": 1048, "maxY": 200, "bold": true},
{"char": 216, "minX": 1048, "minY": 100, "maxX": 1106, "maxY": 200, "bold": true},
{"char": 196, "minX": 1106, "minY": 100, "maxX": 1164, "maxY": 200, "bold": true},
{"char": 197, "minX": 1164, "minY": 100, "maxX": 1222, "maxY": 200, "bold": true},
{"char": 192, "minX": 1222, "minY": 100, "maxX": 1280, "maxY": 200, "bold": true},
{"char": 193, "minX": 1280, "minY": 100, "maxX": 1338, "maxY": 200, "bold": true},
{"char": 194, "minX": 1338, "minY": 100, "maxX": 1396, "maxY": 200, "bold": true},
{"char": 195, "minX": 1396, "minY": 100, "maxX": 1454, "maxY": 200, "bold": true},
{"char": 79, "minX": 1454, "minY": 100, "maxX": 1512, "maxY": 200, "bold": true},
{"char": 81, "minX": 1512, "minY": 100, "maxX": 1570, "maxY": 200, "bold": true},
{"char": 65, "minX": 1570, "minY": 100, "maxX": 1628, "maxY": 200, "bold": true},
{"char": 71, "minX": 1628, "minY": 100, "maxX": 1685, "maxY": 200, "bold": true},
{"char": 126, "minX": 1685, "minY": 100, "maxX": 1741, "maxY": 200, "bold": true},
{"char": 220, "minX": 1741, "minY": 100, "maxX": 1796, "maxY": 200, "bold": true},
{"char": 217, "minX": 1796, "minY": 100, "maxX": 1851, "maxY": 200, "bold": true},
{"char": 218, "minX": 1851, "minY": 100, "maxX": 1906, "maxY": 200, "bold": true},
{"char": 219, "minX": 1906, "minY": 100, "maxX": 1961, "maxY": 200, "bold": true},
{"char": 199, "minX": 1961, "minY": 100, "maxX": 2016, "maxY": 200, "bold": true},
{"char": 239, "minX": 2016, "minY": 100, "maxX": 2048, "maxY": 200, "bold": true},
{"char": 85, "minX": 0, "minY": 200, "maxX": 55, "maxY": 300, "bold": true},
{"char": 86, "minX": 55, "minY": 200, "maxX": 110, "maxY": 300, "bold": true},
{"char": 67, "minX": 110, "minY": 200, "maxX": 165, "maxY": 300, "bold": true},
{"char": 68, "minX": 165, "minY": 200, "maxX": 220, "maxY": 300, "bold": true},
{"char": 221, "minX": 220, "minY": 200, "maxX": 274, "maxY": 300, "bold": true},
{"char": 208, "minX": 274, "minY": 200, "maxX": 328, "maxY": 300, "bold": true},
{"char": 80, "minX": 328, "minY": 200, "maxX": 382, "maxY": 300, "bold": true},
{"char": 88, "minX": 382, "minY": 200, "maxX": 436, "maxY": 300, "bold": true},
{"char": 89, "minX": 436, "minY": 200, "maxX": 490, "maxY": 300, "bold": true},
{"char": 38, "minX": 490, "minY": 200, "maxX": 544, "maxY": 300, "bold": true},
{"char": 167, "minX": 544, "minY": 200, "maxX": 597, "maxY": 300, "bold": true},
{"char": 82, "minX": 597, "minY": 200, "maxX": 650, "maxY": 300, "bold": true},
{"char": 75, "minX": 650, "minY": 200, "maxX": 703, "maxY": 300, "bold": true},
{"char": 66, "minX": 703, "minY": 200, "maxX": 756, "maxY": 300, "bold": true},
{"char": 223, "minX": 756, "minY": 200, "maxX": 808, "maxY": 300, "bold": true},
{"char": 84, "minX": 808, "minY": 200, "maxX": 860, "maxY": 300, "bold": true},
{"char": 35, "minX": 860, "minY": 200, "maxX": 912, "maxY": 300, "bold": true},
{"char": 222, "minX": 912, "minY": 200, "maxX": 963, "maxY": 300, "bold": true},
{"char": 83, "minX": 963, "minY": 200, "maxX": 1014, "maxY": 300, "bold": true},
{"char": 90, "minX": 1014, "minY": 200, "maxX": 1065, "maxY": 300, "bold": true},
{"char": 197, "minX": 1065, "minY": 200, "maxX": 1118, "maxY": 296, "bold": false},
{"char": 192, "minX": 1118, "minY": 200, "maxX": 1171, "maxY": 296, "bold": false},
{"char": 193, "minX": 1171, "minY": 200, "maxX": 1224, "maxY": 296, "bold": false},
{"char": 194, "minX": 1224, "minY": 200, "maxX": 1277, "maxY": 296, "bold": false},
{"char": 195, "minX": 1277, "minY": 200, "maxX": 1330, "maxY": 296, "bold": false},
{"char": 126, "minX": 1330, "minY": 200, "maxX": 1383, "maxY": 296, "bold": false},
{"char": 65, "minX": 1383, "minY": 200, "maxX": 1436, "maxY": 296, "bold": false},
{"char": 220, "minX": 1436, "minY": 200, "maxX": 1488, "maxY": 296, "bold": false},
{"char": 217, "minX": 1488, "minY": 200, "maxX": 1540, "maxY": 296, "bold": false},
{"char": 218, "minX": 1540, "minY": 200, "maxX": 1592, "maxY": 296, "bold": false},
{"char": 219, "minX": 1592, "minY": 200, "maxX": 1644, "maxY": 296, "bold": false},
{"char": 199, "minX": 1644, "minY": 200, "maxX": 1696, "maxY": 296, "bold": false},
{"char": 85, "minX": 1696, "minY": 200, "maxX": 1748, "maxY": 296, "bold": false},
{"char": 86, "minX": 1748, "minY": 200, "maxX": 1800, "maxY": 296, "bold": false},
{"char": 67, "minX": 1800, "minY": 200, "maxX": 1852, "maxY": 296, "bold": false},
{"char": 68, "minX": 1852, "minY": 200, "maxX": 1904, "maxY": 296, "bold": false},
{"char": 208, "minX": 1904, "minY": 200, "maxX": 1955, "maxY": 296, "bold": false},
{"char": 80, "minX": 1955, "minY": 200, "maxX": 2006, "maxY": 296, "bold": false},
{"char": 231, "minX": 2006, "minY": 200, "maxX": 2048, "maxY": 296, "bold": false},
{"char": 240, "minX": 0, "minY": 300, "maxX": 50, "maxY": 400, "bold": true},
{"char": 181, "minX": 50, "minY": 300, "maxX": 100, "maxY": 400, "bold": true},
{"char": 163, "minX": 100, "minY": 300, "maxX": 150, "maxY": 400, "bold": true},
{"char": 244, "minX": 150, "minY": 300, "maxX": 199, "maxY": 400, "bold": true},
{"char": 245, "minX": 199, "minY": 300, "maxX": 248, "maxY": 400, "bold": true},
{"char": 246, "minX": 248, "minY": 300, "maxX": 297, "maxY": 400, "bold": true},
{"char": 247, "minX": 297, "minY": 300, "maxX": 346, "maxY": 400, "bold": true},
{"char": 254, "minX": 346, "minY": 300, "maxX": 395, "maxY": 400, "bold": true},
{"char": 242, "minX": 395, "minY": 300, "maxX": 444, "maxY": 400, "bold": true},
{"char": 243, "minX": 444, "minY": 300, "maxX": 493, "maxY": 400, "bold": true},
{"char": 111, "minX": 493, "minY": 300, "maxX": 542, "maxY": 400, "bold": true},
{"char": 88, "minX": 542, "minY": 300, "maxX": 593, "maxY": 396, "bold": false},
{"char": 38, "minX": 593, "minY": 300, "maxX": 644, "maxY": 396, "bold": false},
{"char": 167, "minX": 644, "minY": 300, "maxX": 694, "maxY": 396, "bold": false},
{"char": 82, "minX": 694, "minY": 300, "maxX": 744, "maxY": 396, "bold": false},
{"char": 75, "minX": 744, "minY": 300, "maxX": 794, "maxY": 396, "bold": false},
{"char": 66, "minX": 794, "minY": 300, "maxX": 844, "maxY": 396, "bold": false},
{"char": 223, "minX": 844, "minY": 300, "maxX": 893, "maxY": 396, "bold": false},
{"char": 84, "minX": 893, "minY": 300, "maxX": 942, "maxY": 396, "bold": false},
{"char": 89, "minX": 942, "minY": 300, "maxX": 991, "maxY": 396, "bold": false},
{"char": 35, "minX": 991, "minY": 300, "maxX": 1040, "maxY": 396, "bold": false},
{"char": 222, "minX": 1040, "minY": 300, "maxX": 1088, "maxY": 396, "bold": false},
{"char": 83, "minX": 1088, "minY": 300, "maxX": 1136, "maxY": 396, "bold": false},
{"char": 90, "minX": 1136, "minY": 300, "maxX": 1184, "maxY": 396, "bold": false},
{"char": 240, "minX": 1184, "minY": 300, "maxX": 1231, "maxY": 396, "bold": false},
{"char": 181, "minX": 1231, "minY": 300, "maxX": 1278, "maxY": 396, "bold": false},
{"char": 163, "minX": 1278, "minY": 300, "maxX": 1325, "maxY": 396, "bold": false},
{"char": 244, "minX": 1325, "minY": 300, "maxX": 1371, "maxY": 396, "bold": false},
{"char": 245, "minX": 1371, "minY": 300, "maxX": 1417, "maxY": 396, "bold": false},
{"char": 246, "minX": 1417, "minY": 300, "maxX": 1463, "maxY": 396, "bold": false},
{"char": 247, "minX": 1463, "minY": 300, "maxX": 1509, "maxY": 396, "bold": false},
{"char": 254, "minX": 1509, "minY": 300, "maxX": 1555, "maxY": 396, "bold": false},
{"char": 242, "minX": 1555, "minY": 300, "maxX": 1601, "maxY": 396, "bold": false},
{"char": 243, "minX": 1601, "minY": 300, "maxX": 1647, "maxY": 396, "bold": false},
{"char": 111, "minX": 1647, "minY": 300, "maxX": 1693, "maxY": 396, "bold": false},
{"char": 248, "minX": 1693, "minY": 300, "maxX": 1738, "maxY": 396, "bold": false},
{"char": 241, "minX": 1738, "minY": 300, "maxX": 1783, "maxY": 396, "bold": false},
{"char": 200, "minX": 1783, "minY": 300, "maxX": 1828, "maxY": 396, "bold": false},
{"char": 201, "minX": 1828, "minY": 300, "maxX": 1873, "maxY": 396, "bold": false},
{"char": 202, "minX": 1873, "minY": 300, "maxX": 1918, "maxY": 396, "bold": false},
{"char": 203, "minX": 1918, "minY": 300, "maxX": 1963, "maxY": 396, "bold": false},
{"char": 162, "minX": 1963, "minY": 300, "maxX": 2008, "maxY": 396, "bold": false},
{"char": 118, "minX": 2008, "minY": 300, "maxX": 2048, "maxY": 396, "bold": false},
{"char": 248, "minX": 0, "minY": 400, "maxX": 48, "maxY": 500, "bold": true},
{"char": 241, "minX": 48, "minY": 400, "maxX": 96, "maxY": 500, "bold": true},
{"char": 200, "minX": 96, "minY": 400, "maxX": 144, "maxY": 500, "bold": true},
{"char": 201, "minX": 144, "minY": 400, "maxX": 192, "maxY": 500, "bold": true},
{"char": 202, "minX": 192, "minY": 400, "maxX": 240, "maxY": 500, "bold": true},
{"char": 203, "minX": 240, "minY": 400, "maxX": 288, "maxY": 500, "bold": true},
{"char": 162, "minX": 288, "minY": 400, "maxX": 336, "maxY": 500, "bold": true},
{"char": 165, "minX": 336, "minY": 400, "maxX": 384, "maxY": 500, "bold": true},
{"char": 103, "minX": 384, "minY": 400, "maxX": 432, "maxY": 500, "bold": true},
{"char": 110, "minX": 432, "minY": 400, "maxX": 480, "maxY": 500, "bold": true},
{"char": 112, "minX": 480, "minY": 400, "maxX": 528, "maxY": 500, "bold": true},
{"char": 113, "minX": 528, "minY": 400, "maxX": 576, "maxY": 500, "bold": true},
{"char": 98, "minX": 576, "minY": 400, "maxX": 624, "maxY": 500, "bold": true},
{"char": 100, "minX": 624, "minY": 400, "maxX": 672, "maxY": 500, "bold": true},
{"char": 69, "minX": 672, "minY": 400, "maxX": 720, "maxY": 500, "bold": true},
{"char": 55, "minX": 720, "minY": 400, "maxX": 768, "maxY": 500, "bold": true},
{"char": 56, "minX": 768, "minY": 400, "maxX": 816, "maxY": 500, "bold": true},
{"char": 57, "minX": 816, "minY": 400, "maxX": 864, "maxY": 500, "bold": true},
{"char": 61, "minX": 864, "minY": 400, "maxX": 912, "maxY": 500, "bold": true},
{"char": 43, "minX": 912, "minY": 400, "maxX": 960, "maxY": 500, "bold": true},
{"char": 48, "minX": 960, "minY": 400, "maxX": 1008, "maxY": 500, "bold": true},
{"char": 49, "minX": 1008, "minY": 400, "maxX": 1056, "maxY": 500, "bold": true},
{"char": 50, "minX": 1056, "minY": 400, "maxX": 1104, "maxY": 500, "bold": true},
{"char": 51, "minX": 1104, "minY": 400, "maxX": 1152, "maxY": 500, "bold": true},
{"char": 52, "minX": 1152, "minY": 400, "maxX": 1200, "maxY": 500, "bold": true},
{"char": 53, "minX": 1200, "minY": 400, "maxX": 1248, "maxY": 500, "bold": true},
{"char": 54, "minX": 1248, "minY": 400, "maxX": 1296, "maxY": 500, "bold": true},
{"char": 36, "minX": 1296, "minY": 400, "maxX": 1344, "maxY": 500, "bold": true},
{"char": 249, "minX": 1344, "minY": 400, "maxX": 1391, "maxY": 500, "bold": true},
{"char": 250, "minX": 1391, "minY": 400, "maxX": 1438, "maxY": 500, "bold": true},
{"char": 251, "minX": 1438, "minY": 400, "maxX": 1485, "maxY": 500, "bold": true},
{"char": 252, "minX": 1485, "minY": 400, "maxX": 1532, "maxY": 500, "bold": true},
{"char": 172, "minX": 1532, "minY": 400, "maxX": 1579, "maxY": 500, "bold": true},
{"char": 117, "minX": 1579, "minY": 400, "maxX": 1626, "maxY": 500, "bold": true},
{"char": 104, "minX": 1626, "minY": 400, "maxX": 1673, "maxY": 500, "bold": true},
{"char": 70, "minX": 1673, "minY": 400, "maxX": 1720, "maxY": 500, "bold": true},
{"char": 74, "minX": 1720, "minY": 400, "maxX": 1767, "maxY": 500, "bold": true},
{"char": 232, "minX": 1767, "minY": 400, "maxX": 1813, "maxY": 500, "bold": true},
{"char": 233, "minX": 1813, "minY": 400, "maxX": 1859, "maxY": 500, "bold": true},
{"char": 234, "minX": 1859, "minY": 400, "maxX": 1905, "maxY": 500, "bold": true},
{"char": 235, "minX": 1905, "minY": 400, "maxX": 1951, "maxY": 500, "bold": true},
{"char": 224, "minX": 1951, "minY": 400, "maxX": 1997, "maxY": 500, "bold": true},
{"char": 225, "minX": 1997, "minY": 400, "maxX": 2043, "maxY": 500, "bold": true},
{"char": 226, "minX": 0, "minY": 500, "maxX": 46, "maxY": 600, "bold": true},
{"char": 227, "minX": 46, "minY": 500, "maxX": 92, "maxY": 600, "bold": true},
{"char": 228, "minX": 92, "minY": 500, "maxX": 138, "maxY": 600, "bold": true},
{"char": 229, "minX": 138, "minY": 500, "maxX": 184, "maxY": 600, "bold": true},
{"char": 215, "minX": 184, "minY": 500, "maxX": 230, "maxY": 600, "bold": true},
{"char": 177, "minX": 230, "minY": 500, "maxX": 276, "maxY": 600, "bold": true},
{"char": 97, "minX": 276, "minY": 500, "maxX": 322, "maxY": 600, "bold": true},
{"char": 101, "minX": 322, "minY": 500, "maxX": 368, "maxY": 600, "bold": true},
{"char": 76, "minX": 368, "minY": 500, "maxX": 414, "maxY": 600, "bold": true},
{"char": 231, "minX": 414, "minY": 500, "maxX": 459, "maxY": 600, "bold": true},
{"char": 120, "minX": 459, "minY": 500, "maxX": 504, "maxY": 600, "bold": true},
{"char": 107, "minX": 504, "minY": 500, "maxX": 549, "maxY": 600, "bold": true},
{"char": 99, "minX": 549, "minY": 500, "maxX": 594, "maxY": 600, "bold": true},
{"char": 62, "minX": 594, "minY": 500, "maxX": 639, "maxY": 600, "bold": true},
{"char": 253, "minX": 639, "minY": 500, "maxX": 683, "maxY": 600, "bold": true},
{"char": 255, "minX": 683, "minY": 500, "maxX": 727, "maxY": 600, "bold": true},
{"char": 115, "minX": 727, "minY": 500, "maxX": 771, "maxY": 600, "bold": true},
{"char": 121, "minX": 771, "minY": 500, "maxX": 815, "maxY": 600, "bold": true},
{"char": 60, "minX": 815, "minY": 500, "maxX": 859, "maxY": 600, "bold": true},
{"char": 103, "minX": 859, "minY": 500, "maxX": 904, "maxY": 596, "bold": false},
{"char": 110, "minX": 904, "minY": 500, "maxX": 949, "maxY": 596, "bold": false},
{"char": 112, "minX": 949, "minY": 500, "maxX": 994, "maxY": 596, "bold": false},
{"char": 113, "minX": 994, "minY": 500, "maxX": 1039, "maxY": 596, "bold": false},
{"char": 98, "minX": 1039, "minY": 500, "maxX": 1084, "maxY": 596, "bold": false},
{"char": 100, "minX": 1084, "minY": 500, "maxX": 1129, "maxY": 596, "bold": false},
{"char": 69, "minX": 1129, "minY": 500, "maxX": 1174, "maxY": 596, "bold": false},
{"char": 55, "minX": 1174, "minY": 500, "maxX": 1219, "maxY": 596, "bold": false},
{"char": 56, "minX": 1219, "minY": 500, "maxX": 1264, "maxY": 596, "bold": false},
{"char": 57, "minX": 1264, "minY": 500, "maxX": 1309, "maxY": 596, "bold": false},
{"char": 61, "minX": 1309, "minY": 500, "maxX": 1354, "maxY": 596, "bold": false},
{"char": 43, "minX": 1354, "minY": 500, "maxX": 1399, "maxY": 596, "bold": false},
{"char": 48, "minX": 1399, "minY": 500, "maxX": 1444, "maxY": 596, "bold": false},
{"char": 49, "minX": 1444, "minY": 500, "maxX": 1489, "maxY": 596, "bold": false},
{"char": 50, "minX": 1489, "minY": 500, "maxX": 1534, "maxY": 596, "bold": false},
{"char": 51, "minX": 1534, "minY": 500, "maxX": 1579, "maxY": 596, "bold": false},
{"char": 52, "minX": 1579, "minY": 500, "maxX": 1624, "maxY": 596, "bold": false},
{"char": 53, "minX": 1624, "minY": 500, "maxX": 1669, "maxY": 596, "bold": false},
{"char": 54, "minX": 1669, "minY": 500, "maxX": 1714, "maxY": 596, "bold": false},
{"char": 36, "minX": 1714, "minY": 500, "maxX": 1759, "maxY": 596, "bold": false},
{"char": 249, "minX": 1759, "minY": 500, "maxX": 1803, "maxY": 596, "bold": false},
{"char": 250, "minX": 1803, "minY": 500, "maxX": 1847, "maxY": 596, "bold": false},
{"char": 251, "minX": 1847, "minY": 500, "maxX": 1891, "maxY": 596, "bold": false},
{"char": 252, "minX": 1891, "minY": 500, "maxX": 1935, "maxY": 596, "bold": false},
{"char": 172, "minX": 1935, "minY": 500, "maxX": 1979, "maxY": 596, "bold": false},
{"char": 117, "minX": 1979, "minY": 500, "maxX": 2023, "maxY": 596, "bold": false},
{"char": 205, "minX": 2023, "minY": 500, "maxX": 2046, "maxY": 596, "bold": false},
{"char": 118, "minX": 0, "minY": 600, "maxX": 43, "maxY": 700, "bold": true},
{"char": 122, "minX": 43, "minY": 600, "maxX": 86, "maxY": 700, "bold": true},
{"char": 104, "minX": 86, "minY": 600, "maxX": 130, "maxY": 696, "bold": false},
{"char": 70, "minX": 130, "minY": 600, "maxX": 174, "maxY": 696, "bold": false},
{"char": 74, "minX": 174, "minY": 600, "maxX": 218, "maxY": 696, "bold": false},
{"char": 232, "minX": 218, "minY": 600, "maxX": 261, "maxY": 696, "bold": false},
{"char": 233, "minX": 261, "minY": 600, "maxX": 304, "maxY": 696, "bold": false},
{"char": 234, "minX": 304, "minY": 600, "maxX": 347, "maxY": 696, "bold": false},
{"char": 235, "minX": 347, "minY": 600, "maxX": 390, "maxY": 696, "bold": false},
{"char": 224, "minX": 390, "minY": 600, "maxX": 433, "maxY": 696, "bold": false},
{"char": 225, "minX": 433, "minY": 600, "maxX": 476, "maxY": 696, "bold": false},
{"char": 226, "minX": 476, "minY": 600, "maxX": 519, "maxY": 696, "bold": false},
{"char": 227, "minX": 519, "minY": 600, "maxX": 562, "maxY": 696, "bold": false},
{"char": 228, "minX": 562, "minY": 600, "maxX": 605, "maxY": 696, "bold": false},
{"char": 229, "minX": 605, "minY": 600, "maxX": 648, "maxY": 696, "bold": false},
{"char": 215, "minX": 648, "minY": 600, "maxX": 691, "maxY": 696, "bold": false},
{"char": 177, "minX": 691, "minY": 600, "maxX": 734, "maxY": 696, "bold": false},
{"char": 165, "minX": 734, "minY": 600, "maxX": 777, "maxY": 696, "bold": false},
{"char": 97, "minX": 777, "minY": 600, "maxX": 820, "maxY": 696, "bold": false},
{"char": 101, "minX": 820, "minY": 600, "maxX": 863, "maxY": 696, "bold": false},
{"char": 76, "minX": 863, "minY": 600, "maxX": 906, "maxY": 696, "bold": false},
{"char": 107, "minX": 906, "minY": 600, "maxX": 948, "maxY": 696, "bold": false},
{"char": 99, "minX": 948, "minY": 600, "maxX": 990, "maxY": 696, "bold": false},
{"char": 62, "minX": 990, "minY": 600, "maxX": 1032, "maxY": 696, "bold": false},
{"char": 115, "minX": 1032, "minY": 600, "maxX": 1073, "maxY": 696, "bold": false},
{"char": 60, "minX": 1073, "minY": 600, "maxX": 1114, "maxY": 696, "bold": false},
{"char": 120, "minX": 1114, "minY": 600, "maxX": 1154, "maxY": 696, "bold": false},
{"char": 122, "minX": 1154, "minY": 600, "maxX": 1194, "maxY": 696, "bold": false},
{"char": 253, "minX": 1194, "minY": 600, "maxX": 1233, "maxY": 696, "bold": false},
{"char": 255, "minX": 1233, "minY": 600, "maxX": 1272, "maxY": 696, "bold": false},
{"char": 187, "minX": 1272, "minY": 600, "maxX": 1311, "maxY": 696, "bold": false},
{"char": 191, "minX": 1311, "minY": 600, "maxX": 1350, "maxY": 696, "bold": false},
{"char": 175, "minX": 1350, "minY": 600, "maxX": 1389, "maxY": 696, "bold": false},
{"char": 182, "minX": 1389, "minY": 600, "maxX": 1428, "maxY": 696, "bold": false},
{"char": 171, "minX": 1428, "minY": 600, "maxX": 1467, "maxY": 696, "bold": false},
{"char": 121, "minX": 1467, "minY": 600, "maxX": 1506, "maxY": 696, "bold": false},
{"char": 63, "minX": 1506, "minY": 600, "maxX": 1545, "maxY": 696, "bold": false},
{"char": 186, "minX": 1545, "minY": 600, "maxX": 1582, "maxY": 696, "bold": false},
{"char": 170, "minX": 1582, "minY": 600, "maxX": 1618, "maxY": 696, "bold": false},
{"char": 95, "minX": 1618, "minY": 600, "maxX": 1654, "maxY": 696, "bold": false},
{"char": 168, "minX": 1654, "minY": 600, "maxX": 1689, "maxY": 696, "bold": false},
{"char": 42, "minX": 1689, "minY": 600, "maxX": 1724, "maxY": 696, "bold": false},
{"char": 94, "minX": 1724, "minY": 600, "maxX": 1758, "maxY": 696, "bold": false},
{"char": 92, "minX": 1758, "minY": 600, "maxX": 1791, "maxY": 696, "bold": false},
{"char": 47, "minX": 1791, "minY": 600, "maxX": 1823, "maxY": 696, "bold": false},
{"char": 185, "minX": 1823, "minY": 600, "maxX": 1853, "maxY": 696, "bold": false},
{"char": 176, "minX": 1853, "minY": 600, "maxX": 1883, "maxY": 696, "bold": false},
{"char": 178, "minX": 1883, "minY": 600, "maxX": 1913, "maxY": 696, "bold": false},
{"char": 179, "minX": 1913, "minY": 600, "maxX": 1943, "maxY": 696, "bold": false},
{"char": 239, "minX": 1943, "minY": 600, "maxX": 1972, "maxY": 696, "bold": false},
{"char": 207, "minX": 1972, "minY": 600, "maxX": 2001, "maxY": 696, "bold": false},
{"char": 238, "minX": 2001, "minY": 600, "maxX": 2029, "maxY": 696, "bold": false},
{"char": 106, "minX": 2029, "minY": 600, "maxX": 2048, "maxY": 696, "bold": false},
{"char": 187, "minX": 0, "minY": 700, "maxX": 42, "maxY": 800, "bold": true},
{"char": 191, "minX": 42, "minY": 700, "maxX": 84, "maxY": 800, "bold": true},
{"char": 175, "minX": 84, "minY": 700, "maxX": 126, "maxY": 800, "bold": true},
{"char": 182, "minX": 126, "minY": 700, "maxX": 168, "maxY": 800, "bold": true},
{"char": 171, "minX": 168, "minY": 700, "maxX": 210, "maxY": 800, "bold": true},
{"char": 63, "minX": 210, "minY": 700, "maxX": 252, "maxY": 800, "bold": true},
{"char": 186, "minX": 252, "minY": 700, "maxX": 292, "maxY": 800, "bold": true},
{"char": 170, "minX": 292, "minY": 700, "maxX": 331, "maxY": 800, "bold": true},
{"char": 95, "minX": 331, "minY": 700, "maxX": 370, "maxY": 800, "bold": true},
{"char": 168, "minX": 370, "minY": 700, "maxX": 408, "maxY": 800, "bold": true},
{"char": 42, "minX": 408, "minY": 700, "maxX": 446, "maxY": 800, "bold": true},
{"char": 94, "minX": 446, "minY": 700, "maxX": 483, "maxY": 800, "bold": true},
{"char": 92, "minX": 483, "minY": 700, "maxX": 519, "maxY": 800, "bold": true},
{"char": 47, "minX": 519, "minY": 700, "maxX": 554, "maxY": 800, "bold": true},
{"char": 185, "minX": 554, "minY": 700, "maxX": 587, "maxY": 800, "bold": true},
{"char": 176, "minX": 587, "minY": 700, "maxX": 620, "maxY": 800, "bold": true},
{"char": 178, "minX": 620, "minY": 700, "maxX": 653, "maxY": 800, "bold": true},
{"char": 179, "minX": 653, "minY": 700, "maxX": 686, "maxY": 800, "bold": true},
{"char": 207, "minX": 686, "minY": 700, "maxX": 718, "maxY": 800, "bold": true},
{"char": 238, "minX": 718, "minY": 700, "maxX": 749, "maxY": 800, "bold": true},
{"char": 206, "minX": 749, "minY": 700, "maxX": 780, "maxY": 800, "bold": true},
{"char": 114, "minX": 780, "minY": 700, "maxX": 811, "maxY": 800, "bold": true},
{"char": 102, "minX": 811, "minY": 700, "maxX": 842, "maxY": 800, "bold": true},
{"char": 40, "minX": 842, "minY": 700, "maxX": 873, "maxY": 800, "bold": true},
{"char": 41, "minX": 873, "minY": 700, "maxX": 904, "maxY": 800, "bold": true},
{"char": 116, "minX": 904, "minY": 700, "maxX": 934, "maxY": 800, "bold": true},
{"char": 123, "minX": 934, "minY": 700, "maxX": 964, "maxY": 800, "bold": true},
{"char": 125, "minX": 964, "minY": 700, "maxX": 994, "maxY": 800, "bold": true},
{"char": 173, "minX": 994, "minY": 700, "maxX": 1023, "maxY": 800, "bold": true},
{"char": 180, "minX": 1023, "minY": 700, "maxX": 1052, "maxY": 800, "bold": true},
{"char": 45, "minX": 1052, "minY": 700, "maxX": 1081, "maxY": 800, "bold": true},
{"char": 34, "minX": 1081, "minY": 700, "maxX": 1110, "maxY": 800, "bold": true},
{"char": 206, "minX": 1110, "minY": 700, "maxX": 1138, "maxY": 796, "bold": false},
{"char": 114, "minX": 1138, "minY": 700, "maxX": 1166, "maxY": 796, "bold": false},
{"char": 102, "minX": 1166, "minY": 700, "maxX": 1194, "maxY": 796, "bold": false},
{"char": 40, "minX": 1194, "minY": 700, "maxX": 1222, "maxY": 796, "bold": false},
{"char": 41, "minX": 1222, "minY": 700, "maxX": 1250, "maxY": 796, "bold": false},
{"char": 116, "minX": 1250, "minY": 700, "maxX": 1277, "maxY": 796, "bold": false},
{"char": 123, "minX": 1277, "minY": 700, "maxX": 1304, "maxY": 796, "bold": false},
{"char": 125, "minX": 1304, "minY": 700, "maxX": 1331, "maxY": 796, "bold": false},
{"char": 173, "minX": 1331, "minY": 700, "maxX": 1357, "maxY": 796, "bold": false},
{"char": 180, "minX": 1357, "minY": 700, "maxX": 1383, "maxY": 796, "bold": false},
{"char": 96, "minX": 1383, "minY": 700, "maxX": 1409, "maxY": 796, "bold": false},
{"char": 45, "minX": 1409, "minY": 700, "maxX": 1435, "maxY": 796, "bold": false},
{"char": 34, "minX": 1435, "minY": 700, "maxX": 1461, "maxY": 796, "bold": false},
{"char": 183, "minX": 1461, "minY": 700, "maxX": 1484, "maxY": 796, "bold": false},
{"char": 73, "minX": 1484, "minY": 700, "maxX": 1507, "maxY": 796, "bold": false},
{"char": 91, "minX": 1507, "minY": 700, "maxX": 1529, "maxY": 796, "bold": false},
{"char": 93, "minX": 1529, "minY": 700, "maxX": 1551, "maxY": 796, "bold": false},
{"char": 46, "minX": 1551, "minY": 700, "maxX": 1573, "maxY": 796, "bold": false},
{"char": 237, "minX": 1573, "minY": 700, "maxX": 1594, "maxY": 796, "bold": false},
{"char": 184, "minX": 1594, "minY": 700, "maxX": 1615, "maxY": 796, "bold": false},
{"char": 161, "minX": 1615, "minY": 700, "maxX": 1636, "maxY": 796, "bold": false},
{"char": 58, "minX": 1636, "minY": 700, "maxX": 1657, "maxY": 796, "bold": false},
{"char": 33, "minX": 1657, "minY": 700, "maxX": 1678, "maxY": 796, "bold": false},
{"char": 236, "minX": 1678, "minY": 700, "maxX": 1698, "maxY": 796, "bold": false},
{"char": 204, "minX": 1698, "minY": 700, "maxX": 1718, "maxY": 796, "bold": false},
{"char": 160, "minX": 1718, "minY": 700, "maxX": 1738, "maxY": 796, "bold": false},
{"char": 166, "minX": 1738, "minY": 700, "maxX": 1758, "maxY": 796, "bold": false},
{"char": 124, "minX": 1758, "minY": 700, "maxX": 1778, "maxY": 796, "bold": false},
{"char": 105, "minX": 1778, "minY": 700, "maxX": 1798, "maxY": 796, "bold": false},
{"char": 108, "minX": 1798, "minY": 700, "maxX": 1818, "maxY": 796, "bold": false},
{"char": 32, "minX": 1818, "minY": 700, "maxX": 1838, "maxY": 796, "bold": false},
{"char": 59, "minX": 1838, "minY": 700, "maxX": 1857, "maxY": 796, "bold": false},
{"char": 44, "minX": 1857, "minY": 700, "maxX": 1875, "maxY": 796, "bold": false},
{"char": 39, "minX": 1875, "minY": 700, "maxX": 1889, "maxY": 796, "bold": false},
{"char": 236, "minX": 0, "minY": 800, "maxX": 26, "maxY": 900, "bold": true},
{"char": 204, "minX": 26, "minY": 800, "maxX": 52, "maxY": 900, "bold": true},
{"char": 205, "minX": 52, "minY": 800, "maxX": 78, "maxY": 900, "bold": true},
{"char": 183, "minX": 78, "minY": 800, "maxX": 104, "maxY": 900, "bold": true},
{"char": 96, "minX": 104, "minY": 800, "maxX": 130, "maxY": 900, "bold": true},
{"char": 73, "minX": 130, "minY": 800, "maxX": 156, "maxY": 900, "bold": true},
{"char": 91, "minX": 156, "minY": 800, "maxX": 181, "maxY": 900, "bold": true},
{"char": 93, "minX": 181, "minY": 800, "maxX": 206, "maxY": 900, "bold": true},
{"char": 46, "minX": 206, "minY": 800, "maxX": 231, "maxY": 900, "bold": true},
{"char": 237, "minX": 231, "minY": 800, "maxX": 255, "maxY": 900, "bold": true},
{"char": 184, "minX": 255, "minY": 800, "maxX": 279, "maxY": 900, "bold": true},
{"char": 161, "minX": 279, "minY": 800, "maxX": 303, "maxY": 900, "bold": true},
{"char": 58, "minX": 303, "minY": 800, "maxX": 327, "maxY": 900, "bold": true},
{"char": 33, "minX": 327, "minY": 800, "maxX": 351, "maxY": 900, "bold": true},
{"char": 160, "minX": 351, "minY": 800, "maxX": 374, "maxY": 900, "bold": true},
{"char": 166, "minX": 374, "minY": 800, "maxX": 397, "maxY": 900, "bold": true},
{"char": 124, "minX": 397, "minY": 800, "maxX": 420, "maxY": 900, "bold": true},
{"char": 105, "minX": 420, "minY": 800, "maxX": 443, "maxY": 900, "bold": true},
{"char": 108, "minX": 443, "minY": 800, "maxX": 466, "maxY": 900, "bold": true},
{"char": 32, "minX": 466, "minY": 800, "maxX": 489, "maxY": 900, "bold": true},
{"char": 106, "minX": 489, "minY": 800, "maxX": 511, "maxY": 900, "bold": true},
{"char": 59, "minX": 511, "minY": 800, "maxX": 533, "maxY": 900, "bold": true},
{"char": 44, "minX": 533, "minY": 800, "maxX": 554, "maxY": 900, "bold": true},
{"char": 39, "minX": 554, "minY": 800, "maxX": 571, "maxY": 900, "bold": true},
{"char": 0, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": false},
{"char": 2, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": false},
{"char": 9, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": false},
{"char": 10, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": false},
{"char": 13, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": false},
{"char": 0, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": true},
{"char": 2, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": true},
{"char": 9, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": true},
{"char": 10, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": true},
{"char": 13, "minX": 0, "minY": 0, "maxX": 0, "maxY": 0, "bold": true}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB