Progress on more rewrites

This commit is contained in:
Speiger 2026-06-13 03:55:20 +02:00
parent 340d8ff463
commit 396d4f2232
144 changed files with 5657 additions and 4997 deletions

View File

@ -24,6 +24,18 @@
<attribute name="gradle_used_by_scope" value="graphics"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/math" path="src/math/java">
<attributes>
<attribute name="gradle_scope" value="math"/>
<attribute name="gradle_used_by_scope" value="main,graphics,math"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/assets" path="src/assets/java">
<attributes>
<attribute name="gradle_scope" value="assets"/>
<attribute name="gradle_used_by_scope" value="assets"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>

View File

@ -16,12 +16,31 @@ eclipse {
}
sourceSets {
graphics {}
math {
java {}
}
assets {
java {}
}
graphics {
java {}
}
main {
compileClasspath += sourceSets.math.output
runtimeClasspath += sourceSets.math.output
}
graphics {
compileClasspath += sourceSets.math.output
runtimeClasspath += sourceSets.math.output
java {}
}
}
configurations {
graphics.extendsFrom implementation
graphics.extendsFrom runtime
graphics.extendsFrom mathRuntime
implementation.extendsFrom mathRuntime
}
repositories {
@ -64,6 +83,7 @@ dependencies {
//Primitive Collections
implementation 'de.speiger:Primitive-Collections:1.0.0'
mathImplementation 'de.speiger:Primitive-Collections:1.0.0'
}
jar {

View File

@ -0,0 +1,14 @@
package speiger.src.coreengine.assets.api;
import java.io.IOException;
import java.io.InputStream;
public interface IAsset {
public IAssetPackage owner();
public ID location();
public String hash();
public InputStream stream() throws IOException;
public <T> T parse(IAssetParser<T> parser) throws IOException;
}

View File

@ -0,0 +1,5 @@
package speiger.src.coreengine.assets.api;
public interface IAssetPackage {
}

View File

@ -0,0 +1,8 @@
package speiger.src.coreengine.assets.api;
import java.io.IOException;
import java.nio.file.Path;
public interface IAssetParser<T> {
public T parse(Path path) throws IOException;
}

View File

@ -0,0 +1,6 @@
package speiger.src.coreengine.assets.api;
public interface IAssetProvider {
public IAsset get(ID id);
public String hash(ID id);
}

View File

@ -0,0 +1,79 @@
package speiger.src.coreengine.assets.api;
import java.util.Objects;
public record ID(String domain, String path) implements Comparable<ID> {
public ID {
Objects.requireNonNull(domain);
Objects.requireNonNull(path);
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
}
public ID prefix(String prefix) { return of(domain, prefix+"/"+path); }
public ID suffix(String suffix) { return of(domain, path+"/"+suffix); }
public ID alternate(String alterversion) { return of(domain, path+"."+alterversion); }
public String fileLocation() { return "assets/"+domain+"/"+path; }
public boolean isRoot() { return !path.contains("/"); }
public boolean isRootFolder(String folder) { return path.indexOf('/', folder.length()+1) < 0; }
public boolean endsWith(String suffix) { return path.endsWith(suffix); }
@Override
public final String toString() {
return domain+":"+path;
}
@Override
public int compareTo(ID o) {
int result = domain.compareToIgnoreCase(o.domain);
return result != 0 ? result : path.compareToIgnoreCase(path);
}
public boolean matches(ID id) {
return id.domain.equals(domain) && id.path.equals(path);
}
public static ID of(String domain, String path) {
return new ID((domain == null || domain.isBlank() ? "base" : domain), path);
}
public static ID of(String location) {
Objects.requireNonNull(location);
int index = location.indexOf(":");
String domain = location.substring(0, index);
String path = location.substring(index + 1);
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
return new ID(domain, path);
}
public static final ID tryOf(String location) {
try { return of(location); }
catch(Exception e) {}
return null;
}
private static boolean isValidDomain(String s) {
for(int i = 0,m=s.length();i<m;i++) {
if(!isValidDomainChar(s.charAt(i))) return false;
}
return true;
}
private static boolean isValidPath(String s) {
for(int i = 0,m=s.length();i<m;i++) {
if(!isValidPathChar(s.charAt(i))) return false;
}
return true;
}
private static boolean isValidPathChar(char c) {
return c == '/' || isValidDomainChar(c);
}
private static boolean isValidDomainChar(char c) {
return c == '_' || c == '-' || c == '.' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
}
}

View File

@ -0,0 +1,54 @@
package speiger.src.coreengine.assets.api;
import java.io.IOException;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
import speiger.src.collections.objects.collections.ObjectIterable;
import speiger.src.collections.objects.collections.ObjectIterator;
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public record MultiAsset(ObjectList<IAsset> assets) implements ObjectIterable<IAsset> {
public MultiAsset(ObjectList<IAsset> assets) {
this.assets = Objects.requireNonNull(assets).unmodifiable();
}
public MultiAsset(IAsset... assets) {
this(ObjectArrayList.wrap(assets));
}
public int size() { return assets.size(); }
public IAsset get(int index) { return assets.get(index); }
@Override
public ObjectIterator<IAsset> iterator() { return assets.iterator(); }
public <T> ObjectIterable<T> map(IAssetParser<T> mapper, Supplier<T> defaultValue) {
return assets.map(E -> {
try { return E.parse(mapper); }
catch(IOException e) {
e.printStackTrace();
return defaultValue.get();
}
});
}
@Override
public void forEach(Consumer<? super IAsset> action) {
assets.forEach(action);
}
@Override
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
assets.forEach(input, action);
}
@Override
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
assets.forEachIndexed(action);
}
}

View File

@ -0,0 +1,7 @@
package speiger.src.coreengine.graphics.api.buffer.states;
public enum IndeciesType {
BYTE,
SHORT,
INT;
}

View File

@ -1,5 +1,7 @@
package speiger.src.coreengine.graphics.api.core;
import speiger.src.coreengine.graphics.api.shader.RenderPass;
import speiger.src.coreengine.graphics.api.target.RenderTarget;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.utils.PushableResource;
import speiger.src.coreengine.math.vector.floats.Vec4f;
@ -7,11 +9,26 @@ import speiger.src.coreengine.math.vector.floats.Vec4f;
public interface GraphicsCommandQueue {
public static final int CLEAR_COLOR = 1;
public static final int CLEAR_DEPTH = 2;
public PushableResource pushClearColor(Vec4f color);
public PushableResource pushClearDepth(double value);
public PushableResource putClearColor(Vec4f color);
public PushableResource putClearDepth(double value);
public PushableResource putRenderTarget(RenderTarget target);
public void clearTexture(int clearParam);
public void clearTexture(int x, int y, int width, int height, int clearParam);
public void clearTexture(Texture texture, int clearParam);
public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam);
public void writeToTexture(Texture target, int x, int y, int width, int height, long source);
public void readFromTexture(Texture source, int x, int y, int width, int height, long target);
public RenderPass createRenderPass(RenderTarget target, DrawArea area);
public record DrawArea(int x, int y, int width, int height) {
public boolean fits(int x, int y, int width, int height) {
return x >= x() && y >= y() && x + width < width() && y + height < height();
}
public boolean fills(int width, int height) {
return x == 0 && y == 0 && width == width() && height == height();
}
}
}

View File

@ -7,8 +7,10 @@ import speiger.src.coreengine.graphics.api.sampler.Sampler;
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
import speiger.src.coreengine.rendering.input.window.Window;
public interface GraphicsDevice {
public Window getWindow();
public GraphicsSurface createSurface();
public GraphicsCommandQueue getQueue();
public VertexBuffer createBuffer(BufferType type, BufferState state);

View File

@ -0,0 +1,5 @@
package speiger.src.coreengine.graphics.api.shader;
public interface CompiledPipeline {
}

View File

@ -0,0 +1,51 @@
package speiger.src.coreengine.graphics.api.shader;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue.DrawArea;
import speiger.src.coreengine.graphics.api.sampler.Sampler;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.utils.ScissorsManager;
public abstract class RenderPass implements AutoCloseable {
protected final DrawArea area;
protected final boolean hasColor;
protected final boolean hasDepth;
protected final ScissorsManager scissors = new ScissorsManager(16);
public RenderPass(DrawArea area, boolean hasColor, boolean hasDepth) {
this.area = area;
this.hasColor = hasColor;
this.hasDepth = hasDepth;
}
public void pushScissors(int x, int y, int width, int height) {
if(area != null && area.fits(x, y, width, height)) {
//TODO implement logging
return;
}
scissors.push(x, y, width, height);
}
public void popScissors() {
scissors.pop();
}
public abstract void setShader(ShaderPipeline pipeline);
public abstract void setTexture(String name, Texture texture, Sampler sampler);
public abstract void clearTextures();
public abstract void removeTexture(String name);
public abstract void setUniform(String name, VertexBuffer buffer);
public abstract void setIndecies(VertexBuffer buffer, IndeciesType type);
public abstract void clearIndecies();
public abstract void setVertexBuffer(int index, VertexBuffer buffer);
public DrawArea area() { return area; }
public boolean hasDepth() { return hasDepth; }
public boolean hasColor() { return hasColor; }
@Override
public abstract void close();
}

View File

@ -0,0 +1,4 @@
package speiger.src.coreengine.graphics.api.target;
public sealed interface RenderTarget permits ScreenTarget, TextureTarget {
}

View File

@ -0,0 +1,6 @@
package speiger.src.coreengine.graphics.api.target;
public final class ScreenTarget implements RenderTarget {
public static final ScreenTarget INSTANCE = new ScreenTarget();
private ScreenTarget() {}
}

View File

@ -0,0 +1,17 @@
package speiger.src.coreengine.graphics.api.target;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
public record TextureTarget(AssetLocation id, Texture color, Texture depth) implements RenderTarget {
public TextureTarget {
if(color == null && depth == null) throw new IllegalArgumentException("At least either texture has to be nonNull");
if(color != null && depth != null) {
if(color.width() != depth.width()) throw new IllegalArgumentException("Width is not matching");
if(color.height() != depth.height()) throw new IllegalArgumentException("Height is not matching");
}
if(color != null && color.settings().type() != TextureType.TEXTURE_2D) throw new IllegalArgumentException("Color Texture has to be 2D");
if(depth != null && depth.settings().type() != TextureType.TEXTURE_2D) throw new IllegalArgumentException("Depth Texture has to be 2D");
}
}

View File

@ -6,7 +6,7 @@ public abstract class Texture implements GraphicsResource {
final TextureSettings settings;
int width;
int height;
public Texture(TextureSettings settings, int width, int height) {
this.settings = settings;
this.width = width;

View File

@ -0,0 +1,52 @@
package speiger.src.coreengine.graphics.api.utils;
import org.lwjgl.opengl.GL11;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.utils.Stack;
import speiger.src.coreengine.math.vector.ints.Vec4i;
public class ScissorsManager {
Stack<Vec4i> stack = new ObjectArrayList<>();
int limit;
public ScissorsManager(int limit) {
if(limit <= 0) throw new IllegalStateException("Limit is negative");
this.limit = limit;
}
public void push(int x, int y, int width, int height) {
if(stack.size() >= limit) {
//TODO implement logging
return;
}
if(stack.isEmpty()) {
stack.push(Vec4i.of(x, y, x + width, y + height));
GL11.glEnable(GL11.GL_SCISSOR_TEST);
GL11.glScissor(x, y, width, height);
return;
}
Vec4i top = stack.top();
stack.push(Vec4i.of(Math.max(x, top.x()), Math.max(y, top.y()), Math.min(x + width, top.z()), Math.min(y + height, top.w())));
}
public boolean contains(int x, int y, int width, int height) {
return stack.isEmpty() || contains(stack.top(), x, y, width, height);
}
protected boolean contains(Vec4i top, int x, int y, int width, int height) {
return x >= top.x() && y >= top.y() && x + width < top.z() && y + height < top.w();
}
public void pop() {
if(stack.isEmpty()) {
//TODO implement logging
return;
}
stack.pop();
}
public void clear() {
stack.clear();
}
}

View File

@ -0,0 +1,167 @@
package speiger.src.coreengine.graphics.opengl.core;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL45;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue;
import speiger.src.coreengine.graphics.api.shader.RenderPass;
import speiger.src.coreengine.graphics.api.target.RenderTarget;
import speiger.src.coreengine.graphics.api.target.ScreenTarget;
import speiger.src.coreengine.graphics.api.target.TextureTarget;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.api.utils.PushableResource;
import speiger.src.coreengine.graphics.opengl.shader.GLRenderPass;
import speiger.src.coreengine.graphics.opengl.texture.FrameBufferCache;
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
import speiger.src.coreengine.math.vector.floats.Vec4f;
import speiger.src.coreengine.rendering.input.window.Window;
public class GLCommandQueue implements GraphicsCommandQueue {
private static final int HAS_COLOR = 1;
private static final int HAS_DEPTH = 2;
private static final int HAS_BOTH = 3;
GLGraphicsDevice device;
FrameBufferCache fboCache = new FrameBufferCache();
GLRenderPass activePass;
RenderTarget renderTarget = ScreenTarget.INSTANCE;
Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F);
double clearDepth = 0D;
public GLCommandQueue(GLGraphicsDevice device) {
this.device = device;
}
@Override
public PushableResource putClearColor(Vec4f color) {
return new PushableObject<>(clearColor.copyAsImmutable(), setClearColor(color), () -> clearColor, this::setClearColor);
}
@Override
public PushableResource putClearDepth(double value) {
return new PushableObject<>(clearDepth, setClearDepth(value), () -> clearDepth, this::setClearDepth);
}
@Override
public PushableResource putRenderTarget(RenderTarget target) {
return new PushableObject<>(renderTarget, setRenderTarget(target), () -> renderTarget, this::setRenderTarget);
}
private Vec4f setClearColor(Vec4f value) {
if(clearColor.equals(value)) return value;
clearColor.set(value);
GL11.glClearColor(value.x(), value.y(), value.y(), value.w());
return value;
}
private double setClearDepth(double value) {
if(Double.compare(clearDepth, value) == 0) return value;
clearDepth = value;
GL11.glClearDepth(value);
return value;
}
private RenderTarget setRenderTarget(RenderTarget target) {
if(this.renderTarget.equals(target)) return target;
this.renderTarget = target;
switch(target) {
case ScreenTarget _ -> {
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, 0);
Window window = device.getWindow();
GL11.glViewport(0, 0, window.width(), window.height());
break;
}
case TextureTarget(AssetLocation id, Texture color, Texture depth) -> {
int fbo = fboCache.getOrCreateFBO(id);
if(color != null) GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
if(depth != null) GL45.glNamedFramebufferTexture(fbo, GL30.GL_DEPTH_ATTACHMENT, ((GLTexture)depth).id(), 0);
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, fbo);
if(color != null) GL11.glViewport(0, 0, color.width(), color.height());
else if(depth != null) GL11.glViewport(0, 0, depth.width(), depth.height());
break;
}
}
return target;
}
@Override
public void clearTexture(int clearParam) {
}
@Override
public void clearTexture(int x, int y, int width, int height, int clearParam) {
}
@Override
public void clearTexture(Texture texture, int clearParam) {
}
@Override
public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam) {
}
@Override
public void writeToTexture(Texture target, int x, int y, int width, int height, long source) {
}
@Override
public void readFromTexture(Texture source, int x, int y, int width, int height, long target) {
}
@Override
public RenderPass createRenderPass(RenderTarget target, DrawArea area) {
int width = 0;
int height = 0;
int hasState = 0;
int frameBuffer = switch(target) {
case ScreenTarget _ -> {
Window window = device.getWindow();
width = window.width();
height = window.height();
hasState = HAS_BOTH;
yield 0;
}
case TextureTarget(AssetLocation id, Texture color, Texture depth) -> {
int fbo = fboCache.getOrCreateFBO(id);
if(color != null) {
hasState |= HAS_COLOR;
GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
}
if(depth != null) {
hasState |= HAS_DEPTH;
GL45.glNamedFramebufferTexture(fbo, GL30.GL_DEPTH_ATTACHMENT, ((GLTexture)depth).id(), 0);
}
if(color != null) {
width = color.width();
height = color.height();
}
else if(depth != null) {
width = depth.width();
height = depth.height();
}
yield fbo;
}
};
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, frameBuffer);
GL11.glViewport(0, 0, width, height);
boolean scissors = area != null && !area.fills(width, height);
if(scissors) {
GL11.glEnable(GL11.GL_SCISSOR_TEST);
GL11.glScissor(area.x(), area.y(), area.width(), area.height());
}
return (activePass = new GLRenderPass(this, area, scissors, (hasState & HAS_COLOR) != 0, (hasState & HAS_DEPTH) != 0, frameBuffer));
}
private record PushableObject<T>(T original, T applying, Supplier<T> current, Consumer<T> apply) implements PushableResource {
@Override
public void close() {
if(current.get().equals(applying)) {
apply.accept(original);
}
}
}
}

View File

@ -9,36 +9,44 @@ import org.lwjgl.opengl.GL33;
import org.lwjgl.opengl.GL43;
import org.lwjgl.opengl.GL45;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue;
import speiger.src.coreengine.graphics.api.core.GraphicsDevice;
import speiger.src.coreengine.graphics.api.core.GraphicsSurface;
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
import speiger.src.coreengine.graphics.opengl.sampler.GLSampler;
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance;
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
import speiger.src.coreengine.graphics.opengl.utils.GLFunctions;
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
import speiger.src.coreengine.rendering.input.window.Window;
public class GLGraphicsDevice implements GraphicsDevice {
GLCommandQueue queue;
Window owner;
public GLGraphicsDevice(Window owner) {
this.owner = owner;
this.queue = new GLCommandQueue(this);
}
@Override
public GraphicsSurface createSurface() {
public Window getWindow() {
return owner;
}
@Override
public GLSurface createSurface() {
return new GLSurface(owner);
}
@Override
public GraphicsCommandQueue getQueue() {
return null;
public GLCommandQueue getQueue() {
return queue;
}
@Override
@ -76,4 +84,10 @@ public class GLGraphicsDevice implements GraphicsDevice {
public GLSampler createSampler(SamplerSettings settings) {
return new GLSampler(Objects.requireNonNull(settings));
}
public ShaderInstance createShader(ShaderPipeline line, IAssetProvider provider) {
return null;
}
}

View File

@ -0,0 +1,100 @@
package speiger.src.coreengine.graphics.opengl.shader;
import java.util.Map;
import java.util.Objects;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL45;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue.DrawArea;
import speiger.src.coreengine.graphics.api.sampler.Sampler;
import speiger.src.coreengine.graphics.api.shader.CompiledPipeline;
import speiger.src.coreengine.graphics.api.shader.RenderPass;
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
import speiger.src.coreengine.graphics.api.texture.Texture;
import speiger.src.coreengine.graphics.opengl.core.GLCommandQueue;
public class GLRenderPass extends RenderPass {
boolean scissors;
GLCommandQueue queue;
int fbo;
VertexBuffer[] buffers = new VertexBuffer[4];
Map<String, ObjectObjectPair<Texture, Sampler>> textures = Object2ObjectMap.builder().linkedMap();
Map<String, VertexBuffer> uniforms = Object2ObjectMap.builder().linkedMap();
VertexBuffer indecies;
IndeciesType indeciesType;
ShaderPipeline pipeline;
CompiledPipeline compiled;
public GLRenderPass(GLCommandQueue queue, DrawArea area, boolean scissors, boolean hasColor, boolean hasDepth, int fbo) {
super(area, hasColor, hasDepth);
this.scissors = scissors;
this.queue = queue;
this.fbo = fbo;
}
@Override
public void setShader(ShaderPipeline pipeline) {
this.pipeline = Objects.requireNonNull(pipeline);
}
@Override
public void setTexture(String name, Texture texture, Sampler sampler) {
Objects.requireNonNull(name, "Sampler Name is needed");
Objects.requireNonNull(texture, "Texture is required");
Objects.requireNonNull(sampler, "Sampler is required");
textures.put(name, ObjectObjectPair.of(texture, sampler));
}
@Override
public void clearTextures() {
textures.clear();
}
@Override
public void removeTexture(String name) {
Objects.requireNonNull(name, "Sampler Name is needed");
textures.remove(name);
}
@Override
public void setUniform(String name, VertexBuffer buffer) {
Objects.requireNonNull(name, "Uniform name is needed");
Objects.requireNonNull(buffer, "Vertex Buffer is required");
uniforms.put(name, buffer);
}
@Override
public void setIndecies(VertexBuffer buffer, IndeciesType type) {
indecies = Objects.requireNonNull(buffer, "Buffer is required");
indeciesType = Objects.requireNonNull(type, "Type is required");
}
@Override
public void clearIndecies() {
indecies = null;
indeciesType = null;
}
@Override
public void setVertexBuffer(int index, VertexBuffer buffer) {
if(index < 0 || index >= 4) throw new ArrayIndexOutOfBoundsException(index);
buffers[index] = buffer;
}
public void applyState() {
}
@Override
public void close() {
if(fbo == -1) return;
if(scissors) GL11.glDisable(GL11.GL_SCISSOR_TEST);
if(fbo != 0) GL45.glBindFramebuffer(GL45.GL_DRAW_FRAMEBUFFER, 0);
fbo = -1;
}
}

View File

@ -0,0 +1,101 @@
package speiger.src.coreengine.graphics.opengl.shader;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonWriter;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.coreengine.assets.AssetLocation;
public class ShaderCache {
public static final ShaderCache INSTANCE = new ShaderCache();
Map<AssetLocation, String> hashCache;
Path cache;
public void init(Path cache) {
this.cache = cache;
if(Files.notExists(cache)) {
try { Files.createDirectories(cache); }
catch(IOException e) {
e.printStackTrace();
this.cache = null;
}
}
try(BufferedReader reader = Files.newBufferedReader(cache.resolve("cache.json"))) {
Map<AssetLocation, String> knownCache = new Object2ObjectOpenHashMap<>();
for(JsonElement element : JsonParser.parseReader(reader).getAsJsonObject().getAsJsonArray("shaders")) {
JsonObject shader = element.getAsJsonObject();
knownCache.put(AssetLocation.of(shader.get("id").getAsString()), shader.get("hash").getAsString());
}
hashCache = knownCache;
}
catch(Exception e) {
e.printStackTrace();
hashCache = new Object2ObjectOpenHashMap<>();
}
}
private void save() {
JsonArray array = new JsonArray();
hashCache.forEach((K, V) -> {
JsonObject obj = new JsonObject();
obj.addProperty("id", K.toString());
obj.addProperty("hash", V);
array.add(obj);
});
try(JsonWriter writer = new JsonWriter(Files.newBufferedWriter(cache.resolve("cache.json")))) {
JsonObject obj = new JsonObject();
obj.add("shaders", array);
writer.setIndent("\t");
Streams.write(obj, writer);
}
catch(Exception e) { e.printStackTrace(); }
}
public byte[] get(AssetLocation shaderLocation, String fileHash) {
String known = hashCache.get(shaderLocation);
if(!Objects.equals(known, fileHash)) return null;
Path path = toFile(shaderLocation);
if(Files.notExists(path)) return null;
try { return Files.readAllBytes(path); }
catch(Exception e) { e.printStackTrace(); }
return null;
}
public void store(AssetLocation shaderLocation, String fileHash, byte[] shader) {
Objects.requireNonNull(shaderLocation);
Objects.requireNonNull(fileHash);
Objects.requireNonNull(shader);
hashCache.put(shaderLocation, fileHash);
try {
Path file = toFile(shaderLocation);
if(Files.notExists(file.getParent())) Files.createDirectories(file.getParent());
Files.write(file, shader);
}
catch(Exception e) {
e.printStackTrace();
}
save();
}
public void delete(AssetLocation shaderLocation) {
if(hashCache.remove(shaderLocation) == null) return;
try { Files.deleteIfExists(toFile(shaderLocation)); }
catch(Exception e) { e.printStackTrace(); }
save();
}
private Path toFile(AssetLocation id) {
return cache.resolve(id.domain()).resolve(id.location()+".bin");
}
}

View File

@ -0,0 +1,9 @@
package speiger.src.coreengine.graphics.opengl.shader;
import java.util.Map;
public record ShaderInstance(int programId, Map<String, UniformObject> uniforms, Map<String, SamplerObject> samplers) {
public record UniformObject(int slot) {}
public record SamplerObject(int unit) {}
}

View File

@ -0,0 +1,26 @@
package speiger.src.coreengine.graphics.opengl.texture;
import org.lwjgl.opengl.GL45;
import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2IntMap;
import speiger.src.coreengine.assets.AssetLocation;
public class FrameBufferCache {
Object2IntMap<AssetLocation> fboCache = new Object2IntOpenHashMap<>();
public int getOrCreateFBO(AssetLocation id) {
return fboCache.supplyIntIfAbsent(id, GL45::glCreateFramebuffers);
}
public void deleteFBO(AssetLocation id) {
int fbo = fboCache.rem(id);
if(fbo == -1) return;
GL45.glDeleteFramebuffers(fbo);
}
public void clear() {
GL45.glDeleteFramebuffers(fboCache.values().toIntArray());
fboCache.clear();
}
}

View File

@ -12,6 +12,10 @@ public class GLTexture extends Texture {
this.id = id;
}
public int id() {
return id;
}
@Override
public boolean isRemoved() {
return id == 0;

View File

@ -10,7 +10,6 @@ import org.lwjgl.opengl.GL43;
import org.lwjgl.system.Configuration;
import org.lwjgl.util.freetype.FreeType;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
@ -19,7 +18,6 @@ import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.math.vector.matrix.Matrix4f;
import speiger.src.coreengine.rendering.gui.font.Font;
import speiger.src.coreengine.rendering.gui.font.FontManager;
import speiger.src.coreengine.rendering.gui.font.TextStyle;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.glyth.MissingGlyth;
@ -157,11 +155,11 @@ public class NewInputTest {
// });
// String s = "The Quick brown fox Jumps over the Lazy dog";
float x = 50;
float y = 50;
float scale = 1F;
y /= scale;
TextStyle style = TextStyle.DEFAULT.size(12).bold(false);
// float x = 50;
// float y = 50;
// float scale = 1F;
// y /= scale;
// TextStyle style = TextStyle.DEFAULT.size(12).bold(false);
// font.drawText(style, "Testing My Theory", x, y, -1, buffer, scale, true);
// float offset = font.drawText(style, "The Quick ", 50, y, -1, buffer, scale, false);
// offset += font.drawText(style, "Brown ", 50+offset, y, -1, buffer, scale, false);
@ -169,7 +167,7 @@ public class NewInputTest {
// offset += font.drawText(style, "Jumps ", 50+offset, y, -1, buffer, scale, false);
// offset += font.drawText(style, "over the Lazy dog", 50+offset, y, -1, buffer, scale, true);
// font.drawText(s, 50, 50, -1, buffer, true);
GLStateTracker tracker = GLStateTracker.instance();
// GLStateTracker tracker = GLStateTracker.instance();
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
while(!window.shouldClose()) {
GLFW.glfwPollEvents();
@ -215,7 +213,7 @@ public class NewInputTest {
GL11.glClearColor(0.4F, 0.55F, 0.36F, 1F);
int size = 512;
int half = size >> 1;
int base = size >> 3;
// int base = size >> 3;
DynamicTexture texture = new DynamicTexture(size, size, DynamicTexture.DEFAULT_PARAMETERS);
texture.fill(0, 0, size, size, -1);

View File

@ -1,39 +1,39 @@
package speiger.src.coreengine.assets;
import java.util.Map;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
public record AssetFilter(String prefix, String extension) {
public static AssetFilter json(String prefix) {
return new AssetFilter(prefix, ".json");
}
public AssetLocation id(AssetLocation file) {
String location = file.location();
return AssetLocation.of(file.domain(), location.substring(prefix().length()+1, location.length()-extension().length()));
}
public AssetLocation file(AssetLocation id) {
return AssetLocation.of(id.domain(), prefix()+"/"+id.location()+extension());
}
public Map<AssetLocation, IAsset> list(IAssetProvider provider) {
return provider.listAssets(prefix, T -> T.endsWith(extension));
}
public Map<AssetLocation, IAsset> listRoot(IAssetProvider provider) {
return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
}
public Map<AssetLocation, MultiAsset> multi(IAssetProvider provider) {
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
}
public Map<AssetLocation, MultiAsset> multiRoot(IAssetProvider provider) {
return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
}
}
package speiger.src.coreengine.assets;
import java.util.Map;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
public record AssetFilter(String prefix, String extension) {
public static AssetFilter json(String prefix) {
return new AssetFilter(prefix, ".json");
}
public AssetLocation id(AssetLocation file) {
String location = file.location();
return AssetLocation.of(file.domain(), location.substring(prefix().length()+1, location.length()-extension().length()));
}
public AssetLocation file(AssetLocation id) {
return AssetLocation.of(id.domain(), prefix()+"/"+id.location()+extension());
}
public Map<AssetLocation, IAsset> list(IAssetProvider provider) {
return provider.listAssets(prefix, T -> T.endsWith(extension));
}
public Map<AssetLocation, IAsset> listRoot(IAssetProvider provider) {
return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
}
public Map<AssetLocation, MultiAsset> multi(IAssetProvider provider) {
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
}
public Map<AssetLocation, MultiAsset> multiRoot(IAssetProvider provider) {
return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
}
}

View File

@ -1,103 +1,103 @@
package speiger.src.coreengine.assets;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Predicate;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
import speiger.src.coreengine.assets.base.IManagedAsset;
import speiger.src.coreengine.assets.base.IReloadableAsset;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.base.PackReloadingTask;
import speiger.src.coreengine.assets.impl.LayeredAssetProvider;
public class AssetManager implements ICloseableAssetProvider
{
ObjectList<IReloadableAsset> listeners = new ObjectArrayList<>();
LayeredAssetProvider provider;
public AssetManager(List<IAssetPackage> packages) {
provider = new LayeredAssetProvider(packages);
}
public void addListener(IReloadableAsset listener) {
listeners.add(listener);
if(listener instanceof IManagedAsset managed) {
managed.setProvider(this);
}
}
public ObjectList<IReloadableAsset> listeners() {
return ObjectLists.unmodifiable(listeners);
}
public AssetManager reload(Executor offthread, Executor syncer, List<IAssetPackage> packages) {
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
}
public AssetManager reload() {
return reload(Runnable::run, Runnable::run);
}
public AssetManager reload(Executor offthread, Executor syncer) {
return reloadSelective(offthread, syncer, listeners);
}
public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
return reloadSelective(Runnable::run, Runnable::run, listeners);
}
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
return this;
}
public AssetManager reloadAssets(List<IAssetPackage> packages) {
provider.close();
provider = new LayeredAssetProvider(packages);
return this;
}
@Override
public void close() {
provider.close();
listeners.forEach(IReloadableAsset::destroy);
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
return provider.getModifiedTime(location);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
return provider.getLatestTime(locations);
}
@Override
public IAsset getAsset(AssetLocation location) {
return provider.getAsset(location);
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
return provider.getAllAssets(location);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
return provider.listAssets(folder, filter);
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
return provider.listAllAssets(folder, filter);
}
}
package speiger.src.coreengine.assets;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Predicate;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
import speiger.src.coreengine.assets.base.IManagedAsset;
import speiger.src.coreengine.assets.base.IReloadableAsset;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.base.PackReloadingTask;
import speiger.src.coreengine.assets.impl.LayeredAssetProvider;
public class AssetManager implements ICloseableAssetProvider
{
ObjectList<IReloadableAsset> listeners = new ObjectArrayList<>();
LayeredAssetProvider provider;
public AssetManager(List<IAssetPackage> packages) {
provider = new LayeredAssetProvider(packages);
}
public void addListener(IReloadableAsset listener) {
listeners.add(listener);
if(listener instanceof IManagedAsset managed) {
managed.setProvider(this);
}
}
public ObjectList<IReloadableAsset> listeners() {
return ObjectLists.unmodifiable(listeners);
}
public AssetManager reload(Executor offthread, Executor syncer, List<IAssetPackage> packages) {
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
}
public AssetManager reload() {
return reload(Runnable::run, Runnable::run);
}
public AssetManager reload(Executor offthread, Executor syncer) {
return reloadSelective(offthread, syncer, listeners);
}
public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
return reloadSelective(Runnable::run, Runnable::run, listeners);
}
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
return this;
}
public AssetManager reloadAssets(List<IAssetPackage> packages) {
provider.close();
provider = new LayeredAssetProvider(packages);
return this;
}
@Override
public void close() {
provider.close();
listeners.forEach(IReloadableAsset::destroy);
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
return provider.getModifiedTime(location);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
return provider.getLatestTime(locations);
}
@Override
public IAsset getAsset(AssetLocation location) {
return provider.getAsset(location);
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
return provider.getAllAssets(location);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
return provider.listAssets(folder, filter);
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
return provider.listAllAssets(folder, filter);
}
}

View File

@ -1,29 +1,29 @@
package speiger.src.coreengine.assets.base;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
import com.google.gson.JsonObject;
import speiger.src.coreengine.assets.AssetLocation;
public interface IAsset extends Closeable
{
public IAssetPackage owner();
public AssetLocation location();
@Override
public void close();
public IAsset subAsset(String alternative);
public InputStream stream() throws IOException;
public ByteBuffer bytes() throws IOException;
public BufferedReader reader() throws IOException;
public List<String> lines() throws IOException;
public JsonObject json() throws IOException;
public BufferedImage texture() throws Exception;
public <T> T custom(IAssetParser<T> parser) throws IOException;
}
package speiger.src.coreengine.assets.base;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
import com.google.gson.JsonObject;
import speiger.src.coreengine.assets.AssetLocation;
public interface IAsset extends Closeable
{
public IAssetPackage owner();
public AssetLocation location();
@Override
public void close();
public IAsset subAsset(String alternative);
public InputStream stream() throws IOException;
public ByteBuffer bytes() throws IOException;
public BufferedReader reader() throws IOException;
public List<String> lines() throws IOException;
public JsonObject json() throws IOException;
public BufferedImage texture() throws Exception;
public <T> T custom(IAssetParser<T> parser) throws IOException;
}

View File

@ -1,31 +1,31 @@
package speiger.src.coreengine.assets.base;
import java.io.Closeable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.impl.FolderAssetPackage;
import speiger.src.coreengine.assets.impl.ZipAssetPackage;
import speiger.src.coreengine.utils.helpers.IOUtils;
public interface IAssetPackage extends Closeable
{
@Override
public void close();
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept);
public List<String> getDomains();
public IAsset getAsset(AssetLocation location);
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> accept);
public static IAssetPackage of(Path path) {
if(Files.exists(path)) {
if(Files.isDirectory(path)) return new FolderAssetPackage(path);
if(IOUtils.isZip(path)) return new ZipAssetPackage(path);
}
return null;
}
}
package speiger.src.coreengine.assets.base;
import java.io.Closeable;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.impl.FolderAssetPackage;
import speiger.src.coreengine.assets.impl.ZipAssetPackage;
import speiger.src.coreengine.utils.helpers.IOUtils;
public interface IAssetPackage extends Closeable
{
@Override
public void close();
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept);
public List<String> getDomains();
public IAsset getAsset(AssetLocation location);
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> accept);
public static IAssetPackage of(Path path) {
if(Files.exists(path)) {
if(Files.isDirectory(path)) return new FolderAssetPackage(path);
if(IOUtils.isZip(path)) return new ZipAssetPackage(path);
}
return null;
}
}

View File

@ -1,22 +1,22 @@
package speiger.src.coreengine.assets.base;
import java.nio.file.attribute.FileTime;
import java.util.Map;
import java.util.function.Predicate;
import speiger.src.coreengine.assets.AssetLocation;
public interface IAssetProvider {
public IAsset getAsset(AssetLocation location);
public MultiAsset getAllAssets(AssetLocation location);
public FileTime getModifiedTime(AssetLocation location);
public FileTime getLatestTime(AssetLocation...locations);
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter);
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter);
public static interface ICloseableAssetProvider extends IAssetProvider, AutoCloseable {
@Override
public void close();
}
}
package speiger.src.coreengine.assets.base;
import java.nio.file.attribute.FileTime;
import java.util.Map;
import java.util.function.Predicate;
import speiger.src.coreengine.assets.AssetLocation;
public interface IAssetProvider {
public IAsset getAsset(AssetLocation location);
public MultiAsset getAllAssets(AssetLocation location);
public FileTime getModifiedTime(AssetLocation location);
public FileTime getLatestTime(AssetLocation...locations);
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter);
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter);
public static interface ICloseableAssetProvider extends IAssetProvider, AutoCloseable {
@Override
public void close();
}
}

View File

@ -1,85 +1,85 @@
package speiger.src.coreengine.assets.base;
import java.io.Closeable;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.Supplier;
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
import speiger.src.collections.objects.collections.ObjectIterable;
import speiger.src.collections.objects.collections.ObjectIterator;
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
ObjectList<IAsset> assets;
public MultiAsset(IAsset...assets) {
this(ObjectArrayList.wrap(assets));
}
public MultiAsset(ObjectList<IAsset> assets) {
this.assets = assets.unmodifiable();
}
@Override
public void close() {
if(assets != null) {
assets.forEach(IAsset::close);
assets = null;
}
}
public int size() {
return assets.size();
}
public IAsset get(int index) {
return assets.get(index);
}
public <T> Iterable<T> map(AssetMapper<T> mappingFunction, Supplier<T> defaultValue) {
return () -> new Iterator<T>() {
int index = 0;
int size = assets.size();
@Override
public boolean hasNext() { return index < size; }
@Override
public T next() {
if(!hasNext()) throw new NoSuchElementException();
try { return mappingFunction.apply(assets.get(index++)); }
catch(IOException e) {
e.printStackTrace();
return defaultValue.get();
}
}
};
}
@Override
public void forEach(Consumer<? super IAsset> action) {
assets.forEach(action);
}
@Override
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
assets.forEach(input, action);
}
@Override
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
assets.forEachIndexed(action);
}
@Override
public ObjectIterator<IAsset> iterator() {
return assets.iterator();
}
public static interface AssetMapper<T> {
public T apply(IAsset asset) throws IOException;
}
}
package speiger.src.coreengine.assets.base;
import java.io.Closeable;
import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import java.util.function.Supplier;
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
import speiger.src.collections.objects.collections.ObjectIterable;
import speiger.src.collections.objects.collections.ObjectIterator;
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
ObjectList<IAsset> assets;
public MultiAsset(IAsset...assets) {
this(ObjectArrayList.wrap(assets));
}
public MultiAsset(ObjectList<IAsset> assets) {
this.assets = assets.unmodifiable();
}
@Override
public void close() {
if(assets != null) {
assets.forEach(IAsset::close);
assets = null;
}
}
public int size() {
return assets.size();
}
public IAsset get(int index) {
return assets.get(index);
}
public <T> Iterable<T> map(AssetMapper<T> mappingFunction, Supplier<T> defaultValue) {
return () -> new Iterator<T>() {
int index = 0;
int size = assets.size();
@Override
public boolean hasNext() { return index < size; }
@Override
public T next() {
if(!hasNext()) throw new NoSuchElementException();
try { return mappingFunction.apply(assets.get(index++)); }
catch(IOException e) {
e.printStackTrace();
return defaultValue.get();
}
}
};
}
@Override
public void forEach(Consumer<? super IAsset> action) {
assets.forEach(action);
}
@Override
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
assets.forEach(input, action);
}
@Override
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
assets.forEachIndexed(action);
}
@Override
public ObjectIterator<IAsset> iterator() {
return assets.iterator();
}
public static interface AssetMapper<T> {
public T apply(IAsset asset) throws IOException;
}
}

View File

@ -1,44 +1,44 @@
package speiger.src.coreengine.assets.impl;
import java.io.Closeable;
import java.util.List;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
public abstract class BaseAsset implements IAsset {
protected AssetLocation location;
protected IAssetPackage owner;
protected List<Closeable> closeable = new ObjectArrayList<>();
public BaseAsset(AssetLocation location, IAssetPackage owner) {
this.location = location;
this.owner = owner;
}
@Override
public void close() {
for(Closeable close : closeable) {
try { close.close(); }
catch(Exception e) { e.printStackTrace(); }
}
closeable.clear();
}
protected <T extends Closeable> T markClosed(T value) {
closeable.add(value);
return value;
}
@Override
public AssetLocation location() {
return location;
}
@Override
public IAssetPackage owner() {
return owner;
}
}
package speiger.src.coreengine.assets.impl;
import java.io.Closeable;
import java.util.List;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
public abstract class BaseAsset implements IAsset {
protected AssetLocation location;
protected IAssetPackage owner;
protected List<Closeable> closeable = new ObjectArrayList<>();
public BaseAsset(AssetLocation location, IAssetPackage owner) {
this.location = location;
this.owner = owner;
}
@Override
public void close() {
for(Closeable close : closeable) {
try { close.close(); }
catch(Exception e) { e.printStackTrace(); }
}
closeable.clear();
}
protected <T extends Closeable> T markClosed(T value) {
closeable.add(value);
return value;
}
@Override
public AssetLocation location() {
return location;
}
@Override
public IAssetPackage owner() {
return owner;
}
}

View File

@ -1,71 +1,71 @@
package speiger.src.coreengine.assets.impl;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class FolderAssetPackage implements IAssetPackage {
Path baseFolder;
public FolderAssetPackage(Path baseFolder) {
this.baseFolder = baseFolder;
}
@Override
public void close() {}
@Override
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
try {
Path start = baseFolder.resolve("assets/").resolve(domain);
for(Path path : IterableWrapper.wrap(Files.walk(start).filter(Files::isRegularFile).iterator())) {
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
}
}
catch(IOException e) { e.printStackTrace(); }
}
@Override
public List<String> getDomains() {
List<String> domains = new ObjectArrayList<>();
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(baseFolder.resolve("assets"))) {
for(Path path : dirs) {
domains.add(path.getFileName().toString());
}
}
catch(IOException e) { e.printStackTrace(); }
return domains;
}
@Override
public IAsset getAsset(AssetLocation location) {
Path path = baseFolder.resolve(location.actualLocation());
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
}
@Override
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
Path start = baseFolder.resolve(folder.actualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
for(Path path : IterableWrapper.wrap(stream.iterator())) {
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
result.accept(location, new SimpleAsset(location, this, path));
}
}
catch(IOException e) {
e.printStackTrace();
}
}
package speiger.src.coreengine.assets.impl;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class FolderAssetPackage implements IAssetPackage {
Path baseFolder;
public FolderAssetPackage(Path baseFolder) {
this.baseFolder = baseFolder;
}
@Override
public void close() {}
@Override
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
try {
Path start = baseFolder.resolve("assets/").resolve(domain);
for(Path path : IterableWrapper.wrap(Files.walk(start).filter(Files::isRegularFile).iterator())) {
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
}
}
catch(IOException e) { e.printStackTrace(); }
}
@Override
public List<String> getDomains() {
List<String> domains = new ObjectArrayList<>();
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(baseFolder.resolve("assets"))) {
for(Path path : dirs) {
domains.add(path.getFileName().toString());
}
}
catch(IOException e) { e.printStackTrace(); }
return domains;
}
@Override
public IAsset getAsset(AssetLocation location) {
Path path = baseFolder.resolve(location.actualLocation());
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
}
@Override
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
Path start = baseFolder.resolve(folder.actualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
for(Path path : IterableWrapper.wrap(stream.iterator())) {
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
result.accept(location, new SimpleAsset(location, this, path));
}
}
catch(IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,161 +1,161 @@
package speiger.src.coreengine.assets.impl;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.math.ArrayUtil;
public class LayeredAssetProvider implements ICloseableAssetProvider {
public static final FileTime DEFAULT_TIME = FileTime.fromMillis(0L);
Map<String, DomainAssetProvider> domains = Object2ObjectMap.builder().linkedMap();
List<IAssetPackage> packages;
public LayeredAssetProvider(List<IAssetPackage> packages) {
this.packages = packages;
for(IAssetPackage pack : packages) {
for(String domain : pack.getDomains()) {
domains.computeIfAbsent(domain, DomainAssetProvider::new).addPackage(pack);
}
}
domains.values().forEach(DomainAssetProvider::buildCaches);
}
@Override
public void close() {
packages.forEach(IAssetPackage::close);
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? DEFAULT_TIME : provider.getModifiedTime(location);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
FileTime time = DEFAULT_TIME;
for(AssetLocation location : locations) {
time = ArrayUtil.higher(time, getModifiedTime(location));
}
return time;
}
@Override
public IAsset getAsset(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? null : provider.getAsset(location);
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? null : provider.getAllAssets(location);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
for(DomainAssetProvider provider : domains.values()) {
result.putAll(provider.listAssets(folder, filter));
}
return result;
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
for(DomainAssetProvider provider : domains.values()) {
result.putAll(provider.listAllAssets(folder, filter));
}
return result;
}
private static class DomainAssetProvider implements IAssetProvider {
final String domain;
ObjectList<IAssetPackage> packages = new ObjectArrayList<>();
Map<AssetLocation, FileTime> lastChanges = Object2ObjectMap.builder().map();
public DomainAssetProvider(String domain) {
this.domain = domain;
}
public void addPackage(IAssetPackage pack) {
packages.add(pack);
}
private void buildCaches() {
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).getModifiedTime(domain, lastChanges::putIfAbsent);
}
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
return lastChanges.getOrDefault(location, DEFAULT_TIME);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
throw new UnsupportedOperationException();
}
@Override
public IAsset getAsset(AssetLocation location) {
for(int i = packages.size()-1;i>=0;i--) {
IAsset asset = packages.get(i).getAsset(location);
if(asset != null) return asset;
}
return null;
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
ObjectList<IAsset> result = new ObjectArrayList<>();
for(int i = packages.size()-1;i>=0;i--) {
IAsset asset = packages.get(i).getAsset(location);
if(asset != null) result.add(asset);
}
return new MultiAsset(result);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
AssetLocation base = AssetLocation.of(domain, folder);
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).gatherAssets(base, (K, V) -> {
if(filter.test(K)) result.putIfAbsent(K, V);
});
}
return result;
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
AssetLocation base = AssetLocation.of(domain, folder);
Object2ObjectMap<AssetLocation, ObjectList<IAsset>> assets = Object2ObjectMap.builder().linkedMap();
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).gatherAssets(base, (K, V) -> {
if(filter.test(K)) assets.supplyIfAbsent(K, ObjectArrayList::new).add(V);
});
}
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
for(Object2ObjectMap.Entry<AssetLocation, ObjectList<IAsset>> entry : Object2ObjectMaps.fastIterable(assets)) {
result.put(entry.getKey(), new MultiAsset(entry.getValue()));
}
return result;
}
}
package speiger.src.coreengine.assets.impl;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.math.ArrayUtil;
public class LayeredAssetProvider implements ICloseableAssetProvider {
public static final FileTime DEFAULT_TIME = FileTime.fromMillis(0L);
Map<String, DomainAssetProvider> domains = Object2ObjectMap.builder().linkedMap();
List<IAssetPackage> packages;
public LayeredAssetProvider(List<IAssetPackage> packages) {
this.packages = packages;
for(IAssetPackage pack : packages) {
for(String domain : pack.getDomains()) {
domains.computeIfAbsent(domain, DomainAssetProvider::new).addPackage(pack);
}
}
domains.values().forEach(DomainAssetProvider::buildCaches);
}
@Override
public void close() {
packages.forEach(IAssetPackage::close);
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? DEFAULT_TIME : provider.getModifiedTime(location);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
FileTime time = DEFAULT_TIME;
for(AssetLocation location : locations) {
time = ArrayUtil.higher(time, getModifiedTime(location));
}
return time;
}
@Override
public IAsset getAsset(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? null : provider.getAsset(location);
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
DomainAssetProvider provider = domains.get(location.domain());
return provider == null ? null : provider.getAllAssets(location);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
for(DomainAssetProvider provider : domains.values()) {
result.putAll(provider.listAssets(folder, filter));
}
return result;
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
for(DomainAssetProvider provider : domains.values()) {
result.putAll(provider.listAllAssets(folder, filter));
}
return result;
}
private static class DomainAssetProvider implements IAssetProvider {
final String domain;
ObjectList<IAssetPackage> packages = new ObjectArrayList<>();
Map<AssetLocation, FileTime> lastChanges = Object2ObjectMap.builder().map();
public DomainAssetProvider(String domain) {
this.domain = domain;
}
public void addPackage(IAssetPackage pack) {
packages.add(pack);
}
private void buildCaches() {
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).getModifiedTime(domain, lastChanges::putIfAbsent);
}
}
@Override
public FileTime getModifiedTime(AssetLocation location) {
return lastChanges.getOrDefault(location, DEFAULT_TIME);
}
@Override
public FileTime getLatestTime(AssetLocation... locations) {
throw new UnsupportedOperationException();
}
@Override
public IAsset getAsset(AssetLocation location) {
for(int i = packages.size()-1;i>=0;i--) {
IAsset asset = packages.get(i).getAsset(location);
if(asset != null) return asset;
}
return null;
}
@Override
public MultiAsset getAllAssets(AssetLocation location) {
ObjectList<IAsset> result = new ObjectArrayList<>();
for(int i = packages.size()-1;i>=0;i--) {
IAsset asset = packages.get(i).getAsset(location);
if(asset != null) result.add(asset);
}
return new MultiAsset(result);
}
@Override
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
AssetLocation base = AssetLocation.of(domain, folder);
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).gatherAssets(base, (K, V) -> {
if(filter.test(K)) result.putIfAbsent(K, V);
});
}
return result;
}
@Override
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
AssetLocation base = AssetLocation.of(domain, folder);
Object2ObjectMap<AssetLocation, ObjectList<IAsset>> assets = Object2ObjectMap.builder().linkedMap();
for(int i = packages.size()-1;i>=0;i--) {
packages.get(i).gatherAssets(base, (K, V) -> {
if(filter.test(K)) assets.supplyIfAbsent(K, ObjectArrayList::new).add(V);
});
}
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
for(Object2ObjectMap.Entry<AssetLocation, ObjectList<IAsset>> entry : Object2ObjectMaps.fastIterable(assets)) {
result.put(entry.getKey(), new MultiAsset(entry.getValue()));
}
return result;
}
}
}

View File

@ -1,51 +1,51 @@
package speiger.src.coreengine.assets.impl;
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.List;
import javax.imageio.ImageIO;
import com.google.gson.JsonObject;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetParser;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class SimpleAsset extends BaseAsset {
Path path;
public SimpleAsset(AssetLocation location, IAssetPackage owner, Path path) {
super(location, owner);
this.path = path;
}
@Override
public IAsset subAsset(String alternative) {
Path newPath = path.resolveSibling(path.getFileName().toString()+"."+alternative);
return Files.exists(newPath) ? new SimpleAsset(location.alternate(alternative), owner, newPath) : null;
}
@Override
public InputStream stream() throws IOException { return markClosed(Files.newInputStream(path)); }
@Override
public ByteBuffer bytes() throws IOException { return ByteBuffer.wrap(Files.readAllBytes(path)); }
@Override
public BufferedImage texture() throws Exception { return ImageIO.read(stream()); }
@Override
public BufferedReader reader() throws IOException { return markClosed(Files.newBufferedReader(path)); }
@Override
public List<String> lines() throws IOException { return Files.readAllLines(path); }
@Override
public JsonObject json() throws IOException { return JsonUtil.loadFile(path); }
@Override
public <T> T custom(IAssetParser<T> parser) throws IOException { return parser.parseAsset(path, closeable::add); }
}
package speiger.src.coreengine.assets.impl;
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.List;
import javax.imageio.ImageIO;
import com.google.gson.JsonObject;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.assets.base.IAssetParser;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class SimpleAsset extends BaseAsset {
Path path;
public SimpleAsset(AssetLocation location, IAssetPackage owner, Path path) {
super(location, owner);
this.path = path;
}
@Override
public IAsset subAsset(String alternative) {
Path newPath = path.resolveSibling(path.getFileName().toString()+"."+alternative);
return Files.exists(newPath) ? new SimpleAsset(location.alternate(alternative), owner, newPath) : null;
}
@Override
public InputStream stream() throws IOException { return markClosed(Files.newInputStream(path)); }
@Override
public ByteBuffer bytes() throws IOException { return ByteBuffer.wrap(Files.readAllBytes(path)); }
@Override
public BufferedImage texture() throws Exception { return ImageIO.read(stream()); }
@Override
public BufferedReader reader() throws IOException { return markClosed(Files.newBufferedReader(path)); }
@Override
public List<String> lines() throws IOException { return Files.readAllLines(path); }
@Override
public JsonObject json() throws IOException { return JsonUtil.loadFile(path); }
@Override
public <T> T custom(IAssetParser<T> parser) throws IOException { return parser.parseAsset(path, closeable::add); }
}

View File

@ -1,107 +1,107 @@
package speiger.src.coreengine.assets.impl;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class ZipAssetPackage implements IAssetPackage {
Path baseFolder;
FileSystem cache;
public ZipAssetPackage(Path baseFolder) {
this.baseFolder = baseFolder;
}
@Override
public void close() {
if(cache != null) {
try { cache.close(); }
catch(Exception e) { e.printStackTrace(); }
cache = null;
}
}
@Override
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
try {
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
Path start = system.getPath("assets");
for(Path path : IterableWrapper.wrap(Files.walk(start.resolve(domain)).filter(Files::isRegularFile).iterator())) {
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
}
}
}
catch(IOException e) { e.printStackTrace(); }
}
protected FileSystem getReference() throws IOException {
if(cache == null) cache = FileSystems.newFileSystem(baseFolder);
return cache;
}
@Override
public List<String> getDomains() {
List<String> domains = new ObjectArrayList<>();
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(system.getPath("assets"))) {
for(Path path : dirs) {
String s = path.getFileName().toString();
domains.add(s.substring(0, s.length()));
}
}
catch(Exception e) {
e.printStackTrace();
}
}
catch(Exception e) {
e.printStackTrace();
}
return domains;
}
@Override
public IAsset getAsset(AssetLocation location) {
try {
Path path = getReference().getPath(location.actualLocation());
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
try {
FileSystem system = getReference();
Path start = system.getPath(folder.actualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
for(Path path : IterableWrapper.wrap(stream.iterator())) {
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
result.accept(location, new SimpleAsset(location, this, path));
}
}
catch(IOException e) {
e.printStackTrace();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
package speiger.src.coreengine.assets.impl;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetPackage;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class ZipAssetPackage implements IAssetPackage {
Path baseFolder;
FileSystem cache;
public ZipAssetPackage(Path baseFolder) {
this.baseFolder = baseFolder;
}
@Override
public void close() {
if(cache != null) {
try { cache.close(); }
catch(Exception e) { e.printStackTrace(); }
cache = null;
}
}
@Override
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
try {
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
Path start = system.getPath("assets");
for(Path path : IterableWrapper.wrap(Files.walk(start.resolve(domain)).filter(Files::isRegularFile).iterator())) {
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
}
}
}
catch(IOException e) { e.printStackTrace(); }
}
protected FileSystem getReference() throws IOException {
if(cache == null) cache = FileSystems.newFileSystem(baseFolder);
return cache;
}
@Override
public List<String> getDomains() {
List<String> domains = new ObjectArrayList<>();
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(system.getPath("assets"))) {
for(Path path : dirs) {
String s = path.getFileName().toString();
domains.add(s.substring(0, s.length()));
}
}
catch(Exception e) {
e.printStackTrace();
}
}
catch(Exception e) {
e.printStackTrace();
}
return domains;
}
@Override
public IAsset getAsset(AssetLocation location) {
try {
Path path = getReference().getPath(location.actualLocation());
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
try {
FileSystem system = getReference();
Path start = system.getPath(folder.actualLocation());
if(Files.notExists(start)) return;
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
for(Path path : IterableWrapper.wrap(stream.iterator())) {
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
result.accept(location, new SimpleAsset(location, this, path));
}
}
catch(IOException e) {
e.printStackTrace();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,106 +1,106 @@
package speiger.src.coreengine.assets.language;
import java.util.Map;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
public class LanguageManager implements IReloadableResource {
final AssetLocation location = AssetLocation.of("lang");
Map<String, Language> languages = new Object2ObjectOpenHashMap<>();
AssetManager assets;
String currentLanguage;
@Override
public void reload() {
languages.clear();
try(MultiAsset langs = assets.getAllAssets(location.subAsset("langs.json"))) {
for(int i = 0,m = langs.size();i < m;i++) {
preLoadLanguage(langs.get(i).json());
}
}
catch(Exception e) {
e.printStackTrace();
}
if(loadLanguage(currentLanguage)) {
I18n.CURRENT_LANGUAGE = languages.get(currentLanguage);
}
else {
Language dummy = new Language("en_US", "English");
dummy.load(Object2ObjectMaps.empty());
I18n.CURRENT_LANGUAGE = dummy;
}
}
public boolean setLanguage(String lang) {
if(loadLanguage(lang)) {
I18n.CURRENT_LANGUAGE = languages.get(lang);
Language currentLang = languages.get(currentLanguage);
currentLanguage = lang;
if(currentLang != null) currentLang.clear();
return true;
}
return false;
}
protected boolean loadLanguage(String loadingLang) {
Language lang = languages.get(loadingLang);
if(lang == null) return false;
Map<String, String> map = new Object2ObjectOpenHashMap<>();
loadLanguage(loadingLang, map);
if(loadingLang != "en_US") loadLanguage("en_US", map);
lang.load(map);
return true;
}
protected void loadLanguage(String lang, Map<String, String> data) {
try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) {
for(int i = 0,m = language.size();i < m;i++) {
try {
for(Map.Entry<String, JsonElement> element : language.get(i).json().entrySet()) {
loadEntry(element.getKey(), element.getValue(), data);
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
catch(Exception e) {
e.printStackTrace();
}
}
protected void loadEntry(String basePath, JsonElement el, Map<String, String> data) {
if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString());
else if(el.isJsonObject()) {
for(Map.Entry<String, JsonElement> elements : el.getAsJsonObject().entrySet()) {
String key = elements.getKey();
if(key.isEmpty()) loadEntry(basePath, elements.getValue(), data);
else loadEntry(basePath+"."+key, elements.getValue(), data);
}
}
}
protected void preLoadLanguage(JsonObject object) {
JsonArray array = object.getAsJsonArray("languages");
if(array == null) return;
for(int i = 0,m = array.size();i < m;i++) {
JsonArray subArray = array.get(i).getAsJsonArray();
if(subArray.size() != 2) continue;
String key = subArray.get(0).getAsString();
String value = subArray.get(1).getAsString();
if(key.length() != 2 || value.length() > 16) continue;
languages.computeIfAbsent(key, T -> new Language(key, value));
}
}
}
package speiger.src.coreengine.assets.language;
import java.util.Map;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
public class LanguageManager implements IReloadableResource {
final AssetLocation location = AssetLocation.of("lang");
Map<String, Language> languages = new Object2ObjectOpenHashMap<>();
AssetManager assets;
String currentLanguage;
@Override
public void reload() {
languages.clear();
try(MultiAsset langs = assets.getAllAssets(location.subAsset("langs.json"))) {
for(int i = 0,m = langs.size();i < m;i++) {
preLoadLanguage(langs.get(i).json());
}
}
catch(Exception e) {
e.printStackTrace();
}
if(loadLanguage(currentLanguage)) {
I18n.CURRENT_LANGUAGE = languages.get(currentLanguage);
}
else {
Language dummy = new Language("en_US", "English");
dummy.load(Object2ObjectMaps.empty());
I18n.CURRENT_LANGUAGE = dummy;
}
}
public boolean setLanguage(String lang) {
if(loadLanguage(lang)) {
I18n.CURRENT_LANGUAGE = languages.get(lang);
Language currentLang = languages.get(currentLanguage);
currentLanguage = lang;
if(currentLang != null) currentLang.clear();
return true;
}
return false;
}
protected boolean loadLanguage(String loadingLang) {
Language lang = languages.get(loadingLang);
if(lang == null) return false;
Map<String, String> map = new Object2ObjectOpenHashMap<>();
loadLanguage(loadingLang, map);
if(loadingLang != "en_US") loadLanguage("en_US", map);
lang.load(map);
return true;
}
protected void loadLanguage(String lang, Map<String, String> data) {
try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) {
for(int i = 0,m = language.size();i < m;i++) {
try {
for(Map.Entry<String, JsonElement> element : language.get(i).json().entrySet()) {
loadEntry(element.getKey(), element.getValue(), data);
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
catch(Exception e) {
e.printStackTrace();
}
}
protected void loadEntry(String basePath, JsonElement el, Map<String, String> data) {
if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString());
else if(el.isJsonObject()) {
for(Map.Entry<String, JsonElement> elements : el.getAsJsonObject().entrySet()) {
String key = elements.getKey();
if(key.isEmpty()) loadEntry(basePath, elements.getValue(), data);
else loadEntry(basePath+"."+key, elements.getValue(), data);
}
}
}
protected void preLoadLanguage(JsonObject object) {
JsonArray array = object.getAsJsonArray("languages");
if(array == null) return;
for(int i = 0,m = array.size();i < m;i++) {
JsonArray subArray = array.get(i).getAsJsonArray();
if(subArray.size() != 2) continue;
String key = subArray.get(0).getAsString();
String value = subArray.get(1).getAsString();
if(key.length() != 2 || value.length() > 16) continue;
languages.computeIfAbsent(key, _ -> new Language(key, value));
}
}
}

View File

@ -1,16 +0,0 @@
package speiger.src.coreengine.math.vector;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.math.vector.floats.Vec3f;
public class VectorUtil
{
public static float barryCentric(Vec3f p1, Vec3f p2, Vec3f p3, Vec2f pos)
{
float det = (p2.z() - p3.z()) * (p1.x() - p3.x()) + (p3.x() - p2.x()) * (p1.z() - p3.z());
float l1 = ((p2.z() - p3.z()) * (pos.x() - p3.x()) + (p3.x() - p2.x()) * (pos.y() - p3.z())) / det;
float l2 = ((p3.z() - p1.z()) * (pos.x() - p3.x()) + (p1.x() - p3.x()) * (pos.y() - p3.z())) / det;
float l3 = 1.0f - l1 - l2;
return l1 * p1.y() + l2 * p2.y() + l3 * p3.y();
}
}

View File

@ -1,51 +0,0 @@
package speiger.src.coreengine.math.vector.bytes;
import java.util.Objects;
public class Vec2bImmutable implements Vec2b {
final byte x;
final byte y;
public Vec2bImmutable() {
x = 0;
y = 0;
}
public Vec2bImmutable(byte value) {
x = value;
y = value;
}
public Vec2bImmutable(byte x, byte y) {
this.x = x;
this.y = y;
}
@Override
public boolean isMutable() { return false; }
@Override
public byte x() { return x; }
@Override
public byte y() { return y; }
@Override
public Vec2b x(byte x) { return this.x == x ? this : Vec2b.of(x, y); }
@Override
public Vec2b y(byte y) { return this.y == y ? this : Vec2b.of(x, y); }
@Override
public Vec2b copy() { return Vec2b.of(this); }
@Override
public Vec2b set(byte x, byte y) { return this.x == x && this.y == y ? this : Vec2b.of(x, y); }
@Override
public int hashCode() { return Objects.hash(x, y); }
@Override
public boolean equals(Object obj) {
if(obj instanceof Vec2b) {
Vec2b vec = (Vec2b)obj;
return vec.x() == x && vec.y() == y;
}
return false;
}
@Override
public String toString() { return "Vec2b[x="+x+", y="+y+"]"; }
}

View File

@ -1,59 +0,0 @@
package speiger.src.coreengine.math.vector.bytes;
import java.util.Objects;
public class Vec3bImmutable implements Vec3b {
final byte x;
final byte y;
final byte z;
public Vec3bImmutable() {
x = 0;
y = 0;
z = 0;
}
public Vec3bImmutable(byte value) {
x = value;
y = value;
z = value;
}
public Vec3bImmutable(byte x, byte y, byte z) {
this.x = x;
this.y = y;
this.z = z;
}
@Override
public boolean isMutable() { return false; }
@Override
public byte x() { return x; }
@Override
public byte y() { return y; }
@Override
public byte z() { return z; }
@Override
public Vec3b x(byte x) { return this.x == x ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b y(byte y) { return this.y == y ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b z(byte z) { return this.z == z ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b copy() { return Vec3b.of(this); }
@Override
public Vec3b set(byte x, byte y, byte z) { return this.x == x && this.y == y && this.z == z ? this : Vec3b.of(x, y, z); }
@Override
public int hashCode() { return Objects.hash(x, y, z); }
@Override
public boolean equals(Object obj) {
if(obj instanceof Vec3b) {
Vec3b vec = (Vec3b)obj;
return vec.x() == x && vec.y() == y && vec.z() == z;
}
return false;
}
@Override
public String toString() { return "Vec3b[x="+x+", y="+y+", z="+z+"]"; }
}

View File

@ -1,68 +0,0 @@
package speiger.src.coreengine.math.vector.bytes;
import java.util.Objects;
public class Vec4bImmutable implements Vec4b {
final byte x;
final byte y;
final byte z;
final byte w;
public Vec4bImmutable() {
x = 0;
y = 0;
z = 0;
w = 0;
}
public Vec4bImmutable(byte value) {
x = value;
y = value;
z = value;
w = value;
}
public Vec4bImmutable(byte x, byte y, byte z, byte w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
@Override
public boolean isMutable() { return false; }
@Override
public byte x() { return x; }
@Override
public byte y() { return y; }
@Override
public byte z() { return z; }
@Override
public byte w() { return w; }
@Override
public Vec4b x(byte x) { return this.x == x ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b y(byte y) { return this.y == y ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b z(byte z) { return this.z == z ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b w(byte w) { return this.w == w ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b copy() { return Vec4b.of(this); }
@Override
public Vec4b set(byte x, byte y, byte z, byte w) { return this.x == x && this.y == y && this.z == z && this.w == w ? this : Vec4b.of(x, y, z, w); }
@Override
public int hashCode() { return Objects.hash(x, y, z, w); }
@Override
public boolean equals(Object obj) {
if(obj instanceof Vec4b) {
Vec4b vec = (Vec4b)obj;
return vec.x() == x && vec.y() == y && vec.z() == z && vec.w() == w;
}
return false;
}
@Override
public String toString() { return "Vec4b[x="+x+", y="+y+", z="+z+", w="+w+"]"; }
}

View File

@ -1,118 +1,118 @@
package speiger.src.coreengine.rendering.gui.font;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import com.google.gson.JsonObject;
import speiger.src.collections.floats.maps.interfaces.Float2ObjectMap;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.coreengine.assets.AssetFilter;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.providers.FreeTypeProvider;
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
private static final int TEXTURE_SIZE = 512;
private static final AssetFilter FILTER = AssetFilter.json("font");
Float2ObjectMap<Font> cachedFonts = Float2ObjectMap.builder().map();
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
List<Runnable> listeners = new ObjectArrayList<>();
List<FontTexture> textures = new ObjectArrayList<>();
public FontManager() {
registerParser("stb-ttf", STBTrueTypeProvider::create);
registerParser("free-ttf", FreeTypeProvider::load);
}
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
fontParsers.putIfAbsent(id, parser);
}
@Override
public String getName() { return "Font Manager"; }
@Override
protected Map<AssetLocation, ObjectList<IFontProvider>> prepare(IAssetProvider provider) {
Map<AssetLocation, IFontProvider> loadingCache = Object2ObjectMap.builder().linkedMap();
Object2ObjectMap<AssetLocation, ObjectList<IFontProvider>> providers = Object2ObjectMap.builder().linkedMap();
for(Entry<AssetLocation, MultiAsset> entry : FILTER.multiRoot(provider).entrySet()) {
AssetLocation id = entry.getKey();
for(JsonObject obj : entry.getValue().map(IAsset::json, JsonObject::new)) {
JsonUtil.iterateValues(obj.get("providers"), T -> {
AssetLocation location = AssetLocation.tryOf(T.getAsString());
if(location == null || !location.isInFolder()) return;
IFontProvider font = loadingCache.computeIfAbsent(location.prefix("font"), E -> getFont(E, provider));
if(font == null) return;
providers.supplyIfAbsent(FILTER.id(id), ObjectArrayList::new).add(font);
});
}
}
return providers;
}
@Override
protected void apply(Map<AssetLocation, ObjectList<IFontProvider>> value, IAssetProvider provider) {
reset();
value.forEach((K, V) -> fonts.put(K, new FontGroup(K, V)));
}
@Override
public void destroy() {
reset();
listeners.clear();
}
private void reset() {
listeners.forEach(Runnable::run);
textures.forEach(FontTexture::delete);
textures.clear();
fonts.values().forEach(FontGroup::close);
fonts.clear();
cachedFonts.clear();
}
public Font createFont() {
return createFont(1F);
}
public Font createFont(float oversample) {
return cachedFonts.computeIfAbsent(oversample, T -> new Font(fonts, this::stitch, T, listeners::add));
}
private Glyth stitch(IGlythSheetInfo info) {
for(int i = 0,m=textures.size();i<m;i++) {
Glyth glyth = textures.get(i).build(info);
if(glyth != null) return glyth;
}
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
textures.add(texture);
Glyth glyth = texture.build(info);
return glyth;
}
private IFontProvider getFont(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
JsonObject obj = asset.json();
BiFunction<JsonObject, IAssetProvider, IFontProvider> builder = fontParsers.get(obj.get("type").getAsString());
return builder == null ? null : builder.apply(obj, provider);
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
package speiger.src.coreengine.rendering.gui.font;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import com.google.gson.JsonObject;
import speiger.src.collections.floats.maps.interfaces.Float2ObjectMap;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.coreengine.assets.AssetFilter;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.MultiAsset;
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.providers.FreeTypeProvider;
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
private static final int TEXTURE_SIZE = 512;
private static final AssetFilter FILTER = AssetFilter.json("font");
Float2ObjectMap<Font> cachedFonts = Float2ObjectMap.builder().map();
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
List<Runnable> listeners = new ObjectArrayList<>();
List<FontTexture> textures = new ObjectArrayList<>();
public FontManager() {
registerParser("stb-ttf", STBTrueTypeProvider::create);
registerParser("free-ttf", FreeTypeProvider::load);
}
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
fontParsers.putIfAbsent(id, parser);
}
@Override
public String getName() { return "Font Manager"; }
@Override
protected Map<AssetLocation, ObjectList<IFontProvider>> prepare(IAssetProvider provider) {
Map<AssetLocation, IFontProvider> loadingCache = Object2ObjectMap.builder().linkedMap();
Object2ObjectMap<AssetLocation, ObjectList<IFontProvider>> providers = Object2ObjectMap.builder().linkedMap();
for(Entry<AssetLocation, MultiAsset> entry : FILTER.multiRoot(provider).entrySet()) {
AssetLocation id = entry.getKey();
for(JsonObject obj : entry.getValue().map(IAsset::json, JsonObject::new)) {
JsonUtil.iterateValues(obj.get("providers"), T -> {
AssetLocation location = AssetLocation.tryOf(T.getAsString());
if(location == null || !location.isInFolder()) return;
IFontProvider font = loadingCache.computeIfAbsent(location.prefix("font"), E -> getFont(E, provider));
if(font == null) return;
providers.supplyIfAbsent(FILTER.id(id), ObjectArrayList::new).add(font);
});
}
}
return providers;
}
@Override
protected void apply(Map<AssetLocation, ObjectList<IFontProvider>> value, IAssetProvider provider) {
reset();
value.forEach((K, V) -> fonts.put(K, new FontGroup(K, V)));
}
@Override
public void destroy() {
reset();
listeners.clear();
}
private void reset() {
listeners.forEach(Runnable::run);
textures.forEach(FontTexture::delete);
textures.clear();
fonts.values().forEach(FontGroup::close);
fonts.clear();
cachedFonts.clear();
}
public Font createFont() {
return createFont(1F);
}
public Font createFont(float oversample) {
return cachedFonts.computeIfAbsent(oversample, T -> new Font(fonts, this::stitch, T, listeners::add));
}
private Glyth stitch(IGlythSheetInfo info) {
for(int i = 0,m=textures.size();i<m;i++) {
Glyth glyth = textures.get(i).build(info);
if(glyth != null) return glyth;
}
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
textures.add(texture);
Glyth glyth = texture.build(info);
return glyth;
}
private IFontProvider getFont(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
JsonObject obj = asset.json();
BiFunction<JsonObject, IAssetProvider, IFontProvider> builder = fontParsers.get(obj.get("type").getAsString());
return builder == null ? null : builder.apply(obj, provider);
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -1,297 +1,297 @@
package speiger.src.coreengine.rendering.gui.font.providers;
import java.nio.ByteBuffer;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.freetype.FT_Bitmap;
import org.lwjgl.util.freetype.FT_Face;
import org.lwjgl.util.freetype.FT_GlyphSlot;
import org.lwjgl.util.freetype.FT_Vector;
import org.lwjgl.util.freetype.FreeType;
import org.lwjgl.util.harfbuzz.HarfBuzz;
import org.lwjgl.util.harfbuzz.hb_glyph_position_t;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.sets.IntOpenHashSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.longs.misc.pairs.LongObjectPair;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.gui.font.FontTexture;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
import speiger.src.coreengine.rendering.textures.custom.Drawable;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class FreeTypeProvider implements IFontProvider {
FreeTypeInstance[] instance;
public FreeTypeProvider(FreeTypeInstance[] instance) {
this.instance = instance;
}
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
return load(asset.json(), provider);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static IFontProvider load(JsonObject data, IAssetProvider provider) {
long library = FreeTypeLibrary.get();
if(library == 0L) return null;
FreeTypeInstance[] instances = new FreeTypeInstance[4];
instances[0] = create(library, 0, data.getAsJsonObject("regular"), provider);
if(instances[0] == null) return null;
instances[1] = create(library, 1, data.getAsJsonObject("bold"), provider);
instances[2] = create(library, 2, data.getAsJsonObject("italic"), provider);
instances[3] = create(library, 3, data.getAsJsonObject("bold_italic"), provider);
return new FreeTypeProvider(instances);
}
private static FreeTypeInstance create(long library, int style, JsonObject obj, IAssetProvider provider) {
if(obj == null || !obj.has("file")) return null;
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
float xOff = 0;
float yOff = 0;
StringBuilder builder = new StringBuilder();
JsonObject shift = obj.getAsJsonObject("offset");
if(shift != null) {
xOff = JsonUtil.getOrDefault(shift, "x", 0F);
yOff = JsonUtil.getOrDefault(shift, "y", 0F);
}
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
LongObjectPair<FT_Face> value = parse(location, provider, library);
if(value == null) return null;
return new FreeTypeInstance(style, value.getLongKey(), value.getValue(), oversample, xOff, yOff, shadowOffset, builder.toString());
}
private static LongObjectPair<FT_Face> parse(AssetLocation location, IAssetProvider provider, long library) {
try(IAsset asset = provider.getAsset(location); MemoryStack stack = MemoryStack.stackPush()) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
PointerBuffer facePointer = stack.mallocPointer(1);
if(FreeTypeLibrary.parseError(FreeType.FT_New_Memory_Face(library, buffer, 0L, facePointer), "Creating Font Face")) {
MemoryUtil.memFree(buffer);
return null;
}
FT_Face face = FT_Face.create(facePointer.get());
String s = FreeType.FT_Get_Font_Format(face);
if(!"TrueType".equals(s)) {
MemoryUtil.memFree(buffer);
throw new IllegalStateException("Font type ["+s+"] is not true type");
}
if(FreeTypeLibrary.parseError(FreeType.FT_Select_Charmap(face, FreeType.FT_ENCODING_UNICODE), "Applying Unicode Encoding")) {
MemoryUtil.memFree(buffer);
return null;
}
return LongObjectPair.of(MemoryUtil.memAddress(buffer), face);
}
catch(Exception exception) {
exception.printStackTrace();
return null;
}
}
@Override
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
FreeTypeInstance instance = this.instance[style & 0x3];
return instance != null ? instance.gylthData(codepoint, size, oversample) : null;
}
@Override
public void close() {
for(int i = 0;i<4;i++) {
if(instance[i] != null) {
instance[i].free();
}
}
instance = null;
}
public static class FreeTypeGlyth implements UnbakedGlyth {
final FT_Face face;
final int width;
final int height;
final float xOff;
final float yOff;
final float oversample;
private final float advance;
final int glyth;
final int glythCodepoint;
final long harfBuzzFont;
public FreeTypeGlyth(FT_Face face, long harfBuzzFont, float xOff, float yOff, int width, int height, float advance, float oversample, int glyth, int glythCodepoint) {
this.face = face;
this.harfBuzzFont = harfBuzzFont;
this.width = width;
this.height = height;
this.oversample = oversample;
this.advance = advance / oversample;
this.xOff = xOff / oversample;
this.yOff = yOff / oversample;
this.glyth = glyth;
this.glythCodepoint = glythCodepoint;
}
@Override
public float advance() {
return advance;
}
@Override
public float kerning(int codepoint) {
int index = FreeType.FT_Get_Char_Index(face, codepoint);
if(index == 0) return 0;
StringBuilder builder = new StringBuilder();
builder.append(Character.toChars(codepoint));
builder.append(Character.toChars(glythCodepoint));
float hbresult = (getAdvance(Character.toString(codepoint)) - getAdvance(builder.toString())) / 64F;
return hbresult;
}
private float getAdvance(String adv) {
long id = HarfBuzz.hb_buffer_create();
try {
HarfBuzz.hb_buffer_add_utf8(id, adv, 0, adv.length());
HarfBuzz.hb_buffer_guess_segment_properties(id);
HarfBuzz.hb_shape(harfBuzzFont, id, null);
hb_glyph_position_t.Buffer positions = HarfBuzz.hb_buffer_get_glyph_positions(id);
float result = positions.hasRemaining() ? positions.x_advance() : 0F;
HarfBuzz.hb_buffer_destroy(positions.address());
return result;
}
finally {
HarfBuzz.hb_buffer_destroy(id);
}
}
@Override
public Glyth bake(GlythBaker baker) {
return baker.bake(new IGlythSheetInfo() {
@Override
public float xOffset() { return xOff; }
@Override
public float yOffset() { return yOff; }
@Override
public int width() { return width; }
@Override
public int height() { return height; }
@Override
public float oversample() { return oversample; }
@Override
public void upload(int texture, int x, int y) {
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
if(drawable.drawFont(face, glyth)) {
drawable.upload(texture, x, y, 0, 0, width, height);
}
drawable.close();
}
@Override
public boolean isColored() { return false; }
});
}
}
public static class FreeTypeInstance {
final int style;
long data;
final FT_Face face;
IntSet skip = new IntOpenHashSet();
final float oversample;
final float xOff;
final float yOff;
final float shadowOffset;
final long harfBuzzFont;
public FreeTypeInstance(int style, long data, FT_Face face, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
this.style = style;
this.data = data;
this.face = face;
this.harfBuzzFont = HarfBuzz.hb_ft_font_create_referenced(face.address());
skip.codePoints().forEach(this.skip::add);
this.oversample = oversample;
this.xOff = xOff;
this.yOff = yOff;
this.shadowOffset = shadowOffset;
try(MemoryStack stack = MemoryStack.stackPush()) {
FT_Vector ft_vector = FT_Vector.malloc(stack).set(Math.round(oversample * xOff * 64F), Math.round(oversample * -yOff * 64F));
FreeType.FT_Set_Transform(face, null, ft_vector);
}
}
public void free() {
if(data == 0L) return;
FreeType.FT_Done_Face(face);
MemoryUtil.nmemFree(data);
data = 0L;
}
public UnbakedGlyth gylthData(int codepoint, float size, float oversample) {
if(skip.contains(codepoint)) return null;
int index = FreeType.FT_Get_Char_Index(face, codepoint);
if(index == 0) return null;
oversample *= this.oversample;
int pixels = Math.round(size * oversample);
if(FreeTypeLibrary.parseError(FreeType.FT_Set_Pixel_Sizes(face, 0, pixels), "Set Pixel Size")) return null;
if(FreeTypeLibrary.parseError(FreeType.FT_Load_Glyph(face, index, FreeType.FT_LOAD_NO_BITMAP | FreeType.FT_LOAD_BITMAP_METRICS_ONLY), "Loading Glyth")) return null;
FT_GlyphSlot slot = face.glyph();
if(slot == null) {
System.out.println("Glyth didn't load for some reason");
return null;
}
float advance = slot.advance().x() / 64F;
FT_Bitmap bitmap = slot.bitmap();
int left = slot.bitmap_left();
int top = slot.bitmap_top();
int width = bitmap.width();
int height = bitmap.rows();
if(width > 0 && height > 0) return new FreeTypeGlyth(face, harfBuzzFont, left, -top, width, height, advance, oversample, index, codepoint);
return new EmptyGlythData(advance / oversample);
}
}
public static class FreeTypeLibrary {
private static long pointer = 0L;
public static long get() {
if(pointer == 0L) {
try(MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer pointBuffer = stack.callocPointer(1);
int result = FreeType.FT_Init_FreeType(pointBuffer);
if(result != 0) {
throw new IllegalStateException(FreeType.FT_Error_String(result));
}
pointer = pointBuffer.get();
}
}
return pointer;
}
public static boolean parseError(int result, String action) {
if(result == 0) return false;
String error = FreeType.FT_Error_String(result);
System.out.println("Couldn't do ["+action+"] because of "+error);
return true;
}
public static void close() {
if(pointer == 0L) return;
FreeType.FT_Done_Library(pointer);
pointer = 0L;
}
}
}
package speiger.src.coreengine.rendering.gui.font.providers;
import java.nio.ByteBuffer;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import org.lwjgl.util.freetype.FT_Bitmap;
import org.lwjgl.util.freetype.FT_Face;
import org.lwjgl.util.freetype.FT_GlyphSlot;
import org.lwjgl.util.freetype.FT_Vector;
import org.lwjgl.util.freetype.FreeType;
import org.lwjgl.util.harfbuzz.HarfBuzz;
import org.lwjgl.util.harfbuzz.hb_glyph_position_t;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.sets.IntOpenHashSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.longs.misc.pairs.LongObjectPair;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.gui.font.FontTexture;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
import speiger.src.coreengine.rendering.textures.custom.Drawable;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class FreeTypeProvider implements IFontProvider {
FreeTypeInstance[] instance;
public FreeTypeProvider(FreeTypeInstance[] instance) {
this.instance = instance;
}
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
return load(asset.json(), provider);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static IFontProvider load(JsonObject data, IAssetProvider provider) {
long library = FreeTypeLibrary.get();
if(library == 0L) return null;
FreeTypeInstance[] instances = new FreeTypeInstance[4];
instances[0] = create(library, 0, data.getAsJsonObject("regular"), provider);
if(instances[0] == null) return null;
instances[1] = create(library, 1, data.getAsJsonObject("bold"), provider);
instances[2] = create(library, 2, data.getAsJsonObject("italic"), provider);
instances[3] = create(library, 3, data.getAsJsonObject("bold_italic"), provider);
return new FreeTypeProvider(instances);
}
private static FreeTypeInstance create(long library, int style, JsonObject obj, IAssetProvider provider) {
if(obj == null || !obj.has("file")) return null;
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
float xOff = 0;
float yOff = 0;
StringBuilder builder = new StringBuilder();
JsonObject shift = obj.getAsJsonObject("offset");
if(shift != null) {
xOff = JsonUtil.getOrDefault(shift, "x", 0F);
yOff = JsonUtil.getOrDefault(shift, "y", 0F);
}
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
LongObjectPair<FT_Face> value = parse(location, provider, library);
if(value == null) return null;
return new FreeTypeInstance(style, value.getLongKey(), value.getValue(), oversample, xOff, yOff, shadowOffset, builder.toString());
}
private static LongObjectPair<FT_Face> parse(AssetLocation location, IAssetProvider provider, long library) {
try(IAsset asset = provider.getAsset(location); MemoryStack stack = MemoryStack.stackPush()) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
PointerBuffer facePointer = stack.mallocPointer(1);
if(FreeTypeLibrary.parseError(FreeType.FT_New_Memory_Face(library, buffer, 0L, facePointer), "Creating Font Face")) {
MemoryUtil.memFree(buffer);
return null;
}
FT_Face face = FT_Face.create(facePointer.get());
String s = FreeType.FT_Get_Font_Format(face);
if(!"TrueType".equals(s)) {
MemoryUtil.memFree(buffer);
throw new IllegalStateException("Font type ["+s+"] is not true type");
}
if(FreeTypeLibrary.parseError(FreeType.FT_Select_Charmap(face, FreeType.FT_ENCODING_UNICODE), "Applying Unicode Encoding")) {
MemoryUtil.memFree(buffer);
return null;
}
return LongObjectPair.of(MemoryUtil.memAddress(buffer), face);
}
catch(Exception exception) {
exception.printStackTrace();
return null;
}
}
@Override
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
FreeTypeInstance instance = this.instance[style & 0x3];
return instance != null ? instance.gylthData(codepoint, size, oversample) : null;
}
@Override
public void close() {
for(int i = 0;i<4;i++) {
if(instance[i] != null) {
instance[i].free();
}
}
instance = null;
}
public static class FreeTypeGlyth implements UnbakedGlyth {
final FT_Face face;
final int width;
final int height;
final float xOff;
final float yOff;
final float oversample;
private final float advance;
final int glyth;
final int glythCodepoint;
final long harfBuzzFont;
public FreeTypeGlyth(FT_Face face, long harfBuzzFont, float xOff, float yOff, int width, int height, float advance, float oversample, int glyth, int glythCodepoint) {
this.face = face;
this.harfBuzzFont = harfBuzzFont;
this.width = width;
this.height = height;
this.oversample = oversample;
this.advance = advance / oversample;
this.xOff = xOff / oversample;
this.yOff = yOff / oversample;
this.glyth = glyth;
this.glythCodepoint = glythCodepoint;
}
@Override
public float advance() {
return advance;
}
@Override
public float kerning(int codepoint) {
int index = FreeType.FT_Get_Char_Index(face, codepoint);
if(index == 0) return 0;
StringBuilder builder = new StringBuilder();
builder.append(Character.toChars(codepoint));
builder.append(Character.toChars(glythCodepoint));
float hbresult = (getAdvance(Character.toString(codepoint)) - getAdvance(builder.toString())) / 64F;
return hbresult;
}
private float getAdvance(String adv) {
long id = HarfBuzz.hb_buffer_create();
try {
HarfBuzz.hb_buffer_add_utf8(id, adv, 0, adv.length());
HarfBuzz.hb_buffer_guess_segment_properties(id);
HarfBuzz.hb_shape(harfBuzzFont, id, null);
hb_glyph_position_t.Buffer positions = HarfBuzz.hb_buffer_get_glyph_positions(id);
float result = positions.hasRemaining() ? positions.x_advance() : 0F;
HarfBuzz.hb_buffer_destroy(positions.address());
return result;
}
finally {
HarfBuzz.hb_buffer_destroy(id);
}
}
@Override
public Glyth bake(GlythBaker baker) {
return baker.bake(new IGlythSheetInfo() {
@Override
public float xOffset() { return xOff; }
@Override
public float yOffset() { return yOff; }
@Override
public int width() { return width; }
@Override
public int height() { return height; }
@Override
public float oversample() { return oversample; }
@Override
public void upload(int texture, int x, int y) {
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
if(drawable.drawFont(face, glyth)) {
drawable.upload(texture, x, y, 0, 0, width, height);
}
drawable.close();
}
@Override
public boolean isColored() { return false; }
});
}
}
public static class FreeTypeInstance {
final int style;
long data;
final FT_Face face;
IntSet skip = new IntOpenHashSet();
final float oversample;
final float xOff;
final float yOff;
final float shadowOffset;
final long harfBuzzFont;
public FreeTypeInstance(int style, long data, FT_Face face, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
this.style = style;
this.data = data;
this.face = face;
this.harfBuzzFont = HarfBuzz.hb_ft_font_create_referenced(face.address());
skip.codePoints().forEach(this.skip::add);
this.oversample = oversample;
this.xOff = xOff;
this.yOff = yOff;
this.shadowOffset = shadowOffset;
try(MemoryStack stack = MemoryStack.stackPush()) {
FT_Vector ft_vector = FT_Vector.malloc(stack).set(Math.round(oversample * xOff * 64F), Math.round(oversample * -yOff * 64F));
FreeType.FT_Set_Transform(face, null, ft_vector);
}
}
public void free() {
if(data == 0L) return;
FreeType.FT_Done_Face(face);
MemoryUtil.nmemFree(data);
data = 0L;
}
public UnbakedGlyth gylthData(int codepoint, float size, float oversample) {
if(skip.contains(codepoint)) return null;
int index = FreeType.FT_Get_Char_Index(face, codepoint);
if(index == 0) return null;
oversample *= this.oversample;
int pixels = Math.round(size * oversample);
if(FreeTypeLibrary.parseError(FreeType.FT_Set_Pixel_Sizes(face, 0, pixels), "Set Pixel Size")) return null;
if(FreeTypeLibrary.parseError(FreeType.FT_Load_Glyph(face, index, FreeType.FT_LOAD_NO_BITMAP | FreeType.FT_LOAD_BITMAP_METRICS_ONLY), "Loading Glyth")) return null;
FT_GlyphSlot slot = face.glyph();
if(slot == null) {
System.out.println("Glyth didn't load for some reason");
return null;
}
float advance = slot.advance().x() / 64F;
FT_Bitmap bitmap = slot.bitmap();
int left = slot.bitmap_left();
int top = slot.bitmap_top();
int width = bitmap.width();
int height = bitmap.rows();
if(width > 0 && height > 0) return new FreeTypeGlyth(face, harfBuzzFont, left, -top, width, height, advance, oversample, index, codepoint);
return new EmptyGlythData(advance / oversample);
}
}
public static class FreeTypeLibrary {
private static long pointer = 0L;
public static long get() {
if(pointer == 0L) {
try(MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer pointBuffer = stack.callocPointer(1);
int result = FreeType.FT_Init_FreeType(pointBuffer);
if(result != 0) {
throw new IllegalStateException(FreeType.FT_Error_String(result));
}
pointer = pointBuffer.get();
}
}
return pointer;
}
public static boolean parseError(int result, String action) {
if(result == 0) return false;
String error = FreeType.FT_Error_String(result);
System.out.println("Couldn't do ["+action+"] because of "+error);
return true;
}
public static void close() {
if(pointer == 0L) return;
FreeType.FT_Done_Library(pointer);
pointer = 0L;
}
}
}

View File

@ -1,214 +1,214 @@
package speiger.src.coreengine.rendering.gui.font.providers;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTruetype;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.sets.IntOpenHashSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.gui.font.FontTexture;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.textures.custom.Drawable;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class STBTrueTypeProvider implements IFontProvider {
TrueTypeInstance[] instances;
public STBTrueTypeProvider(TrueTypeInstance[] instances) {
this.instances = instances;
}
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
return create(asset.json(), provider);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static IFontProvider create(JsonObject data, IAssetProvider provider) {
TrueTypeInstance[] instances = new TrueTypeInstance[4];
instances[0] = create(0, data.getAsJsonObject("regular"), provider);
if(instances[0] == null) return null;
instances[1] = create(1, data.getAsJsonObject("bold"), provider);
instances[2] = create(2, data.getAsJsonObject("italic"), provider);
instances[3] = create(3, data.getAsJsonObject("bold_italic"), provider);
return new STBTrueTypeProvider(instances);
}
private static TrueTypeInstance create(int style, JsonObject obj, IAssetProvider provider) {
if(obj == null || !obj.has("file")) return null;
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
float xOff = 0;
float yOff = 0;
StringBuilder builder = new StringBuilder();
JsonObject shift = obj.getAsJsonObject("offset");
if(shift != null) {
xOff = JsonUtil.getOrDefault(shift, "x", 0);
yOff = JsonUtil.getOrDefault(shift, "y", 0);
}
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
try(IAsset asset = provider.getAsset(location)) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
STBTTFontinfo info = STBTTFontinfo.create();
if(!STBTruetype.stbtt_InitFont(info, buffer)) {
System.out.println("Couldn't load font");
MemoryUtil.memFree(buffer);
info.free();
return null;
}
return new TrueTypeInstance(style, MemoryUtil.memAddress(buffer), info, oversample, xOff, yOff, shadowOffset, builder.toString());
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
public static class TrueTypeInstance {
final int style;
long data;
final STBTTFontinfo info;
IntSet skip = new IntOpenHashSet();
final float oversample;
final float xOff;
final float yOff;
final float shadowOffset;
final float ascent;
public TrueTypeInstance(int style, long data, STBTTFontinfo info, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
this.style = style;
this.data = data;
this.info = info;
skip.codePoints().forEach(this.skip::add);
this.oversample = oversample;
this.xOff = xOff;
this.yOff = yOff;
this.shadowOffset = shadowOffset;
int[] ascent = new int[1];
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
this.ascent = ascent[0];
}
public void free() {
if(data == 0L) return;
info.free();
MemoryUtil.nmemFree(data);
data = 0L;
}
public UnbakedGlyth glythData(int codepoint, float size, float oversample) {
if(skip.contains(codepoint)) return null;
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
if(glyth == 0) return null;
oversample *= this.oversample;
float scale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
try(MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer left = stack.mallocInt(1);
IntBuffer bottom = stack.mallocInt(1);
IntBuffer right = stack.mallocInt(1);
IntBuffer top = stack.mallocInt(1);
IntBuffer advance = stack.mallocInt(1);
IntBuffer leftSideBearing = stack.mallocInt(1);
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, scale, scale, xOff, yOff, left, bottom, right, top);
int minX = left.get(0);
int minY = -top.get(0);
int maxX = right.get(0);
int maxY = -bottom.get(0);
if(maxX - minX <= 0 || maxY - minY <= 0) return new EmptyGlythData(advance.get(0) * scale / oversample);
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0), leftSideBearing.get(0), scale, oversample, glyth);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
@Override
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
TrueTypeInstance instance = instances[style & 0x3];
return instance == null ? null : instance.glythData(codepoint, size, oversample);
}
@Override
public void close() {
if(instances == null) return;
for(int i = 0;i<4;i++) {
if(instances[i] == null) continue;
instances[i].free();
}
instances = null;
}
private static class STBGlyth implements UnbakedGlyth {
final TrueTypeInstance owner;
final float xOffset;
final float yOffset;
final int width;
final int height;
final float oversample;
final float scale;
final float advance;
final int glyth;
public STBGlyth(TrueTypeInstance owner, int minX, int minY, int maxX, int maxY, float advance, float leftPadding, float scale, float oversample, int glyth) {
this.owner = owner;
this.width = maxX - minX;
this.height = maxY - minY;
this.scale = scale;
this.oversample = oversample;
this.xOffset = ((leftPadding * scale) + minX + owner.xOff) / oversample;
this.yOffset = ((owner.ascent * scale) - maxY + owner.yOff) / oversample;
this.advance = advance * scale / oversample;
this.glyth = glyth;
}
@Override
public float advance() { return advance; }
@Override
public float shadowOffset() { return owner.shadowOffset; }
@Override
public float kerning(int codepoint) { return STBTruetype.stbtt_GetCodepointKernAdvance(owner.info, codepoint, glyth) * scale / oversample; }
@Override
public Glyth bake(GlythBaker baker) {
return baker.bake(new IGlythSheetInfo() {
@Override
public float xOffset() { return xOffset; }
@Override
public float yOffset() { return yOffset; }
@Override
public int width() { return width; }
@Override
public int height() { return height; }
@Override
public float oversample() { return oversample; }
@Override
public boolean isColored() { return false; }
@Override
public void upload(int texture, int x, int y) {
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
drawable.drawFont(owner.info, glyth, owner.xOff, owner.yOff, 0, 0, width, height, scale, scale);
drawable.upload(texture, x, y, 0, 0, width, height);
drawable.close();
}
});
}
}
}
package speiger.src.coreengine.rendering.gui.font.providers;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.stb.STBTTFontinfo;
import org.lwjgl.stb.STBTruetype;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.sets.IntOpenHashSet;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.gui.font.FontTexture;
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
import speiger.src.coreengine.rendering.textures.custom.Drawable;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class STBTrueTypeProvider implements IFontProvider {
TrueTypeInstance[] instances;
public STBTrueTypeProvider(TrueTypeInstance[] instances) {
this.instances = instances;
}
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
try(IAsset asset = provider.getAsset(location)) {
return create(asset.json(), provider);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static IFontProvider create(JsonObject data, IAssetProvider provider) {
TrueTypeInstance[] instances = new TrueTypeInstance[4];
instances[0] = create(0, data.getAsJsonObject("regular"), provider);
if(instances[0] == null) return null;
instances[1] = create(1, data.getAsJsonObject("bold"), provider);
instances[2] = create(2, data.getAsJsonObject("italic"), provider);
instances[3] = create(3, data.getAsJsonObject("bold_italic"), provider);
return new STBTrueTypeProvider(instances);
}
private static TrueTypeInstance create(int style, JsonObject obj, IAssetProvider provider) {
if(obj == null || !obj.has("file")) return null;
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
float xOff = 0;
float yOff = 0;
StringBuilder builder = new StringBuilder();
JsonObject shift = obj.getAsJsonObject("offset");
if(shift != null) {
xOff = JsonUtil.getOrDefault(shift, "x", 0);
yOff = JsonUtil.getOrDefault(shift, "y", 0);
}
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
try(IAsset asset = provider.getAsset(location)) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
STBTTFontinfo info = STBTTFontinfo.create();
if(!STBTruetype.stbtt_InitFont(info, buffer)) {
System.out.println("Couldn't load font");
MemoryUtil.memFree(buffer);
info.free();
return null;
}
return new TrueTypeInstance(style, MemoryUtil.memAddress(buffer), info, oversample, xOff, yOff, shadowOffset, builder.toString());
}
catch(Exception e) {
e.printStackTrace();
}
return null;
}
public static class TrueTypeInstance {
final int style;
long data;
final STBTTFontinfo info;
IntSet skip = new IntOpenHashSet();
final float oversample;
final float xOff;
final float yOff;
final float shadowOffset;
final float ascent;
public TrueTypeInstance(int style, long data, STBTTFontinfo info, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
this.style = style;
this.data = data;
this.info = info;
skip.codePoints().forEach(this.skip::add);
this.oversample = oversample;
this.xOff = xOff;
this.yOff = yOff;
this.shadowOffset = shadowOffset;
int[] ascent = new int[1];
STBTruetype.stbtt_GetFontVMetrics(info, ascent, new int[1], new int[1]);
this.ascent = ascent[0];
}
public void free() {
if(data == 0L) return;
info.free();
MemoryUtil.nmemFree(data);
data = 0L;
}
public UnbakedGlyth glythData(int codepoint, float size, float oversample) {
if(skip.contains(codepoint)) return null;
int glyth = STBTruetype.nstbtt_FindGlyphIndex(info.address(), codepoint);
if(glyth == 0) return null;
oversample *= this.oversample;
float scale = STBTruetype.stbtt_ScaleForPixelHeight(info, size * oversample);
try(MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer left = stack.mallocInt(1);
IntBuffer bottom = stack.mallocInt(1);
IntBuffer right = stack.mallocInt(1);
IntBuffer top = stack.mallocInt(1);
IntBuffer advance = stack.mallocInt(1);
IntBuffer leftSideBearing = stack.mallocInt(1);
STBTruetype.stbtt_GetGlyphHMetrics(info, glyth, advance, leftSideBearing);
STBTruetype.stbtt_GetGlyphBitmapBoxSubpixel(info, glyth, scale, scale, xOff, yOff, left, bottom, right, top);
int minX = left.get(0);
int minY = -top.get(0);
int maxX = right.get(0);
int maxY = -bottom.get(0);
if(maxX - minX <= 0 || maxY - minY <= 0) return new EmptyGlythData(advance.get(0) * scale / oversample);
return new STBGlyth(this, minX, minY, maxX, maxY, advance.get(0), leftSideBearing.get(0), scale, oversample, glyth);
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
@Override
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
TrueTypeInstance instance = instances[style & 0x3];
return instance == null ? null : instance.glythData(codepoint, size, oversample);
}
@Override
public void close() {
if(instances == null) return;
for(int i = 0;i<4;i++) {
if(instances[i] == null) continue;
instances[i].free();
}
instances = null;
}
private static class STBGlyth implements UnbakedGlyth {
final TrueTypeInstance owner;
final float xOffset;
final float yOffset;
final int width;
final int height;
final float oversample;
final float scale;
final float advance;
final int glyth;
public STBGlyth(TrueTypeInstance owner, int minX, int minY, int maxX, int maxY, float advance, float leftPadding, float scale, float oversample, int glyth) {
this.owner = owner;
this.width = maxX - minX;
this.height = maxY - minY;
this.scale = scale;
this.oversample = oversample;
this.xOffset = ((leftPadding * scale) + minX + owner.xOff) / oversample;
this.yOffset = ((owner.ascent * scale) - maxY + owner.yOff) / oversample;
this.advance = advance * scale / oversample;
this.glyth = glyth;
}
@Override
public float advance() { return advance; }
@Override
public float shadowOffset() { return owner.shadowOffset; }
@Override
public float kerning(int codepoint) { return STBTruetype.stbtt_GetCodepointKernAdvance(owner.info, codepoint, glyth) * scale / oversample; }
@Override
public Glyth bake(GlythBaker baker) {
return baker.bake(new IGlythSheetInfo() {
@Override
public float xOffset() { return xOffset; }
@Override
public float yOffset() { return yOffset; }
@Override
public int width() { return width; }
@Override
public int height() { return height; }
@Override
public float oversample() { return oversample; }
@Override
public boolean isColored() { return false; }
@Override
public void upload(int texture, int x, int y) {
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
drawable.drawFont(owner.info, glyth, owner.xOff, owner.yOff, 0, 0, width, height, scale, scale);
drawable.upload(texture, x, y, 0, 0, width, height);
drawable.close();
}
});
}
}
}

View File

@ -690,7 +690,7 @@ public abstract class GuiComponent extends FlagHolder
public final GuiComponent addListener(Runnable runnable, int index)
{
listeners[index].add(T -> runnable.run());
listeners[index].add(_ -> runnable.run());
return this;
}

View File

@ -9,9 +9,9 @@ import speiger.src.coreengine.rendering.guiOld.renderer.FontRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.GuiShader;
import speiger.src.coreengine.rendering.guiOld.renderer.UIRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.provider.FontManager;
import speiger.src.coreengine.rendering.inputOld.events.MouseEvent;
import speiger.src.coreengine.rendering.inputOld.events.KeyEvent.CharTypeEvent;
import speiger.src.coreengine.rendering.inputOld.events.KeyEvent.KeyPressEvent;
import speiger.src.coreengine.rendering.inputOld.events.MouseEvent;
import speiger.src.coreengine.rendering.inputOld.window.IWindowListener;
import speiger.src.coreengine.rendering.inputOld.window.ScaledResolution;
import speiger.src.coreengine.rendering.inputOld.window.Window;

View File

@ -13,8 +13,8 @@ import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.components.list.SelectionEntry;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.renderer.UIRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;

View File

@ -1,334 +1,334 @@
package speiger.src.coreengine.rendering.guiOld.components;
import speiger.src.collections.floats.functions.FloatSupplier;
import speiger.src.collections.objects.functions.function.ToFloatFunction;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
public class SingleTabPanelComponent extends PanelComponent
{
PanelComponent selection = new PanelComponent();
PanelComponent panel = new PanelComponent().setScissors(true);
ObjectList<Tab> tabs = new ObjectArrayList<>();
int selectedTab = -1;
float tabScale = 1F;
Facing facing;
int backgroundColor = ColorUtils.GRAY;
int unselectedColor = ColorUtils.GRAY;
int selectedColor = ColorUtils.DARK_GRAY;
float padding = 30F;
public SingleTabPanelComponent()
{
this(Facing.NORTH);
}
public SingleTabPanelComponent(Facing facing)
{
this(0F, 0F, 0F, 0F, facing);
}
public SingleTabPanelComponent(float x, float y, float width, float height)
{
this(x, y, width, height, Facing.NORTH);
}
public SingleTabPanelComponent(float x, float y, float width, float height, Facing facing)
{
super(x, y, width, height);
this.facing = facing;
}
public SingleTabPanelComponent setFacing(Facing facing)
{
this.facing = facing;
updateConstrains(selection, createView());
for(Tab tab : tabs)
{
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
}
updateConstrains(panel, createPanel());
onChanged(true);
return this;
}
public SingleTabPanelComponent setPadding(float padding)
{
this.padding = padding;
for(Tab tab : tabs)
{
tab.updatePadding();
}
onChanged(true);
return this;
}
public SingleTabPanelComponent addTab(String name)
{
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
tabs.add(newTab);
if(selectedTab == -1) {
selectedTab = tabs.size()-1;
}
newTab.onAction(() -> selectTab(newTab));
selection.addChild(newTab, createConstraint(newTab));
onChanged(true);
return this;
}
public Facing getFacing()
{
return facing;
}
public int findTab(String name)
{
for(int i = 0,m=tabs.size();i<m;i++) {
if(tabs.get(i).name.equals(name)) return i;
}
return -1;
}
public int getActiveIndex()
{
return selectedTab;
}
public PanelComponent getPanel()
{
return panel;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
getRenderer().drawQuad(selection.getBox(), backgroundColor);
return true;
}
@Override
public void init()
{
addChild(selection, createView());
addChild(panel, createPanel());
super.init();
}
@Override
protected void repaint()
{
if(facing.isZAxis())
{
float room = getBox().getBaseWidth();
float requiredSpace = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
float width = tab.getWidth() * tab.getTextScale();
if(i == selectedTab) room -= width;
else requiredSpace += width;
}
tabScale = Math.min(1F, room / requiredSpace);
}
else
{
tabScale = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
}
tabScale *= getBox().getScale();
tabScale += 1F;
}
}
protected Constrains createView()
{
switch(facing)
{
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createPanel()
{
switch(facing)
{
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createConstraint(Tab tab)
{
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
}
protected void selectTab(Tab tab)
{
if(selectTab(tabs.indexOf(tab)))
{
notifyListeners(LISTENER_USER_ACTION);
}
}
public boolean selectTab(int index)
{
if(index < 0 || index >= tabs.size()) return false;
if(selectedTab == index) return false;
selectedTab = index;
onChanged(true);
return true;
}
protected float getOffset(Tab tab)
{
int index = tabs.indexOf(tab);
float offset = 0F;
for(int i = 0;i<index;i++)
{
Tab entry = tabs.get(i);
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
else offset += tab.getBox().getBaseHeight();
}
return offset;
}
protected float getPanelOffset()
{
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
}
protected float getPanelWidth()
{
return tabScale + 0.25F;
}
protected float getXOffset()
{
return tabScale + 0.25F;
}
protected float getWidth(Tab tab)
{
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
}
private static class DynamicTab implements FloatSupplier
{
Tab tab;
ToFloatFunction<Tab> function;
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
{
this.tab = tab;
this.function = function;
}
@Override
public float getAsFloat()
{
return function.applyAsFloat(tab);
}
}
private class Tab extends GuiComponent implements IButtonComponent
{
String name;
float width = -1F;
TextComponent comp;
public Tab(String name)
{
super(0F, 0F, 100F, 7.5F);
this.name = name;
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
setFlag(FLAG_SUPPORT_BINDING);
}
public Tab align(Align align)
{
comp.horizontal(align);
return this;
}
public void updatePadding()
{
if(getGui() != null) width = getFont().width(name)+padding;
}
@Override
public void init()
{
addChild(comp, Constrains.parent());
updatePadding();
}
public float getWidth()
{
return width;
}
public float getTextScale()
{
return comp.getTextScale();
}
@Override
protected void repaint()
{
String s = name;
float scale = comp.getTextScale();
float width = (this.width-padding)*scale;
float desiredWidth = getBox().getBaseWidth();
if(width > desiredWidth) {
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
s = s.substring(0, s.length()-1);
}
comp.setText(s+"...");
return;
}
comp.setText(s);
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
boolean notSelected = tabs.indexOf(this) != selectedTab;
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
return true;
}
@Override
public void onRelease(int button, int mouseX, int mouseY)
{
notifyListeners(LISTENER_USER_ACTION);
}
@Override
protected boolean onUserKey()
{
notifyListeners(LISTENER_USER_ACTION);
return true;
}
}
package speiger.src.coreengine.rendering.guiOld.components;
import speiger.src.collections.floats.functions.FloatSupplier;
import speiger.src.collections.objects.functions.function.ToFloatFunction;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
public class SingleTabPanelComponent extends PanelComponent
{
PanelComponent selection = new PanelComponent();
PanelComponent panel = new PanelComponent().setScissors(true);
ObjectList<Tab> tabs = new ObjectArrayList<>();
int selectedTab = -1;
float tabScale = 1F;
Facing facing;
int backgroundColor = ColorUtils.GRAY;
int unselectedColor = ColorUtils.GRAY;
int selectedColor = ColorUtils.DARK_GRAY;
float padding = 30F;
public SingleTabPanelComponent()
{
this(Facing.NORTH);
}
public SingleTabPanelComponent(Facing facing)
{
this(0F, 0F, 0F, 0F, facing);
}
public SingleTabPanelComponent(float x, float y, float width, float height)
{
this(x, y, width, height, Facing.NORTH);
}
public SingleTabPanelComponent(float x, float y, float width, float height, Facing facing)
{
super(x, y, width, height);
this.facing = facing;
}
public SingleTabPanelComponent setFacing(Facing facing)
{
this.facing = facing;
updateConstrains(selection, createView());
for(Tab tab : tabs)
{
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
}
updateConstrains(panel, createPanel());
onChanged(true);
return this;
}
public SingleTabPanelComponent setPadding(float padding)
{
this.padding = padding;
for(Tab tab : tabs)
{
tab.updatePadding();
}
onChanged(true);
return this;
}
public SingleTabPanelComponent addTab(String name)
{
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
tabs.add(newTab);
if(selectedTab == -1) {
selectedTab = tabs.size()-1;
}
newTab.onAction(() -> selectTab(newTab));
selection.addChild(newTab, createConstraint(newTab));
onChanged(true);
return this;
}
public Facing getFacing()
{
return facing;
}
public int findTab(String name)
{
for(int i = 0,m=tabs.size();i<m;i++) {
if(tabs.get(i).name.equals(name)) return i;
}
return -1;
}
public int getActiveIndex()
{
return selectedTab;
}
public PanelComponent getPanel()
{
return panel;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
getRenderer().drawQuad(selection.getBox(), backgroundColor);
return true;
}
@Override
public void init()
{
addChild(selection, createView());
addChild(panel, createPanel());
super.init();
}
@Override
protected void repaint()
{
if(facing.isZAxis())
{
float room = getBox().getBaseWidth();
float requiredSpace = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
float width = tab.getWidth() * tab.getTextScale();
if(i == selectedTab) room -= width;
else requiredSpace += width;
}
tabScale = Math.min(1F, room / requiredSpace);
}
else
{
tabScale = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
}
tabScale *= getBox().getScale();
tabScale += 1F;
}
}
protected Constrains createView()
{
switch(facing)
{
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createPanel()
{
switch(facing)
{
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createConstraint(Tab tab)
{
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
}
protected void selectTab(Tab tab)
{
if(selectTab(tabs.indexOf(tab)))
{
notifyListeners(LISTENER_USER_ACTION);
}
}
public boolean selectTab(int index)
{
if(index < 0 || index >= tabs.size()) return false;
if(selectedTab == index) return false;
selectedTab = index;
onChanged(true);
return true;
}
protected float getOffset(Tab tab)
{
int index = tabs.indexOf(tab);
float offset = 0F;
for(int i = 0;i<index;i++)
{
Tab entry = tabs.get(i);
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
else offset += tab.getBox().getBaseHeight();
}
return offset;
}
protected float getPanelOffset()
{
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
}
protected float getPanelWidth()
{
return tabScale + 0.25F;
}
protected float getXOffset()
{
return tabScale + 0.25F;
}
protected float getWidth(Tab tab)
{
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
}
private static class DynamicTab implements FloatSupplier
{
Tab tab;
ToFloatFunction<Tab> function;
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
{
this.tab = tab;
this.function = function;
}
@Override
public float getAsFloat()
{
return function.applyAsFloat(tab);
}
}
private class Tab extends GuiComponent implements IButtonComponent
{
String name;
float width = -1F;
TextComponent comp;
public Tab(String name)
{
super(0F, 0F, 100F, 7.5F);
this.name = name;
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
setFlag(FLAG_SUPPORT_BINDING);
}
public Tab align(Align align)
{
comp.horizontal(align);
return this;
}
public void updatePadding()
{
if(getGui() != null) width = getFont().width(name)+padding;
}
@Override
public void init()
{
addChild(comp, Constrains.parent());
updatePadding();
}
public float getWidth()
{
return width;
}
public float getTextScale()
{
return comp.getTextScale();
}
@Override
protected void repaint()
{
String s = name;
float scale = comp.getTextScale();
float width = (this.width-padding)*scale;
float desiredWidth = getBox().getBaseWidth();
if(width > desiredWidth) {
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
s = s.substring(0, s.length()-1);
}
comp.setText(s+"...");
return;
}
comp.setText(s);
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
boolean notSelected = tabs.indexOf(this) != selectedTab;
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
return true;
}
@Override
public void onRelease(int button, int mouseX, int mouseY)
{
notifyListeners(LISTENER_USER_ACTION);
}
@Override
protected boolean onUserKey()
{
notifyListeners(LISTENER_USER_ACTION);
return true;
}
}
}

View File

@ -1,339 +1,339 @@
package speiger.src.coreengine.rendering.guiOld.components;
import speiger.src.collections.floats.functions.FloatSupplier;
import speiger.src.collections.objects.functions.function.ToFloatFunction;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
public class TabbedPanelComponent extends PanelComponent
{
PanelComponent selection = new PanelComponent();
ObjectList<Tab> tabs = new ObjectArrayList<>();
int selectedTab = -1;
float tabScale = 1F;
Facing facing;
int backgroundColor = ColorUtils.GRAY;
int unselectedColor = ColorUtils.GRAY;
int selectedColor = ColorUtils.DARK_GRAY;
float padding = 30F;
public TabbedPanelComponent()
{
this(Facing.NORTH);
}
public TabbedPanelComponent(Facing facing)
{
this(0F, 0F, 0F, 0F, facing);
}
public TabbedPanelComponent(float x, float y, float width, float height)
{
this(x, y, width, height, Facing.NORTH);
}
public TabbedPanelComponent(float x, float y, float width, float height, Facing facing)
{
super(x, y, width, height);
this.facing = facing;
}
public TabbedPanelComponent setFacing(Facing facing)
{
this.facing = facing;
updateConstrains(selection, createView());
for(Tab tab : tabs)
{
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
updateConstrains(tab.getPanel(), createPanel());
}
onChanged(true);
return this;
}
public TabbedPanelComponent setPadding(float padding)
{
this.padding = padding;
for(Tab tab : tabs)
{
tab.updatePadding();
}
onChanged(true);
return this;
}
public Facing getFacing()
{
return facing;
}
public PanelComponent addTab(String name)
{
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
tabs.add(newTab);
if(selectedTab == -1) {
selectedTab = tabs.size()-1;
newTab.getPanel().setVisible(true);
}
newTab.onAction(() -> selectTab(newTab));
selection.addChild(newTab, createConstraint(newTab));
addChild(newTab.getPanel(), createPanel());
onChanged(true);
return newTab.getPanel();
}
public int findTab(String name)
{
for(int i = 0,m=tabs.size();i<m;i++) {
if(tabs.get(i).name.equals(name)) return i;
}
return -1;
}
public int getActiveIndex()
{
return selectedTab;
}
public PanelComponent getActiveTab()
{
return selectedTab == -1 ? null : tabs.get(selectedTab).getPanel();
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
getRenderer().drawQuad(selection.getBox(), backgroundColor);
return true;
}
@Override
public void init()
{
addChild(selection, createView());
super.init();
}
@Override
protected void repaint()
{
if(facing.isZAxis())
{
float room = getBox().getBaseWidth();
float requiredSpace = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
float width = tab.getWidth() * tab.getTextScale();
if(i == selectedTab) room -= width;
else requiredSpace += width;
}
tabScale = Math.min(1F, room / requiredSpace);
}
else
{
tabScale = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
}
tabScale *= getBox().getScale();
tabScale += 1F;
}
}
protected Constrains createView()
{
switch(facing)
{
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createPanel()
{
switch(facing)
{
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createConstraint(Tab tab)
{
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
}
protected void selectTab(Tab tab)
{
selectTab(tabs.indexOf(tab));
}
public boolean selectTab(int index)
{
if(index < 0 || index >= tabs.size()) return false;
if(selectedTab == index) return false;
if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false);
selectedTab = index;
tabs.get(selectedTab).getPanel().setVisible(true);
onChanged(true);
return true;
}
protected float getOffset(Tab tab)
{
int index = tabs.indexOf(tab);
float offset = 0F;
for(int i = 0;i<index;i++)
{
Tab entry = tabs.get(i);
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
else offset += tab.getBox().getBaseHeight();
}
return offset;
}
protected float getPanelOffset()
{
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
}
protected float getPanelWidth()
{
return tabScale + 0.25F;
}
protected float getXOffset()
{
return tabScale + 0.25F;
}
protected float getWidth(Tab tab)
{
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
}
private static class DynamicTab implements FloatSupplier
{
Tab tab;
ToFloatFunction<Tab> function;
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
{
this.tab = tab;
this.function = function;
}
@Override
public float getAsFloat()
{
return function.applyAsFloat(tab);
}
}
private class Tab extends GuiComponent implements IButtonComponent
{
String name;
float width = -1F;
TextComponent comp;
PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast();
public Tab(String name)
{
super(0F, 0F, 100F, 7.5F);
this.name = name;
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
setFlag(FLAG_SUPPORT_BINDING);
}
public Tab align(Align align)
{
comp.horizontal(align);
return this;
}
public void updatePadding()
{
if(getGui() != null) width = getFont().width(name)+padding;
}
@Override
public void init()
{
addChild(comp, Constrains.parent());
updatePadding();
}
public float getWidth()
{
return width;
}
public float getTextScale()
{
return comp.getTextScale();
}
@Override
protected void repaint()
{
String s = name;
float scale = comp.getTextScale();
float width = (this.width-padding)*scale;
float desiredWidth = getBox().getBaseWidth();
if(width > desiredWidth) {
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
s = s.substring(0, s.length()-1);
}
comp.setText(s+"...");
return;
}
comp.setText(s);
}
public PanelComponent getPanel()
{
return panel;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
boolean notSelected = tabs.indexOf(this) != selectedTab;
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
return true;
}
@Override
public void onRelease(int button, int mouseX, int mouseY)
{
notifyListeners(LISTENER_USER_ACTION);
}
@Override
protected boolean onUserKey()
{
notifyListeners(LISTENER_USER_ACTION);
return true;
}
}
package speiger.src.coreengine.rendering.guiOld.components;
import speiger.src.collections.floats.functions.FloatSupplier;
import speiger.src.collections.objects.functions.function.ToFloatFunction;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
public class TabbedPanelComponent extends PanelComponent
{
PanelComponent selection = new PanelComponent();
ObjectList<Tab> tabs = new ObjectArrayList<>();
int selectedTab = -1;
float tabScale = 1F;
Facing facing;
int backgroundColor = ColorUtils.GRAY;
int unselectedColor = ColorUtils.GRAY;
int selectedColor = ColorUtils.DARK_GRAY;
float padding = 30F;
public TabbedPanelComponent()
{
this(Facing.NORTH);
}
public TabbedPanelComponent(Facing facing)
{
this(0F, 0F, 0F, 0F, facing);
}
public TabbedPanelComponent(float x, float y, float width, float height)
{
this(x, y, width, height, Facing.NORTH);
}
public TabbedPanelComponent(float x, float y, float width, float height, Facing facing)
{
super(x, y, width, height);
this.facing = facing;
}
public TabbedPanelComponent setFacing(Facing facing)
{
this.facing = facing;
updateConstrains(selection, createView());
for(Tab tab : tabs)
{
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
updateConstrains(tab.getPanel(), createPanel());
}
onChanged(true);
return this;
}
public TabbedPanelComponent setPadding(float padding)
{
this.padding = padding;
for(Tab tab : tabs)
{
tab.updatePadding();
}
onChanged(true);
return this;
}
public Facing getFacing()
{
return facing;
}
public PanelComponent addTab(String name)
{
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
tabs.add(newTab);
if(selectedTab == -1) {
selectedTab = tabs.size()-1;
newTab.getPanel().setVisible(true);
}
newTab.onAction(() -> selectTab(newTab));
selection.addChild(newTab, createConstraint(newTab));
addChild(newTab.getPanel(), createPanel());
onChanged(true);
return newTab.getPanel();
}
public int findTab(String name)
{
for(int i = 0,m=tabs.size();i<m;i++) {
if(tabs.get(i).name.equals(name)) return i;
}
return -1;
}
public int getActiveIndex()
{
return selectedTab;
}
public PanelComponent getActiveTab()
{
return selectedTab == -1 ? null : tabs.get(selectedTab).getPanel();
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
getRenderer().drawQuad(selection.getBox(), backgroundColor);
return true;
}
@Override
public void init()
{
addChild(selection, createView());
super.init();
}
@Override
protected void repaint()
{
if(facing.isZAxis())
{
float room = getBox().getBaseWidth();
float requiredSpace = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
float width = tab.getWidth() * tab.getTextScale();
if(i == selectedTab) room -= width;
else requiredSpace += width;
}
tabScale = Math.min(1F, room / requiredSpace);
}
else
{
tabScale = 0F;
for(int i = 0,m=tabs.size();i<m;i++)
{
Tab tab = tabs.get(i);
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
}
tabScale *= getBox().getScale();
tabScale += 1F;
}
}
protected Constrains createView()
{
switch(facing)
{
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createPanel()
{
switch(facing)
{
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
default: return Constrains.parent();
}
}
protected Constrains createConstraint(Tab tab)
{
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
}
protected void selectTab(Tab tab)
{
selectTab(tabs.indexOf(tab));
}
public boolean selectTab(int index)
{
if(index < 0 || index >= tabs.size()) return false;
if(selectedTab == index) return false;
if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false);
selectedTab = index;
tabs.get(selectedTab).getPanel().setVisible(true);
onChanged(true);
return true;
}
protected float getOffset(Tab tab)
{
int index = tabs.indexOf(tab);
float offset = 0F;
for(int i = 0;i<index;i++)
{
Tab entry = tabs.get(i);
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
else offset += tab.getBox().getBaseHeight();
}
return offset;
}
protected float getPanelOffset()
{
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
}
protected float getPanelWidth()
{
return tabScale + 0.25F;
}
protected float getXOffset()
{
return tabScale + 0.25F;
}
protected float getWidth(Tab tab)
{
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
}
private static class DynamicTab implements FloatSupplier
{
Tab tab;
ToFloatFunction<Tab> function;
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
{
this.tab = tab;
this.function = function;
}
@Override
public float getAsFloat()
{
return function.applyAsFloat(tab);
}
}
private class Tab extends GuiComponent implements IButtonComponent
{
String name;
float width = -1F;
TextComponent comp;
PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast();
public Tab(String name)
{
super(0F, 0F, 100F, 7.5F);
this.name = name;
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
setFlag(FLAG_SUPPORT_BINDING);
}
public Tab align(Align align)
{
comp.horizontal(align);
return this;
}
public void updatePadding()
{
if(getGui() != null) width = getFont().width(name)+padding;
}
@Override
public void init()
{
addChild(comp, Constrains.parent());
updatePadding();
}
public float getWidth()
{
return width;
}
public float getTextScale()
{
return comp.getTextScale();
}
@Override
protected void repaint()
{
String s = name;
float scale = comp.getTextScale();
float width = (this.width-padding)*scale;
float desiredWidth = getBox().getBaseWidth();
if(width > desiredWidth) {
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
s = s.substring(0, s.length()-1);
}
comp.setText(s+"...");
return;
}
comp.setText(s);
}
public PanelComponent getPanel()
{
return panel;
}
@Override
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
{
boolean notSelected = tabs.indexOf(this) != selectedTab;
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
return true;
}
@Override
public void onRelease(int button, int mouseX, int mouseY)
{
notifyListeners(LISTENER_USER_ACTION);
}
@Override
protected boolean onUserKey()
{
notifyListeners(LISTENER_USER_ACTION);
return true;
}
}
}

View File

@ -11,8 +11,8 @@ import speiger.src.coreengine.rendering.guiOld.base.IKeyComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
import speiger.src.coreengine.rendering.guiOld.helper.box.ParentBox;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.renderer.UIRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextMetadata;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.Word;

View File

@ -59,8 +59,8 @@ public class ColorPickerWindowComponent extends WindowComponent
addBox(selectedBox);
addChild(brightness.onChange(minimizedListener).onAction(T -> setColor(hsv[0], hsv[1], T.cast(SliderComponent.class).getValue() * 0.01F)));
addChild(saturation.onChange(minimizedListener).onAction(T -> setColor(hsv[0], T.cast(SliderComponent.class).getValue() * 0.01F, hsv[2])));
addChild(code.setScale(0.5F).onChange(minimizedListener).onAction(T -> onTyped()));
addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Select", ColorUtils.GREEN).setScale(0.4F).onAction(T -> apply()), new Constrains(null, new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null));
addChild(code.setScale(0.5F).onChange(minimizedListener).onAction(_ -> onTyped()));
addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Select", ColorUtils.GREEN).setScale(0.4F).onAction(_ -> apply()), new Constrains(null, new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null));
addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Cancel", ColorUtils.RED).setScale(0.4F).onAction(T -> T.getGui().removeComponent(this)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null));
setColor(hsv[0], hsv[1], hsv[2]);
}

View File

@ -15,17 +15,17 @@ import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.guiOld.base.IKeyComponent;
import speiger.src.coreengine.rendering.guiOld.components.PieComponent;
import speiger.src.coreengine.rendering.guiOld.components.PieComponent.IPieIndex;
import speiger.src.coreengine.rendering.guiOld.components.PieComponent.PieIndex;
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
import speiger.src.coreengine.rendering.guiOld.components.PieComponent.IPieIndex;
import speiger.src.coreengine.rendering.guiOld.components.PieComponent.PieIndex;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.PixelConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.inputOld.Keyboard;
import speiger.src.coreengine.utils.profiler.IProfiler;
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;

View File

@ -1,216 +1,216 @@
package speiger.src.coreengine.rendering.guiOld.components.window.debug;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.ObjIntConsumer;
import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
import speiger.src.collections.ints.queues.IntPriorityQueue;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
import speiger.src.coreengine.rendering.guiOld.components.TreeComponent;
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
import speiger.src.coreengine.rendering.guiOld.components.tree.ProfilerTreeEntry;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.utils.profiler.IProfiler;
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;
public class TreeProfilerWindow extends WindowComponent
{
IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue();
ObjIntConsumer<IProfiler> listener = (T, V) -> todoList.enqueue(V);
SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast();
TreeComponent<ProfilerTreeEntry> tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build());
List<ProfilerTab> tabs = new ObjectArrayList<>();
int previouseTab = -1;
public TreeProfilerWindow(float x, float y, float width, float height, String name)
{
super(x, y, width, height, DEFAULT_FLAGS, name);
}
public TreeProfilerWindow addProfiler(IProfiler profiler, String root)
{
panel.addTab(profiler.getName());
tabs.add(new ProfilerTab(profiler, root));
if(tabs.size() == 1)
{
onProfilerChanged();
}
return this;
}
@Override
public boolean canMoveIntoForground()
{
return true;
}
@Override
public Vec2f getMinimumBounds()
{
return Vec2f.of(100F, 50F);
}
@Override
public void init()
{
super.init();
addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build());
}
@Override
public void onClosed()
{
super.onClosed();
applyProfiler(false, this::disable);
}
@Override
protected boolean fixedUpdateSelf()
{
ProfilerTab entry = getActiveTab();
if(entry == null)
{
todoList.clear();
return true;
}
while(!todoList.isEmpty())
{
int index = todoList.dequeue();
switch(index)
{
case 0:
addEntries(entry.getRootEntry());
break;
case 1:
tree.setTree(null);
break;
case 2:
if(tree.getTree() == null)
{
addEntries(entry.getRootEntry());
break;
}
updateChildren(entry.getRootEntry(), tree.getTree());
tree.onTreeChanged();
break;
}
}
return true;
}
protected void onProfilerChanged()
{
if(previouseTab == panel.getActiveIndex()) return;
applyProfiler(true, this::disable);
applyProfiler(false, this::enable);
previouseTab = panel.getActiveIndex();
ProfilerTab tab = tabs.get(previouseTab);
setCurrentEntry(tab.getRoot());
}
protected void enable(IProfiler profiler)
{
profiler.enable();
profiler.addListener(listener);
}
protected void disable(IProfiler profiler)
{
profiler.removeListener(listener);
profiler.disable();
}
protected void addEntries(IProfilerEntry entry)
{
if(entry == null) return;
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), child);
}
tree.setTree(child);
tree.openAll();
}
public TreeProfilerWindow setCurrentEntry(String name)
{
addEntries(getActive().getEntry(name));
return this;
}
protected void updateChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
{
if(entry == null || tree == null) return;
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), tree);
}
}
protected void addChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
{
if(entry == null || tree == null) return;
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
int index = tree.indexOf(child);
if(index != -1) child = (ProfilerTreeEntry)tree.getChild(index);
else tree.addChild(child);
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), child);
}
}
protected IProfiler getActive()
{
return tabs.get(panel.getActiveIndex()).getProfiler();
}
protected ProfilerTab getActiveTab()
{
int index = panel.getActiveIndex();
return index < 0 || index >= tabs.size() ? null : tabs.get(index);
}
protected void applyProfiler(boolean prev, Consumer<IProfiler> action)
{
int index = prev ? previouseTab : panel.getActiveIndex();
if(index >= 0) action.accept(tabs.get(index).getProfiler());
}
private static class ProfilerTab
{
IProfiler profiler;
String root;
public ProfilerTab(IProfiler profiler, String root)
{
this.profiler = profiler;
this.root = root;
}
public IProfiler getProfiler()
{
return profiler;
}
public String getRoot()
{
return root;
}
public IProfilerEntry getRootEntry()
{
return profiler.getEntry(root);
}
}
}
package speiger.src.coreengine.rendering.guiOld.components.window.debug;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.ObjIntConsumer;
import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
import speiger.src.collections.ints.queues.IntPriorityQueue;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
import speiger.src.coreengine.rendering.guiOld.components.TreeComponent;
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
import speiger.src.coreengine.rendering.guiOld.components.tree.ProfilerTreeEntry;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.utils.profiler.IProfiler;
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;
public class TreeProfilerWindow extends WindowComponent
{
IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue();
ObjIntConsumer<IProfiler> listener = (_, V) -> todoList.enqueue(V);
SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast();
TreeComponent<ProfilerTreeEntry> tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build());
List<ProfilerTab> tabs = new ObjectArrayList<>();
int previouseTab = -1;
public TreeProfilerWindow(float x, float y, float width, float height, String name)
{
super(x, y, width, height, DEFAULT_FLAGS, name);
}
public TreeProfilerWindow addProfiler(IProfiler profiler, String root)
{
panel.addTab(profiler.getName());
tabs.add(new ProfilerTab(profiler, root));
if(tabs.size() == 1)
{
onProfilerChanged();
}
return this;
}
@Override
public boolean canMoveIntoForground()
{
return true;
}
@Override
public Vec2f getMinimumBounds()
{
return Vec2f.of(100F, 50F);
}
@Override
public void init()
{
super.init();
addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build());
}
@Override
public void onClosed()
{
super.onClosed();
applyProfiler(false, this::disable);
}
@Override
protected boolean fixedUpdateSelf()
{
ProfilerTab entry = getActiveTab();
if(entry == null)
{
todoList.clear();
return true;
}
while(!todoList.isEmpty())
{
int index = todoList.dequeue();
switch(index)
{
case 0:
addEntries(entry.getRootEntry());
break;
case 1:
tree.setTree(null);
break;
case 2:
if(tree.getTree() == null)
{
addEntries(entry.getRootEntry());
break;
}
updateChildren(entry.getRootEntry(), tree.getTree());
tree.onTreeChanged();
break;
}
}
return true;
}
protected void onProfilerChanged()
{
if(previouseTab == panel.getActiveIndex()) return;
applyProfiler(true, this::disable);
applyProfiler(false, this::enable);
previouseTab = panel.getActiveIndex();
ProfilerTab tab = tabs.get(previouseTab);
setCurrentEntry(tab.getRoot());
}
protected void enable(IProfiler profiler)
{
profiler.enable();
profiler.addListener(listener);
}
protected void disable(IProfiler profiler)
{
profiler.removeListener(listener);
profiler.disable();
}
protected void addEntries(IProfilerEntry entry)
{
if(entry == null) return;
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), child);
}
tree.setTree(child);
tree.openAll();
}
public TreeProfilerWindow setCurrentEntry(String name)
{
addEntries(getActive().getEntry(name));
return this;
}
protected void updateChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
{
if(entry == null || tree == null) return;
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), tree);
}
}
protected void addChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
{
if(entry == null || tree == null) return;
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
int index = tree.indexOf(child);
if(index != -1) child = (ProfilerTreeEntry)tree.getChild(index);
else tree.addChild(child);
for(int i = 0,m=entry.getChildCount();i<m;i++)
{
addChildren(entry.getChild(i), child);
}
}
protected IProfiler getActive()
{
return tabs.get(panel.getActiveIndex()).getProfiler();
}
protected ProfilerTab getActiveTab()
{
int index = panel.getActiveIndex();
return index < 0 || index >= tabs.size() ? null : tabs.get(index);
}
protected void applyProfiler(boolean prev, Consumer<IProfiler> action)
{
int index = prev ? previouseTab : panel.getActiveIndex();
if(index >= 0) action.accept(tabs.get(index).getProfiler());
}
private static class ProfilerTab
{
IProfiler profiler;
String root;
public ProfilerTab(IProfiler profiler, String root)
{
this.profiler = profiler;
this.root = root;
}
public IProfiler getProfiler()
{
return profiler;
}
public String getRoot()
{
return root;
}
public IProfilerEntry getRootEntry()
{
return profiler.getEntry(root);
}
}
}

View File

@ -46,8 +46,8 @@ public class ChoiceComponent extends WindowComponent
super.init();
yesButton.getText().setTextScale(0.5F);
noButton.getText().setTextScale(0.5F);
addChild(yesButton.onChange(minimizedListener).onAction(closeListener).onAction(T -> listener.accept(true)), new Constrains(new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)));
addChild(noButton.onChange(minimizedListener).onAction(closeListener).onAction(T -> listener.accept(false)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)));
addChild(yesButton.onChange(minimizedListener).onAction(closeListener).onAction(_ -> listener.accept(true)), new Constrains(new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)));
addChild(noButton.onChange(minimizedListener).onAction(closeListener).onAction(_ -> listener.accept(false)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)));
addChild(message, new Constrains(new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message)));
getBox().setHeight(25F + message.getMetadata().getMaxHeight());
}

View File

@ -1,446 +1,446 @@
package speiger.src.coreengine.rendering.guiOld.renderer;
import java.util.List;
import java.util.Locale;
import org.lwjgl.opengl.GL11;
import speiger.src.collections.floats.lists.FloatArrayList;
import speiger.src.collections.floats.lists.FloatList;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.DelayedRenderBuffer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.TranslatedVertexBuilder;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.Line;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextLexer;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext.WordContext;
import speiger.src.coreengine.rendering.guiOld.renderer.provider.IFontProvider;
import speiger.src.coreengine.rendering.models.DrawCall;
import speiger.src.coreengine.rendering.tesselationOld.IVertexBuilder;
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;
import speiger.src.coreengine.rendering.tesselationOld.VertexType;
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
import speiger.src.coreengine.utils.helpers.TextUtil;
public class FontRenderer implements IFontRenderer
{
public static final String INVALID_SEARCH = new String(" §<");
public static final int EMPTY = (char)0;
public static final int SPACE = ' ';
public static final int TAB = '\t';
public static final int LINE_SEPERATOR = '\n';
Tesselator bufferBuilder = new Tesselator(655340);
IFontProvider provider;
final TextLexer lexer = new TextLexer(this);
final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer();
public void setProvider(IFontProvider provider)
{
this.provider = provider;
}
@Override
public CharInstance getInstance(int codepoint, boolean isBold)
{
return provider.getCharacter(codepoint, isBold);
}
@Override
public float height()
{
return provider.height();
}
@Override
public float baseLine()
{
return provider.baseLine();
}
@Override
public ITexture getTexture()
{
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)
{
if(text.isEmpty()) return ObjectLists.empty();
List<DrawCall> drawCalls = new ObjectArrayList<>();
TextContext context = new TextContext(1F, 0);
List<Line> lines = lexer.evaluateLines(text, context, Float.MAX_VALUE);
if(lines.isEmpty()) return ObjectLists.empty();
WordContext effects = context.getEffect();
int textColor = effects.color;
float yOffset = 0F;
IVertexBuilder builder = new TranslatedVertexBuilder(bufferBuilder, x, y, z, 1F);
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.IN_WORLD_UI);
for(int i = 0,m=lines.size();i<m;i++)
{
float xOffset = 9F;
for(CharInstance letter : lines.get(i).letterIterator())
{
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
}
yOffset += height() * context.getScale();
}
bufferBuilder.finishData();
if(bufferBuilder.getVertexCount() > 0)
{
drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureId()));
}
bufferBuilder.setOffset(0F, 0F, 0F);
return drawCalls;
}
@Override
public void updateText(TextComponent component)
{
RenderBuffer buffer = component.getBuffer();
buffer.clear();
if(component.getText().isEmpty())
{
return;
}
TextContext context = new TextContext(component);
float boxWidth = component.getBox().getWidth();
float boxHeight = component.getBox().getHeight();
List<Line> lines = lexer.evaluateLines(component.getText(), context, component.isWidthLimited() ? boxWidth : Float.MAX_VALUE);
if(lines.isEmpty())
{
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();
float maxWidth = 0F;
float yOffset = component.getVertical().align(boxHeight, maxHeight);
float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth());
component.getMetadata().setStart(startX, yOffset);
WordContext effects = context.getEffect();
while(effects.isNext(0))
{
effects = effects.next();
}
int textColor = effects.color;
Float strikeThrough = effects.strike_through ? startX : null;
Float underline = effects.underline ? startX : -1F;
if(component.getBackgroundColor() != null)
{
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).setOffset(0F, 0F, -0.001F);
addBackground(tes, lines, maxLanes, yOffset, component.getHorizontal(), boxWidth, component.getBackgroundColor(), false);
tes.setOffset(0F, 0F, 0F);
buffer.finishShape(0);
}
for(int i = 0, index = 0;i < maxLanes;i++)
{
float xOffset = component.getHorizontal().align(boxWidth, lines.get(i).getWidth());
maxWidth = Math.max(maxWidth, lines.get(i).getWidth());
strikeThrough = effects.strike_through ? xOffset : null;
underline = effects.underline ? xOffset : null;
for(CharInstance letter : lines.get(i).letterIterator())
{
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, bufferBuilder, false);
if(effects.isNext(++index))
{
WordContext next = effects.next();
Float newStrike = getValue(effects.strike_through, next.strike_through, xOffset, strikeThrough);
if(newStrike == null && strikeThrough != null)
{
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
}
strikeThrough = newStrike;
Float newLine = getValue(effects.underline, next.underline, xOffset, strikeThrough);
if(newLine == null && underline != null)
{
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
}
textColor = next.color;
underline = newLine;
effects = next;
}
}
if(strikeThrough != null)
{
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
}
if(underline != null)
{
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
}
yOffset += height() * context.getScale();
component.getMetadata().addLine(lines.get(i));
}
maxWidth /= 2;
buffer.finishShape(getTexture().getTextureId(), bufferBuilder);
if(lineBuffer.hasData())
{
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F);
lineBuffer.merge(tes);
tes.setOffset(0F, 0F, 0F);
buffer.finishShape(0);
}
}
protected float renderChar(CharInstance instance, float x, float y, float scale, float italic, boolean flipped, int color, IVertexBuilder buffer, boolean flipPos)
{
switch(instance.getCharacter())
{
case TAB:
return provider.getTabWidth() * scale;
case SPACE:
return provider.getSpaceWidth() * scale;
}
if(instance.getXAdvance() <= 0F)
{
return 0F;
}
if(flipPos) flipped = !flipped;
float minX = x;
float minY = y;
float maxX = x + (instance.getWidth() * scale);
float maxY = flipPos ? y - (instance.getHeight() * scale) : y + (instance.getHeight() * scale);
float minV = flipped ? instance.getMaxV() : instance.getMinV();
float maxV = flipped ? instance.getMinV() : instance.getMaxV();
buffer.pos(minX - italic, maxY, 0F).tex(instance.getMinU(), maxV).color4f(color).endVertex();
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
buffer.pos(maxX + italic, minY, 0F).tex(instance.getMaxU(), minV).color4f(color).endVertex();
return instance.getXAdvance() * scale;
}
protected void addBackground(IVertexBuilder tes, List<Line> lines, int maxLines, float yPos, Align align, float width, int color, boolean flipPos)
{
for(int i = 0;i < maxLines;i++)
{
float lineWidth = lines.get(i).getWidth();
float xOffset = align.align(width, lineWidth);
float maxY = flipPos ? yPos - height() : yPos + height();
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();
tes.pos(xOffset + lineWidth, 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, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
yPos = maxY;
}
}
protected void addUnderline(float xStart, float width, float yStart, int color, IVertexBuilder buffer, boolean flipPos)
{
float minY = yStart + baseLine() + 0.5F;
float maxY = yStart + baseLine() + 1.5F;
if(flipPos)
{
minY = yStart - baseLine() - 0.5F;
maxY = yStart - baseLine() - 1.5F;
}
buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
}
protected void addStrikeThrough(float xStart, float width, float yStart, int color, IVertexBuilder buffer)
{
float minY = yStart + height() / 2.0F;
float maxY = yStart + height() / 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();
buffer.pos(xStart + width, 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, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
}
protected Float getValue(boolean oldValue, boolean newValue, Float position, Float oldPosition)
{
if((position == null && oldPosition == null) || (position != null && oldPosition != null)) return oldPosition;
return newValue ? position : null;
}
@Override
public String trimToWidth(String text, float limit, boolean reverse)
{
StringBuilder builder = new StringBuilder();
float width = 0F;
int start = reverse ? text.length() - 1 : 0;
int direction = reverse ? -1 : 1;
for(int i = start;i >= 0 && i < text.length() && width < limit;i += direction)
{
char letter = text.charAt(i);
width += width(letter);
if(width > limit) break;
if(reverse) builder.insert(0, letter);
else builder.append(letter);
}
return builder.toString();
}
@Override
public float width(int codepoint, boolean bold)
{
switch(codepoint)
{
case SPACE:
return provider.getSpaceWidth();
case TAB:
return provider.getTabWidth();
default:
CharInstance instance = getInstance(codepoint, bold);
return instance == null ? 0F : instance.getXAdvance();
}
}
@Override
public float width(String text, int flags)
{
float result = 0.0F;
float current = 0.0F;
boolean bold = (flags & BOLD) != 0;
for(int i = 0;i < text.length();i++)
{
char character = text.charAt(i);
if(LINE_SEPERATOR == character)
{
result = Math.max(result, current += provider.getSpaceWidth());
current = 0.0F;
continue;
}
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
{
String search = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
if(search.length() > 0)
{
for(String entry : search.toLowerCase(Locale.ROOT).split(","))
{
bold = TextUtil.findFlag(entry, "bold", bold);
}
i += search.length() + 2;
continue;
}
}
current += width(character, bold);
}
return Math.max(result, current);
}
@Override
public float[] widths(String text, int flags)
{
FloatList results = new FloatArrayList();
results.add(0F);
float current = 0F;
int chars = 0;
boolean bold = (flags & BOLD) != 0;
float max = 0F;
for(int i = 0;i < text.length();i++)
{
char character = text.charAt(i);
if(LINE_SEPERATOR == character)
{
results.add(current);
max = Math.max(max, current);
current = 0F;
chars = 0;
continue;
}
chars++;
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
{
String result = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
if(result.length() > 0)
{
for(String entry : result.toLowerCase(Locale.ROOT).split(","))
{
bold = TextUtil.findFlag(entry, "bold", bold);
}
i += result.length() + 2;
continue;
}
}
current += width(character, bold);
}
if(chars++ > 0)
{
results.add(current);
max = Math.max(max, current);
}
results.set(0, max);
return results.toFloatArray();
}
@Override
public float height(String text, int flags)
{
return widths(text, flags).length - 1 * height();
}
@Override
public boolean isCharValid(int codepoint)
{
return provider.isCharacterValid(codepoint);
}
@Override
public String[] split(String text, float maxWidth, int flags)
{
TextContext context = new TextContext(1F, ((flags & IFontRenderer.SPECIAL) != 0 ? 16 : 0) | ((flags & IFontRenderer.BOLD) != 0 ? 1 : 0));
List<Line> lines = lexer.evaluateLines(text, context, maxWidth);
String[] array = new String[lines.size()];
if(context.allowsSpecial())
{
int index = 0;
StringBuilder builder = new StringBuilder();
WordContext wordContext = context.getEffect();
while(wordContext.isNext(0))
{
builder.append(wordContext.getString(false));
wordContext = wordContext.next();
}
for(int i = 0,m=lines.size();i<m;i++)
{
if(i != 0) builder.append(wordContext.getString(true));
for(CharInstance letter : lines.get(i).letterIterator())
{
builder.append(letter.getCharacter());
if(wordContext.isNext(++index))
{
wordContext = wordContext.next();
builder.append(wordContext.getString(false));
}
}
array[i] = builder.toString();
builder.setLength(0);
}
}
else
{
for(int i = 0,m=lines.size();i<m;i++) array[i] = lines.get(i).getText();
}
return array;
}
}
package speiger.src.coreengine.rendering.guiOld.renderer;
import java.util.List;
import java.util.Locale;
import org.lwjgl.opengl.GL11;
import speiger.src.collections.floats.lists.FloatArrayList;
import speiger.src.collections.floats.lists.FloatList;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.DelayedRenderBuffer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.TranslatedVertexBuilder;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.Line;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext.WordContext;
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextLexer;
import speiger.src.coreengine.rendering.guiOld.renderer.provider.IFontProvider;
import speiger.src.coreengine.rendering.models.DrawCall;
import speiger.src.coreengine.rendering.tesselationOld.IVertexBuilder;
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;
import speiger.src.coreengine.rendering.tesselationOld.VertexType;
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
import speiger.src.coreengine.utils.helpers.TextUtil;
public class FontRenderer implements IFontRenderer
{
public static final String INVALID_SEARCH = new String(" §<");
public static final int EMPTY = (char)0;
public static final int SPACE = ' ';
public static final int TAB = '\t';
public static final int LINE_SEPERATOR = '\n';
Tesselator bufferBuilder = new Tesselator(655340);
IFontProvider provider;
final TextLexer lexer = new TextLexer(this);
final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer();
public void setProvider(IFontProvider provider)
{
this.provider = provider;
}
@Override
public CharInstance getInstance(int codepoint, boolean isBold)
{
return provider.getCharacter(codepoint, isBold);
}
@Override
public float height()
{
return provider.height();
}
@Override
public float baseLine()
{
return provider.baseLine();
}
@Override
public ITexture getTexture()
{
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)
{
if(text.isEmpty()) return ObjectLists.empty();
List<DrawCall> drawCalls = new ObjectArrayList<>();
TextContext context = new TextContext(1F, 0);
List<Line> lines = lexer.evaluateLines(text, context, Float.MAX_VALUE);
if(lines.isEmpty()) return ObjectLists.empty();
WordContext effects = context.getEffect();
int textColor = effects.color;
float yOffset = 0F;
IVertexBuilder builder = new TranslatedVertexBuilder(bufferBuilder, x, y, z, 1F);
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.IN_WORLD_UI);
for(int i = 0,m=lines.size();i<m;i++)
{
float xOffset = 9F;
for(CharInstance letter : lines.get(i).letterIterator())
{
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
}
yOffset += height() * context.getScale();
}
bufferBuilder.finishData();
if(bufferBuilder.getVertexCount() > 0)
{
drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureId()));
}
bufferBuilder.setOffset(0F, 0F, 0F);
return drawCalls;
}
@Override
public void updateText(TextComponent component)
{
RenderBuffer buffer = component.getBuffer();
buffer.clear();
if(component.getText().isEmpty())
{
return;
}
TextContext context = new TextContext(component);
float boxWidth = component.getBox().getWidth();
float boxHeight = component.getBox().getHeight();
List<Line> lines = lexer.evaluateLines(component.getText(), context, component.isWidthLimited() ? boxWidth : Float.MAX_VALUE);
if(lines.isEmpty())
{
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();
float maxWidth = 0F;
float yOffset = component.getVertical().align(boxHeight, maxHeight);
float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth());
component.getMetadata().setStart(startX, yOffset);
WordContext effects = context.getEffect();
while(effects.isNext(0))
{
effects = effects.next();
}
int textColor = effects.color;
Float strikeThrough = effects.strike_through ? startX : null;
Float underline = effects.underline ? startX : -1F;
if(component.getBackgroundColor() != null)
{
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).setOffset(0F, 0F, -0.001F);
addBackground(tes, lines, maxLanes, yOffset, component.getHorizontal(), boxWidth, component.getBackgroundColor(), false);
tes.setOffset(0F, 0F, 0F);
buffer.finishShape(0);
}
for(int i = 0, index = 0;i < maxLanes;i++)
{
float xOffset = component.getHorizontal().align(boxWidth, lines.get(i).getWidth());
maxWidth = Math.max(maxWidth, lines.get(i).getWidth());
strikeThrough = effects.strike_through ? xOffset : null;
underline = effects.underline ? xOffset : null;
for(CharInstance letter : lines.get(i).letterIterator())
{
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, bufferBuilder, false);
if(effects.isNext(++index))
{
WordContext next = effects.next();
Float newStrike = getValue(effects.strike_through, next.strike_through, xOffset, strikeThrough);
if(newStrike == null && strikeThrough != null)
{
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
}
strikeThrough = newStrike;
Float newLine = getValue(effects.underline, next.underline, xOffset, strikeThrough);
if(newLine == null && underline != null)
{
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
}
textColor = next.color;
underline = newLine;
effects = next;
}
}
if(strikeThrough != null)
{
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
}
if(underline != null)
{
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
}
yOffset += height() * context.getScale();
component.getMetadata().addLine(lines.get(i));
}
maxWidth /= 2;
buffer.finishShape(getTexture().getTextureId(), bufferBuilder);
if(lineBuffer.hasData())
{
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F);
lineBuffer.merge(tes);
tes.setOffset(0F, 0F, 0F);
buffer.finishShape(0);
}
}
protected float renderChar(CharInstance instance, float x, float y, float scale, float italic, boolean flipped, int color, IVertexBuilder buffer, boolean flipPos)
{
switch(instance.getCharacter())
{
case TAB:
return provider.getTabWidth() * scale;
case SPACE:
return provider.getSpaceWidth() * scale;
}
if(instance.getXAdvance() <= 0F)
{
return 0F;
}
if(flipPos) flipped = !flipped;
float minX = x;
float minY = y;
float maxX = x + (instance.getWidth() * scale);
float maxY = flipPos ? y - (instance.getHeight() * scale) : y + (instance.getHeight() * scale);
float minV = flipped ? instance.getMaxV() : instance.getMinV();
float maxV = flipped ? instance.getMinV() : instance.getMaxV();
buffer.pos(minX - italic, maxY, 0F).tex(instance.getMinU(), maxV).color4f(color).endVertex();
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
buffer.pos(maxX + italic, minY, 0F).tex(instance.getMaxU(), minV).color4f(color).endVertex();
return instance.getXAdvance() * scale;
}
protected void addBackground(IVertexBuilder tes, List<Line> lines, int maxLines, float yPos, Align align, float width, int color, boolean flipPos)
{
for(int i = 0;i < maxLines;i++)
{
float lineWidth = lines.get(i).getWidth();
float xOffset = align.align(width, lineWidth);
float maxY = flipPos ? yPos - height() : yPos + height();
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();
tes.pos(xOffset + lineWidth, 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, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
yPos = maxY;
}
}
protected void addUnderline(float xStart, float width, float yStart, int color, IVertexBuilder buffer, boolean flipPos)
{
float minY = yStart + baseLine() + 0.5F;
float maxY = yStart + baseLine() + 1.5F;
if(flipPos)
{
minY = yStart - baseLine() - 0.5F;
maxY = yStart - baseLine() - 1.5F;
}
buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
buffer.pos(xStart + width, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
}
protected void addStrikeThrough(float xStart, float width, float yStart, int color, IVertexBuilder buffer)
{
float minY = yStart + height() / 2.0F;
float maxY = yStart + height() / 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();
buffer.pos(xStart + width, 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, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
}
protected Float getValue(boolean oldValue, boolean newValue, Float position, Float oldPosition)
{
if((position == null && oldPosition == null) || (position != null && oldPosition != null)) return oldPosition;
return newValue ? position : null;
}
@Override
public String trimToWidth(String text, float limit, boolean reverse)
{
StringBuilder builder = new StringBuilder();
float width = 0F;
int start = reverse ? text.length() - 1 : 0;
int direction = reverse ? -1 : 1;
for(int i = start;i >= 0 && i < text.length() && width < limit;i += direction)
{
char letter = text.charAt(i);
width += width(letter);
if(width > limit) break;
if(reverse) builder.insert(0, letter);
else builder.append(letter);
}
return builder.toString();
}
@Override
public float width(int codepoint, boolean bold)
{
switch(codepoint)
{
case SPACE:
return provider.getSpaceWidth();
case TAB:
return provider.getTabWidth();
default:
CharInstance instance = getInstance(codepoint, bold);
return instance == null ? 0F : instance.getXAdvance();
}
}
@Override
public float width(String text, int flags)
{
float result = 0.0F;
float current = 0.0F;
boolean bold = (flags & BOLD) != 0;
for(int i = 0;i < text.length();i++)
{
char character = text.charAt(i);
if(LINE_SEPERATOR == character)
{
result = Math.max(result, current += provider.getSpaceWidth());
current = 0.0F;
continue;
}
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
{
String search = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
if(search.length() > 0)
{
for(String entry : search.toLowerCase(Locale.ROOT).split(","))
{
bold = TextUtil.findFlag(entry, "bold", bold);
}
i += search.length() + 2;
continue;
}
}
current += width(character, bold);
}
return Math.max(result, current);
}
@Override
public float[] widths(String text, int flags)
{
FloatList results = new FloatArrayList();
results.add(0F);
float current = 0F;
int chars = 0;
boolean bold = (flags & BOLD) != 0;
float max = 0F;
for(int i = 0;i < text.length();i++)
{
char character = text.charAt(i);
if(LINE_SEPERATOR == character)
{
results.add(current);
max = Math.max(max, current);
current = 0F;
chars = 0;
continue;
}
chars++;
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
{
String result = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
if(result.length() > 0)
{
for(String entry : result.toLowerCase(Locale.ROOT).split(","))
{
bold = TextUtil.findFlag(entry, "bold", bold);
}
i += result.length() + 2;
continue;
}
}
current += width(character, bold);
}
if(chars++ > 0)
{
results.add(current);
max = Math.max(max, current);
}
results.set(0, max);
return results.toFloatArray();
}
@Override
public float height(String text, int flags)
{
return widths(text, flags).length - 1 * height();
}
@Override
public boolean isCharValid(int codepoint)
{
return provider.isCharacterValid(codepoint);
}
@Override
public String[] split(String text, float maxWidth, int flags)
{
TextContext context = new TextContext(1F, ((flags & IFontRenderer.SPECIAL) != 0 ? 16 : 0) | ((flags & IFontRenderer.BOLD) != 0 ? 1 : 0));
List<Line> lines = lexer.evaluateLines(text, context, maxWidth);
String[] array = new String[lines.size()];
if(context.allowsSpecial())
{
int index = 0;
StringBuilder builder = new StringBuilder();
WordContext wordContext = context.getEffect();
while(wordContext.isNext(0))
{
builder.append(wordContext.getString(false));
wordContext = wordContext.next();
}
for(int i = 0,m=lines.size();i<m;i++)
{
if(i != 0) builder.append(wordContext.getString(true));
for(CharInstance letter : lines.get(i).letterIterator())
{
builder.append(letter.getCharacter());
if(wordContext.isNext(++index))
{
wordContext = wordContext.next();
builder.append(wordContext.getString(false));
}
}
array[i] = builder.toString();
builder.setLength(0);
}
}
else
{
for(int i = 0,m=lines.size();i<m;i++) array[i] = lines.get(i).getText();
}
return array;
}
}

View File

@ -1,143 +1,143 @@
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
import java.awt.image.BufferedImage;
import java.util.List;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
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.base.IAsset;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder;
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder.WrittenChar;
import speiger.src.coreengine.rendering.guiOld.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class BitmapFontProvider implements IFontProvider
{
FontInfo info;
ITexture texture;
Int2ObjectMap<CharInstance>[] instances;
float space;
public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap<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(int codepoint)
{
return instances[0].containsKey(codepoint) || instances[1].containsKey(codepoint);
}
@Override
public CharInstance getCharacter(int codepoint, boolean bold)
{
Int2ObjectMap<CharInstance> map = instances[bold ? 1 : 0];
return (map.isEmpty() ? instances[bold ? 0 : 1] : map).get(codepoint);
}
@Override
public float height()
{
return info.fontHeight;
}
@Override
public float baseLine()
{
return info.fontBase;
}
@Override
public float getSpaceWidth()
{
return space;
}
@Override
public float getTabWidth()
{
return space * info.tabs;
}
@SuppressWarnings("unchecked")
public static BitmapFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
{
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
float multiplier = info.setDesiredHeight(desiredSize);
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<>(), new Int2ObjectOpenHashMap<>()};
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] = Int2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
return new BitmapFontProvider(info, ITexture.simple(AssetLocation.of(object.get("file").getAsString())), maps);
}
@SuppressWarnings("unchecked")
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.stream(), 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.y(), size.x(), tabs);
float mulitplier = fontInfo.setDesiredHeight(desiredSize);
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<CharInstance>(), new Int2ObjectOpenHashMap<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] = Int2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
return new BitmapFontProvider(fontInfo, ITexture.direct(image), maps);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
import java.awt.image.BufferedImage;
import java.util.List;
import com.google.gson.JsonObject;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
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.base.IAsset;
import speiger.src.coreengine.math.vector.ints.Vec2i;
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder;
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder.WrittenChar;
import speiger.src.coreengine.rendering.guiOld.renderer.IFontRenderer.CharInstance;
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class BitmapFontProvider implements IFontProvider
{
FontInfo info;
ITexture texture;
Int2ObjectMap<CharInstance>[] instances;
float space;
public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap<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(int codepoint)
{
return instances[0].containsKey(codepoint) || instances[1].containsKey(codepoint);
}
@Override
public CharInstance getCharacter(int codepoint, boolean bold)
{
Int2ObjectMap<CharInstance> map = instances[bold ? 1 : 0];
return (map.isEmpty() ? instances[bold ? 0 : 1] : map).get(codepoint);
}
@Override
public float height()
{
return info.fontHeight;
}
@Override
public float baseLine()
{
return info.fontBase;
}
@Override
public float getSpaceWidth()
{
return space;
}
@Override
public float getTabWidth()
{
return space * info.tabs;
}
@SuppressWarnings("unchecked")
public static BitmapFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
{
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
float multiplier = info.setDesiredHeight(desiredSize);
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<>(), new Int2ObjectOpenHashMap<>()};
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] = Int2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
return new BitmapFontProvider(info, ITexture.simple(AssetLocation.of(object.get("file").getAsString())), maps);
}
@SuppressWarnings("unchecked")
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.stream(), 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.y(), size.x(), tabs);
float mulitplier = fontInfo.setDesiredHeight(desiredSize);
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<CharInstance>(), new Int2ObjectOpenHashMap<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] = Int2ObjectMaps.empty();
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
return new BitmapFontProvider(fontInfo, ITexture.direct(image), maps);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}

View File

@ -1,100 +1,100 @@
package speiger.src.coreengine.rendering.guiOld.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.base.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.rendering.guiOld.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.json();
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();
}
package speiger.src.coreengine.rendering.guiOld.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.base.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.rendering.guiOld.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.json();
IFontLoader loader = loaders.get(obj.get("type").getAsString());
if(loader == null) return null;
return loader.create(obj, desiredSize, manager);
}
catch(Exception e) { e.printStackTrace(); }
return null;
}
public static interface IFontLoader
{
public IFontProvider create(JsonObject obj, float desiredSize, AssetManager loader);
}
@Override
public void reload()
{
List<IFontProvider> providers = new ObjectArrayList<>();
for(Entry<AssetLocation> entry : Object2FloatMaps.fastIterable(fontSizes))
{
AssetLocation location = entry.getKey();
FontRenderer font = fontRenders.get(location);
providers.add(font.getProvider());
font.setProvider(loadProvider(location, entry.getFloatValue()));
}
for(int i = 0,m=providers.size();i<m;providers.get(i++).destroy());
}
@Override
public void destroy()
{
fontRenders.values().forEach(FontRenderer::destory);
fontRenders.clear();
}
}

View File

@ -66,10 +66,10 @@ public class Window
protected void initWindowListeners() {
addCallback(T -> GLFW.glfwSetFramebufferSizeCallback(T, this::onResize));
addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (K, V) -> flags.setFlag(FLAG_WINDOW_CHANGE)));
addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (W, X, Y) -> setPosition(X, Y)));
addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (K, V) -> flags.setFlag(FLAG_FOCUS, V)));
addCallback(T -> GLFW.glfwSetErrorCallback(this::error));
addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (_, _) -> flags.setFlag(FLAG_WINDOW_CHANGE)));
addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (_, X, Y) -> setPosition(X, Y)));
addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (_, V) -> flags.setFlag(FLAG_FOCUS, V)));
addCallback(_ -> GLFW.glfwSetErrorCallback(this::error));
}
private void error(int error, long text) {

View File

@ -1,103 +1,103 @@
package speiger.src.coreengine.rendering.models.loader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.UUID;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class ModelLoader
{
public static List<SimpleModelData> readModelData(AssetLocation location, AssetManager manager)
{
try(IAsset asset = manager.getAsset(location))
{
List<SimpleModelData> result = new ObjectArrayList<>();
JsonObject obj = asset.json();
JsonUtil.iterate(obj.get("models"), T -> {
JsonObject info = T.getAsJsonObject("info");
JsonObject format = T.getAsJsonObject("format");
JsonObject data = T.getAsJsonObject("data");
List<VertexEntry> entries = VertexLoader.loadVertexFormat(format);
ByteBuffer buffer = VertexLoader.parseVertexData(data, info.get("vertecies").getAsInt(), entries, true);
result.add(new SimpleModelData(info.get("name").getAsString(), UUID.fromString(info.get("id").getAsString()), buffer.array(), JsonUtil.parseIntArray(data.getAsJsonArray("indecies"))));
});
return result;
}
catch(Exception e)
{
e.printStackTrace();
}
return ObjectLists.empty();
}
public static List<SimpleModelData> readLegacyModelData(AssetLocation location, AssetManager manager)
{
List<SimpleModelData> resultModels = new ObjectArrayList<SimpleModelData>();
ByteBuffer buffer = null;
int[] indexes = null;
String currentName = null;
try(IAsset asset = manager.getAsset(location))
{
boolean flag = false;
for(String line : IterableWrapper.wrap(asset.reader()))
{
if(line.startsWith("{"))
{
if(currentName != null)
{
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
currentName = null;
}
currentName = line.substring(1, line.length() - 1);
flag = true;
}
else if(flag)
{
flag = false;
String[] bounds = line.split(";");
buffer = ByteBuffer.allocate(Integer.parseInt(bounds[0]) * 28).order(ByteOrder.nativeOrder());
indexes = new int[Integer.parseInt(bounds[1])];
}
else if(line.startsWith("<"))
{
String[] data = line.substring(1, line.length() - 1).split(" ");
String[] position = data[0].split(";");
String[] normal = data[2].split(";");
buffer.putFloat(Float.parseFloat(position[0])).putFloat(Float.parseFloat(position[1])).putFloat(Float.parseFloat(position[2]));
ColorUtils.write(Integer.parseInt(data[1]), true, buffer);
buffer.putFloat(Float.parseFloat(normal[0])).putFloat(Float.parseFloat(normal[1])).putFloat(Float.parseFloat(normal[2]));
}
else if(line.startsWith("["))
{
String[] data = line.substring(1, line.length() - 1).split(";");
for(int j = 0;j<data.length;j++)
{
indexes[j] = Integer.parseInt(data[j]);
}
}
}
if(currentName != null)
{
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
currentName = null;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return resultModels;
}
}
package speiger.src.coreengine.rendering.models.loader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.UUID;
import com.google.gson.JsonObject;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.utils.ObjectLists;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
import speiger.src.coreengine.utils.helpers.JsonUtil;
public class ModelLoader
{
public static List<SimpleModelData> readModelData(AssetLocation location, AssetManager manager)
{
try(IAsset asset = manager.getAsset(location))
{
List<SimpleModelData> result = new ObjectArrayList<>();
JsonObject obj = asset.json();
JsonUtil.iterate(obj.get("models"), T -> {
JsonObject info = T.getAsJsonObject("info");
JsonObject format = T.getAsJsonObject("format");
JsonObject data = T.getAsJsonObject("data");
List<VertexEntry> entries = VertexLoader.loadVertexFormat(format);
ByteBuffer buffer = VertexLoader.parseVertexData(data, info.get("vertecies").getAsInt(), entries, true);
result.add(new SimpleModelData(info.get("name").getAsString(), UUID.fromString(info.get("id").getAsString()), buffer.array(), JsonUtil.parseIntArray(data.getAsJsonArray("indecies"))));
});
return result;
}
catch(Exception e)
{
e.printStackTrace();
}
return ObjectLists.empty();
}
public static List<SimpleModelData> readLegacyModelData(AssetLocation location, AssetManager manager)
{
List<SimpleModelData> resultModels = new ObjectArrayList<SimpleModelData>();
ByteBuffer buffer = null;
int[] indexes = null;
String currentName = null;
try(IAsset asset = manager.getAsset(location))
{
boolean flag = false;
for(String line : IterableWrapper.wrap(asset.reader()))
{
if(line.startsWith("{"))
{
if(currentName != null)
{
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
currentName = null;
}
currentName = line.substring(1, line.length() - 1);
flag = true;
}
else if(flag)
{
flag = false;
String[] bounds = line.split(";");
buffer = ByteBuffer.allocate(Integer.parseInt(bounds[0]) * 28).order(ByteOrder.nativeOrder());
indexes = new int[Integer.parseInt(bounds[1])];
}
else if(line.startsWith("<"))
{
String[] data = line.substring(1, line.length() - 1).split(" ");
String[] position = data[0].split(";");
String[] normal = data[2].split(";");
buffer.putFloat(Float.parseFloat(position[0])).putFloat(Float.parseFloat(position[1])).putFloat(Float.parseFloat(position[2]));
ColorUtils.write(Integer.parseInt(data[1]), true, buffer);
buffer.putFloat(Float.parseFloat(normal[0])).putFloat(Float.parseFloat(normal[1])).putFloat(Float.parseFloat(normal[2]));
}
else if(line.startsWith("["))
{
String[] data = line.substring(1, line.length() - 1).split(";");
for(int j = 0;j<data.length;j++)
{
indexes[j] = Integer.parseInt(data[j]);
}
}
}
if(currentName != null)
{
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
currentName = null;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return resultModels;
}
}

View File

@ -1,137 +1,137 @@
package speiger.src.coreengine.rendering.shader;
import java.nio.ByteBuffer;
import java.nio.file.attribute.FileTime;
import java.util.Map;
import java.util.function.IntPredicate;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL41;
import org.lwjgl.opengl.GL45;
import org.lwjgl.opengl.GL46;
import org.lwjgl.system.MemoryUtil;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.math.ArrayUtil;
import speiger.src.coreengine.rendering.shader.uniform.UniformManager;
import speiger.src.coreengine.rendering.utils.GLStateTracker;
import speiger.src.coreengine.rendering.utils.values.IGLValue.IShaderType;
import speiger.src.coreengine.utils.io.GameLog;
public abstract class ShaderProgram {
static final Map<AssetLocation, String> IMPORTS = Object2ObjectMap.builder().<AssetLocation, String>map().synchronize();
protected final UniformManager uniforms = new UniformManager(this);
private int id;
public boolean isValid() { return id != 0; }
public boolean isActive() { return GLStateTracker.instance().shaders.isShaderActive(this); }
public int id() { return id; }
public UniformManager getUniforms() { return uniforms; }
protected void setId(int id) {
this.id = id;
}
public void bind() {
GLStateTracker.instance().shaders.bind(this);
uniforms.bind();
}
public void remove() {
if(id == 0) return;
uniforms.remove();
GL20.glDeleteProgram(id);
id = 0;
}
public void validateProgram() {
if(id == 0) return;
uniforms.validate();
GL46.glValidateProgram(id);
}
public static int loadOrGenerateCache(String location, FileTime newestResource, IntPredicate callback) {
int id = GL20.glCreateProgram();
boolean fail = true;
if((fail = !loadFromBinary(id, location, newestResource)) && callback.test(id)) {
if(GL46.glGetProgrami(id, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) {
if(ShaderCache.INSTANCE.hasCache()) ShaderCache.INSTANCE.storeInCache(location, getProgramBytes(id));
fail = false;
}
}
if(fail) {
GL20.glDeleteProgram(id);
return 0;
}
String error = GL45.glGetProgramInfoLog(id);
if(!error.isBlank()) {
System.out.println("Error: "+error);
}
return id;
}
private static boolean loadFromBinary(int programId, String location, FileTime newestResource) {
ByteBuffer buffer = ShaderCache.INSTANCE.readFromCache(location, newestResource);
if(buffer != null) {
GL41.glProgramBinary(programId, buffer.getInt(), buffer);
MemoryUtil.memFree(buffer);
if(GL46.glGetProgrami(programId, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) return true;
}
return false;
}
private static byte[] getProgramBytes(int programId) {
ByteBuffer buffer = MemoryUtil.memAlloc(GL20.glGetProgrami(programId, GL41.GL_PROGRAM_BINARY_LENGTH) + 4);
int[] format = new int[1];
GL41.glGetProgramBinary(programId, null, format, buffer.position(4));
return ArrayUtil.toArray(buffer.putInt(0, format[0]).flip(), MemoryUtil::memFree);
}
public static int loadShader(IAssetProvider provider, AssetLocation location, IShaderType type) {
StringBuilder builder = new StringBuilder(2048);
try(IAsset asset = provider.getAsset(location)) {
for(String line : asset.lines()) {
if(line.startsWith("//")) continue;
if(line.startsWith("#import<") && line.endsWith(">")) {
builder.append(importLines(provider, AssetLocation.of(line.substring(8, line.length()-1)))).append("\n");
continue;
}
builder.append(line).append("\n");
}
}
catch(Exception e) {
e.printStackTrace();
return -1;
}
int shaderID = GL20.glCreateShader(type.glValue());
GL20.glShaderSource(shaderID, builder);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
GameLog.warn("Could not compile shader " + location);
GameLog.error(GL20.glGetShaderInfoLog(shaderID, GL20.glGetShaderi(shaderID, GL20.GL_INFO_LOG_LENGTH)));
GL20.glDeleteShader(shaderID);
return -1;
}
return shaderID;
}
public static String importLines(IAssetProvider provider, AssetLocation location) {
return IMPORTS.computeIfAbsent(location, T -> {
try(IAsset asset = provider.getAsset(T)) {
StringBuilder builder = new StringBuilder();
for(String line : asset.lines()) {
if(line.startsWith("//")) continue;
builder.append(line).append("\n");
}
return builder.toString();
}
catch(Exception e) {
e.printStackTrace();
return "";
}
});
}
}
package speiger.src.coreengine.rendering.shader;
import java.nio.ByteBuffer;
import java.nio.file.attribute.FileTime;
import java.util.Map;
import java.util.function.IntPredicate;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL41;
import org.lwjgl.opengl.GL45;
import org.lwjgl.opengl.GL46;
import org.lwjgl.system.MemoryUtil;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.math.ArrayUtil;
import speiger.src.coreengine.rendering.shader.uniform.UniformManager;
import speiger.src.coreengine.rendering.utils.GLStateTracker;
import speiger.src.coreengine.rendering.utils.values.IGLValue.IShaderType;
import speiger.src.coreengine.utils.io.GameLog;
public abstract class ShaderProgram {
static final Map<AssetLocation, String> IMPORTS = Object2ObjectMap.builder().<AssetLocation, String>map().synchronize();
protected final UniformManager uniforms = new UniformManager(this);
private int id;
public boolean isValid() { return id != 0; }
public boolean isActive() { return GLStateTracker.instance().shaders.isShaderActive(this); }
public int id() { return id; }
public UniformManager getUniforms() { return uniforms; }
protected void setId(int id) {
this.id = id;
}
public void bind() {
GLStateTracker.instance().shaders.bind(this);
uniforms.bind();
}
public void remove() {
if(id == 0) return;
uniforms.remove();
GL20.glDeleteProgram(id);
id = 0;
}
public void validateProgram() {
if(id == 0) return;
uniforms.validate();
GL46.glValidateProgram(id);
}
public static int loadOrGenerateCache(String location, FileTime newestResource, IntPredicate callback) {
int id = GL20.glCreateProgram();
boolean fail = true;
if((fail = !loadFromBinary(id, location, newestResource)) && callback.test(id)) {
if(GL46.glGetProgrami(id, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) {
if(ShaderCache.INSTANCE.hasCache()) ShaderCache.INSTANCE.storeInCache(location, getProgramBytes(id));
fail = false;
}
}
if(fail) {
GL20.glDeleteProgram(id);
return 0;
}
String error = GL45.glGetProgramInfoLog(id);
if(!error.isBlank()) {
System.out.println("Error: "+error);
}
return id;
}
private static boolean loadFromBinary(int programId, String location, FileTime newestResource) {
ByteBuffer buffer = ShaderCache.INSTANCE.readFromCache(location, newestResource);
if(buffer != null) {
GL41.glProgramBinary(programId, buffer.getInt(), buffer);
MemoryUtil.memFree(buffer);
if(GL46.glGetProgrami(programId, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) return true;
}
return false;
}
private static byte[] getProgramBytes(int programId) {
ByteBuffer buffer = MemoryUtil.memAlloc(GL20.glGetProgrami(programId, GL41.GL_PROGRAM_BINARY_LENGTH) + 4);
int[] format = new int[1];
GL41.glGetProgramBinary(programId, null, format, buffer.position(4));
return ArrayUtil.toArray(buffer.putInt(0, format[0]).flip(), MemoryUtil::memFree);
}
public static int loadShader(IAssetProvider provider, AssetLocation location, IShaderType type) {
StringBuilder builder = new StringBuilder(2048);
try(IAsset asset = provider.getAsset(location)) {
for(String line : asset.lines()) {
if(line.startsWith("//")) continue;
if(line.startsWith("#import<") && line.endsWith(">")) {
builder.append(importLines(provider, AssetLocation.of(line.substring(8, line.length()-1)))).append("\n");
continue;
}
builder.append(line).append("\n");
}
}
catch(Exception e) {
e.printStackTrace();
return -1;
}
int shaderID = GL20.glCreateShader(type.glValue());
GL20.glShaderSource(shaderID, builder);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
GameLog.warn("Could not compile shader " + location);
GameLog.error(GL20.glGetShaderInfoLog(shaderID, GL20.glGetShaderi(shaderID, GL20.GL_INFO_LOG_LENGTH)));
GL20.glDeleteShader(shaderID);
return -1;
}
return shaderID;
}
public static String importLines(IAssetProvider provider, AssetLocation location) {
return IMPORTS.computeIfAbsent(location, T -> {
try(IAsset asset = provider.getAsset(T)) {
StringBuilder builder = new StringBuilder();
for(String line : asset.lines()) {
if(line.startsWith("//")) continue;
builder.append(line).append("\n");
}
return builder.toString();
}
catch(Exception e) {
e.printStackTrace();
return "";
}
});
}
}

View File

@ -1,109 +1,109 @@
package speiger.src.coreengine.rendering.shaderOld;
import java.util.List;
import org.lwjgl.opengl.GL20;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.rendering.shaderOld.ShaderTracker.ReloadReference;
import speiger.src.coreengine.rendering.shaderOld.uniforms.Uniform;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
import speiger.src.coreengine.utils.io.GameLog;
public abstract class ShaderProgram
{
protected List<Uniform> localUniforms = new ObjectArrayList<>();
ReloadReference<?> reference;
private int shaderID;
protected ShaderProgram(AssetLocation vertex, AssetLocation fragment, String[] attributes) {
int vertexID = loadShader(vertex, GL20.GL_VERTEX_SHADER);
int fragmentID = loadShader(fragment, GL20.GL_FRAGMENT_SHADER);
if(vertexID == -1 || fragmentID == -1) {
shaderID = 0;
return;
}
shaderID = GL20.glCreateProgram();
GL20.glAttachShader(shaderID, vertexID);
GL20.glAttachShader(shaderID, fragmentID);
for(int i = 0;i < attributes.length;i++) {
GL20.glBindAttribLocation(shaderID, i, attributes[i]);
}
GL20.glLinkProgram(shaderID);
GL20.glDetachShader(shaderID, vertexID);
GL20.glDetachShader(shaderID, fragmentID);
GL20.glDeleteShader(vertexID);
GL20.glDeleteShader(fragmentID);
}
public void addUniforms(Uniform... uniforms) {
for(Uniform uni : uniforms) {
uni.loadUniform(this);
localUniforms.add(uni);
}
GL20.glValidateProgram(shaderID);
}
void setReference(ReloadReference<?> ref) {
reference = ref;
}
public abstract ShaderProgram init();
public boolean isShaderValid() {
return shaderID != 0;
}
public int getShaderID() {
return shaderID;
}
public void startShader() {
ShaderTracker.INSTANCE.startNextShader(this);
}
public void stopShader() {
ShaderTracker.INSTANCE.stopShader(this);
}
public boolean isShaderRunning() {
return ShaderTracker.INSTANCE.activeShader == getShaderID();
}
public void removeShader() {
if(shaderID == 0) return;
stopShader();
GL20.glDeleteProgram(shaderID);
shaderID = 0;
reference.removeReference();
reference = null;
}
private int loadShader(AssetLocation location, int type) {
StringBuilder shaderSource = new StringBuilder();
try(IAsset asset = ShaderTracker.INSTANCE.getAssets().getAsset(location)) {
for(String s : IterableWrapper.wrap(asset.reader()))
{
if(s.startsWith("//")) continue;
shaderSource.append(s).append("\n");
}
}
catch(Exception e) {
e.printStackTrace();
return -1;
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
GameLog.warn("Could not compile shader " + location);
int[] length = new int[1];
GL20.glGetShaderiv(shaderID, GL20.GL_INFO_LOG_LENGTH, length);
GameLog.error(GL20.glGetShaderInfoLog(shaderID, length[0]));
return -1;
}
return shaderID;
}
}
package speiger.src.coreengine.rendering.shaderOld;
import java.util.List;
import org.lwjgl.opengl.GL20;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.rendering.shaderOld.ShaderTracker.ReloadReference;
import speiger.src.coreengine.rendering.shaderOld.uniforms.Uniform;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
import speiger.src.coreengine.utils.io.GameLog;
public abstract class ShaderProgram
{
protected List<Uniform> localUniforms = new ObjectArrayList<>();
ReloadReference<?> reference;
private int shaderID;
protected ShaderProgram(AssetLocation vertex, AssetLocation fragment, String[] attributes) {
int vertexID = loadShader(vertex, GL20.GL_VERTEX_SHADER);
int fragmentID = loadShader(fragment, GL20.GL_FRAGMENT_SHADER);
if(vertexID == -1 || fragmentID == -1) {
shaderID = 0;
return;
}
shaderID = GL20.glCreateProgram();
GL20.glAttachShader(shaderID, vertexID);
GL20.glAttachShader(shaderID, fragmentID);
for(int i = 0;i < attributes.length;i++) {
GL20.glBindAttribLocation(shaderID, i, attributes[i]);
}
GL20.glLinkProgram(shaderID);
GL20.glDetachShader(shaderID, vertexID);
GL20.glDetachShader(shaderID, fragmentID);
GL20.glDeleteShader(vertexID);
GL20.glDeleteShader(fragmentID);
}
public void addUniforms(Uniform... uniforms) {
for(Uniform uni : uniforms) {
uni.loadUniform(this);
localUniforms.add(uni);
}
GL20.glValidateProgram(shaderID);
}
void setReference(ReloadReference<?> ref) {
reference = ref;
}
public abstract ShaderProgram init();
public boolean isShaderValid() {
return shaderID != 0;
}
public int getShaderID() {
return shaderID;
}
public void startShader() {
ShaderTracker.INSTANCE.startNextShader(this);
}
public void stopShader() {
ShaderTracker.INSTANCE.stopShader(this);
}
public boolean isShaderRunning() {
return ShaderTracker.INSTANCE.activeShader == getShaderID();
}
public void removeShader() {
if(shaderID == 0) return;
stopShader();
GL20.glDeleteProgram(shaderID);
shaderID = 0;
reference.removeReference();
reference = null;
}
private int loadShader(AssetLocation location, int type) {
StringBuilder shaderSource = new StringBuilder();
try(IAsset asset = ShaderTracker.INSTANCE.getAssets().getAsset(location)) {
for(String s : IterableWrapper.wrap(asset.reader()))
{
if(s.startsWith("//")) continue;
shaderSource.append(s).append("\n");
}
}
catch(Exception e) {
e.printStackTrace();
return -1;
}
int shaderID = GL20.glCreateShader(type);
GL20.glShaderSource(shaderID, shaderSource);
GL20.glCompileShader(shaderID);
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
GameLog.warn("Could not compile shader " + location);
int[] length = new int[1];
GL20.glGetShaderiv(shaderID, GL20.GL_INFO_LOG_LENGTH, length);
GameLog.error(GL20.glGetShaderInfoLog(shaderID, length[0]));
return -1;
}
return shaderID;
}
}

View File

@ -6,8 +6,8 @@ import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.math.vector.floats.Vec3f;
import speiger.src.coreengine.rendering.models.DrawCall;
import speiger.src.coreengine.rendering.tesselation.format.VertexElement;
import speiger.src.coreengine.rendering.tesselation.format.VertexFormat;
import speiger.src.coreengine.rendering.tesselation.format.VertexElement.Usage;
import speiger.src.coreengine.rendering.tesselation.format.VertexFormat;
import speiger.src.coreengine.rendering.utils.values.GLMode;
public class Tesselator implements IVertexBuilder

View File

@ -1,8 +1,8 @@
package speiger.src.coreengine.rendering.tesselationOld;
import speiger.src.coreengine.rendering.tesselation.format.VertexElement;
import speiger.src.coreengine.rendering.tesselation.format.VertexFormat;
import speiger.src.coreengine.rendering.tesselation.format.VertexElement.Usage;
import speiger.src.coreengine.rendering.tesselation.format.VertexFormat;
public class VertexType
{

View File

@ -1,76 +1,76 @@
package speiger.src.coreengine.rendering.textures.simple;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.textures.base.BaseTexture;
import speiger.src.coreengine.rendering.textures.base.TextureMetadata;
import speiger.src.coreengine.rendering.utils.GLFunctions;
import speiger.src.coreengine.rendering.utils.values.GLDataType;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureFormat;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue;
public class SimpleTexture extends BaseTexture {
public static final TextureMetadata DEFAULT_DATA = TextureMetadata.builder()
.externalFormat(GLTextureFormat.RGBA).internalFormat(GLTextureFormat.RGBAI).dataFormat(GLDataType.UNSIGNED_BYTE).mipmapping(false)
.arguement(GLTextureParameter.MIN_FILTER, GLTextureValue.NEAREST).arguement(GLTextureParameter.MAG_FILTER, GLTextureValue.NEAREST)
.arguement(GLTextureParameter.WRAP_S, GLTextureValue.CLAMP_TO_EDGE).arguement(GLTextureParameter.WRAP_T, GLTextureValue.CLAMP_TO_EDGE).build();
AssetLocation location;
TextureMetadata metadata;
int width;
int height;
public SimpleTexture(AssetLocation location, TextureMetadata metadata) {
this.location = location;
this.metadata = metadata;
track();
}
@Override
public void load(IAssetProvider provider) {
long address = 0L;
int channel = GLTextureFormat.stbComponents(GL11.GL_RGBA);
try(IAsset asset = provider.getAsset(location)) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
int[] width = new int[1];
int[] height = new int[1];
int[] fileChannels = new int[1];
address = STBImage.nstbi_load_from_memory(MemoryUtil.memAddress(buffer), buffer.remaining(), width, height, fileChannels, channel);
MemoryUtil.memFree(buffer);
if(address == 0) {
throw new IllegalArgumentException("Couldn't load texture ["+location+"]");
}
this.width = width[0];
this.height = height[0];
if(channel == 0) channel = fileChannels[0];
}
catch(IOException e) {
e.printStackTrace();
}
if(address == 0L) return;
createTexture();
metadata.applyArguments(id());
GLFunctions.upload2DImage(id(), 0, metadata, width, height, 0, address);
if(metadata.generateMipMappings()) GLFunctions.generateMipMaps(textureType());
STBImage.nstbi_image_free(address);
}
@Override
public int width() {
return width;
}
@Override
public int height() {
return height;
}
}
package speiger.src.coreengine.rendering.textures.simple;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.stb.STBImage;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.textures.base.BaseTexture;
import speiger.src.coreengine.rendering.textures.base.TextureMetadata;
import speiger.src.coreengine.rendering.utils.GLFunctions;
import speiger.src.coreengine.rendering.utils.values.GLDataType;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureFormat;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter;
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue;
public class SimpleTexture extends BaseTexture {
public static final TextureMetadata DEFAULT_DATA = TextureMetadata.builder()
.externalFormat(GLTextureFormat.RGBA).internalFormat(GLTextureFormat.RGBAI).dataFormat(GLDataType.UNSIGNED_BYTE).mipmapping(false)
.arguement(GLTextureParameter.MIN_FILTER, GLTextureValue.NEAREST).arguement(GLTextureParameter.MAG_FILTER, GLTextureValue.NEAREST)
.arguement(GLTextureParameter.WRAP_S, GLTextureValue.CLAMP_TO_EDGE).arguement(GLTextureParameter.WRAP_T, GLTextureValue.CLAMP_TO_EDGE).build();
AssetLocation location;
TextureMetadata metadata;
int width;
int height;
public SimpleTexture(AssetLocation location, TextureMetadata metadata) {
this.location = location;
this.metadata = metadata;
track();
}
@Override
public void load(IAssetProvider provider) {
long address = 0L;
int channel = GLTextureFormat.stbComponents(GL11.GL_RGBA);
try(IAsset asset = provider.getAsset(location)) {
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
int[] width = new int[1];
int[] height = new int[1];
int[] fileChannels = new int[1];
address = STBImage.nstbi_load_from_memory(MemoryUtil.memAddress(buffer), buffer.remaining(), width, height, fileChannels, channel);
MemoryUtil.memFree(buffer);
if(address == 0) {
throw new IllegalArgumentException("Couldn't load texture ["+location+"]");
}
this.width = width[0];
this.height = height[0];
if(channel == 0) channel = fileChannels[0];
}
catch(IOException e) {
e.printStackTrace();
}
if(address == 0L) return;
createTexture();
metadata.applyArguments(id());
GLFunctions.upload2DImage(id(), 0, metadata, width, height, 0, address);
if(metadata.generateMipMappings()) GLFunctions.generateMipMaps(textureType());
STBImage.nstbi_image_free(address);
}
@Override
public int width() {
return width;
}
@Override
public int height() {
return height;
}
}

View File

@ -1,144 +1,144 @@
package speiger.src.coreengine.rendering.texturesOld.base;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.assets.reloader.ResourceReloader;
import speiger.src.coreengine.rendering.utils.GLStateTracker;
import speiger.src.coreengine.rendering.utils.states.GLState;
import speiger.src.coreengine.utils.io.GameLog;
import speiger.src.coreengine.utils.io.GameLog.LogLevel;
public class TextureManager implements IReloadableResource
{
public static final TextureManager INSTANCE = new TextureManager();
public static final GLState TEXTURE = GLStateTracker.instance().addState(new GLState(GL11.GL_TEXTURE_2D, false));
AssetManager manager;
ResourceReloader reloader = new ResourceReloader();
int[] textureBanks = new int[GL13.GL_TEXTURE31 - GL13.GL_TEXTURE0];
int activeBank = 0;
public void init(AssetManager manager)
{
this.manager = manager;
}
public ResourceReloader getReloader()
{
return reloader;
}
public void addTexture(ITexture texture)
{
if(texture != null)
{
reloader.addReloadableResource(texture);
}
}
public void removeTexture(ITexture texture)
{
if(texture != null)
{
GL11.glDeleteTextures(texture.getTextureId());
reloader.removeReloadableResource(texture);
}
}
public void removeTexture(int id)
{
GL11.glDeleteTextures(id);
}
public static void bindTexture(int texture)
{
INSTANCE.setActiveTexture(texture);
}
public static void bindTexture(int texture, int bank)
{
INSTANCE.setActiveTexture(texture, bank);
}
public static void unbindTexture()
{
INSTANCE.setActiveTexture(0);
}
public void setActiveTexture(int texture)
{
if(textureBanks[activeBank] != texture)
{
textureBanks[activeBank] = texture;
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
}
}
public void setActiveTexture(int texture, int bank)
{
if(activeBank != bank)
{
activeBank = bank;
GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeBank);
}
bindTexture(texture);
}
@Override
public void reload()
{
reloader.reloadResources();
}
@Override
public void destroy()
{
reloader.deleteResources();
}
public AssetManager getManager()
{
return manager;
}
public static GLFWImage create(AssetLocation location)
{
try(IAsset asset = INSTANCE.manager.getAsset(location))
{
BufferedImage image = asset.texture();
int width = image.getWidth();
int height = image.getHeight();
int[] pixelData = new int[width * height];
image.getRGB(0, 0, width, height, pixelData, 0, width);
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
for(int y = 0;y<height;y++)
{
for(int x = 0;x<width;x++)
{
int pixel = pixelData[(y * width) + x];
buffer.put((byte)((pixel >> 16) & 0xFF));
buffer.put((byte)((pixel >> 8) & 0xFF));
buffer.put((byte)(pixel & 0xFF));
buffer.put((byte)((pixel >> 24) & 0xFF));
}
}
GLFWImage glfw = GLFWImage.malloc();
glfw.set(width, height, buffer);
return glfw;
}
catch(Exception e)
{
GameLog.error("Couldn't Load Texture ["+location.toString()+"]", e, LogLevel.ERROR);
return null;
}
}
}
package speiger.src.coreengine.rendering.texturesOld.base;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.assets.reloader.IReloadableResource;
import speiger.src.coreengine.assets.reloader.ResourceReloader;
import speiger.src.coreengine.rendering.utils.GLStateTracker;
import speiger.src.coreengine.rendering.utils.states.GLState;
import speiger.src.coreengine.utils.io.GameLog;
import speiger.src.coreengine.utils.io.GameLog.LogLevel;
public class TextureManager implements IReloadableResource
{
public static final TextureManager INSTANCE = new TextureManager();
public static final GLState TEXTURE = GLStateTracker.instance().addState(new GLState(GL11.GL_TEXTURE_2D, false));
AssetManager manager;
ResourceReloader reloader = new ResourceReloader();
int[] textureBanks = new int[GL13.GL_TEXTURE31 - GL13.GL_TEXTURE0];
int activeBank = 0;
public void init(AssetManager manager)
{
this.manager = manager;
}
public ResourceReloader getReloader()
{
return reloader;
}
public void addTexture(ITexture texture)
{
if(texture != null)
{
reloader.addReloadableResource(texture);
}
}
public void removeTexture(ITexture texture)
{
if(texture != null)
{
GL11.glDeleteTextures(texture.getTextureId());
reloader.removeReloadableResource(texture);
}
}
public void removeTexture(int id)
{
GL11.glDeleteTextures(id);
}
public static void bindTexture(int texture)
{
INSTANCE.setActiveTexture(texture);
}
public static void bindTexture(int texture, int bank)
{
INSTANCE.setActiveTexture(texture, bank);
}
public static void unbindTexture()
{
INSTANCE.setActiveTexture(0);
}
public void setActiveTexture(int texture)
{
if(textureBanks[activeBank] != texture)
{
textureBanks[activeBank] = texture;
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
}
}
public void setActiveTexture(int texture, int bank)
{
if(activeBank != bank)
{
activeBank = bank;
GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeBank);
}
bindTexture(texture);
}
@Override
public void reload()
{
reloader.reloadResources();
}
@Override
public void destroy()
{
reloader.deleteResources();
}
public AssetManager getManager()
{
return manager;
}
public static GLFWImage create(AssetLocation location)
{
try(IAsset asset = INSTANCE.manager.getAsset(location))
{
BufferedImage image = asset.texture();
int width = image.getWidth();
int height = image.getHeight();
int[] pixelData = new int[width * height];
image.getRGB(0, 0, width, height, pixelData, 0, width);
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
for(int y = 0;y<height;y++)
{
for(int x = 0;x<width;x++)
{
int pixel = pixelData[(y * width) + x];
buffer.put((byte)((pixel >> 16) & 0xFF));
buffer.put((byte)((pixel >> 8) & 0xFF));
buffer.put((byte)(pixel & 0xFF));
buffer.put((byte)((pixel >> 24) & 0xFF));
}
}
GLFWImage glfw = GLFWImage.malloc();
glfw.set(width, height, buffer);
return glfw;
}
catch(Exception e)
{
GameLog.error("Couldn't Load Texture ["+location.toString()+"]", e, LogLevel.ERROR);
return null;
}
}
}

View File

@ -1,87 +1,87 @@
package speiger.src.coreengine.rendering.texturesOld.normal;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
public class SimpleTexture extends AbstractTexture
{
AssetLocation location;
int width;
int height;
public SimpleTexture(AssetLocation location)
{
super();
this.location = location;
loadTexture();
}
public void loadTexture()
{
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location))
{
BufferedImage image = asset.texture();
width = image.getWidth();
height = image.getHeight();
int[] pixelData = new int[width * height];
image.getRGB(0, 0, width, height, pixelData, 0, width);
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
for(int y = 0;y<height;y++)
{
for(int x = 0;x<width;x++)
{
int pixel = pixelData[(y * width) + x];
buffer.put((byte)((pixel >> 16) & 0xFF));
buffer.put((byte)((pixel >> 8) & 0xFF));
buffer.put((byte)(pixel & 0xFF));
buffer.put((byte)((pixel >> 24) & 0xFF));
}
}
buffer.flip();
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, buffer);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
MemoryUtil.memFree(buffer);
}
catch(Exception e)
{
e.printStackTrace();
}
}
@Override
public void reload()
{
int old = textureID;
loadTexture();
TextureManager.INSTANCE.removeTexture(old);
}
@Override
public int getWidth()
{
return width;
}
@Override
public int getHeight()
{
return height;
}
}
package speiger.src.coreengine.rendering.texturesOld.normal;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL30;
import org.lwjgl.system.MemoryUtil;
import speiger.src.coreengine.assets.AssetLocation;
import speiger.src.coreengine.assets.base.IAsset;
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
public class SimpleTexture extends AbstractTexture
{
AssetLocation location;
int width;
int height;
public SimpleTexture(AssetLocation location)
{
super();
this.location = location;
loadTexture();
}
public void loadTexture()
{
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location))
{
BufferedImage image = asset.texture();
width = image.getWidth();
height = image.getHeight();
int[] pixelData = new int[width * height];
image.getRGB(0, 0, width, height, pixelData, 0, width);
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
for(int y = 0;y<height;y++)
{
for(int x = 0;x<width;x++)
{
int pixel = pixelData[(y * width) + x];
buffer.put((byte)((pixel >> 16) & 0xFF));
buffer.put((byte)((pixel >> 8) & 0xFF));
buffer.put((byte)(pixel & 0xFF));
buffer.put((byte)((pixel >> 24) & 0xFF));
}
}
buffer.flip();
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, buffer);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
MemoryUtil.memFree(buffer);
}
catch(Exception e)
{
e.printStackTrace();
}
}
@Override
public void reload()
{
int old = textureID;
loadTexture();
TextureManager.INSTANCE.removeTexture(old);
}
@Override
public int getWidth()
{
return width;
}
@Override
public int getHeight()
{
return height;
}
}

View File

@ -1,99 +1,99 @@
package speiger.src.coreengine.rendering.texturesOld.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.base.IAsset;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
import speiger.src.coreengine.rendering.texturesOld.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.custom(NativeMemoryParser.INSTANCE);
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;
}
}
}
package speiger.src.coreengine.rendering.texturesOld.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.base.IAsset;
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
import speiger.src.coreengine.rendering.texturesOld.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.custom(NativeMemoryParser.INSTANCE);
int[] width = new int[1];
int[] height = new int[1];
int[] fileChannels = new int[1];
ByteBuffer image = STBImage.stbi_load_from_memory(buffer, width, height, fileChannels, 4);
if(image == null) {
MemoryUtil.memFree(buffer);
throw new IOException("Could not load image: " + STBImage.stbi_failure_reason());
}
imageData = MemoryUtil.memAddress(image);
this.width = width[0];
this.height = height[0];
MemoryUtil.memFree(buffer);
}
catch(Exception e)
{
e.printStackTrace();
return;
}
setTextureID(GL11.glGenTextures());
bindTexture();
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_BORDER);
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageData);
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
}
@Override
public int getWidth()
{
return width;
}
@Override
public int getHeight()
{
return height;
}
@Override
public void reload()
{
if(imageData != 0)
{
STBImage.nstbi_image_free(imageData);
imageData = 0;
}
int old = textureID;
loadTexture();
TextureManager.INSTANCE.removeTexture(old);
}
@Override
public void deleteTexture()
{
super.deleteTexture();
if(imageData != 0)
{
STBImage.nstbi_image_free(imageData);
imageData = 0;
}
}
}

View File

@ -1,25 +1,25 @@
package speiger.src.coreengine.utils.functions;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class Functions
{
static final Predicate<Object> ALWAYS_TRUE = (T) -> true;
static final Consumer<Object> EMPTY_CONSUMER = (T) -> {};
public static final Predicate<String> NUMBERS_ONLY = T -> {
if(T.isEmpty() || T.equals("#") || T.equals("0x")) return true;
try { return Long.decode(T) != null; }
catch(Exception e){ return false; }
};
@SuppressWarnings("unchecked")
public static <T> Predicate<T> getAlwaysTrue() {
return (Predicate<T>)ALWAYS_TRUE;
}
@SuppressWarnings("unchecked")
public static <T> Consumer<T> getVoidConsumer() {
return (Consumer<T>)EMPTY_CONSUMER;
}
}
package speiger.src.coreengine.utils.functions;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class Functions
{
static final Predicate<Object> ALWAYS_TRUE = _ -> true;
static final Consumer<Object> EMPTY_CONSUMER = _ -> {};
public static final Predicate<String> NUMBERS_ONLY = T -> {
if(T.isEmpty() || T.equals("#") || T.equals("0x")) return true;
try { return Long.decode(T) != null; }
catch(Exception e){ return false; }
};
@SuppressWarnings("unchecked")
public static <T> Predicate<T> getAlwaysTrue() {
return (Predicate<T>)ALWAYS_TRUE;
}
@SuppressWarnings("unchecked")
public static <T> Consumer<T> getVoidConsumer() {
return (Consumer<T>)EMPTY_CONSUMER;
}
}

View File

@ -1,28 +1,28 @@
package speiger.src.coreengine.utils.io.dataTag.compression;
import java.io.IOException;
public interface DataTagLimiter {
public static final DataTagLimiter INFINTE = T -> {};
public static DataTagLimiter limit(int byteLimit) {
return new Instance(byteLimit);
}
public void countBytes(int amount) throws IOException;
public static class Instance implements DataTagLimiter {
final int max;
int read = 0;
public Instance(int max) {
this.max = max;
}
@Override
public void countBytes(int amount) throws IOException {
read += amount;
if(read > amount) throw new IllegalStateException("To many Bytes Read");
}
}
}
package speiger.src.coreengine.utils.io.dataTag.compression;
import java.io.IOException;
public interface DataTagLimiter {
public static final DataTagLimiter INFINTE = _ -> {};
public static DataTagLimiter limit(int byteLimit) {
return new Instance(byteLimit);
}
public void countBytes(int amount) throws IOException;
public static class Instance implements DataTagLimiter {
final int max;
int read = 0;
public Instance(int max) {
this.max = max;
}
@Override
public void countBytes(int amount) throws IOException {
read += amount;
if(read > amount) throw new IllegalStateException("To many Bytes Read");
}
}
}

View File

@ -1,146 +1,146 @@
package speiger.src.coreengine.math;
public class MathUtils {
private static final float[] SIN_TABLE;
private static final float[] COS_TABLE;
private static final float TABLE_MASK;
private static final int SIN_MASK;
public static final double HALF_PI = Math.PI * 0.5D;
public static final double PI_INVERSION = 180D / Math.PI;
public static float sin(float a) {
return SIN_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float sin(double a) {
return SIN_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float cos(float a) {
return COS_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float cos(double a) {
return COS_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static byte clamp(byte min, byte max, byte current) {
return current < min ? min : (current > max ? max : current);
}
public static short clamp(short min, short max, short current) {
return current < min ? min : (current > max ? max : current);
}
public static int clamp(int min, int max, int current) {
return current < min ? min : (current > max ? max : current);
}
public static float clamp(float min, float max, float current) {
return current < min ? min : (current > max ? max : current);
}
public static double clamp(double min, double max, double current) {
return current < min ? min : (current > max ? max : current);
}
public static long clamp(long min, long max, long current) {
return current < min ? min : (current > max ? max : current);
}
public static byte sign(byte value) {
return (byte)Integer.signum(value);
}
public static short sign(short value) {
return (short)Integer.signum(value);
}
public static int sign(int value) {
return Integer.signum(value);
}
public static long sign(long value) {
return Long.signum(value);
}
public static float sign(float value) {
return Math.signum(value);
}
public static double sign(double value) {
return Math.signum(value);
}
public static int sub(int key, int value) {
return key - value;
}
public static int ceil(double value) {
int i = (int)value;
return value > i ? i + 1 : i;
}
public static int ceil(float value) {
int i = (int)value;
return value > i ? i + 1 : i;
}
public static int floor(float value) {
int i = (int)value;
return value < i ? i - 1 : i;
}
public static int floor(double value) {
int i = (int)value;
return value < i ? i - 1 : i;
}
public static int pow(int base, int exp) {
return (int)Math.pow(base, exp);
}
public static float lerp(float start, float end, float progress) {
return start + ((end - start) * progress);
}
public static double lerp(double start, double end, float progress) {
return start + ((end - start) * progress);
}
public static float smoothLerp(float start, float end, float progress) {
float cosProgress = (1F - MathUtils.cos(progress * Math.PI)) * 0.5F;
return start * (1F - cosProgress) + end * cosProgress;
}
public static float quadraticCurve(float start, float median, float end, float progress) {
return lerp(lerp(start, median, progress), lerp(median, end, progress), progress);
}
public static float smoothQuadraticCurve(float start, float median, float end, float progress) {
return smoothLerp(smoothLerp(start, median, progress), smoothLerp(median, end, progress), progress);
}
static {
SIN_MASK = ~(-1 << 12);
int SIN_COUNT = SIN_MASK + 1;
float radFull = (float)(Math.PI * 2D);
float degFull = (float)(360.0);
float radToIndex = SIN_COUNT / radFull;
float degToIndex = SIN_COUNT / degFull;
TABLE_MASK = radToIndex;
SIN_TABLE = new float[SIN_COUNT];
COS_TABLE = new float[SIN_COUNT];
for(int i = 0;i < SIN_COUNT;i++) {
SIN_TABLE[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull);
COS_TABLE[i] = (float)Math.cos((i + 0.5f) / SIN_COUNT * radFull);
}
for(int i = 0;i < 360;i += 90) {
SIN_TABLE[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * Math.PI / 180D);
COS_TABLE[(int)(i * degToIndex) & SIN_MASK] = (float)Math.cos(i * Math.PI / 180D);
}
}
}
package speiger.src.coreengine.math;
public class MathUtils {
private static final float[] SIN_TABLE;
private static final float[] COS_TABLE;
private static final float TABLE_MASK;
private static final int SIN_MASK;
public static final double HALF_PI = Math.PI * 0.5D;
public static final double PI_INVERSION = 180D / Math.PI;
public static float sin(float a) {
return SIN_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float sin(double a) {
return SIN_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float cos(float a) {
return COS_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static float cos(double a) {
return COS_TABLE[(int)(a * TABLE_MASK) & SIN_MASK];
}
public static byte clamp(byte min, byte max, byte current) {
return current < min ? min : (current > max ? max : current);
}
public static short clamp(short min, short max, short current) {
return current < min ? min : (current > max ? max : current);
}
public static int clamp(int min, int max, int current) {
return current < min ? min : (current > max ? max : current);
}
public static float clamp(float min, float max, float current) {
return current < min ? min : (current > max ? max : current);
}
public static double clamp(double min, double max, double current) {
return current < min ? min : (current > max ? max : current);
}
public static long clamp(long min, long max, long current) {
return current < min ? min : (current > max ? max : current);
}
public static byte sign(byte value) {
return (byte)Integer.signum(value);
}
public static short sign(short value) {
return (short)Integer.signum(value);
}
public static int sign(int value) {
return Integer.signum(value);
}
public static long sign(long value) {
return Long.signum(value);
}
public static float sign(float value) {
return Math.signum(value);
}
public static double sign(double value) {
return Math.signum(value);
}
public static int sub(int key, int value) {
return key - value;
}
public static int ceil(double value) {
int i = (int)value;
return value > i ? i + 1 : i;
}
public static int ceil(float value) {
int i = (int)value;
return value > i ? i + 1 : i;
}
public static int floor(float value) {
int i = (int)value;
return value < i ? i - 1 : i;
}
public static int floor(double value) {
int i = (int)value;
return value < i ? i - 1 : i;
}
public static int pow(int base, int exp) {
return (int)Math.pow(base, exp);
}
public static float lerp(float start, float end, float progress) {
return start + ((end - start) * progress);
}
public static double lerp(double start, double end, float progress) {
return start + ((end - start) * progress);
}
public static float smoothLerp(float start, float end, float progress) {
float cosProgress = (1F - MathUtils.cos(progress * Math.PI)) * 0.5F;
return start * (1F - cosProgress) + end * cosProgress;
}
public static float quadraticCurve(float start, float median, float end, float progress) {
return lerp(lerp(start, median, progress), lerp(median, end, progress), progress);
}
public static float smoothQuadraticCurve(float start, float median, float end, float progress) {
return smoothLerp(smoothLerp(start, median, progress), smoothLerp(median, end, progress), progress);
}
static {
SIN_MASK = ~(-1 << 12);
int SIN_COUNT = SIN_MASK + 1;
float radFull = (float)(Math.PI * 2D);
float degFull = (float)(360.0);
float radToIndex = SIN_COUNT / radFull;
float degToIndex = SIN_COUNT / degFull;
TABLE_MASK = radToIndex;
SIN_TABLE = new float[SIN_COUNT];
COS_TABLE = new float[SIN_COUNT];
for(int i = 0;i < SIN_COUNT;i++) {
SIN_TABLE[i] = (float)Math.sin((i + 0.5f) / SIN_COUNT * radFull);
COS_TABLE[i] = (float)Math.cos((i + 0.5f) / SIN_COUNT * radFull);
}
for(int i = 0;i < 360;i += 90) {
SIN_TABLE[(int)(i * degToIndex) & SIN_MASK] = (float)Math.sin(i * Math.PI / 180D);
COS_TABLE[(int)(i * degToIndex) & SIN_MASK] = (float)Math.cos(i * Math.PI / 180D);
}
}
}

View File

@ -0,0 +1,23 @@
package speiger.src.coreengine.math.vector.bytes;
public record Vec2bImmutable(byte x, byte y) implements Vec2b {
public Vec2bImmutable() {
this((byte)0, (byte)0);
}
public Vec2bImmutable(byte value) {
this(value, value);
}
@Override
public boolean isMutable() { return false; }
@Override
public Vec2b x(byte x) { return this.x == x ? this : Vec2b.of(x, y); }
@Override
public Vec2b y(byte y) { return this.y == y ? this : Vec2b.of(x, y); }
@Override
public Vec2b copy() { return Vec2b.of(this); }
@Override
public Vec2b set(byte x, byte y) { return this.x == x && this.y == y ? this : Vec2b.of(x, y); }
}

View File

@ -0,0 +1,25 @@
package speiger.src.coreengine.math.vector.bytes;
public record Vec3bImmutable(byte x, byte y, byte z) implements Vec3b {
public Vec3bImmutable() {
this((byte)0, (byte)0, (byte)0);
}
public Vec3bImmutable(byte value) {
this(value, value, value);
}
@Override
public boolean isMutable() { return false; }
@Override
public Vec3b x(byte x) { return this.x == x ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b y(byte y) { return this.y == y ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b z(byte z) { return this.z == z ? this : Vec3b.of(x, y, z); }
@Override
public Vec3b copy() { return Vec3b.of(this); }
@Override
public Vec3b set(byte x, byte y, byte z) { return this.x == x && this.y == y && this.z == z ? this : Vec3b.of(x, y, z); }
}

View File

@ -0,0 +1,27 @@
package speiger.src.coreengine.math.vector.bytes;
public record Vec4bImmutable(byte x, byte y, byte z, byte w) implements Vec4b {
public Vec4bImmutable() {
this((byte)0, (byte)0, (byte)0, (byte)0);
}
public Vec4bImmutable(byte value) {
this(value, value, value, value);
}
@Override
public boolean isMutable() { return false; }
@Override
public Vec4b x(byte x) { return this.x == x ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b y(byte y) { return this.y == y ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b z(byte z) { return this.z == z ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b w(byte w) { return this.w == w ? this : Vec4b.of(x, y, z, w); }
@Override
public Vec4b copy() { return Vec4b.of(this); }
@Override
public Vec4b set(byte x, byte y, byte z, byte w) { return this.x == x && this.y == y && this.z == z && this.w == w ? this : Vec4b.of(x, y, z, w); }
}

Some files were not shown because too many files have changed in this diff Show More