Progress on more rewrites
This commit is contained in:
parent
340d8ff463
commit
396d4f2232
12
.classpath
12
.classpath
@ -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"/>
|
||||
|
||||
22
build.gradle
22
build.gradle
@ -16,12 +16,31 @@ eclipse {
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
graphics {}
|
||||
math {
|
||||
java {}
|
||||
}
|
||||
assets {
|
||||
java {}
|
||||
}
|
||||
graphics {
|
||||
java {}
|
||||
}
|
||||
main {
|
||||
compileClasspath += sourceSets.math.output
|
||||
runtimeClasspath += sourceSets.math.output
|
||||
}
|
||||
graphics {
|
||||
compileClasspath += sourceSets.math.output
|
||||
runtimeClasspath += sourceSets.math.output
|
||||
java {}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
graphics.extendsFrom implementation
|
||||
graphics.extendsFrom runtime
|
||||
graphics.extendsFrom mathRuntime
|
||||
implementation.extendsFrom mathRuntime
|
||||
}
|
||||
|
||||
repositories {
|
||||
@ -64,6 +83,7 @@ dependencies {
|
||||
|
||||
//Primitive Collections
|
||||
implementation 'de.speiger:Primitive-Collections:1.0.0'
|
||||
mathImplementation 'de.speiger:Primitive-Collections:1.0.0'
|
||||
}
|
||||
|
||||
jar {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
79
src/assets/java/speiger/src/coreengine/assets/api/ID.java
Normal file
79
src/assets/java/speiger/src/coreengine/assets/api/ID.java
Normal file
@ -0,0 +1,79 @@
|
||||
package speiger.src.coreengine.assets.api;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record ID(String domain, String path) implements Comparable<ID> {
|
||||
|
||||
public ID {
|
||||
Objects.requireNonNull(domain);
|
||||
Objects.requireNonNull(path);
|
||||
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
|
||||
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||
}
|
||||
|
||||
public ID prefix(String prefix) { return of(domain, prefix+"/"+path); }
|
||||
public ID suffix(String suffix) { return of(domain, path+"/"+suffix); }
|
||||
public ID alternate(String alterversion) { return of(domain, path+"."+alterversion); }
|
||||
|
||||
public String fileLocation() { return "assets/"+domain+"/"+path; }
|
||||
public boolean isRoot() { return !path.contains("/"); }
|
||||
public boolean isRootFolder(String folder) { return path.indexOf('/', folder.length()+1) < 0; }
|
||||
public boolean endsWith(String suffix) { return path.endsWith(suffix); }
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return domain+":"+path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ID o) {
|
||||
int result = domain.compareToIgnoreCase(o.domain);
|
||||
return result != 0 ? result : path.compareToIgnoreCase(path);
|
||||
}
|
||||
|
||||
public boolean matches(ID id) {
|
||||
return id.domain.equals(domain) && id.path.equals(path);
|
||||
}
|
||||
|
||||
public static ID of(String domain, String path) {
|
||||
return new ID((domain == null || domain.isBlank() ? "base" : domain), path);
|
||||
}
|
||||
|
||||
public static ID of(String location) {
|
||||
Objects.requireNonNull(location);
|
||||
int index = location.indexOf(":");
|
||||
String domain = location.substring(0, index);
|
||||
String path = location.substring(index + 1);
|
||||
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+path+"]");
|
||||
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||
return new ID(domain, path);
|
||||
}
|
||||
|
||||
public static final ID tryOf(String location) {
|
||||
try { return of(location); }
|
||||
catch(Exception e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isValidDomain(String s) {
|
||||
for(int i = 0,m=s.length();i<m;i++) {
|
||||
if(!isValidDomainChar(s.charAt(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidPath(String s) {
|
||||
for(int i = 0,m=s.length();i<m;i++) {
|
||||
if(!isValidPathChar(s.charAt(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidPathChar(char c) {
|
||||
return c == '/' || isValidDomainChar(c);
|
||||
}
|
||||
|
||||
private static boolean isValidDomainChar(char c) {
|
||||
return c == '_' || c == '-' || c == '.' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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) {}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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); }
|
||||
}
|
||||
@ -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); }
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package speiger.src.coreengine.math.vector.bytes;
|
||||
|
||||
public record Vec4bImmutable(byte x, byte y, byte z, byte w) implements Vec4b {
|
||||
|
||||
public Vec4bImmutable() {
|
||||
this((byte)0, (byte)0, (byte)0, (byte)0);
|
||||
}
|
||||
|
||||
public Vec4bImmutable(byte value) {
|
||||
this(value, value, value, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() { return false; }
|
||||
@Override
|
||||
public Vec4b x(byte x) { return this.x == x ? this : Vec4b.of(x, y, z, w); }
|
||||
@Override
|
||||
public Vec4b y(byte y) { return this.y == y ? this : Vec4b.of(x, y, z, w); }
|
||||
@Override
|
||||
public Vec4b z(byte z) { return this.z == z ? this : Vec4b.of(x, y, z, w); }
|
||||
@Override
|
||||
public Vec4b w(byte w) { return this.w == w ? this : Vec4b.of(x, y, z, w); }
|
||||
@Override
|
||||
public Vec4b copy() { return Vec4b.of(this); }
|
||||
@Override
|
||||
public Vec4b set(byte x, byte y, byte z, byte w) { return this.x == x && this.y == y && this.z == z && this.w == w ? this : Vec4b.of(x, y, z, w); }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user