diff --git a/.classpath b/.classpath index f60f002..b8e2565 100644 --- a/.classpath +++ b/.classpath @@ -24,6 +24,18 @@ + + + + + + + + + + + + diff --git a/build.gradle b/build.gradle index c5f792e..bd66764 100644 --- a/build.gradle +++ b/build.gradle @@ -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 { diff --git a/src/assets/java/speiger/src/coreengine/assets/api/IAsset.java b/src/assets/java/speiger/src/coreengine/assets/api/IAsset.java new file mode 100644 index 0000000..f38f8aa --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/IAsset.java @@ -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 parse(IAssetParser parser) throws IOException; +} diff --git a/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java b/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java new file mode 100644 index 0000000..42834e5 --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java @@ -0,0 +1,5 @@ +package speiger.src.coreengine.assets.api; + +public interface IAssetPackage { + +} diff --git a/src/assets/java/speiger/src/coreengine/assets/api/IAssetParser.java b/src/assets/java/speiger/src/coreengine/assets/api/IAssetParser.java new file mode 100644 index 0000000..c57201f --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/IAssetParser.java @@ -0,0 +1,8 @@ +package speiger.src.coreengine.assets.api; + +import java.io.IOException; +import java.nio.file.Path; + +public interface IAssetParser { + public T parse(Path path) throws IOException; +} diff --git a/src/assets/java/speiger/src/coreengine/assets/api/IAssetProvider.java b/src/assets/java/speiger/src/coreengine/assets/api/IAssetProvider.java new file mode 100644 index 0000000..cf0b41e --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/IAssetProvider.java @@ -0,0 +1,6 @@ +package speiger.src.coreengine.assets.api; + +public interface IAssetProvider { + public IAsset get(ID id); + public String hash(ID id); +} diff --git a/src/assets/java/speiger/src/coreengine/assets/api/ID.java b/src/assets/java/speiger/src/coreengine/assets/api/ID.java new file mode 100644 index 0000000..88f3f21 --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/ID.java @@ -0,0 +1,79 @@ +package speiger.src.coreengine.assets.api; + +import java.util.Objects; + +public record ID(String domain, String path) implements Comparable { + + 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= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); + } +} diff --git a/src/assets/java/speiger/src/coreengine/assets/api/MultiAsset.java b/src/assets/java/speiger/src/coreengine/assets/api/MultiAsset.java new file mode 100644 index 0000000..5e3ec0c --- /dev/null +++ b/src/assets/java/speiger/src/coreengine/assets/api/MultiAsset.java @@ -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 assets) implements ObjectIterable { + + public MultiAsset(ObjectList 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 iterator() { return assets.iterator(); } + + public ObjectIterable map(IAssetParser mapper, Supplier defaultValue) { + return assets.map(E -> { + try { return E.parse(mapper); } + catch(IOException e) { + e.printStackTrace(); + return defaultValue.get(); + } + }); + } + + @Override + public void forEach(Consumer action) { + assets.forEach(action); + } + + @Override + public void forEach(E input, ObjectObjectConsumer action) { + assets.forEach(input, action); + } + + @Override + public void forEachIndexed(IntObjectConsumer action) { + assets.forEachIndexed(action); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/states/IndeciesType.java b/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/states/IndeciesType.java new file mode 100644 index 0000000..f65af13 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/states/IndeciesType.java @@ -0,0 +1,7 @@ +package speiger.src.coreengine.graphics.api.buffer.states; + +public enum IndeciesType { + BYTE, + SHORT, + INT; +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java index 4fd6278..38afb60 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java @@ -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(); + } + } } \ No newline at end of file diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java index 6007bb3..708b8c6 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java @@ -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); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/shader/CompiledPipeline.java b/src/graphics/java/speiger/src/coreengine/graphics/api/shader/CompiledPipeline.java new file mode 100644 index 0000000..98a7a38 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/shader/CompiledPipeline.java @@ -0,0 +1,5 @@ +package speiger.src.coreengine.graphics.api.shader; + +public interface CompiledPipeline { + +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/shader/RenderPass.java b/src/graphics/java/speiger/src/coreengine/graphics/api/shader/RenderPass.java new file mode 100644 index 0000000..5c6df02 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/shader/RenderPass.java @@ -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(); + + +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/target/RenderTarget.java b/src/graphics/java/speiger/src/coreengine/graphics/api/target/RenderTarget.java new file mode 100644 index 0000000..8423348 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/target/RenderTarget.java @@ -0,0 +1,4 @@ +package speiger.src.coreengine.graphics.api.target; + +public sealed interface RenderTarget permits ScreenTarget, TextureTarget { +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/target/ScreenTarget.java b/src/graphics/java/speiger/src/coreengine/graphics/api/target/ScreenTarget.java new file mode 100644 index 0000000..79d2deb --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/target/ScreenTarget.java @@ -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() {} +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/target/TextureTarget.java b/src/graphics/java/speiger/src/coreengine/graphics/api/target/TextureTarget.java new file mode 100644 index 0000000..6edec88 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/target/TextureTarget.java @@ -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"); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/texture/Texture.java b/src/graphics/java/speiger/src/coreengine/graphics/api/texture/Texture.java index 8105ae4..863cf6a 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/texture/Texture.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/texture/Texture.java @@ -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; diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java b/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java new file mode 100644 index 0000000..df5ee2f --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java @@ -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 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(); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java new file mode 100644 index 0000000..5ddb61e --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java @@ -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 original, T applying, Supplier current, Consumer apply) implements PushableResource { + @Override + public void close() { + if(current.get().equals(applying)) { + apply.accept(original); + } + } + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java index 31a3f36..f7c890b 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java @@ -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; + } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/GLRenderPass.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/GLRenderPass.java new file mode 100644 index 0000000..5d6e053 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/GLRenderPass.java @@ -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> textures = Object2ObjectMap.builder().linkedMap(); + Map 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; + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java new file mode 100644 index 0000000..4c0d2ee --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java @@ -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 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 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"); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java new file mode 100644 index 0000000..23f9dd1 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java @@ -0,0 +1,9 @@ +package speiger.src.coreengine.graphics.opengl.shader; + +import java.util.Map; + +public record ShaderInstance(int programId, Map uniforms, Map samplers) { + + public record UniformObject(int slot) {} + public record SamplerObject(int unit) {} +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java new file mode 100644 index 0000000..e15d84d --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java @@ -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 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(); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/GLTexture.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/GLTexture.java index bdbe199..f7da30c 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/GLTexture.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/GLTexture.java @@ -12,6 +12,10 @@ public class GLTexture extends Texture { this.id = id; } + public int id() { + return id; + } + @Override public boolean isRemoved() { return id == 0; diff --git a/src/main/java/speiger/src/coreengine/NewInputTest.java b/src/main/java/speiger/src/coreengine/NewInputTest.java index 54c08d9..9ace68e 100644 --- a/src/main/java/speiger/src/coreengine/NewInputTest.java +++ b/src/main/java/speiger/src/coreengine/NewInputTest.java @@ -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); diff --git a/src/main/java/speiger/src/coreengine/assets/AssetFilter.java b/src/main/java/speiger/src/coreengine/assets/AssetFilter.java index 17889d3..ea8dadc 100644 --- a/src/main/java/speiger/src/coreengine/assets/AssetFilter.java +++ b/src/main/java/speiger/src/coreengine/assets/AssetFilter.java @@ -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 list(IAssetProvider provider) { - return provider.listAssets(prefix, T -> T.endsWith(extension)); - } - - public Map listRoot(IAssetProvider provider) { - return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix)); - } - - public Map multi(IAssetProvider provider) { - return provider.listAllAssets(prefix, T -> T.endsWith(extension)); - } - - public Map 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 list(IAssetProvider provider) { + return provider.listAssets(prefix, T -> T.endsWith(extension)); + } + + public Map listRoot(IAssetProvider provider) { + return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix)); + } + + public Map multi(IAssetProvider provider) { + return provider.listAllAssets(prefix, T -> T.endsWith(extension)); + } + + public Map multiRoot(IAssetProvider provider) { + return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix)); + } + +} diff --git a/src/main/java/speiger/src/coreengine/assets/AssetManager.java b/src/main/java/speiger/src/coreengine/assets/AssetManager.java index 349551e..2cb03aa 100644 --- a/src/main/java/speiger/src/coreengine/assets/AssetManager.java +++ b/src/main/java/speiger/src/coreengine/assets/AssetManager.java @@ -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 listeners = new ObjectArrayList<>(); - LayeredAssetProvider provider; - - public AssetManager(List packages) { - provider = new LayeredAssetProvider(packages); - } - - public void addListener(IReloadableAsset listener) { - listeners.add(listener); - if(listener instanceof IManagedAsset managed) { - managed.setProvider(this); - } - } - - public ObjectList listeners() { - return ObjectLists.unmodifiable(listeners); - } - - public AssetManager reload(Executor offthread, Executor syncer, List 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 listeners) { - return reloadSelective(Runnable::run, Runnable::run, listeners); - } - - public AssetManager reloadSelective(Executor offthread, Executor syncer, List listeners) { - PackReloadingTask.reload(provider, listeners, offthread, syncer).join(); - return this; - } - - public AssetManager reloadAssets(List 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 listAssets(String folder, Predicate filter) { - return provider.listAssets(folder, filter); - } - - @Override - public Map listAllAssets(String folder, Predicate 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 listeners = new ObjectArrayList<>(); + LayeredAssetProvider provider; + + public AssetManager(List packages) { + provider = new LayeredAssetProvider(packages); + } + + public void addListener(IReloadableAsset listener) { + listeners.add(listener); + if(listener instanceof IManagedAsset managed) { + managed.setProvider(this); + } + } + + public ObjectList listeners() { + return ObjectLists.unmodifiable(listeners); + } + + public AssetManager reload(Executor offthread, Executor syncer, List 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 listeners) { + return reloadSelective(Runnable::run, Runnable::run, listeners); + } + + public AssetManager reloadSelective(Executor offthread, Executor syncer, List listeners) { + PackReloadingTask.reload(provider, listeners, offthread, syncer).join(); + return this; + } + + public AssetManager reloadAssets(List 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 listAssets(String folder, Predicate filter) { + return provider.listAssets(folder, filter); + } + + @Override + public Map listAllAssets(String folder, Predicate filter) { + return provider.listAllAssets(folder, filter); + } +} diff --git a/src/main/java/speiger/src/coreengine/assets/base/IAsset.java b/src/main/java/speiger/src/coreengine/assets/base/IAsset.java index dccc2b4..759700a 100644 --- a/src/main/java/speiger/src/coreengine/assets/base/IAsset.java +++ b/src/main/java/speiger/src/coreengine/assets/base/IAsset.java @@ -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 lines() throws IOException; - public JsonObject json() throws IOException; - public BufferedImage texture() throws Exception; - public T custom(IAssetParser 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 lines() throws IOException; + public JsonObject json() throws IOException; + public BufferedImage texture() throws Exception; + public T custom(IAssetParser parser) throws IOException; +} diff --git a/src/main/java/speiger/src/coreengine/assets/base/IAssetPackage.java b/src/main/java/speiger/src/coreengine/assets/base/IAssetPackage.java index 6782d9a..5f243ca 100644 --- a/src/main/java/speiger/src/coreengine/assets/base/IAssetPackage.java +++ b/src/main/java/speiger/src/coreengine/assets/base/IAssetPackage.java @@ -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 accept); - public List getDomains(); - public IAsset getAsset(AssetLocation location); - public void gatherAssets(AssetLocation folder, BiConsumer 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 accept); + public List getDomains(); + public IAsset getAsset(AssetLocation location); + public void gatherAssets(AssetLocation folder, BiConsumer 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; + } +} diff --git a/src/main/java/speiger/src/coreengine/assets/base/IAssetProvider.java b/src/main/java/speiger/src/coreengine/assets/base/IAssetProvider.java index 5952f49..71ae8f6 100644 --- a/src/main/java/speiger/src/coreengine/assets/base/IAssetProvider.java +++ b/src/main/java/speiger/src/coreengine/assets/base/IAssetProvider.java @@ -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 listAssets(String folder, Predicate filter); - public Map listAllAssets(String folder, Predicate 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 listAssets(String folder, Predicate filter); + public Map listAllAssets(String folder, Predicate filter); + + public static interface ICloseableAssetProvider extends IAssetProvider, AutoCloseable { + @Override + public void close(); + } +} diff --git a/src/main/java/speiger/src/coreengine/assets/base/MultiAsset.java b/src/main/java/speiger/src/coreengine/assets/base/MultiAsset.java index cb434ee..414291b 100644 --- a/src/main/java/speiger/src/coreengine/assets/base/MultiAsset.java +++ b/src/main/java/speiger/src/coreengine/assets/base/MultiAsset.java @@ -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 { - ObjectList assets; - - public MultiAsset(IAsset...assets) { - this(ObjectArrayList.wrap(assets)); - } - - public MultiAsset(ObjectList 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 Iterable map(AssetMapper mappingFunction, Supplier defaultValue) { - return () -> new Iterator() { - 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 action) { - assets.forEach(action); - } - - @Override - public void forEach(E input, ObjectObjectConsumer action) { - assets.forEach(input, action); - } - - @Override - public void forEachIndexed(IntObjectConsumer action) { - assets.forEachIndexed(action); - } - - @Override - public ObjectIterator iterator() { - return assets.iterator(); - } - - public static interface AssetMapper { - 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 { + ObjectList assets; + + public MultiAsset(IAsset...assets) { + this(ObjectArrayList.wrap(assets)); + } + + public MultiAsset(ObjectList 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 Iterable map(AssetMapper mappingFunction, Supplier defaultValue) { + return () -> new Iterator() { + 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 action) { + assets.forEach(action); + } + + @Override + public void forEach(E input, ObjectObjectConsumer action) { + assets.forEach(input, action); + } + + @Override + public void forEachIndexed(IntObjectConsumer action) { + assets.forEachIndexed(action); + } + + @Override + public ObjectIterator iterator() { + return assets.iterator(); + } + + public static interface AssetMapper { + public T apply(IAsset asset) throws IOException; + } +} diff --git a/src/main/java/speiger/src/coreengine/assets/impl/BaseAsset.java b/src/main/java/speiger/src/coreengine/assets/impl/BaseAsset.java index 248ba3b..5e6dbcb 100644 --- a/src/main/java/speiger/src/coreengine/assets/impl/BaseAsset.java +++ b/src/main/java/speiger/src/coreengine/assets/impl/BaseAsset.java @@ -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 = 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 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 = 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 markClosed(T value) { + closeable.add(value); + return value; + } + + @Override + public AssetLocation location() { + return location; + } + + @Override + public IAssetPackage owner() { + return owner; + } +} diff --git a/src/main/java/speiger/src/coreengine/assets/impl/FolderAssetPackage.java b/src/main/java/speiger/src/coreengine/assets/impl/FolderAssetPackage.java index ce0abf1..45b29e7 100644 --- a/src/main/java/speiger/src/coreengine/assets/impl/FolderAssetPackage.java +++ b/src/main/java/speiger/src/coreengine/assets/impl/FolderAssetPackage.java @@ -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 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 getDomains() { - List domains = new ObjectArrayList<>(); - try(DirectoryStream 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 result) { - Path start = baseFolder.resolve(folder.actualLocation()); - if(Files.notExists(start)) return; - try(Stream 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 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 getDomains() { + List domains = new ObjectArrayList<>(); + try(DirectoryStream 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 result) { + Path start = baseFolder.resolve(folder.actualLocation()); + if(Files.notExists(start)) return; + try(Stream 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(); + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/assets/impl/LayeredAssetProvider.java b/src/main/java/speiger/src/coreengine/assets/impl/LayeredAssetProvider.java index b801fdd..3d7a2fd 100644 --- a/src/main/java/speiger/src/coreengine/assets/impl/LayeredAssetProvider.java +++ b/src/main/java/speiger/src/coreengine/assets/impl/LayeredAssetProvider.java @@ -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 domains = Object2ObjectMap.builder().linkedMap(); - List packages; - - public LayeredAssetProvider(List 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 listAssets(String folder, Predicate filter) { - Map result = Object2ObjectMap.builder().linkedMap(); - for(DomainAssetProvider provider : domains.values()) { - result.putAll(provider.listAssets(folder, filter)); - } - return result; - } - - @Override - public Map listAllAssets(String folder, Predicate filter) { - Map 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 packages = new ObjectArrayList<>(); - Map 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 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 listAssets(String folder, Predicate filter) { - AssetLocation base = AssetLocation.of(domain, folder); - Map 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 listAllAssets(String folder, Predicate filter) { - AssetLocation base = AssetLocation.of(domain, folder); - Object2ObjectMap> 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 result = Object2ObjectMap.builder().linkedMap(); - for(Object2ObjectMap.Entry> 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 domains = Object2ObjectMap.builder().linkedMap(); + List packages; + + public LayeredAssetProvider(List 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 listAssets(String folder, Predicate filter) { + Map result = Object2ObjectMap.builder().linkedMap(); + for(DomainAssetProvider provider : domains.values()) { + result.putAll(provider.listAssets(folder, filter)); + } + return result; + } + + @Override + public Map listAllAssets(String folder, Predicate filter) { + Map 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 packages = new ObjectArrayList<>(); + Map 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 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 listAssets(String folder, Predicate filter) { + AssetLocation base = AssetLocation.of(domain, folder); + Map 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 listAllAssets(String folder, Predicate filter) { + AssetLocation base = AssetLocation.of(domain, folder); + Object2ObjectMap> 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 result = Object2ObjectMap.builder().linkedMap(); + for(Object2ObjectMap.Entry> entry : Object2ObjectMaps.fastIterable(assets)) { + result.put(entry.getKey(), new MultiAsset(entry.getValue())); + } + return result; + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/assets/impl/SimpleAsset.java b/src/main/java/speiger/src/coreengine/assets/impl/SimpleAsset.java index 072a427..1e12fe6 100644 --- a/src/main/java/speiger/src/coreengine/assets/impl/SimpleAsset.java +++ b/src/main/java/speiger/src/coreengine/assets/impl/SimpleAsset.java @@ -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 lines() throws IOException { return Files.readAllLines(path); } - @Override - public JsonObject json() throws IOException { return JsonUtil.loadFile(path); } - @Override - public T custom(IAssetParser 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 lines() throws IOException { return Files.readAllLines(path); } + @Override + public JsonObject json() throws IOException { return JsonUtil.loadFile(path); } + @Override + public T custom(IAssetParser parser) throws IOException { return parser.parseAsset(path, closeable::add); } + +} diff --git a/src/main/java/speiger/src/coreengine/assets/impl/ZipAssetPackage.java b/src/main/java/speiger/src/coreengine/assets/impl/ZipAssetPackage.java index c53298a..cf09b90 100644 --- a/src/main/java/speiger/src/coreengine/assets/impl/ZipAssetPackage.java +++ b/src/main/java/speiger/src/coreengine/assets/impl/ZipAssetPackage.java @@ -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 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 getDomains() { - List domains = new ObjectArrayList<>(); - try(FileSystem system = FileSystems.newFileSystem(baseFolder)) { - try(DirectoryStream 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 result) { - try { - FileSystem system = getReference(); - Path start = system.getPath(folder.actualLocation()); - if(Files.notExists(start)) return; - try(Stream 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 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 getDomains() { + List domains = new ObjectArrayList<>(); + try(FileSystem system = FileSystems.newFileSystem(baseFolder)) { + try(DirectoryStream 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 result) { + try { + FileSystem system = getReference(); + Path start = system.getPath(folder.actualLocation()); + if(Files.notExists(start)) return; + try(Stream 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(); + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/assets/language/LanguageManager.java b/src/main/java/speiger/src/coreengine/assets/language/LanguageManager.java index 36b5103..359b081 100644 --- a/src/main/java/speiger/src/coreengine/assets/language/LanguageManager.java +++ b/src/main/java/speiger/src/coreengine/assets/language/LanguageManager.java @@ -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 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 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 data) { - try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) { - for(int i = 0,m = language.size();i < m;i++) { - try { - for(Map.Entry 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 data) { - if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString()); - else if(el.isJsonObject()) { - for(Map.Entry 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 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 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 data) { + try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) { + for(int i = 0,m = language.size();i < m;i++) { + try { + for(Map.Entry 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 data) { + if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString()); + else if(el.isJsonObject()) { + for(Map.Entry 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)); + } + } + +} diff --git a/src/main/java/speiger/src/coreengine/math/vector/VectorUtil.java b/src/main/java/speiger/src/coreengine/math/vector/VectorUtil.java deleted file mode 100644 index a6d145e..0000000 --- a/src/main/java/speiger/src/coreengine/math/vector/VectorUtil.java +++ /dev/null @@ -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(); - } -} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java b/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java deleted file mode 100644 index 7c5a3a9..0000000 --- a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java +++ /dev/null @@ -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+"]"; } -} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java b/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java deleted file mode 100644 index 30b685a..0000000 --- a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java +++ /dev/null @@ -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+"]"; } -} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java b/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java deleted file mode 100644 index c32b4ea..0000000 --- a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java +++ /dev/null @@ -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+"]"; } -} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/font/FontManager.java b/src/main/java/speiger/src/coreengine/rendering/gui/font/FontManager.java index ab9649f..63f73f7 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/font/FontManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/font/FontManager.java @@ -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>> { - private static final int TEXTURE_SIZE = 512; - private static final AssetFilter FILTER = AssetFilter.json("font"); - Float2ObjectMap cachedFonts = Float2ObjectMap.builder().map(); - Map fonts = Object2ObjectMap.builder().linkedMap(); - Map> fontParsers = Object2ObjectMap.builder().map(); - List listeners = new ObjectArrayList<>(); - List textures = new ObjectArrayList<>(); - - public FontManager() { - registerParser("stb-ttf", STBTrueTypeProvider::create); - registerParser("free-ttf", FreeTypeProvider::load); - } - - public void registerParser(String id, BiFunction parser) { - fontParsers.putIfAbsent(id, parser); - } - - @Override - public String getName() { return "Font Manager"; } - - @Override - protected Map> prepare(IAssetProvider provider) { - Map loadingCache = Object2ObjectMap.builder().linkedMap(); - Object2ObjectMap> providers = Object2ObjectMap.builder().linkedMap(); - for(Entry 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> 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 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>> { + private static final int TEXTURE_SIZE = 512; + private static final AssetFilter FILTER = AssetFilter.json("font"); + Float2ObjectMap cachedFonts = Float2ObjectMap.builder().map(); + Map fonts = Object2ObjectMap.builder().linkedMap(); + Map> fontParsers = Object2ObjectMap.builder().map(); + List listeners = new ObjectArrayList<>(); + List textures = new ObjectArrayList<>(); + + public FontManager() { + registerParser("stb-ttf", STBTrueTypeProvider::create); + registerParser("free-ttf", FreeTypeProvider::load); + } + + public void registerParser(String id, BiFunction parser) { + fontParsers.putIfAbsent(id, parser); + } + + @Override + public String getName() { return "Font Manager"; } + + @Override + protected Map> prepare(IAssetProvider provider) { + Map loadingCache = Object2ObjectMap.builder().linkedMap(); + Object2ObjectMap> providers = Object2ObjectMap.builder().linkedMap(); + for(Entry 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> 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 builder = fontParsers.get(obj.get("type").getAsString()); + return builder == null ? null : builder.apply(obj, provider); + } + catch(Exception e) { + e.printStackTrace(); + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/FreeTypeProvider.java b/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/FreeTypeProvider.java index c3a2412..5ddd34d 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/FreeTypeProvider.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/FreeTypeProvider.java @@ -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 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 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 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 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; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/STBTrueTypeProvider.java b/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/STBTrueTypeProvider.java index d693a67..c96832e 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/STBTrueTypeProvider.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/font/providers/STBTrueTypeProvider.java @@ -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(); + } + }); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiComponent.java index d585282..f399ed8 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiComponent.java @@ -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; } diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiManager.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiManager.java index 11a0bac..f0b1a88 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/GuiManager.java @@ -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; diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SelectionComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SelectionComponent.java index 9c6d25c..b9d4c55 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SelectionComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SelectionComponent.java @@ -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; diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SingleTabPanelComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SingleTabPanelComponent.java index 0631fcd..54a5fd7 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SingleTabPanelComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/SingleTabPanelComponent.java @@ -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 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= 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 function; - - public DynamicTab(Tab tab, ToFloatFunction 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 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= 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 function; + + public DynamicTab(Tab tab, ToFloatFunction 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; + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TabbedPanelComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TabbedPanelComponent.java index 127cf6a..c280c3d 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TabbedPanelComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TabbedPanelComponent.java @@ -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 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= 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 function; - - public DynamicTab(Tab tab, ToFloatFunction 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 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= 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 function; + + public DynamicTab(Tab tab, ToFloatFunction 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; + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TextFieldComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TextFieldComponent.java index 2c34c90..a99e7ad 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TextFieldComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/TextFieldComponent.java @@ -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; diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/color/ColorPickerWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/color/ColorPickerWindowComponent.java index b5f71aa..37ba4fc 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/color/ColorPickerWindowComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/color/ColorPickerWindowComponent.java @@ -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]); } diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/PieProfilerWindow.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/PieProfilerWindow.java index e9f9630..341626d 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/PieProfilerWindow.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/PieProfilerWindow.java @@ -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; diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/TreeProfilerWindow.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/TreeProfilerWindow.java index 951da14..fb66d6f 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/TreeProfilerWindow.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/debug/TreeProfilerWindow.java @@ -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 listener = (T, V) -> todoList.enqueue(V); - SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast(); - TreeComponent 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 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= tabs.size() ? null : tabs.get(index); - } - - protected void applyProfiler(boolean prev, Consumer 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 listener = (_, V) -> todoList.enqueue(V); + SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast(); + TreeComponent 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 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= tabs.size() ? null : tabs.get(index); + } + + protected void applyProfiler(boolean prev, Consumer 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); + } + + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/misc/ChoiceComponent.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/misc/ChoiceComponent.java index fe12539..980df02 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/misc/ChoiceComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/components/window/misc/ChoiceComponent.java @@ -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()); } diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/FontRenderer.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/FontRenderer.java index fa0d574..af0d062 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/FontRenderer.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/FontRenderer.java @@ -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 renderText(String text, float x, float y, float z) - { - if(text.isEmpty()) return ObjectLists.empty(); - List drawCalls = new ObjectArrayList<>(); - TextContext context = new TextContext(1F, 0); - List 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 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 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 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 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 renderText(String text, float x, float y, float z) + { + if(text.isEmpty()) return ObjectLists.empty(); + List drawCalls = new ObjectArrayList<>(); + TextContext context = new TextContext(1F, 0); + List 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 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 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 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 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[] instances; - float space; - - public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap[] 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 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[] 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, List> 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[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap(), new Int2ObjectOpenHashMap()}; - 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[] instances; + float space; + + public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap[] 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 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[] 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, List> 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[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap(), new Int2ObjectOpenHashMap()}; + 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; + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/provider/FontManager.java b/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/provider/FontManager.java index 26e1e67..c8b8078 100644 --- a/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/provider/FontManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/guiOld/renderer/provider/FontManager.java @@ -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 fontRenders = new Object2ObjectLinkedOpenHashMap<>(); - Object2FloatMap fontSizes = new Object2FloatLinkedOpenHashMap<>(); - Map 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 providers = new ObjectArrayList<>(); - for(Entry 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 fontRenders = new Object2ObjectLinkedOpenHashMap<>(); + Object2FloatMap fontSizes = new Object2FloatLinkedOpenHashMap<>(); + Map 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 providers = new ObjectArrayList<>(); + for(Entry 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 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) { diff --git a/src/main/java/speiger/src/coreengine/rendering/models/loader/ModelLoader.java b/src/main/java/speiger/src/coreengine/rendering/models/loader/ModelLoader.java index f598893..c0a47b2 100644 --- a/src/main/java/speiger/src/coreengine/rendering/models/loader/ModelLoader.java +++ b/src/main/java/speiger/src/coreengine/rendering/models/loader/ModelLoader.java @@ -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 readModelData(AssetLocation location, AssetManager manager) - { - try(IAsset asset = manager.getAsset(location)) - { - List 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 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 readLegacyModelData(AssetLocation location, AssetManager manager) - { - List resultModels = new ObjectArrayList(); - 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 readModelData(AssetLocation location, AssetManager manager) + { + try(IAsset asset = manager.getAsset(location)) + { + List 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 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 readLegacyModelData(AssetLocation location, AssetManager manager) + { + List resultModels = new ObjectArrayList(); + 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 IMPORTS = Object2ObjectMap.builder().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 IMPORTS = Object2ObjectMap.builder().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 ""; + } + }); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/shaderOld/ShaderProgram.java b/src/main/java/speiger/src/coreengine/rendering/shaderOld/ShaderProgram.java index 634cbaf..a1ea716 100644 --- a/src/main/java/speiger/src/coreengine/rendering/shaderOld/ShaderProgram.java +++ b/src/main/java/speiger/src/coreengine/rendering/shaderOld/ShaderProgram.java @@ -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 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 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; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/tesselationOld/Tesselator.java b/src/main/java/speiger/src/coreengine/rendering/tesselationOld/Tesselator.java index 71c6cc2..c0f4530 100644 --- a/src/main/java/speiger/src/coreengine/rendering/tesselationOld/Tesselator.java +++ b/src/main/java/speiger/src/coreengine/rendering/tesselationOld/Tesselator.java @@ -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 diff --git a/src/main/java/speiger/src/coreengine/rendering/tesselationOld/VertexType.java b/src/main/java/speiger/src/coreengine/rendering/tesselationOld/VertexType.java index 08426fb..7de9ab5 100644 --- a/src/main/java/speiger/src/coreengine/rendering/tesselationOld/VertexType.java +++ b/src/main/java/speiger/src/coreengine/rendering/tesselationOld/VertexType.java @@ -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 { diff --git a/src/main/java/speiger/src/coreengine/rendering/textures/simple/SimpleTexture.java b/src/main/java/speiger/src/coreengine/rendering/textures/simple/SimpleTexture.java index 7a2de5f..a05c5b8 100644 --- a/src/main/java/speiger/src/coreengine/rendering/textures/simple/SimpleTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/textures/simple/SimpleTexture.java @@ -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; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/texturesOld/base/TextureManager.java b/src/main/java/speiger/src/coreengine/rendering/texturesOld/base/TextureManager.java index 6979de3..05883f5 100644 --- a/src/main/java/speiger/src/coreengine/rendering/texturesOld/base/TextureManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/texturesOld/base/TextureManager.java @@ -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> 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> 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; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/texturesOld/normal/SimpleTexture.java b/src/main/java/speiger/src/coreengine/rendering/texturesOld/normal/SimpleTexture.java index cad32f3..69dc9ab 100644 --- a/src/main/java/speiger/src/coreengine/rendering/texturesOld/normal/SimpleTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/texturesOld/normal/SimpleTexture.java @@ -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> 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> 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; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/texturesOld/stb/STBTexture.java b/src/main/java/speiger/src/coreengine/rendering/texturesOld/stb/STBTexture.java index a83683c..8ea8a04 100644 --- a/src/main/java/speiger/src/coreengine/rendering/texturesOld/stb/STBTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/texturesOld/stb/STBTexture.java @@ -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; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/utils/functions/Functions.java b/src/main/java/speiger/src/coreengine/utils/functions/Functions.java index e44fb22..4faf99c 100644 --- a/src/main/java/speiger/src/coreengine/utils/functions/Functions.java +++ b/src/main/java/speiger/src/coreengine/utils/functions/Functions.java @@ -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 ALWAYS_TRUE = (T) -> true; - static final Consumer EMPTY_CONSUMER = (T) -> {}; - public static final Predicate 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 Predicate getAlwaysTrue() { - return (Predicate)ALWAYS_TRUE; - } - - @SuppressWarnings("unchecked") - public static Consumer getVoidConsumer() { - return (Consumer)EMPTY_CONSUMER; - } -} +package speiger.src.coreengine.utils.functions; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class Functions +{ + static final Predicate ALWAYS_TRUE = _ -> true; + static final Consumer EMPTY_CONSUMER = _ -> {}; + public static final Predicate 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 Predicate getAlwaysTrue() { + return (Predicate)ALWAYS_TRUE; + } + + @SuppressWarnings("unchecked") + public static Consumer getVoidConsumer() { + return (Consumer)EMPTY_CONSUMER; + } +} diff --git a/src/main/java/speiger/src/coreengine/utils/io/dataTag/compression/DataTagLimiter.java b/src/main/java/speiger/src/coreengine/utils/io/dataTag/compression/DataTagLimiter.java index c9e79bd..74a1cfb 100644 --- a/src/main/java/speiger/src/coreengine/utils/io/dataTag/compression/DataTagLimiter.java +++ b/src/main/java/speiger/src/coreengine/utils/io/dataTag/compression/DataTagLimiter.java @@ -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"); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/math/MathUtils.java b/src/math/java/speiger/src/coreengine/math/MathUtils.java similarity index 96% rename from src/main/java/speiger/src/coreengine/math/MathUtils.java rename to src/math/java/speiger/src/coreengine/math/MathUtils.java index ca87f24..4c4c839 100644 --- a/src/main/java/speiger/src/coreengine/math/MathUtils.java +++ b/src/math/java/speiger/src/coreengine/math/MathUtils.java @@ -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); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/math/value/ConstantValue.java b/src/math/java/speiger/src/coreengine/math/value/ConstantValue.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/ConstantValue.java rename to src/math/java/speiger/src/coreengine/math/value/ConstantValue.java diff --git a/src/main/java/speiger/src/coreengine/math/value/CubicValue.java b/src/math/java/speiger/src/coreengine/math/value/CubicValue.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/CubicValue.java rename to src/math/java/speiger/src/coreengine/math/value/CubicValue.java diff --git a/src/main/java/speiger/src/coreengine/math/value/IValue.java b/src/math/java/speiger/src/coreengine/math/value/IValue.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/IValue.java rename to src/math/java/speiger/src/coreengine/math/value/IValue.java diff --git a/src/main/java/speiger/src/coreengine/math/value/LiniarValue.java b/src/math/java/speiger/src/coreengine/math/value/LiniarValue.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/LiniarValue.java rename to src/math/java/speiger/src/coreengine/math/value/LiniarValue.java diff --git a/src/main/java/speiger/src/coreengine/math/value/QuadraticValue.java b/src/math/java/speiger/src/coreengine/math/value/QuadraticValue.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/QuadraticValue.java rename to src/math/java/speiger/src/coreengine/math/value/QuadraticValue.java diff --git a/src/main/java/speiger/src/coreengine/math/value/Value.java b/src/math/java/speiger/src/coreengine/math/value/Value.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/value/Value.java rename to src/math/java/speiger/src/coreengine/math/value/Value.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/Vec.java b/src/math/java/speiger/src/coreengine/math/vector/Vec.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/Vec.java rename to src/math/java/speiger/src/coreengine/math/vector/Vec.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2b.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2b.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2b.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2b.java diff --git a/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java new file mode 100644 index 0000000..3c8b65c --- /dev/null +++ b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2bImmutable.java @@ -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); } +} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2bMutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2bMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec2bMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec2bMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3b.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3b.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3b.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3b.java diff --git a/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java new file mode 100644 index 0000000..527ce35 --- /dev/null +++ b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3bImmutable.java @@ -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); } +} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3bMutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3bMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec3bMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec3bMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4b.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4b.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4b.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4b.java diff --git a/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java new file mode 100644 index 0000000..0e4bce6 --- /dev/null +++ b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4bImmutable.java @@ -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); } +} diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4bMutable.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4bMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vec4bMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vec4bMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/bytes/Vecb.java b/src/math/java/speiger/src/coreengine/math/vector/bytes/Vecb.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/bytes/Vecb.java rename to src/math/java/speiger/src/coreengine/math/vector/bytes/Vecb.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2d.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2d.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2d.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2d.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2dImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2dImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2dImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2dImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2dMutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2dMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec2dMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec2dMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3d.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3d.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3d.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3d.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3dImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3dImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3dImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3dImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3dMutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3dMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec3dMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec3dMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4d.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4d.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4d.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4d.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4dImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4dImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4dImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4dImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4dMutable.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4dMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vec4dMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vec4dMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/doubles/Vecd.java b/src/math/java/speiger/src/coreengine/math/vector/doubles/Vecd.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/doubles/Vecd.java rename to src/math/java/speiger/src/coreengine/math/vector/doubles/Vecd.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec2f.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec2f.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec2f.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec2f.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec2fImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec2fImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec2fImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec2fImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec2fMutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec2fMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec2fMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec2fMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec3f.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec3f.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec3f.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec3f.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec3fImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec3fImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec3fImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec3fImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec3fMutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec3fMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec3fMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec3fMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec4f.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec4f.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec4f.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec4f.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec4fImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec4fImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec4fImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec4fImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vec4fMutable.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vec4fMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vec4fMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vec4fMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/floats/Vecf.java b/src/math/java/speiger/src/coreengine/math/vector/floats/Vecf.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/floats/Vecf.java rename to src/math/java/speiger/src/coreengine/math/vector/floats/Vecf.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec2i.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec2i.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec2i.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec2i.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec2iImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec2iImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec2iImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec2iImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec2iMutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec2iMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec2iMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec2iMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec3i.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec3i.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec3i.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec3i.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec3iImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec3iImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec3iImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec3iImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec3iMutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec3iMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec3iMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec3iMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec4i.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec4i.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec4i.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec4i.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec4iImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec4iImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec4iImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec4iImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Vec4iMutable.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Vec4iMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Vec4iMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Vec4iMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/ints/Veci.java b/src/math/java/speiger/src/coreengine/math/vector/ints/Veci.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/ints/Veci.java rename to src/math/java/speiger/src/coreengine/math/vector/ints/Veci.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec2l.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec2l.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec2l.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec2l.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec2lImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec2lImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec2lImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec2lImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec2lMutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec2lMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec2lMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec2lMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec3l.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec3l.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec3l.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec3l.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec3lImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec3lImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec3lImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec3lImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec3lMutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec3lMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec3lMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec3lMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec4l.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec4l.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec4l.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec4l.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec4lImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec4lImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec4lImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec4lImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vec4lMutable.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vec4lMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vec4lMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vec4lMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/longs/Vecl.java b/src/math/java/speiger/src/coreengine/math/vector/longs/Vecl.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/longs/Vecl.java rename to src/math/java/speiger/src/coreengine/math/vector/longs/Vecl.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/matrix/ITransformOutput.java b/src/math/java/speiger/src/coreengine/math/vector/matrix/ITransformOutput.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/matrix/ITransformOutput.java rename to src/math/java/speiger/src/coreengine/math/vector/matrix/ITransformOutput.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java b/src/math/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java similarity index 97% rename from src/main/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java rename to src/math/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java index 92d78f2..4c8d5d6 100644 --- a/src/main/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java +++ b/src/math/java/speiger/src/coreengine/math/vector/matrix/Matrix4f.java @@ -1,766 +1,767 @@ -package speiger.src.coreengine.math.vector.matrix; - -import java.nio.ByteBuffer; -import java.nio.FloatBuffer; -import java.util.Arrays; - -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.vector.floats.Vec3f; -import speiger.src.coreengine.math.vector.floats.Vec4f; -import speiger.src.coreengine.math.vector.quaternion.Quaternion; - -public class Matrix4f { - public static final int PROPERTY_UNKNOWN = 0; - public static final int PROPERTY_IDENTITY = 1 << 0; - public static final int PROPERTY_AFFINE = 1 << 1; - public static final int PROPERTY_TRANSLATION = 1 << 2; - public static final int PROPERTY_SCALE = 1 << 3; - public static final int PROPERTY_ROTATION = 1 << 4; - private static final int PROPERTY_DEFAULT = 3; - - public static final int M00 = 0; - public static final int M01 = 1; - public static final int M02 = 2; - public static final int M03 = 3; - public static final int M10 = 4; - public static final int M11 = 5; - public static final int M12 = 6; - public static final int M13 = 7; - public static final int M20 = 8; - public static final int M21 = 9; - public static final int M22 = 10; - public static final int M23 = 11; - public static final int M30 = 12; - public static final int M31 = 13; - public static final int M32 = 14; - public static final int M33 = 15; - - int properties; - float[] data = new float[16]; - - public Matrix4f() { - setIdentity(); - } - public Matrix4f(float[] data) { - System.arraycopy(data, 0, this.data, 0, 16); - evaluateProps(); - } - public Matrix4f(Matrix4f other) { - this(other.data); - } - - public Matrix4f store(FloatBuffer buffer) { - buffer.put(data); - return this; - } - - public Matrix4f store(ByteBuffer buffer) { - for(int i = 0;i < 16;i++) - buffer.putFloat(data[i]); - return this; - } - - public Matrix4f store(Matrix4f other) { - System.arraycopy(data, 0, other.data, 0, 16); - return this; - } - - public Matrix4f load(FloatBuffer buffer) { - buffer.get(data); - return evaluateProps(); - } - - public Matrix4f load(ByteBuffer buffer) { - for(int i = 0;i < 16;i++) - data[i] = buffer.getFloat(); - return evaluateProps(); - } - - public Matrix4f load(Matrix4f other) { - System.arraycopy(other.data, 0, data, 0, 16); - return evaluateProps(); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder().append("\n"); - buf.append("x0=").append(data[M00]).append(' ').append("y0=").append(data[M10]).append(' ').append("z0=").append(data[M20]).append(' ').append("w0=").append(data[M30]).append('\n'); - buf.append("x1=").append(data[M01]).append(' ').append("y1=").append(data[M11]).append(' ').append("z1=").append(data[M21]).append(' ').append("w1=").append(data[M31]).append('\n'); - buf.append("x2=").append(data[M02]).append(' ').append("y2=").append(data[M12]).append(' ').append("z2=").append(data[M22]).append(' ').append("w2=").append(data[M32]).append('\n'); - buf.append("x3=").append(data[M03]).append(' ').append("y3=").append(data[M13]).append(' ').append("z3=").append(data[M23]).append(' ').append("w3=").append(data[M33]).append('\n'); - return buf.toString(); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof Matrix4f matrix && Arrays.equals(data, matrix.data); - } - - public float[] getData() { return data; } - public float get(int index) { return data[index]; } - public float get(int column, int row) { return data[(column * 4) + row]; } - public int properties() { return properties; } - - public Matrix4f set(int column, int row, float value) { - data[(column * 4) + row] = value; - properties = PROPERTY_UNKNOWN; - return this; - } - - public Matrix4f set(int index, float value) { - data[index] = value; - properties = PROPERTY_UNKNOWN; - return this; - } - - public Matrix4f evaluateProps() { - int properties = PROPERTY_UNKNOWN; - if(data[M03] == 0F && data[M13] == 0F && data[M23] == 0F && data[M33] == 1F) { - properties |= PROPERTY_AFFINE; - if(data[M01] == 0F && data[M02] == 0F && data[M10] == 0F && data[M12] == 0F && data[M20] == 0F && data[M21] == 0F) { - properties |= PROPERTY_TRANSLATION; - if(data[M00] == 1F && data[M11] == 1F && data[M22] == 1F) { - if(data[M30] == 0F && data[M31] == 0F && data[M32] == 0F) { - properties |= PROPERTY_IDENTITY; - } - } - else { - properties |= PROPERTY_SCALE; - } - } - else { - properties |= PROPERTY_ROTATION; - } - } - this.properties = properties; - return this; - } - - public Matrix4f setIdentity() { - Arrays.fill(data, 0F); - data[M00] = 1F; - data[M11] = 1F; - data[M22] = 1F; - data[M33] = 1F; - properties = PROPERTY_DEFAULT; - return this; - } - - public Matrix4f invert() { - float determinant = determinant(); - if(determinant != 0F) { - float determinant_inv = 1F / determinant; - float t00 = determinant3x3(data[M11], data[M12], data[M13], data[M21], data[M22], data[M23], data[M31], data[M32], data[M33]); - float t01 = -determinant3x3(data[M10], data[M12], data[M13], data[M20], data[M22], data[M23], data[M30], data[M32], data[M33]); - float t02 = determinant3x3(data[M10], data[M11], data[M13], data[M20], data[M21], data[M23], data[M30], data[M31], data[M33]); - float t03 = -determinant3x3(data[M10], data[M11], data[M12], data[M20], data[M21], data[M22], data[M30], data[M31], data[M32]); - float t10 = -determinant3x3(data[M01], data[M02], data[M03], data[M21], data[M22], data[M23], data[M31], data[M32], data[M33]); - float t11 = determinant3x3(data[M00], data[M02], data[M03], data[M20], data[M22], data[M23], data[M30], data[M32], data[M33]); - float t12 = -determinant3x3(data[M00], data[M01], data[M03], data[M20], data[M21], data[M23], data[M30], data[M31], data[M33]); - float t13 = determinant3x3(data[M00], data[M01], data[M02], data[M20], data[M21], data[M22], data[M30], data[M31], data[M32]); - float t20 = determinant3x3(data[M01], data[M02], data[M03], data[M11], data[M12], data[M13], data[M31], data[M32], data[M33]); - float t21 = -determinant3x3(data[M00], data[M02], data[M03], data[M10], data[M12], data[M13], data[M30], data[M32], data[M33]); - float t22 = determinant3x3(data[M00], data[M01], data[M03], data[M10], data[M11], data[M13], data[M30], data[M31], data[M33]); - float t23 = -determinant3x3(data[M00], data[M01], data[M02], data[M10], data[M11], data[M12], data[M30], data[M31], data[M32]); - float t30 = -determinant3x3(data[M01], data[M02], data[M03], data[M11], data[M12], data[M13], data[M21], data[M22], data[M23]); - float t31 = determinant3x3(data[M00], data[M02], data[M03], data[M10], data[M12], data[M13], data[M20], data[M22], data[M23]); - float t32 = -determinant3x3(data[M00], data[M01], data[M03], data[M10], data[M11], data[M13], data[M20], data[M21], data[M23]); - float t33 = determinant3x3(data[M00], data[M01], data[M02], data[M10], data[M11], data[M12], data[M20], data[M21], data[M22]); - - data[M00] = t00 * determinant_inv; - data[M11] = t11 * determinant_inv; - data[M22] = t22 * determinant_inv; - data[M33] = t33 * determinant_inv; - data[M01] = t10 * determinant_inv; - data[M10] = t01 * determinant_inv; - data[M20] = t02 * determinant_inv; - data[M02] = t20 * determinant_inv; - data[M12] = t21 * determinant_inv; - data[M21] = t12 * determinant_inv; - data[M03] = t30 * determinant_inv; - data[M30] = t03 * determinant_inv; - data[M13] = t31 * determinant_inv; - data[M31] = t13 * determinant_inv; - data[M32] = t23 * determinant_inv; - data[M23] = t32 * determinant_inv; - evaluateProps(); - } - return this; - } - - public Matrix4f flip() { - data[M00] = -data[M00]; - data[M01] = -data[M01]; - data[M02] = -data[M02]; - data[M03] = -data[M03]; - data[M10] = -data[M10]; - data[M11] = -data[M11]; - data[M12] = -data[M12]; - data[M13] = -data[M13]; - data[M20] = -data[M20]; - data[M21] = -data[M21]; - data[M22] = -data[M22]; - data[M23] = -data[M23]; - data[M30] = -data[M30]; - data[M31] = -data[M31]; - data[M32] = -data[M32]; - data[M33] = -data[M33]; - return evaluateProps(); - } - - public Matrix4f negate() { - Arrays.fill(data, 0F); - return evaluateProps(); - } - - public Matrix4f add(Matrix4f other) { - data[M00] += other.data[M00]; - data[M01] += other.data[M01]; - data[M02] += other.data[M02]; - data[M03] += other.data[M03]; - data[M10] += other.data[M10]; - data[M11] += other.data[M11]; - data[M12] += other.data[M12]; - data[M13] += other.data[M13]; - data[M20] += other.data[M20]; - data[M21] += other.data[M21]; - data[M22] += other.data[M22]; - data[M23] += other.data[M23]; - data[M30] += other.data[M30]; - data[M31] += other.data[M31]; - data[M32] += other.data[M32]; - data[M33] += other.data[M33]; - return evaluateProps(); - } - - public Matrix4f sub(Matrix4f other) { - data[M00] -= other.data[M00]; - data[M01] -= other.data[M01]; - data[M02] -= other.data[M02]; - data[M03] -= other.data[M03]; - data[M10] -= other.data[M10]; - data[M11] -= other.data[M11]; - data[M12] -= other.data[M12]; - data[M13] -= other.data[M13]; - data[M20] -= other.data[M20]; - data[M21] -= other.data[M21]; - data[M22] -= other.data[M22]; - data[M23] -= other.data[M23]; - data[M30] -= other.data[M30]; - data[M31] -= other.data[M31]; - data[M32] -= other.data[M32]; - data[M33] -= other.data[M33]; - return evaluateProps(); - } - - public Matrix4f multiply(Matrix4f other) { - float data0 = data[M00] * other.data[M00] + data[M10] * other.data[M01] + data[M20] * other.data[M02] + data[M30] * other.data[M03]; - float data1 = data[M01] * other.data[M00] + data[M11] * other.data[M01] + data[M21] * other.data[M02] + data[M31] * other.data[M03]; - float data2 = data[M02] * other.data[M00] + data[M12] * other.data[M01] + data[M22] * other.data[M02] + data[M32] * other.data[M03]; - float data3 = data[M03] * other.data[M00] + data[M13] * other.data[M01] + data[M23] * other.data[M02] + data[M33] * other.data[M03]; - float data4 = data[M00] * other.data[M10] + data[M10] * other.data[M11] + data[M20] * other.data[M12] + data[M30] * other.data[M13]; - float data5 = data[M01] * other.data[M10] + data[M11] * other.data[M11] + data[M21] * other.data[M12] + data[M31] * other.data[M13]; - float data6 = data[M02] * other.data[M10] + data[M12] * other.data[M11] + data[M22] * other.data[M12] + data[M32] * other.data[M13]; - float data7 = data[M03] * other.data[M10] + data[M13] * other.data[M11] + data[M23] * other.data[M12] + data[M33] * other.data[M13]; - float data8 = data[M00] * other.data[M20] + data[M10] * other.data[M21] + data[M20] * other.data[M22] + data[M30] * other.data[M23]; - float data9 = data[M01] * other.data[M20] + data[M11] * other.data[M21] + data[M21] * other.data[M22] + data[M31] * other.data[M23]; - float data10 = data[M02] * other.data[M20] + data[M12] * other.data[M21] + data[M22] * other.data[M22] + data[M32] * other.data[M23]; - float data11 = data[M03] * other.data[M20] + data[M13] * other.data[M21] + data[M23] * other.data[M22] + data[M33] * other.data[M23]; - float data12 = data[M00] * other.data[M30] + data[M10] * other.data[M31] + data[M20] * other.data[M32] + data[M30] * other.data[M33]; - float data13 = data[M01] * other.data[M30] + data[M11] * other.data[M31] + data[M21] * other.data[M32] + data[M31] * other.data[M33]; - float data14 = data[M02] * other.data[M30] + data[M12] * other.data[M31] + data[M22] * other.data[M32] + data[M32] * other.data[M33]; - float data15 = data[M03] * other.data[M30] + data[M13] * other.data[M31] + data[M23] * other.data[M32] + data[M33] * other.data[M33]; - data[M00] = data0; - data[M01] = data1; - data[M02] = data2; - data[M03] = data3; - data[M10] = data4; - data[M11] = data5; - data[M12] = data6; - data[M13] = data7; - data[M20] = data8; - data[M21] = data9; - data[M22] = data10; - data[M23] = data11; - data[M30] = data12; - data[M31] = data13; - data[M32] = data14; - data[M33] = data15; - return evaluateProps(); - } - - public Matrix4f transpose() { - float data0 = data[M00]; - float data1 = data[M10]; - float data2 = data[M20]; - float data3 = data[M30]; - float data4 = data[M01]; - float data5 = data[M11]; - float data6 = data[M21]; - float data7 = data[M31]; - float data8 = data[M02]; - float data9 = data[M12]; - float data10 = data[M22]; - float data11 = data[M32]; - float data12 = data[M03]; - float data13 = data[M13]; - float data14 = data[M23]; - float data15 = data[M33]; - - data[M00] = data0; - data[M01] = data1; - data[M02] = data2; - data[M03] = data3; - data[M10] = data4; - data[M11] = data5; - data[M12] = data6; - data[M13] = data7; - data[M20] = data8; - data[M21] = data9; - data[M22] = data10; - data[M23] = data11; - data[M30] = data12; - data[M31] = data13; - data[M32] = data14; - data[M33] = data15; - return evaluateProps(); - } - - public Matrix4f transpose3x3() { - float nm00 = data[M00]; - float nm01 = data[M10]; - float nm02 = data[M20]; - float nm10 = data[M01]; - float nm11 = data[M11]; - float nm12 = data[M21]; - float nm20 = data[M02]; - float nm21 = data[M12]; - float nm22 = data[M22]; - data[M00] = nm00; - data[M01] = nm01; - data[M02] = nm02; - data[M10] = nm10; - data[M11] = nm11; - data[M12] = nm12; - data[M20] = nm20; - data[M21] = nm21; - data[M22] = nm22; - return evaluateProps(); - } - - public Matrix4f decompose(Vec3f position, Quaternion rotation, Vec3f scale) { - position.set(get(3, 0), get(3, 1), get(3, 2)); - rotation.set(this); - scale.set(get(0, 0), get(1, 1), get(2, 2)); - return this; - } - - public Matrix4f setTranslation(float x, float y, float z) { - data[M30] = x; - data[M31] = y; - data[M32] = z; - if(x != 0F || y != 0F || z != 0F) properties |= PROPERTY_TRANSLATION; - else properties &= PROPERTY_TRANSLATION; - return this; - } - - public Matrix4f translateZ(float z) { - if(z == 0F) return this; - if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { - data[M32] += z; - return evaluateProps(); - } - data[M30] += data[M20] * z; - data[M31] += data[M21] * z; - data[M32] += data[M22] * z; - data[M33] += data[M23] * z; - return evaluateProps(); - } - - public Matrix4f translate(float x, float y) { - if(x == 0F && y == 0F) return this; - if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { - data[M30] += x; - data[M31] += y; - return evaluateProps(); - } - data[M30] += data[M00] * x + data[M10] * y; - data[M31] += data[M01] * x + data[M11] * y; - data[M32] += data[M02] * x + data[M12] * y; - data[M33] += data[M03] * x + data[M13] * y; - return evaluateProps(); - } - - public Matrix4f translate(float x, float y, float z) { - if(x == 0F && y == 0F && z == 0F) return this; - if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { - data[M30] += x; - data[M31] += y; - data[M32] += z; - properties |= PROPERTY_TRANSLATION; - return evaluateProps(); - } - data[M30] += data[M00] * x + data[M10] * y + data[M20] * z; - data[M31] += data[M01] * x + data[M11] * y + data[M21] * z; - data[M32] += data[M02] * x + data[M12] * y + data[M22] * z; - data[M33] += data[M03] * x + data[M13] * y + data[M23] * z; - return evaluateProps(); - } - - public Matrix4f rotateX(float angle) { return rotate((float)Math.toRadians(angle), 1F, 0F, 0F); } - public Matrix4f rotateY(float angle) { return rotate((float)Math.toRadians(angle), 0F, 1F, 0F); } - public Matrix4f rotateZ(float angle) { return rotate((float)Math.toRadians(angle), 0F, 0F, 1F); } - public Matrix4f rotateRadX(float angle) { return rotate(angle, 1F, 0F, 0F); } - public Matrix4f rotateRadY(float angle) { return rotate(angle, 0F, 1F, 0F); } - public Matrix4f rotateRadZ(float angle) { return rotate(angle, 0F, 0F, 1F); } - - public Matrix4f rotate(float angle, float x, float y, float z) { - float c = MathUtils.cos(angle); - float s = MathUtils.sin(angle); - float oneminusc = 1.0F - c; - float xy = x * y; - float yz = y * z; - float xz = x * z; - float xs = x * s; - float ys = y * s; - float zs = z * s; - - float f00 = x * x * oneminusc + c; - float f01 = xy * oneminusc + zs; - float f02 = xz * oneminusc - ys; - - float f10 = xy * oneminusc - zs; - float f11 = y * y * oneminusc + c; - float f12 = yz * oneminusc + xs; - - float f20 = xz * oneminusc + ys; - float f21 = yz * oneminusc - xs; - float f22 = z * z * oneminusc + c; - - float t00 = data[M00] * f00 + data[M10] * f01 + data[M20] * f02; - float t01 = data[M01] * f00 + data[M11] * f01 + data[M21] * f02; - float t02 = data[M02] * f00 + data[M12] * f01 + data[M22] * f02; - float t03 = data[M03] * f00 + data[M13] * f01 + data[M23] * f02; - float t10 = data[M00] * f10 + data[M10] * f11 + data[M20] * f12; - float t11 = data[M01] * f10 + data[M11] * f11 + data[M21] * f12; - float t12 = data[M02] * f10 + data[M12] * f11 + data[M22] * f12; - float t13 = data[M03] * f10 + data[M13] * f11 + data[M23] * f12; - data[M20] = data[M00] * f20 + data[M10] * f21 + data[M20] * f22; - data[M21] = data[M01] * f20 + data[M11] * f21 + data[M21] * f22; - data[M22] = data[M02] * f20 + data[M12] * f21 + data[M22] * f22; - data[M23] = data[M03] * f20 + data[M13] * f21 + data[M23] * f22; - data[M00] = t00; - data[M01] = t01; - data[M02] = t02; - data[M03] = t03; - data[M10] = t10; - data[M11] = t11; - data[M12] = t12; - data[M13] = t13; - return evaluateProps(); - } - - public Matrix4f rotate(Quaternion rotation) { - float w2 = rotation.getW() * rotation.getW(); - float x2 = rotation.getX() * rotation.getX(); - float y2 = rotation.getY() * rotation.getY(); - float z2 = rotation.getZ() * rotation.getZ(); - float zw = rotation.getZ() * rotation.getW(); - float dzw = zw + zw; - float xy = rotation.getX() * rotation.getY(); - float dxy = xy + xy; - float xz = rotation.getX() * rotation.getZ(); - float dxz = xz + xz; - float yw = rotation.getY() * rotation.getW(); - float dyw = yw + yw; - float yz = rotation.getY() * rotation.getZ(); - float dyz = yz + yz; - float xw = rotation.getX() * rotation.getW(); - float dxw = xw + xw; - float rm00 = w2 + x2 - z2 - y2; - float rm01 = dxy + dzw; - float rm02 = dxz - dyw; - float rm10 = -dzw + dxy; - float rm11 = y2 - z2 + w2 - x2; - float rm12 = dyz + dxw; - float rm20 = dyw + dxz; - float rm21 = dyz - dxw; - float rm22 = z2 - y2 - x2 + w2; - float nm00 = data[M00] * rm00 + data[M10] * rm01 + data[M20] * rm02; - float nm01 = data[M01] * rm00 + data[M11] * rm01 + data[M21] * rm02; - float nm02 = data[M02] * rm00 + data[M12] * rm01 + data[M22] * rm02; - float nm03 = data[M03] * rm00 + data[M13] * rm01 + data[M23] * rm02; - float nm10 = data[M00] * rm10 + data[M10] * rm11 + data[M20] * rm12; - float nm11 = data[M01] * rm10 + data[M11] * rm11 + data[M21] * rm12; - float nm12 = data[M02] * rm10 + data[M12] * rm11 + data[M22] * rm12; - float nm13 = data[M03] * rm10 + data[M13] * rm11 + data[M23] * rm12; - data[M20] = data[M00] * rm20 + data[M10] * rm21 + data[M20] * rm22; - data[M21] = data[M01] * rm20 + data[M11] * rm21 + data[M21] * rm22; - data[M22] = data[M02] * rm20 + data[M12] * rm21 + data[M22] * rm22; - data[M23] = data[M03] * rm20 + data[M13] * rm21 + data[M23] * rm22; - data[M00] = nm00; - data[M01] = nm01; - data[M02] = nm02; - data[M03] = nm03; - data[M10] = nm10; - data[M11] = nm11; - data[M12] = nm12; - data[M13] = nm13; - return evaluateProps(); - } - - public Matrix4f setRotation(Matrix4f source) { - data[M00] = source.data[M00]; - data[M01] = source.data[M01]; - data[M02] = source.data[M02]; - data[M10] = source.data[M10]; - data[M11] = source.data[M11]; - data[M12] = source.data[M12]; - data[M20] = source.data[M20]; - data[M21] = source.data[M21]; - data[M22] = source.data[M22]; - return evaluateProps(); - } - - public Matrix4f setBillboard(Matrix4f source) { - data[M00] = source.data[M00]; - data[M01] = source.data[M10]; - data[M02] = source.data[M20]; - data[M10] = source.data[M01]; - data[M11] = source.data[M11]; - data[M12] = source.data[M21]; - data[M20] = source.data[M02]; - data[M21] = source.data[M12]; - data[M22] = source.data[M22]; - return evaluateProps(); - } - - public Matrix4f scale(float value) { return scale(value, value, value); } - - public Matrix4f scale(float x, float y, float z) { - if(x != 1F) { - data[M00] *= x; - data[M01] *= x; - data[M02] *= x; - data[M03] *= x; - } - if(y != 1F) { - data[M10] *= y; - data[M11] *= y; - data[M12] *= y; - data[M13] *= y; - } - if(z != 1F) { - data[M20] *= z; - data[M21] *= z; - data[M22] *= z; - data[M23] *= z; - } - return evaluateProps(); - } - - public Matrix4f unscale(float scale) { return unscale(scale, scale, scale); } - - public Matrix4f unscale(float x, float y, float z) { - if(x != 1F) { - data[M00] /= x; - data[M01] /= x; - data[M02] /= x; - data[M03] /= x; - } - if(y != 1F) { - data[M10] /= y; - data[M11] /= y; - data[M12] /= y; - data[M13] /= y; - } - if(z != 1F) { - data[M20] /= z; - data[M21] /= z; - data[M22] /= z; - data[M23] /= z; - } - return evaluateProps(); - } - - public Matrix4f setPerspective(float fovy, float aspect, float zNear, float zFar) { - float h = (float)Math.tan(fovy * 0.5F); - set(0, 0, 1F / (h * aspect)).set(1, 1, 1F / h); - boolean farInf = zFar > 0 && Float.isInfinite(zFar); - boolean nearInf = zNear > 0 && Float.isInfinite(zNear); - if(farInf) { - set(2, 2, 0.999999F).set(3, 2, 1.999999F * zNear); - } - else if(nearInf) { - float e = 1E-6F; - set(2, 2, 1F - e).set(3, 2, (2F - e) * zFar); - } - else { - set(2, 2, (zFar + zNear) / (zNear - zFar)).set(3, 2, (zFar + zFar) * zNear / (zNear - zFar)); - } - return set(2, 3, -1F).evaluateProps(); - } - - public Matrix4f getTranslation(Vec3f vec) { - vec.set(data[M30], data[M31], data[M32]); - return this; - } - - public Matrix4f getScale(Vec3f vec) { - vec.x((float)Math.sqrt(data[M00] * data[M00] + data[M01] * data[M01] + data[M02] * data[M02])); - vec.y((float)Math.sqrt(data[M10] * data[M10] + data[M11] * data[M11] + data[M12] * data[M12])); - vec.z((float)Math.sqrt(data[M20] * data[M20] + data[M21] * data[M21] + data[M22] * data[M22])); - return this; - } - - public void transform(Vec4f input, FloatBuffer buffer) { - transform(input.x(), input.y(), input.z(), input.w(), buffer::put); - } - - public void transform(Vec3f input, boolean position, FloatBuffer buffer) { - transform(input.x(), input.y(), input.z(), position, buffer::put); - } - - public void transform(float x, float y, float z, float w, ITransformOutput output) { - if((properties & PROPERTY_IDENTITY) != 0) { - output.accept(x, y, z, w); - return; - } - if((properties & PROPERTY_ROTATION) != 0) { - output.accept(fma(M00, M10, M20, M30, x, y, z, w), fma(M01, M11, M21, M31, x, y, z, w), fma(M02, M12, M22, M32, x, y, z, w), fma(M03, M13, M23, M33, x, y, z, w)); - return; - } - if((properties & PROPERTY_SCALE) != 0) { - output.accept(Math.fma(data[M00], x, data[M30]), Math.fma(data[M01], y, data[M31]), Math.fma(data[M02], z, data[M32]), Math.fma(data[M03], w, data[M33])); - return; - } - output.accept(x + data[M30], y + data[M31], z + data[M32], w + data[M33]); - } - - public void transform(float x, float y, float z, boolean pos, ITransformOutput output) { - if((properties & PROPERTY_IDENTITY) != 0) { - output.accept(x, y, z); - return; - } - if((properties & PROPERTY_ROTATION) != 0) { - float w = pos ? 1F : 0F; - output.accept(fma(M00, M10, M20, M30, x, y, z, w), fma(M01, M11, M21, M31, x, y, z, w), fma(M02, M12, M22, M32, x, y, z, w)); - return; - } - if((properties & PROPERTY_SCALE) != 0) { - if(pos) output.accept(Math.fma(data[M00], x, data[M30]), Math.fma(data[M01], y, data[M31]), Math.fma(data[M02], z, data[M32])); - else output.accept(data[M00] * x, data[M01] * y, data[M02] * z); - return; - } - if(pos) { - output.accept(x + data[M30], y + data[M31], z + data[M32]); - return; - } - output.accept(x, y, z); - } - - public float fma(int xPos, int yPos, int zPos, int wPos, float x, float y, float z, float w) { - return Math.fma(data[xPos], x, Math.fma(data[yPos], y, Math.fma(data[zPos], z, data[wPos] * w))); - } - - public float determinant() { - float f = data[M00] * ((data[M11] * data[M22] * data[M33] + data[M12] * data[M23] * data[M31] + data[M13] * data[M21] * data[M32]) - data[M13] * data[M22] * data[M31] - data[M11] * data[M23] * data[M32] - data[M12] * data[M21] * data[M33]); - f -= data[M01] * ((data[M10] * data[M22] * data[M33] + data[M12] * data[M23] * data[M30] + data[M13] * data[M20] * data[M32]) - data[M13] * data[M22] * data[M30] - data[M10] * data[M23] * data[M32] - data[M12] * data[M20] * data[M33]); - f += data[M02] * ((data[M10] * data[M21] * data[M33] + data[M11] * data[M23] * data[M30] + data[M13] * data[M20] * data[M31]) - data[M13] * data[M21] * data[M30] - data[M10] * data[M23] * data[M31] - data[M11] * data[M20] * data[M33]); - f -= data[M03] * ((data[M10] * data[M21] * data[M32] + data[M11] * data[M22] * data[M30] + data[M12] * data[M20] * data[M31]) - data[M12] * data[M21] * data[M30] - data[M10] * data[M22] * data[M31] - data[M11] * data[M20] * data[M32]); - return f; - } - - public float determinant3x3(float t00, float t01, float t02, float t10, float t11, float t12, float t20, float t21, float t22) { - return t00 * (t11 * t22 - t12 * t21) + t01 * (t12 * t20 - t10 * t22) + t02 * (t10 * t21 - t11 * t20); - } - - public Vec3f project(float x, float y, float z, int[] viewport, Vec3f winCoordsDest) { - float invW = 1F / Math.fma(data[M03], x, Math.fma(data[M13], y, Math.fma(data[M23], z, data[M33]))); - float nx = Math.fma(data[M00], x, Math.fma(data[M10], y, Math.fma(data[M20], z, data[M30]))) * invW; - float ny = Math.fma(data[M01], x, Math.fma(data[M11], y, Math.fma(data[M21], z, data[M31]))) * invW; - float nz = Math.fma(data[M02], x, Math.fma(data[M12], y, Math.fma(data[M22], z, data[M32]))) * invW; - return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5F, 0.5F), viewport[2], viewport[0]), Math.fma(Math.fma(ny, 0.5F, 0.5F), viewport[3], viewport[1]), Math.fma(0.5F, nz, 0.5F)); - } - - public Vec3f unproject(float winX, float winY, float winZ, int[] viewport, Vec3f dest) { - float a = data[M00] * data[M11] - data[M01] * data[M10]; - float b = data[M00] * data[M12] - data[M02] * data[M10]; - float c = data[M00] * data[M13] - data[M03] * data[M10]; - float d = data[M01] * data[M12] - data[M02] * data[M11]; - float e = data[M01] * data[M13] - data[M03] * data[M11]; - float f = data[M02] * data[M13] - data[M03] * data[M12]; - float g = data[M20] * data[M31] - data[M21] * data[M30]; - float h = data[M20] * data[M32] - data[M22] * data[M30]; - float i = data[M20] * data[M33] - data[M23] * data[M30]; - float j = data[M21] * data[M32] - data[M22] * data[M31]; - float k = data[M21] * data[M33] - data[M23] * data[M31]; - float l = data[M22] * data[M33] - data[M23] * data[M32]; - float det = a * l - b * k + c * j + d * i - e * h + f * g; - det = 1F / det; - float im00 = (data[M11] * l - data[M12] * k + data[M13] * j) * det; - float im01 = (-data[M01] * l + data[M02] * k - data[M03] * j) * det; - float im02 = (data[M31] * f - data[M32] * e + data[M33] * d) * det; - float im03 = (-data[M21] * f + data[M22] * e - data[M23] * d) * det; - float im10 = (-data[M10] * l + data[M12] * i - data[M13] * h) * det; - float im11 = (data[M00] * l - data[M02] * i + data[M03] * h) * det; - float im12 = (-data[M30] * f + data[M32] * c - data[M33] * b) * det; - float im13 = (data[M20] * f - data[M22] * c + data[M23] * b) * det; - float im20 = (data[M10] * k - data[M11] * i + data[M13] * g) * det; - float im21 = (-data[M00] * k + data[M01] * i - data[M03] * g) * det; - float im22 = (data[M30] * e - data[M31] * c + data[M33] * a) * det; - float im23 = (-data[M20] * e + data[M21] * c - data[M23] * a) * det; - float im30 = (-data[M10] * j + data[M11] * h - data[M12] * g) * det; - float im31 = (data[M00] * j - data[M01] * h + data[M02] * g) * det; - float im32 = (-data[M30] * d + data[M31] * b - data[M32] * a) * det; - float im33 = (data[M20] * d - data[M21] * b + data[M22] * a) * det; - float ndcX = (winX - viewport[0]) / viewport[2] * 2F - 1F; - float ndcY = (winY - viewport[1]) / viewport[3] * 2F - 1F; - float ndcZ = winZ + winZ - 1F; - float invW = 1F / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); - return dest.set((im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW, (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW, (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW); - } - - public Matrix4f ortho(float x, float y, float width, float height, float zNear, float zFar) { - return ortho(x, x + width, y + height, y, zNear, zFar, false); - } - - public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) { - float rm00 = 2F / (right - left); - float rm11 = 2F / (top - bottom); - float rm22 = (zZeroToOne ? 1F : 2F) / (zFar - zNear); - float rm30 = (left + right) / (left - right); - float rm31 = (top + bottom) / (bottom - top); - float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); - - data[M30] = data[M00] * rm30 + data[M10] * rm31 + data[M20] * rm32 + data[M30]; - data[M31] = data[M01] * rm30 + data[M11] * rm31 + data[M21] * rm32 + data[M31]; - data[M32] = data[M02] * rm30 + data[M12] * rm31 + data[M22] * rm32 + data[M32]; - data[M33] = data[M03] * rm30 + data[M13] * rm31 + data[M23] * rm32 + data[M33]; - data[M00] = data[M00] * rm00; - data[M01] = data[M01] * rm00; - data[M02] = data[M02] * rm00; - data[M03] = data[M03] * rm00; - data[M10] = data[M10] * rm11; - data[M11] = data[M11] * rm11; - data[M12] = data[M12] * rm11; - data[M13] = data[M13] * rm11; - data[M20] = data[M20] * rm22; - data[M21] = data[M21] * rm22; - data[M22] = data[M22] * rm22; - data[M23] = data[M23] * rm22; - return evaluateProps(); - } - - public Vec4f storeFrustrumPlane(int plane, Vec4f toStore) { - return switch(plane) { - case 0 -> toStore.set(data[M03] + data[M00], data[M13] + data[M10], data[M23] + data[M20], data[M33] + data[M30]).normalize3D(); - case 1 -> toStore.set(data[M03] - data[M00], data[M13] - data[M10], data[M23] - data[M20], data[M33] - data[M30]).normalize3D(); - case 2 -> toStore.set(data[M03] + data[M01], data[M13] + data[M11], data[M23] + data[M21], data[M33] + data[M31]).normalize3D(); - case 3 -> toStore.set(data[M03] - data[M01], data[M13] - data[M11], data[M23] - data[M21], data[M33] - data[M31]).normalize3D(); - case 4 -> toStore.set(data[M03] + data[M02], data[M13] + data[M12], data[M23] + data[M22], data[M33] + data[M32]).normalize3D(); - case 5 -> toStore.set(data[M03] - data[M02], data[M13] - data[M12], data[M23] - data[M22], data[M33] - data[M32]).normalize3D(); - default -> toStore; - }; - } +package speiger.src.coreengine.math.vector.matrix; + +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.Arrays; + +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.vector.floats.Vec3f; +import speiger.src.coreengine.math.vector.floats.Vec4f; +import speiger.src.coreengine.math.vector.quaternion.Quaternion; + +public class Matrix4f { + public static final int PROPERTY_UNKNOWN = 0; + public static final int PROPERTY_IDENTITY = 1 << 0; + public static final int PROPERTY_AFFINE = 1 << 1; + public static final int PROPERTY_TRANSLATION = 1 << 2; + public static final int PROPERTY_SCALE = 1 << 3; + public static final int PROPERTY_ROTATION = 1 << 4; + private static final int PROPERTY_DEFAULT = 1; + + public static final int M00 = 0; + public static final int M01 = 1; + public static final int M02 = 2; + public static final int M03 = 3; + public static final int M10 = 4; + public static final int M11 = 5; + public static final int M12 = 6; + public static final int M13 = 7; + public static final int M20 = 8; + public static final int M21 = 9; + public static final int M22 = 10; + public static final int M23 = 11; + public static final int M30 = 12; + public static final int M31 = 13; + public static final int M32 = 14; + public static final int M33 = 15; + + int properties; + float[] data = new float[16]; + + public Matrix4f() { + setIdentity(); + } + public Matrix4f(float[] data) { + System.arraycopy(data, 0, this.data, 0, 16); + evaluateProps(); + } + public Matrix4f(Matrix4f other) { + this(other.data); + } + + public Matrix4f store(FloatBuffer buffer) { + buffer.put(data); + return this; + } + + public Matrix4f store(ByteBuffer buffer) { + for(int i = 0;i < 16;i++) + buffer.putFloat(data[i]); + return this; + } + + public Matrix4f store(Matrix4f other) { + System.arraycopy(data, 0, other.data, 0, 16); + return this; + } + + public Matrix4f load(FloatBuffer buffer) { + buffer.get(data); + return evaluateProps(); + } + + public Matrix4f load(ByteBuffer buffer) { + for(int i = 0;i < 16;i++) + data[i] = buffer.getFloat(); + return evaluateProps(); + } + + public Matrix4f load(Matrix4f other) { + System.arraycopy(other.data, 0, data, 0, 16); + return evaluateProps(); + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder().append("\n"); + buf.append("x0=").append(data[M00]).append(' ').append("y0=").append(data[M10]).append(' ').append("z0=").append(data[M20]).append(' ').append("w0=").append(data[M30]).append('\n'); + buf.append("x1=").append(data[M01]).append(' ').append("y1=").append(data[M11]).append(' ').append("z1=").append(data[M21]).append(' ').append("w1=").append(data[M31]).append('\n'); + buf.append("x2=").append(data[M02]).append(' ').append("y2=").append(data[M12]).append(' ').append("z2=").append(data[M22]).append(' ').append("w2=").append(data[M32]).append('\n'); + buf.append("x3=").append(data[M03]).append(' ').append("y3=").append(data[M13]).append(' ').append("z3=").append(data[M23]).append(' ').append("w3=").append(data[M33]).append('\n'); + return buf.toString(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Matrix4f matrix && Arrays.equals(data, matrix.data); + } + + public float[] getData() { return data; } + public float get(int index) { return data[index]; } + public float get(int column, int row) { return data[(column * 4) + row]; } + public int properties() { return properties; } + + public Matrix4f set(int column, int row, float value) { + data[(column * 4) + row] = value; + properties = PROPERTY_UNKNOWN; + return this; + } + + public Matrix4f set(int index, float value) { + data[index] = value; + properties = PROPERTY_UNKNOWN; + return this; + } + + public Matrix4f evaluateProps() { + int properties = PROPERTY_UNKNOWN; + if(data[M03] == 0F && data[M13] == 0F && data[M23] == 0F && data[M33] == 1F) { + properties |= PROPERTY_AFFINE; + if(data[M01] == 0F && data[M02] == 0F && data[M10] == 0F && data[M12] == 0F && data[M20] == 0F && data[M21] == 0F) { + properties |= PROPERTY_TRANSLATION; + if(data[M00] == 1F && data[M11] == 1F && data[M22] == 1F) { + if(data[M30] == 0F && data[M31] == 0F && data[M32] == 0F) { + properties |= PROPERTY_IDENTITY; + } + } + else { + properties |= PROPERTY_SCALE; + } + } + else { + properties |= PROPERTY_ROTATION; + } + } + this.properties = properties; + return this; + } + + public Matrix4f setIdentity() { + if(properties == PROPERTY_DEFAULT) return this; + Arrays.fill(data, 0F); + data[M00] = 1F; + data[M11] = 1F; + data[M22] = 1F; + data[M33] = 1F; + properties = PROPERTY_DEFAULT; + return this; + } + + public Matrix4f invert() { + float determinant = determinant(); + if(determinant != 0F) { + float determinant_inv = 1F / determinant; + float t00 = determinant3x3(data[M11], data[M12], data[M13], data[M21], data[M22], data[M23], data[M31], data[M32], data[M33]); + float t01 = -determinant3x3(data[M10], data[M12], data[M13], data[M20], data[M22], data[M23], data[M30], data[M32], data[M33]); + float t02 = determinant3x3(data[M10], data[M11], data[M13], data[M20], data[M21], data[M23], data[M30], data[M31], data[M33]); + float t03 = -determinant3x3(data[M10], data[M11], data[M12], data[M20], data[M21], data[M22], data[M30], data[M31], data[M32]); + float t10 = -determinant3x3(data[M01], data[M02], data[M03], data[M21], data[M22], data[M23], data[M31], data[M32], data[M33]); + float t11 = determinant3x3(data[M00], data[M02], data[M03], data[M20], data[M22], data[M23], data[M30], data[M32], data[M33]); + float t12 = -determinant3x3(data[M00], data[M01], data[M03], data[M20], data[M21], data[M23], data[M30], data[M31], data[M33]); + float t13 = determinant3x3(data[M00], data[M01], data[M02], data[M20], data[M21], data[M22], data[M30], data[M31], data[M32]); + float t20 = determinant3x3(data[M01], data[M02], data[M03], data[M11], data[M12], data[M13], data[M31], data[M32], data[M33]); + float t21 = -determinant3x3(data[M00], data[M02], data[M03], data[M10], data[M12], data[M13], data[M30], data[M32], data[M33]); + float t22 = determinant3x3(data[M00], data[M01], data[M03], data[M10], data[M11], data[M13], data[M30], data[M31], data[M33]); + float t23 = -determinant3x3(data[M00], data[M01], data[M02], data[M10], data[M11], data[M12], data[M30], data[M31], data[M32]); + float t30 = -determinant3x3(data[M01], data[M02], data[M03], data[M11], data[M12], data[M13], data[M21], data[M22], data[M23]); + float t31 = determinant3x3(data[M00], data[M02], data[M03], data[M10], data[M12], data[M13], data[M20], data[M22], data[M23]); + float t32 = -determinant3x3(data[M00], data[M01], data[M03], data[M10], data[M11], data[M13], data[M20], data[M21], data[M23]); + float t33 = determinant3x3(data[M00], data[M01], data[M02], data[M10], data[M11], data[M12], data[M20], data[M21], data[M22]); + + data[M00] = t00 * determinant_inv; + data[M11] = t11 * determinant_inv; + data[M22] = t22 * determinant_inv; + data[M33] = t33 * determinant_inv; + data[M01] = t10 * determinant_inv; + data[M10] = t01 * determinant_inv; + data[M20] = t02 * determinant_inv; + data[M02] = t20 * determinant_inv; + data[M12] = t21 * determinant_inv; + data[M21] = t12 * determinant_inv; + data[M03] = t30 * determinant_inv; + data[M30] = t03 * determinant_inv; + data[M13] = t31 * determinant_inv; + data[M31] = t13 * determinant_inv; + data[M32] = t23 * determinant_inv; + data[M23] = t32 * determinant_inv; + evaluateProps(); + } + return this; + } + + public Matrix4f flip() { + data[M00] = -data[M00]; + data[M01] = -data[M01]; + data[M02] = -data[M02]; + data[M03] = -data[M03]; + data[M10] = -data[M10]; + data[M11] = -data[M11]; + data[M12] = -data[M12]; + data[M13] = -data[M13]; + data[M20] = -data[M20]; + data[M21] = -data[M21]; + data[M22] = -data[M22]; + data[M23] = -data[M23]; + data[M30] = -data[M30]; + data[M31] = -data[M31]; + data[M32] = -data[M32]; + data[M33] = -data[M33]; + return evaluateProps(); + } + + public Matrix4f negate() { + Arrays.fill(data, 0F); + return evaluateProps(); + } + + public Matrix4f add(Matrix4f other) { + data[M00] += other.data[M00]; + data[M01] += other.data[M01]; + data[M02] += other.data[M02]; + data[M03] += other.data[M03]; + data[M10] += other.data[M10]; + data[M11] += other.data[M11]; + data[M12] += other.data[M12]; + data[M13] += other.data[M13]; + data[M20] += other.data[M20]; + data[M21] += other.data[M21]; + data[M22] += other.data[M22]; + data[M23] += other.data[M23]; + data[M30] += other.data[M30]; + data[M31] += other.data[M31]; + data[M32] += other.data[M32]; + data[M33] += other.data[M33]; + return evaluateProps(); + } + + public Matrix4f sub(Matrix4f other) { + data[M00] -= other.data[M00]; + data[M01] -= other.data[M01]; + data[M02] -= other.data[M02]; + data[M03] -= other.data[M03]; + data[M10] -= other.data[M10]; + data[M11] -= other.data[M11]; + data[M12] -= other.data[M12]; + data[M13] -= other.data[M13]; + data[M20] -= other.data[M20]; + data[M21] -= other.data[M21]; + data[M22] -= other.data[M22]; + data[M23] -= other.data[M23]; + data[M30] -= other.data[M30]; + data[M31] -= other.data[M31]; + data[M32] -= other.data[M32]; + data[M33] -= other.data[M33]; + return evaluateProps(); + } + + public Matrix4f multiply(Matrix4f other) { + float data0 = data[M00] * other.data[M00] + data[M10] * other.data[M01] + data[M20] * other.data[M02] + data[M30] * other.data[M03]; + float data1 = data[M01] * other.data[M00] + data[M11] * other.data[M01] + data[M21] * other.data[M02] + data[M31] * other.data[M03]; + float data2 = data[M02] * other.data[M00] + data[M12] * other.data[M01] + data[M22] * other.data[M02] + data[M32] * other.data[M03]; + float data3 = data[M03] * other.data[M00] + data[M13] * other.data[M01] + data[M23] * other.data[M02] + data[M33] * other.data[M03]; + float data4 = data[M00] * other.data[M10] + data[M10] * other.data[M11] + data[M20] * other.data[M12] + data[M30] * other.data[M13]; + float data5 = data[M01] * other.data[M10] + data[M11] * other.data[M11] + data[M21] * other.data[M12] + data[M31] * other.data[M13]; + float data6 = data[M02] * other.data[M10] + data[M12] * other.data[M11] + data[M22] * other.data[M12] + data[M32] * other.data[M13]; + float data7 = data[M03] * other.data[M10] + data[M13] * other.data[M11] + data[M23] * other.data[M12] + data[M33] * other.data[M13]; + float data8 = data[M00] * other.data[M20] + data[M10] * other.data[M21] + data[M20] * other.data[M22] + data[M30] * other.data[M23]; + float data9 = data[M01] * other.data[M20] + data[M11] * other.data[M21] + data[M21] * other.data[M22] + data[M31] * other.data[M23]; + float data10 = data[M02] * other.data[M20] + data[M12] * other.data[M21] + data[M22] * other.data[M22] + data[M32] * other.data[M23]; + float data11 = data[M03] * other.data[M20] + data[M13] * other.data[M21] + data[M23] * other.data[M22] + data[M33] * other.data[M23]; + float data12 = data[M00] * other.data[M30] + data[M10] * other.data[M31] + data[M20] * other.data[M32] + data[M30] * other.data[M33]; + float data13 = data[M01] * other.data[M30] + data[M11] * other.data[M31] + data[M21] * other.data[M32] + data[M31] * other.data[M33]; + float data14 = data[M02] * other.data[M30] + data[M12] * other.data[M31] + data[M22] * other.data[M32] + data[M32] * other.data[M33]; + float data15 = data[M03] * other.data[M30] + data[M13] * other.data[M31] + data[M23] * other.data[M32] + data[M33] * other.data[M33]; + data[M00] = data0; + data[M01] = data1; + data[M02] = data2; + data[M03] = data3; + data[M10] = data4; + data[M11] = data5; + data[M12] = data6; + data[M13] = data7; + data[M20] = data8; + data[M21] = data9; + data[M22] = data10; + data[M23] = data11; + data[M30] = data12; + data[M31] = data13; + data[M32] = data14; + data[M33] = data15; + return evaluateProps(); + } + + public Matrix4f transpose() { + float data0 = data[M00]; + float data1 = data[M10]; + float data2 = data[M20]; + float data3 = data[M30]; + float data4 = data[M01]; + float data5 = data[M11]; + float data6 = data[M21]; + float data7 = data[M31]; + float data8 = data[M02]; + float data9 = data[M12]; + float data10 = data[M22]; + float data11 = data[M32]; + float data12 = data[M03]; + float data13 = data[M13]; + float data14 = data[M23]; + float data15 = data[M33]; + + data[M00] = data0; + data[M01] = data1; + data[M02] = data2; + data[M03] = data3; + data[M10] = data4; + data[M11] = data5; + data[M12] = data6; + data[M13] = data7; + data[M20] = data8; + data[M21] = data9; + data[M22] = data10; + data[M23] = data11; + data[M30] = data12; + data[M31] = data13; + data[M32] = data14; + data[M33] = data15; + return evaluateProps(); + } + + public Matrix4f transpose3x3() { + float nm00 = data[M00]; + float nm01 = data[M10]; + float nm02 = data[M20]; + float nm10 = data[M01]; + float nm11 = data[M11]; + float nm12 = data[M21]; + float nm20 = data[M02]; + float nm21 = data[M12]; + float nm22 = data[M22]; + data[M00] = nm00; + data[M01] = nm01; + data[M02] = nm02; + data[M10] = nm10; + data[M11] = nm11; + data[M12] = nm12; + data[M20] = nm20; + data[M21] = nm21; + data[M22] = nm22; + return evaluateProps(); + } + + public Matrix4f decompose(Vec3f position, Quaternion rotation, Vec3f scale) { + position.set(get(3, 0), get(3, 1), get(3, 2)); + rotation.set(this); + scale.set(get(0, 0), get(1, 1), get(2, 2)); + return this; + } + + public Matrix4f setTranslation(float x, float y, float z) { + data[M30] = x; + data[M31] = y; + data[M32] = z; + if(x != 0F || y != 0F || z != 0F) properties |= PROPERTY_TRANSLATION; + else properties &= PROPERTY_TRANSLATION; + return this; + } + + public Matrix4f translateZ(float z) { + if(z == 0F) return this; + if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { + data[M32] += z; + return evaluateProps(); + } + data[M30] += data[M20] * z; + data[M31] += data[M21] * z; + data[M32] += data[M22] * z; + data[M33] += data[M23] * z; + return evaluateProps(); + } + + public Matrix4f translate(float x, float y) { + if(x == 0F && y == 0F) return this; + if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { + data[M30] += x; + data[M31] += y; + return evaluateProps(); + } + data[M30] += data[M00] * x + data[M10] * y; + data[M31] += data[M01] * x + data[M11] * y; + data[M32] += data[M02] * x + data[M12] * y; + data[M33] += data[M03] * x + data[M13] * y; + return evaluateProps(); + } + + public Matrix4f translate(float x, float y, float z) { + if(x == 0F && y == 0F && z == 0F) return this; + if((properties & (PROPERTY_ROTATION | PROPERTY_SCALE)) == 0) { + data[M30] += x; + data[M31] += y; + data[M32] += z; + properties |= PROPERTY_TRANSLATION; + return evaluateProps(); + } + data[M30] += data[M00] * x + data[M10] * y + data[M20] * z; + data[M31] += data[M01] * x + data[M11] * y + data[M21] * z; + data[M32] += data[M02] * x + data[M12] * y + data[M22] * z; + data[M33] += data[M03] * x + data[M13] * y + data[M23] * z; + return evaluateProps(); + } + + public Matrix4f rotateX(float angle) { return rotate((float)Math.toRadians(angle), 1F, 0F, 0F); } + public Matrix4f rotateY(float angle) { return rotate((float)Math.toRadians(angle), 0F, 1F, 0F); } + public Matrix4f rotateZ(float angle) { return rotate((float)Math.toRadians(angle), 0F, 0F, 1F); } + public Matrix4f rotateRadX(float angle) { return rotate(angle, 1F, 0F, 0F); } + public Matrix4f rotateRadY(float angle) { return rotate(angle, 0F, 1F, 0F); } + public Matrix4f rotateRadZ(float angle) { return rotate(angle, 0F, 0F, 1F); } + + public Matrix4f rotate(float angle, float x, float y, float z) { + float c = MathUtils.cos(angle); + float s = MathUtils.sin(angle); + float oneminusc = 1.0F - c; + float xy = x * y; + float yz = y * z; + float xz = x * z; + float xs = x * s; + float ys = y * s; + float zs = z * s; + + float f00 = x * x * oneminusc + c; + float f01 = xy * oneminusc + zs; + float f02 = xz * oneminusc - ys; + + float f10 = xy * oneminusc - zs; + float f11 = y * y * oneminusc + c; + float f12 = yz * oneminusc + xs; + + float f20 = xz * oneminusc + ys; + float f21 = yz * oneminusc - xs; + float f22 = z * z * oneminusc + c; + + float t00 = data[M00] * f00 + data[M10] * f01 + data[M20] * f02; + float t01 = data[M01] * f00 + data[M11] * f01 + data[M21] * f02; + float t02 = data[M02] * f00 + data[M12] * f01 + data[M22] * f02; + float t03 = data[M03] * f00 + data[M13] * f01 + data[M23] * f02; + float t10 = data[M00] * f10 + data[M10] * f11 + data[M20] * f12; + float t11 = data[M01] * f10 + data[M11] * f11 + data[M21] * f12; + float t12 = data[M02] * f10 + data[M12] * f11 + data[M22] * f12; + float t13 = data[M03] * f10 + data[M13] * f11 + data[M23] * f12; + data[M20] = data[M00] * f20 + data[M10] * f21 + data[M20] * f22; + data[M21] = data[M01] * f20 + data[M11] * f21 + data[M21] * f22; + data[M22] = data[M02] * f20 + data[M12] * f21 + data[M22] * f22; + data[M23] = data[M03] * f20 + data[M13] * f21 + data[M23] * f22; + data[M00] = t00; + data[M01] = t01; + data[M02] = t02; + data[M03] = t03; + data[M10] = t10; + data[M11] = t11; + data[M12] = t12; + data[M13] = t13; + return evaluateProps(); + } + + public Matrix4f rotate(Quaternion rotation) { + float w2 = rotation.getW() * rotation.getW(); + float x2 = rotation.getX() * rotation.getX(); + float y2 = rotation.getY() * rotation.getY(); + float z2 = rotation.getZ() * rotation.getZ(); + float zw = rotation.getZ() * rotation.getW(); + float dzw = zw + zw; + float xy = rotation.getX() * rotation.getY(); + float dxy = xy + xy; + float xz = rotation.getX() * rotation.getZ(); + float dxz = xz + xz; + float yw = rotation.getY() * rotation.getW(); + float dyw = yw + yw; + float yz = rotation.getY() * rotation.getZ(); + float dyz = yz + yz; + float xw = rotation.getX() * rotation.getW(); + float dxw = xw + xw; + float rm00 = w2 + x2 - z2 - y2; + float rm01 = dxy + dzw; + float rm02 = dxz - dyw; + float rm10 = -dzw + dxy; + float rm11 = y2 - z2 + w2 - x2; + float rm12 = dyz + dxw; + float rm20 = dyw + dxz; + float rm21 = dyz - dxw; + float rm22 = z2 - y2 - x2 + w2; + float nm00 = data[M00] * rm00 + data[M10] * rm01 + data[M20] * rm02; + float nm01 = data[M01] * rm00 + data[M11] * rm01 + data[M21] * rm02; + float nm02 = data[M02] * rm00 + data[M12] * rm01 + data[M22] * rm02; + float nm03 = data[M03] * rm00 + data[M13] * rm01 + data[M23] * rm02; + float nm10 = data[M00] * rm10 + data[M10] * rm11 + data[M20] * rm12; + float nm11 = data[M01] * rm10 + data[M11] * rm11 + data[M21] * rm12; + float nm12 = data[M02] * rm10 + data[M12] * rm11 + data[M22] * rm12; + float nm13 = data[M03] * rm10 + data[M13] * rm11 + data[M23] * rm12; + data[M20] = data[M00] * rm20 + data[M10] * rm21 + data[M20] * rm22; + data[M21] = data[M01] * rm20 + data[M11] * rm21 + data[M21] * rm22; + data[M22] = data[M02] * rm20 + data[M12] * rm21 + data[M22] * rm22; + data[M23] = data[M03] * rm20 + data[M13] * rm21 + data[M23] * rm22; + data[M00] = nm00; + data[M01] = nm01; + data[M02] = nm02; + data[M03] = nm03; + data[M10] = nm10; + data[M11] = nm11; + data[M12] = nm12; + data[M13] = nm13; + return evaluateProps(); + } + + public Matrix4f setRotation(Matrix4f source) { + data[M00] = source.data[M00]; + data[M01] = source.data[M01]; + data[M02] = source.data[M02]; + data[M10] = source.data[M10]; + data[M11] = source.data[M11]; + data[M12] = source.data[M12]; + data[M20] = source.data[M20]; + data[M21] = source.data[M21]; + data[M22] = source.data[M22]; + return evaluateProps(); + } + + public Matrix4f setBillboard(Matrix4f source) { + data[M00] = source.data[M00]; + data[M01] = source.data[M10]; + data[M02] = source.data[M20]; + data[M10] = source.data[M01]; + data[M11] = source.data[M11]; + data[M12] = source.data[M21]; + data[M20] = source.data[M02]; + data[M21] = source.data[M12]; + data[M22] = source.data[M22]; + return evaluateProps(); + } + + public Matrix4f scale(float value) { return scale(value, value, value); } + + public Matrix4f scale(float x, float y, float z) { + if(x != 1F) { + data[M00] *= x; + data[M01] *= x; + data[M02] *= x; + data[M03] *= x; + } + if(y != 1F) { + data[M10] *= y; + data[M11] *= y; + data[M12] *= y; + data[M13] *= y; + } + if(z != 1F) { + data[M20] *= z; + data[M21] *= z; + data[M22] *= z; + data[M23] *= z; + } + return evaluateProps(); + } + + public Matrix4f unscale(float scale) { return unscale(scale, scale, scale); } + + public Matrix4f unscale(float x, float y, float z) { + if(x != 1F) { + data[M00] /= x; + data[M01] /= x; + data[M02] /= x; + data[M03] /= x; + } + if(y != 1F) { + data[M10] /= y; + data[M11] /= y; + data[M12] /= y; + data[M13] /= y; + } + if(z != 1F) { + data[M20] /= z; + data[M21] /= z; + data[M22] /= z; + data[M23] /= z; + } + return evaluateProps(); + } + + public Matrix4f setPerspective(float fovy, float aspect, float zNear, float zFar) { + float h = (float)Math.tan(fovy * 0.5F); + set(0, 0, 1F / (h * aspect)).set(1, 1, 1F / h); + boolean farInf = zFar > 0 && Float.isInfinite(zFar); + boolean nearInf = zNear > 0 && Float.isInfinite(zNear); + if(farInf) { + set(2, 2, 0.999999F).set(3, 2, 1.999999F * zNear); + } + else if(nearInf) { + float e = 1E-6F; + set(2, 2, 1F - e).set(3, 2, (2F - e) * zFar); + } + else { + set(2, 2, (zFar + zNear) / (zNear - zFar)).set(3, 2, (zFar + zFar) * zNear / (zNear - zFar)); + } + return set(2, 3, -1F).evaluateProps(); + } + + public Matrix4f getTranslation(Vec3f vec) { + vec.set(data[M30], data[M31], data[M32]); + return this; + } + + public Matrix4f getScale(Vec3f vec) { + vec.x((float)Math.sqrt(data[M00] * data[M00] + data[M01] * data[M01] + data[M02] * data[M02])); + vec.y((float)Math.sqrt(data[M10] * data[M10] + data[M11] * data[M11] + data[M12] * data[M12])); + vec.z((float)Math.sqrt(data[M20] * data[M20] + data[M21] * data[M21] + data[M22] * data[M22])); + return this; + } + + public void transform(Vec4f input, FloatBuffer buffer) { + transform(input.x(), input.y(), input.z(), input.w(), buffer::put); + } + + public void transform(Vec3f input, boolean position, FloatBuffer buffer) { + transform(input.x(), input.y(), input.z(), position, buffer::put); + } + + public void transform(float x, float y, float z, float w, ITransformOutput output) { + if((properties & PROPERTY_IDENTITY) != 0) { + output.accept(x, y, z, w); + return; + } + if((properties & PROPERTY_ROTATION) != 0) { + output.accept(fma(M00, M10, M20, M30, x, y, z, w), fma(M01, M11, M21, M31, x, y, z, w), fma(M02, M12, M22, M32, x, y, z, w), fma(M03, M13, M23, M33, x, y, z, w)); + return; + } + if((properties & PROPERTY_SCALE) != 0) { + output.accept(Math.fma(data[M00], x, data[M30]), Math.fma(data[M01], y, data[M31]), Math.fma(data[M02], z, data[M32]), Math.fma(data[M03], w, data[M33])); + return; + } + output.accept(x + data[M30], y + data[M31], z + data[M32], w + data[M33]); + } + + public void transform(float x, float y, float z, boolean pos, ITransformOutput output) { + if((properties & PROPERTY_IDENTITY) != 0) { + output.accept(x, y, z); + return; + } + if((properties & PROPERTY_ROTATION) != 0) { + float w = pos ? 1F : 0F; + output.accept(fma(M00, M10, M20, M30, x, y, z, w), fma(M01, M11, M21, M31, x, y, z, w), fma(M02, M12, M22, M32, x, y, z, w)); + return; + } + if((properties & PROPERTY_SCALE) != 0) { + if(pos) output.accept(Math.fma(data[M00], x, data[M30]), Math.fma(data[M01], y, data[M31]), Math.fma(data[M02], z, data[M32])); + else output.accept(data[M00] * x, data[M01] * y, data[M02] * z); + return; + } + if(pos) { + output.accept(x + data[M30], y + data[M31], z + data[M32]); + return; + } + output.accept(x, y, z); + } + + public float fma(int xPos, int yPos, int zPos, int wPos, float x, float y, float z, float w) { + return Math.fma(data[xPos], x, Math.fma(data[yPos], y, Math.fma(data[zPos], z, data[wPos] * w))); + } + + public float determinant() { + float f = data[M00] * ((data[M11] * data[M22] * data[M33] + data[M12] * data[M23] * data[M31] + data[M13] * data[M21] * data[M32]) - data[M13] * data[M22] * data[M31] - data[M11] * data[M23] * data[M32] - data[M12] * data[M21] * data[M33]); + f -= data[M01] * ((data[M10] * data[M22] * data[M33] + data[M12] * data[M23] * data[M30] + data[M13] * data[M20] * data[M32]) - data[M13] * data[M22] * data[M30] - data[M10] * data[M23] * data[M32] - data[M12] * data[M20] * data[M33]); + f += data[M02] * ((data[M10] * data[M21] * data[M33] + data[M11] * data[M23] * data[M30] + data[M13] * data[M20] * data[M31]) - data[M13] * data[M21] * data[M30] - data[M10] * data[M23] * data[M31] - data[M11] * data[M20] * data[M33]); + f -= data[M03] * ((data[M10] * data[M21] * data[M32] + data[M11] * data[M22] * data[M30] + data[M12] * data[M20] * data[M31]) - data[M12] * data[M21] * data[M30] - data[M10] * data[M22] * data[M31] - data[M11] * data[M20] * data[M32]); + return f; + } + + public float determinant3x3(float t00, float t01, float t02, float t10, float t11, float t12, float t20, float t21, float t22) { + return t00 * (t11 * t22 - t12 * t21) + t01 * (t12 * t20 - t10 * t22) + t02 * (t10 * t21 - t11 * t20); + } + + public Vec3f project(float x, float y, float z, int[] viewport, Vec3f winCoordsDest) { + float invW = 1F / Math.fma(data[M03], x, Math.fma(data[M13], y, Math.fma(data[M23], z, data[M33]))); + float nx = Math.fma(data[M00], x, Math.fma(data[M10], y, Math.fma(data[M20], z, data[M30]))) * invW; + float ny = Math.fma(data[M01], x, Math.fma(data[M11], y, Math.fma(data[M21], z, data[M31]))) * invW; + float nz = Math.fma(data[M02], x, Math.fma(data[M12], y, Math.fma(data[M22], z, data[M32]))) * invW; + return winCoordsDest.set(Math.fma(Math.fma(nx, 0.5F, 0.5F), viewport[2], viewport[0]), Math.fma(Math.fma(ny, 0.5F, 0.5F), viewport[3], viewport[1]), Math.fma(0.5F, nz, 0.5F)); + } + + public Vec3f unproject(float winX, float winY, float winZ, int[] viewport, Vec3f dest) { + float a = data[M00] * data[M11] - data[M01] * data[M10]; + float b = data[M00] * data[M12] - data[M02] * data[M10]; + float c = data[M00] * data[M13] - data[M03] * data[M10]; + float d = data[M01] * data[M12] - data[M02] * data[M11]; + float e = data[M01] * data[M13] - data[M03] * data[M11]; + float f = data[M02] * data[M13] - data[M03] * data[M12]; + float g = data[M20] * data[M31] - data[M21] * data[M30]; + float h = data[M20] * data[M32] - data[M22] * data[M30]; + float i = data[M20] * data[M33] - data[M23] * data[M30]; + float j = data[M21] * data[M32] - data[M22] * data[M31]; + float k = data[M21] * data[M33] - data[M23] * data[M31]; + float l = data[M22] * data[M33] - data[M23] * data[M32]; + float det = a * l - b * k + c * j + d * i - e * h + f * g; + det = 1F / det; + float im00 = (data[M11] * l - data[M12] * k + data[M13] * j) * det; + float im01 = (-data[M01] * l + data[M02] * k - data[M03] * j) * det; + float im02 = (data[M31] * f - data[M32] * e + data[M33] * d) * det; + float im03 = (-data[M21] * f + data[M22] * e - data[M23] * d) * det; + float im10 = (-data[M10] * l + data[M12] * i - data[M13] * h) * det; + float im11 = (data[M00] * l - data[M02] * i + data[M03] * h) * det; + float im12 = (-data[M30] * f + data[M32] * c - data[M33] * b) * det; + float im13 = (data[M20] * f - data[M22] * c + data[M23] * b) * det; + float im20 = (data[M10] * k - data[M11] * i + data[M13] * g) * det; + float im21 = (-data[M00] * k + data[M01] * i - data[M03] * g) * det; + float im22 = (data[M30] * e - data[M31] * c + data[M33] * a) * det; + float im23 = (-data[M20] * e + data[M21] * c - data[M23] * a) * det; + float im30 = (-data[M10] * j + data[M11] * h - data[M12] * g) * det; + float im31 = (data[M00] * j - data[M01] * h + data[M02] * g) * det; + float im32 = (-data[M30] * d + data[M31] * b - data[M32] * a) * det; + float im33 = (data[M20] * d - data[M21] * b + data[M22] * a) * det; + float ndcX = (winX - viewport[0]) / viewport[2] * 2F - 1F; + float ndcY = (winY - viewport[1]) / viewport[3] * 2F - 1F; + float ndcZ = winZ + winZ - 1F; + float invW = 1F / (im03 * ndcX + im13 * ndcY + im23 * ndcZ + im33); + return dest.set((im00 * ndcX + im10 * ndcY + im20 * ndcZ + im30) * invW, (im01 * ndcX + im11 * ndcY + im21 * ndcZ + im31) * invW, (im02 * ndcX + im12 * ndcY + im22 * ndcZ + im32) * invW); + } + + public Matrix4f ortho(float x, float y, float width, float height, float zNear, float zFar) { + return ortho(x, x + width, y + height, y, zNear, zFar, false); + } + + public Matrix4f ortho(float left, float right, float bottom, float top, float zNear, float zFar, boolean zZeroToOne) { + float rm00 = 2F / (right - left); + float rm11 = 2F / (top - bottom); + float rm22 = (zZeroToOne ? 1F : 2F) / (zFar - zNear); + float rm30 = (left + right) / (left - right); + float rm31 = (top + bottom) / (bottom - top); + float rm32 = (zZeroToOne ? zNear : (zFar + zNear)) / (zNear - zFar); + + data[M30] = data[M00] * rm30 + data[M10] * rm31 + data[M20] * rm32 + data[M30]; + data[M31] = data[M01] * rm30 + data[M11] * rm31 + data[M21] * rm32 + data[M31]; + data[M32] = data[M02] * rm30 + data[M12] * rm31 + data[M22] * rm32 + data[M32]; + data[M33] = data[M03] * rm30 + data[M13] * rm31 + data[M23] * rm32 + data[M33]; + data[M00] = data[M00] * rm00; + data[M01] = data[M01] * rm00; + data[M02] = data[M02] * rm00; + data[M03] = data[M03] * rm00; + data[M10] = data[M10] * rm11; + data[M11] = data[M11] * rm11; + data[M12] = data[M12] * rm11; + data[M13] = data[M13] * rm11; + data[M20] = data[M20] * rm22; + data[M21] = data[M21] * rm22; + data[M22] = data[M22] * rm22; + data[M23] = data[M23] * rm22; + return evaluateProps(); + } + + public Vec4f storeFrustrumPlane(int plane, Vec4f toStore) { + return switch(plane) { + case 0 -> toStore.set(data[M03] + data[M00], data[M13] + data[M10], data[M23] + data[M20], data[M33] + data[M30]).normalize3D(); + case 1 -> toStore.set(data[M03] - data[M00], data[M13] - data[M10], data[M23] - data[M20], data[M33] - data[M30]).normalize3D(); + case 2 -> toStore.set(data[M03] + data[M01], data[M13] + data[M11], data[M23] + data[M21], data[M33] + data[M31]).normalize3D(); + case 3 -> toStore.set(data[M03] - data[M01], data[M13] - data[M11], data[M23] - data[M21], data[M33] - data[M31]).normalize3D(); + case 4 -> toStore.set(data[M03] + data[M02], data[M13] + data[M12], data[M23] + data[M22], data[M33] + data[M32]).normalize3D(); + case 5 -> toStore.set(data[M03] - data[M02], data[M13] - data[M12], data[M23] - data[M22], data[M33] - data[M32]).normalize3D(); + default -> toStore; + }; + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/math/vector/matrix/Matrix4fStack.java b/src/math/java/speiger/src/coreengine/math/vector/matrix/Matrix4fStack.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/matrix/Matrix4fStack.java rename to src/math/java/speiger/src/coreengine/math/vector/matrix/Matrix4fStack.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/quaternion/Quaternion.java b/src/math/java/speiger/src/coreengine/math/vector/quaternion/Quaternion.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/quaternion/Quaternion.java rename to src/math/java/speiger/src/coreengine/math/vector/quaternion/Quaternion.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/quaternion/QuaternionImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/quaternion/QuaternionImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/quaternion/QuaternionImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/quaternion/QuaternionImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/quaternion/QuaternionMutable.java b/src/math/java/speiger/src/coreengine/math/vector/quaternion/QuaternionMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/quaternion/QuaternionMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/quaternion/QuaternionMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2s.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2s.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2s.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2s.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2sImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2sImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2sImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2sImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2sMutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2sMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec2sMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec2sMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3s.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3s.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3s.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3s.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3sImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3sImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3sImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3sImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3sMutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3sMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec3sMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec3sMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4s.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4s.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4s.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4s.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4sImmutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4sImmutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4sImmutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4sImmutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4sMutable.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4sMutable.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vec4sMutable.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vec4sMutable.java diff --git a/src/main/java/speiger/src/coreengine/math/vector/shorts/Vecs.java b/src/math/java/speiger/src/coreengine/math/vector/shorts/Vecs.java similarity index 100% rename from src/main/java/speiger/src/coreengine/math/vector/shorts/Vecs.java rename to src/math/java/speiger/src/coreengine/math/vector/shorts/Vecs.java