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:
@@ -1,6 +1,7 @@
|
||||
package speiger.src.coreengine.application;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.IntConsumer;
|
||||
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.rendering.gui.GuiManager;
|
||||
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.Mouse;
|
||||
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.shader.ProjectionBuffer;
|
||||
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.utils.counters.timers.FPSTimer;
|
||||
import speiger.src.coreengine.utils.eventbus.EventBus;
|
||||
@@ -41,6 +44,7 @@ public abstract class Application
|
||||
|
||||
protected ResourceReloader reloader = new ResourceReloader();
|
||||
protected AssetManager assetManager;
|
||||
protected FontManager fonts = new FontManager();
|
||||
protected ProjectionBuffer projectionBuffer;
|
||||
protected GuiManager uiManager;
|
||||
|
||||
@@ -49,10 +53,11 @@ public abstract class Application
|
||||
GLFWErrorCallback.createPrint(System.err).set();
|
||||
if(!GLFW.glfwInit()) throw new IllegalStateException("OpenGL can't be loaded");
|
||||
provider.init();
|
||||
boolean initEarly = earlyUILoad();
|
||||
try
|
||||
{
|
||||
mainWindow = createWindow(provider);
|
||||
mainWindow.finishWindow();
|
||||
if(initEarly) mainWindow.finishWindow();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@@ -68,6 +73,7 @@ public abstract class Application
|
||||
file = file.getName().endsWith(".jar") ? file : new File("bin/main");
|
||||
internalInit(file);
|
||||
init(file);
|
||||
if(!initEarly) mainWindow.finishWindow();
|
||||
executor.start(mainWindow);
|
||||
mainWindow.destroy();
|
||||
reloader.deleteResources();
|
||||
@@ -78,8 +84,12 @@ public abstract class Application
|
||||
protected void internalInit(File file)
|
||||
{
|
||||
assetManager = reloader.addReloadableResource(new AssetManager(file), true);
|
||||
assetManager.registerAssetParser(ByteBuffer.class, new NativeMemoryParser());
|
||||
reloader.addReloadableResource(fonts);
|
||||
fonts.setAssetManager(assetManager);
|
||||
ShaderTracker.INSTANCE.init(assetManager);
|
||||
TextureManager.INSTANCE.init(assetManager);
|
||||
preinit();
|
||||
reloader.addReloadableResource(ShaderTracker.INSTANCE);
|
||||
reloader.addReloadableResource(TextureManager.INSTANCE);
|
||||
camera = new Camera(mainWindow);
|
||||
@@ -95,8 +105,10 @@ public abstract class Application
|
||||
public void addExtraTickRates(IntConsumer ticks) {};
|
||||
public void addExtraTimers(ObjLongConsumer<String> profiler) {};
|
||||
public boolean initUI() { return true; }
|
||||
public boolean earlyUILoad() { return true; }
|
||||
public DebugOverlay createCustomDebug() { return null; }
|
||||
public abstract Window createWindow(WindowProvider provider) throws Exception;
|
||||
public void preinit() {}
|
||||
public abstract void init(File file);
|
||||
public abstract void update();
|
||||
public abstract void render(float particalTicks);
|
||||
|
||||
@@ -13,7 +13,7 @@ public class BaseUIManager extends GuiManager
|
||||
|
||||
public BaseUIManager(Application application)
|
||||
{
|
||||
super(application.mainWindow, application.eventBus);
|
||||
super(application.mainWindow, application.eventBus, application.fonts);
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import java.util.function.Function;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
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;
|
||||
final String domain;
|
||||
final String location;
|
||||
@@ -74,6 +74,13 @@ public final class AssetLocation
|
||||
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)
|
||||
{
|
||||
return location.domain.equals(domain) && location.location.equals(this.location);
|
||||
|
||||
@@ -5,21 +5,25 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
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.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.ZipAssetPackage;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
|
||||
public class AssetManager implements IReloadableResource
|
||||
{
|
||||
Map<String, DomainAssets> domains = new Object2ObjectLinkedOpenHashMap<>();
|
||||
Object2ObjectMap<String, DomainAssets> domains = new Object2ObjectLinkedOpenHashMap<>();
|
||||
Object2ObjectMap<Class<?>, IAssetParser<?>> parsers = new Object2ObjectLinkedOpenHashMap<>();
|
||||
Path path;
|
||||
|
||||
@@ -121,11 +125,21 @@ public class AssetManager implements IReloadableResource
|
||||
DomainAssets asset = domains.get(location.getDomain());
|
||||
if(asset == null)
|
||||
{
|
||||
throw new FileNotFoundException("File["+location.toString()+"] not found");
|
||||
throw new FileNotFoundException("Domain & File["+location.toString()+"] not found");
|
||||
}
|
||||
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)
|
||||
{
|
||||
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()]));
|
||||
}
|
||||
|
||||
public void gatherAssets(AssetLocation folder, int maxDepth, Predicate<String> filter, Collection<AssetLocation> result)
|
||||
{
|
||||
for(IAssetPackage entry : packages)
|
||||
{
|
||||
entry.getAllAssets(folder, filter, maxDepth, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
@@ -16,11 +17,13 @@ public interface IAsset extends Closeable
|
||||
|
||||
public InputStream getStream() throws IOException;
|
||||
|
||||
public BufferedImage getTexture() throws Exception;
|
||||
public ByteBuffer getBytes() throws IOException;
|
||||
|
||||
public BufferedReader getStringReader() throws IOException;
|
||||
|
||||
public JsonObject getJsonObject() throws IOException;
|
||||
|
||||
public BufferedImage getTexture() throws Exception;
|
||||
|
||||
public <T> T getCustom(Class<T> clz) throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public interface IAssetPackage
|
||||
{
|
||||
public void setParsers(Function<Class<?>, IAssetParser<?>> parsers);
|
||||
public List<String> getDomains();
|
||||
public IAsset getAsset(AssetLocation location);
|
||||
public void getAllAssets(AssetLocation folder, Predicate<String> fileNames, int maxDepth, Collection<AssetLocation> result);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface IAssetParser<T>
|
||||
{
|
||||
public T parseAsset(Path path, Consumer<Closeable> autoCloser);
|
||||
public T parseAsset(Path path, Consumer<Closeable> autoCloser) throws IOException;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
@@ -76,6 +77,12 @@ public class FolderAsset implements IAsset
|
||||
return markClosed(Files.newInputStream(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getBytes() throws IOException
|
||||
{
|
||||
return ByteBuffer.wrap(Files.readAllBytes(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getTexture() throws Exception
|
||||
{
|
||||
|
||||
@@ -5,14 +5,18 @@ import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
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.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.IAsset;
|
||||
import speiger.src.coreengine.assets.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.IAssetParser;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class FolderAssetPackage implements IAssetPackage
|
||||
{
|
||||
@@ -59,4 +63,22 @@ public class FolderAssetPackage implements IAssetPackage
|
||||
Path path = baseFolder.resolve(location.getActualLocation());
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.Function;
|
||||
@@ -71,6 +72,12 @@ public class ZipAsset implements IAsset
|
||||
return Files.newInputStream(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getBytes() throws IOException
|
||||
{
|
||||
return ByteBuffer.wrap(Files.readAllBytes(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getTexture() throws Exception
|
||||
{
|
||||
|
||||
@@ -7,15 +7,19 @@ import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
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.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.IAsset;
|
||||
import speiger.src.coreengine.assets.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.IAssetParser;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class ZipAssetPackage implements IAssetPackage
|
||||
{
|
||||
@@ -90,4 +94,23 @@ public class ZipAssetPackage implements IAssetPackage
|
||||
}
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
|
||||
|
||||
public class ResourceReloader
|
||||
{
|
||||
Set<IReloadableResource> resources = new ObjectLinkedOpenHashSet<IReloadableResource>();
|
||||
Set<IReloadableResource> resources = new ObjectLinkedOpenHashSet<>();
|
||||
boolean globalRemoval = false;
|
||||
boolean reloading = false;
|
||||
|
||||
|
||||
@@ -316,6 +316,16 @@ public class ColorObject
|
||||
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)
|
||||
{
|
||||
buffer.put((byte)((color >> 16) & 0xFF)).put((byte)((color >> 8) & 0xFF)).put((byte)(color & 0xFF));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.GuiShader;
|
||||
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.KeyPressEvent;
|
||||
import speiger.src.coreengine.rendering.input.events.MouseEvent;
|
||||
@@ -31,12 +32,13 @@ public abstract class GuiManager implements IWindowListener
|
||||
protected ScaledResolution res;
|
||||
protected long globalClock = 0L;
|
||||
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);
|
||||
|
||||
public GuiManager(Window window, EventBus bus)
|
||||
public GuiManager(Window window, EventBus bus, FontManager manager)
|
||||
{
|
||||
this.window = window;
|
||||
font = manager.loadFont(AssetLocation.of("font/roboto.json"), 18.5F);
|
||||
bus.register(MouseEvent.class, this::onMouseEvent);
|
||||
bus.register(KeyPressEvent.class, (T) -> T.setCanceled(onKeyPressed(T.key)));
|
||||
bus.register(CharTypeEvent.class, (T) -> T.setCanceled(onCharTyped(T.character, T.codePoint)));
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
package speiger.src.coreengine.rendering.gui;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.rendering.textures.ITexture;
|
||||
import speiger.src.coreengine.rendering.textures.SimpleTexture;
|
||||
import speiger.src.coreengine.rendering.textures.base.ITexture;
|
||||
|
||||
public class UITextures
|
||||
{
|
||||
public static final AssetLocation TEXTURE_LOCATION = AssetLocation.of("textures");
|
||||
|
||||
// public static final ITexture OK_SYMBOL = new SimpleTexture(sub("okSymbol.png"));
|
||||
// public static final ITexture CANCLE_SYMBOL = new SimpleTexture(sub("cancelSymbol.png"));
|
||||
public static final ITexture COLOR_WHEEL = new SimpleTexture(sub("colorWheel.png"));
|
||||
public static final ITexture COLOR_WHEEL = ITexture.simple(sub("colorWheel.png")).makeReloadable();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package speiger.src.coreengine.rendering.gui.components;
|
||||
|
||||
import speiger.src.coreengine.math.misc.ColorObject;
|
||||
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
|
||||
{
|
||||
|
||||
@@ -52,6 +52,7 @@ public class ListComponent<T extends IListEntry> extends GuiComponent
|
||||
protected int selectionMode = 1;
|
||||
protected int updateMode = 1;
|
||||
protected float entryHeight;
|
||||
protected float cachedWidth = 0F;
|
||||
protected ScrollBarComponent verticalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY);
|
||||
protected ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorObject.LIGHT_GRAY).setHorizontal(true);
|
||||
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()));
|
||||
}
|
||||
|
||||
public float getCachedWidth()
|
||||
{
|
||||
return cachedWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
@@ -434,6 +440,7 @@ public class ListComponent<T extends IListEntry> extends GuiComponent
|
||||
{
|
||||
width = Math.max(width, entries.get(i).getWidth());
|
||||
}
|
||||
this.cachedWidth = width;
|
||||
boolean lastVertical = this.verticalBar.isInUse();
|
||||
boolean lastHorizontal = this.horizontalBar.isInUse();
|
||||
verticalBar.setScrollMax(MathUtils.ceil(this.entries.size() * entryHeight));
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package speiger.src.coreengine.rendering.gui.components.icon;
|
||||
|
||||
import speiger.src.coreengine.math.misc.ColorObject;
|
||||
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
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ public class TextFilter
|
||||
public static final Predicate<String> INTEGER_ONLY = T -> {
|
||||
try {
|
||||
if(T == null || T.isEmpty());
|
||||
else if(T.length() == 1 && T.charAt(0) == '-');
|
||||
else Integer.parseInt(T);
|
||||
return true;
|
||||
}
|
||||
@@ -16,6 +17,7 @@ public class TextFilter
|
||||
public static final Predicate<String> FLOAT_ONLY = T -> {
|
||||
try {
|
||||
if(T == null || T.isEmpty());
|
||||
else if(T.length() == 1 && T.charAt(0) == '-');
|
||||
else Float.parseFloat(T);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.Locale;
|
||||
|
||||
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.FloatList;
|
||||
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.WordContext;
|
||||
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.tesselation.IVertexBuilder;
|
||||
import speiger.src.coreengine.rendering.tesselation.Tesselator;
|
||||
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;
|
||||
|
||||
public class FontRenderer implements IFontRenderer
|
||||
@@ -36,45 +36,51 @@ public class FontRenderer implements IFontRenderer
|
||||
public static final char LINE_SEPERATOR = '\n';
|
||||
Tesselator bufferBuilder = new Tesselator(655340);
|
||||
|
||||
IFontProvider provider;
|
||||
final TextLexer lexer = new TextLexer(this);
|
||||
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.texture = texture;
|
||||
this.height = height;
|
||||
this.baseLine = baseLine;
|
||||
space = chars[0].get(' ').getXAdvance();
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharInstance getInstance(char letter, boolean isBold)
|
||||
{
|
||||
return chars[isBold ? 1 : 0].get(letter);
|
||||
return provider.getCharacter(letter, isBold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFontHeight()
|
||||
{
|
||||
return height;
|
||||
return provider.getFontHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBaseLine()
|
||||
{
|
||||
return baseLine;
|
||||
return provider.getBaseLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)
|
||||
@@ -96,12 +102,12 @@ public class FontRenderer implements IFontRenderer
|
||||
{
|
||||
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
|
||||
}
|
||||
yOffset += height * context.getScale();
|
||||
yOffset += getFontHeight() * context.getScale();
|
||||
}
|
||||
bufferBuilder.finishData();
|
||||
if(bufferBuilder.getVertexCount() > 0)
|
||||
{
|
||||
drawCalls.add(bufferBuilder.getDrawCall(texture.getTextureID()));
|
||||
drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureID()));
|
||||
}
|
||||
bufferBuilder.setOffset(0F, 0F, 0F);
|
||||
return drawCalls;
|
||||
@@ -125,8 +131,8 @@ public class FontRenderer implements IFontRenderer
|
||||
return;
|
||||
}
|
||||
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.UI);
|
||||
int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (height * context.getScale())), lines.size()) : lines.size();
|
||||
float maxHeight = maxLanes * height * context.getScale();
|
||||
int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (getFontHeight() * context.getScale())), lines.size()) : lines.size();
|
||||
float maxHeight = maxLanes * getFontHeight() * context.getScale();
|
||||
float maxWidth = 0F;
|
||||
float yOffset = component.getVertical().align(boxHeight, maxHeight);
|
||||
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);
|
||||
}
|
||||
yOffset += height * context.getScale();
|
||||
yOffset += getFontHeight() * context.getScale();
|
||||
component.getMetadata().addLine(lines.get(i));
|
||||
}
|
||||
maxWidth /= 2;
|
||||
buffer.finishShape(texture.getTextureID(), bufferBuilder);
|
||||
buffer.finishShape(getTexture().getTextureID(), bufferBuilder);
|
||||
if(lineBuffer.hasData())
|
||||
{
|
||||
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())
|
||||
{
|
||||
case TAB:
|
||||
return space * 4 * scale;
|
||||
return provider.getTabWidth() * scale;
|
||||
case SPACE:
|
||||
return space * scale;
|
||||
return provider.getSpaceWidth() * scale;
|
||||
}
|
||||
if(instance.getXAdvance() <= 0F)
|
||||
{
|
||||
@@ -231,7 +237,7 @@ public class FontRenderer implements IFontRenderer
|
||||
{
|
||||
float lineWidth = lines.get(i).getWidth();
|
||||
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, yPos, 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)
|
||||
{
|
||||
float minY = yStart + baseLine + 0.5F;
|
||||
float maxY = yStart + baseLine + 1.5F;
|
||||
float minY = yStart + getBaseLine() + 0.5F;
|
||||
float maxY = yStart + getBaseLine() + 1.5F;
|
||||
if(flipPos)
|
||||
{
|
||||
minY = yStart - baseLine - 0.5F;
|
||||
maxY = yStart - baseLine - 1.5F;
|
||||
minY = yStart - getBaseLine() - 0.5F;
|
||||
maxY = yStart - getBaseLine() - 1.5F;
|
||||
}
|
||||
buffer.pos(xStart, maxY, 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)
|
||||
{
|
||||
float minY = yStart + height / 2.0F;
|
||||
float maxY = yStart + height / 2.0F + 1.4F;
|
||||
float minY = yStart + getFontHeight() / 2.0F;
|
||||
float maxY = yStart + getFontHeight() / 2.0F + 1.4F;
|
||||
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 + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
@@ -301,9 +307,9 @@ public class FontRenderer implements IFontRenderer
|
||||
switch(letter)
|
||||
{
|
||||
case SPACE:
|
||||
return space;
|
||||
return provider.getSpaceWidth();
|
||||
case TAB:
|
||||
return space * 4;
|
||||
return provider.getTabWidth();
|
||||
default:
|
||||
CharInstance instance = getInstance(letter, bold);
|
||||
return instance == null ? 0F : instance.getXAdvance();
|
||||
@@ -321,7 +327,7 @@ public class FontRenderer implements IFontRenderer
|
||||
char character = text.charAt(i);
|
||||
if(LINE_SEPERATOR == character)
|
||||
{
|
||||
result = Math.max(result, current += space);
|
||||
result = Math.max(result, current += provider.getSpaceWidth());
|
||||
current = 0.0F;
|
||||
continue;
|
||||
}
|
||||
@@ -391,13 +397,13 @@ public class FontRenderer implements IFontRenderer
|
||||
@Override
|
||||
public float getTextHeight(String text, int flags)
|
||||
{
|
||||
return getTextLengths(text, flags).length - 1 * height;
|
||||
return getTextLengths(text, flags).length - 1 * getFontHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCharValid(char letter)
|
||||
{
|
||||
return chars[0].containsKey(letter);
|
||||
return provider.isCharacterValid(letter);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package speiger.src.coreengine.rendering.gui.renderer;
|
||||
|
||||
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
|
||||
{
|
||||
@@ -62,6 +62,12 @@ public interface IFontRenderer
|
||||
float xAdvance;
|
||||
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)
|
||||
{
|
||||
this.character = character;
|
||||
|
||||
@@ -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.Tesselator;
|
||||
import speiger.src.coreengine.rendering.tesselation.VertexType;
|
||||
import speiger.src.coreengine.rendering.textures.ITexture;
|
||||
import speiger.src.coreengine.rendering.textures.TextureManager;
|
||||
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.utils.collections.pools.SimplePool;
|
||||
|
||||
|
||||
+141
@@ -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;
|
||||
}
|
||||
}
|
||||
+100
@@ -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();
|
||||
}
|
||||
}
|
||||
+72
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,56 @@
|
||||
package speiger.src.coreengine.rendering.models;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
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
|
||||
{
|
||||
static final Int2ObjectMap<GLDataType> ID_TO_TYPE = new Int2ObjectOpenHashMap<>();
|
||||
static final Map<String, GLDataType> NAME_TO_TYPE = new Object2ObjectOpenHashMap<>();
|
||||
//Normal Types
|
||||
public static final GLDataType BYTE = new GLDataType(GL11.GL_BYTE, 1);
|
||||
public static final GLDataType UNSIGNED_BYTE = new GLDataType(GL11.GL_UNSIGNED_BYTE, 1);
|
||||
public static final GLDataType SHORT = new GLDataType(GL11.GL_SHORT, 2);
|
||||
public static final GLDataType UNSIGNED_SHORT = new GLDataType(GL11.GL_UNSIGNED_SHORT, 2);
|
||||
public static final GLDataType INT = new GLDataType(GL11.GL_INT, 4);
|
||||
public static final GLDataType UNSIGNED_INT = new GLDataType(GL11.GL_UNSIGNED_INT, 4);
|
||||
public static final GLDataType FLOAT = new GLDataType(GL11.GL_FLOAT, 4);
|
||||
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, DataType.BYTE, "u_byte");
|
||||
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, DataType.SHORT, "u_short");
|
||||
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, DataType.INT, "u_int");
|
||||
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
|
||||
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_2_10_10_10_REV = new GLDataType(GL12.GL_UNSIGNED_INT_2_10_10_10_REV, 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, DataType.INT, true, "u_int_2_10_10_10_rev");
|
||||
|
||||
//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_5_9_9_9_REV = new GLDataType(GL30.GL_UNSIGNED_INT_5_9_9_9_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, DataType.INT, true, "u_int_5_9_9_9_rev");
|
||||
|
||||
final int glType;
|
||||
final int byteSize;
|
||||
final DataType dataType;
|
||||
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.byteSize = byteSize;
|
||||
this.dataType = dataType;
|
||||
this.ignoreAttributeSize = ignoreAttributeSize;
|
||||
this.name = name;
|
||||
ID_TO_TYPE.put(glType, this);
|
||||
NAME_TO_TYPE.put(name, this);
|
||||
}
|
||||
|
||||
public int getGLType()
|
||||
@@ -44,13 +58,28 @@ public class GLDataType
|
||||
return glType;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getByteSize()
|
||||
{
|
||||
return byteSize;
|
||||
return dataType.getByteSize();
|
||||
}
|
||||
|
||||
public boolean isSpecialType()
|
||||
{
|
||||
return ignoreAttributeSize;
|
||||
}
|
||||
|
||||
public DataType getDataType()
|
||||
{
|
||||
return dataType;
|
||||
}
|
||||
|
||||
public int calulateSize(int attributeSize)
|
||||
{
|
||||
return ignoreAttributeSize ? byteSize : attributeSize * byteSize;
|
||||
return ignoreAttributeSize ? dataType.getByteSize() : attributeSize * dataType.getByteSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.util.function.Consumer;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
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.utils.io.GameLog;
|
||||
|
||||
@@ -213,12 +213,12 @@ public class VertexBuffer
|
||||
return this;
|
||||
}
|
||||
|
||||
public VertexBuffer fillBuffer(List<Entry<byte[]>> data)
|
||||
public VertexBuffer fillBuffer(List<IntObjectPair<byte[]>> 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())
|
||||
{
|
||||
@@ -228,7 +228,7 @@ public class VertexBuffer
|
||||
ByteBuffer buffer = GL15.glMapBuffer(bufferType, GL15.GL_WRITE_ONLY);
|
||||
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.put(entry.getValue());
|
||||
totalData += entry.getValue().length;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
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
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package speiger.src.coreengine.rendering.shader.uniforms;
|
||||
|
||||
import speiger.src.coreengine.rendering.textures.ITexture;
|
||||
import speiger.src.coreengine.rendering.textures.TextureManager;
|
||||
import speiger.src.coreengine.rendering.textures.base.ITexture;
|
||||
import speiger.src.coreengine.rendering.textures.base.TextureManager;
|
||||
|
||||
public class UniformTexture extends UniformInt
|
||||
{
|
||||
|
||||
@@ -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);}
|
||||
}
|
||||
+5
-3
@@ -1,12 +1,14 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.base;
|
||||
|
||||
public abstract class AbstractTexture implements ITexture
|
||||
{
|
||||
int textureID;
|
||||
protected int textureID;
|
||||
|
||||
public AbstractTexture()
|
||||
@Override
|
||||
public ITexture makeReloadable()
|
||||
{
|
||||
TextureManager.INSTANCE.addTexture(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setTextureID(int textureID)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.base;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
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.reloader.IReloadableResource;
|
||||
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.states.GLState;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
+8
-2
@@ -1,4 +1,4 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.base;
|
||||
|
||||
public class WrappedTexture implements ITexture
|
||||
{
|
||||
@@ -8,7 +8,13 @@ public class WrappedTexture implements ITexture
|
||||
{
|
||||
this.textureId = textureId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ITexture makeReloadable()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
+5
-2
@@ -1,4 +1,4 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.custom;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
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.utils.ITrimmable;
|
||||
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;
|
||||
|
||||
public class DynamicTexture extends AbstractTexture
|
||||
@@ -132,8 +134,9 @@ public class DynamicTexture extends AbstractTexture
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
TextureManager.INSTANCE.removeTexture(getTextureID());
|
||||
int old = getTextureID();
|
||||
setTextureID(GL11.glGenTextures());
|
||||
TextureManager.INSTANCE.removeTexture(old);
|
||||
dirtyChunks.clear();
|
||||
first = true;
|
||||
updateData();
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -1,4 +1,4 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.normal;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -8,6 +8,9 @@ import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
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
|
||||
{
|
||||
BufferedImage image;
|
||||
@@ -93,7 +96,8 @@ public class DirectTexture extends AbstractTexture
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
TextureManager.INSTANCE.removeTexture(textureID);
|
||||
int old = textureID;
|
||||
loadTexture();
|
||||
TextureManager.INSTANCE.removeTexture(old);
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -1,4 +1,4 @@
|
||||
package speiger.src.coreengine.rendering.textures;
|
||||
package speiger.src.coreengine.rendering.textures.normal;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -10,6 +10,8 @@ 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 SimpleTexture extends AbstractTexture
|
||||
{
|
||||
@@ -66,8 +68,9 @@ public class SimpleTexture extends AbstractTexture
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
TextureManager.INSTANCE.removeTexture(textureID);
|
||||
int old = textureID;
|
||||
loadTexture();
|
||||
TextureManager.INSTANCE.removeTexture(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
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
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CollectionUtils
|
||||
List<T>[] list = new List[size];
|
||||
for(int i = 0;i<size;i++)
|
||||
{
|
||||
list[i] = new ObjectArrayList<T>();
|
||||
list[i] = new ObjectArrayList<>();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
+3
-4
@@ -6,10 +6,9 @@ import java.util.Set;
|
||||
|
||||
import speiger.src.collections.ints.collections.IntIterator;
|
||||
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.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.IntSet;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
@@ -166,7 +165,7 @@ public class DynamicDataManager<T>
|
||||
}
|
||||
return;
|
||||
}
|
||||
List<Entry<byte[]>> list = new ObjectArrayList<>();
|
||||
List<IntObjectPair<byte[]>> list = new ObjectArrayList<>();
|
||||
while(!changedSlots.isEmpty())
|
||||
{
|
||||
DataSlot start = null;
|
||||
@@ -196,7 +195,7 @@ public class DynamicDataManager<T>
|
||||
bytesAllocated += start.getUsedBytes();
|
||||
start = start.next;
|
||||
}
|
||||
list.add(new AbstractInt2ObjectMap.BasicEntry<>(byteOffset, data));
|
||||
list.add(IntObjectPair.of(byteOffset, data));
|
||||
}
|
||||
if(!list.isEmpty())
|
||||
{
|
||||
|
||||
+2
-2
@@ -2,10 +2,10 @@ package speiger.src.coreengine.utils.collections.managers.dynamic;
|
||||
|
||||
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 byte[] toBytes(T entry);
|
||||
public void uploadBytes(List<Entry<byte[]>> list, int newArraySize);
|
||||
public void uploadBytes(List<IntObjectPair<byte[]>> list, int newArraySize);
|
||||
}
|
||||
|
||||
+6
-7
@@ -10,10 +10,9 @@ import speiger.src.collections.ints.collections.IntIterator;
|
||||
import speiger.src.collections.ints.functions.IntComparator;
|
||||
import speiger.src.collections.ints.lists.IntArrayList;
|
||||
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.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.IntLinkedOpenHashSet;
|
||||
import speiger.src.collections.ints.sets.IntSet;
|
||||
@@ -284,7 +283,7 @@ public class FixedDataManager
|
||||
{
|
||||
ObjectArrays.quickSort(slots);
|
||||
List<FixedSlot> fixed = new ObjectArrayList<FixedSlot>();
|
||||
List<Entry<byte[]>> data = new ObjectArrayList<Entry<byte[]>>();
|
||||
List<IntObjectPair<byte[]>> data = new ObjectArrayList<>();
|
||||
FixedSlot first = null;
|
||||
FixedSlot last = null;
|
||||
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());
|
||||
handler.createData(buffer, fixed.size(), fixed);
|
||||
fixed.clear();
|
||||
data.add(new BasicEntry<byte[]>(first.index * bytes, buffer.array()));
|
||||
data.add(IntObjectPair.of(first.index * bytes, buffer.array()));
|
||||
i--;
|
||||
first = last = null;
|
||||
}
|
||||
@@ -313,7 +312,7 @@ public class FixedDataManager
|
||||
ByteBuffer buffer = ByteBuffer.allocate(fixed.size() * bytes).order(ByteOrder.nativeOrder());
|
||||
handler.createData(buffer, fixed.size(), fixed);
|
||||
fixed.clear();
|
||||
data.add(new BasicEntry<byte[]>(first.index * bytes, buffer.array()));
|
||||
data.add(IntObjectPair.of(first.index * bytes, buffer.array()));
|
||||
}
|
||||
SLOTS.accept(slots);
|
||||
return new FinishingTask(handler, data, size);
|
||||
@@ -339,10 +338,10 @@ public class FixedDataManager
|
||||
static class FinishingTask implements Runnable
|
||||
{
|
||||
IFixedDataHandler handler;
|
||||
List<Entry<byte[]>> data;
|
||||
List<IntObjectPair<byte[]>> data;
|
||||
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.data = data;
|
||||
|
||||
+2
-2
@@ -3,11 +3,11 @@ package speiger.src.coreengine.utils.collections.managers.fixed;
|
||||
import java.nio.ByteBuffer;
|
||||
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 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);
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
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)
|
||||
{
|
||||
JsonElement el = obj.get(name);
|
||||
@@ -103,6 +131,7 @@ public class JsonUtil
|
||||
return el == null ? defaultValue : el.getAsString();
|
||||
}
|
||||
|
||||
|
||||
public static JsonArray toArray(byte[] values)
|
||||
{
|
||||
JsonArray array = new JsonArray();
|
||||
@@ -113,7 +142,28 @@ public class JsonUtil
|
||||
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()];
|
||||
for(int i = 0,m=data.length;i<m;i++)
|
||||
@@ -122,4 +172,14 @@ public class JsonUtil
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user