Progress on more rewrites
This commit is contained in:
1 parent
340d8ff463
commit
396d4f2232
144 files changed
+5657
-4997
No files matched your search
+12
@@ -24,6 +24,18 @@
|
||||
<attribute name="gradle_used_by_scope" value="graphics"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin/math" path="src/math/java">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="math"/>
|
||||
<attribute name="gradle_used_by_scope" value="main,graphics,math"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin/assets" path="src/assets/java">
|
||||
<attributes>
|
||||
<attribute name="gradle_scope" value="assets"/>
|
||||
<attribute name="gradle_used_by_scope" value="assets"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
|
||||
+21
-1
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface IAsset {
|
||||
public IAssetPackage owner();
|
||||
public ID location();
|
||||
|
||||
public String hash();
|
||||
public InputStream stream() throws IOException;
|
||||
|
||||
public <T> T parse(IAssetParser<T> parser) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
public interface IAssetPackage {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface IAssetParser<T> {
|
||||
public T parse(Path path) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
public interface IAssetProvider {
|
||||
public IAsset get(ID id);
|
||||
public String hash(ID id);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record ID(String domain, String path) implements Comparable<ID> {
|
||||
|
||||
public ID {
|
||||
Objects.requireNonNull(domain);
|
||||
Objects.requireNonNull(path);
|
||||
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
|
||||
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||
}
|
||||
|
||||
public ID prefix(String prefix) { return of(domain, prefix+"/"+path); }
|
||||
public ID suffix(String suffix) { return of(domain, path+"/"+suffix); }
|
||||
public ID alternate(String alterversion) { return of(domain, path+"."+alterversion); }
|
||||
|
||||
public String fileLocation() { return "assets/"+domain+"/"+path; }
|
||||
public boolean isRoot() { return !path.contains("/"); }
|
||||
public boolean isRootFolder(String folder) { return path.indexOf('/', folder.length()+1) < 0; }
|
||||
public boolean endsWith(String suffix) { return path.endsWith(suffix); }
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return domain+":"+path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ID o) {
|
||||
int result = domain.compareToIgnoreCase(o.domain);
|
||||
return result != 0 ? result : path.compareToIgnoreCase(path);
|
||||
}
|
||||
|
||||
public boolean matches(ID id) {
|
||||
return id.domain.equals(domain) && id.path.equals(path);
|
||||
}
|
||||
|
||||
public static ID of(String domain, String path) {
|
||||
return new ID((domain == null || domain.isBlank() ? "base" : domain), path);
|
||||
}
|
||||
|
||||
public static ID of(String location) {
|
||||
Objects.requireNonNull(location);
|
||||
int index = location.indexOf(":");
|
||||
String domain = location.substring(0, index);
|
||||
String path = location.substring(index + 1);
|
||||
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
|
||||
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||
return new ID(domain, path);
|
||||
}
|
||||
|
||||
public static final ID tryOf(String location) {
|
||||
try { return of(location); }
|
||||
catch(Exception e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isValidDomain(String s) {
|
||||
for(int i = 0,m=s.length();i<m;i++) {
|
||||
if(!isValidDomainChar(s.charAt(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidPath(String s) {
|
||||
for(int i = 0,m=s.length();i<m;i++) {
|
||||
if(!isValidPathChar(s.charAt(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidPathChar(char c) {
|
||||
return c == '/' || isValidDomainChar(c);
|
||||
}
|
||||
|
||||
private static boolean isValidDomainChar(char c) {
|
||||
return c == '_' || c == '-' || c == '.' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
|
||||
import speiger.src.collections.objects.collections.ObjectIterable;
|
||||
import speiger.src.collections.objects.collections.ObjectIterator;
|
||||
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
|
||||
public record MultiAsset(ObjectList<IAsset> assets) implements ObjectIterable<IAsset> {
|
||||
|
||||
public MultiAsset(ObjectList<IAsset> assets) {
|
||||
this.assets = Objects.requireNonNull(assets).unmodifiable();
|
||||
}
|
||||
|
||||
public MultiAsset(IAsset... assets) {
|
||||
this(ObjectArrayList.wrap(assets));
|
||||
}
|
||||
|
||||
public int size() { return assets.size(); }
|
||||
public IAsset get(int index) { return assets.get(index); }
|
||||
@Override
|
||||
public ObjectIterator<IAsset> iterator() { return assets.iterator(); }
|
||||
|
||||
public <T> ObjectIterable<T> map(IAssetParser<T> mapper, Supplier<T> defaultValue) {
|
||||
return assets.map(E -> {
|
||||
try { return E.parse(mapper); }
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
return defaultValue.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super IAsset> action) {
|
||||
assets.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
|
||||
assets.forEach(input, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
|
||||
assets.forEachIndexed(action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package speiger.src.coreengine.graphics.api.buffer.states;
|
||||
|
||||
public enum IndeciesType {
|
||||
BYTE,
|
||||
SHORT,
|
||||
INT;
|
||||
}
|
||||
+20
-3
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package speiger.src.coreengine.graphics.api.shader;
|
||||
|
||||
public interface CompiledPipeline {
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package speiger.src.coreengine.graphics.api.target;
|
||||
|
||||
public sealed interface RenderTarget permits ScreenTarget, TextureTarget {
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package speiger.src.coreengine.graphics.api.utils;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.utils.Stack;
|
||||
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||
|
||||
public class ScissorsManager {
|
||||
Stack<Vec4i> stack = new ObjectArrayList<>();
|
||||
int limit;
|
||||
|
||||
public ScissorsManager(int limit) {
|
||||
if(limit <= 0) throw new IllegalStateException("Limit is negative");
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void push(int x, int y, int width, int height) {
|
||||
if(stack.size() >= limit) {
|
||||
//TODO implement logging
|
||||
return;
|
||||
}
|
||||
if(stack.isEmpty()) {
|
||||
stack.push(Vec4i.of(x, y, x + width, y + height));
|
||||
GL11.glEnable(GL11.GL_SCISSOR_TEST);
|
||||
GL11.glScissor(x, y, width, height);
|
||||
return;
|
||||
}
|
||||
Vec4i top = stack.top();
|
||||
stack.push(Vec4i.of(Math.max(x, top.x()), Math.max(y, top.y()), Math.min(x + width, top.z()), Math.min(y + height, top.w())));
|
||||
}
|
||||
|
||||
public boolean contains(int x, int y, int width, int height) {
|
||||
return stack.isEmpty() || contains(stack.top(), x, y, width, height);
|
||||
}
|
||||
|
||||
protected boolean contains(Vec4i top, int x, int y, int width, int height) {
|
||||
return x >= top.x() && y >= top.y() && x + width < top.z() && y + height < top.w();
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
if(stack.isEmpty()) {
|
||||
//TODO implement logging
|
||||
return;
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
stack.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package speiger.src.coreengine.graphics.opengl.core;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue;
|
||||
import speiger.src.coreengine.graphics.api.shader.RenderPass;
|
||||
import speiger.src.coreengine.graphics.api.target.RenderTarget;
|
||||
import speiger.src.coreengine.graphics.api.target.ScreenTarget;
|
||||
import speiger.src.coreengine.graphics.api.target.TextureTarget;
|
||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||
import speiger.src.coreengine.graphics.api.utils.PushableResource;
|
||||
import speiger.src.coreengine.graphics.opengl.shader.GLRenderPass;
|
||||
import speiger.src.coreengine.graphics.opengl.texture.FrameBufferCache;
|
||||
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
|
||||
import speiger.src.coreengine.math.vector.floats.Vec4f;
|
||||
import speiger.src.coreengine.rendering.input.window.Window;
|
||||
|
||||
public class GLCommandQueue implements GraphicsCommandQueue {
|
||||
private static final int HAS_COLOR = 1;
|
||||
private static final int HAS_DEPTH = 2;
|
||||
private static final int HAS_BOTH = 3;
|
||||
GLGraphicsDevice device;
|
||||
FrameBufferCache fboCache = new FrameBufferCache();
|
||||
GLRenderPass activePass;
|
||||
RenderTarget renderTarget = ScreenTarget.INSTANCE;
|
||||
Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F);
|
||||
double clearDepth = 0D;
|
||||
|
||||
public GLCommandQueue(GLGraphicsDevice device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushableResource putClearColor(Vec4f color) {
|
||||
return new PushableObject<>(clearColor.copyAsImmutable(), setClearColor(color), () -> clearColor, this::setClearColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushableResource putClearDepth(double value) {
|
||||
return new PushableObject<>(clearDepth, setClearDepth(value), () -> clearDepth, this::setClearDepth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PushableResource putRenderTarget(RenderTarget target) {
|
||||
return new PushableObject<>(renderTarget, setRenderTarget(target), () -> renderTarget, this::setRenderTarget);
|
||||
}
|
||||
|
||||
private Vec4f setClearColor(Vec4f value) {
|
||||
if(clearColor.equals(value)) return value;
|
||||
clearColor.set(value);
|
||||
GL11.glClearColor(value.x(), value.y(), value.y(), value.w());
|
||||
return value;
|
||||
}
|
||||
|
||||
private double setClearDepth(double value) {
|
||||
if(Double.compare(clearDepth, value) == 0) return value;
|
||||
clearDepth = value;
|
||||
GL11.glClearDepth(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private RenderTarget setRenderTarget(RenderTarget target) {
|
||||
if(this.renderTarget.equals(target)) return target;
|
||||
this.renderTarget = target;
|
||||
switch(target) {
|
||||
case ScreenTarget _ -> {
|
||||
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, 0);
|
||||
Window window = device.getWindow();
|
||||
GL11.glViewport(0, 0, window.width(), window.height());
|
||||
break;
|
||||
}
|
||||
case TextureTarget(AssetLocation id, Texture color, Texture depth) -> {
|
||||
int fbo = fboCache.getOrCreateFBO(id);
|
||||
if(color != null) GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
|
||||
if(depth != null) GL45.glNamedFramebufferTexture(fbo, GL30.GL_DEPTH_ATTACHMENT, ((GLTexture)depth).id(), 0);
|
||||
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, fbo);
|
||||
if(color != null) GL11.glViewport(0, 0, color.width(), color.height());
|
||||
else if(depth != null) GL11.glViewport(0, 0, depth.width(), depth.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTexture(int clearParam) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTexture(int x, int y, int width, int height, int clearParam) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTexture(Texture texture, int clearParam) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToTexture(Texture target, int x, int y, int width, int height, long source) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromTexture(Texture source, int x, int y, int width, int height, long target) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderPass createRenderPass(RenderTarget target, DrawArea area) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int hasState = 0;
|
||||
int frameBuffer = switch(target) {
|
||||
case ScreenTarget _ -> {
|
||||
Window window = device.getWindow();
|
||||
width = window.width();
|
||||
height = window.height();
|
||||
hasState = HAS_BOTH;
|
||||
yield 0;
|
||||
}
|
||||
case TextureTarget(AssetLocation id, Texture color, Texture depth) -> {
|
||||
int fbo = fboCache.getOrCreateFBO(id);
|
||||
if(color != null) {
|
||||
hasState |= HAS_COLOR;
|
||||
GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
|
||||
}
|
||||
if(depth != null) {
|
||||
hasState |= HAS_DEPTH;
|
||||
GL45.glNamedFramebufferTexture(fbo, GL30.GL_DEPTH_ATTACHMENT, ((GLTexture)depth).id(), 0);
|
||||
}
|
||||
if(color != null) {
|
||||
width = color.width();
|
||||
height = color.height();
|
||||
}
|
||||
else if(depth != null) {
|
||||
width = depth.width();
|
||||
height = depth.height();
|
||||
}
|
||||
yield fbo;
|
||||
}
|
||||
};
|
||||
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, frameBuffer);
|
||||
GL11.glViewport(0, 0, width, height);
|
||||
boolean scissors = area != null && !area.fills(width, height);
|
||||
if(scissors) {
|
||||
GL11.glEnable(GL11.GL_SCISSOR_TEST);
|
||||
GL11.glScissor(area.x(), area.y(), area.width(), area.height());
|
||||
}
|
||||
return (activePass = new GLRenderPass(this, area, scissors, (hasState & HAS_COLOR) != 0, (hasState & HAS_DEPTH) != 0, frameBuffer));
|
||||
}
|
||||
|
||||
private record PushableObject<T>(T original, T applying, Supplier<T> current, Consumer<T> apply) implements PushableResource {
|
||||
@Override
|
||||
public void close() {
|
||||
if(current.get().equals(applying)) {
|
||||
apply.accept(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-5
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package speiger.src.coreengine.graphics.opengl.shader;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
|
||||
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
|
||||
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue.DrawArea;
|
||||
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
||||
import speiger.src.coreengine.graphics.api.shader.CompiledPipeline;
|
||||
import speiger.src.coreengine.graphics.api.shader.RenderPass;
|
||||
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||
import speiger.src.coreengine.graphics.opengl.core.GLCommandQueue;
|
||||
|
||||
public class GLRenderPass extends RenderPass {
|
||||
boolean scissors;
|
||||
GLCommandQueue queue;
|
||||
int fbo;
|
||||
VertexBuffer[] buffers = new VertexBuffer[4];
|
||||
Map<String, ObjectObjectPair<Texture, Sampler>> textures = Object2ObjectMap.builder().linkedMap();
|
||||
Map<String, VertexBuffer> uniforms = Object2ObjectMap.builder().linkedMap();
|
||||
VertexBuffer indecies;
|
||||
IndeciesType indeciesType;
|
||||
ShaderPipeline pipeline;
|
||||
CompiledPipeline compiled;
|
||||
|
||||
public GLRenderPass(GLCommandQueue queue, DrawArea area, boolean scissors, boolean hasColor, boolean hasDepth, int fbo) {
|
||||
super(area, hasColor, hasDepth);
|
||||
this.scissors = scissors;
|
||||
this.queue = queue;
|
||||
this.fbo = fbo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShader(ShaderPipeline pipeline) {
|
||||
this.pipeline = Objects.requireNonNull(pipeline);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(String name, Texture texture, Sampler sampler) {
|
||||
Objects.requireNonNull(name, "Sampler Name is needed");
|
||||
Objects.requireNonNull(texture, "Texture is required");
|
||||
Objects.requireNonNull(sampler, "Sampler is required");
|
||||
textures.put(name, ObjectObjectPair.of(texture, sampler));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTextures() {
|
||||
textures.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTexture(String name) {
|
||||
Objects.requireNonNull(name, "Sampler Name is needed");
|
||||
textures.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUniform(String name, VertexBuffer buffer) {
|
||||
Objects.requireNonNull(name, "Uniform name is needed");
|
||||
Objects.requireNonNull(buffer, "Vertex Buffer is required");
|
||||
uniforms.put(name, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIndecies(VertexBuffer buffer, IndeciesType type) {
|
||||
indecies = Objects.requireNonNull(buffer, "Buffer is required");
|
||||
indeciesType = Objects.requireNonNull(type, "Type is required");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearIndecies() {
|
||||
indecies = null;
|
||||
indeciesType = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVertexBuffer(int index, VertexBuffer buffer) {
|
||||
if(index < 0 || index >= 4) throw new ArrayIndexOutOfBoundsException(index);
|
||||
buffers[index] = buffer;
|
||||
}
|
||||
|
||||
public void applyState() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(fbo == -1) return;
|
||||
if(scissors) GL11.glDisable(GL11.GL_SCISSOR_TEST);
|
||||
if(fbo != 0) GL45.glBindFramebuffer(GL45.GL_DRAW_FRAMEBUFFER, 0);
|
||||
fbo = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package speiger.src.coreengine.graphics.opengl.shader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public class ShaderCache {
|
||||
public static final ShaderCache INSTANCE = new ShaderCache();
|
||||
Map<AssetLocation, String> hashCache;
|
||||
Path cache;
|
||||
|
||||
public void init(Path cache) {
|
||||
this.cache = cache;
|
||||
if(Files.notExists(cache)) {
|
||||
try { Files.createDirectories(cache); }
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
this.cache = null;
|
||||
}
|
||||
}
|
||||
try(BufferedReader reader = Files.newBufferedReader(cache.resolve("cache.json"))) {
|
||||
Map<AssetLocation, String> knownCache = new Object2ObjectOpenHashMap<>();
|
||||
for(JsonElement element : JsonParser.parseReader(reader).getAsJsonObject().getAsJsonArray("shaders")) {
|
||||
JsonObject shader = element.getAsJsonObject();
|
||||
knownCache.put(AssetLocation.of(shader.get("id").getAsString()), shader.get("hash").getAsString());
|
||||
}
|
||||
hashCache = knownCache;
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
hashCache = new Object2ObjectOpenHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
JsonArray array = new JsonArray();
|
||||
hashCache.forEach((K, V) -> {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("id", K.toString());
|
||||
obj.addProperty("hash", V);
|
||||
array.add(obj);
|
||||
});
|
||||
try(JsonWriter writer = new JsonWriter(Files.newBufferedWriter(cache.resolve("cache.json")))) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.add("shaders", array);
|
||||
writer.setIndent("\t");
|
||||
Streams.write(obj, writer);
|
||||
}
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
public byte[] get(AssetLocation shaderLocation, String fileHash) {
|
||||
String known = hashCache.get(shaderLocation);
|
||||
if(!Objects.equals(known, fileHash)) return null;
|
||||
Path path = toFile(shaderLocation);
|
||||
if(Files.notExists(path)) return null;
|
||||
try { return Files.readAllBytes(path); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public void store(AssetLocation shaderLocation, String fileHash, byte[] shader) {
|
||||
Objects.requireNonNull(shaderLocation);
|
||||
Objects.requireNonNull(fileHash);
|
||||
Objects.requireNonNull(shader);
|
||||
hashCache.put(shaderLocation, fileHash);
|
||||
try {
|
||||
Path file = toFile(shaderLocation);
|
||||
if(Files.notExists(file.getParent())) Files.createDirectories(file.getParent());
|
||||
Files.write(file, shader);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
public void delete(AssetLocation shaderLocation) {
|
||||
if(hashCache.remove(shaderLocation) == null) return;
|
||||
try { Files.deleteIfExists(toFile(shaderLocation)); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
save();
|
||||
}
|
||||
|
||||
private Path toFile(AssetLocation id) {
|
||||
return cache.resolve(id.domain()).resolve(id.location()+".bin");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package speiger.src.coreengine.graphics.opengl.shader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record ShaderInstance(int programId, Map<String, UniformObject> uniforms, Map<String, SamplerObject> samplers) {
|
||||
|
||||
public record UniformObject(int slot) {}
|
||||
public record SamplerObject(int unit) {}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package speiger.src.coreengine.graphics.opengl.texture;
|
||||
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2IntMap;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public class FrameBufferCache {
|
||||
Object2IntMap<AssetLocation> fboCache = new Object2IntOpenHashMap<>();
|
||||
|
||||
public int getOrCreateFBO(AssetLocation id) {
|
||||
return fboCache.supplyIntIfAbsent(id, GL45::glCreateFramebuffers);
|
||||
}
|
||||
|
||||
public void deleteFBO(AssetLocation id) {
|
||||
int fbo = fboCache.rem(id);
|
||||
if(fbo == -1) return;
|
||||
GL45.glDeleteFramebuffers(fbo);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
GL45.glDeleteFramebuffers(fboCache.values().toIntArray());
|
||||
fboCache.clear();
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,10 @@ public class GLTexture extends Texture {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRemoved() {
|
||||
return id == 0;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
|
||||
public record AssetFilter(String prefix, String extension) {
|
||||
public static AssetFilter json(String prefix) {
|
||||
return new AssetFilter(prefix, ".json");
|
||||
}
|
||||
|
||||
public AssetLocation id(AssetLocation file) {
|
||||
String location = file.location();
|
||||
return AssetLocation.of(file.domain(), location.substring(prefix().length()+1, location.length()-extension().length()));
|
||||
}
|
||||
|
||||
public AssetLocation file(AssetLocation id) {
|
||||
return AssetLocation.of(id.domain(), prefix()+"/"+id.location()+extension());
|
||||
}
|
||||
|
||||
public Map<AssetLocation, IAsset> list(IAssetProvider provider) {
|
||||
return provider.listAssets(prefix, T -> T.endsWith(extension));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, IAsset> listRoot(IAssetProvider provider) {
|
||||
return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, MultiAsset> multi(IAssetProvider provider) {
|
||||
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, MultiAsset> multiRoot(IAssetProvider provider) {
|
||||
return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
|
||||
}
|
||||
|
||||
}
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
|
||||
public record AssetFilter(String prefix, String extension) {
|
||||
public static AssetFilter json(String prefix) {
|
||||
return new AssetFilter(prefix, ".json");
|
||||
}
|
||||
|
||||
public AssetLocation id(AssetLocation file) {
|
||||
String location = file.location();
|
||||
return AssetLocation.of(file.domain(), location.substring(prefix().length()+1, location.length()-extension().length()));
|
||||
}
|
||||
|
||||
public AssetLocation file(AssetLocation id) {
|
||||
return AssetLocation.of(id.domain(), prefix()+"/"+id.location()+extension());
|
||||
}
|
||||
|
||||
public Map<AssetLocation, IAsset> list(IAssetProvider provider) {
|
||||
return provider.listAssets(prefix, T -> T.endsWith(extension));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, IAsset> listRoot(IAssetProvider provider) {
|
||||
return provider.listAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, MultiAsset> multi(IAssetProvider provider) {
|
||||
return provider.listAllAssets(prefix, T -> T.endsWith(extension));
|
||||
}
|
||||
|
||||
public Map<AssetLocation, MultiAsset> multiRoot(IAssetProvider provider) {
|
||||
return provider.listAllAssets(prefix, T -> T.endsWith(extension) && !T.isInFolder(prefix));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +1,103 @@
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.IManagedAsset;
|
||||
import speiger.src.coreengine.assets.base.IReloadableAsset;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.base.PackReloadingTask;
|
||||
import speiger.src.coreengine.assets.impl.LayeredAssetProvider;
|
||||
|
||||
public class AssetManager implements ICloseableAssetProvider
|
||||
{
|
||||
ObjectList<IReloadableAsset> listeners = new ObjectArrayList<>();
|
||||
LayeredAssetProvider provider;
|
||||
|
||||
public AssetManager(List<IAssetPackage> packages) {
|
||||
provider = new LayeredAssetProvider(packages);
|
||||
}
|
||||
|
||||
public void addListener(IReloadableAsset listener) {
|
||||
listeners.add(listener);
|
||||
if(listener instanceof IManagedAsset managed) {
|
||||
managed.setProvider(this);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectList<IReloadableAsset> listeners() {
|
||||
return ObjectLists.unmodifiable(listeners);
|
||||
}
|
||||
|
||||
public AssetManager reload(Executor offthread, Executor syncer, List<IAssetPackage> packages) {
|
||||
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reload() {
|
||||
return reload(Runnable::run, Runnable::run);
|
||||
}
|
||||
|
||||
public AssetManager reload(Executor offthread, Executor syncer) {
|
||||
return reloadSelective(offthread, syncer, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
|
||||
return reloadSelective(Runnable::run, Runnable::run, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
|
||||
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
|
||||
return this;
|
||||
}
|
||||
|
||||
public AssetManager reloadAssets(List<IAssetPackage> packages) {
|
||||
provider.close();
|
||||
provider = new LayeredAssetProvider(packages);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
provider.close();
|
||||
listeners.forEach(IReloadableAsset::destroy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
return provider.getModifiedTime(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
return provider.getLatestTime(locations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
return provider.getAsset(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
return provider.getAllAssets(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
return provider.listAssets(folder, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
return provider.listAllAssets(folder, filter);
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.IManagedAsset;
|
||||
import speiger.src.coreengine.assets.base.IReloadableAsset;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.base.PackReloadingTask;
|
||||
import speiger.src.coreengine.assets.impl.LayeredAssetProvider;
|
||||
|
||||
public class AssetManager implements ICloseableAssetProvider
|
||||
{
|
||||
ObjectList<IReloadableAsset> listeners = new ObjectArrayList<>();
|
||||
LayeredAssetProvider provider;
|
||||
|
||||
public AssetManager(List<IAssetPackage> packages) {
|
||||
provider = new LayeredAssetProvider(packages);
|
||||
}
|
||||
|
||||
public void addListener(IReloadableAsset listener) {
|
||||
listeners.add(listener);
|
||||
if(listener instanceof IManagedAsset managed) {
|
||||
managed.setProvider(this);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectList<IReloadableAsset> listeners() {
|
||||
return ObjectLists.unmodifiable(listeners);
|
||||
}
|
||||
|
||||
public AssetManager reload(Executor offthread, Executor syncer, List<IAssetPackage> packages) {
|
||||
return reloadAssets(packages).reloadSelective(offthread, syncer, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reload() {
|
||||
return reload(Runnable::run, Runnable::run);
|
||||
}
|
||||
|
||||
public AssetManager reload(Executor offthread, Executor syncer) {
|
||||
return reloadSelective(offthread, syncer, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reloadSelective(List<IReloadableAsset> listeners) {
|
||||
return reloadSelective(Runnable::run, Runnable::run, listeners);
|
||||
}
|
||||
|
||||
public AssetManager reloadSelective(Executor offthread, Executor syncer, List<IReloadableAsset> listeners) {
|
||||
PackReloadingTask.reload(provider, listeners, offthread, syncer).join();
|
||||
return this;
|
||||
}
|
||||
|
||||
public AssetManager reloadAssets(List<IAssetPackage> packages) {
|
||||
provider.close();
|
||||
provider = new LayeredAssetProvider(packages);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
provider.close();
|
||||
listeners.forEach(IReloadableAsset::destroy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
return provider.getModifiedTime(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
return provider.getLatestTime(locations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
return provider.getAsset(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
return provider.getAllAssets(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
return provider.listAssets(folder, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
return provider.listAllAssets(folder, filter);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,29 @@
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public interface IAsset extends Closeable
|
||||
{
|
||||
public IAssetPackage owner();
|
||||
public AssetLocation location();
|
||||
@Override
|
||||
public void close();
|
||||
public IAsset subAsset(String alternative);
|
||||
public InputStream stream() throws IOException;
|
||||
public ByteBuffer bytes() throws IOException;
|
||||
public BufferedReader reader() throws IOException;
|
||||
public List<String> lines() throws IOException;
|
||||
public JsonObject json() throws IOException;
|
||||
public BufferedImage texture() throws Exception;
|
||||
public <T> T custom(IAssetParser<T> parser) throws IOException;
|
||||
}
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public interface IAsset extends Closeable
|
||||
{
|
||||
public IAssetPackage owner();
|
||||
public AssetLocation location();
|
||||
@Override
|
||||
public void close();
|
||||
public IAsset subAsset(String alternative);
|
||||
public InputStream stream() throws IOException;
|
||||
public ByteBuffer bytes() throws IOException;
|
||||
public BufferedReader reader() throws IOException;
|
||||
public List<String> lines() throws IOException;
|
||||
public JsonObject json() throws IOException;
|
||||
public BufferedImage texture() throws Exception;
|
||||
public <T> T custom(IAssetParser<T> parser) throws IOException;
|
||||
}
|
||||
@@ -1,31 +1,31 @@
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.impl.FolderAssetPackage;
|
||||
import speiger.src.coreengine.assets.impl.ZipAssetPackage;
|
||||
import speiger.src.coreengine.utils.helpers.IOUtils;
|
||||
|
||||
public interface IAssetPackage extends Closeable
|
||||
{
|
||||
@Override
|
||||
public void close();
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept);
|
||||
public List<String> getDomains();
|
||||
public IAsset getAsset(AssetLocation location);
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> accept);
|
||||
|
||||
public static IAssetPackage of(Path path) {
|
||||
if(Files.exists(path)) {
|
||||
if(Files.isDirectory(path)) return new FolderAssetPackage(path);
|
||||
if(IOUtils.isZip(path)) return new ZipAssetPackage(path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.impl.FolderAssetPackage;
|
||||
import speiger.src.coreengine.assets.impl.ZipAssetPackage;
|
||||
import speiger.src.coreengine.utils.helpers.IOUtils;
|
||||
|
||||
public interface IAssetPackage extends Closeable
|
||||
{
|
||||
@Override
|
||||
public void close();
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept);
|
||||
public List<String> getDomains();
|
||||
public IAsset getAsset(AssetLocation location);
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> accept);
|
||||
|
||||
public static IAssetPackage of(Path path) {
|
||||
if(Files.exists(path)) {
|
||||
if(Files.isDirectory(path)) return new FolderAssetPackage(path);
|
||||
if(IOUtils.isZip(path)) return new ZipAssetPackage(path);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public interface IAssetProvider {
|
||||
|
||||
public IAsset getAsset(AssetLocation location);
|
||||
public MultiAsset getAllAssets(AssetLocation location);
|
||||
public FileTime getModifiedTime(AssetLocation location);
|
||||
public FileTime getLatestTime(AssetLocation...locations);
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter);
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter);
|
||||
|
||||
public static interface ICloseableAssetProvider extends IAssetProvider, AutoCloseable {
|
||||
@Override
|
||||
public void close();
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
|
||||
public interface IAssetProvider {
|
||||
|
||||
public IAsset getAsset(AssetLocation location);
|
||||
public MultiAsset getAllAssets(AssetLocation location);
|
||||
public FileTime getModifiedTime(AssetLocation location);
|
||||
public FileTime getLatestTime(AssetLocation...locations);
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter);
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter);
|
||||
|
||||
public static interface ICloseableAssetProvider extends IAssetProvider, AutoCloseable {
|
||||
@Override
|
||||
public void close();
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,85 @@
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
|
||||
import speiger.src.collections.objects.collections.ObjectIterable;
|
||||
import speiger.src.collections.objects.collections.ObjectIterator;
|
||||
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
|
||||
public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
|
||||
ObjectList<IAsset> assets;
|
||||
|
||||
public MultiAsset(IAsset...assets) {
|
||||
this(ObjectArrayList.wrap(assets));
|
||||
}
|
||||
|
||||
public MultiAsset(ObjectList<IAsset> assets) {
|
||||
this.assets = assets.unmodifiable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(assets != null) {
|
||||
assets.forEach(IAsset::close);
|
||||
assets = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return assets.size();
|
||||
}
|
||||
|
||||
public IAsset get(int index) {
|
||||
return assets.get(index);
|
||||
}
|
||||
|
||||
public <T> Iterable<T> map(AssetMapper<T> mappingFunction, Supplier<T> defaultValue) {
|
||||
return () -> new Iterator<T>() {
|
||||
int index = 0;
|
||||
int size = assets.size();
|
||||
@Override
|
||||
public boolean hasNext() { return index < size; }
|
||||
@Override
|
||||
public T next() {
|
||||
if(!hasNext()) throw new NoSuchElementException();
|
||||
try { return mappingFunction.apply(assets.get(index++)); }
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
return defaultValue.get();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super IAsset> action) {
|
||||
assets.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
|
||||
assets.forEach(input, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
|
||||
assets.forEachIndexed(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectIterator<IAsset> iterator() {
|
||||
return assets.iterator();
|
||||
}
|
||||
|
||||
public static interface AssetMapper<T> {
|
||||
public T apply(IAsset asset) throws IOException;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.base;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import speiger.src.collections.ints.functions.consumer.IntObjectConsumer;
|
||||
import speiger.src.collections.objects.collections.ObjectIterable;
|
||||
import speiger.src.collections.objects.collections.ObjectIterator;
|
||||
import speiger.src.collections.objects.functions.consumer.ObjectObjectConsumer;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
|
||||
public class MultiAsset implements Closeable, ObjectIterable<IAsset> {
|
||||
ObjectList<IAsset> assets;
|
||||
|
||||
public MultiAsset(IAsset...assets) {
|
||||
this(ObjectArrayList.wrap(assets));
|
||||
}
|
||||
|
||||
public MultiAsset(ObjectList<IAsset> assets) {
|
||||
this.assets = assets.unmodifiable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(assets != null) {
|
||||
assets.forEach(IAsset::close);
|
||||
assets = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return assets.size();
|
||||
}
|
||||
|
||||
public IAsset get(int index) {
|
||||
return assets.get(index);
|
||||
}
|
||||
|
||||
public <T> Iterable<T> map(AssetMapper<T> mappingFunction, Supplier<T> defaultValue) {
|
||||
return () -> new Iterator<T>() {
|
||||
int index = 0;
|
||||
int size = assets.size();
|
||||
@Override
|
||||
public boolean hasNext() { return index < size; }
|
||||
@Override
|
||||
public T next() {
|
||||
if(!hasNext()) throw new NoSuchElementException();
|
||||
try { return mappingFunction.apply(assets.get(index++)); }
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
return defaultValue.get();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super IAsset> action) {
|
||||
assets.forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> void forEach(E input, ObjectObjectConsumer<E, IAsset> action) {
|
||||
assets.forEach(input, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachIndexed(IntObjectConsumer<IAsset> action) {
|
||||
assets.forEachIndexed(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectIterator<IAsset> iterator() {
|
||||
return assets.iterator();
|
||||
}
|
||||
|
||||
public static interface AssetMapper<T> {
|
||||
public T apply(IAsset asset) throws IOException;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
|
||||
public abstract class BaseAsset implements IAsset {
|
||||
protected AssetLocation location;
|
||||
protected IAssetPackage owner;
|
||||
protected List<Closeable> closeable = new ObjectArrayList<>();
|
||||
|
||||
public BaseAsset(AssetLocation location, IAssetPackage owner) {
|
||||
this.location = location;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for(Closeable close : closeable) {
|
||||
try { close.close(); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
closeable.clear();
|
||||
}
|
||||
|
||||
protected <T extends Closeable> T markClosed(T value) {
|
||||
closeable.add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetLocation location() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAssetPackage owner() {
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.List;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
|
||||
public abstract class BaseAsset implements IAsset {
|
||||
protected AssetLocation location;
|
||||
protected IAssetPackage owner;
|
||||
protected List<Closeable> closeable = new ObjectArrayList<>();
|
||||
|
||||
public BaseAsset(AssetLocation location, IAssetPackage owner) {
|
||||
this.location = location;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for(Closeable close : closeable) {
|
||||
try { close.close(); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
closeable.clear();
|
||||
}
|
||||
|
||||
protected <T extends Closeable> T markClosed(T value) {
|
||||
closeable.add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetLocation location() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAssetPackage owner() {
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +1,71 @@
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class FolderAssetPackage implements IAssetPackage {
|
||||
Path baseFolder;
|
||||
|
||||
public FolderAssetPackage(Path baseFolder) {
|
||||
this.baseFolder = baseFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
||||
try {
|
||||
Path start = baseFolder.resolve("assets/").resolve(domain);
|
||||
for(Path path : IterableWrapper.wrap(Files.walk(start).filter(Files::isRegularFile).iterator())) {
|
||||
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDomains() {
|
||||
List<String> domains = new ObjectArrayList<>();
|
||||
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(baseFolder.resolve("assets"))) {
|
||||
for(Path path : dirs) {
|
||||
domains.add(path.getFileName().toString());
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
return domains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
Path path = baseFolder.resolve(location.actualLocation());
|
||||
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
|
||||
Path start = baseFolder.resolve(folder.actualLocation());
|
||||
if(Files.notExists(start)) return;
|
||||
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
|
||||
for(Path path : IterableWrapper.wrap(stream.iterator())) {
|
||||
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
|
||||
result.accept(location, new SimpleAsset(location, this, path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class FolderAssetPackage implements IAssetPackage {
|
||||
Path baseFolder;
|
||||
|
||||
public FolderAssetPackage(Path baseFolder) {
|
||||
this.baseFolder = baseFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
||||
try {
|
||||
Path start = baseFolder.resolve("assets/").resolve(domain);
|
||||
for(Path path : IterableWrapper.wrap(Files.walk(start).filter(Files::isRegularFile).iterator())) {
|
||||
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDomains() {
|
||||
List<String> domains = new ObjectArrayList<>();
|
||||
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(baseFolder.resolve("assets"))) {
|
||||
for(Path path : dirs) {
|
||||
domains.add(path.getFileName().toString());
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
return domains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
Path path = baseFolder.resolve(location.actualLocation());
|
||||
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
|
||||
Path start = baseFolder.resolve(folder.actualLocation());
|
||||
if(Files.notExists(start)) return;
|
||||
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
|
||||
for(Path path : IterableWrapper.wrap(stream.iterator())) {
|
||||
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
|
||||
result.accept(location, new SimpleAsset(location, this, path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,161 +1,161 @@
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.math.ArrayUtil;
|
||||
|
||||
public class LayeredAssetProvider implements ICloseableAssetProvider {
|
||||
public static final FileTime DEFAULT_TIME = FileTime.fromMillis(0L);
|
||||
Map<String, DomainAssetProvider> domains = Object2ObjectMap.builder().linkedMap();
|
||||
List<IAssetPackage> packages;
|
||||
|
||||
public LayeredAssetProvider(List<IAssetPackage> packages) {
|
||||
this.packages = packages;
|
||||
for(IAssetPackage pack : packages) {
|
||||
for(String domain : pack.getDomains()) {
|
||||
domains.computeIfAbsent(domain, DomainAssetProvider::new).addPackage(pack);
|
||||
}
|
||||
}
|
||||
domains.values().forEach(DomainAssetProvider::buildCaches);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
packages.forEach(IAssetPackage::close);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? DEFAULT_TIME : provider.getModifiedTime(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
FileTime time = DEFAULT_TIME;
|
||||
for(AssetLocation location : locations) {
|
||||
time = ArrayUtil.higher(time, getModifiedTime(location));
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? null : provider.getAsset(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? null : provider.getAllAssets(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(DomainAssetProvider provider : domains.values()) {
|
||||
result.putAll(provider.listAssets(folder, filter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(DomainAssetProvider provider : domains.values()) {
|
||||
result.putAll(provider.listAllAssets(folder, filter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class DomainAssetProvider implements IAssetProvider {
|
||||
final String domain;
|
||||
ObjectList<IAssetPackage> packages = new ObjectArrayList<>();
|
||||
Map<AssetLocation, FileTime> lastChanges = Object2ObjectMap.builder().map();
|
||||
|
||||
public DomainAssetProvider(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public void addPackage(IAssetPackage pack) {
|
||||
packages.add(pack);
|
||||
}
|
||||
|
||||
private void buildCaches() {
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).getModifiedTime(domain, lastChanges::putIfAbsent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
return lastChanges.getOrDefault(location, DEFAULT_TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
IAsset asset = packages.get(i).getAsset(location);
|
||||
if(asset != null) return asset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
ObjectList<IAsset> result = new ObjectArrayList<>();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
IAsset asset = packages.get(i).getAsset(location);
|
||||
if(asset != null) result.add(asset);
|
||||
}
|
||||
return new MultiAsset(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
AssetLocation base = AssetLocation.of(domain, folder);
|
||||
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).gatherAssets(base, (K, V) -> {
|
||||
if(filter.test(K)) result.putIfAbsent(K, V);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
AssetLocation base = AssetLocation.of(domain, folder);
|
||||
Object2ObjectMap<AssetLocation, ObjectList<IAsset>> assets = Object2ObjectMap.builder().linkedMap();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).gatherAssets(base, (K, V) -> {
|
||||
if(filter.test(K)) assets.supplyIfAbsent(K, ObjectArrayList::new).add(V);
|
||||
});
|
||||
}
|
||||
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(Object2ObjectMap.Entry<AssetLocation, ObjectList<IAsset>> entry : Object2ObjectMaps.fastIterable(assets)) {
|
||||
result.put(entry.getKey(), new MultiAsset(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider.ICloseableAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.math.ArrayUtil;
|
||||
|
||||
public class LayeredAssetProvider implements ICloseableAssetProvider {
|
||||
public static final FileTime DEFAULT_TIME = FileTime.fromMillis(0L);
|
||||
Map<String, DomainAssetProvider> domains = Object2ObjectMap.builder().linkedMap();
|
||||
List<IAssetPackage> packages;
|
||||
|
||||
public LayeredAssetProvider(List<IAssetPackage> packages) {
|
||||
this.packages = packages;
|
||||
for(IAssetPackage pack : packages) {
|
||||
for(String domain : pack.getDomains()) {
|
||||
domains.computeIfAbsent(domain, DomainAssetProvider::new).addPackage(pack);
|
||||
}
|
||||
}
|
||||
domains.values().forEach(DomainAssetProvider::buildCaches);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
packages.forEach(IAssetPackage::close);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? DEFAULT_TIME : provider.getModifiedTime(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
FileTime time = DEFAULT_TIME;
|
||||
for(AssetLocation location : locations) {
|
||||
time = ArrayUtil.higher(time, getModifiedTime(location));
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? null : provider.getAsset(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
DomainAssetProvider provider = domains.get(location.domain());
|
||||
return provider == null ? null : provider.getAllAssets(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(DomainAssetProvider provider : domains.values()) {
|
||||
result.putAll(provider.listAssets(folder, filter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(DomainAssetProvider provider : domains.values()) {
|
||||
result.putAll(provider.listAllAssets(folder, filter));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class DomainAssetProvider implements IAssetProvider {
|
||||
final String domain;
|
||||
ObjectList<IAssetPackage> packages = new ObjectArrayList<>();
|
||||
Map<AssetLocation, FileTime> lastChanges = Object2ObjectMap.builder().map();
|
||||
|
||||
public DomainAssetProvider(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public void addPackage(IAssetPackage pack) {
|
||||
packages.add(pack);
|
||||
}
|
||||
|
||||
private void buildCaches() {
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).getModifiedTime(domain, lastChanges::putIfAbsent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getModifiedTime(AssetLocation location) {
|
||||
return lastChanges.getOrDefault(location, DEFAULT_TIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLatestTime(AssetLocation... locations) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
IAsset asset = packages.get(i).getAsset(location);
|
||||
if(asset != null) return asset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiAsset getAllAssets(AssetLocation location) {
|
||||
ObjectList<IAsset> result = new ObjectArrayList<>();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
IAsset asset = packages.get(i).getAsset(location);
|
||||
if(asset != null) result.add(asset);
|
||||
}
|
||||
return new MultiAsset(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, IAsset> listAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
AssetLocation base = AssetLocation.of(domain, folder);
|
||||
Map<AssetLocation, IAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).gatherAssets(base, (K, V) -> {
|
||||
if(filter.test(K)) result.putIfAbsent(K, V);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<AssetLocation, MultiAsset> listAllAssets(String folder, Predicate<AssetLocation> filter) {
|
||||
AssetLocation base = AssetLocation.of(domain, folder);
|
||||
Object2ObjectMap<AssetLocation, ObjectList<IAsset>> assets = Object2ObjectMap.builder().linkedMap();
|
||||
for(int i = packages.size()-1;i>=0;i--) {
|
||||
packages.get(i).gatherAssets(base, (K, V) -> {
|
||||
if(filter.test(K)) assets.supplyIfAbsent(K, ObjectArrayList::new).add(V);
|
||||
});
|
||||
}
|
||||
Map<AssetLocation, MultiAsset> result = Object2ObjectMap.builder().linkedMap();
|
||||
for(Object2ObjectMap.Entry<AssetLocation, ObjectList<IAsset>> entry : Object2ObjectMaps.fastIterable(assets)) {
|
||||
result.put(entry.getKey(), new MultiAsset(entry.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,51 @@
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetParser;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class SimpleAsset extends BaseAsset {
|
||||
Path path;
|
||||
|
||||
public SimpleAsset(AssetLocation location, IAssetPackage owner, Path path) {
|
||||
super(location, owner);
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset subAsset(String alternative) {
|
||||
Path newPath = path.resolveSibling(path.getFileName().toString()+"."+alternative);
|
||||
return Files.exists(newPath) ? new SimpleAsset(location.alternate(alternative), owner, newPath) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() throws IOException { return markClosed(Files.newInputStream(path)); }
|
||||
@Override
|
||||
public ByteBuffer bytes() throws IOException { return ByteBuffer.wrap(Files.readAllBytes(path)); }
|
||||
@Override
|
||||
public BufferedImage texture() throws Exception { return ImageIO.read(stream()); }
|
||||
@Override
|
||||
public BufferedReader reader() throws IOException { return markClosed(Files.newBufferedReader(path)); }
|
||||
@Override
|
||||
public List<String> lines() throws IOException { return Files.readAllLines(path); }
|
||||
@Override
|
||||
public JsonObject json() throws IOException { return JsonUtil.loadFile(path); }
|
||||
@Override
|
||||
public <T> T custom(IAssetParser<T> parser) throws IOException { return parser.parseAsset(path, closeable::add); }
|
||||
|
||||
}
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.assets.base.IAssetParser;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class SimpleAsset extends BaseAsset {
|
||||
Path path;
|
||||
|
||||
public SimpleAsset(AssetLocation location, IAssetPackage owner, Path path) {
|
||||
super(location, owner);
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset subAsset(String alternative) {
|
||||
Path newPath = path.resolveSibling(path.getFileName().toString()+"."+alternative);
|
||||
return Files.exists(newPath) ? new SimpleAsset(location.alternate(alternative), owner, newPath) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() throws IOException { return markClosed(Files.newInputStream(path)); }
|
||||
@Override
|
||||
public ByteBuffer bytes() throws IOException { return ByteBuffer.wrap(Files.readAllBytes(path)); }
|
||||
@Override
|
||||
public BufferedImage texture() throws Exception { return ImageIO.read(stream()); }
|
||||
@Override
|
||||
public BufferedReader reader() throws IOException { return markClosed(Files.newBufferedReader(path)); }
|
||||
@Override
|
||||
public List<String> lines() throws IOException { return Files.readAllLines(path); }
|
||||
@Override
|
||||
public JsonObject json() throws IOException { return JsonUtil.loadFile(path); }
|
||||
@Override
|
||||
public <T> T custom(IAssetParser<T> parser) throws IOException { return parser.parseAsset(path, closeable::add); }
|
||||
|
||||
}
|
||||
@@ -1,107 +1,107 @@
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class ZipAssetPackage implements IAssetPackage {
|
||||
Path baseFolder;
|
||||
FileSystem cache;
|
||||
|
||||
public ZipAssetPackage(Path baseFolder) {
|
||||
this.baseFolder = baseFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(cache != null) {
|
||||
try { cache.close(); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
cache = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
||||
try {
|
||||
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
|
||||
Path start = system.getPath("assets");
|
||||
for(Path path : IterableWrapper.wrap(Files.walk(start.resolve(domain)).filter(Files::isRegularFile).iterator())) {
|
||||
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
protected FileSystem getReference() throws IOException {
|
||||
if(cache == null) cache = FileSystems.newFileSystem(baseFolder);
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDomains() {
|
||||
List<String> domains = new ObjectArrayList<>();
|
||||
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
|
||||
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(system.getPath("assets"))) {
|
||||
for(Path path : dirs) {
|
||||
String s = path.getFileName().toString();
|
||||
domains.add(s.substring(0, s.length()));
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
try {
|
||||
Path path = getReference().getPath(location.actualLocation());
|
||||
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
|
||||
try {
|
||||
FileSystem system = getReference();
|
||||
Path start = system.getPath(folder.actualLocation());
|
||||
if(Files.notExists(start)) return;
|
||||
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
|
||||
for(Path path : IterableWrapper.wrap(stream.iterator())) {
|
||||
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
|
||||
result.accept(location, new SimpleAsset(location, this, path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.assets.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetPackage;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
|
||||
public class ZipAssetPackage implements IAssetPackage {
|
||||
Path baseFolder;
|
||||
FileSystem cache;
|
||||
|
||||
public ZipAssetPackage(Path baseFolder) {
|
||||
this.baseFolder = baseFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if(cache != null) {
|
||||
try { cache.close(); }
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
cache = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getModifiedTime(String domain, BiConsumer<AssetLocation, FileTime> accept) {
|
||||
try {
|
||||
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
|
||||
Path start = system.getPath("assets");
|
||||
for(Path path : IterableWrapper.wrap(Files.walk(start.resolve(domain)).filter(Files::isRegularFile).iterator())) {
|
||||
accept.accept(AssetLocation.of(domain, start.relativize(path).toString().replace("\\", "/")), Files.getLastModifiedTime(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(IOException e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
protected FileSystem getReference() throws IOException {
|
||||
if(cache == null) cache = FileSystems.newFileSystem(baseFolder);
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDomains() {
|
||||
List<String> domains = new ObjectArrayList<>();
|
||||
try(FileSystem system = FileSystems.newFileSystem(baseFolder)) {
|
||||
try(DirectoryStream<Path> dirs = Files.newDirectoryStream(system.getPath("assets"))) {
|
||||
for(Path path : dirs) {
|
||||
String s = path.getFileName().toString();
|
||||
domains.add(s.substring(0, s.length()));
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAsset getAsset(AssetLocation location) {
|
||||
try {
|
||||
Path path = getReference().getPath(location.actualLocation());
|
||||
return Files.exists(path) ? new SimpleAsset(location, this, path) : null;
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gatherAssets(AssetLocation folder, BiConsumer<AssetLocation, IAsset> result) {
|
||||
try {
|
||||
FileSystem system = getReference();
|
||||
Path start = system.getPath(folder.actualLocation());
|
||||
if(Files.notExists(start)) return;
|
||||
try(Stream<Path> stream = Files.walk(start).filter(Files::isRegularFile)) {
|
||||
for(Path path : IterableWrapper.wrap(stream.iterator())) {
|
||||
AssetLocation location = folder.subAsset(start.relativize(path).toString().replace("\\", "/"));
|
||||
result.accept(location, new SimpleAsset(location, this, path));
|
||||
}
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,106 +1,106 @@
|
||||
package speiger.src.coreengine.assets.language;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
|
||||
public class LanguageManager implements IReloadableResource {
|
||||
final AssetLocation location = AssetLocation.of("lang");
|
||||
Map<String, Language> languages = new Object2ObjectOpenHashMap<>();
|
||||
AssetManager assets;
|
||||
String currentLanguage;
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
languages.clear();
|
||||
try(MultiAsset langs = assets.getAllAssets(location.subAsset("langs.json"))) {
|
||||
for(int i = 0,m = langs.size();i < m;i++) {
|
||||
preLoadLanguage(langs.get(i).json());
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(loadLanguage(currentLanguage)) {
|
||||
I18n.CURRENT_LANGUAGE = languages.get(currentLanguage);
|
||||
}
|
||||
else {
|
||||
Language dummy = new Language("en_US", "English");
|
||||
dummy.load(Object2ObjectMaps.empty());
|
||||
I18n.CURRENT_LANGUAGE = dummy;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setLanguage(String lang) {
|
||||
if(loadLanguage(lang)) {
|
||||
I18n.CURRENT_LANGUAGE = languages.get(lang);
|
||||
Language currentLang = languages.get(currentLanguage);
|
||||
currentLanguage = lang;
|
||||
if(currentLang != null) currentLang.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean loadLanguage(String loadingLang) {
|
||||
Language lang = languages.get(loadingLang);
|
||||
if(lang == null) return false;
|
||||
Map<String, String> map = new Object2ObjectOpenHashMap<>();
|
||||
loadLanguage(loadingLang, map);
|
||||
if(loadingLang != "en_US") loadLanguage("en_US", map);
|
||||
lang.load(map);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void loadLanguage(String lang, Map<String, String> data) {
|
||||
try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) {
|
||||
for(int i = 0,m = language.size();i < m;i++) {
|
||||
try {
|
||||
for(Map.Entry<String, JsonElement> element : language.get(i).json().entrySet()) {
|
||||
loadEntry(element.getKey(), element.getValue(), data);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadEntry(String basePath, JsonElement el, Map<String, String> data) {
|
||||
if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString());
|
||||
else if(el.isJsonObject()) {
|
||||
for(Map.Entry<String, JsonElement> elements : el.getAsJsonObject().entrySet()) {
|
||||
String key = elements.getKey();
|
||||
if(key.isEmpty()) loadEntry(basePath, elements.getValue(), data);
|
||||
else loadEntry(basePath+"."+key, elements.getValue(), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void preLoadLanguage(JsonObject object) {
|
||||
JsonArray array = object.getAsJsonArray("languages");
|
||||
if(array == null) return;
|
||||
for(int i = 0,m = array.size();i < m;i++) {
|
||||
JsonArray subArray = array.get(i).getAsJsonArray();
|
||||
if(subArray.size() != 2) continue;
|
||||
String key = subArray.get(0).getAsString();
|
||||
String value = subArray.get(1).getAsString();
|
||||
if(key.length() != 2 || value.length() > 16) continue;
|
||||
languages.computeIfAbsent(key, T -> new Language(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package speiger.src.coreengine.assets.language;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
|
||||
public class LanguageManager implements IReloadableResource {
|
||||
final AssetLocation location = AssetLocation.of("lang");
|
||||
Map<String, Language> languages = new Object2ObjectOpenHashMap<>();
|
||||
AssetManager assets;
|
||||
String currentLanguage;
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
languages.clear();
|
||||
try(MultiAsset langs = assets.getAllAssets(location.subAsset("langs.json"))) {
|
||||
for(int i = 0,m = langs.size();i < m;i++) {
|
||||
preLoadLanguage(langs.get(i).json());
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(loadLanguage(currentLanguage)) {
|
||||
I18n.CURRENT_LANGUAGE = languages.get(currentLanguage);
|
||||
}
|
||||
else {
|
||||
Language dummy = new Language("en_US", "English");
|
||||
dummy.load(Object2ObjectMaps.empty());
|
||||
I18n.CURRENT_LANGUAGE = dummy;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setLanguage(String lang) {
|
||||
if(loadLanguage(lang)) {
|
||||
I18n.CURRENT_LANGUAGE = languages.get(lang);
|
||||
Language currentLang = languages.get(currentLanguage);
|
||||
currentLanguage = lang;
|
||||
if(currentLang != null) currentLang.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean loadLanguage(String loadingLang) {
|
||||
Language lang = languages.get(loadingLang);
|
||||
if(lang == null) return false;
|
||||
Map<String, String> map = new Object2ObjectOpenHashMap<>();
|
||||
loadLanguage(loadingLang, map);
|
||||
if(loadingLang != "en_US") loadLanguage("en_US", map);
|
||||
lang.load(map);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void loadLanguage(String lang, Map<String, String> data) {
|
||||
try(MultiAsset language = assets.getAllAssets(location.subAsset(lang+".lang"))) {
|
||||
for(int i = 0,m = language.size();i < m;i++) {
|
||||
try {
|
||||
for(Map.Entry<String, JsonElement> element : language.get(i).json().entrySet()) {
|
||||
loadEntry(element.getKey(), element.getValue(), data);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadEntry(String basePath, JsonElement el, Map<String, String> data) {
|
||||
if(el.isJsonPrimitive()) data.putIfAbsent(basePath, el.getAsString());
|
||||
else if(el.isJsonObject()) {
|
||||
for(Map.Entry<String, JsonElement> elements : el.getAsJsonObject().entrySet()) {
|
||||
String key = elements.getKey();
|
||||
if(key.isEmpty()) loadEntry(basePath, elements.getValue(), data);
|
||||
else loadEntry(basePath+"."+key, elements.getValue(), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void preLoadLanguage(JsonObject object) {
|
||||
JsonArray array = object.getAsJsonArray("languages");
|
||||
if(array == null) return;
|
||||
for(int i = 0,m = array.size();i < m;i++) {
|
||||
JsonArray subArray = array.get(i).getAsJsonArray();
|
||||
if(subArray.size() != 2) continue;
|
||||
String key = subArray.get(0).getAsString();
|
||||
String value = subArray.get(1).getAsString();
|
||||
if(key.length() != 2 || value.length() > 16) continue;
|
||||
languages.computeIfAbsent(key, _ -> new Language(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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+"]"; }
|
||||
}
|
||||
@@ -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+"]"; }
|
||||
}
|
||||
@@ -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+"]"; }
|
||||
}
|
||||
@@ -1,118 +1,118 @@
|
||||
package speiger.src.coreengine.rendering.gui.font;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.floats.maps.interfaces.Float2ObjectMap;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.coreengine.assets.AssetFilter;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.FreeTypeProvider;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
|
||||
private static final int TEXTURE_SIZE = 512;
|
||||
private static final AssetFilter FILTER = AssetFilter.json("font");
|
||||
Float2ObjectMap<Font> cachedFonts = Float2ObjectMap.builder().map();
|
||||
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
|
||||
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
|
||||
List<Runnable> listeners = new ObjectArrayList<>();
|
||||
List<FontTexture> textures = new ObjectArrayList<>();
|
||||
|
||||
public FontManager() {
|
||||
registerParser("stb-ttf", STBTrueTypeProvider::create);
|
||||
registerParser("free-ttf", FreeTypeProvider::load);
|
||||
}
|
||||
|
||||
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
|
||||
fontParsers.putIfAbsent(id, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return "Font Manager"; }
|
||||
|
||||
@Override
|
||||
protected Map<AssetLocation, ObjectList<IFontProvider>> prepare(IAssetProvider provider) {
|
||||
Map<AssetLocation, IFontProvider> loadingCache = Object2ObjectMap.builder().linkedMap();
|
||||
Object2ObjectMap<AssetLocation, ObjectList<IFontProvider>> providers = Object2ObjectMap.builder().linkedMap();
|
||||
for(Entry<AssetLocation, MultiAsset> entry : FILTER.multiRoot(provider).entrySet()) {
|
||||
AssetLocation id = entry.getKey();
|
||||
for(JsonObject obj : entry.getValue().map(IAsset::json, JsonObject::new)) {
|
||||
JsonUtil.iterateValues(obj.get("providers"), T -> {
|
||||
AssetLocation location = AssetLocation.tryOf(T.getAsString());
|
||||
if(location == null || !location.isInFolder()) return;
|
||||
IFontProvider font = loadingCache.computeIfAbsent(location.prefix("font"), E -> getFont(E, provider));
|
||||
if(font == null) return;
|
||||
providers.supplyIfAbsent(FILTER.id(id), ObjectArrayList::new).add(font);
|
||||
});
|
||||
}
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Map<AssetLocation, ObjectList<IFontProvider>> value, IAssetProvider provider) {
|
||||
reset();
|
||||
value.forEach((K, V) -> fonts.put(K, new FontGroup(K, V)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
reset();
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
listeners.forEach(Runnable::run);
|
||||
textures.forEach(FontTexture::delete);
|
||||
textures.clear();
|
||||
fonts.values().forEach(FontGroup::close);
|
||||
fonts.clear();
|
||||
cachedFonts.clear();
|
||||
}
|
||||
|
||||
public Font createFont() {
|
||||
return createFont(1F);
|
||||
}
|
||||
|
||||
public Font createFont(float oversample) {
|
||||
return cachedFonts.computeIfAbsent(oversample, T -> new Font(fonts, this::stitch, T, listeners::add));
|
||||
}
|
||||
|
||||
private Glyth stitch(IGlythSheetInfo info) {
|
||||
for(int i = 0,m=textures.size();i<m;i++) {
|
||||
Glyth glyth = textures.get(i).build(info);
|
||||
if(glyth != null) return glyth;
|
||||
}
|
||||
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
|
||||
textures.add(texture);
|
||||
Glyth glyth = texture.build(info);
|
||||
return glyth;
|
||||
}
|
||||
|
||||
private IFontProvider getFont(AssetLocation location, IAssetProvider provider) {
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
JsonObject obj = asset.json();
|
||||
BiFunction<JsonObject, IAssetProvider, IFontProvider> builder = fontParsers.get(obj.get("type").getAsString());
|
||||
return builder == null ? null : builder.apply(obj, provider);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
package speiger.src.coreengine.rendering.gui.font;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.floats.maps.interfaces.Float2ObjectMap;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.coreengine.assets.AssetFilter;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.base.MultiAsset;
|
||||
import speiger.src.coreengine.assets.base.SteppedReloadableAsset;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.FreeTypeProvider;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.IFontProvider;
|
||||
import speiger.src.coreengine.rendering.gui.font.providers.STBTrueTypeProvider;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class FontManager extends SteppedReloadableAsset<Map<AssetLocation, ObjectList<IFontProvider>>> {
|
||||
private static final int TEXTURE_SIZE = 512;
|
||||
private static final AssetFilter FILTER = AssetFilter.json("font");
|
||||
Float2ObjectMap<Font> cachedFonts = Float2ObjectMap.builder().map();
|
||||
Map<AssetLocation, FontGroup> fonts = Object2ObjectMap.builder().linkedMap();
|
||||
Map<String, BiFunction<JsonObject, IAssetProvider, IFontProvider>> fontParsers = Object2ObjectMap.builder().map();
|
||||
List<Runnable> listeners = new ObjectArrayList<>();
|
||||
List<FontTexture> textures = new ObjectArrayList<>();
|
||||
|
||||
public FontManager() {
|
||||
registerParser("stb-ttf", STBTrueTypeProvider::create);
|
||||
registerParser("free-ttf", FreeTypeProvider::load);
|
||||
}
|
||||
|
||||
public void registerParser(String id, BiFunction<JsonObject, IAssetProvider, IFontProvider> parser) {
|
||||
fontParsers.putIfAbsent(id, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return "Font Manager"; }
|
||||
|
||||
@Override
|
||||
protected Map<AssetLocation, ObjectList<IFontProvider>> prepare(IAssetProvider provider) {
|
||||
Map<AssetLocation, IFontProvider> loadingCache = Object2ObjectMap.builder().linkedMap();
|
||||
Object2ObjectMap<AssetLocation, ObjectList<IFontProvider>> providers = Object2ObjectMap.builder().linkedMap();
|
||||
for(Entry<AssetLocation, MultiAsset> entry : FILTER.multiRoot(provider).entrySet()) {
|
||||
AssetLocation id = entry.getKey();
|
||||
for(JsonObject obj : entry.getValue().map(IAsset::json, JsonObject::new)) {
|
||||
JsonUtil.iterateValues(obj.get("providers"), T -> {
|
||||
AssetLocation location = AssetLocation.tryOf(T.getAsString());
|
||||
if(location == null || !location.isInFolder()) return;
|
||||
IFontProvider font = loadingCache.computeIfAbsent(location.prefix("font"), E -> getFont(E, provider));
|
||||
if(font == null) return;
|
||||
providers.supplyIfAbsent(FILTER.id(id), ObjectArrayList::new).add(font);
|
||||
});
|
||||
}
|
||||
}
|
||||
return providers;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Map<AssetLocation, ObjectList<IFontProvider>> value, IAssetProvider provider) {
|
||||
reset();
|
||||
value.forEach((K, V) -> fonts.put(K, new FontGroup(K, V)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
reset();
|
||||
listeners.clear();
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
listeners.forEach(Runnable::run);
|
||||
textures.forEach(FontTexture::delete);
|
||||
textures.clear();
|
||||
fonts.values().forEach(FontGroup::close);
|
||||
fonts.clear();
|
||||
cachedFonts.clear();
|
||||
}
|
||||
|
||||
public Font createFont() {
|
||||
return createFont(1F);
|
||||
}
|
||||
|
||||
public Font createFont(float oversample) {
|
||||
return cachedFonts.computeIfAbsent(oversample, T -> new Font(fonts, this::stitch, T, listeners::add));
|
||||
}
|
||||
|
||||
private Glyth stitch(IGlythSheetInfo info) {
|
||||
for(int i = 0,m=textures.size();i<m;i++) {
|
||||
Glyth glyth = textures.get(i).build(info);
|
||||
if(glyth != null) return glyth;
|
||||
}
|
||||
FontTexture texture = new FontTexture(TEXTURE_SIZE, info.isColored());
|
||||
textures.add(texture);
|
||||
Glyth glyth = texture.build(info);
|
||||
return glyth;
|
||||
}
|
||||
|
||||
private IFontProvider getFont(AssetLocation location, IAssetProvider provider) {
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
JsonObject obj = asset.json();
|
||||
BiFunction<JsonObject, IAssetProvider, IFontProvider> builder = fontParsers.get(obj.get("type").getAsString());
|
||||
return builder == null ? null : builder.apply(obj, provider);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+297
-297
@@ -1,297 +1,297 @@
|
||||
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.lwjgl.util.freetype.FT_Bitmap;
|
||||
import org.lwjgl.util.freetype.FT_Face;
|
||||
import org.lwjgl.util.freetype.FT_GlyphSlot;
|
||||
import org.lwjgl.util.freetype.FT_Vector;
|
||||
import org.lwjgl.util.freetype.FreeType;
|
||||
import org.lwjgl.util.harfbuzz.HarfBuzz;
|
||||
import org.lwjgl.util.harfbuzz.hb_glyph_position_t;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
||||
import speiger.src.collections.ints.sets.IntSet;
|
||||
import speiger.src.collections.longs.misc.pairs.LongObjectPair;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
|
||||
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
|
||||
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class FreeTypeProvider implements IFontProvider {
|
||||
|
||||
FreeTypeInstance[] instance;
|
||||
|
||||
public FreeTypeProvider(FreeTypeInstance[] instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
return load(asset.json(), provider);
|
||||
}
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IFontProvider load(JsonObject data, IAssetProvider provider) {
|
||||
long library = FreeTypeLibrary.get();
|
||||
if(library == 0L) return null;
|
||||
FreeTypeInstance[] instances = new FreeTypeInstance[4];
|
||||
instances[0] = create(library, 0, data.getAsJsonObject("regular"), provider);
|
||||
if(instances[0] == null) return null;
|
||||
instances[1] = create(library, 1, data.getAsJsonObject("bold"), provider);
|
||||
instances[2] = create(library, 2, data.getAsJsonObject("italic"), provider);
|
||||
instances[3] = create(library, 3, data.getAsJsonObject("bold_italic"), provider);
|
||||
return new FreeTypeProvider(instances);
|
||||
}
|
||||
|
||||
private static FreeTypeInstance create(long library, int style, JsonObject obj, IAssetProvider provider) {
|
||||
if(obj == null || !obj.has("file")) return null;
|
||||
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
||||
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
|
||||
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
|
||||
float xOff = 0;
|
||||
float yOff = 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
JsonObject shift = obj.getAsJsonObject("offset");
|
||||
if(shift != null) {
|
||||
xOff = JsonUtil.getOrDefault(shift, "x", 0F);
|
||||
yOff = JsonUtil.getOrDefault(shift, "y", 0F);
|
||||
}
|
||||
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
|
||||
LongObjectPair<FT_Face> value = parse(location, provider, library);
|
||||
if(value == null) return null;
|
||||
return new FreeTypeInstance(style, value.getLongKey(), value.getValue(), oversample, xOff, yOff, shadowOffset, builder.toString());
|
||||
}
|
||||
|
||||
private static LongObjectPair<FT_Face> parse(AssetLocation location, IAssetProvider provider, long library) {
|
||||
try(IAsset asset = provider.getAsset(location); MemoryStack stack = MemoryStack.stackPush()) {
|
||||
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
|
||||
PointerBuffer facePointer = stack.mallocPointer(1);
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_New_Memory_Face(library, buffer, 0L, facePointer), "Creating Font Face")) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
return null;
|
||||
}
|
||||
FT_Face face = FT_Face.create(facePointer.get());
|
||||
String s = FreeType.FT_Get_Font_Format(face);
|
||||
if(!"TrueType".equals(s)) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
throw new IllegalStateException("Font type ["+s+"] is not true type");
|
||||
}
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Select_Charmap(face, FreeType.FT_ENCODING_UNICODE), "Applying Unicode Encoding")) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
return null;
|
||||
}
|
||||
return LongObjectPair.of(MemoryUtil.memAddress(buffer), face);
|
||||
}
|
||||
catch(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
|
||||
FreeTypeInstance instance = this.instance[style & 0x3];
|
||||
return instance != null ? instance.gylthData(codepoint, size, oversample) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for(int i = 0;i<4;i++) {
|
||||
if(instance[i] != null) {
|
||||
instance[i].free();
|
||||
}
|
||||
}
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public static class FreeTypeGlyth implements UnbakedGlyth {
|
||||
final FT_Face face;
|
||||
final int width;
|
||||
final int height;
|
||||
final float xOff;
|
||||
final float yOff;
|
||||
final float oversample;
|
||||
private final float advance;
|
||||
final int glyth;
|
||||
final int glythCodepoint;
|
||||
final long harfBuzzFont;
|
||||
|
||||
public FreeTypeGlyth(FT_Face face, long harfBuzzFont, float xOff, float yOff, int width, int height, float advance, float oversample, int glyth, int glythCodepoint) {
|
||||
this.face = face;
|
||||
this.harfBuzzFont = harfBuzzFont;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.oversample = oversample;
|
||||
this.advance = advance / oversample;
|
||||
this.xOff = xOff / oversample;
|
||||
this.yOff = yOff / oversample;
|
||||
this.glyth = glyth;
|
||||
this.glythCodepoint = glythCodepoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float advance() {
|
||||
return advance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float kerning(int codepoint) {
|
||||
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||
if(index == 0) return 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(Character.toChars(codepoint));
|
||||
builder.append(Character.toChars(glythCodepoint));
|
||||
float hbresult = (getAdvance(Character.toString(codepoint)) - getAdvance(builder.toString())) / 64F;
|
||||
return hbresult;
|
||||
}
|
||||
|
||||
private float getAdvance(String adv) {
|
||||
long id = HarfBuzz.hb_buffer_create();
|
||||
try {
|
||||
HarfBuzz.hb_buffer_add_utf8(id, adv, 0, adv.length());
|
||||
HarfBuzz.hb_buffer_guess_segment_properties(id);
|
||||
HarfBuzz.hb_shape(harfBuzzFont, id, null);
|
||||
hb_glyph_position_t.Buffer positions = HarfBuzz.hb_buffer_get_glyph_positions(id);
|
||||
float result = positions.hasRemaining() ? positions.x_advance() : 0F;
|
||||
HarfBuzz.hb_buffer_destroy(positions.address());
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
HarfBuzz.hb_buffer_destroy(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Glyth bake(GlythBaker baker) {
|
||||
return baker.bake(new IGlythSheetInfo() {
|
||||
@Override
|
||||
public float xOffset() { return xOff; }
|
||||
@Override
|
||||
public float yOffset() { return yOff; }
|
||||
@Override
|
||||
public int width() { return width; }
|
||||
@Override
|
||||
public int height() { return height; }
|
||||
@Override
|
||||
public float oversample() { return oversample; }
|
||||
@Override
|
||||
public void upload(int texture, int x, int y) {
|
||||
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
||||
if(drawable.drawFont(face, glyth)) {
|
||||
drawable.upload(texture, x, y, 0, 0, width, height);
|
||||
}
|
||||
drawable.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isColored() { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FreeTypeInstance {
|
||||
final int style;
|
||||
long data;
|
||||
final FT_Face face;
|
||||
IntSet skip = new IntOpenHashSet();
|
||||
final float oversample;
|
||||
final float xOff;
|
||||
final float yOff;
|
||||
final float shadowOffset;
|
||||
final long harfBuzzFont;
|
||||
|
||||
public FreeTypeInstance(int style, long data, FT_Face face, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
||||
this.style = style;
|
||||
this.data = data;
|
||||
this.face = face;
|
||||
this.harfBuzzFont = HarfBuzz.hb_ft_font_create_referenced(face.address());
|
||||
skip.codePoints().forEach(this.skip::add);
|
||||
this.oversample = oversample;
|
||||
this.xOff = xOff;
|
||||
this.yOff = yOff;
|
||||
this.shadowOffset = shadowOffset;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||
FT_Vector ft_vector = FT_Vector.malloc(stack).set(Math.round(oversample * xOff * 64F), Math.round(oversample * -yOff * 64F));
|
||||
FreeType.FT_Set_Transform(face, null, ft_vector);
|
||||
}
|
||||
}
|
||||
|
||||
public void free() {
|
||||
if(data == 0L) return;
|
||||
FreeType.FT_Done_Face(face);
|
||||
MemoryUtil.nmemFree(data);
|
||||
data = 0L;
|
||||
}
|
||||
|
||||
public UnbakedGlyth gylthData(int codepoint, float size, float oversample) {
|
||||
if(skip.contains(codepoint)) return null;
|
||||
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||
if(index == 0) return null;
|
||||
oversample *= this.oversample;
|
||||
int pixels = Math.round(size * oversample);
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Set_Pixel_Sizes(face, 0, pixels), "Set Pixel Size")) return null;
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Load_Glyph(face, index, FreeType.FT_LOAD_NO_BITMAP | FreeType.FT_LOAD_BITMAP_METRICS_ONLY), "Loading Glyth")) return null;
|
||||
FT_GlyphSlot slot = face.glyph();
|
||||
if(slot == null) {
|
||||
System.out.println("Glyth didn't load for some reason");
|
||||
return null;
|
||||
}
|
||||
float advance = slot.advance().x() / 64F;
|
||||
FT_Bitmap bitmap = slot.bitmap();
|
||||
|
||||
int left = slot.bitmap_left();
|
||||
int top = slot.bitmap_top();
|
||||
int width = bitmap.width();
|
||||
int height = bitmap.rows();
|
||||
if(width > 0 && height > 0) return new FreeTypeGlyth(face, harfBuzzFont, left, -top, width, height, advance, oversample, index, codepoint);
|
||||
return new EmptyGlythData(advance / oversample);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FreeTypeLibrary {
|
||||
private static long pointer = 0L;
|
||||
|
||||
public static long get() {
|
||||
if(pointer == 0L) {
|
||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||
PointerBuffer pointBuffer = stack.callocPointer(1);
|
||||
int result = FreeType.FT_Init_FreeType(pointBuffer);
|
||||
if(result != 0) {
|
||||
throw new IllegalStateException(FreeType.FT_Error_String(result));
|
||||
}
|
||||
pointer = pointBuffer.get();
|
||||
}
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public static boolean parseError(int result, String action) {
|
||||
if(result == 0) return false;
|
||||
String error = FreeType.FT_Error_String(result);
|
||||
System.out.println("Couldn't do ["+action+"] because of "+error);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
if(pointer == 0L) return;
|
||||
FreeType.FT_Done_Library(pointer);
|
||||
pointer = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.gui.font.providers;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.PointerBuffer;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.lwjgl.util.freetype.FT_Bitmap;
|
||||
import org.lwjgl.util.freetype.FT_Face;
|
||||
import org.lwjgl.util.freetype.FT_GlyphSlot;
|
||||
import org.lwjgl.util.freetype.FT_Vector;
|
||||
import org.lwjgl.util.freetype.FreeType;
|
||||
import org.lwjgl.util.harfbuzz.HarfBuzz;
|
||||
import org.lwjgl.util.harfbuzz.hb_glyph_position_t;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
||||
import speiger.src.collections.ints.sets.IntSet;
|
||||
import speiger.src.collections.longs.misc.pairs.LongObjectPair;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.assets.parsers.NativeMemoryParser;
|
||||
import speiger.src.coreengine.rendering.gui.font.FontTexture;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.Glyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.IGlythSheetInfo;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth;
|
||||
import speiger.src.coreengine.rendering.gui.font.glyth.UnbakedGlyth.EmptyGlythData;
|
||||
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class FreeTypeProvider implements IFontProvider {
|
||||
|
||||
FreeTypeInstance[] instance;
|
||||
|
||||
public FreeTypeProvider(FreeTypeInstance[] instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public static IFontProvider create(AssetLocation location, IAssetProvider provider) {
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
return load(asset.json(), provider);
|
||||
}
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IFontProvider load(JsonObject data, IAssetProvider provider) {
|
||||
long library = FreeTypeLibrary.get();
|
||||
if(library == 0L) return null;
|
||||
FreeTypeInstance[] instances = new FreeTypeInstance[4];
|
||||
instances[0] = create(library, 0, data.getAsJsonObject("regular"), provider);
|
||||
if(instances[0] == null) return null;
|
||||
instances[1] = create(library, 1, data.getAsJsonObject("bold"), provider);
|
||||
instances[2] = create(library, 2, data.getAsJsonObject("italic"), provider);
|
||||
instances[3] = create(library, 3, data.getAsJsonObject("bold_italic"), provider);
|
||||
return new FreeTypeProvider(instances);
|
||||
}
|
||||
|
||||
private static FreeTypeInstance create(long library, int style, JsonObject obj, IAssetProvider provider) {
|
||||
if(obj == null || !obj.has("file")) return null;
|
||||
AssetLocation location = AssetLocation.of(obj.get("file").getAsString());
|
||||
float oversample = JsonUtil.getOrDefault(obj, "oversample", 1F);
|
||||
float shadowOffset = JsonUtil.getOrDefault(obj, "shadowOffset", 1F);
|
||||
float xOff = 0;
|
||||
float yOff = 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
JsonObject shift = obj.getAsJsonObject("offset");
|
||||
if(shift != null) {
|
||||
xOff = JsonUtil.getOrDefault(shift, "x", 0F);
|
||||
yOff = JsonUtil.getOrDefault(shift, "y", 0F);
|
||||
}
|
||||
JsonUtil.iterateValues(obj.get("skip"), T -> builder.append(T.getAsString()));
|
||||
LongObjectPair<FT_Face> value = parse(location, provider, library);
|
||||
if(value == null) return null;
|
||||
return new FreeTypeInstance(style, value.getLongKey(), value.getValue(), oversample, xOff, yOff, shadowOffset, builder.toString());
|
||||
}
|
||||
|
||||
private static LongObjectPair<FT_Face> parse(AssetLocation location, IAssetProvider provider, long library) {
|
||||
try(IAsset asset = provider.getAsset(location); MemoryStack stack = MemoryStack.stackPush()) {
|
||||
ByteBuffer buffer = asset.custom(NativeMemoryParser.INSTANCE);
|
||||
PointerBuffer facePointer = stack.mallocPointer(1);
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_New_Memory_Face(library, buffer, 0L, facePointer), "Creating Font Face")) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
return null;
|
||||
}
|
||||
FT_Face face = FT_Face.create(facePointer.get());
|
||||
String s = FreeType.FT_Get_Font_Format(face);
|
||||
if(!"TrueType".equals(s)) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
throw new IllegalStateException("Font type ["+s+"] is not true type");
|
||||
}
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Select_Charmap(face, FreeType.FT_ENCODING_UNICODE), "Applying Unicode Encoding")) {
|
||||
MemoryUtil.memFree(buffer);
|
||||
return null;
|
||||
}
|
||||
return LongObjectPair.of(MemoryUtil.memAddress(buffer), face);
|
||||
}
|
||||
catch(Exception exception) {
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedGlyth glythData(int codepoint, int style, float size, float oversample) {
|
||||
FreeTypeInstance instance = this.instance[style & 0x3];
|
||||
return instance != null ? instance.gylthData(codepoint, size, oversample) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for(int i = 0;i<4;i++) {
|
||||
if(instance[i] != null) {
|
||||
instance[i].free();
|
||||
}
|
||||
}
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public static class FreeTypeGlyth implements UnbakedGlyth {
|
||||
final FT_Face face;
|
||||
final int width;
|
||||
final int height;
|
||||
final float xOff;
|
||||
final float yOff;
|
||||
final float oversample;
|
||||
private final float advance;
|
||||
final int glyth;
|
||||
final int glythCodepoint;
|
||||
final long harfBuzzFont;
|
||||
|
||||
public FreeTypeGlyth(FT_Face face, long harfBuzzFont, float xOff, float yOff, int width, int height, float advance, float oversample, int glyth, int glythCodepoint) {
|
||||
this.face = face;
|
||||
this.harfBuzzFont = harfBuzzFont;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.oversample = oversample;
|
||||
this.advance = advance / oversample;
|
||||
this.xOff = xOff / oversample;
|
||||
this.yOff = yOff / oversample;
|
||||
this.glyth = glyth;
|
||||
this.glythCodepoint = glythCodepoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float advance() {
|
||||
return advance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float kerning(int codepoint) {
|
||||
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||
if(index == 0) return 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(Character.toChars(codepoint));
|
||||
builder.append(Character.toChars(glythCodepoint));
|
||||
float hbresult = (getAdvance(Character.toString(codepoint)) - getAdvance(builder.toString())) / 64F;
|
||||
return hbresult;
|
||||
}
|
||||
|
||||
private float getAdvance(String adv) {
|
||||
long id = HarfBuzz.hb_buffer_create();
|
||||
try {
|
||||
HarfBuzz.hb_buffer_add_utf8(id, adv, 0, adv.length());
|
||||
HarfBuzz.hb_buffer_guess_segment_properties(id);
|
||||
HarfBuzz.hb_shape(harfBuzzFont, id, null);
|
||||
hb_glyph_position_t.Buffer positions = HarfBuzz.hb_buffer_get_glyph_positions(id);
|
||||
float result = positions.hasRemaining() ? positions.x_advance() : 0F;
|
||||
HarfBuzz.hb_buffer_destroy(positions.address());
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
HarfBuzz.hb_buffer_destroy(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Glyth bake(GlythBaker baker) {
|
||||
return baker.bake(new IGlythSheetInfo() {
|
||||
@Override
|
||||
public float xOffset() { return xOff; }
|
||||
@Override
|
||||
public float yOffset() { return yOff; }
|
||||
@Override
|
||||
public int width() { return width; }
|
||||
@Override
|
||||
public int height() { return height; }
|
||||
@Override
|
||||
public float oversample() { return oversample; }
|
||||
@Override
|
||||
public void upload(int texture, int x, int y) {
|
||||
Drawable drawable = new Drawable(FontTexture.formatByColor(false), width, height);
|
||||
if(drawable.drawFont(face, glyth)) {
|
||||
drawable.upload(texture, x, y, 0, 0, width, height);
|
||||
}
|
||||
drawable.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isColored() { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FreeTypeInstance {
|
||||
final int style;
|
||||
long data;
|
||||
final FT_Face face;
|
||||
IntSet skip = new IntOpenHashSet();
|
||||
final float oversample;
|
||||
final float xOff;
|
||||
final float yOff;
|
||||
final float shadowOffset;
|
||||
final long harfBuzzFont;
|
||||
|
||||
public FreeTypeInstance(int style, long data, FT_Face face, float oversample, float xOff, float yOff, float shadowOffset, String skip) {
|
||||
this.style = style;
|
||||
this.data = data;
|
||||
this.face = face;
|
||||
this.harfBuzzFont = HarfBuzz.hb_ft_font_create_referenced(face.address());
|
||||
skip.codePoints().forEach(this.skip::add);
|
||||
this.oversample = oversample;
|
||||
this.xOff = xOff;
|
||||
this.yOff = yOff;
|
||||
this.shadowOffset = shadowOffset;
|
||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||
FT_Vector ft_vector = FT_Vector.malloc(stack).set(Math.round(oversample * xOff * 64F), Math.round(oversample * -yOff * 64F));
|
||||
FreeType.FT_Set_Transform(face, null, ft_vector);
|
||||
}
|
||||
}
|
||||
|
||||
public void free() {
|
||||
if(data == 0L) return;
|
||||
FreeType.FT_Done_Face(face);
|
||||
MemoryUtil.nmemFree(data);
|
||||
data = 0L;
|
||||
}
|
||||
|
||||
public UnbakedGlyth gylthData(int codepoint, float size, float oversample) {
|
||||
if(skip.contains(codepoint)) return null;
|
||||
int index = FreeType.FT_Get_Char_Index(face, codepoint);
|
||||
if(index == 0) return null;
|
||||
oversample *= this.oversample;
|
||||
int pixels = Math.round(size * oversample);
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Set_Pixel_Sizes(face, 0, pixels), "Set Pixel Size")) return null;
|
||||
if(FreeTypeLibrary.parseError(FreeType.FT_Load_Glyph(face, index, FreeType.FT_LOAD_NO_BITMAP | FreeType.FT_LOAD_BITMAP_METRICS_ONLY), "Loading Glyth")) return null;
|
||||
FT_GlyphSlot slot = face.glyph();
|
||||
if(slot == null) {
|
||||
System.out.println("Glyth didn't load for some reason");
|
||||
return null;
|
||||
}
|
||||
float advance = slot.advance().x() / 64F;
|
||||
FT_Bitmap bitmap = slot.bitmap();
|
||||
|
||||
int left = slot.bitmap_left();
|
||||
int top = slot.bitmap_top();
|
||||
int width = bitmap.width();
|
||||
int height = bitmap.rows();
|
||||
if(width > 0 && height > 0) return new FreeTypeGlyth(face, harfBuzzFont, left, -top, width, height, advance, oversample, index, codepoint);
|
||||
return new EmptyGlythData(advance / oversample);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FreeTypeLibrary {
|
||||
private static long pointer = 0L;
|
||||
|
||||
public static long get() {
|
||||
if(pointer == 0L) {
|
||||
try(MemoryStack stack = MemoryStack.stackPush()) {
|
||||
PointerBuffer pointBuffer = stack.callocPointer(1);
|
||||
int result = FreeType.FT_Init_FreeType(pointBuffer);
|
||||
if(result != 0) {
|
||||
throw new IllegalStateException(FreeType.FT_Error_String(result));
|
||||
}
|
||||
pointer = pointBuffer.get();
|
||||
}
|
||||
}
|
||||
return pointer;
|
||||
}
|
||||
|
||||
public static boolean parseError(int result, String action) {
|
||||
if(result == 0) return false;
|
||||
String error = FreeType.FT_Error_String(result);
|
||||
System.out.println("Couldn't do ["+action+"] because of "+error);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void close() {
|
||||
if(pointer == 0L) return;
|
||||
FreeType.FT_Done_Library(pointer);
|
||||
pointer = 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
+214
-214
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+333
-333
@@ -1,334 +1,334 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.components;
|
||||
|
||||
import speiger.src.collections.floats.functions.FloatSupplier;
|
||||
import speiger.src.collections.objects.functions.function.ToFloatFunction;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
|
||||
public class SingleTabPanelComponent extends PanelComponent
|
||||
{
|
||||
PanelComponent selection = new PanelComponent();
|
||||
PanelComponent panel = new PanelComponent().setScissors(true);
|
||||
ObjectList<Tab> tabs = new ObjectArrayList<>();
|
||||
int selectedTab = -1;
|
||||
float tabScale = 1F;
|
||||
|
||||
Facing facing;
|
||||
int backgroundColor = ColorUtils.GRAY;
|
||||
int unselectedColor = ColorUtils.GRAY;
|
||||
int selectedColor = ColorUtils.DARK_GRAY;
|
||||
float padding = 30F;
|
||||
|
||||
public SingleTabPanelComponent()
|
||||
{
|
||||
this(Facing.NORTH);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(Facing facing)
|
||||
{
|
||||
this(0F, 0F, 0F, 0F, facing);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(float x, float y, float width, float height)
|
||||
{
|
||||
this(x, y, width, height, Facing.NORTH);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(float x, float y, float width, float height, Facing facing)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent setFacing(Facing facing)
|
||||
{
|
||||
this.facing = facing;
|
||||
updateConstrains(selection, createView());
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
|
||||
}
|
||||
updateConstrains(panel, createPanel());
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent setPadding(float padding)
|
||||
{
|
||||
this.padding = padding;
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
tab.updatePadding();
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent addTab(String name)
|
||||
{
|
||||
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
|
||||
tabs.add(newTab);
|
||||
if(selectedTab == -1) {
|
||||
selectedTab = tabs.size()-1;
|
||||
}
|
||||
newTab.onAction(() -> selectTab(newTab));
|
||||
selection.addChild(newTab, createConstraint(newTab));
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Facing getFacing()
|
||||
{
|
||||
return facing;
|
||||
}
|
||||
|
||||
public int findTab(String name)
|
||||
{
|
||||
for(int i = 0,m=tabs.size();i<m;i++) {
|
||||
if(tabs.get(i).name.equals(name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getActiveIndex()
|
||||
{
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
public PanelComponent getPanel()
|
||||
{
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
getRenderer().drawQuad(selection.getBox(), backgroundColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(selection, createView());
|
||||
addChild(panel, createPanel());
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
if(facing.isZAxis())
|
||||
{
|
||||
float room = getBox().getBaseWidth();
|
||||
float requiredSpace = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
float width = tab.getWidth() * tab.getTextScale();
|
||||
if(i == selectedTab) room -= width;
|
||||
else requiredSpace += width;
|
||||
}
|
||||
tabScale = Math.min(1F, room / requiredSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabScale = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
|
||||
}
|
||||
tabScale *= getBox().getScale();
|
||||
tabScale += 1F;
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createView()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createPanel()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
|
||||
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
|
||||
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createConstraint(Tab tab)
|
||||
{
|
||||
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
|
||||
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
}
|
||||
|
||||
protected void selectTab(Tab tab)
|
||||
{
|
||||
if(selectTab(tabs.indexOf(tab)))
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean selectTab(int index)
|
||||
{
|
||||
if(index < 0 || index >= tabs.size()) return false;
|
||||
if(selectedTab == index) return false;
|
||||
selectedTab = index;
|
||||
onChanged(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected float getOffset(Tab tab)
|
||||
{
|
||||
int index = tabs.indexOf(tab);
|
||||
float offset = 0F;
|
||||
for(int i = 0;i<index;i++)
|
||||
{
|
||||
Tab entry = tabs.get(i);
|
||||
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
|
||||
else offset += tab.getBox().getBaseHeight();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected float getPanelOffset()
|
||||
{
|
||||
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getPanelWidth()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getXOffset()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getWidth(Tab tab)
|
||||
{
|
||||
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
|
||||
}
|
||||
|
||||
private static class DynamicTab implements FloatSupplier
|
||||
{
|
||||
Tab tab;
|
||||
ToFloatFunction<Tab> function;
|
||||
|
||||
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
|
||||
{
|
||||
this.tab = tab;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAsFloat()
|
||||
{
|
||||
return function.applyAsFloat(tab);
|
||||
}
|
||||
}
|
||||
|
||||
private class Tab extends GuiComponent implements IButtonComponent
|
||||
{
|
||||
String name;
|
||||
float width = -1F;
|
||||
TextComponent comp;
|
||||
|
||||
public Tab(String name)
|
||||
{
|
||||
super(0F, 0F, 100F, 7.5F);
|
||||
this.name = name;
|
||||
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
|
||||
setFlag(FLAG_SUPPORT_BINDING);
|
||||
}
|
||||
|
||||
public Tab align(Align align)
|
||||
{
|
||||
comp.horizontal(align);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void updatePadding()
|
||||
{
|
||||
if(getGui() != null) width = getFont().width(name)+padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(comp, Constrains.parent());
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
public float getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getTextScale()
|
||||
{
|
||||
return comp.getTextScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
String s = name;
|
||||
float scale = comp.getTextScale();
|
||||
float width = (this.width-padding)*scale;
|
||||
float desiredWidth = getBox().getBaseWidth();
|
||||
if(width > desiredWidth) {
|
||||
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
|
||||
s = s.substring(0, s.length()-1);
|
||||
}
|
||||
comp.setText(s+"...");
|
||||
return;
|
||||
}
|
||||
comp.setText(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
boolean notSelected = tabs.indexOf(this) != selectedTab;
|
||||
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
|
||||
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int button, int mouseX, int mouseY)
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUserKey()
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.components;
|
||||
|
||||
import speiger.src.collections.floats.functions.FloatSupplier;
|
||||
import speiger.src.collections.objects.functions.function.ToFloatFunction;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
|
||||
|
||||
public class SingleTabPanelComponent extends PanelComponent
|
||||
{
|
||||
PanelComponent selection = new PanelComponent();
|
||||
PanelComponent panel = new PanelComponent().setScissors(true);
|
||||
ObjectList<Tab> tabs = new ObjectArrayList<>();
|
||||
int selectedTab = -1;
|
||||
float tabScale = 1F;
|
||||
|
||||
Facing facing;
|
||||
int backgroundColor = ColorUtils.GRAY;
|
||||
int unselectedColor = ColorUtils.GRAY;
|
||||
int selectedColor = ColorUtils.DARK_GRAY;
|
||||
float padding = 30F;
|
||||
|
||||
public SingleTabPanelComponent()
|
||||
{
|
||||
this(Facing.NORTH);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(Facing facing)
|
||||
{
|
||||
this(0F, 0F, 0F, 0F, facing);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(float x, float y, float width, float height)
|
||||
{
|
||||
this(x, y, width, height, Facing.NORTH);
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent(float x, float y, float width, float height, Facing facing)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent setFacing(Facing facing)
|
||||
{
|
||||
this.facing = facing;
|
||||
updateConstrains(selection, createView());
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
|
||||
}
|
||||
updateConstrains(panel, createPanel());
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent setPadding(float padding)
|
||||
{
|
||||
this.padding = padding;
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
tab.updatePadding();
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleTabPanelComponent addTab(String name)
|
||||
{
|
||||
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
|
||||
tabs.add(newTab);
|
||||
if(selectedTab == -1) {
|
||||
selectedTab = tabs.size()-1;
|
||||
}
|
||||
newTab.onAction(() -> selectTab(newTab));
|
||||
selection.addChild(newTab, createConstraint(newTab));
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Facing getFacing()
|
||||
{
|
||||
return facing;
|
||||
}
|
||||
|
||||
public int findTab(String name)
|
||||
{
|
||||
for(int i = 0,m=tabs.size();i<m;i++) {
|
||||
if(tabs.get(i).name.equals(name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getActiveIndex()
|
||||
{
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
public PanelComponent getPanel()
|
||||
{
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
getRenderer().drawQuad(selection.getBox(), backgroundColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(selection, createView());
|
||||
addChild(panel, createPanel());
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
if(facing.isZAxis())
|
||||
{
|
||||
float room = getBox().getBaseWidth();
|
||||
float requiredSpace = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
float width = tab.getWidth() * tab.getTextScale();
|
||||
if(i == selectedTab) room -= width;
|
||||
else requiredSpace += width;
|
||||
}
|
||||
tabScale = Math.min(1F, room / requiredSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabScale = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
|
||||
}
|
||||
tabScale *= getBox().getScale();
|
||||
tabScale += 1F;
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createView()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createPanel()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
|
||||
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
|
||||
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createConstraint(Tab tab)
|
||||
{
|
||||
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
|
||||
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
}
|
||||
|
||||
protected void selectTab(Tab tab)
|
||||
{
|
||||
if(selectTab(tabs.indexOf(tab)))
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean selectTab(int index)
|
||||
{
|
||||
if(index < 0 || index >= tabs.size()) return false;
|
||||
if(selectedTab == index) return false;
|
||||
selectedTab = index;
|
||||
onChanged(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected float getOffset(Tab tab)
|
||||
{
|
||||
int index = tabs.indexOf(tab);
|
||||
float offset = 0F;
|
||||
for(int i = 0;i<index;i++)
|
||||
{
|
||||
Tab entry = tabs.get(i);
|
||||
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
|
||||
else offset += tab.getBox().getBaseHeight();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected float getPanelOffset()
|
||||
{
|
||||
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getPanelWidth()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getXOffset()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getWidth(Tab tab)
|
||||
{
|
||||
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
|
||||
}
|
||||
|
||||
private static class DynamicTab implements FloatSupplier
|
||||
{
|
||||
Tab tab;
|
||||
ToFloatFunction<Tab> function;
|
||||
|
||||
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
|
||||
{
|
||||
this.tab = tab;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAsFloat()
|
||||
{
|
||||
return function.applyAsFloat(tab);
|
||||
}
|
||||
}
|
||||
|
||||
private class Tab extends GuiComponent implements IButtonComponent
|
||||
{
|
||||
String name;
|
||||
float width = -1F;
|
||||
TextComponent comp;
|
||||
|
||||
public Tab(String name)
|
||||
{
|
||||
super(0F, 0F, 100F, 7.5F);
|
||||
this.name = name;
|
||||
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
|
||||
setFlag(FLAG_SUPPORT_BINDING);
|
||||
}
|
||||
|
||||
public Tab align(Align align)
|
||||
{
|
||||
comp.horizontal(align);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void updatePadding()
|
||||
{
|
||||
if(getGui() != null) width = getFont().width(name)+padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(comp, Constrains.parent());
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
public float getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getTextScale()
|
||||
{
|
||||
return comp.getTextScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
String s = name;
|
||||
float scale = comp.getTextScale();
|
||||
float width = (this.width-padding)*scale;
|
||||
float desiredWidth = getBox().getBaseWidth();
|
||||
if(width > desiredWidth) {
|
||||
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
|
||||
s = s.substring(0, s.length()-1);
|
||||
}
|
||||
comp.setText(s+"...");
|
||||
return;
|
||||
}
|
||||
comp.setText(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
boolean notSelected = tabs.indexOf(this) != selectedTab;
|
||||
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
|
||||
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int button, int mouseX, int mouseY)
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUserKey()
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+338
-338
@@ -1,339 +1,339 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.components;
|
||||
|
||||
import speiger.src.collections.floats.functions.FloatSupplier;
|
||||
import speiger.src.collections.objects.functions.function.ToFloatFunction;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
|
||||
public class TabbedPanelComponent extends PanelComponent
|
||||
{
|
||||
PanelComponent selection = new PanelComponent();
|
||||
ObjectList<Tab> tabs = new ObjectArrayList<>();
|
||||
int selectedTab = -1;
|
||||
float tabScale = 1F;
|
||||
|
||||
Facing facing;
|
||||
int backgroundColor = ColorUtils.GRAY;
|
||||
int unselectedColor = ColorUtils.GRAY;
|
||||
int selectedColor = ColorUtils.DARK_GRAY;
|
||||
float padding = 30F;
|
||||
|
||||
public TabbedPanelComponent()
|
||||
{
|
||||
this(Facing.NORTH);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(Facing facing)
|
||||
{
|
||||
this(0F, 0F, 0F, 0F, facing);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(float x, float y, float width, float height)
|
||||
{
|
||||
this(x, y, width, height, Facing.NORTH);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(float x, float y, float width, float height, Facing facing)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
public TabbedPanelComponent setFacing(Facing facing)
|
||||
{
|
||||
this.facing = facing;
|
||||
updateConstrains(selection, createView());
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
|
||||
updateConstrains(tab.getPanel(), createPanel());
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabbedPanelComponent setPadding(float padding)
|
||||
{
|
||||
this.padding = padding;
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
tab.updatePadding();
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Facing getFacing()
|
||||
{
|
||||
return facing;
|
||||
}
|
||||
|
||||
public PanelComponent addTab(String name)
|
||||
{
|
||||
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
|
||||
tabs.add(newTab);
|
||||
if(selectedTab == -1) {
|
||||
selectedTab = tabs.size()-1;
|
||||
newTab.getPanel().setVisible(true);
|
||||
}
|
||||
newTab.onAction(() -> selectTab(newTab));
|
||||
selection.addChild(newTab, createConstraint(newTab));
|
||||
addChild(newTab.getPanel(), createPanel());
|
||||
onChanged(true);
|
||||
return newTab.getPanel();
|
||||
}
|
||||
|
||||
public int findTab(String name)
|
||||
{
|
||||
for(int i = 0,m=tabs.size();i<m;i++) {
|
||||
if(tabs.get(i).name.equals(name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getActiveIndex()
|
||||
{
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
public PanelComponent getActiveTab()
|
||||
{
|
||||
return selectedTab == -1 ? null : tabs.get(selectedTab).getPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
getRenderer().drawQuad(selection.getBox(), backgroundColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(selection, createView());
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
if(facing.isZAxis())
|
||||
{
|
||||
float room = getBox().getBaseWidth();
|
||||
float requiredSpace = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
float width = tab.getWidth() * tab.getTextScale();
|
||||
if(i == selectedTab) room -= width;
|
||||
else requiredSpace += width;
|
||||
}
|
||||
tabScale = Math.min(1F, room / requiredSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabScale = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
|
||||
}
|
||||
tabScale *= getBox().getScale();
|
||||
tabScale += 1F;
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createView()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createPanel()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
|
||||
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
|
||||
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createConstraint(Tab tab)
|
||||
{
|
||||
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
|
||||
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
}
|
||||
|
||||
protected void selectTab(Tab tab)
|
||||
{
|
||||
selectTab(tabs.indexOf(tab));
|
||||
}
|
||||
|
||||
public boolean selectTab(int index)
|
||||
{
|
||||
if(index < 0 || index >= tabs.size()) return false;
|
||||
if(selectedTab == index) return false;
|
||||
if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false);
|
||||
selectedTab = index;
|
||||
tabs.get(selectedTab).getPanel().setVisible(true);
|
||||
onChanged(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected float getOffset(Tab tab)
|
||||
{
|
||||
int index = tabs.indexOf(tab);
|
||||
float offset = 0F;
|
||||
for(int i = 0;i<index;i++)
|
||||
{
|
||||
Tab entry = tabs.get(i);
|
||||
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
|
||||
else offset += tab.getBox().getBaseHeight();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected float getPanelOffset()
|
||||
{
|
||||
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getPanelWidth()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getXOffset()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getWidth(Tab tab)
|
||||
{
|
||||
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
|
||||
}
|
||||
|
||||
private static class DynamicTab implements FloatSupplier
|
||||
{
|
||||
Tab tab;
|
||||
ToFloatFunction<Tab> function;
|
||||
|
||||
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
|
||||
{
|
||||
this.tab = tab;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAsFloat()
|
||||
{
|
||||
return function.applyAsFloat(tab);
|
||||
}
|
||||
}
|
||||
|
||||
private class Tab extends GuiComponent implements IButtonComponent
|
||||
{
|
||||
String name;
|
||||
float width = -1F;
|
||||
TextComponent comp;
|
||||
PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast();
|
||||
|
||||
public Tab(String name)
|
||||
{
|
||||
super(0F, 0F, 100F, 7.5F);
|
||||
this.name = name;
|
||||
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
|
||||
setFlag(FLAG_SUPPORT_BINDING);
|
||||
}
|
||||
|
||||
public Tab align(Align align)
|
||||
{
|
||||
comp.horizontal(align);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void updatePadding()
|
||||
{
|
||||
if(getGui() != null) width = getFont().width(name)+padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(comp, Constrains.parent());
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
public float getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getTextScale()
|
||||
{
|
||||
return comp.getTextScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
String s = name;
|
||||
float scale = comp.getTextScale();
|
||||
float width = (this.width-padding)*scale;
|
||||
float desiredWidth = getBox().getBaseWidth();
|
||||
if(width > desiredWidth) {
|
||||
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
|
||||
s = s.substring(0, s.length()-1);
|
||||
}
|
||||
comp.setText(s+"...");
|
||||
return;
|
||||
}
|
||||
comp.setText(s);
|
||||
}
|
||||
|
||||
public PanelComponent getPanel()
|
||||
{
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
boolean notSelected = tabs.indexOf(this) != selectedTab;
|
||||
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
|
||||
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int button, int mouseX, int mouseY)
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUserKey()
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.components;
|
||||
|
||||
import speiger.src.collections.floats.functions.FloatSupplier;
|
||||
import speiger.src.collections.objects.functions.function.ToFloatFunction;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.lists.ObjectList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
|
||||
|
||||
public class TabbedPanelComponent extends PanelComponent
|
||||
{
|
||||
PanelComponent selection = new PanelComponent();
|
||||
ObjectList<Tab> tabs = new ObjectArrayList<>();
|
||||
int selectedTab = -1;
|
||||
float tabScale = 1F;
|
||||
|
||||
Facing facing;
|
||||
int backgroundColor = ColorUtils.GRAY;
|
||||
int unselectedColor = ColorUtils.GRAY;
|
||||
int selectedColor = ColorUtils.DARK_GRAY;
|
||||
float padding = 30F;
|
||||
|
||||
public TabbedPanelComponent()
|
||||
{
|
||||
this(Facing.NORTH);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(Facing facing)
|
||||
{
|
||||
this(0F, 0F, 0F, 0F, facing);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(float x, float y, float width, float height)
|
||||
{
|
||||
this(x, y, width, height, Facing.NORTH);
|
||||
}
|
||||
|
||||
public TabbedPanelComponent(float x, float y, float width, float height, Facing facing)
|
||||
{
|
||||
super(x, y, width, height);
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
public TabbedPanelComponent setFacing(Facing facing)
|
||||
{
|
||||
this.facing = facing;
|
||||
updateConstrains(selection, createView());
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab));
|
||||
updateConstrains(tab.getPanel(), createPanel());
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabbedPanelComponent setPadding(float padding)
|
||||
{
|
||||
this.padding = padding;
|
||||
for(Tab tab : tabs)
|
||||
{
|
||||
tab.updatePadding();
|
||||
}
|
||||
onChanged(true);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Facing getFacing()
|
||||
{
|
||||
return facing;
|
||||
}
|
||||
|
||||
public PanelComponent addTab(String name)
|
||||
{
|
||||
Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM));
|
||||
tabs.add(newTab);
|
||||
if(selectedTab == -1) {
|
||||
selectedTab = tabs.size()-1;
|
||||
newTab.getPanel().setVisible(true);
|
||||
}
|
||||
newTab.onAction(() -> selectTab(newTab));
|
||||
selection.addChild(newTab, createConstraint(newTab));
|
||||
addChild(newTab.getPanel(), createPanel());
|
||||
onChanged(true);
|
||||
return newTab.getPanel();
|
||||
}
|
||||
|
||||
public int findTab(String name)
|
||||
{
|
||||
for(int i = 0,m=tabs.size();i<m;i++) {
|
||||
if(tabs.get(i).name.equals(name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getActiveIndex()
|
||||
{
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
public PanelComponent getActiveTab()
|
||||
{
|
||||
return selectedTab == -1 ? null : tabs.get(selectedTab).getPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
getRenderer().drawQuad(selection.getBox(), backgroundColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(selection, createView());
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
if(facing.isZAxis())
|
||||
{
|
||||
float room = getBox().getBaseWidth();
|
||||
float requiredSpace = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
float width = tab.getWidth() * tab.getTextScale();
|
||||
if(i == selectedTab) room -= width;
|
||||
else requiredSpace += width;
|
||||
}
|
||||
tabScale = Math.min(1F, room / requiredSpace);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabScale = 0F;
|
||||
for(int i = 0,m=tabs.size();i<m;i++)
|
||||
{
|
||||
Tab tab = tabs.get(i);
|
||||
tabScale = Math.max(tabScale, tab.getWidth() * tab.getTextScale());
|
||||
}
|
||||
tabScale *= getBox().getScale();
|
||||
tabScale += 1F;
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createView()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(Target.X).parent(Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case SOUTH: return Constrains.parent(Target.X).invParent(7.7F, Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
case EAST: return Constrains.xPos(new DynamicConstrain(this::getXOffset).setInverted(true)).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.parent(Target.X).parent(Target.Y).dynamic(this::getPanelWidth, Target.WIDTH).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createPanel()
|
||||
{
|
||||
switch(facing)
|
||||
{
|
||||
case NORTH: return Constrains.parent(0F, 7.2F, 0F, 3.6F);
|
||||
case SOUTH: return Constrains.parent(0F, 0F, 0F, 3.6F);
|
||||
case EAST: return Constrains.parent(Target.X).parent(Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
case WEST: return Constrains.dynamic(this::getXOffset, Target.X).parent(0F, Target.Y).width(new DynamicConstrain(this::getPanelWidth).setInverted(true)).parent(Target.HEIGHT).build();
|
||||
default: return Constrains.parent();
|
||||
}
|
||||
}
|
||||
|
||||
protected Constrains createConstraint(Tab tab)
|
||||
{
|
||||
if(facing.isZAxis()) return Constrains.parent(Target.Y).parent(Target.HEIGHT).dynamic(new DynamicTab(tab, this::getOffset), Target.X).dynamic(new DynamicTab(tab, this::getWidth), Target.WIDTH).build();
|
||||
return Constrains.parent(Target.X).dynamic(new DynamicTab(tab, this::getOffset), Target.Y).parent(Target.WIDTH).height(7.5F).build();
|
||||
}
|
||||
|
||||
protected void selectTab(Tab tab)
|
||||
{
|
||||
selectTab(tabs.indexOf(tab));
|
||||
}
|
||||
|
||||
public boolean selectTab(int index)
|
||||
{
|
||||
if(index < 0 || index >= tabs.size()) return false;
|
||||
if(selectedTab == index) return false;
|
||||
if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false);
|
||||
selectedTab = index;
|
||||
tabs.get(selectedTab).getPanel().setVisible(true);
|
||||
onChanged(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected float getOffset(Tab tab)
|
||||
{
|
||||
int index = tabs.indexOf(tab);
|
||||
float offset = 0F;
|
||||
for(int i = 0;i<index;i++)
|
||||
{
|
||||
Tab entry = tabs.get(i);
|
||||
if(facing.isZAxis()) offset += entry.getWidth() * (i == selectedTab ? 1F : tabScale) * entry.getTextScale();
|
||||
else offset += tab.getBox().getBaseHeight();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
protected float getPanelOffset()
|
||||
{
|
||||
return facing == Facing.EAST ? 0F : tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getPanelWidth()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getXOffset()
|
||||
{
|
||||
return tabScale + 0.25F;
|
||||
}
|
||||
|
||||
protected float getWidth(Tab tab)
|
||||
{
|
||||
return facing.isZAxis() ? tab.getWidth() * (selectedTab == tabs.indexOf(tab) ? 1F : tabScale) * tab.getTextScale() : tabScale;
|
||||
}
|
||||
|
||||
private static class DynamicTab implements FloatSupplier
|
||||
{
|
||||
Tab tab;
|
||||
ToFloatFunction<Tab> function;
|
||||
|
||||
public DynamicTab(Tab tab, ToFloatFunction<Tab> function)
|
||||
{
|
||||
this.tab = tab;
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAsFloat()
|
||||
{
|
||||
return function.applyAsFloat(tab);
|
||||
}
|
||||
}
|
||||
|
||||
private class Tab extends GuiComponent implements IButtonComponent
|
||||
{
|
||||
String name;
|
||||
float width = -1F;
|
||||
TextComponent comp;
|
||||
PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast();
|
||||
|
||||
public Tab(String name)
|
||||
{
|
||||
super(0F, 0F, 100F, 7.5F);
|
||||
this.name = name;
|
||||
comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP);
|
||||
setFlag(FLAG_SUPPORT_BINDING);
|
||||
}
|
||||
|
||||
public Tab align(Align align)
|
||||
{
|
||||
comp.horizontal(align);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void updatePadding()
|
||||
{
|
||||
if(getGui() != null) width = getFont().width(name)+padding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
addChild(comp, Constrains.parent());
|
||||
updatePadding();
|
||||
}
|
||||
|
||||
public float getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public float getTextScale()
|
||||
{
|
||||
return comp.getTextScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void repaint()
|
||||
{
|
||||
String s = name;
|
||||
float scale = comp.getTextScale();
|
||||
float width = (this.width-padding)*scale;
|
||||
float desiredWidth = getBox().getBaseWidth();
|
||||
if(width > desiredWidth) {
|
||||
while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) {
|
||||
s = s.substring(0, s.length()-1);
|
||||
}
|
||||
comp.setText(s+"...");
|
||||
return;
|
||||
}
|
||||
comp.setText(s);
|
||||
}
|
||||
|
||||
public PanelComponent getPanel()
|
||||
{
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
|
||||
{
|
||||
boolean notSelected = tabs.indexOf(this) != selectedTab;
|
||||
getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor);
|
||||
if(notSelected) getRenderer().drawFrame(getBox(), selectedColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRelease(int button, int mouseX, int mouseY)
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onUserKey()
|
||||
{
|
||||
notifyListeners(LISTENER_USER_ACTION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+2
-2
@@ -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]);
|
||||
}
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
+216
-216
@@ -1,216 +1,216 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.components.window.debug;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.ObjIntConsumer;
|
||||
|
||||
import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
|
||||
import speiger.src.collections.ints.queues.IntPriorityQueue;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.math.vector.floats.Vec2f;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.TreeComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.tree.ProfilerTreeEntry;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
import speiger.src.coreengine.utils.profiler.IProfiler;
|
||||
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;
|
||||
|
||||
public class TreeProfilerWindow extends WindowComponent
|
||||
{
|
||||
IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue();
|
||||
ObjIntConsumer<IProfiler> listener = (T, V) -> todoList.enqueue(V);
|
||||
SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast();
|
||||
TreeComponent<ProfilerTreeEntry> tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build());
|
||||
List<ProfilerTab> tabs = new ObjectArrayList<>();
|
||||
int previouseTab = -1;
|
||||
|
||||
|
||||
public TreeProfilerWindow(float x, float y, float width, float height, String name)
|
||||
{
|
||||
super(x, y, width, height, DEFAULT_FLAGS, name);
|
||||
}
|
||||
|
||||
public TreeProfilerWindow addProfiler(IProfiler profiler, String root)
|
||||
{
|
||||
panel.addTab(profiler.getName());
|
||||
tabs.add(new ProfilerTab(profiler, root));
|
||||
if(tabs.size() == 1)
|
||||
{
|
||||
onProfilerChanged();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMoveIntoForground()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2f getMinimumBounds()
|
||||
{
|
||||
return Vec2f.of(100F, 50F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed()
|
||||
{
|
||||
super.onClosed();
|
||||
applyProfiler(false, this::disable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean fixedUpdateSelf()
|
||||
{
|
||||
ProfilerTab entry = getActiveTab();
|
||||
if(entry == null)
|
||||
{
|
||||
todoList.clear();
|
||||
return true;
|
||||
}
|
||||
while(!todoList.isEmpty())
|
||||
{
|
||||
int index = todoList.dequeue();
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
addEntries(entry.getRootEntry());
|
||||
break;
|
||||
case 1:
|
||||
tree.setTree(null);
|
||||
break;
|
||||
case 2:
|
||||
if(tree.getTree() == null)
|
||||
{
|
||||
addEntries(entry.getRootEntry());
|
||||
break;
|
||||
}
|
||||
updateChildren(entry.getRootEntry(), tree.getTree());
|
||||
tree.onTreeChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onProfilerChanged()
|
||||
{
|
||||
if(previouseTab == panel.getActiveIndex()) return;
|
||||
applyProfiler(true, this::disable);
|
||||
applyProfiler(false, this::enable);
|
||||
previouseTab = panel.getActiveIndex();
|
||||
ProfilerTab tab = tabs.get(previouseTab);
|
||||
setCurrentEntry(tab.getRoot());
|
||||
}
|
||||
|
||||
protected void enable(IProfiler profiler)
|
||||
{
|
||||
profiler.enable();
|
||||
profiler.addListener(listener);
|
||||
}
|
||||
|
||||
protected void disable(IProfiler profiler)
|
||||
{
|
||||
profiler.removeListener(listener);
|
||||
profiler.disable();
|
||||
}
|
||||
|
||||
protected void addEntries(IProfilerEntry entry)
|
||||
{
|
||||
if(entry == null) return;
|
||||
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), child);
|
||||
}
|
||||
tree.setTree(child);
|
||||
tree.openAll();
|
||||
}
|
||||
|
||||
public TreeProfilerWindow setCurrentEntry(String name)
|
||||
{
|
||||
addEntries(getActive().getEntry(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void updateChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
|
||||
{
|
||||
if(entry == null || tree == null) return;
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), tree);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
|
||||
{
|
||||
if(entry == null || tree == null) return;
|
||||
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
|
||||
int index = tree.indexOf(child);
|
||||
|
||||
if(index != -1) child = (ProfilerTreeEntry)tree.getChild(index);
|
||||
else tree.addChild(child);
|
||||
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), child);
|
||||
}
|
||||
}
|
||||
|
||||
protected IProfiler getActive()
|
||||
{
|
||||
return tabs.get(panel.getActiveIndex()).getProfiler();
|
||||
}
|
||||
|
||||
protected ProfilerTab getActiveTab()
|
||||
{
|
||||
int index = panel.getActiveIndex();
|
||||
return index < 0 || index >= tabs.size() ? null : tabs.get(index);
|
||||
}
|
||||
|
||||
protected void applyProfiler(boolean prev, Consumer<IProfiler> action)
|
||||
{
|
||||
int index = prev ? previouseTab : panel.getActiveIndex();
|
||||
if(index >= 0) action.accept(tabs.get(index).getProfiler());
|
||||
}
|
||||
|
||||
private static class ProfilerTab
|
||||
{
|
||||
IProfiler profiler;
|
||||
String root;
|
||||
|
||||
public ProfilerTab(IProfiler profiler, String root)
|
||||
{
|
||||
this.profiler = profiler;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public IProfiler getProfiler()
|
||||
{
|
||||
return profiler;
|
||||
}
|
||||
|
||||
public String getRoot()
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
public IProfilerEntry getRootEntry()
|
||||
{
|
||||
return profiler.getEntry(root);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.components.window.debug;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.ObjIntConsumer;
|
||||
|
||||
import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
|
||||
import speiger.src.collections.ints.queues.IntPriorityQueue;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.math.misc.Facing;
|
||||
import speiger.src.coreengine.math.vector.floats.Vec2f;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.TreeComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.tree.ProfilerTreeEntry;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
|
||||
import speiger.src.coreengine.utils.profiler.IProfiler;
|
||||
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;
|
||||
|
||||
public class TreeProfilerWindow extends WindowComponent
|
||||
{
|
||||
IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue();
|
||||
ObjIntConsumer<IProfiler> listener = (_, V) -> todoList.enqueue(V);
|
||||
SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast();
|
||||
TreeComponent<ProfilerTreeEntry> tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build());
|
||||
List<ProfilerTab> tabs = new ObjectArrayList<>();
|
||||
int previouseTab = -1;
|
||||
|
||||
|
||||
public TreeProfilerWindow(float x, float y, float width, float height, String name)
|
||||
{
|
||||
super(x, y, width, height, DEFAULT_FLAGS, name);
|
||||
}
|
||||
|
||||
public TreeProfilerWindow addProfiler(IProfiler profiler, String root)
|
||||
{
|
||||
panel.addTab(profiler.getName());
|
||||
tabs.add(new ProfilerTab(profiler, root));
|
||||
if(tabs.size() == 1)
|
||||
{
|
||||
onProfilerChanged();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMoveIntoForground()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2f getMinimumBounds()
|
||||
{
|
||||
return Vec2f.of(100F, 50F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed()
|
||||
{
|
||||
super.onClosed();
|
||||
applyProfiler(false, this::disable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean fixedUpdateSelf()
|
||||
{
|
||||
ProfilerTab entry = getActiveTab();
|
||||
if(entry == null)
|
||||
{
|
||||
todoList.clear();
|
||||
return true;
|
||||
}
|
||||
while(!todoList.isEmpty())
|
||||
{
|
||||
int index = todoList.dequeue();
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
addEntries(entry.getRootEntry());
|
||||
break;
|
||||
case 1:
|
||||
tree.setTree(null);
|
||||
break;
|
||||
case 2:
|
||||
if(tree.getTree() == null)
|
||||
{
|
||||
addEntries(entry.getRootEntry());
|
||||
break;
|
||||
}
|
||||
updateChildren(entry.getRootEntry(), tree.getTree());
|
||||
tree.onTreeChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void onProfilerChanged()
|
||||
{
|
||||
if(previouseTab == panel.getActiveIndex()) return;
|
||||
applyProfiler(true, this::disable);
|
||||
applyProfiler(false, this::enable);
|
||||
previouseTab = panel.getActiveIndex();
|
||||
ProfilerTab tab = tabs.get(previouseTab);
|
||||
setCurrentEntry(tab.getRoot());
|
||||
}
|
||||
|
||||
protected void enable(IProfiler profiler)
|
||||
{
|
||||
profiler.enable();
|
||||
profiler.addListener(listener);
|
||||
}
|
||||
|
||||
protected void disable(IProfiler profiler)
|
||||
{
|
||||
profiler.removeListener(listener);
|
||||
profiler.disable();
|
||||
}
|
||||
|
||||
protected void addEntries(IProfilerEntry entry)
|
||||
{
|
||||
if(entry == null) return;
|
||||
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), child);
|
||||
}
|
||||
tree.setTree(child);
|
||||
tree.openAll();
|
||||
}
|
||||
|
||||
public TreeProfilerWindow setCurrentEntry(String name)
|
||||
{
|
||||
addEntries(getActive().getEntry(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void updateChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
|
||||
{
|
||||
if(entry == null || tree == null) return;
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), tree);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
|
||||
{
|
||||
if(entry == null || tree == null) return;
|
||||
ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
|
||||
int index = tree.indexOf(child);
|
||||
|
||||
if(index != -1) child = (ProfilerTreeEntry)tree.getChild(index);
|
||||
else tree.addChild(child);
|
||||
|
||||
for(int i = 0,m=entry.getChildCount();i<m;i++)
|
||||
{
|
||||
addChildren(entry.getChild(i), child);
|
||||
}
|
||||
}
|
||||
|
||||
protected IProfiler getActive()
|
||||
{
|
||||
return tabs.get(panel.getActiveIndex()).getProfiler();
|
||||
}
|
||||
|
||||
protected ProfilerTab getActiveTab()
|
||||
{
|
||||
int index = panel.getActiveIndex();
|
||||
return index < 0 || index >= tabs.size() ? null : tabs.get(index);
|
||||
}
|
||||
|
||||
protected void applyProfiler(boolean prev, Consumer<IProfiler> action)
|
||||
{
|
||||
int index = prev ? previouseTab : panel.getActiveIndex();
|
||||
if(index >= 0) action.accept(tabs.get(index).getProfiler());
|
||||
}
|
||||
|
||||
private static class ProfilerTab
|
||||
{
|
||||
IProfiler profiler;
|
||||
String root;
|
||||
|
||||
public ProfilerTab(IProfiler profiler, String root)
|
||||
{
|
||||
this.profiler = profiler;
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
public IProfiler getProfiler()
|
||||
{
|
||||
return profiler;
|
||||
}
|
||||
|
||||
public String getRoot()
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
public IProfilerEntry getRootEntry()
|
||||
{
|
||||
return profiler.getEntry(root);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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());
|
||||
}
|
||||
|
||||
+446
-446
@@ -1,446 +1,446 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import speiger.src.collections.floats.lists.FloatArrayList;
|
||||
import speiger.src.collections.floats.lists.FloatList;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.DelayedRenderBuffer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.TranslatedVertexBuilder;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.Line;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextLexer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext.WordContext;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.provider.IFontProvider;
|
||||
import speiger.src.coreengine.rendering.models.DrawCall;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.IVertexBuilder;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.VertexType;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
|
||||
import speiger.src.coreengine.utils.helpers.TextUtil;
|
||||
|
||||
public class FontRenderer implements IFontRenderer
|
||||
{
|
||||
public static final String INVALID_SEARCH = new String(" §<");
|
||||
public static final int EMPTY = (char)0;
|
||||
public static final int SPACE = ' ';
|
||||
public static final int TAB = '\t';
|
||||
public static final int LINE_SEPERATOR = '\n';
|
||||
Tesselator bufferBuilder = new Tesselator(655340);
|
||||
|
||||
IFontProvider provider;
|
||||
final TextLexer lexer = new TextLexer(this);
|
||||
final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer();
|
||||
|
||||
public void setProvider(IFontProvider provider)
|
||||
{
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharInstance getInstance(int codepoint, boolean isBold)
|
||||
{
|
||||
return provider.getCharacter(codepoint, isBold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height()
|
||||
{
|
||||
return provider.height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float baseLine()
|
||||
{
|
||||
return provider.baseLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITexture getTexture()
|
||||
{
|
||||
return provider.getTexture();
|
||||
}
|
||||
|
||||
public IFontProvider getProvider()
|
||||
{
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void destory()
|
||||
{
|
||||
if(provider != null)
|
||||
{
|
||||
provider.destroy();
|
||||
provider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DrawCall> renderText(String text, float x, float y, float z)
|
||||
{
|
||||
if(text.isEmpty()) return ObjectLists.empty();
|
||||
List<DrawCall> drawCalls = new ObjectArrayList<>();
|
||||
TextContext context = new TextContext(1F, 0);
|
||||
List<Line> lines = lexer.evaluateLines(text, context, Float.MAX_VALUE);
|
||||
if(lines.isEmpty()) return ObjectLists.empty();
|
||||
WordContext effects = context.getEffect();
|
||||
int textColor = effects.color;
|
||||
float yOffset = 0F;
|
||||
IVertexBuilder builder = new TranslatedVertexBuilder(bufferBuilder, x, y, z, 1F);
|
||||
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.IN_WORLD_UI);
|
||||
for(int i = 0,m=lines.size();i<m;i++)
|
||||
{
|
||||
float xOffset = 9F;
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
|
||||
}
|
||||
yOffset += height() * context.getScale();
|
||||
}
|
||||
bufferBuilder.finishData();
|
||||
if(bufferBuilder.getVertexCount() > 0)
|
||||
{
|
||||
drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureId()));
|
||||
}
|
||||
bufferBuilder.setOffset(0F, 0F, 0F);
|
||||
return drawCalls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateText(TextComponent component)
|
||||
{
|
||||
RenderBuffer buffer = component.getBuffer();
|
||||
buffer.clear();
|
||||
if(component.getText().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
TextContext context = new TextContext(component);
|
||||
float boxWidth = component.getBox().getWidth();
|
||||
float boxHeight = component.getBox().getHeight();
|
||||
List<Line> lines = lexer.evaluateLines(component.getText(), context, component.isWidthLimited() ? boxWidth : Float.MAX_VALUE);
|
||||
if(lines.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.UI);
|
||||
int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (height() * context.getScale())), lines.size()) : lines.size();
|
||||
float maxHeight = maxLanes * height() * context.getScale();
|
||||
float maxWidth = 0F;
|
||||
float yOffset = component.getVertical().align(boxHeight, maxHeight);
|
||||
float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth());
|
||||
component.getMetadata().setStart(startX, yOffset);
|
||||
WordContext effects = context.getEffect();
|
||||
while(effects.isNext(0))
|
||||
{
|
||||
effects = effects.next();
|
||||
}
|
||||
int textColor = effects.color;
|
||||
Float strikeThrough = effects.strike_through ? startX : null;
|
||||
Float underline = effects.underline ? startX : -1F;
|
||||
if(component.getBackgroundColor() != null)
|
||||
{
|
||||
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).setOffset(0F, 0F, -0.001F);
|
||||
addBackground(tes, lines, maxLanes, yOffset, component.getHorizontal(), boxWidth, component.getBackgroundColor(), false);
|
||||
tes.setOffset(0F, 0F, 0F);
|
||||
buffer.finishShape(0);
|
||||
}
|
||||
for(int i = 0, index = 0;i < maxLanes;i++)
|
||||
{
|
||||
float xOffset = component.getHorizontal().align(boxWidth, lines.get(i).getWidth());
|
||||
maxWidth = Math.max(maxWidth, lines.get(i).getWidth());
|
||||
strikeThrough = effects.strike_through ? xOffset : null;
|
||||
underline = effects.underline ? xOffset : null;
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, bufferBuilder, false);
|
||||
if(effects.isNext(++index))
|
||||
{
|
||||
WordContext next = effects.next();
|
||||
Float newStrike = getValue(effects.strike_through, next.strike_through, xOffset, strikeThrough);
|
||||
if(newStrike == null && strikeThrough != null)
|
||||
{
|
||||
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
|
||||
}
|
||||
strikeThrough = newStrike;
|
||||
Float newLine = getValue(effects.underline, next.underline, xOffset, strikeThrough);
|
||||
if(newLine == null && underline != null)
|
||||
{
|
||||
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
|
||||
}
|
||||
textColor = next.color;
|
||||
underline = newLine;
|
||||
effects = next;
|
||||
}
|
||||
}
|
||||
if(strikeThrough != null)
|
||||
{
|
||||
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
|
||||
}
|
||||
if(underline != null)
|
||||
{
|
||||
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
|
||||
}
|
||||
yOffset += height() * context.getScale();
|
||||
component.getMetadata().addLine(lines.get(i));
|
||||
}
|
||||
maxWidth /= 2;
|
||||
buffer.finishShape(getTexture().getTextureId(), bufferBuilder);
|
||||
if(lineBuffer.hasData())
|
||||
{
|
||||
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F);
|
||||
lineBuffer.merge(tes);
|
||||
tes.setOffset(0F, 0F, 0F);
|
||||
buffer.finishShape(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected float renderChar(CharInstance instance, float x, float y, float scale, float italic, boolean flipped, int color, IVertexBuilder buffer, boolean flipPos)
|
||||
{
|
||||
switch(instance.getCharacter())
|
||||
{
|
||||
case TAB:
|
||||
return provider.getTabWidth() * scale;
|
||||
case SPACE:
|
||||
return provider.getSpaceWidth() * scale;
|
||||
}
|
||||
if(instance.getXAdvance() <= 0F)
|
||||
{
|
||||
return 0F;
|
||||
}
|
||||
if(flipPos) flipped = !flipped;
|
||||
float minX = x;
|
||||
float minY = y;
|
||||
float maxX = x + (instance.getWidth() * scale);
|
||||
float maxY = flipPos ? y - (instance.getHeight() * scale) : y + (instance.getHeight() * scale);
|
||||
float minV = flipped ? instance.getMaxV() : instance.getMinV();
|
||||
float maxV = flipped ? instance.getMinV() : instance.getMaxV();
|
||||
buffer.pos(minX - italic, maxY, 0F).tex(instance.getMinU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
|
||||
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
|
||||
buffer.pos(maxX + italic, minY, 0F).tex(instance.getMaxU(), minV).color4f(color).endVertex();
|
||||
return instance.getXAdvance() * scale;
|
||||
}
|
||||
|
||||
protected void addBackground(IVertexBuilder tes, List<Line> lines, int maxLines, float yPos, Align align, float width, int color, boolean flipPos)
|
||||
{
|
||||
for(int i = 0;i < maxLines;i++)
|
||||
{
|
||||
float lineWidth = lines.get(i).getWidth();
|
||||
float xOffset = align.align(width, lineWidth);
|
||||
float maxY = flipPos ? yPos - height() : yPos + height();
|
||||
tes.pos(xOffset, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
yPos = maxY;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addUnderline(float xStart, float width, float yStart, int color, IVertexBuilder buffer, boolean flipPos)
|
||||
{
|
||||
float minY = yStart + baseLine() + 0.5F;
|
||||
float maxY = yStart + baseLine() + 1.5F;
|
||||
if(flipPos)
|
||||
{
|
||||
minY = yStart - baseLine() - 0.5F;
|
||||
maxY = yStart - baseLine() - 1.5F;
|
||||
}
|
||||
buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
}
|
||||
|
||||
protected void addStrikeThrough(float xStart, float width, float yStart, int color, IVertexBuilder buffer)
|
||||
{
|
||||
float minY = yStart + height() / 2.0F;
|
||||
float maxY = yStart + height() / 2.0F + 1.4F;
|
||||
buffer.pos(xStart, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
}
|
||||
|
||||
protected Float getValue(boolean oldValue, boolean newValue, Float position, Float oldPosition)
|
||||
{
|
||||
if((position == null && oldPosition == null) || (position != null && oldPosition != null)) return oldPosition;
|
||||
return newValue ? position : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String trimToWidth(String text, float limit, boolean reverse)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
float width = 0F;
|
||||
int start = reverse ? text.length() - 1 : 0;
|
||||
int direction = reverse ? -1 : 1;
|
||||
for(int i = start;i >= 0 && i < text.length() && width < limit;i += direction)
|
||||
{
|
||||
char letter = text.charAt(i);
|
||||
width += width(letter);
|
||||
if(width > limit) break;
|
||||
if(reverse) builder.insert(0, letter);
|
||||
else builder.append(letter);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float width(int codepoint, boolean bold)
|
||||
{
|
||||
switch(codepoint)
|
||||
{
|
||||
case SPACE:
|
||||
return provider.getSpaceWidth();
|
||||
case TAB:
|
||||
return provider.getTabWidth();
|
||||
default:
|
||||
CharInstance instance = getInstance(codepoint, bold);
|
||||
return instance == null ? 0F : instance.getXAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float width(String text, int flags)
|
||||
{
|
||||
float result = 0.0F;
|
||||
float current = 0.0F;
|
||||
boolean bold = (flags & BOLD) != 0;
|
||||
for(int i = 0;i < text.length();i++)
|
||||
{
|
||||
char character = text.charAt(i);
|
||||
if(LINE_SEPERATOR == character)
|
||||
{
|
||||
result = Math.max(result, current += provider.getSpaceWidth());
|
||||
current = 0.0F;
|
||||
continue;
|
||||
}
|
||||
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
|
||||
{
|
||||
String search = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
|
||||
if(search.length() > 0)
|
||||
{
|
||||
for(String entry : search.toLowerCase(Locale.ROOT).split(","))
|
||||
{
|
||||
bold = TextUtil.findFlag(entry, "bold", bold);
|
||||
}
|
||||
i += search.length() + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current += width(character, bold);
|
||||
}
|
||||
return Math.max(result, current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] widths(String text, int flags)
|
||||
{
|
||||
FloatList results = new FloatArrayList();
|
||||
results.add(0F);
|
||||
float current = 0F;
|
||||
int chars = 0;
|
||||
boolean bold = (flags & BOLD) != 0;
|
||||
float max = 0F;
|
||||
for(int i = 0;i < text.length();i++)
|
||||
{
|
||||
char character = text.charAt(i);
|
||||
if(LINE_SEPERATOR == character)
|
||||
{
|
||||
results.add(current);
|
||||
max = Math.max(max, current);
|
||||
current = 0F;
|
||||
chars = 0;
|
||||
continue;
|
||||
}
|
||||
chars++;
|
||||
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
|
||||
{
|
||||
String result = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
|
||||
if(result.length() > 0)
|
||||
{
|
||||
for(String entry : result.toLowerCase(Locale.ROOT).split(","))
|
||||
{
|
||||
bold = TextUtil.findFlag(entry, "bold", bold);
|
||||
}
|
||||
i += result.length() + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current += width(character, bold);
|
||||
}
|
||||
if(chars++ > 0)
|
||||
{
|
||||
results.add(current);
|
||||
max = Math.max(max, current);
|
||||
}
|
||||
results.set(0, max);
|
||||
return results.toFloatArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height(String text, int flags)
|
||||
{
|
||||
return widths(text, flags).length - 1 * height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCharValid(int codepoint)
|
||||
{
|
||||
return provider.isCharacterValid(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] split(String text, float maxWidth, int flags)
|
||||
{
|
||||
TextContext context = new TextContext(1F, ((flags & IFontRenderer.SPECIAL) != 0 ? 16 : 0) | ((flags & IFontRenderer.BOLD) != 0 ? 1 : 0));
|
||||
List<Line> lines = lexer.evaluateLines(text, context, maxWidth);
|
||||
String[] array = new String[lines.size()];
|
||||
if(context.allowsSpecial())
|
||||
{
|
||||
int index = 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
WordContext wordContext = context.getEffect();
|
||||
while(wordContext.isNext(0))
|
||||
{
|
||||
builder.append(wordContext.getString(false));
|
||||
wordContext = wordContext.next();
|
||||
}
|
||||
for(int i = 0,m=lines.size();i<m;i++)
|
||||
{
|
||||
if(i != 0) builder.append(wordContext.getString(true));
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
builder.append(letter.getCharacter());
|
||||
if(wordContext.isNext(++index))
|
||||
{
|
||||
wordContext = wordContext.next();
|
||||
builder.append(wordContext.getString(false));
|
||||
}
|
||||
}
|
||||
array[i] = builder.toString();
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0,m=lines.size();i<m;i++) array[i] = lines.get(i).getText();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import speiger.src.collections.floats.lists.FloatArrayList;
|
||||
import speiger.src.collections.floats.lists.FloatList;
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.rendering.guiOld.components.TextComponent;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.Align;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.DelayedRenderBuffer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.TranslatedVertexBuilder;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.Line;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextContext.WordContext;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.lexer.TextLexer;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.provider.IFontProvider;
|
||||
import speiger.src.coreengine.rendering.models.DrawCall;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.IVertexBuilder;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;
|
||||
import speiger.src.coreengine.rendering.tesselationOld.VertexType;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
|
||||
import speiger.src.coreengine.utils.helpers.TextUtil;
|
||||
|
||||
public class FontRenderer implements IFontRenderer
|
||||
{
|
||||
public static final String INVALID_SEARCH = new String(" §<");
|
||||
public static final int EMPTY = (char)0;
|
||||
public static final int SPACE = ' ';
|
||||
public static final int TAB = '\t';
|
||||
public static final int LINE_SEPERATOR = '\n';
|
||||
Tesselator bufferBuilder = new Tesselator(655340);
|
||||
|
||||
IFontProvider provider;
|
||||
final TextLexer lexer = new TextLexer(this);
|
||||
final DelayedRenderBuffer lineBuffer = new DelayedRenderBuffer();
|
||||
|
||||
public void setProvider(IFontProvider provider)
|
||||
{
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharInstance getInstance(int codepoint, boolean isBold)
|
||||
{
|
||||
return provider.getCharacter(codepoint, isBold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height()
|
||||
{
|
||||
return provider.height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float baseLine()
|
||||
{
|
||||
return provider.baseLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITexture getTexture()
|
||||
{
|
||||
return provider.getTexture();
|
||||
}
|
||||
|
||||
public IFontProvider getProvider()
|
||||
{
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void destory()
|
||||
{
|
||||
if(provider != null)
|
||||
{
|
||||
provider.destroy();
|
||||
provider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DrawCall> renderText(String text, float x, float y, float z)
|
||||
{
|
||||
if(text.isEmpty()) return ObjectLists.empty();
|
||||
List<DrawCall> drawCalls = new ObjectArrayList<>();
|
||||
TextContext context = new TextContext(1F, 0);
|
||||
List<Line> lines = lexer.evaluateLines(text, context, Float.MAX_VALUE);
|
||||
if(lines.isEmpty()) return ObjectLists.empty();
|
||||
WordContext effects = context.getEffect();
|
||||
int textColor = effects.color;
|
||||
float yOffset = 0F;
|
||||
IVertexBuilder builder = new TranslatedVertexBuilder(bufferBuilder, x, y, z, 1F);
|
||||
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.IN_WORLD_UI);
|
||||
for(int i = 0,m=lines.size();i<m;i++)
|
||||
{
|
||||
float xOffset = 9F;
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, builder, true);
|
||||
}
|
||||
yOffset += height() * context.getScale();
|
||||
}
|
||||
bufferBuilder.finishData();
|
||||
if(bufferBuilder.getVertexCount() > 0)
|
||||
{
|
||||
drawCalls.add(bufferBuilder.getDrawCall(getTexture().getTextureId()));
|
||||
}
|
||||
bufferBuilder.setOffset(0F, 0F, 0F);
|
||||
return drawCalls;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateText(TextComponent component)
|
||||
{
|
||||
RenderBuffer buffer = component.getBuffer();
|
||||
buffer.clear();
|
||||
if(component.getText().isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
TextContext context = new TextContext(component);
|
||||
float boxWidth = component.getBox().getWidth();
|
||||
float boxHeight = component.getBox().getHeight();
|
||||
List<Line> lines = lexer.evaluateLines(component.getText(), context, component.isWidthLimited() ? boxWidth : Float.MAX_VALUE);
|
||||
if(lines.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
bufferBuilder.begin(GL11.GL_TRIANGLES, VertexType.UI);
|
||||
int maxLanes = component.isHeightLimited() ? Math.min((int)(boxHeight / (height() * context.getScale())), lines.size()) : lines.size();
|
||||
float maxHeight = maxLanes * height() * context.getScale();
|
||||
float maxWidth = 0F;
|
||||
float yOffset = component.getVertical().align(boxHeight, maxHeight);
|
||||
float startX = component.getHorizontal().align(boxWidth, lines.get(0).getWidth());
|
||||
component.getMetadata().setStart(startX, yOffset);
|
||||
WordContext effects = context.getEffect();
|
||||
while(effects.isNext(0))
|
||||
{
|
||||
effects = effects.next();
|
||||
}
|
||||
int textColor = effects.color;
|
||||
Float strikeThrough = effects.strike_through ? startX : null;
|
||||
Float underline = effects.underline ? startX : -1F;
|
||||
if(component.getBackgroundColor() != null)
|
||||
{
|
||||
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).setOffset(0F, 0F, -0.001F);
|
||||
addBackground(tes, lines, maxLanes, yOffset, component.getHorizontal(), boxWidth, component.getBackgroundColor(), false);
|
||||
tes.setOffset(0F, 0F, 0F);
|
||||
buffer.finishShape(0);
|
||||
}
|
||||
for(int i = 0, index = 0;i < maxLanes;i++)
|
||||
{
|
||||
float xOffset = component.getHorizontal().align(boxWidth, lines.get(i).getWidth());
|
||||
maxWidth = Math.max(maxWidth, lines.get(i).getWidth());
|
||||
strikeThrough = effects.strike_through ? xOffset : null;
|
||||
underline = effects.underline ? xOffset : null;
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
xOffset += renderChar(letter, xOffset, yOffset, context.getScale(), effects.italic, effects.flipped, textColor, bufferBuilder, false);
|
||||
if(effects.isNext(++index))
|
||||
{
|
||||
WordContext next = effects.next();
|
||||
Float newStrike = getValue(effects.strike_through, next.strike_through, xOffset, strikeThrough);
|
||||
if(newStrike == null && strikeThrough != null)
|
||||
{
|
||||
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
|
||||
}
|
||||
strikeThrough = newStrike;
|
||||
Float newLine = getValue(effects.underline, next.underline, xOffset, strikeThrough);
|
||||
if(newLine == null && underline != null)
|
||||
{
|
||||
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
|
||||
}
|
||||
textColor = next.color;
|
||||
underline = newLine;
|
||||
effects = next;
|
||||
}
|
||||
}
|
||||
if(strikeThrough != null)
|
||||
{
|
||||
addStrikeThrough(strikeThrough, xOffset - strikeThrough, yOffset, textColor, lineBuffer);
|
||||
}
|
||||
if(underline != null)
|
||||
{
|
||||
addUnderline(underline, xOffset - underline, yOffset, textColor, lineBuffer, false);
|
||||
}
|
||||
yOffset += height() * context.getScale();
|
||||
component.getMetadata().addLine(lines.get(i));
|
||||
}
|
||||
maxWidth /= 2;
|
||||
buffer.finishShape(getTexture().getTextureId(), bufferBuilder);
|
||||
if(lineBuffer.hasData())
|
||||
{
|
||||
Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).offset(0F, 0F, 0.001F);
|
||||
lineBuffer.merge(tes);
|
||||
tes.setOffset(0F, 0F, 0F);
|
||||
buffer.finishShape(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected float renderChar(CharInstance instance, float x, float y, float scale, float italic, boolean flipped, int color, IVertexBuilder buffer, boolean flipPos)
|
||||
{
|
||||
switch(instance.getCharacter())
|
||||
{
|
||||
case TAB:
|
||||
return provider.getTabWidth() * scale;
|
||||
case SPACE:
|
||||
return provider.getSpaceWidth() * scale;
|
||||
}
|
||||
if(instance.getXAdvance() <= 0F)
|
||||
{
|
||||
return 0F;
|
||||
}
|
||||
if(flipPos) flipped = !flipped;
|
||||
float minX = x;
|
||||
float minY = y;
|
||||
float maxX = x + (instance.getWidth() * scale);
|
||||
float maxY = flipPos ? y - (instance.getHeight() * scale) : y + (instance.getHeight() * scale);
|
||||
float minV = flipped ? instance.getMaxV() : instance.getMinV();
|
||||
float maxV = flipped ? instance.getMinV() : instance.getMaxV();
|
||||
buffer.pos(minX - italic, maxY, 0F).tex(instance.getMinU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
|
||||
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(maxX - italic, maxY, 0F).tex(instance.getMaxU(), maxV).color4f(color).endVertex();
|
||||
buffer.pos(minX + italic, minY, 0F).tex(instance.getMinU(), minV).color4f(color).endVertex();
|
||||
buffer.pos(maxX + italic, minY, 0F).tex(instance.getMaxU(), minV).color4f(color).endVertex();
|
||||
return instance.getXAdvance() * scale;
|
||||
}
|
||||
|
||||
protected void addBackground(IVertexBuilder tes, List<Line> lines, int maxLines, float yPos, Align align, float width, int color, boolean flipPos)
|
||||
{
|
||||
for(int i = 0;i < maxLines;i++)
|
||||
{
|
||||
float lineWidth = lines.get(i).getWidth();
|
||||
float xOffset = align.align(width, lineWidth);
|
||||
float maxY = flipPos ? yPos - height() : yPos + height();
|
||||
tes.pos(xOffset, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
tes.pos(xOffset + lineWidth, yPos, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
yPos = maxY;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addUnderline(float xStart, float width, float yStart, int color, IVertexBuilder buffer, boolean flipPos)
|
||||
{
|
||||
float minY = yStart + baseLine() + 0.5F;
|
||||
float maxY = yStart + baseLine() + 1.5F;
|
||||
if(flipPos)
|
||||
{
|
||||
minY = yStart - baseLine() - 0.5F;
|
||||
maxY = yStart - baseLine() - 1.5F;
|
||||
}
|
||||
buffer.pos(xStart, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, minY, 0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
}
|
||||
|
||||
protected void addStrikeThrough(float xStart, float width, float yStart, int color, IVertexBuilder buffer)
|
||||
{
|
||||
float minY = yStart + height() / 2.0F;
|
||||
float maxY = yStart + height() / 2.0F + 1.4F;
|
||||
buffer.pos(xStart, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, maxY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
buffer.pos(xStart + width, minY, 0.0F).tex(0F, 0F).color4f(color).endVertex();
|
||||
}
|
||||
|
||||
protected Float getValue(boolean oldValue, boolean newValue, Float position, Float oldPosition)
|
||||
{
|
||||
if((position == null && oldPosition == null) || (position != null && oldPosition != null)) return oldPosition;
|
||||
return newValue ? position : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String trimToWidth(String text, float limit, boolean reverse)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
float width = 0F;
|
||||
int start = reverse ? text.length() - 1 : 0;
|
||||
int direction = reverse ? -1 : 1;
|
||||
for(int i = start;i >= 0 && i < text.length() && width < limit;i += direction)
|
||||
{
|
||||
char letter = text.charAt(i);
|
||||
width += width(letter);
|
||||
if(width > limit) break;
|
||||
if(reverse) builder.insert(0, letter);
|
||||
else builder.append(letter);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float width(int codepoint, boolean bold)
|
||||
{
|
||||
switch(codepoint)
|
||||
{
|
||||
case SPACE:
|
||||
return provider.getSpaceWidth();
|
||||
case TAB:
|
||||
return provider.getTabWidth();
|
||||
default:
|
||||
CharInstance instance = getInstance(codepoint, bold);
|
||||
return instance == null ? 0F : instance.getXAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float width(String text, int flags)
|
||||
{
|
||||
float result = 0.0F;
|
||||
float current = 0.0F;
|
||||
boolean bold = (flags & BOLD) != 0;
|
||||
for(int i = 0;i < text.length();i++)
|
||||
{
|
||||
char character = text.charAt(i);
|
||||
if(LINE_SEPERATOR == character)
|
||||
{
|
||||
result = Math.max(result, current += provider.getSpaceWidth());
|
||||
current = 0.0F;
|
||||
continue;
|
||||
}
|
||||
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
|
||||
{
|
||||
String search = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
|
||||
if(search.length() > 0)
|
||||
{
|
||||
for(String entry : search.toLowerCase(Locale.ROOT).split(","))
|
||||
{
|
||||
bold = TextUtil.findFlag(entry, "bold", bold);
|
||||
}
|
||||
i += search.length() + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current += width(character, bold);
|
||||
}
|
||||
return Math.max(result, current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] widths(String text, int flags)
|
||||
{
|
||||
FloatList results = new FloatArrayList();
|
||||
results.add(0F);
|
||||
float current = 0F;
|
||||
int chars = 0;
|
||||
boolean bold = (flags & BOLD) != 0;
|
||||
float max = 0F;
|
||||
for(int i = 0;i < text.length();i++)
|
||||
{
|
||||
char character = text.charAt(i);
|
||||
if(LINE_SEPERATOR == character)
|
||||
{
|
||||
results.add(current);
|
||||
max = Math.max(max, current);
|
||||
current = 0F;
|
||||
chars = 0;
|
||||
continue;
|
||||
}
|
||||
chars++;
|
||||
if(character == '§' && (flags & SPECIAL) != 0 && i + 1 < text.length() && text.charAt(i + 1) == '<')
|
||||
{
|
||||
String result = TextUtil.searchUntil(text, i + 2, '>', INVALID_SEARCH);
|
||||
if(result.length() > 0)
|
||||
{
|
||||
for(String entry : result.toLowerCase(Locale.ROOT).split(","))
|
||||
{
|
||||
bold = TextUtil.findFlag(entry, "bold", bold);
|
||||
}
|
||||
i += result.length() + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
current += width(character, bold);
|
||||
}
|
||||
if(chars++ > 0)
|
||||
{
|
||||
results.add(current);
|
||||
max = Math.max(max, current);
|
||||
}
|
||||
results.set(0, max);
|
||||
return results.toFloatArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height(String text, int flags)
|
||||
{
|
||||
return widths(text, flags).length - 1 * height();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCharValid(int codepoint)
|
||||
{
|
||||
return provider.isCharacterValid(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] split(String text, float maxWidth, int flags)
|
||||
{
|
||||
TextContext context = new TextContext(1F, ((flags & IFontRenderer.SPECIAL) != 0 ? 16 : 0) | ((flags & IFontRenderer.BOLD) != 0 ? 1 : 0));
|
||||
List<Line> lines = lexer.evaluateLines(text, context, maxWidth);
|
||||
String[] array = new String[lines.size()];
|
||||
if(context.allowsSpecial())
|
||||
{
|
||||
int index = 0;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
WordContext wordContext = context.getEffect();
|
||||
while(wordContext.isNext(0))
|
||||
{
|
||||
builder.append(wordContext.getString(false));
|
||||
wordContext = wordContext.next();
|
||||
}
|
||||
for(int i = 0,m=lines.size();i<m;i++)
|
||||
{
|
||||
if(i != 0) builder.append(wordContext.getString(true));
|
||||
for(CharInstance letter : lines.get(i).letterIterator())
|
||||
{
|
||||
builder.append(letter.getCharacter());
|
||||
if(wordContext.isNext(++index))
|
||||
{
|
||||
wordContext = wordContext.next();
|
||||
builder.append(wordContext.getString(false));
|
||||
}
|
||||
}
|
||||
array[i] = builder.toString();
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0,m=lines.size();i<m;i++) array[i] = lines.get(i).getText();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
+142
-142
@@ -1,143 +1,143 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
||||
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
||||
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
|
||||
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.math.vector.ints.Vec2i;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder.WrittenChar;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.IFontRenderer.CharInstance;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class BitmapFontProvider implements IFontProvider
|
||||
{
|
||||
FontInfo info;
|
||||
ITexture texture;
|
||||
Int2ObjectMap<CharInstance>[] instances;
|
||||
float space;
|
||||
|
||||
public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap<CharInstance>[] instances)
|
||||
{
|
||||
this.info = info;
|
||||
this.texture = texture;
|
||||
this.instances = instances;
|
||||
if(instances[0].containsKey(' ')) space = instances[0].get(' ').getXAdvance();
|
||||
else if(instances[1].containsKey(' ')) space = instances[1].get(' ').getXAdvance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
texture.destroy();
|
||||
texture = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITexture getTexture()
|
||||
{
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCharacterValid(int codepoint)
|
||||
{
|
||||
return instances[0].containsKey(codepoint) || instances[1].containsKey(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharInstance getCharacter(int codepoint, boolean bold)
|
||||
{
|
||||
Int2ObjectMap<CharInstance> map = instances[bold ? 1 : 0];
|
||||
return (map.isEmpty() ? instances[bold ? 0 : 1] : map).get(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height()
|
||||
{
|
||||
return info.fontHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float baseLine()
|
||||
{
|
||||
return info.fontBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSpaceWidth()
|
||||
{
|
||||
return space;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTabWidth()
|
||||
{
|
||||
return space * info.tabs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static BitmapFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
|
||||
{
|
||||
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
|
||||
float multiplier = info.setDesiredHeight(desiredSize);
|
||||
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<>(), new Int2ObjectOpenHashMap<>()};
|
||||
JsonUtil.iterate(object.get("chars"), T -> {
|
||||
CharInstance instance = info.create(T);
|
||||
instance.scale(multiplier);
|
||||
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
|
||||
});
|
||||
if(maps[0].isEmpty()) maps[0] = Int2ObjectMaps.empty();
|
||||
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
|
||||
return new BitmapFontProvider(info, ITexture.simple(AssetLocation.of(object.get("file").getAsString())), maps);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static IFontProvider create(JsonObject object, float desiredSize, AssetManager manager)
|
||||
{
|
||||
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(AssetLocation.of(object.get("file").getAsString())))
|
||||
{
|
||||
JsonObject info = object.getAsJsonObject("info");
|
||||
int tabs = JsonUtil.getOrDefault(info, "tabs", 4);
|
||||
boolean literal = JsonUtil.getOrDefault(info, "literal", false);
|
||||
boolean plain = JsonUtil.getOrDefault(info, "plain", true);
|
||||
boolean bold = JsonUtil.getOrDefault(info, "bold", true);
|
||||
if(!plain && !bold) throw new IllegalStateException("You need a plain or bold font at the very least");
|
||||
|
||||
int flags = (literal ? FontBuilder.LITERAL : 0) | (plain ? FontBuilder.PLAIN : 0) | (bold ? FontBuilder.BOLD : 0);
|
||||
ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> written = FontBuilder.createBitmapFont(asset.stream(), info.get("charset").getAsString(), flags, info.get("size").getAsFloat());
|
||||
BufferedImage image = written.getKey().getValue();
|
||||
Vec2i size = written.getKey().getKey();
|
||||
FontInfo fontInfo = new FontInfo(image.getWidth(), image.getHeight(), size.y(), size.x(), tabs);
|
||||
float mulitplier = fontInfo.setDesiredHeight(desiredSize);
|
||||
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<CharInstance>(), new Int2ObjectOpenHashMap<CharInstance>()};
|
||||
for(WrittenChar entry : written.getValue())
|
||||
{
|
||||
CharInstance instance = entry.create(fontInfo.textureWidth, fontInfo.textureHeight);
|
||||
instance.scale(mulitplier);
|
||||
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
|
||||
}
|
||||
if(maps[0].isEmpty()) maps[0] = Int2ObjectMaps.empty();
|
||||
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
|
||||
return new BitmapFontProvider(fontInfo, ITexture.direct(image), maps);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
||||
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
||||
import speiger.src.collections.ints.utils.maps.Int2ObjectMaps;
|
||||
import speiger.src.collections.objects.misc.pairs.ObjectObjectPair;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.math.vector.ints.Vec2i;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder;
|
||||
import speiger.src.coreengine.rendering.guiOld.helper.FontBuilder.WrittenChar;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.IFontRenderer.CharInstance;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.ITexture;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class BitmapFontProvider implements IFontProvider
|
||||
{
|
||||
FontInfo info;
|
||||
ITexture texture;
|
||||
Int2ObjectMap<CharInstance>[] instances;
|
||||
float space;
|
||||
|
||||
public BitmapFontProvider(FontInfo info, ITexture texture, Int2ObjectMap<CharInstance>[] instances)
|
||||
{
|
||||
this.info = info;
|
||||
this.texture = texture;
|
||||
this.instances = instances;
|
||||
if(instances[0].containsKey(' ')) space = instances[0].get(' ').getXAdvance();
|
||||
else if(instances[1].containsKey(' ')) space = instances[1].get(' ').getXAdvance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
texture.destroy();
|
||||
texture = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITexture getTexture()
|
||||
{
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCharacterValid(int codepoint)
|
||||
{
|
||||
return instances[0].containsKey(codepoint) || instances[1].containsKey(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharInstance getCharacter(int codepoint, boolean bold)
|
||||
{
|
||||
Int2ObjectMap<CharInstance> map = instances[bold ? 1 : 0];
|
||||
return (map.isEmpty() ? instances[bold ? 0 : 1] : map).get(codepoint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float height()
|
||||
{
|
||||
return info.fontHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float baseLine()
|
||||
{
|
||||
return info.fontBase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSpaceWidth()
|
||||
{
|
||||
return space;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTabWidth()
|
||||
{
|
||||
return space * info.tabs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static BitmapFontProvider load(JsonObject object, float desiredSize, AssetManager manager)
|
||||
{
|
||||
FontInfo info = new FontInfo(object.getAsJsonObject("info"));
|
||||
float multiplier = info.setDesiredHeight(desiredSize);
|
||||
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<>(), new Int2ObjectOpenHashMap<>()};
|
||||
JsonUtil.iterate(object.get("chars"), T -> {
|
||||
CharInstance instance = info.create(T);
|
||||
instance.scale(multiplier);
|
||||
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
|
||||
});
|
||||
if(maps[0].isEmpty()) maps[0] = Int2ObjectMaps.empty();
|
||||
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
|
||||
return new BitmapFontProvider(info, ITexture.simple(AssetLocation.of(object.get("file").getAsString())), maps);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static IFontProvider create(JsonObject object, float desiredSize, AssetManager manager)
|
||||
{
|
||||
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(AssetLocation.of(object.get("file").getAsString())))
|
||||
{
|
||||
JsonObject info = object.getAsJsonObject("info");
|
||||
int tabs = JsonUtil.getOrDefault(info, "tabs", 4);
|
||||
boolean literal = JsonUtil.getOrDefault(info, "literal", false);
|
||||
boolean plain = JsonUtil.getOrDefault(info, "plain", true);
|
||||
boolean bold = JsonUtil.getOrDefault(info, "bold", true);
|
||||
if(!plain && !bold) throw new IllegalStateException("You need a plain or bold font at the very least");
|
||||
|
||||
int flags = (literal ? FontBuilder.LITERAL : 0) | (plain ? FontBuilder.PLAIN : 0) | (bold ? FontBuilder.BOLD : 0);
|
||||
ObjectObjectPair<ObjectObjectPair<Vec2i, BufferedImage>, List<WrittenChar>> written = FontBuilder.createBitmapFont(asset.stream(), info.get("charset").getAsString(), flags, info.get("size").getAsFloat());
|
||||
BufferedImage image = written.getKey().getValue();
|
||||
Vec2i size = written.getKey().getKey();
|
||||
FontInfo fontInfo = new FontInfo(image.getWidth(), image.getHeight(), size.y(), size.x(), tabs);
|
||||
float mulitplier = fontInfo.setDesiredHeight(desiredSize);
|
||||
Int2ObjectMap<CharInstance>[] maps = new Int2ObjectMap[]{new Int2ObjectOpenHashMap<CharInstance>(), new Int2ObjectOpenHashMap<CharInstance>()};
|
||||
for(WrittenChar entry : written.getValue())
|
||||
{
|
||||
CharInstance instance = entry.create(fontInfo.textureWidth, fontInfo.textureHeight);
|
||||
instance.scale(mulitplier);
|
||||
maps[instance.isBold() ? 1 : 0].put(instance.getCharacter(), instance);
|
||||
}
|
||||
if(maps[0].isEmpty()) maps[0] = Int2ObjectMaps.empty();
|
||||
if(maps[1].isEmpty()) maps[1] = Int2ObjectMaps.empty();
|
||||
return new BitmapFontProvider(fontInfo, ITexture.direct(image), maps);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+99
-99
@@ -1,100 +1,100 @@
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2FloatLinkedOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap.Entry;
|
||||
import speiger.src.collections.objects.utils.maps.Object2FloatMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.FontRenderer;
|
||||
|
||||
public class FontManager implements IReloadableResource
|
||||
{
|
||||
Map<AssetLocation, FontRenderer> fontRenders = new Object2ObjectLinkedOpenHashMap<>();
|
||||
Object2FloatMap<AssetLocation> fontSizes = new Object2FloatLinkedOpenHashMap<>();
|
||||
Map<String, IFontLoader> loaders = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
AssetManager manager;
|
||||
|
||||
public FontManager()
|
||||
{
|
||||
registerFontLoader("bitmap", BitmapFontProvider::load);
|
||||
registerFontLoader("java-ttf", BitmapFontProvider::create);
|
||||
}
|
||||
|
||||
public void setAssetManager(AssetManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void registerFontLoader(String id, IFontLoader provider)
|
||||
{
|
||||
loaders.put(id, provider);
|
||||
}
|
||||
|
||||
public FontRenderer loadFont(AssetLocation location, float desiredSize)
|
||||
{
|
||||
FontRenderer render = fontRenders.get(location);
|
||||
if(render == null)
|
||||
{
|
||||
IFontProvider provider = loadProvider(location, desiredSize);
|
||||
if(provider != null)
|
||||
{
|
||||
render = new FontRenderer();
|
||||
render.setProvider(provider);
|
||||
fontRenders.put(location, render);
|
||||
fontSizes.putIfAbsent(location, desiredSize);
|
||||
}
|
||||
}
|
||||
return render;
|
||||
}
|
||||
|
||||
private IFontProvider loadProvider(AssetLocation location, float desiredSize)
|
||||
{
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
JsonObject obj = asset.json();
|
||||
IFontLoader loader = loaders.get(obj.get("type").getAsString());
|
||||
if(loader == null) return null;
|
||||
return loader.create(obj, desiredSize, manager);
|
||||
}
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static interface IFontLoader
|
||||
{
|
||||
public IFontProvider create(JsonObject obj, float desiredSize, AssetManager loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
List<IFontProvider> providers = new ObjectArrayList<>();
|
||||
for(Entry<AssetLocation> entry : Object2FloatMaps.fastIterable(fontSizes))
|
||||
{
|
||||
AssetLocation location = entry.getKey();
|
||||
FontRenderer font = fontRenders.get(location);
|
||||
providers.add(font.getProvider());
|
||||
font.setProvider(loadProvider(location, entry.getFloatValue()));
|
||||
}
|
||||
for(int i = 0,m=providers.size();i<m;providers.get(i++).destroy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
fontRenders.values().forEach(FontRenderer::destory);
|
||||
fontRenders.clear();
|
||||
}
|
||||
package speiger.src.coreengine.rendering.guiOld.renderer.provider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2FloatLinkedOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap;
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2FloatMap.Entry;
|
||||
import speiger.src.collections.objects.utils.maps.Object2FloatMaps;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
import speiger.src.coreengine.rendering.guiOld.renderer.FontRenderer;
|
||||
|
||||
public class FontManager implements IReloadableResource
|
||||
{
|
||||
Map<AssetLocation, FontRenderer> fontRenders = new Object2ObjectLinkedOpenHashMap<>();
|
||||
Object2FloatMap<AssetLocation> fontSizes = new Object2FloatLinkedOpenHashMap<>();
|
||||
Map<String, IFontLoader> loaders = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
AssetManager manager;
|
||||
|
||||
public FontManager()
|
||||
{
|
||||
registerFontLoader("bitmap", BitmapFontProvider::load);
|
||||
registerFontLoader("java-ttf", BitmapFontProvider::create);
|
||||
}
|
||||
|
||||
public void setAssetManager(AssetManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void registerFontLoader(String id, IFontLoader provider)
|
||||
{
|
||||
loaders.put(id, provider);
|
||||
}
|
||||
|
||||
public FontRenderer loadFont(AssetLocation location, float desiredSize)
|
||||
{
|
||||
FontRenderer render = fontRenders.get(location);
|
||||
if(render == null)
|
||||
{
|
||||
IFontProvider provider = loadProvider(location, desiredSize);
|
||||
if(provider != null)
|
||||
{
|
||||
render = new FontRenderer();
|
||||
render.setProvider(provider);
|
||||
fontRenders.put(location, render);
|
||||
fontSizes.putIfAbsent(location, desiredSize);
|
||||
}
|
||||
}
|
||||
return render;
|
||||
}
|
||||
|
||||
private IFontProvider loadProvider(AssetLocation location, float desiredSize)
|
||||
{
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
JsonObject obj = asset.json();
|
||||
IFontLoader loader = loaders.get(obj.get("type").getAsString());
|
||||
if(loader == null) return null;
|
||||
return loader.create(obj, desiredSize, manager);
|
||||
}
|
||||
catch(Exception e) { e.printStackTrace(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public static interface IFontLoader
|
||||
{
|
||||
public IFontProvider create(JsonObject obj, float desiredSize, AssetManager loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
List<IFontProvider> providers = new ObjectArrayList<>();
|
||||
for(Entry<AssetLocation> entry : Object2FloatMaps.fastIterable(fontSizes))
|
||||
{
|
||||
AssetLocation location = entry.getKey();
|
||||
FontRenderer font = fontRenders.get(location);
|
||||
providers.add(font.getProvider());
|
||||
font.setProvider(loadProvider(location, entry.getFloatValue()));
|
||||
}
|
||||
for(int i = 0,m=providers.size();i<m;providers.get(i++).destroy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
fontRenders.values().forEach(FontRenderer::destory);
|
||||
fontRenders.clear();
|
||||
}
|
||||
}
|
||||
@@ -66,10 +66,10 @@ public class Window
|
||||
|
||||
protected void initWindowListeners() {
|
||||
addCallback(T -> GLFW.glfwSetFramebufferSizeCallback(T, this::onResize));
|
||||
addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (K, V) -> flags.setFlag(FLAG_WINDOW_CHANGE)));
|
||||
addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (W, X, Y) -> setPosition(X, Y)));
|
||||
addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (K, V) -> flags.setFlag(FLAG_FOCUS, V)));
|
||||
addCallback(T -> GLFW.glfwSetErrorCallback(this::error));
|
||||
addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (_, _) -> flags.setFlag(FLAG_WINDOW_CHANGE)));
|
||||
addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (_, X, Y) -> setPosition(X, Y)));
|
||||
addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (_, V) -> flags.setFlag(FLAG_FOCUS, V)));
|
||||
addCallback(_ -> GLFW.glfwSetErrorCallback(this::error));
|
||||
}
|
||||
|
||||
private void error(int error, long text) {
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
package speiger.src.coreengine.rendering.models.loader;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class ModelLoader
|
||||
{
|
||||
|
||||
public static List<SimpleModelData> readModelData(AssetLocation location, AssetManager manager)
|
||||
{
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
List<SimpleModelData> result = new ObjectArrayList<>();
|
||||
JsonObject obj = asset.json();
|
||||
JsonUtil.iterate(obj.get("models"), T -> {
|
||||
JsonObject info = T.getAsJsonObject("info");
|
||||
JsonObject format = T.getAsJsonObject("format");
|
||||
JsonObject data = T.getAsJsonObject("data");
|
||||
List<VertexEntry> entries = VertexLoader.loadVertexFormat(format);
|
||||
ByteBuffer buffer = VertexLoader.parseVertexData(data, info.get("vertecies").getAsInt(), entries, true);
|
||||
result.add(new SimpleModelData(info.get("name").getAsString(), UUID.fromString(info.get("id").getAsString()), buffer.array(), JsonUtil.parseIntArray(data.getAsJsonArray("indecies"))));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ObjectLists.empty();
|
||||
}
|
||||
|
||||
public static List<SimpleModelData> readLegacyModelData(AssetLocation location, AssetManager manager)
|
||||
{
|
||||
List<SimpleModelData> resultModels = new ObjectArrayList<SimpleModelData>();
|
||||
ByteBuffer buffer = null;
|
||||
int[] indexes = null;
|
||||
String currentName = null;
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
boolean flag = false;
|
||||
for(String line : IterableWrapper.wrap(asset.reader()))
|
||||
{
|
||||
if(line.startsWith("{"))
|
||||
{
|
||||
if(currentName != null)
|
||||
{
|
||||
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
|
||||
currentName = null;
|
||||
}
|
||||
currentName = line.substring(1, line.length() - 1);
|
||||
flag = true;
|
||||
}
|
||||
else if(flag)
|
||||
{
|
||||
flag = false;
|
||||
String[] bounds = line.split(";");
|
||||
buffer = ByteBuffer.allocate(Integer.parseInt(bounds[0]) * 28).order(ByteOrder.nativeOrder());
|
||||
indexes = new int[Integer.parseInt(bounds[1])];
|
||||
}
|
||||
else if(line.startsWith("<"))
|
||||
{
|
||||
String[] data = line.substring(1, line.length() - 1).split(" ");
|
||||
String[] position = data[0].split(";");
|
||||
String[] normal = data[2].split(";");
|
||||
buffer.putFloat(Float.parseFloat(position[0])).putFloat(Float.parseFloat(position[1])).putFloat(Float.parseFloat(position[2]));
|
||||
ColorUtils.write(Integer.parseInt(data[1]), true, buffer);
|
||||
buffer.putFloat(Float.parseFloat(normal[0])).putFloat(Float.parseFloat(normal[1])).putFloat(Float.parseFloat(normal[2]));
|
||||
}
|
||||
else if(line.startsWith("["))
|
||||
{
|
||||
String[] data = line.substring(1, line.length() - 1).split(";");
|
||||
for(int j = 0;j<data.length;j++)
|
||||
{
|
||||
indexes[j] = Integer.parseInt(data[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(currentName != null)
|
||||
{
|
||||
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
|
||||
currentName = null;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultModels;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.models.loader;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.collections.objects.utils.ObjectLists;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.math.misc.ColorUtils;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
import speiger.src.coreengine.utils.helpers.JsonUtil;
|
||||
|
||||
public class ModelLoader
|
||||
{
|
||||
|
||||
public static List<SimpleModelData> readModelData(AssetLocation location, AssetManager manager)
|
||||
{
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
List<SimpleModelData> result = new ObjectArrayList<>();
|
||||
JsonObject obj = asset.json();
|
||||
JsonUtil.iterate(obj.get("models"), T -> {
|
||||
JsonObject info = T.getAsJsonObject("info");
|
||||
JsonObject format = T.getAsJsonObject("format");
|
||||
JsonObject data = T.getAsJsonObject("data");
|
||||
List<VertexEntry> entries = VertexLoader.loadVertexFormat(format);
|
||||
ByteBuffer buffer = VertexLoader.parseVertexData(data, info.get("vertecies").getAsInt(), entries, true);
|
||||
result.add(new SimpleModelData(info.get("name").getAsString(), UUID.fromString(info.get("id").getAsString()), buffer.array(), JsonUtil.parseIntArray(data.getAsJsonArray("indecies"))));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return ObjectLists.empty();
|
||||
}
|
||||
|
||||
public static List<SimpleModelData> readLegacyModelData(AssetLocation location, AssetManager manager)
|
||||
{
|
||||
List<SimpleModelData> resultModels = new ObjectArrayList<SimpleModelData>();
|
||||
ByteBuffer buffer = null;
|
||||
int[] indexes = null;
|
||||
String currentName = null;
|
||||
try(IAsset asset = manager.getAsset(location))
|
||||
{
|
||||
boolean flag = false;
|
||||
for(String line : IterableWrapper.wrap(asset.reader()))
|
||||
{
|
||||
if(line.startsWith("{"))
|
||||
{
|
||||
if(currentName != null)
|
||||
{
|
||||
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
|
||||
currentName = null;
|
||||
}
|
||||
currentName = line.substring(1, line.length() - 1);
|
||||
flag = true;
|
||||
}
|
||||
else if(flag)
|
||||
{
|
||||
flag = false;
|
||||
String[] bounds = line.split(";");
|
||||
buffer = ByteBuffer.allocate(Integer.parseInt(bounds[0]) * 28).order(ByteOrder.nativeOrder());
|
||||
indexes = new int[Integer.parseInt(bounds[1])];
|
||||
}
|
||||
else if(line.startsWith("<"))
|
||||
{
|
||||
String[] data = line.substring(1, line.length() - 1).split(" ");
|
||||
String[] position = data[0].split(";");
|
||||
String[] normal = data[2].split(";");
|
||||
buffer.putFloat(Float.parseFloat(position[0])).putFloat(Float.parseFloat(position[1])).putFloat(Float.parseFloat(position[2]));
|
||||
ColorUtils.write(Integer.parseInt(data[1]), true, buffer);
|
||||
buffer.putFloat(Float.parseFloat(normal[0])).putFloat(Float.parseFloat(normal[1])).putFloat(Float.parseFloat(normal[2]));
|
||||
}
|
||||
else if(line.startsWith("["))
|
||||
{
|
||||
String[] data = line.substring(1, line.length() - 1).split(";");
|
||||
for(int j = 0;j<data.length;j++)
|
||||
{
|
||||
indexes[j] = Integer.parseInt(data[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(currentName != null)
|
||||
{
|
||||
resultModels.add(new SimpleModelData(currentName, null, buffer.array(), indexes));
|
||||
currentName = null;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultModels;
|
||||
}
|
||||
}
|
||||
@@ -1,137 +1,137 @@
|
||||
package speiger.src.coreengine.rendering.shader;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL41;
|
||||
import org.lwjgl.opengl.GL45;
|
||||
import org.lwjgl.opengl.GL46;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.math.ArrayUtil;
|
||||
import speiger.src.coreengine.rendering.shader.uniform.UniformManager;
|
||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||
import speiger.src.coreengine.rendering.utils.values.IGLValue.IShaderType;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
|
||||
public abstract class ShaderProgram {
|
||||
static final Map<AssetLocation, String> IMPORTS = Object2ObjectMap.builder().<AssetLocation, String>map().synchronize();
|
||||
protected final UniformManager uniforms = new UniformManager(this);
|
||||
private int id;
|
||||
|
||||
public boolean isValid() { return id != 0; }
|
||||
public boolean isActive() { return GLStateTracker.instance().shaders.isShaderActive(this); }
|
||||
public int id() { return id; }
|
||||
public UniformManager getUniforms() { return uniforms; }
|
||||
|
||||
protected void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
GLStateTracker.instance().shaders.bind(this);
|
||||
uniforms.bind();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if(id == 0) return;
|
||||
uniforms.remove();
|
||||
GL20.glDeleteProgram(id);
|
||||
id = 0;
|
||||
}
|
||||
|
||||
public void validateProgram() {
|
||||
if(id == 0) return;
|
||||
uniforms.validate();
|
||||
GL46.glValidateProgram(id);
|
||||
}
|
||||
|
||||
public static int loadOrGenerateCache(String location, FileTime newestResource, IntPredicate callback) {
|
||||
int id = GL20.glCreateProgram();
|
||||
boolean fail = true;
|
||||
if((fail = !loadFromBinary(id, location, newestResource)) && callback.test(id)) {
|
||||
if(GL46.glGetProgrami(id, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) {
|
||||
if(ShaderCache.INSTANCE.hasCache()) ShaderCache.INSTANCE.storeInCache(location, getProgramBytes(id));
|
||||
fail = false;
|
||||
}
|
||||
}
|
||||
if(fail) {
|
||||
GL20.glDeleteProgram(id);
|
||||
return 0;
|
||||
}
|
||||
String error = GL45.glGetProgramInfoLog(id);
|
||||
if(!error.isBlank()) {
|
||||
System.out.println("Error: "+error);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private static boolean loadFromBinary(int programId, String location, FileTime newestResource) {
|
||||
ByteBuffer buffer = ShaderCache.INSTANCE.readFromCache(location, newestResource);
|
||||
if(buffer != null) {
|
||||
GL41.glProgramBinary(programId, buffer.getInt(), buffer);
|
||||
MemoryUtil.memFree(buffer);
|
||||
if(GL46.glGetProgrami(programId, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] getProgramBytes(int programId) {
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(GL20.glGetProgrami(programId, GL41.GL_PROGRAM_BINARY_LENGTH) + 4);
|
||||
int[] format = new int[1];
|
||||
GL41.glGetProgramBinary(programId, null, format, buffer.position(4));
|
||||
return ArrayUtil.toArray(buffer.putInt(0, format[0]).flip(), MemoryUtil::memFree);
|
||||
}
|
||||
|
||||
public static int loadShader(IAssetProvider provider, AssetLocation location, IShaderType type) {
|
||||
StringBuilder builder = new StringBuilder(2048);
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
for(String line : asset.lines()) {
|
||||
if(line.startsWith("//")) continue;
|
||||
if(line.startsWith("#import<") && line.endsWith(">")) {
|
||||
builder.append(importLines(provider, AssetLocation.of(line.substring(8, line.length()-1)))).append("\n");
|
||||
continue;
|
||||
}
|
||||
builder.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
int shaderID = GL20.glCreateShader(type.glValue());
|
||||
GL20.glShaderSource(shaderID, builder);
|
||||
GL20.glCompileShader(shaderID);
|
||||
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
|
||||
GameLog.warn("Could not compile shader " + location);
|
||||
GameLog.error(GL20.glGetShaderInfoLog(shaderID, GL20.glGetShaderi(shaderID, GL20.GL_INFO_LOG_LENGTH)));
|
||||
GL20.glDeleteShader(shaderID);
|
||||
return -1;
|
||||
}
|
||||
return shaderID;
|
||||
}
|
||||
|
||||
public static String importLines(IAssetProvider provider, AssetLocation location) {
|
||||
return IMPORTS.computeIfAbsent(location, T -> {
|
||||
try(IAsset asset = provider.getAsset(T)) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(String line : asset.lines()) {
|
||||
if(line.startsWith("//")) continue;
|
||||
builder.append(line).append("\n");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.shader;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.IntPredicate;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL41;
|
||||
import org.lwjgl.opengl.GL45;
|
||||
import org.lwjgl.opengl.GL46;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||
import speiger.src.coreengine.math.ArrayUtil;
|
||||
import speiger.src.coreengine.rendering.shader.uniform.UniformManager;
|
||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||
import speiger.src.coreengine.rendering.utils.values.IGLValue.IShaderType;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
|
||||
public abstract class ShaderProgram {
|
||||
static final Map<AssetLocation, String> IMPORTS = Object2ObjectMap.builder().<AssetLocation, String>map().synchronize();
|
||||
protected final UniformManager uniforms = new UniformManager(this);
|
||||
private int id;
|
||||
|
||||
public boolean isValid() { return id != 0; }
|
||||
public boolean isActive() { return GLStateTracker.instance().shaders.isShaderActive(this); }
|
||||
public int id() { return id; }
|
||||
public UniformManager getUniforms() { return uniforms; }
|
||||
|
||||
protected void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
GLStateTracker.instance().shaders.bind(this);
|
||||
uniforms.bind();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if(id == 0) return;
|
||||
uniforms.remove();
|
||||
GL20.glDeleteProgram(id);
|
||||
id = 0;
|
||||
}
|
||||
|
||||
public void validateProgram() {
|
||||
if(id == 0) return;
|
||||
uniforms.validate();
|
||||
GL46.glValidateProgram(id);
|
||||
}
|
||||
|
||||
public static int loadOrGenerateCache(String location, FileTime newestResource, IntPredicate callback) {
|
||||
int id = GL20.glCreateProgram();
|
||||
boolean fail = true;
|
||||
if((fail = !loadFromBinary(id, location, newestResource)) && callback.test(id)) {
|
||||
if(GL46.glGetProgrami(id, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) {
|
||||
if(ShaderCache.INSTANCE.hasCache()) ShaderCache.INSTANCE.storeInCache(location, getProgramBytes(id));
|
||||
fail = false;
|
||||
}
|
||||
}
|
||||
if(fail) {
|
||||
GL20.glDeleteProgram(id);
|
||||
return 0;
|
||||
}
|
||||
String error = GL45.glGetProgramInfoLog(id);
|
||||
if(!error.isBlank()) {
|
||||
System.out.println("Error: "+error);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private static boolean loadFromBinary(int programId, String location, FileTime newestResource) {
|
||||
ByteBuffer buffer = ShaderCache.INSTANCE.readFromCache(location, newestResource);
|
||||
if(buffer != null) {
|
||||
GL41.glProgramBinary(programId, buffer.getInt(), buffer);
|
||||
MemoryUtil.memFree(buffer);
|
||||
if(GL46.glGetProgrami(programId, GL46.GL_LINK_STATUS) == GL46.GL_TRUE) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static byte[] getProgramBytes(int programId) {
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(GL20.glGetProgrami(programId, GL41.GL_PROGRAM_BINARY_LENGTH) + 4);
|
||||
int[] format = new int[1];
|
||||
GL41.glGetProgramBinary(programId, null, format, buffer.position(4));
|
||||
return ArrayUtil.toArray(buffer.putInt(0, format[0]).flip(), MemoryUtil::memFree);
|
||||
}
|
||||
|
||||
public static int loadShader(IAssetProvider provider, AssetLocation location, IShaderType type) {
|
||||
StringBuilder builder = new StringBuilder(2048);
|
||||
try(IAsset asset = provider.getAsset(location)) {
|
||||
for(String line : asset.lines()) {
|
||||
if(line.startsWith("//")) continue;
|
||||
if(line.startsWith("#import<") && line.endsWith(">")) {
|
||||
builder.append(importLines(provider, AssetLocation.of(line.substring(8, line.length()-1)))).append("\n");
|
||||
continue;
|
||||
}
|
||||
builder.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
int shaderID = GL20.glCreateShader(type.glValue());
|
||||
GL20.glShaderSource(shaderID, builder);
|
||||
GL20.glCompileShader(shaderID);
|
||||
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
|
||||
GameLog.warn("Could not compile shader " + location);
|
||||
GameLog.error(GL20.glGetShaderInfoLog(shaderID, GL20.glGetShaderi(shaderID, GL20.GL_INFO_LOG_LENGTH)));
|
||||
GL20.glDeleteShader(shaderID);
|
||||
return -1;
|
||||
}
|
||||
return shaderID;
|
||||
}
|
||||
|
||||
public static String importLines(IAssetProvider provider, AssetLocation location) {
|
||||
return IMPORTS.computeIfAbsent(location, T -> {
|
||||
try(IAsset asset = provider.getAsset(T)) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(String line : asset.lines()) {
|
||||
if(line.startsWith("//")) continue;
|
||||
builder.append(line).append("\n");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,109 +1,109 @@
|
||||
package speiger.src.coreengine.rendering.shaderOld;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.rendering.shaderOld.ShaderTracker.ReloadReference;
|
||||
import speiger.src.coreengine.rendering.shaderOld.uniforms.Uniform;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
|
||||
public abstract class ShaderProgram
|
||||
{
|
||||
protected List<Uniform> localUniforms = new ObjectArrayList<>();
|
||||
ReloadReference<?> reference;
|
||||
private int shaderID;
|
||||
|
||||
protected ShaderProgram(AssetLocation vertex, AssetLocation fragment, String[] attributes) {
|
||||
int vertexID = loadShader(vertex, GL20.GL_VERTEX_SHADER);
|
||||
int fragmentID = loadShader(fragment, GL20.GL_FRAGMENT_SHADER);
|
||||
if(vertexID == -1 || fragmentID == -1) {
|
||||
shaderID = 0;
|
||||
return;
|
||||
}
|
||||
shaderID = GL20.glCreateProgram();
|
||||
GL20.glAttachShader(shaderID, vertexID);
|
||||
GL20.glAttachShader(shaderID, fragmentID);
|
||||
for(int i = 0;i < attributes.length;i++) {
|
||||
GL20.glBindAttribLocation(shaderID, i, attributes[i]);
|
||||
}
|
||||
GL20.glLinkProgram(shaderID);
|
||||
GL20.glDetachShader(shaderID, vertexID);
|
||||
GL20.glDetachShader(shaderID, fragmentID);
|
||||
GL20.glDeleteShader(vertexID);
|
||||
GL20.glDeleteShader(fragmentID);
|
||||
}
|
||||
|
||||
public void addUniforms(Uniform... uniforms) {
|
||||
for(Uniform uni : uniforms) {
|
||||
uni.loadUniform(this);
|
||||
localUniforms.add(uni);
|
||||
}
|
||||
GL20.glValidateProgram(shaderID);
|
||||
}
|
||||
|
||||
void setReference(ReloadReference<?> ref) {
|
||||
reference = ref;
|
||||
}
|
||||
|
||||
public abstract ShaderProgram init();
|
||||
|
||||
public boolean isShaderValid() {
|
||||
return shaderID != 0;
|
||||
}
|
||||
|
||||
public int getShaderID() {
|
||||
return shaderID;
|
||||
}
|
||||
|
||||
public void startShader() {
|
||||
ShaderTracker.INSTANCE.startNextShader(this);
|
||||
}
|
||||
|
||||
public void stopShader() {
|
||||
ShaderTracker.INSTANCE.stopShader(this);
|
||||
}
|
||||
|
||||
public boolean isShaderRunning() {
|
||||
return ShaderTracker.INSTANCE.activeShader == getShaderID();
|
||||
}
|
||||
|
||||
public void removeShader() {
|
||||
if(shaderID == 0) return;
|
||||
stopShader();
|
||||
GL20.glDeleteProgram(shaderID);
|
||||
shaderID = 0;
|
||||
reference.removeReference();
|
||||
reference = null;
|
||||
}
|
||||
|
||||
private int loadShader(AssetLocation location, int type) {
|
||||
StringBuilder shaderSource = new StringBuilder();
|
||||
try(IAsset asset = ShaderTracker.INSTANCE.getAssets().getAsset(location)) {
|
||||
for(String s : IterableWrapper.wrap(asset.reader()))
|
||||
{
|
||||
if(s.startsWith("//")) continue;
|
||||
shaderSource.append(s).append("\n");
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
int shaderID = GL20.glCreateShader(type);
|
||||
GL20.glShaderSource(shaderID, shaderSource);
|
||||
GL20.glCompileShader(shaderID);
|
||||
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
|
||||
GameLog.warn("Could not compile shader " + location);
|
||||
int[] length = new int[1];
|
||||
GL20.glGetShaderiv(shaderID, GL20.GL_INFO_LOG_LENGTH, length);
|
||||
GameLog.error(GL20.glGetShaderInfoLog(shaderID, length[0]));
|
||||
return -1;
|
||||
}
|
||||
return shaderID;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.shaderOld;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.rendering.shaderOld.ShaderTracker.ReloadReference;
|
||||
import speiger.src.coreengine.rendering.shaderOld.uniforms.Uniform;
|
||||
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
|
||||
public abstract class ShaderProgram
|
||||
{
|
||||
protected List<Uniform> localUniforms = new ObjectArrayList<>();
|
||||
ReloadReference<?> reference;
|
||||
private int shaderID;
|
||||
|
||||
protected ShaderProgram(AssetLocation vertex, AssetLocation fragment, String[] attributes) {
|
||||
int vertexID = loadShader(vertex, GL20.GL_VERTEX_SHADER);
|
||||
int fragmentID = loadShader(fragment, GL20.GL_FRAGMENT_SHADER);
|
||||
if(vertexID == -1 || fragmentID == -1) {
|
||||
shaderID = 0;
|
||||
return;
|
||||
}
|
||||
shaderID = GL20.glCreateProgram();
|
||||
GL20.glAttachShader(shaderID, vertexID);
|
||||
GL20.glAttachShader(shaderID, fragmentID);
|
||||
for(int i = 0;i < attributes.length;i++) {
|
||||
GL20.glBindAttribLocation(shaderID, i, attributes[i]);
|
||||
}
|
||||
GL20.glLinkProgram(shaderID);
|
||||
GL20.glDetachShader(shaderID, vertexID);
|
||||
GL20.glDetachShader(shaderID, fragmentID);
|
||||
GL20.glDeleteShader(vertexID);
|
||||
GL20.glDeleteShader(fragmentID);
|
||||
}
|
||||
|
||||
public void addUniforms(Uniform... uniforms) {
|
||||
for(Uniform uni : uniforms) {
|
||||
uni.loadUniform(this);
|
||||
localUniforms.add(uni);
|
||||
}
|
||||
GL20.glValidateProgram(shaderID);
|
||||
}
|
||||
|
||||
void setReference(ReloadReference<?> ref) {
|
||||
reference = ref;
|
||||
}
|
||||
|
||||
public abstract ShaderProgram init();
|
||||
|
||||
public boolean isShaderValid() {
|
||||
return shaderID != 0;
|
||||
}
|
||||
|
||||
public int getShaderID() {
|
||||
return shaderID;
|
||||
}
|
||||
|
||||
public void startShader() {
|
||||
ShaderTracker.INSTANCE.startNextShader(this);
|
||||
}
|
||||
|
||||
public void stopShader() {
|
||||
ShaderTracker.INSTANCE.stopShader(this);
|
||||
}
|
||||
|
||||
public boolean isShaderRunning() {
|
||||
return ShaderTracker.INSTANCE.activeShader == getShaderID();
|
||||
}
|
||||
|
||||
public void removeShader() {
|
||||
if(shaderID == 0) return;
|
||||
stopShader();
|
||||
GL20.glDeleteProgram(shaderID);
|
||||
shaderID = 0;
|
||||
reference.removeReference();
|
||||
reference = null;
|
||||
}
|
||||
|
||||
private int loadShader(AssetLocation location, int type) {
|
||||
StringBuilder shaderSource = new StringBuilder();
|
||||
try(IAsset asset = ShaderTracker.INSTANCE.getAssets().getAsset(location)) {
|
||||
for(String s : IterableWrapper.wrap(asset.reader()))
|
||||
{
|
||||
if(s.startsWith("//")) continue;
|
||||
shaderSource.append(s).append("\n");
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
int shaderID = GL20.glCreateShader(type);
|
||||
GL20.glShaderSource(shaderID, shaderSource);
|
||||
GL20.glCompileShader(shaderID);
|
||||
if(GL20.glGetShaderi(shaderID, GL20.GL_COMPILE_STATUS) == 0) {
|
||||
GameLog.warn("Could not compile shader " + location);
|
||||
int[] length = new int[1];
|
||||
GL20.glGetShaderiv(shaderID, GL20.GL_INFO_LOG_LENGTH, length);
|
||||
GameLog.error(GL20.glGetShaderInfoLog(shaderID, length[0]));
|
||||
return -1;
|
||||
}
|
||||
return shaderID;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+144
-144
@@ -1,144 +1,144 @@
|
||||
package speiger.src.coreengine.rendering.texturesOld.base;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.glfw.GLFWImage;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
import speiger.src.coreengine.assets.reloader.ResourceReloader;
|
||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||
import speiger.src.coreengine.rendering.utils.states.GLState;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
import speiger.src.coreengine.utils.io.GameLog.LogLevel;
|
||||
|
||||
public class TextureManager implements IReloadableResource
|
||||
{
|
||||
public static final TextureManager INSTANCE = new TextureManager();
|
||||
public static final GLState TEXTURE = GLStateTracker.instance().addState(new GLState(GL11.GL_TEXTURE_2D, false));
|
||||
AssetManager manager;
|
||||
ResourceReloader reloader = new ResourceReloader();
|
||||
int[] textureBanks = new int[GL13.GL_TEXTURE31 - GL13.GL_TEXTURE0];
|
||||
int activeBank = 0;
|
||||
|
||||
public void init(AssetManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public ResourceReloader getReloader()
|
||||
{
|
||||
return reloader;
|
||||
}
|
||||
|
||||
public void addTexture(ITexture texture)
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
reloader.addReloadableResource(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTexture(ITexture texture)
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
GL11.glDeleteTextures(texture.getTextureId());
|
||||
reloader.removeReloadableResource(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTexture(int id)
|
||||
{
|
||||
GL11.glDeleteTextures(id);
|
||||
}
|
||||
|
||||
public static void bindTexture(int texture)
|
||||
{
|
||||
INSTANCE.setActiveTexture(texture);
|
||||
}
|
||||
|
||||
public static void bindTexture(int texture, int bank)
|
||||
{
|
||||
INSTANCE.setActiveTexture(texture, bank);
|
||||
}
|
||||
|
||||
public static void unbindTexture()
|
||||
{
|
||||
INSTANCE.setActiveTexture(0);
|
||||
}
|
||||
|
||||
public void setActiveTexture(int texture)
|
||||
{
|
||||
if(textureBanks[activeBank] != texture)
|
||||
{
|
||||
textureBanks[activeBank] = texture;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveTexture(int texture, int bank)
|
||||
{
|
||||
if(activeBank != bank)
|
||||
{
|
||||
activeBank = bank;
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeBank);
|
||||
}
|
||||
bindTexture(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
reloader.reloadResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
reloader.deleteResources();
|
||||
}
|
||||
|
||||
public AssetManager getManager()
|
||||
{
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static GLFWImage create(AssetLocation location)
|
||||
{
|
||||
try(IAsset asset = INSTANCE.manager.getAsset(location))
|
||||
{
|
||||
BufferedImage image = asset.texture();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int[] pixelData = new int[width * height];
|
||||
image.getRGB(0, 0, width, height, pixelData, 0, width);
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
|
||||
for(int y = 0;y<height;y++)
|
||||
{
|
||||
for(int x = 0;x<width;x++)
|
||||
{
|
||||
int pixel = pixelData[(y * width) + x];
|
||||
buffer.put((byte)((pixel >> 16) & 0xFF));
|
||||
buffer.put((byte)((pixel >> 8) & 0xFF));
|
||||
buffer.put((byte)(pixel & 0xFF));
|
||||
buffer.put((byte)((pixel >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
GLFWImage glfw = GLFWImage.malloc();
|
||||
glfw.set(width, height, buffer);
|
||||
return glfw;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
GameLog.error("Couldn't Load Texture ["+location.toString()+"]", e, LogLevel.ERROR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.texturesOld.base;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.glfw.GLFWImage;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.AssetManager;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.assets.reloader.IReloadableResource;
|
||||
import speiger.src.coreengine.assets.reloader.ResourceReloader;
|
||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||
import speiger.src.coreengine.rendering.utils.states.GLState;
|
||||
import speiger.src.coreengine.utils.io.GameLog;
|
||||
import speiger.src.coreengine.utils.io.GameLog.LogLevel;
|
||||
|
||||
public class TextureManager implements IReloadableResource
|
||||
{
|
||||
public static final TextureManager INSTANCE = new TextureManager();
|
||||
public static final GLState TEXTURE = GLStateTracker.instance().addState(new GLState(GL11.GL_TEXTURE_2D, false));
|
||||
AssetManager manager;
|
||||
ResourceReloader reloader = new ResourceReloader();
|
||||
int[] textureBanks = new int[GL13.GL_TEXTURE31 - GL13.GL_TEXTURE0];
|
||||
int activeBank = 0;
|
||||
|
||||
public void init(AssetManager manager)
|
||||
{
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public ResourceReloader getReloader()
|
||||
{
|
||||
return reloader;
|
||||
}
|
||||
|
||||
public void addTexture(ITexture texture)
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
reloader.addReloadableResource(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTexture(ITexture texture)
|
||||
{
|
||||
if(texture != null)
|
||||
{
|
||||
GL11.glDeleteTextures(texture.getTextureId());
|
||||
reloader.removeReloadableResource(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTexture(int id)
|
||||
{
|
||||
GL11.glDeleteTextures(id);
|
||||
}
|
||||
|
||||
public static void bindTexture(int texture)
|
||||
{
|
||||
INSTANCE.setActiveTexture(texture);
|
||||
}
|
||||
|
||||
public static void bindTexture(int texture, int bank)
|
||||
{
|
||||
INSTANCE.setActiveTexture(texture, bank);
|
||||
}
|
||||
|
||||
public static void unbindTexture()
|
||||
{
|
||||
INSTANCE.setActiveTexture(0);
|
||||
}
|
||||
|
||||
public void setActiveTexture(int texture)
|
||||
{
|
||||
if(textureBanks[activeBank] != texture)
|
||||
{
|
||||
textureBanks[activeBank] = texture;
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveTexture(int texture, int bank)
|
||||
{
|
||||
if(activeBank != bank)
|
||||
{
|
||||
activeBank = bank;
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0 + activeBank);
|
||||
}
|
||||
bindTexture(texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
reloader.reloadResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
reloader.deleteResources();
|
||||
}
|
||||
|
||||
public AssetManager getManager()
|
||||
{
|
||||
return manager;
|
||||
}
|
||||
|
||||
public static GLFWImage create(AssetLocation location)
|
||||
{
|
||||
try(IAsset asset = INSTANCE.manager.getAsset(location))
|
||||
{
|
||||
BufferedImage image = asset.texture();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
int[] pixelData = new int[width * height];
|
||||
image.getRGB(0, 0, width, height, pixelData, 0, width);
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
|
||||
for(int y = 0;y<height;y++)
|
||||
{
|
||||
for(int x = 0;x<width;x++)
|
||||
{
|
||||
int pixel = pixelData[(y * width) + x];
|
||||
buffer.put((byte)((pixel >> 16) & 0xFF));
|
||||
buffer.put((byte)((pixel >> 8) & 0xFF));
|
||||
buffer.put((byte)(pixel & 0xFF));
|
||||
buffer.put((byte)((pixel >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
GLFWImage glfw = GLFWImage.malloc();
|
||||
glfw.set(width, height, buffer);
|
||||
return glfw;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
GameLog.error("Couldn't Load Texture ["+location.toString()+"]", e, LogLevel.ERROR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
-87
@@ -1,87 +1,87 @@
|
||||
package speiger.src.coreengine.rendering.texturesOld.normal;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
|
||||
|
||||
public class SimpleTexture extends AbstractTexture
|
||||
{
|
||||
AssetLocation location;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
public SimpleTexture(AssetLocation location)
|
||||
{
|
||||
super();
|
||||
this.location = location;
|
||||
loadTexture();
|
||||
}
|
||||
|
||||
public void loadTexture()
|
||||
{
|
||||
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location))
|
||||
{
|
||||
BufferedImage image = asset.texture();
|
||||
width = image.getWidth();
|
||||
height = image.getHeight();
|
||||
int[] pixelData = new int[width * height];
|
||||
image.getRGB(0, 0, width, height, pixelData, 0, width);
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
|
||||
for(int y = 0;y<height;y++)
|
||||
{
|
||||
for(int x = 0;x<width;x++)
|
||||
{
|
||||
int pixel = pixelData[(y * width) + x];
|
||||
buffer.put((byte)((pixel >> 16) & 0xFF));
|
||||
buffer.put((byte)((pixel >> 8) & 0xFF));
|
||||
buffer.put((byte)(pixel & 0xFF));
|
||||
buffer.put((byte)((pixel >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
setTextureID(GL11.glGenTextures());
|
||||
bindTexture();
|
||||
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_BORDER);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
int old = textureID;
|
||||
loadTexture();
|
||||
TextureManager.INSTANCE.removeTexture(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.rendering.texturesOld.normal;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import speiger.src.coreengine.assets.AssetLocation;
|
||||
import speiger.src.coreengine.assets.base.IAsset;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.AbstractTexture;
|
||||
import speiger.src.coreengine.rendering.texturesOld.base.TextureManager;
|
||||
|
||||
public class SimpleTexture extends AbstractTexture
|
||||
{
|
||||
AssetLocation location;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
public SimpleTexture(AssetLocation location)
|
||||
{
|
||||
super();
|
||||
this.location = location;
|
||||
loadTexture();
|
||||
}
|
||||
|
||||
public void loadTexture()
|
||||
{
|
||||
try(IAsset asset = TextureManager.INSTANCE.getManager().getAsset(location))
|
||||
{
|
||||
BufferedImage image = asset.texture();
|
||||
width = image.getWidth();
|
||||
height = image.getHeight();
|
||||
int[] pixelData = new int[width * height];
|
||||
image.getRGB(0, 0, width, height, pixelData, 0, width);
|
||||
ByteBuffer buffer = MemoryUtil.memAlloc(pixelData.length * 4);
|
||||
for(int y = 0;y<height;y++)
|
||||
{
|
||||
for(int x = 0;x<width;x++)
|
||||
{
|
||||
int pixel = pixelData[(y * width) + x];
|
||||
buffer.put((byte)((pixel >> 16) & 0xFF));
|
||||
buffer.put((byte)((pixel >> 8) & 0xFF));
|
||||
buffer.put((byte)(pixel & 0xFF));
|
||||
buffer.put((byte)((pixel >> 24) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
buffer.flip();
|
||||
setTextureID(GL11.glGenTextures());
|
||||
bindTexture();
|
||||
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP_TO_BORDER);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload()
|
||||
{
|
||||
int old = textureID;
|
||||
loadTexture();
|
||||
TextureManager.INSTANCE.removeTexture(old);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,25 @@
|
||||
package speiger.src.coreengine.utils.functions;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Functions
|
||||
{
|
||||
static final Predicate<Object> ALWAYS_TRUE = (T) -> true;
|
||||
static final Consumer<Object> EMPTY_CONSUMER = (T) -> {};
|
||||
public static final Predicate<String> NUMBERS_ONLY = T -> {
|
||||
if(T.isEmpty() || T.equals("#") || T.equals("0x")) return true;
|
||||
try { return Long.decode(T) != null; }
|
||||
catch(Exception e){ return false; }
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Predicate<T> getAlwaysTrue() {
|
||||
return (Predicate<T>)ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Consumer<T> getVoidConsumer() {
|
||||
return (Consumer<T>)EMPTY_CONSUMER;
|
||||
}
|
||||
}
|
||||
package speiger.src.coreengine.utils.functions;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Functions
|
||||
{
|
||||
static final Predicate<Object> ALWAYS_TRUE = _ -> true;
|
||||
static final Consumer<Object> EMPTY_CONSUMER = _ -> {};
|
||||
public static final Predicate<String> NUMBERS_ONLY = T -> {
|
||||
if(T.isEmpty() || T.equals("#") || T.equals("0x")) return true;
|
||||
try { return Long.decode(T) != null; }
|
||||
catch(Exception e){ return false; }
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Predicate<T> getAlwaysTrue() {
|
||||
return (Predicate<T>)ALWAYS_TRUE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Consumer<T> getVoidConsumer() {
|
||||
return (Consumer<T>)EMPTY_CONSUMER;
|
||||
}
|
||||
}
|
||||
+28
-28
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
+146
-146
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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); }
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -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); }
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -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); }
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 144 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user