Next Milestone reached.
This commit is contained in:
@@ -5,7 +5,7 @@ connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
|||||||
connection.project.dir=
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
gradle.user.home=
|
gradle.user.home=
|
||||||
java.home=C\:/Program Files/Eclipse Adoptium/jdk25
|
java.home=C\:/Program Files/Java/jdk25
|
||||||
jvm.arguments=
|
jvm.arguments=
|
||||||
offline.mode=false
|
offline.mode=false
|
||||||
override.workspace.settings=true
|
override.workspace.settings=true
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
org.gradle.jvmargs=-Xmx2G
|
org.gradle.jvmargs=-Xmx2G
|
||||||
|
|
||||||
lwjglVersion = 3.3.4
|
lwjglVersion = 3.4.2
|
||||||
lwjglNatives = natives-windows
|
lwjglNatives = natives-windows
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package speiger.src.coreengine.assets.api;
|
package speiger.src.coreengine.assets.api;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
@@ -12,7 +14,9 @@ import java.util.function.Consumer;
|
|||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.assets.impl.FolderAssetPackage;
|
||||||
import speiger.src.coreengine.assets.impl.FolderWatcher.ChangeType;
|
import speiger.src.coreengine.assets.impl.FolderWatcher.ChangeType;
|
||||||
|
import speiger.src.coreengine.assets.impl.ZipAssetPackage;
|
||||||
|
|
||||||
@NullMarked
|
@NullMarked
|
||||||
public interface IAssetPackage extends AutoCloseable {
|
public interface IAssetPackage extends AutoCloseable {
|
||||||
@@ -23,6 +27,23 @@ public interface IAssetPackage extends AutoCloseable {
|
|||||||
IAsset get(ID location);
|
IAsset get(ID location);
|
||||||
void getAll(ID folder, BiConsumer<ID, IAsset> assets);
|
void getAll(ID folder, BiConsumer<ID, IAsset> assets);
|
||||||
|
|
||||||
|
public static IAssetPackage asset(Path path) {
|
||||||
|
return create(path, "assets");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IAssetPackage create(Path path, String baseFolder) {
|
||||||
|
if(Files.exists(path)) {
|
||||||
|
if(Files.isDirectory(path)) return new FolderAssetPackage(path.resolve(baseFolder));
|
||||||
|
if(isZip(path)) return new ZipAssetPackage(path, baseFolder);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isZip(Path path) {
|
||||||
|
try(FileSystem system = FileSystems.newFileSystem(path)) { return "jar".equals(system.provider().getScheme()); }
|
||||||
|
catch(Exception _) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
public record AssetIdentity(long size, FileTime lastModified) {
|
public record AssetIdentity(long size, FileTime lastModified) {
|
||||||
|
|
||||||
public AssetIdentity(Path path) throws IOException {
|
public AssetIdentity(Path path) throws IOException {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public record ID(String domain, String path) implements Comparable<ID> {
|
|||||||
public static final ID of(String location) {
|
public static final ID of(String location) {
|
||||||
Objects.requireNonNull(location);
|
Objects.requireNonNull(location);
|
||||||
int index = location.indexOf(":");
|
int index = location.indexOf(":");
|
||||||
String domain = location.substring(0, index);
|
String domain = index == -1 ? "base" : location.substring(0, index);
|
||||||
String path = location.substring(index + 1);
|
String path = index == -1 ? location : location.substring(index + 1);
|
||||||
if(!isValidDomain(domain)) throw new IllegalArgumentException("Non [a-zA-Z0-9_.-] Character found in domain of location ["+domain+":"+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+"]");
|
if(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]");
|
||||||
return new ID(domain, path);
|
return new ID(domain, path);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class Checksums {
|
|||||||
public static class CRC implements IAssetParser<String> {
|
public static class CRC implements IAssetParser<String> {
|
||||||
@Override
|
@Override
|
||||||
public String parse(Path path) throws IOException {
|
public String parse(Path path) throws IOException {
|
||||||
Map<String, Object> files = Files.readAttributes(path, "crc");
|
Map<String, Object> files = Files.readAttributes(path, "*");
|
||||||
if(files.containsKey("crc")) return Long.toHexString(((Long)files.get("crc")) & 0xFFFFFFFFL);
|
if(files.containsKey("crc")) return Long.toHexString(((Long)files.get("crc")) & 0xFFFFFFFFL);
|
||||||
CRC32C crc = new CRC32C();
|
CRC32C crc = new CRC32C();
|
||||||
crc.update(Files.readAllBytes(path));
|
crc.update(Files.readAllBytes(path));
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ public class AssetManager {
|
|||||||
List<IAssetPackage> packages;
|
List<IAssetPackage> packages;
|
||||||
ReloadTracker tracker = new ReloadTracker();
|
ReloadTracker tracker = new ReloadTracker();
|
||||||
ReloadManager manager;
|
ReloadManager manager;
|
||||||
|
AtomicInteger InUse = new AtomicInteger();
|
||||||
|
|
||||||
public AssetManager(BaseProvider provider) {
|
public AssetManager(BaseProvider provider) {
|
||||||
setPackages(provider);
|
setPackages(provider);
|
||||||
@@ -89,21 +91,29 @@ public class AssetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IAssetProvider get() {
|
public IAssetProvider get() {
|
||||||
return new WrappedProvider(provider);
|
InUse.incrementAndGet();
|
||||||
|
return new WrappedProvider(provider, this::manageClose);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void manageClose() throws Exception {
|
||||||
|
if(InUse.decrementAndGet() > 0) return;
|
||||||
|
provider.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class WrappedProvider implements IAssetProvider {
|
public final class WrappedProvider implements IAssetProvider {
|
||||||
BaseProvider provider;
|
BaseProvider provider;
|
||||||
|
AutoCloseable closer;
|
||||||
|
|
||||||
public WrappedProvider(BaseProvider provider) {
|
public WrappedProvider(BaseProvider provider, AutoCloseable closer) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
|
this.closer = closer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
BaseProvider provider = this.provider;
|
if(provider == null) return;
|
||||||
this.provider = null;
|
this.provider = null;
|
||||||
provider.close();
|
closer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import java.util.List;
|
|||||||
import speiger.src.coreengine.assets.api.IAssetPackage;
|
import speiger.src.coreengine.assets.api.IAssetPackage;
|
||||||
import speiger.src.coreengine.assets.api.IAssetProvider;
|
import speiger.src.coreengine.assets.api.IAssetProvider;
|
||||||
|
|
||||||
public interface BaseProvider extends IAssetProvider, AutoCloseable {
|
public interface BaseProvider extends IAssetProvider {
|
||||||
List<IAssetPackage> packages();
|
List<IAssetPackage> packages();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,21 @@ public abstract class VertexBuffer implements GraphicsResource {
|
|||||||
|
|
||||||
public abstract VertexBuffer allocate(int totalBytes);
|
public abstract VertexBuffer allocate(int totalBytes);
|
||||||
public abstract VertexBuffer set(long pointer, int totalBytes);
|
public abstract VertexBuffer set(long pointer, int totalBytes);
|
||||||
public VertexBuffer set(ByteBuffer buffer) {
|
public VertexBuffer set(ByteBuffer buffer) { return set(MemoryUtil.memAddress(buffer), buffer.remaining()); }
|
||||||
return set(MemoryUtil.memAddress(buffer), buffer.remaining());
|
public VertexBuffer set(byte[] data) {
|
||||||
|
ByteBuffer buffer = MemoryUtil.memAlloc(data.length).put(data).flip();
|
||||||
|
set(buffer);
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract VertexBuffer fill(long pointer, int totalBytes, int offset);
|
public abstract VertexBuffer fill(long pointer, int totalBytes, int offset);
|
||||||
public VertexBuffer fill(int offset, ByteBuffer buffer) {
|
public VertexBuffer fill(int offset, ByteBuffer buffer) { return fill(MemoryUtil.memAddress(buffer), buffer.remaining(), offset); }
|
||||||
return fill(MemoryUtil.memAddress(buffer), buffer.remaining(), offset);
|
public VertexBuffer fill(int offset, byte[] data) {
|
||||||
|
ByteBuffer buffer = MemoryUtil.memAlloc(data.length).put(data).flip();
|
||||||
|
fill(offset, buffer);
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract VertexBuffer read(long pointer, int totalBytes, int offset);
|
public abstract VertexBuffer read(long pointer, int totalBytes, int offset);
|
||||||
|
|||||||
+6
-3
@@ -13,10 +13,13 @@ public interface GraphicsCommandBuffer extends GraphicsResource {
|
|||||||
|
|
||||||
GraphicsCommandBuffer pipeline(ShaderPipeline pipeline);
|
GraphicsCommandBuffer pipeline(ShaderPipeline pipeline);
|
||||||
GraphicsCommandBuffer mesh(Mesh mesh);
|
GraphicsCommandBuffer mesh(Mesh mesh);
|
||||||
GraphicsCommandBuffer texture(int set, int binding, Texture texture, Sampler sampler);
|
GraphicsCommandBuffer texture(int binding, Texture texture, Sampler sampler);
|
||||||
GraphicsCommandBuffer uniform(int set, int binding, VertexBuffer buffer);
|
|
||||||
|
|
||||||
GraphicsCommandBuffer drawIndexed(int start, int count);
|
GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer);
|
||||||
|
GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer, long offset, long size);
|
||||||
|
|
||||||
|
GraphicsCommandBuffer drawArrays(int offset, int count);
|
||||||
|
GraphicsCommandBuffer drawElements(int offset, int count);
|
||||||
|
|
||||||
GraphicsCommandBuffer pushScissors(int x, int y, int width, int height);
|
GraphicsCommandBuffer pushScissors(int x, int y, int width, int height);
|
||||||
GraphicsCommandBuffer popScissors();
|
GraphicsCommandBuffer popScissors();
|
||||||
|
|||||||
+9
-12
@@ -1,34 +1,31 @@
|
|||||||
package speiger.src.coreengine.graphics.api.core;
|
package speiger.src.coreengine.graphics.api.core;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.GraphicsDataType;
|
||||||
import speiger.src.coreengine.graphics.api.target.RenderTarget;
|
import speiger.src.coreengine.graphics.api.target.RenderTarget;
|
||||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
||||||
import speiger.src.coreengine.graphics.api.utils.PushableResource;
|
import speiger.src.coreengine.graphics.api.utils.PushableResource;
|
||||||
import speiger.src.coreengine.math.vector.floats.Vec4f;
|
import speiger.src.coreengine.math.vector.floats.Vec4f;
|
||||||
|
|
||||||
public interface GraphicsCommandQueue {
|
public interface GraphicsCommandQueue {
|
||||||
public static final int CLEAR_COLOR = 1;
|
public static final int CLEAR_COLOR = 1;
|
||||||
public static final int CLEAR_DEPTH = 2;
|
public static final int CLEAR_DEPTH = 2;
|
||||||
|
public static final int CLEAR_BOTH = 3;
|
||||||
public PushableResource putClearColor(Vec4f color);
|
public PushableResource putClearColor(Vec4f color);
|
||||||
public PushableResource putClearDepth(double value);
|
public PushableResource putClearDepth(double value);
|
||||||
public PushableResource putRenderTarget(RenderTarget target);
|
public PushableResource putRenderTarget(RenderTarget target);
|
||||||
|
public PushableResource pushViewPort(int x, int y, int width, int height);
|
||||||
|
|
||||||
public void clearTexture(int clearParam);
|
public void clearTexture(int clearParam);
|
||||||
public void clearTexture(int x, int y, int width, int height, 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 clearParam);
|
||||||
public void clearTexture(Texture texture, int x, int y, int width, int height, 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 writeToTexture(Texture target, TextureFormat format, GraphicsDataType dataType, long source);
|
||||||
public void readFromTexture(Texture source, int x, int y, int width, int height, long target);
|
public default void writeToTexture(Texture target, int x, int y, int width, int height, TextureFormat format, GraphicsDataType dataType, long source) {
|
||||||
|
writeToTexture(target, 0, 0, x, y, width, height, format, dataType, source);
|
||||||
|
}
|
||||||
|
public void writeToTexture(Texture target, int sourceX, int sourceY, int targetX, int targetY, int width, int height, TextureFormat format, GraphicsDataType dataType, long source);
|
||||||
|
|
||||||
public void submitCommands(GraphicsCommandBuffer buffer);
|
public void submitCommands(GraphicsCommandBuffer buffer);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,28 @@
|
|||||||
package speiger.src.coreengine.graphics.api.core;
|
package speiger.src.coreengine.graphics.api.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
||||||
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
|
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
|
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
|
||||||
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
|
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
|
||||||
import speiger.src.coreengine.rendering.input.window.Window;
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
public interface GraphicsDevice {
|
public interface GraphicsDevice {
|
||||||
public Window getWindow();
|
Window window();
|
||||||
public GraphicsSurface createSurface();
|
GraphicsSurface createSurface();
|
||||||
public GraphicsCommandBuffer createCommandBuffer(ExecutionType type);
|
GraphicsCommandBuffer createCommandBuffer(ExecutionType type);
|
||||||
public GraphicsCommandQueue getQueue();
|
GraphicsCommandQueue queue();
|
||||||
public VertexBuffer createBuffer(BufferType type, BufferState state);
|
VertexBuffer createBuffer(BufferType type, BufferState state);
|
||||||
public VertexBuffer createBuffer(BufferType type, BufferState state, int allocatedBytes);
|
VertexBuffer createBuffer(BufferType type, BufferState state, int allocatedBytes);
|
||||||
public Texture createTexture(TextureSettings data, int width, int height);
|
Texture createTexture(TextureSettings data, int width, int height);
|
||||||
public Sampler createSampler(SamplerSettings settings);
|
Sampler createSampler(SamplerSettings settings);
|
||||||
public Mesh createMesh(Mesh.Builder builder);
|
Mesh createMesh(Mesh.Builder builder);
|
||||||
|
void preloadPipelines(List<ShaderPipeline> pipelines);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ public record SamplerSettings(BorderMode wrapS, BorderMode wrapT, Optional<Borde
|
|||||||
Objects.requireNonNull(magSample);
|
Objects.requireNonNull(magSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
BorderMode wrapS;
|
BorderMode wrapS;
|
||||||
BorderMode wrapT;
|
BorderMode wrapT;
|
||||||
@@ -23,6 +27,19 @@ public record SamplerSettings(BorderMode wrapS, BorderMode wrapT, Optional<Borde
|
|||||||
SampleMode minSample;
|
SampleMode minSample;
|
||||||
SampleMode magSample;
|
SampleMode magSample;
|
||||||
|
|
||||||
|
public Builder wrap(BorderMode mode) {
|
||||||
|
return wrap(mode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder wrap(BorderMode mode, boolean includeR) {
|
||||||
|
wrapS = Objects.requireNonNull(mode);
|
||||||
|
wrapT = Objects.requireNonNull(mode);
|
||||||
|
if(includeR) {
|
||||||
|
wrapR = Objects.requireNonNull(mode);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder wrapS(BorderMode mode) {
|
public Builder wrapS(BorderMode mode) {
|
||||||
wrapS = Objects.requireNonNull(mode);
|
wrapS = Objects.requireNonNull(mode);
|
||||||
return this;
|
return this;
|
||||||
@@ -38,6 +55,13 @@ public record SamplerSettings(BorderMode wrapS, BorderMode wrapT, Optional<Borde
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder sampler(SampleMode mode) {
|
||||||
|
minSample = Objects.requireNonNull(mode);
|
||||||
|
if(mode != SampleMode.LINEAR && mode != SampleMode.NEAREST) throw new IllegalArgumentException("["+mode+"] is not supported in mag filter");
|
||||||
|
magSample = Objects.requireNonNull(mode);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder minSample(SampleMode mode) {
|
public Builder minSample(SampleMode mode) {
|
||||||
minSample = Objects.requireNonNull(mode);
|
minSample = Objects.requireNonNull(mode);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import speiger.src.coreengine.graphics.api.utils.AlphaFunction;
|
import speiger.src.coreengine.graphics.api.utils.AlphaFunction;
|
||||||
|
|
||||||
public record DepthTarget(AlphaFunction function, boolean write) {
|
public record DepthTarget(boolean enabled, AlphaFunction function, boolean write) {
|
||||||
public static final DepthTarget DEFAULT = new DepthTarget(AlphaFunction.GEQUAL, true);
|
public static final DepthTarget DEFAULT = new DepthTarget(true, AlphaFunction.GEQUAL, true);
|
||||||
|
|
||||||
public DepthTarget {
|
public DepthTarget {
|
||||||
Objects.requireNonNull(function);
|
Objects.requireNonNull(function);
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
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();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -69,13 +69,13 @@ public record ShaderPipeline(ID id, Map<ShaderType, ID> shaders, List<VertexBind
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder withUniform(String name, int binding, int set, int bytes) {
|
public Builder withUniform(String name, int binding, int slot, int bytes) {
|
||||||
uniforms.add(new UniformBinding(name, binding, set, bytes));
|
uniforms.add(new UniformBinding(name, binding, slot, bytes));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder withTexture(String name, int binding, int set, TextureType type) {
|
public Builder withTexture(String name, int binding, int slot, TextureType type) {
|
||||||
textures.add(new TextureBinding(name, binding, set, type));
|
textures.add(new TextureBinding(name, binding, slot, type));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import java.util.Objects;
|
|||||||
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
|
|
||||||
public class Bindings {
|
public class Bindings {
|
||||||
public record UniformBinding(String name, int binding, int set, int bytes) {
|
public record UniformBinding(String name, int binding, int slot, int bytes) {
|
||||||
public UniformBinding {
|
public UniformBinding {
|
||||||
Objects.requireNonNull(name, "A name has to be provided");
|
Objects.requireNonNull(name, "A name has to be provided");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record TextureBinding(String name, int binding, int set, TextureType type) {
|
public record TextureBinding(String name, int binding, int slot, TextureType type) {
|
||||||
public TextureBinding {
|
public TextureBinding {
|
||||||
Objects.requireNonNull(name, "A name has to be provided");
|
Objects.requireNonNull(name, "A name has to be provided");
|
||||||
Objects.requireNonNull(type, "A TextureType has to be provided");
|
Objects.requireNonNull(type, "A TextureType has to be provided");
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package speiger.src.coreengine.graphics.api.shader.states;
|
package speiger.src.coreengine.graphics.api.shader.states;
|
||||||
|
|
||||||
public record BlendFunction(BlendFactor colorSource, BlendFactor alphaSource, BlendFactor colorTarget, BlendFactor alphaTarget) {
|
public record BlendFunction(BlendFactor colorSource, BlendFactor alphaSource, BlendFactor colorTarget, BlendFactor alphaTarget) {
|
||||||
|
public static final BlendFunction DEFAULT = new BlendFunction(BlendFactor.ONE, BlendFactor.ZERO);
|
||||||
public BlendFunction(BlendFactor source, BlendFactor target) {
|
public BlendFunction(BlendFactor source, BlendFactor target) {
|
||||||
this(source, BlendFactor.ONE, target, BlendFactor.ZERO);
|
this(source, BlendFactor.ONE, target, BlendFactor.ZERO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package speiger.src.coreengine.graphics.api.target;
|
package speiger.src.coreengine.graphics.api.target;
|
||||||
|
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.api.ID;
|
||||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
|
|
||||||
public record TextureTarget(AssetLocation id, Texture color, Texture depth) implements RenderTarget {
|
public record TextureTarget(ID id, Texture color, Texture depth) implements RenderTarget {
|
||||||
public TextureTarget {
|
public TextureTarget {
|
||||||
if(color == null && depth == null) throw new IllegalArgumentException("At least either texture has to be nonNull");
|
if(color == null && depth == null) throw new IllegalArgumentException("At least either texture has to be nonNull");
|
||||||
if(color != null && depth != null) {
|
if(color != null && depth != null) {
|
||||||
|
|||||||
@@ -10,12 +10,11 @@ import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
|
|||||||
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
|
|
||||||
public record TextureSettings(TextureType type, TextureFormat internal, TextureFormat external, boolean generateMipmapping, OptionalInt baseLevel, OptionalInt maxLevel, ImmutableObjectList<Optional<SwizzleMask>> swizzle, Optional<StencilType> stencilType) {
|
public record TextureSettings(TextureType type, TextureFormat internal, boolean generateMipmapping, OptionalInt baseLevel, OptionalInt maxLevel, ImmutableObjectList<Optional<SwizzleMask>> swizzle, Optional<StencilType> stencilType) {
|
||||||
|
|
||||||
public TextureSettings {
|
public TextureSettings {
|
||||||
Objects.requireNonNull(type, "Texture Type shouldn't be null");
|
Objects.requireNonNull(type, "Texture Type shouldn't be null");
|
||||||
Objects.requireNonNull(internal, "Internal Format shouldn't be null");
|
Objects.requireNonNull(internal, "Internal Format shouldn't be null");
|
||||||
Objects.requireNonNull(external, "External Format shouldn't be null");
|
|
||||||
Objects.requireNonNull(baseLevel);
|
Objects.requireNonNull(baseLevel);
|
||||||
Objects.requireNonNull(maxLevel);
|
Objects.requireNonNull(maxLevel);
|
||||||
Objects.requireNonNull(swizzle);
|
Objects.requireNonNull(swizzle);
|
||||||
@@ -33,9 +32,8 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
TextureFormat internalFormat;
|
TextureFormat internalFormat = TextureFormat.RGBA;
|
||||||
TextureFormat externalFormat;
|
TextureType type = TextureType.TEXTURE_2D;
|
||||||
TextureType type;
|
|
||||||
boolean generateMipmapping = false;
|
boolean generateMipmapping = false;
|
||||||
OptionalInt baseLevel = OptionalInt.empty();
|
OptionalInt baseLevel = OptionalInt.empty();
|
||||||
OptionalInt maxLevel = OptionalInt.empty();
|
OptionalInt maxLevel = OptionalInt.empty();
|
||||||
@@ -47,7 +45,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF
|
|||||||
private Builder(TextureSettings settings) {
|
private Builder(TextureSettings settings) {
|
||||||
type = settings.type;
|
type = settings.type;
|
||||||
internalFormat = settings.internal;
|
internalFormat = settings.internal;
|
||||||
externalFormat = settings.external;
|
|
||||||
generateMipmapping = settings.generateMipmapping;
|
generateMipmapping = settings.generateMipmapping;
|
||||||
baseLevel = settings.baseLevel;
|
baseLevel = settings.baseLevel;
|
||||||
maxLevel = settings.maxLevel;
|
maxLevel = settings.maxLevel;
|
||||||
@@ -58,8 +55,7 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF
|
|||||||
public TextureSettings build() {
|
public TextureSettings build() {
|
||||||
return new TextureSettings(
|
return new TextureSettings(
|
||||||
Objects.requireNonNull(type, "Texture Type shouldn't be null"),
|
Objects.requireNonNull(type, "Texture Type shouldn't be null"),
|
||||||
Objects.requireNonNull(internalFormat, "Internal Format shouldn't be null"),
|
Objects.requireNonNull(internalFormat, "Internal Format shouldn't be null"),
|
||||||
Objects.requireNonNull(externalFormat, "External Format shouldn't be null"),
|
|
||||||
generateMipmapping, baseLevel, maxLevel, new ImmutableObjectList<>(swizzle), stencilType);
|
generateMipmapping, baseLevel, maxLevel, new ImmutableObjectList<>(swizzle), stencilType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +66,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF
|
|||||||
|
|
||||||
public Builder format(TextureFormat format) {
|
public Builder format(TextureFormat format) {
|
||||||
this.internalFormat = format;
|
this.internalFormat = format;
|
||||||
this.externalFormat = format;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,11 +74,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder external(TextureFormat format) {
|
|
||||||
this.externalFormat = format;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder swizzle(SwizzleMask red, SwizzleMask green, SwizzleMask blue, SwizzleMask alpha) {
|
public Builder swizzle(SwizzleMask red, SwizzleMask green, SwizzleMask blue, SwizzleMask alpha) {
|
||||||
swizzle[0] = Optional.ofNullable(red);
|
swizzle[0] = Optional.ofNullable(red);
|
||||||
swizzle[1] = Optional.ofNullable(green);
|
swizzle[1] = Optional.ofNullable(green);
|
||||||
|
|||||||
+18
-7
@@ -1,11 +1,22 @@
|
|||||||
package speiger.src.coreengine.graphics.api.texture.states;
|
package speiger.src.coreengine.graphics.api.texture.states;
|
||||||
|
|
||||||
public enum TextureFormat {
|
public enum TextureFormat {
|
||||||
R,
|
R(1),
|
||||||
RGB,
|
RG(2),
|
||||||
RGBA,
|
RGB(3),
|
||||||
DEPTH,
|
RGBA(4),
|
||||||
DEPTH_STENCIL,
|
DEPTH(1),
|
||||||
LUMINANCE,
|
DEPTH_STENCIL(2),
|
||||||
LUMINANCE_ALPHA
|
LUMINANCE(1),
|
||||||
|
LUMINANCE_ALPHA(2);
|
||||||
|
|
||||||
|
int components;
|
||||||
|
|
||||||
|
private TextureFormat(int components) {
|
||||||
|
this.components = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int components() {
|
||||||
|
return components;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,29 @@
|
|||||||
package speiger.src.coreengine.graphics.api.utils;
|
package speiger.src.coreengine.graphics.api.utils;
|
||||||
|
|
||||||
import org.lwjgl.opengl.GL11;
|
import java.util.Objects;
|
||||||
|
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
import speiger.src.collections.utils.Stack;
|
import speiger.src.collections.utils.Stack;
|
||||||
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
|
|
||||||
public class ScissorsManager {
|
public class ScissorsManager {
|
||||||
|
IScissorsHandler handler;
|
||||||
Stack<Vec4i> stack = new ObjectArrayList<>();
|
Stack<Vec4i> stack = new ObjectArrayList<>();
|
||||||
|
boolean withRoot = false;
|
||||||
int limit;
|
int limit;
|
||||||
|
|
||||||
public ScissorsManager(int limit) {
|
public ScissorsManager(int limit, IScissorsHandler handler) {
|
||||||
if(limit <= 0) throw new IllegalStateException("Limit is negative");
|
if(limit <= 0) throw new IllegalStateException("Limit is negative");
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
|
this.handler = Objects.requireNonNull(handler, "Handler is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoot(int x, int y, int width, int height) {
|
||||||
|
if(stack.size() > 0) throw new IllegalStateException("A Root can't be set if the Stack is already in use or the root is already set");
|
||||||
|
withRoot = true;
|
||||||
|
stack.push(Vec4i.of(x, y, x + width, y + height));
|
||||||
|
handler.enable();
|
||||||
|
handler.apply(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void push(int x, int y, int width, int height) {
|
public void push(int x, int y, int width, int height) {
|
||||||
@@ -22,12 +33,18 @@ public class ScissorsManager {
|
|||||||
}
|
}
|
||||||
if(stack.isEmpty()) {
|
if(stack.isEmpty()) {
|
||||||
stack.push(Vec4i.of(x, y, x + width, y + height));
|
stack.push(Vec4i.of(x, y, x + width, y + height));
|
||||||
GL11.glEnable(GL11.GL_SCISSOR_TEST);
|
handler.enable();
|
||||||
GL11.glScissor(x, y, width, height);
|
handler.apply(x, y, width, height);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Vec4i top = stack.top();
|
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())));
|
Vec4i result = Vec4i.of(Math.max(x, top.x()), Math.max(y, top.y()), Math.min(x + width, top.z()), Math.min(y + height, top.w()));
|
||||||
|
stack.push(result);
|
||||||
|
handler.apply(result.x(), result.y(), result.z() - result.x(), result.w() - result.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec4i top() {
|
||||||
|
return stack.isEmpty() ? Vec4i.MINUS_ONE : stack.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(int x, int y, int width, int height) {
|
public boolean contains(int x, int y, int width, int height) {
|
||||||
@@ -39,14 +56,39 @@ public class ScissorsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void pop() {
|
public void pop() {
|
||||||
if(stack.isEmpty()) {
|
if(stack.size() <= (withRoot ? 1 : 0)) {
|
||||||
//TODO implement logging
|
//TODO implement logging
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
if(stack.isEmpty()) {
|
||||||
|
handler.disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec4i result = stack.top();
|
||||||
|
handler.apply(result.x(), result.y(), result.z() - result.x(), result.w() - result.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
withRoot = false;
|
||||||
|
handler.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface IScissorsHandler {
|
||||||
|
public void enable();
|
||||||
|
public void disable();
|
||||||
|
public void apply(int x, int y, int width, int height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoOp implements IScissorsHandler {
|
||||||
|
public static final IScissorsHandler INSTANCE = new NoOp();
|
||||||
|
@Override
|
||||||
|
public void enable() {}
|
||||||
|
@Override
|
||||||
|
public void disable() {}
|
||||||
|
@Override
|
||||||
|
public void apply(int x, int y, int width, int height) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class VertexLayout implements ObjectIterable<Element> {
|
|||||||
private void add(Element element) {
|
private void add(Element element) {
|
||||||
if(mapped.put(element.name(), element) != null) throw new IllegalStateException("Duplicated Names are not allowed");
|
if(mapped.put(element.name(), element) != null) throw new IllegalStateException("Duplicated Names are not allowed");
|
||||||
elements.add(element);
|
elements.add(element);
|
||||||
offsets.add(stride);
|
offsets.add(bytes);
|
||||||
int size = element.size();
|
int size = element.size();
|
||||||
stride += size;
|
stride += size;
|
||||||
bytes += element.type().size(size);
|
bytes += element.type().size(size);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class GLVertexBuffer extends VertexBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int id() {
|
public int id() {
|
||||||
|
if(id == 0) throw new IllegalStateException("Buffer is already removed");
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,24 @@ import org.lwjgl.opengl.GL11;
|
|||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
import org.lwjgl.opengl.GL45;
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.api.ID;
|
||||||
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
||||||
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue;
|
import speiger.src.coreengine.graphics.api.core.GraphicsCommandQueue;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.GraphicsDataType;
|
||||||
import speiger.src.coreengine.graphics.api.target.RenderTarget;
|
import speiger.src.coreengine.graphics.api.target.RenderTarget;
|
||||||
import speiger.src.coreengine.graphics.api.target.ScreenTarget;
|
import speiger.src.coreengine.graphics.api.target.ScreenTarget;
|
||||||
import speiger.src.coreengine.graphics.api.target.TextureTarget;
|
import speiger.src.coreengine.graphics.api.target.TextureTarget;
|
||||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
||||||
import speiger.src.coreengine.graphics.api.utils.PushableResource;
|
import speiger.src.coreengine.graphics.api.utils.PushableResource;
|
||||||
import speiger.src.coreengine.graphics.opengl.texture.FrameBufferCache;
|
import speiger.src.coreengine.graphics.opengl.texture.FrameBufferCache;
|
||||||
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
|
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLStates;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.ViewPortStack;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.ScissorState;
|
||||||
import speiger.src.coreengine.math.vector.floats.Vec4f;
|
import speiger.src.coreengine.math.vector.floats.Vec4f;
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
import speiger.src.coreengine.rendering.input.window.Window;
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
public class GLCommandQueue implements GraphicsCommandQueue {
|
public class GLCommandQueue implements GraphicsCommandQueue {
|
||||||
@@ -25,12 +32,14 @@ public class GLCommandQueue implements GraphicsCommandQueue {
|
|||||||
FrameBufferCache fboCache = new FrameBufferCache();
|
FrameBufferCache fboCache = new FrameBufferCache();
|
||||||
RenderTarget renderTarget = ScreenTarget.INSTANCE;
|
RenderTarget renderTarget = ScreenTarget.INSTANCE;
|
||||||
ScreenBuffer targetFBO;
|
ScreenBuffer targetFBO;
|
||||||
|
int tempWriteFBO;
|
||||||
Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F);
|
Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F);
|
||||||
double clearDepth = 0D;
|
double clearDepth = 0D;
|
||||||
|
|
||||||
public GLCommandQueue(GLGraphicsDevice device) {
|
public GLCommandQueue(GLGraphicsDevice device) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
this.targetFBO = new ScreenBuffer(0, device.getWindow().width(), device.getWindow().height());
|
this.targetFBO = new ScreenBuffer(0, device.window().width(), device.window().height());
|
||||||
|
tempWriteFBO = GL45.glCreateFramebuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -48,6 +57,22 @@ public class GLCommandQueue implements GraphicsCommandQueue {
|
|||||||
return new PushableObject<>(renderTarget, setRenderTarget(target), () -> renderTarget, this::setRenderTarget);
|
return new PushableObject<>(renderTarget, setRenderTarget(target), () -> renderTarget, this::setRenderTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PushableResource pushViewPort(int x, int y, int width, int height) {
|
||||||
|
ViewPortStack stack = device.states.viewPort;
|
||||||
|
Vec4i top = stack.top();
|
||||||
|
Vec4i bounds = Vec4i.of(x, y, height, width);
|
||||||
|
stack.push(x, y, width, height);
|
||||||
|
return new PushableObject<>(top, bounds, stack::top, _ -> stack.pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void submitCommands(GraphicsCommandBuffer buffer) {
|
||||||
|
if(buffer instanceof GLRecordingCommandBuffer recorder) {
|
||||||
|
recorder.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Vec4f setClearColor(Vec4f value) {
|
private Vec4f setClearColor(Vec4f value) {
|
||||||
if(clearColor.equals(value)) return value;
|
if(clearColor.equals(value)) return value;
|
||||||
clearColor.set(value);
|
clearColor.set(value);
|
||||||
@@ -67,10 +92,10 @@ public class GLCommandQueue implements GraphicsCommandQueue {
|
|||||||
this.renderTarget = target;
|
this.renderTarget = target;
|
||||||
targetFBO = switch(target) {
|
targetFBO = switch(target) {
|
||||||
case ScreenTarget _ -> {
|
case ScreenTarget _ -> {
|
||||||
Window window = device.getWindow();
|
Window window = device.window();
|
||||||
yield new ScreenBuffer(0, window.width(), window.height());
|
yield new ScreenBuffer(0, window.width(), window.height());
|
||||||
}
|
}
|
||||||
case TextureTarget(AssetLocation id, Texture color, Texture depth) -> {
|
case TextureTarget(ID id, Texture color, Texture depth) -> {
|
||||||
int fbo = fboCache.getOrCreateFBO(id);
|
int fbo = fboCache.getOrCreateFBO(id);
|
||||||
if(color != null) {
|
if(color != null) {
|
||||||
GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
|
GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0);
|
||||||
@@ -90,26 +115,61 @@ public class GLCommandQueue implements GraphicsCommandQueue {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearTexture(int clearParam) {
|
public void clearTexture(int clearParam) {
|
||||||
|
GL11.glClear(((clearParam & CLEAR_COLOR) != 0 ? GL11.GL_COLOR_BUFFER_BIT : 0) | ((clearParam & CLEAR_DEPTH) != 0 ? GL11.GL_DEPTH_BUFFER_BIT : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearTexture(int x, int y, int width, int height, int clearParam) {
|
public void clearTexture(int x, int y, int width, int height, int clearParam) {
|
||||||
|
ScissorState state = device.states.scissors;
|
||||||
|
state.backup();
|
||||||
|
try(PushableResource _ = pushViewPort(0, 0, targetFBO.width(), targetFBO.height())) {
|
||||||
|
state.set(Vec4i.of(x, y, x + width, y + height));
|
||||||
|
clearTexture(clearParam);
|
||||||
|
}
|
||||||
|
state.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearTexture(Texture texture, int clearParam) {
|
public void clearTexture(Texture texture, int clearParam) {
|
||||||
|
if((clearParam & CLEAR_BOTH) == CLEAR_BOTH) {
|
||||||
|
//TODO implement Logging
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, tempWriteFBO);
|
||||||
|
GL45.glNamedFramebufferTexture(tempWriteFBO, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)texture).id(), 0);
|
||||||
|
clearTexture(clearParam);
|
||||||
|
GL45.glNamedFramebufferTexture(tempWriteFBO, GL30.GL_COLOR_ATTACHMENT0, 0, 0);
|
||||||
|
GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, targetFBO.fbo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam) {
|
public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam) {
|
||||||
|
ScissorState state = device.states.scissors;
|
||||||
|
state.backup();
|
||||||
|
try(PushableResource _ = pushViewPort(x, y, texture.width(), texture.height())) {
|
||||||
|
state.set(Vec4i.of(x, y, x + width, y + height));
|
||||||
|
clearTexture(texture, clearParam);
|
||||||
|
}
|
||||||
|
state.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToTexture(Texture target, int x, int y, int width, int height, long source) {
|
public void writeToTexture(Texture target, TextureFormat format, GraphicsDataType dataType, long source) {
|
||||||
|
GL45.glTextureSubImage2D(((GLTexture)target).id(), 0, 0, 0, target.width(), target.height(), GLUtils.toGLExternal(format), GLUtils.toGL(dataType), source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFromTexture(Texture source, int x, int y, int width, int height, long target) {
|
public void writeToTexture(Texture target, int sourceX, int sourceY, int targetX, int targetY, int width, int height, TextureFormat format, GraphicsDataType dataType, long source) {
|
||||||
|
GLStates states = device.states;
|
||||||
|
states.unpack_alignment.set(target.settings().internal().components());
|
||||||
|
states.unpack_row_length.set(target.width());
|
||||||
|
states.unpack_skip_pixel.set(sourceX);
|
||||||
|
states.unpack_skip_rows.set(sourceY);
|
||||||
|
GL45.glTextureSubImage2D(((GLTexture)target).id(), 0, targetX, targetY, width, height, GLUtils.toGLExternal(format), GLUtils.toGL(dataType), source);
|
||||||
|
states.unpack_alignment.setDefault();
|
||||||
|
states.unpack_row_length.setDefault();
|
||||||
|
states.unpack_skip_pixel.setDefault();
|
||||||
|
states.unpack_skip_rows.setDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
private record PushableObject<T>(T original, T applying, Supplier<T> current, Consumer<T> apply) implements PushableResource {
|
private record PushableObject<T>(T original, T applying, Supplier<T> current, Consumer<T> apply) implements PushableResource {
|
||||||
@@ -122,9 +182,4 @@ public class GLCommandQueue implements GraphicsCommandQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private record ScreenBuffer(int fbo, int width, int height) {}
|
private record ScreenBuffer(int fbo, int width, int height) {}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void submitCommands(GraphicsCommandBuffer buffer) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
package speiger.src.coreengine.graphics.opengl.core;
|
package speiger.src.coreengine.graphics.opengl.core;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.opengl.GL;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.assets.manager.AssetManager;
|
||||||
import speiger.src.coreengine.graphics.api.core.Graphics;
|
import speiger.src.coreengine.graphics.api.core.Graphics;
|
||||||
import speiger.src.coreengine.rendering.input.window.Window;
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
public class GLGraphics implements Graphics {
|
public class GLGraphics implements Graphics {
|
||||||
|
AssetManager manager;
|
||||||
|
|
||||||
|
public GLGraphics(AssetManager manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "OpenGL";
|
return "OpenGL";
|
||||||
@@ -14,6 +21,9 @@ public class GLGraphics implements Graphics {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setupWindowArguments() {
|
public void setupWindowArguments() {
|
||||||
|
GLFW.glfwDefaultWindowHints();
|
||||||
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||||||
|
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
||||||
@@ -22,7 +32,7 @@ public class GLGraphics implements Graphics {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GLGraphicsDevice createDevice(Window window) {
|
public GLGraphicsDevice createDevice(Window window) {
|
||||||
return new GLGraphicsDevice(window);
|
return new GLGraphicsDevice(window, manager, GL.createCapabilities());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+205
-6
@@ -1,19 +1,41 @@
|
|||||||
package speiger.src.coreengine.graphics.opengl.core;
|
package speiger.src.coreengine.graphics.opengl.core;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
|
import java.util.function.IntPredicate;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
import org.lwjgl.opengl.GL12;
|
import org.lwjgl.opengl.GL12;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
import org.lwjgl.opengl.GL31;
|
||||||
import org.lwjgl.opengl.GL33;
|
import org.lwjgl.opengl.GL33;
|
||||||
|
import org.lwjgl.opengl.GL41;
|
||||||
import org.lwjgl.opengl.GL43;
|
import org.lwjgl.opengl.GL43;
|
||||||
import org.lwjgl.opengl.GL45;
|
import org.lwjgl.opengl.GL45;
|
||||||
|
import org.lwjgl.opengl.GL46;
|
||||||
|
import org.lwjgl.opengl.GLCapabilities;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import speiger.src.collections.ints.lists.IntArrayList;
|
||||||
|
import speiger.src.collections.ints.lists.IntList;
|
||||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectLinkedOpenHashMap;
|
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectLinkedOpenHashMap;
|
||||||
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
||||||
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
||||||
|
import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap;
|
||||||
|
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||||
|
import speiger.src.collections.objects.maps.interfaces.Object2IntMap;
|
||||||
|
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
|
||||||
|
import speiger.src.collections.objects.utils.ObjectIterables;
|
||||||
|
import speiger.src.coreengine.assets.api.IAsset;
|
||||||
import speiger.src.coreengine.assets.api.IAssetProvider;
|
import speiger.src.coreengine.assets.api.IAssetProvider;
|
||||||
|
import speiger.src.coreengine.assets.api.ID;
|
||||||
|
import speiger.src.coreengine.assets.api.MultiAsset;
|
||||||
|
import speiger.src.coreengine.assets.manager.AssetManager;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
||||||
@@ -22,30 +44,50 @@ import speiger.src.coreengine.graphics.api.core.GraphicsDevice;
|
|||||||
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
||||||
import speiger.src.coreengine.graphics.api.mesh.Mesh.LayoutInfo;
|
import speiger.src.coreengine.graphics.api.mesh.Mesh.LayoutInfo;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
|
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.BufferAttribute;
|
||||||
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.VertexBinding;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.Bindings.TextureBinding;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.Bindings.UniformBinding;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.ShaderType;
|
||||||
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
|
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
|
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
|
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
|
||||||
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
|
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
|
||||||
import speiger.src.coreengine.graphics.opengl.mesh.GLMesh;
|
import speiger.src.coreengine.graphics.opengl.mesh.GLMesh;
|
||||||
import speiger.src.coreengine.graphics.opengl.sampler.GLSampler;
|
import speiger.src.coreengine.graphics.opengl.sampler.GLSampler;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderCache;
|
||||||
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance;
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance.SamplerObject;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance.ShaderStorage;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderInstance.UniformObject;
|
||||||
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
|
import speiger.src.coreengine.graphics.opengl.texture.GLTexture;
|
||||||
import speiger.src.coreengine.graphics.opengl.utils.GLFunctions;
|
import speiger.src.coreengine.graphics.opengl.utils.GLFunctions;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLStates;
|
||||||
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
import speiger.src.coreengine.rendering.input.window.Window;
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
|
||||||
public class GLGraphicsDevice implements GraphicsDevice {
|
public class GLGraphicsDevice implements GraphicsDevice {
|
||||||
|
static final Map<ID, String> IMPORTS = Object2ObjectMap.builder().<ID, String>map().synchronize();
|
||||||
|
Object2IntMap<ID> shaderCache = new Object2IntOpenHashMap<>();
|
||||||
|
Object2ObjectMap<ID, ShaderInstance> programCache = new Object2ObjectOpenHashMap<>();
|
||||||
|
AssetManager manager;
|
||||||
|
GLCapabilities capabilities;
|
||||||
|
GLStates states = new GLStates();
|
||||||
|
ShaderCache cache = new ShaderCache();
|
||||||
GLCommandQueue queue;
|
GLCommandQueue queue;
|
||||||
Window owner;
|
Window owner;
|
||||||
|
|
||||||
public GLGraphicsDevice(Window owner) {
|
public GLGraphicsDevice(Window owner, AssetManager manager, GLCapabilities capbilities) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
this.manager = manager;
|
||||||
|
this.capabilities = capbilities;
|
||||||
this.queue = new GLCommandQueue(this);
|
this.queue = new GLCommandQueue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Window getWindow() {
|
public Window window() {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,11 +98,11 @@ public class GLGraphicsDevice implements GraphicsDevice {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer createCommandBuffer(ExecutionType type) {
|
public GraphicsCommandBuffer createCommandBuffer(ExecutionType type) {
|
||||||
return null;
|
return type == ExecutionType.IMMEDIATE ? new GLImmidateCommandBuffer(this) : new GLRecordingCommandBuffer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GLCommandQueue getQueue() {
|
public GLCommandQueue queue() {
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +121,7 @@ public class GLGraphicsDevice implements GraphicsDevice {
|
|||||||
public GLTexture createTexture(TextureSettings settings, int width, int height) {
|
public GLTexture createTexture(TextureSettings settings, int width, int height) {
|
||||||
if(width < 0) throw new IllegalArgumentException("Width ["+width+"] is invalid");
|
if(width < 0) throw new IllegalArgumentException("Width ["+width+"] is invalid");
|
||||||
if(height < 0) throw new IllegalArgumentException("Height ["+height+"] is invalid");
|
if(height < 0) throw new IllegalArgumentException("Height ["+height+"] is invalid");
|
||||||
|
if(settings.type() != TextureType.TEXTURE_2D) throw new IllegalStateException("Currently only 2D textures are supported");
|
||||||
int id = GLFunctions.createTexture(settings.type());
|
int id = GLFunctions.createTexture(settings.type());
|
||||||
settings.stencilType().ifPresent(T -> GL45.glTextureParameteri(id, GL43.GL_DEPTH_STENCIL_TEXTURE_MODE, GLUtils.toGL(T)));
|
settings.stencilType().ifPresent(T -> GL45.glTextureParameteri(id, GL43.GL_DEPTH_STENCIL_TEXTURE_MODE, GLUtils.toGL(T)));
|
||||||
settings.baseLevel().ifPresent(T -> GL45.glTextureParameteri(id, GL12.GL_TEXTURE_BASE_LEVEL, T));
|
settings.baseLevel().ifPresent(T -> GL45.glTextureParameteri(id, GL12.GL_TEXTURE_BASE_LEVEL, T));
|
||||||
@@ -92,6 +135,7 @@ public class GLGraphicsDevice implements GraphicsDevice {
|
|||||||
GLUtils.toGL(masks.get(3).orElse(SwizzleMask.ALPHA)),
|
GLUtils.toGL(masks.get(3).orElse(SwizzleMask.ALPHA)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
GL45.glTextureStorage2D(id, 1, GLUtils.toGLInternal(settings.internal()), width, height);
|
||||||
return new GLTexture(settings, id, width, height);
|
return new GLTexture(settings, id, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +160,162 @@ public class GLGraphicsDevice implements GraphicsDevice {
|
|||||||
return new GLMesh(builder.info(), new Int2ObjectOpenHashMap<>(), null, null, false);
|
return new GLMesh(builder.info(), new Int2ObjectOpenHashMap<>(), null, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShaderInstance createShader(ShaderPipeline line, IAssetProvider provider) {
|
@Override
|
||||||
return null;
|
public void preloadPipelines(List<ShaderPipeline> pipelines) {
|
||||||
|
try(IAssetProvider provider = manager.get()) {
|
||||||
|
for(ShaderPipeline pipeline : pipelines) {
|
||||||
|
computeShaderProgram(pipeline, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderInstance getShader(ShaderPipeline pipeline) {
|
||||||
|
return programCache.supplyIfAbsent(pipeline.id(), () -> computeShaderProgram(pipeline));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShaderInstance computeShaderProgram(ShaderPipeline pipeline) {
|
||||||
|
try(IAssetProvider provider = manager.get()) {
|
||||||
|
return computeShaderProgram(pipeline, provider);
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShaderInstance computeShaderProgram(ShaderPipeline pipeline, IAssetProvider provider) {
|
||||||
|
MultiAsset assets = MultiAsset.combineNonNull(provider, pipeline.shaders().values().toArray(ID[]::new));
|
||||||
|
if(assets == null) {
|
||||||
|
//TODO log stuff
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int program = loadOrCreateProgram(pipeline, assets, T -> {
|
||||||
|
Map<ID, IAsset> map = Object2ObjectMap.builder().map();
|
||||||
|
assets.forEach(map, (K, V) -> K.put(V.location(), V));
|
||||||
|
IntList shaders = new IntArrayList();
|
||||||
|
for(Entry<ShaderType, ID> entry : pipeline.shaders().entrySet()) {
|
||||||
|
ShaderType type = entry.getKey();
|
||||||
|
IAsset asset = map.get(entry.getValue());
|
||||||
|
int id = shaderCache.computeIfAbsent(entry.getValue(), E -> computeShader(E, asset, type, provider));
|
||||||
|
if(id == -1) {
|
||||||
|
System.out.println("Couldn't create a shader. Type["+type+"], of Id["+asset.location()+"]");
|
||||||
|
//TODO implement logging.
|
||||||
|
//Failed to compile shader
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
GL20.glAttachShader(T, id);
|
||||||
|
}
|
||||||
|
for(BufferAttribute attribute : ObjectIterables.flatMap(pipeline.attributes(), VertexBinding::attributes)) {
|
||||||
|
GL20.glBindAttribLocation(T, attribute.index(), attribute.name());
|
||||||
|
}
|
||||||
|
GL20.glLinkProgram(T);
|
||||||
|
for(int i = 0,m=shaders.size();i<m;i++) {
|
||||||
|
GL20.glDetachShader(T, shaders.getInt(i));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if(program == 0) return null;
|
||||||
|
ShaderStorage<UniformObject> uniforms = new ShaderStorage<>();
|
||||||
|
ShaderStorage<SamplerObject> samplers = new ShaderStorage<>();
|
||||||
|
for(TextureBinding binding : pipeline.textures()) {
|
||||||
|
int location = GL20.glGetUniformLocation(program, binding.name());
|
||||||
|
if(location == -1) {
|
||||||
|
System.out.println("Couldn't find Location ["+binding.name()+"] in Program ["+program+"]");
|
||||||
|
//TODO Warn that location wasn't found
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
samplers.add(binding.name(), binding.slot(), new SamplerObject(binding.slot()));
|
||||||
|
}
|
||||||
|
for(UniformBinding binding : pipeline.uniforms()) {
|
||||||
|
int location = GL31.glGetUniformBlockIndex(program, binding.name());
|
||||||
|
if(location == GL31.GL_INVALID_INDEX) {
|
||||||
|
System.out.println("Couldn't find Location ["+binding.name()+"] in Program ["+program+"]");
|
||||||
|
|
||||||
|
//TODO Warn that location wasn't found
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uniforms.add(binding.name(), binding.slot(), new UniformObject(binding.slot()));
|
||||||
|
}
|
||||||
|
ShaderInstance instance = new ShaderInstance(program, uniforms, samplers);
|
||||||
|
states.shaders.register(instance);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int computeShader(ID id, IAsset asset, ShaderType type, IAssetProvider provider) {
|
||||||
|
StringBuilder builder = new StringBuilder(2048);
|
||||||
|
try {
|
||||||
|
for(String line : asset.lines()) {
|
||||||
|
if(line.startsWith("//")) continue;
|
||||||
|
if(line.startsWith("#import<") && line.endsWith(">")) builder.append(importLines(provider, ID.of(line.substring(8, line.length()-1))));
|
||||||
|
else builder.append(line);
|
||||||
|
builder.append("\n");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int shader = GL20.glCreateShader(GLUtils.toGL(type));
|
||||||
|
GL20.glShaderSource(shader, builder);
|
||||||
|
GL20.glCompileShader(shader);
|
||||||
|
if(GL20.glGetShaderi(shader, GL20.GL_COMPILE_STATUS) == 0) {
|
||||||
|
//TODO improve logging
|
||||||
|
System.out.println(GL20.glGetShaderInfoLog(shader, GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH)));
|
||||||
|
GL20.glDeleteShader(shader);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int loadOrCreateProgram(ShaderPipeline pipeline, MultiAsset assets, IntPredicate callback) {
|
||||||
|
int id = GL20.glCreateProgram();
|
||||||
|
boolean fail = true;
|
||||||
|
if((fail = !loadFromCache(id, pipeline, assets) && callback.test(id))) {
|
||||||
|
if(GL20.glGetProgrami(id, GL20.GL_LINK_STATUS) == GL11.GL_TRUE) {
|
||||||
|
cache.store(pipeline.id(), assets.crc(), getProgramBytes(id));
|
||||||
|
fail = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fail) {
|
||||||
|
GL20.glDeleteProgram(id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String error = GL20.glGetProgramInfoLog(id);
|
||||||
|
if(!error.isBlank()) {
|
||||||
|
System.out.println("Error: "+error);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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));
|
||||||
|
buffer.putInt(0, format[0]).flip();
|
||||||
|
byte[] data = new byte[buffer.remaining()];
|
||||||
|
buffer.get(data);
|
||||||
|
MemoryUtil.memFree(buffer);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean loadFromCache(int programId, ShaderPipeline pipeline, MultiAsset asset) {
|
||||||
|
ByteBuffer data = cache.get(pipeline.id(), asset::crc);
|
||||||
|
if(data == null) return false;
|
||||||
|
GL41.glProgramBinary(programId, data.getInt(), data);
|
||||||
|
MemoryUtil.memFree(data);
|
||||||
|
return GL46.glGetProgrami(programId, GL46.GL_LINK_STATUS) == GL46.GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String importLines(IAssetProvider provider, ID location) {
|
||||||
|
return IMPORTS.computeIfAbsent(location, T -> {
|
||||||
|
try { return ObjectIterables.filter(provider.get(T).lines(), E -> !E.startsWith("//")).reduce(new StringBuilder(), (K, V) -> K.append(V).append("\n")).toString(); }
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+132
-11
@@ -1,85 +1,206 @@
|
|||||||
package speiger.src.coreengine.graphics.opengl.core;
|
package speiger.src.coreengine.graphics.opengl.core;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
import org.lwjgl.opengl.GL31;
|
||||||
|
import org.lwjgl.opengl.GL33;
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||||
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
||||||
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ColorTarget;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.DepthTarget;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.RasterizerState;
|
||||||
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||||
import speiger.src.coreengine.graphics.api.texture.Texture;
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.ScissorsManager;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.mesh.GLMesh;
|
||||||
|
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.GLScissorsHandler;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLStates;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
|
|
||||||
public class GLImmidateCommandBuffer implements GraphicsCommandBuffer {
|
public class GLImmidateCommandBuffer implements GraphicsCommandBuffer {
|
||||||
|
GLGraphicsDevice device;
|
||||||
|
boolean removed = false;
|
||||||
boolean recording = false;
|
boolean recording = false;
|
||||||
ShaderPipeline pipeline;
|
|
||||||
Mesh mesh;
|
|
||||||
int recorded = 0;
|
int recorded = 0;
|
||||||
|
|
||||||
|
ScissorsManager scissors;
|
||||||
|
ShaderPipeline pipeline;
|
||||||
|
ShaderInstance shader;
|
||||||
|
GLMesh mesh;
|
||||||
|
|
||||||
|
public GLImmidateCommandBuffer(GLGraphicsDevice device) {
|
||||||
|
this.device = device;
|
||||||
|
this.scissors = new ScissorsManager(8, new GLScissorsHandler(device.states));
|
||||||
|
}
|
||||||
|
|
||||||
protected void ensureDrawing() {
|
protected void ensureDrawing() {
|
||||||
|
if(removed) throw new IllegalStateException("CommandBuffer is removed");
|
||||||
if(!recording) throw new IllegalStateException("CommandBuffer isn't recording");
|
if(!recording) throw new IllegalStateException("CommandBuffer isn't recording");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRemoved() { return false; }
|
public boolean isRemoved() { return removed; }
|
||||||
@Override
|
@Override
|
||||||
public void remove() {}
|
public void remove() {
|
||||||
|
clear();
|
||||||
|
device = null;
|
||||||
|
removed = true;
|
||||||
|
recorded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer begin() {
|
public GraphicsCommandBuffer begin() {
|
||||||
|
if(removed) throw new IllegalStateException("CommandBuffer is removed");
|
||||||
if(recording) throw new IllegalStateException("CommandBuffer already recording");
|
if(recording) throw new IllegalStateException("CommandBuffer already recording");
|
||||||
recording = true;
|
recording = true;
|
||||||
|
recorded = 0;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer setScissors(int x, int y, int width, int height) {
|
public GraphicsCommandBuffer setScissors(int x, int y, int width, int height) {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.setRoot(x, y, width, height);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer pipeline(ShaderPipeline pipeline) {
|
public GraphicsCommandBuffer pipeline(ShaderPipeline pipeline) {
|
||||||
|
Objects.requireNonNull(pipeline);
|
||||||
|
ensureDrawing();
|
||||||
|
if(this.pipeline == pipeline) return this;
|
||||||
this.pipeline = pipeline;
|
this.pipeline = pipeline;
|
||||||
|
shader = device.getShader(pipeline);
|
||||||
|
if(shader == null) {
|
||||||
|
//TODO implement logging
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
GLStates states = device.states;
|
||||||
|
states.shaders.bind(shader);
|
||||||
|
RasterizerState rasterization = pipeline.rasterizer();
|
||||||
|
states.polygon.set(rasterization.fillMode());
|
||||||
|
states.backCulling.set(rasterization.cullBack());
|
||||||
|
DepthTarget depth = pipeline.depthTarget();
|
||||||
|
if(depth.enabled()) {
|
||||||
|
states.depth.enable();
|
||||||
|
states.setDepthMask(depth.write());
|
||||||
|
states.setDepthFunction(depth.function());
|
||||||
|
}
|
||||||
|
else states.depth.disable();
|
||||||
|
ColorTarget color = pipeline.colorTarget();
|
||||||
|
color.blend().ifPresentOrElse(states.blend::enableSet, states.blend::disable);
|
||||||
|
states.setColorMask(color.writeMask());
|
||||||
|
recorded++;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer mesh(Mesh mesh) {
|
public GraphicsCommandBuffer mesh(Mesh mesh) {
|
||||||
this.mesh = mesh;
|
Objects.requireNonNull(mesh);
|
||||||
|
ensureDrawing();
|
||||||
|
if(this.mesh == mesh) return this;
|
||||||
|
this.mesh = (GLMesh)mesh;
|
||||||
|
this.mesh.bind();
|
||||||
|
// GL30.glBindVertexArray(this.mesh.id());
|
||||||
|
recorded++;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer texture(int set, int binding, Texture texture, Sampler sampler) {
|
public GraphicsCommandBuffer texture(int binding, Texture texture, Sampler sampler) {
|
||||||
|
Objects.requireNonNull(texture);
|
||||||
|
Objects.requireNonNull(sampler);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.samplers().byIndex(binding), "Texture["+binding+"] binding not found");
|
||||||
|
// GLStates states = device.states;
|
||||||
|
GL45.glBindTextureUnit(binding, ((GLTexture)texture).id());
|
||||||
|
GL33.glBindSampler(binding, ((GLSampler)sampler).id());
|
||||||
|
// states.textures.bind(binding, ((GLTexture)texture).id());
|
||||||
|
// states.samplers.bind(binding, ((GLSampler)sampler).id());
|
||||||
|
recorded++;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer uniform(int set, int binding, VertexBuffer buffer) {
|
public GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer) {
|
||||||
|
Objects.requireNonNull(buffer);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.uniforms().byIndex(binding), "Uniform for binding ["+binding+"] doesn't exist");
|
||||||
|
GL30.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, binding, ((GLVertexBuffer)buffer).id());
|
||||||
|
recorded++;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer, long offset, long size) {
|
||||||
|
Objects.requireNonNull(buffer);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.uniforms().byIndex(binding), "Uniform for binding ["+binding+"] doesn't exist");
|
||||||
|
GL30.glBindBufferRange(GL31.GL_UNIFORM_BUFFER, binding, ((GLVertexBuffer)buffer).id(), offset, size);
|
||||||
|
recorded++;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer drawIndexed(int start, int count) {
|
public GraphicsCommandBuffer drawArrays(int offset, int count) {
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
GL11.glDrawArrays(GLUtils.toGL(pipeline.rasterizer().mode()), offset, count);
|
||||||
|
recorded++;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer drawElements(int offset, int count) {
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
GL11.nglDrawElements(GLUtils.toGL(pipeline.rasterizer().mode()), count, GLUtils.toGL(mesh.indeciesType()), offset);
|
||||||
|
recorded++;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer pushScissors(int x, int y, int width, int height) {
|
public GraphicsCommandBuffer pushScissors(int x, int y, int width, int height) {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.push(x, y, width, height);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer popScissors() {
|
public GraphicsCommandBuffer popScissors() {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.pop();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GraphicsCommandBuffer end() {
|
public GraphicsCommandBuffer end() {
|
||||||
if(!recording) throw new IllegalStateException("Already Stopped Recording");
|
if(!recording) throw new IllegalStateException("Already Stopped Recording");
|
||||||
pipeline = null;
|
clear();
|
||||||
mesh = null;
|
|
||||||
recording = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void clear() {
|
||||||
|
recording = false;
|
||||||
|
pipeline = null;
|
||||||
|
shader = null;
|
||||||
|
mesh = null;
|
||||||
|
scissors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int commandCount() { return recorded; }
|
public int commandCount() { return recorded; }
|
||||||
}
|
}
|
||||||
|
|||||||
+239
@@ -0,0 +1,239 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.core;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
import org.lwjgl.opengl.GL31;
|
||||||
|
|
||||||
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||||
|
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
|
||||||
|
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
||||||
|
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
||||||
|
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ColorTarget;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.DepthTarget;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.RasterizerState;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.DrawMode;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.ScissorsManager;
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.ScissorsManager.NoOp;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.buffer.GLVertexBuffer;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.mesh.GLMesh;
|
||||||
|
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.GLStates;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
|
|
||||||
|
public class GLRecordingCommandBuffer implements GraphicsCommandBuffer {
|
||||||
|
List<Runnable> tasks = new ObjectArrayList<>();
|
||||||
|
boolean recording = false;
|
||||||
|
boolean removed = false;
|
||||||
|
GLGraphicsDevice device;
|
||||||
|
|
||||||
|
ScissorsManager scissors = new ScissorsManager(8, NoOp.INSTANCE);
|
||||||
|
ShaderPipeline pipeline;
|
||||||
|
ShaderInstance shader;
|
||||||
|
GLMesh mesh;
|
||||||
|
|
||||||
|
|
||||||
|
public GLRecordingCommandBuffer(GLGraphicsDevice device) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ensureDrawing() {
|
||||||
|
if(removed) throw new IllegalStateException("CommandBuffer is removed");
|
||||||
|
if(!recording) throw new IllegalStateException("CommandBuffer isn't recording");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRemoved() {
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove() {
|
||||||
|
removed = true;
|
||||||
|
clear();
|
||||||
|
recording = false;
|
||||||
|
tasks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer begin() {
|
||||||
|
if(removed) throw new IllegalStateException("CommandBuffer is removed");
|
||||||
|
if(recording) throw new IllegalStateException("CommandBuffer already recording");
|
||||||
|
recording = true;
|
||||||
|
tasks.clear();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer setScissors(int x, int y, int width, int height) {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.setRoot(x, y, width, height);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer pipeline(ShaderPipeline pipeline) {
|
||||||
|
Objects.requireNonNull(pipeline);
|
||||||
|
ensureDrawing();
|
||||||
|
if(this.pipeline == pipeline) return this;
|
||||||
|
this.pipeline = pipeline;
|
||||||
|
shader = device.getShader(pipeline);
|
||||||
|
tasks.add(new SetPipeline(pipeline, shader, device.states));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer mesh(Mesh mesh) {
|
||||||
|
Objects.requireNonNull(mesh);
|
||||||
|
ensureDrawing();
|
||||||
|
if(this.mesh == mesh) return this;
|
||||||
|
this.mesh = (GLMesh)mesh;
|
||||||
|
this.tasks.add(new SetMesh(this.mesh));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer texture(int binding, Texture texture, Sampler sampler) {
|
||||||
|
Objects.requireNonNull(texture);
|
||||||
|
Objects.requireNonNull(sampler);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.samplers().byIndex(binding), "Texture["+binding+"] binding not found");
|
||||||
|
tasks.add(new SetTexture(binding, (GLTexture)texture, (GLSampler)sampler, device.states));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer) {
|
||||||
|
Objects.requireNonNull(buffer);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.uniforms().byIndex(binding), "Uniform for binding ["+binding+"] doesn't exist");
|
||||||
|
tasks.add(new SetUniform(binding, (GLVertexBuffer)buffer, -1, -1));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer uniform(int binding, VertexBuffer buffer, long offset, long size) {
|
||||||
|
Objects.requireNonNull(buffer);
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
Objects.requireNonNull(shader.uniforms().byIndex(binding), "Uniform for binding ["+binding+"] doesn't exist");
|
||||||
|
tasks.add(new SetUniform(binding, (GLVertexBuffer)buffer, offset, size));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer drawArrays(int offset, int count) {
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
DrawMode mode = pipeline.rasterizer().mode();
|
||||||
|
tasks.add(() -> GL11.glDrawArrays(GLUtils.toGL(mode), offset, count));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer drawElements(int offset, int count) {
|
||||||
|
ensureDrawing();
|
||||||
|
Objects.requireNonNull(shader, "No Pipeline found");
|
||||||
|
DrawMode mode = pipeline.rasterizer().mode();
|
||||||
|
IndeciesType type = mesh.indeciesType();
|
||||||
|
tasks.add(() -> GL11.nglDrawElements(GLUtils.toGL(mode), count, GLUtils.toGL(type), offset));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer pushScissors(int x, int y, int width, int height) {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.push(x, y, width, height);
|
||||||
|
tasks.add(new SetScissors(scissors.top(), device.states));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer popScissors() {
|
||||||
|
ensureDrawing();
|
||||||
|
scissors.pop();
|
||||||
|
tasks.add(new SetScissors(scissors.top(), device.states));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GraphicsCommandBuffer end() {
|
||||||
|
if(!recording) throw new IllegalStateException("Already Stopped Recording");
|
||||||
|
clear();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int commandCount() {
|
||||||
|
return tasks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() {
|
||||||
|
tasks.forEach(Runnable::run);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clear() {
|
||||||
|
recording = false;
|
||||||
|
pipeline = null;
|
||||||
|
shader = null;
|
||||||
|
mesh = null;
|
||||||
|
scissors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SetScissors(Vec4i area, GLStates states) implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() { states.scissors.set(area); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SetPipeline(ShaderPipeline pipeline, ShaderInstance instance, GLStates states) implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
states.shaders.bind(instance);
|
||||||
|
RasterizerState rasterization = pipeline.rasterizer();
|
||||||
|
states.polygon.set(rasterization.fillMode());
|
||||||
|
states.backCulling.set(rasterization.cullBack());
|
||||||
|
DepthTarget depth = pipeline.depthTarget();
|
||||||
|
if(depth.enabled()) {
|
||||||
|
states.depth.enable();
|
||||||
|
states.setDepthMask(depth.write());
|
||||||
|
states.setDepthFunction(depth.function());
|
||||||
|
}
|
||||||
|
else states.depth.disable();
|
||||||
|
ColorTarget color = pipeline.colorTarget();
|
||||||
|
color.blend().ifPresentOrElse(states.blend::enableSet, states.blend::disable);
|
||||||
|
states.setColorMask(color.writeMask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SetMesh(GLMesh mesh) implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() { GL30.glBindVertexArray(mesh.id()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SetTexture(int binding, GLTexture texture, GLSampler sampler, GLStates states) implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
states.textures.bind(binding, texture.id());
|
||||||
|
states.samplers.bind(binding, sampler.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record SetUniform(int binding, GLVertexBuffer buffer, long offset, long size) implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if(size < 0 || offset < 0) GL30.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, binding, buffer.id());
|
||||||
|
else GL30.glBindBufferRange(GL31.GL_UNIFORM_BUFFER, binding, buffer.id(), offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package speiger.src.coreengine.graphics.opengl.core;
|
package speiger.src.coreengine.graphics.opengl.core;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import speiger.src.coreengine.graphics.api.core.GraphicsSurface;
|
import speiger.src.coreengine.graphics.api.core.GraphicsSurface;
|
||||||
import speiger.src.coreengine.rendering.input.window.Window;
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
@@ -19,6 +20,9 @@ public class GLSurface implements GraphicsSurface {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beginFrame() {
|
public void beginFrame() {
|
||||||
|
GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F);
|
||||||
|
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||||
|
window.beginFrame();
|
||||||
GLFW.glfwPollEvents();
|
GLFW.glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package speiger.src.coreengine.graphics.opengl.mesh;
|
package speiger.src.coreengine.graphics.opengl.mesh;
|
||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
import org.lwjgl.opengl.GL45;
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
import speiger.src.collections.ints.collections.IntIterator;
|
import speiger.src.collections.ints.collections.IntIterator;
|
||||||
@@ -29,6 +30,22 @@ public class GLMesh extends Mesh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int id() {
|
||||||
|
return vao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind() {
|
||||||
|
GL30.glBindVertexArray(vao);
|
||||||
|
for(Element element : layouts.values().map(LayoutInfo::layout).flatMap(VertexLayout::elements)) {
|
||||||
|
GL45.glEnableVertexArrayAttrib(vao, element.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof GLMesh mesh && mesh.vao == vao;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRemoved() { return vao == 0; }
|
public boolean isRemoved() { return vao == 0; }
|
||||||
|
|
||||||
@@ -47,6 +64,7 @@ public class GLMesh extends Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void bindElement() {
|
private void bindElement() {
|
||||||
|
indeciesBuffer.bind();
|
||||||
GL45.glVertexArrayElementBuffer(vao, ((GLVertexBuffer)indeciesBuffer).id());
|
GL45.glVertexArrayElementBuffer(vao, ((GLVertexBuffer)indeciesBuffer).id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +72,7 @@ public class GLMesh extends Mesh {
|
|||||||
LayoutInfo info = layouts.get(binding);
|
LayoutInfo info = layouts.get(binding);
|
||||||
VertexLayout layout = info.layout();
|
VertexLayout layout = info.layout();
|
||||||
GLVertexBuffer buffer = (GLVertexBuffer)buffers.get(binding);
|
GLVertexBuffer buffer = (GLVertexBuffer)buffers.get(binding);
|
||||||
|
buffer.bind();
|
||||||
GL45.glVertexArrayVertexBuffer(vao, binding, buffer.id(), 0, layout.bytes());
|
GL45.glVertexArrayVertexBuffer(vao, binding, buffer.id(), 0, layout.bytes());
|
||||||
if(info.instanceCount() > 0) GL45.glVertexArrayBindingDivisor(vao, binding, info.instanceCount());
|
if(info.instanceCount() > 0) GL45.glVertexArrayBindingDivisor(vao, binding, info.instanceCount());
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ public class GLSampler extends Sampler {
|
|||||||
GL45.glSamplerParameteri(id, GL11.GL_TEXTURE_MAG_FILTER, GLUtils.toGL(settings.magSample()));
|
GL45.glSamplerParameteri(id, GL11.GL_TEXTURE_MAG_FILTER, GLUtils.toGL(settings.magSample()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRemoved() {
|
public boolean isRemoved() {
|
||||||
return id == 0;
|
return id == 0;
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ package speiger.src.coreengine.graphics.opengl.shader;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
@@ -62,12 +66,16 @@ public class ShaderCache {
|
|||||||
catch(Exception e) { e.printStackTrace(); }
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] get(ID shaderId, String fileHash) {
|
public ByteBuffer get(ID shaderId, Supplier<String> fileHash) {
|
||||||
|
if(cache == null) return null;
|
||||||
String known = hashCache.get(shaderId);
|
String known = hashCache.get(shaderId);
|
||||||
if(!Objects.equals(known, fileHash)) return null;
|
if(known == null || !Objects.equals(known, fileHash.get())) return null;
|
||||||
Path path = toFile(shaderId);
|
Path path = toFile(shaderId);
|
||||||
if(Files.notExists(path)) return null;
|
if(Files.notExists(path)) return null;
|
||||||
try { return Files.readAllBytes(path); }
|
try {
|
||||||
|
byte[] data = Files.readAllBytes(path);
|
||||||
|
return MemoryUtil.memAlloc(data.length).put(data).flip();
|
||||||
|
}
|
||||||
catch(Exception e) { e.printStackTrace(); }
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -76,6 +84,7 @@ public class ShaderCache {
|
|||||||
Objects.requireNonNull(shaderId);
|
Objects.requireNonNull(shaderId);
|
||||||
Objects.requireNonNull(fileHash);
|
Objects.requireNonNull(fileHash);
|
||||||
Objects.requireNonNull(shader);
|
Objects.requireNonNull(shader);
|
||||||
|
if(cache == null) return;
|
||||||
hashCache.put(shaderId, fileHash);
|
hashCache.put(shaderId, fileHash);
|
||||||
try {
|
try {
|
||||||
Path file = toFile(shaderId);
|
Path file = toFile(shaderId);
|
||||||
@@ -89,6 +98,7 @@ public class ShaderCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void delete(ID shaderId) {
|
public void delete(ID shaderId) {
|
||||||
|
if(cache == null) return;
|
||||||
if(hashCache.remove(shaderId) == null) return;
|
if(hashCache.remove(shaderId) == null) return;
|
||||||
try { Files.deleteIfExists(toFile(shaderId)); }
|
try { Files.deleteIfExists(toFile(shaderId)); }
|
||||||
catch(Exception e) { e.printStackTrace(); }
|
catch(Exception e) { e.printStackTrace(); }
|
||||||
|
|||||||
+23
-2
@@ -2,8 +2,29 @@ package speiger.src.coreengine.graphics.opengl.shader;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public record ShaderInstance(int programId, Map<String, UniformObject> uniforms, Map<String, SamplerObject> samplers) {
|
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
|
||||||
|
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
|
||||||
|
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
|
||||||
|
|
||||||
|
public record ShaderInstance(int programId, ShaderStorage<UniformObject> uniforms, ShaderStorage<SamplerObject> samplers) {
|
||||||
public record UniformObject(int slot) {}
|
public record UniformObject(int slot) {}
|
||||||
public record SamplerObject(int unit) {}
|
public record SamplerObject(int unit) {}
|
||||||
|
|
||||||
|
public static class ShaderStorage<T> {
|
||||||
|
Map<String, T> byName = new Object2ObjectOpenHashMap<>();
|
||||||
|
Int2ObjectMap<T> byIndex = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public void add(String name, int index, T value) {
|
||||||
|
byName.put(name, value);
|
||||||
|
byIndex.put(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T byName(String name) {
|
||||||
|
return byName.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T byIndex(int index) {
|
||||||
|
return byIndex.get(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.shader;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
|
import speiger.src.collections.objects.lists.ObjectList;
|
||||||
|
|
||||||
|
public class ShaderTracker {
|
||||||
|
ObjectList<ShaderInstance> knownShaders = new ObjectArrayList<ShaderInstance>();
|
||||||
|
int boundShader;
|
||||||
|
|
||||||
|
public void register(ShaderInstance instance) {
|
||||||
|
knownShaders.add(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(ShaderInstance instance) {
|
||||||
|
knownShaders.remove(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(ShaderInstance instance) {
|
||||||
|
int id = instance.programId();
|
||||||
|
if(id == boundShader) return;
|
||||||
|
boundShader = id;
|
||||||
|
GL20.glUseProgram(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -4,16 +4,16 @@ import org.lwjgl.opengl.GL45;
|
|||||||
|
|
||||||
import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap;
|
import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap;
|
||||||
import speiger.src.collections.objects.maps.interfaces.Object2IntMap;
|
import speiger.src.collections.objects.maps.interfaces.Object2IntMap;
|
||||||
import speiger.src.coreengine.assets.AssetLocation;
|
import speiger.src.coreengine.assets.api.ID;
|
||||||
|
|
||||||
public class FrameBufferCache {
|
public class FrameBufferCache {
|
||||||
Object2IntMap<AssetLocation> fboCache = new Object2IntOpenHashMap<>();
|
Object2IntMap<ID> fboCache = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
public int getOrCreateFBO(AssetLocation id) {
|
public int getOrCreateFBO(ID id) {
|
||||||
return fboCache.supplyIntIfAbsent(id, GL45::glCreateFramebuffers);
|
return fboCache.supplyIntIfAbsent(id, GL45::glCreateFramebuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteFBO(AssetLocation id) {
|
public void deleteFBO(ID id) {
|
||||||
int fbo = fboCache.rem(id);
|
int fbo = fboCache.rem(id);
|
||||||
if(fbo == -1) return;
|
if(fbo == -1) return;
|
||||||
GL45.glDeleteFramebuffers(fbo);
|
GL45.glDeleteFramebuffers(fbo);
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.ScissorsManager.IScissorsHandler;
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
|
|
||||||
|
public record GLScissorsHandler(GLStates states) implements IScissorsHandler {
|
||||||
|
@Override
|
||||||
|
public void enable() { states.scissors.enable(); }
|
||||||
|
@Override
|
||||||
|
public void disable() { states.scissors.disable(); }
|
||||||
|
@Override
|
||||||
|
public void apply(int x, int y, int width, int height) { states.scissors.set(Vec4i.of(x, y, x + width, y + height)); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL13;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ColorTarget;
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.AlphaFunction;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.shader.ShaderTracker;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.BlendState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.CullState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.FloatState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.GLPolygon;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.GLState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.PixelState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.SamplerState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.ScissorState;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.states.TextureState;
|
||||||
|
|
||||||
|
public final class GLStates {
|
||||||
|
public final GLState multiSampling = new GLState(GL13.GL_MULTISAMPLE);
|
||||||
|
public final GLState depth = new GLState(GL11.GL_DEPTH_TEST);
|
||||||
|
public final GLPolygon polygon = new GLPolygon();
|
||||||
|
public final GLState backCulling = new CullState();
|
||||||
|
public final FloatState pointSize = new FloatState(1F, GL11::glPointSize);
|
||||||
|
public final FloatState lineSize = new FloatState(1F, GL11::glLineWidth);
|
||||||
|
public final TextureState textures = new TextureState();
|
||||||
|
public final SamplerState samplers = new SamplerState();
|
||||||
|
public final BlendState blend = new BlendState();
|
||||||
|
public final ScissorState scissors = new ScissorState();
|
||||||
|
public final ViewPortStack viewPort = new ViewPortStack();
|
||||||
|
|
||||||
|
//Texture States
|
||||||
|
public final PixelState unpack_alignment = new PixelState(GL11.GL_UNPACK_ALIGNMENT, 4);
|
||||||
|
public final PixelState unpack_skip_pixel = new PixelState(GL11.GL_UNPACK_SKIP_PIXELS, 0);
|
||||||
|
public final PixelState unpack_skip_rows = new PixelState(GL11.GL_UNPACK_SKIP_ROWS, 0);
|
||||||
|
public final PixelState unpack_row_length = new PixelState(GL11.GL_UNPACK_ROW_LENGTH, 0);
|
||||||
|
|
||||||
|
public final ShaderTracker shaders = new ShaderTracker();
|
||||||
|
|
||||||
|
|
||||||
|
int colorMask = ColorTarget.ALL;
|
||||||
|
boolean depthMask = true;
|
||||||
|
AlphaFunction depthFunction = AlphaFunction.GEQUAL;
|
||||||
|
int activeVAO = 0;
|
||||||
|
int activeShader = 0;
|
||||||
|
|
||||||
|
public void setColorMask(int mask) {
|
||||||
|
if(colorMask == mask) return;
|
||||||
|
colorMask = mask;
|
||||||
|
GL11.glColorMask((mask & ColorTarget.RED) != 0, (mask & ColorTarget.GREEN) != 0, (mask & ColorTarget.BLUE) != 0, (mask & ColorTarget.ALPHA) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepthMask(boolean depth) {
|
||||||
|
if(depthMask == depth) return;
|
||||||
|
depthMask = depth;
|
||||||
|
GL11.glDepthMask(depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepthFunction(AlphaFunction function) {
|
||||||
|
if(depthFunction == function) return;
|
||||||
|
depthFunction = function;
|
||||||
|
GL11.glDepthFunc(GLUtils.toGL(function));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import org.lwjgl.opengl.GL12;
|
|||||||
import org.lwjgl.opengl.GL13;
|
import org.lwjgl.opengl.GL13;
|
||||||
import org.lwjgl.opengl.GL14;
|
import org.lwjgl.opengl.GL14;
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
import org.lwjgl.opengl.GL21;
|
import org.lwjgl.opengl.GL21;
|
||||||
import org.lwjgl.opengl.GL30;
|
import org.lwjgl.opengl.GL30;
|
||||||
import org.lwjgl.opengl.GL31;
|
import org.lwjgl.opengl.GL31;
|
||||||
@@ -16,17 +17,21 @@ import org.lwjgl.opengl.GL44;
|
|||||||
|
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferState;
|
||||||
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
import speiger.src.coreengine.graphics.api.buffer.states.BufferType;
|
||||||
|
import speiger.src.coreengine.graphics.api.buffer.states.IndeciesType;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.states.BorderMode;
|
import speiger.src.coreengine.graphics.api.sampler.states.BorderMode;
|
||||||
import speiger.src.coreengine.graphics.api.sampler.states.SampleMode;
|
import speiger.src.coreengine.graphics.api.sampler.states.SampleMode;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.BlendFactor;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.DrawMode;
|
||||||
import speiger.src.coreengine.graphics.api.shader.states.GraphicsDataType;
|
import speiger.src.coreengine.graphics.api.shader.states.GraphicsDataType;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.PolygonMode;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.ShaderType;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.StencilType;
|
import speiger.src.coreengine.graphics.api.texture.states.StencilType;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
|
import speiger.src.coreengine.graphics.api.texture.states.SwizzleMask;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
||||||
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
import speiger.src.coreengine.graphics.api.utils.AlphaFunction;
|
import speiger.src.coreengine.graphics.api.utils.AlphaFunction;
|
||||||
|
|
||||||
public class GLUtils {
|
public class GLUtils {
|
||||||
//Buffer Begin
|
|
||||||
|
|
||||||
public static int toGL(BufferType type) {
|
public static int toGL(BufferType type) {
|
||||||
return switch(type) {
|
return switch(type) {
|
||||||
case ARRAY_BUFFER -> GL15.GL_ARRAY_BUFFER;
|
case ARRAY_BUFFER -> GL15.GL_ARRAY_BUFFER;
|
||||||
@@ -58,9 +63,7 @@ public class GLUtils {
|
|||||||
case DYNAMIC_COPY -> GL15.GL_DYNAMIC_COPY;
|
case DYNAMIC_COPY -> GL15.GL_DYNAMIC_COPY;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//Texture Begin
|
|
||||||
|
|
||||||
public static int toGL(TextureType type) {
|
public static int toGL(TextureType type) {
|
||||||
return switch(type) {
|
return switch(type) {
|
||||||
case TEXTURE_1D -> GL11.GL_TEXTURE_1D;
|
case TEXTURE_1D -> GL11.GL_TEXTURE_1D;
|
||||||
@@ -77,6 +80,45 @@ public class GLUtils {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int toGLInternal(TextureFormat format) {
|
||||||
|
return switch(format) {
|
||||||
|
case R -> GL11.GL_RED;
|
||||||
|
case RG -> GL30.GL_RG;
|
||||||
|
case RGB -> GL11.GL_RGB;
|
||||||
|
case RGBA -> GL11.GL_RGBA8;
|
||||||
|
case DEPTH -> GL11.GL_DEPTH_COMPONENT;
|
||||||
|
case DEPTH_STENCIL -> GL30.GL_DEPTH_STENCIL;
|
||||||
|
case LUMINANCE -> GL30.GL_R8;
|
||||||
|
case LUMINANCE_ALPHA -> GL11.GL_LUMINANCE8_ALPHA8;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toGLExternal(TextureFormat format) {
|
||||||
|
return switch(format) {
|
||||||
|
case R -> GL11.GL_RED;
|
||||||
|
case RG -> GL30.GL_RG;
|
||||||
|
case RGB -> GL11.GL_RGB;
|
||||||
|
case RGBA -> GL11.GL_RGBA;
|
||||||
|
case DEPTH -> GL11.GL_DEPTH_COMPONENT;
|
||||||
|
case DEPTH_STENCIL -> GL30.GL_DEPTH_STENCIL;
|
||||||
|
case LUMINANCE -> GL30.GL_R8;
|
||||||
|
case LUMINANCE_ALPHA -> GL11.GL_LUMINANCE8_ALPHA8;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int components(TextureFormat format) {
|
||||||
|
return switch(format) {
|
||||||
|
case R -> 1;
|
||||||
|
case RG -> 2;
|
||||||
|
case RGB -> 3;
|
||||||
|
case RGBA -> 4;
|
||||||
|
case DEPTH -> 1;
|
||||||
|
case DEPTH_STENCIL -> 2;
|
||||||
|
case LUMINANCE -> 1;
|
||||||
|
case LUMINANCE_ALPHA -> 2;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static int toGL(SwizzleMask mask) {
|
public static int toGL(SwizzleMask mask) {
|
||||||
return switch(mask) {
|
return switch(mask) {
|
||||||
case RED -> GL11.GL_RED;
|
case RED -> GL11.GL_RED;
|
||||||
@@ -154,4 +196,64 @@ public class GLUtils {
|
|||||||
case UNSIGNED_INT_5_9_9_9_REV -> GL30.GL_UNSIGNED_INT_5_9_9_9_REV;
|
case UNSIGNED_INT_5_9_9_9_REV -> GL30.GL_UNSIGNED_INT_5_9_9_9_REV;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int toGL(BlendFactor type) {
|
||||||
|
return switch(type) {
|
||||||
|
case ZERO -> GL11.GL_ZERO;
|
||||||
|
case ONE -> GL11.GL_ONE;
|
||||||
|
case CONSTANT_COLOR -> GL15.GL_CONSTANT_COLOR;
|
||||||
|
case CONSTANT_ALPHA -> GL15.GL_CONSTANT_ALPHA;
|
||||||
|
case SRC_COLOR -> GL11.GL_SRC_COLOR;
|
||||||
|
case SRC_ALPHA -> GL11.GL_SRC_ALPHA;
|
||||||
|
case DST_COLOR -> GL11.GL_DST_COLOR;
|
||||||
|
case DST_ALPHA -> GL11.GL_DST_ALPHA;
|
||||||
|
case ONE_MINUS_SRC_COLOR -> GL11.GL_ONE_MINUS_SRC_COLOR;
|
||||||
|
case ONE_MINUS_SRC_ALPHA -> GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
case ONE_MINUS_DST_COLOR -> GL11.GL_ONE_MINUS_DST_COLOR;
|
||||||
|
case ONE_MINUS_DST_ALPHA -> GL11.GL_ONE_MINUS_DST_ALPHA;
|
||||||
|
case ONE_MINUS_CONSTANT_COLOR -> GL15.GL_ONE_MINUS_CONSTANT_COLOR;
|
||||||
|
case ONE_MINUS_CONSTANT_ALPHA -> GL15.GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||||
|
case SRC_ALPHA_SATURATE -> GL11.GL_SRC_ALPHA_SATURATE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toGL(PolygonMode state) {
|
||||||
|
return switch(state) {
|
||||||
|
case FILL -> GL11.GL_FILL;
|
||||||
|
case LINE -> GL11.GL_LINE;
|
||||||
|
case POINT -> GL11.GL_POINT;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toGL(ShaderType type) {
|
||||||
|
return switch(type) {
|
||||||
|
case VERTEX -> GL20.GL_VERTEX_SHADER;
|
||||||
|
case FRAGMENT -> GL20.GL_FRAGMENT_SHADER;
|
||||||
|
case GEOMETRY -> GL32.GL_GEOMETRY_SHADER;
|
||||||
|
case TESSELATION_CONTROL -> GL40.GL_TESS_CONTROL_SHADER;
|
||||||
|
case TESSELATION_EVALUATION -> GL40.GL_TESS_EVALUATION_SHADER;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toGL(DrawMode mode) {
|
||||||
|
return switch(mode) {
|
||||||
|
case POINT -> GL11.GL_POINT;
|
||||||
|
case LINES -> GL11.GL_LINES;
|
||||||
|
case LINE_LOOP -> GL11.GL_LINE_LOOP;
|
||||||
|
case LINE_STRIP -> GL11.GL_LINE_STRIP;
|
||||||
|
case TRIANGLES -> GL11.GL_TRIANGLES;
|
||||||
|
case TRIANGLE_FAN -> GL11.GL_TRIANGLE_FAN;
|
||||||
|
case TRIANGLE_STRIP -> GL11.GL_TRIANGLE_STRIP;
|
||||||
|
case QUADS -> GL11.GL_QUADS;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int toGL(IndeciesType type) {
|
||||||
|
return switch(type) {
|
||||||
|
case BYTE -> GL11.GL_UNSIGNED_BYTE;
|
||||||
|
case SHORT -> GL11.GL_UNSIGNED_SHORT;
|
||||||
|
case INT -> GL11.GL_UNSIGNED_INT;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.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 ViewPortStack {
|
||||||
|
Stack<Vec4i> stack = new ObjectArrayList<>();
|
||||||
|
Vec4i defaultPort = Vec4i.ZERO;
|
||||||
|
|
||||||
|
public void setDefault(int x, int y, int w, int h) {
|
||||||
|
if(defaultPort.x() == x && defaultPort.y() == y && defaultPort.z() == w && defaultPort.w() == h) return;
|
||||||
|
defaultPort.set(x, y, w, h);
|
||||||
|
if(stack.isEmpty()) GL11.glViewport(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void push(int x, int y, int w, int h) {
|
||||||
|
Vec4i current = top();
|
||||||
|
if(current.x() == x && current.y() == y && current.z() == w && current.w() == h) return;
|
||||||
|
stack.push(Vec4i.of(x, y, w, h));
|
||||||
|
GL11.glViewport(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pop() {
|
||||||
|
if(stack.isEmpty()) return;
|
||||||
|
stack.pop();
|
||||||
|
Vec4i current = top();
|
||||||
|
GL11.glViewport(current.x(), current.y(), current.z(), current.w());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec4i top() {
|
||||||
|
return stack.isEmpty() ? defaultPort : stack.top();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.BlendFunction;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
|
|
||||||
|
public class BlendState extends GLState {
|
||||||
|
BlendFunction function = BlendFunction.DEFAULT;
|
||||||
|
|
||||||
|
public BlendState() {
|
||||||
|
super(GL11.GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlendState enableSet(BlendFunction function) {
|
||||||
|
enable();
|
||||||
|
return set(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlendState set(BlendFunction function) {
|
||||||
|
if(this.function.equals(function)) return this;
|
||||||
|
this.function = function;
|
||||||
|
GL15.glBlendFuncSeparate(GLUtils.toGL(function.colorSource()), GLUtils.toGL(function.colorTarget()), GLUtils.toGL(function.alphaSource()), GLUtils.toGL(function.alphaTarget()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
super.reapply();
|
||||||
|
GL15.glBlendFuncSeparate(GLUtils.toGL(function.colorSource()), GLUtils.toGL(function.colorTarget()), GLUtils.toGL(function.alphaSource()), GLUtils.toGL(function.alphaTarget()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
super.setDefault();
|
||||||
|
set(BlendFunction.DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
public class CullState extends GLState {
|
||||||
|
|
||||||
|
public CullState() {
|
||||||
|
super(GL11.GL_CULL_FACE, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GLState enable() {
|
||||||
|
super.enable();
|
||||||
|
GL11.glCullFace(GL11.GL_BACK);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
super.reapply();
|
||||||
|
GL11.glCullFace(GL11.GL_BACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import speiger.src.collections.floats.functions.FloatConsumer;
|
||||||
|
|
||||||
|
public class FloatState implements IGLState {
|
||||||
|
protected final float defaultValue;
|
||||||
|
protected float value;
|
||||||
|
FloatConsumer setter;
|
||||||
|
|
||||||
|
public FloatState(float defaultValue, FloatConsumer setter) {
|
||||||
|
this.defaultValue = this.value = defaultValue;
|
||||||
|
this.setter = setter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatState set(float value) {
|
||||||
|
if(equalsNot(this.value, value)) {
|
||||||
|
this.value = value;
|
||||||
|
setter.accept(value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float get() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
set(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
setter.accept(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean equalsNot(float key, float value) {
|
||||||
|
return Float.floatToIntBits(key) != Float.floatToIntBits(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.PolygonMode;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.utils.GLUtils;
|
||||||
|
|
||||||
|
|
||||||
|
public class GLPolygon implements IGLState
|
||||||
|
{
|
||||||
|
PolygonMode defaultState = PolygonMode.FILL;
|
||||||
|
PolygonMode state = PolygonMode.FILL;
|
||||||
|
|
||||||
|
public GLPolygon set(PolygonMode state) {
|
||||||
|
if(this.state == state) return this;
|
||||||
|
this.state = state;
|
||||||
|
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GLUtils.toGL(state));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
set(defaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GLUtils.toGL(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
public class GLState implements IGLState {
|
||||||
|
final int id;
|
||||||
|
final boolean defaultValue;
|
||||||
|
boolean value;
|
||||||
|
|
||||||
|
public GLState(int id) {
|
||||||
|
this(id, GL11.glGetBoolean(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLState(int id, boolean defaultValue) {
|
||||||
|
this.id = id;
|
||||||
|
this.defaultValue = this.value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLState enable() {
|
||||||
|
return set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLState disable() {
|
||||||
|
return set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GLState set(boolean value) {
|
||||||
|
if(this.value != value) {
|
||||||
|
this.value = value;
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean enabled() { return value; }
|
||||||
|
|
||||||
|
protected void setValue(boolean value) {
|
||||||
|
if(value) GL11.glEnable(id);
|
||||||
|
else GL11.glDisable(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
set(defaultValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
public interface IGLState
|
||||||
|
{
|
||||||
|
public void setDefault();
|
||||||
|
public void reapply();
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
public class PixelState implements IGLState {
|
||||||
|
final int id;
|
||||||
|
final int defaultValue;
|
||||||
|
int value;
|
||||||
|
|
||||||
|
public PixelState(int id, int defaultValue) {
|
||||||
|
this.id = id;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
this.value = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PixelState set(int value) {
|
||||||
|
if(this.value != value) {
|
||||||
|
this.value = value;
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setValue(int value) {
|
||||||
|
GL11.glPixelStorei(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int get() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
set(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
import org.lwjgl.opengl.GL33;
|
||||||
|
import org.lwjgl.opengl.GL44;
|
||||||
|
|
||||||
|
public class SamplerState implements IGLState {
|
||||||
|
int[] samplers = new int[GL20.GL_TEXTURE31 - GL20.GL_TEXTURE0];
|
||||||
|
|
||||||
|
public SamplerState bind(int sampler) {
|
||||||
|
return bind(0, sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SamplerState bind(int unit, int sampler) {
|
||||||
|
if(samplers[unit] != sampler) {
|
||||||
|
this.samplers[unit] = sampler;
|
||||||
|
GL33.glBindSampler(unit, sampler);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SamplerState unbind(int unit) {
|
||||||
|
if(samplers[unit] != 0) {
|
||||||
|
samplers[unit] = 0;
|
||||||
|
GL33.glBindSampler(unit, 0);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SamplerState unbindAll() {
|
||||||
|
setDefault();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSamplerId(int unit) {
|
||||||
|
return samplers[unit];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
GL44.nglBindSamplers(0, samplers.length, 0);
|
||||||
|
Arrays.fill(samplers, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
GL44.glBindSamplers(0, samplers);
|
||||||
|
}
|
||||||
|
}
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
|
|
||||||
|
public class ScissorState extends GLState {
|
||||||
|
Vec4i current = Vec4i.MINUS_ONE;
|
||||||
|
Vec4i backup = null;
|
||||||
|
|
||||||
|
public ScissorState() {
|
||||||
|
super(GL11.GL_SCISSOR_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScissorState set(Vec4i bounds) {
|
||||||
|
if(current.equals(bounds)) return this;
|
||||||
|
current = bounds.asImmutable();
|
||||||
|
if(Vec4i.MINUS_ONE.equals(bounds)) {
|
||||||
|
disable();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
enable();
|
||||||
|
GL11.glScissor(bounds.x(), bounds.y(), bounds.z() - bounds.x(), bounds.w() - bounds.y());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void backup() {
|
||||||
|
backup = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restore() {
|
||||||
|
if(backup == null) return;
|
||||||
|
set(backup);
|
||||||
|
backup = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec4i current() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
super.setDefault();
|
||||||
|
current = Vec4i.MINUS_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
super.reapply();
|
||||||
|
GL11.glScissor(current.x(), current.y(), current.z() - current.x(), current.w() - current.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package speiger.src.coreengine.graphics.opengl.utils.states;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
import org.lwjgl.opengl.GL45;
|
||||||
|
|
||||||
|
public class TextureState implements IGLState {
|
||||||
|
int[] textures = new int[GL20.GL_TEXTURE31 - GL20.GL_TEXTURE0];
|
||||||
|
|
||||||
|
public TextureState bind(int texture) {
|
||||||
|
return bind(0, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureState bind(int unit, int texture) {
|
||||||
|
if(textures[unit] != texture) {
|
||||||
|
this.textures[unit] = texture;
|
||||||
|
GL45.glBindTextureUnit(unit, texture);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureState unbind(int unit) {
|
||||||
|
if(textures[unit] != 0) {
|
||||||
|
textures[unit] = 0;
|
||||||
|
GL45.glBindTextureUnit(unit, 0);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureState unbindAll() {
|
||||||
|
setDefault();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTextureId(int unit) {
|
||||||
|
return textures[unit];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault() {
|
||||||
|
GL45.nglBindTextures(0, textures.length, 0);
|
||||||
|
Arrays.fill(textures, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reapply() {
|
||||||
|
GL45.glBindTextures(0, textures);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -76,8 +76,8 @@ public class NewInputTest {
|
|||||||
Joystick.INSTANCE.init(manager, bus);
|
Joystick.INSTANCE.init(manager, bus);
|
||||||
FileDrop.INSTANCE.init(bus);
|
FileDrop.INSTANCE.init(bus);
|
||||||
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
|
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
|
||||||
Window window = manager.builder().title("Testing Engine").width(800).height(600).antialis(0).build();
|
Window window = manager.builder().title("Testing Engine").width(800).height(600).antialis(0).build(null);
|
||||||
Window secondWindow = manager.builder().title("Second Window Engine").width(800).height(600).antialis(0).build();
|
Window secondWindow = manager.builder().title("Second Window Engine").width(800).height(600).antialis(0).build(null);
|
||||||
Thread.ofPlatform().start(() -> drawSecondScreen(secondWindow));
|
Thread.ofPlatform().start(() -> drawSecondScreen(secondWindow));
|
||||||
window.setupContext();
|
window.setupContext();
|
||||||
shaderTest.register();
|
shaderTest.register();
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
package speiger.src.coreengine;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.lwjgl.system.Configuration;
|
||||||
|
import org.lwjgl.util.freetype.FreeType;
|
||||||
|
|
||||||
|
import speiger.src.coreengine.assets.api.IAssetPackage;
|
||||||
|
import speiger.src.coreengine.assets.api.ID;
|
||||||
|
import speiger.src.coreengine.assets.manager.AssetManager;
|
||||||
|
import speiger.src.coreengine.graphics.api.buffer.VertexBuffer;
|
||||||
|
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.Graphics;
|
||||||
|
import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer;
|
||||||
|
import speiger.src.coreengine.graphics.api.core.GraphicsDevice;
|
||||||
|
import speiger.src.coreengine.graphics.api.core.GraphicsSurface;
|
||||||
|
import speiger.src.coreengine.graphics.api.mesh.Mesh;
|
||||||
|
import speiger.src.coreengine.graphics.api.sampler.Sampler;
|
||||||
|
import speiger.src.coreengine.graphics.api.sampler.SamplerSettings;
|
||||||
|
import speiger.src.coreengine.graphics.api.sampler.states.BorderMode;
|
||||||
|
import speiger.src.coreengine.graphics.api.sampler.states.SampleMode;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.ShaderPipeline;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.GraphicsDataType;
|
||||||
|
import speiger.src.coreengine.graphics.api.shader.states.ShaderType;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.Texture;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.TextureSettings;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureFormat;
|
||||||
|
import speiger.src.coreengine.graphics.api.texture.states.TextureType;
|
||||||
|
import speiger.src.coreengine.graphics.api.utils.ExecutionType;
|
||||||
|
import speiger.src.coreengine.graphics.api.vertex.VertexLayout;
|
||||||
|
import speiger.src.coreengine.graphics.api.vertex.VertexLayout.Usage;
|
||||||
|
import speiger.src.coreengine.graphics.opengl.core.GLGraphics;
|
||||||
|
import speiger.src.coreengine.math.vector.matrix.Matrix4f;
|
||||||
|
import speiger.src.coreengine.rendering.input.devices.FileDrop;
|
||||||
|
import speiger.src.coreengine.rendering.input.devices.Joystick;
|
||||||
|
import speiger.src.coreengine.rendering.input.devices.Keyboard;
|
||||||
|
import speiger.src.coreengine.rendering.input.devices.Mouse;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.Window;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.WindowManager;
|
||||||
|
import speiger.src.coreengine.rendering.tesselation.buffer.VertexBuilder;
|
||||||
|
import speiger.src.coreengine.rendering.tesselation.format.VertexTypes;
|
||||||
|
import speiger.src.coreengine.rendering.textures.custom.Drawable;
|
||||||
|
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureFormat;
|
||||||
|
import speiger.src.coreengine.utils.eventbus.EventBus;
|
||||||
|
import speiger.src.coreengine.utils.helpers.IOUtils;
|
||||||
|
|
||||||
|
public class NewRenderEngineTest {
|
||||||
|
EventBus bus = new EventBus();
|
||||||
|
WindowManager manager = new WindowManager();
|
||||||
|
AssetManager assets = AssetManager.single(IAssetPackage.asset(IOUtils.getBaseLocation()));
|
||||||
|
|
||||||
|
public static void main(String... args) {
|
||||||
|
new NewRenderEngineTest().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
Configuration.HARFBUZZ_LIBRARY_NAME.set(FreeType.getLibrary());
|
||||||
|
GLFW.glfwInit();
|
||||||
|
manager.initialize();
|
||||||
|
Mouse.INSTANCE.init(bus);
|
||||||
|
Keyboard.INSTANCE.init(bus);
|
||||||
|
Joystick.INSTANCE.init(manager, bus);
|
||||||
|
FileDrop.INSTANCE.init(bus);
|
||||||
|
manager.addDevices(Mouse.INSTANCE, Keyboard.INSTANCE, Joystick.INSTANCE, FileDrop.INSTANCE);
|
||||||
|
Graphics graphics = new GLGraphics(assets);
|
||||||
|
Window window = manager.builder().title("Testing Engine").width(800).height(600).antialis(0).build(graphics);
|
||||||
|
GraphicsDevice device = graphics.createDevice(window);
|
||||||
|
window.setupContext();
|
||||||
|
|
||||||
|
GraphicsSurface surface = device.createSurface();
|
||||||
|
int size = 512;
|
||||||
|
int half = size >> 1;
|
||||||
|
int base = size >> 3;
|
||||||
|
Drawable drawer = new Drawable(GLTextureFormat.RGBA, size, size);
|
||||||
|
drawer.fill(0, 0, size, size, -1);
|
||||||
|
drawer.fill(0, 0, half, half, 255, 0, 0, 255);
|
||||||
|
drawer.fill(half, 0, half, half, 0, 255, 0, 255);
|
||||||
|
drawer.fill(half, half, half, half, 255, 0, 0, 255);
|
||||||
|
drawer.fill(0, half, half, half, 0, 0, 255, 255);
|
||||||
|
|
||||||
|
VertexBuilder builder = new VertexBuilder(255);
|
||||||
|
builder.start(null, VertexTypes.TESTING);
|
||||||
|
builder.pos(-0.5F, -0.5F, 0).tex(0F, 1F).rgba(-1).endVertex();
|
||||||
|
builder.pos(0.5F, -0.5F, 0).tex(1F, 1F).rgba(-1).endVertex();
|
||||||
|
builder.pos(0.5F, 0.5F, 0).tex(1F, 0F).rgba(-1).endVertex();
|
||||||
|
builder.pos(0.5F, 0.5F, 0).tex(1F, 0F).rgba(-1).endVertex();
|
||||||
|
builder.pos(-0.5F, 0.5F, 0).tex(0F, 0F).rgba(-1).endVertex();
|
||||||
|
builder.pos(-0.5F, -0.5F, 0).tex(0F, 1F).rgba(-1).endVertex();
|
||||||
|
|
||||||
|
Texture texture = device.createTexture(TextureSettings.builder().build(), size, size);
|
||||||
|
device.queue().writeToTexture(texture, TextureFormat.RGBA, GraphicsDataType.UNSIGNED_BYTE, drawer.pixels());
|
||||||
|
drawer.close();
|
||||||
|
|
||||||
|
VertexLayout layout = VertexLayout.builder()
|
||||||
|
.element("pos", 0, 3, Usage.POS)
|
||||||
|
.element("tex", 1, 2, Usage.UV)
|
||||||
|
.element("color", 2, 4, Usage.COLOR, GraphicsDataType.UNSIGNED_BYTE, true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Mesh mesh = device.createMesh(Mesh.builder().layout(layout));
|
||||||
|
mesh.buffer(0, device.createBuffer(BufferType.ARRAY_BUFFER, BufferState.STATIC_DRAW).bind().set(builder.getBytes()).unbind());
|
||||||
|
|
||||||
|
Sampler sampler = device.createSampler(SamplerSettings.builder().sampler(SampleMode.NEAREST).wrap(BorderMode.CLAMP_TO_EDGE).build());
|
||||||
|
VertexBuffer buffer = device.createBuffer(BufferType.UNIFORM_BUFFER, BufferState.STATIC_DRAW);
|
||||||
|
ByteBuffer mat = ByteBuffer.allocate(64);
|
||||||
|
int scale = 0;
|
||||||
|
new Matrix4f().ortho(0, 0, window.width() >> scale, window.height() >> scale, 1000, -1000).store(mat);
|
||||||
|
buffer.bind().set(mat.flip().array()).unbind();
|
||||||
|
|
||||||
|
|
||||||
|
ShaderPipeline pipeline = ShaderPipeline.builder(ID.of("gui"))
|
||||||
|
.withStage(ShaderType.VERTEX, ID.of("shader/testGui/vertex.vs"))
|
||||||
|
.withStage(ShaderType.FRAGMENT, ID.of("shader/testGui/fragment.fs"))
|
||||||
|
.withTexture("texture", 0, 0, TextureType.TEXTURE_2D)
|
||||||
|
.withUniform("Camera", 0, 0, 64)
|
||||||
|
.withFormat()
|
||||||
|
.attribute("in_position", 0, 3)
|
||||||
|
.attribute("in_tex", 1, 2)
|
||||||
|
.attribute("in_color", 2, 4, GraphicsDataType.UNSIGNED_BYTE, true)
|
||||||
|
.endFormat()
|
||||||
|
.build();
|
||||||
|
window.visible(true);
|
||||||
|
GraphicsCommandBuffer queue = device.createCommandBuffer(ExecutionType.IMMEDIATE);
|
||||||
|
|
||||||
|
while(!window.shouldClose()) {
|
||||||
|
surface.beginFrame();
|
||||||
|
if(window.changed()) {
|
||||||
|
window.updateViewport();
|
||||||
|
new Matrix4f().ortho(0, 0, window.width() >> scale, window.height() >> scale, 1000, -1000).store(mat);
|
||||||
|
buffer.bind().set(mat.flip().array()).unbind();
|
||||||
|
}
|
||||||
|
queue.begin();
|
||||||
|
queue.pipeline(pipeline)
|
||||||
|
.mesh(mesh)
|
||||||
|
.texture(0, texture, sampler)
|
||||||
|
.uniform(0, buffer)
|
||||||
|
.drawArrays(0, 6)
|
||||||
|
.drawArrays(0, 6);
|
||||||
|
|
||||||
|
queue.end();
|
||||||
|
|
||||||
|
surface.finishFrame();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
catch(Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,341 +1,342 @@
|
|||||||
package speiger.src.coreengine.rendering.input.window;
|
package speiger.src.coreengine.rendering.input.window;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
import org.lwjgl.opengl.GL;
|
import org.lwjgl.opengl.GL;
|
||||||
import org.lwjgl.opengl.GLCapabilities;
|
import org.lwjgl.opengl.GLCapabilities;
|
||||||
import org.lwjgl.system.CallbackI;
|
import org.lwjgl.system.CallbackI;
|
||||||
|
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
import speiger.src.coreengine.math.BitUtil;
|
import speiger.src.coreengine.graphics.api.core.Graphics;
|
||||||
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
import speiger.src.coreengine.math.BitUtil;
|
||||||
import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason;
|
import speiger.src.coreengine.math.vector.ints.Vec4i;
|
||||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
|
import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason;
|
||||||
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
|
import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction;
|
||||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder;
|
||||||
import speiger.src.coreengine.utils.collections.FlagHolder;
|
import speiger.src.coreengine.utils.collections.FlagHolder;
|
||||||
|
|
||||||
public class Window {
|
public class Window {
|
||||||
static final int VISIBLE = 1;
|
static final int VISIBLE = 1;
|
||||||
static final int VSYNC = 2;
|
static final int VSYNC = 2;
|
||||||
static final int FOCUS = 4;
|
static final int FOCUS = 4;
|
||||||
static final int CPU_FPS_CAP = 8;
|
static final int CPU_FPS_CAP = 8;
|
||||||
static final int FULL_SCREEN = 16;
|
static final int FULL_SCREEN = 16;
|
||||||
static final int MAXIMIZED = 32;
|
static final int MAXIMIZED = 32;
|
||||||
static final int BORDERLESS = 64;
|
static final int BORDERLESS = 64;
|
||||||
static final int RESIZABLE = 128;
|
static final int RESIZABLE = 128;
|
||||||
static final int FLOATING = 256;
|
static final int FLOATING = 256;
|
||||||
static final int CLOSE = 512;
|
static final int CLOSE = 512;
|
||||||
static final int WINDOW_CHANGE = 1024;
|
static final int WINDOW_CHANGE = 1024;
|
||||||
WindowManager manager;
|
WindowManager manager;
|
||||||
FlagHolder flags = new FlagHolder();
|
FlagHolder flags = new FlagHolder();
|
||||||
long id;
|
long id;
|
||||||
VideoMode fullScreenMode;
|
VideoMode fullScreenMode;
|
||||||
String title = "";
|
String title = "";
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
||||||
int frameWidth;
|
int frameWidth;
|
||||||
int frameHeight;
|
int frameHeight;
|
||||||
|
|
||||||
Vec4i[] backup = new Vec4i[] {Vec4i.mutable(), Vec4i.mutable()};
|
Vec4i[] backup = new Vec4i[] {Vec4i.mutable(), Vec4i.mutable()};
|
||||||
int backupIndex = 0;
|
int backupIndex = 0;
|
||||||
|
|
||||||
final int antialiasing;
|
final int antialiasing;
|
||||||
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
||||||
List<IWindowListener> listeners = new ObjectArrayList<>();
|
List<IWindowListener> listeners = new ObjectArrayList<>();
|
||||||
GLCapabilities capabilities;
|
GLCapabilities capabilities;
|
||||||
|
|
||||||
protected Window(WindowBuilder builder) {
|
protected Window(WindowBuilder builder, Graphics graphics) {
|
||||||
manager = builder.manager;
|
manager = builder.manager;
|
||||||
title = builder.title;
|
title = builder.title;
|
||||||
frameWidth = width = builder.width;
|
frameWidth = width = builder.width;
|
||||||
frameHeight = height = builder.height;
|
frameHeight = height = builder.height;
|
||||||
antialiasing = builder.antiAlis;
|
antialiasing = builder.antiAlis;
|
||||||
fullScreenMode = builder.fullScreenTarget;
|
fullScreenMode = builder.fullScreenTarget;
|
||||||
flags.setFlag(BORDERLESS, builder.borderless);
|
flags.setFlag(BORDERLESS, builder.borderless);
|
||||||
flags.setFlag(FULL_SCREEN, builder.fullScreen);
|
flags.setFlag(FULL_SCREEN, builder.fullScreen);
|
||||||
flags.setFlag(FLOATING, builder.floating);
|
flags.setFlag(FLOATING, builder.floating);
|
||||||
flags.setFlag(RESIZABLE, builder.resizable);
|
flags.setFlag(RESIZABLE, builder.resizable);
|
||||||
flags.setFlag(VSYNC, builder.vsync);
|
flags.setFlag(VSYNC, builder.vsync);
|
||||||
flags.setFlag(CPU_FPS_CAP, builder.fpsCap);
|
flags.setFlag(CPU_FPS_CAP, builder.fpsCap);
|
||||||
createDefaultWindowHints();
|
if(graphics != null) graphics.setupWindowArguments();
|
||||||
for(int i = 0,m=builder.windowHints.size();i<m;i++) {
|
else createDefaultWindowHints();
|
||||||
long value = builder.windowHints.getLong(i);
|
for(int i = 0,m=builder.windowHints.size();i<m;i++) {
|
||||||
GLFW.glfwWindowHint(BitUtil.intKey(value), BitUtil.intValue(value));
|
long value = builder.windowHints.getLong(i);
|
||||||
}
|
GLFW.glfwWindowHint(BitUtil.intKey(value), BitUtil.intValue(value));
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, antialiasing);
|
}
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, flags.isFlagSet(RESIZABLE) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, antialiasing);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(BORDERLESS) ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, flags.isFlagSet(RESIZABLE) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(FLOATING) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(BORDERLESS) ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(MAXIMIZED) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(FLOATING) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
Monitor monitor = manager.getMonitor(builder.monitor);
|
GLFW.glfwWindowHint(GLFW.GLFW_MAXIMIZED, flags.isFlagNotSet(FULL_SCREEN) && flags.isFlagSet(MAXIMIZED) ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
if(monitor == null) throw new IllegalStateException("Monitor is missing: "+monitor);
|
Monitor monitor = manager.getMonitor(builder.monitor);
|
||||||
VideoMode mode = monitor.defaultMode();
|
if(monitor == null) throw new IllegalStateException("Monitor is missing: "+monitor);
|
||||||
boolean fullscreen = builder.fullScreen;
|
VideoMode mode = monitor.defaultMode();
|
||||||
id = GLFW.glfwCreateWindow(fullscreen ? mode.width() : width, fullscreen ? mode.height() : height, title, builder.fullScreen ? monitor.id() : 0, manager.getPrimaryWindow());
|
boolean fullscreen = builder.fullScreen;
|
||||||
if(id == 0) throw new IllegalStateException("Window Couldn't be Created");
|
id = GLFW.glfwCreateWindow(fullscreen ? mode.width() : width, fullscreen ? mode.height() : height, title, builder.fullScreen ? monitor.id() : 0, manager.getPrimaryWindow());
|
||||||
manager.addWindow(this);
|
if(id == 0) throw new IllegalStateException("Window Couldn't be Created");
|
||||||
createWindowListeners();
|
manager.addWindow(this);
|
||||||
GLFW.glfwMakeContextCurrent(id);
|
createWindowListeners();
|
||||||
capabilities = GL.createCapabilities(true);
|
GLFW.glfwMakeContextCurrent(id);
|
||||||
x = monitor.xOffset() + (builder.center ? (mode.width() / 2) - (width / 2) : 0);
|
if(graphics == null) capabilities = GL.createCapabilities(true);
|
||||||
y = monitor.yOffset() + (builder.center ? (mode.height() / 2) - (height / 2) : 0);
|
x = monitor.xOffset() + (builder.center ? (mode.width() / 2) - (width / 2) : 0);
|
||||||
if(!fullscreen) GLFW.glfwSetWindowPos(id, x, y);
|
y = monitor.yOffset() + (builder.center ? (mode.height() / 2) - (height / 2) : 0);
|
||||||
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
if(!fullscreen) GLFW.glfwSetWindowPos(id, x, y);
|
||||||
fetchWindowBounds();
|
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
||||||
updateViewport();
|
fetchWindowBounds();
|
||||||
}
|
updateViewport();
|
||||||
|
}
|
||||||
protected void createDefaultWindowHints() {
|
|
||||||
GLFW.glfwDefaultWindowHints();
|
protected void createDefaultWindowHints() {
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
GLFW.glfwDefaultWindowHints();
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);
|
||||||
}
|
GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, GLFW.GLFW_TRUE);
|
||||||
|
}
|
||||||
protected void createWindowListeners() {
|
|
||||||
addCallback(this::framebuffer, GLFW::glfwSetFramebufferSizeCallback);
|
protected void createWindowListeners() {
|
||||||
addCallback(this::focused, GLFW::glfwSetWindowFocusCallback);
|
addCallback(this::framebuffer, GLFW::glfwSetFramebufferSizeCallback);
|
||||||
addCallback(this::position, GLFW::glfwSetWindowPosCallback);
|
addCallback(this::focused, GLFW::glfwSetWindowFocusCallback);
|
||||||
addCallback(this::bounds, GLFW::glfwSetWindowSizeCallback);
|
addCallback(this::position, GLFW::glfwSetWindowPosCallback);
|
||||||
}
|
addCallback(this::bounds, GLFW::glfwSetWindowSizeCallback);
|
||||||
|
}
|
||||||
private void framebuffer(long window, int width, int height) {
|
|
||||||
frameWidth = width;
|
private void framebuffer(long window, int width, int height) {
|
||||||
frameHeight = height;
|
frameWidth = width;
|
||||||
flags.setFlag(WINDOW_CHANGE);
|
frameHeight = height;
|
||||||
}
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
}
|
||||||
private void focused(long window, boolean focused) {
|
|
||||||
manager.updateFocus(this, focused);
|
private void focused(long window, boolean focused) {
|
||||||
}
|
manager.updateFocus(this, focused);
|
||||||
|
}
|
||||||
private void position(long window, int x, int y) {
|
|
||||||
this.x = x;
|
private void position(long window, int x, int y) {
|
||||||
this.y = y;
|
this.x = x;
|
||||||
flags.setFlag(WINDOW_CHANGE);
|
this.y = y;
|
||||||
}
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
}
|
||||||
private void bounds(long window, int width, int height) {
|
|
||||||
this.width = width;
|
private void bounds(long window, int width, int height) {
|
||||||
this.height = height;
|
this.width = width;
|
||||||
flags.setFlag(WINDOW_CHANGE);
|
this.height = height;
|
||||||
}
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
|
}
|
||||||
protected void fetchWindowBounds() {
|
|
||||||
int[] width = new int[1];
|
protected void fetchWindowBounds() {
|
||||||
int[] height = new int[1];
|
int[] width = new int[1];
|
||||||
GLFW.glfwGetWindowSize(id, width, height);
|
int[] height = new int[1];
|
||||||
this.frameWidth = width[0];
|
GLFW.glfwGetWindowSize(id, width, height);
|
||||||
this.frameHeight = height[0];
|
this.frameWidth = width[0];
|
||||||
}
|
this.frameHeight = height[0];
|
||||||
|
}
|
||||||
public void updateViewport() {
|
|
||||||
flags.clearFlag(WINDOW_CHANGE);
|
public void updateViewport() {
|
||||||
GLStateTracker.instance().viewPort.setDefault(0, 0, frameWidth, frameHeight);
|
flags.clearFlag(WINDOW_CHANGE);
|
||||||
for(int i = 0,m=listeners.size();i<m;i++) {
|
// GLStateTracker.instance().viewPort.setDefault(0, 0, frameWidth, frameHeight);
|
||||||
listeners.get(i).onChanged(this, Reason.CHANGE);
|
for(int i = 0,m=listeners.size();i<m;i++) {
|
||||||
}
|
listeners.get(i).onChanged(this, Reason.CHANGE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void setupContext() {
|
|
||||||
GL.setCapabilities(capabilities);
|
public void setupContext() {
|
||||||
GLFW.glfwMakeContextCurrent(id);
|
if(capabilities != null) GL.setCapabilities(capabilities);
|
||||||
|
GLFW.glfwMakeContextCurrent(id);
|
||||||
}
|
|
||||||
|
}
|
||||||
public void beginFrame() {
|
|
||||||
setupContext();
|
public void beginFrame() {
|
||||||
if(flags.isFlagSet(WINDOW_CHANGE)) updateViewport();
|
setupContext();
|
||||||
}
|
if(flags.isFlagSet(WINDOW_CHANGE)) updateViewport();
|
||||||
|
}
|
||||||
public void handleInput() { manager.processDevices(id); }
|
|
||||||
public boolean shouldClose() { return flags.isFlagSet(CLOSE) || GLFW.glfwWindowShouldClose(id); }
|
public void handleInput() { manager.processDevices(id); }
|
||||||
public void finishFrame() { GLFW.glfwSwapBuffers(id); }
|
public boolean shouldClose() { return flags.isFlagSet(CLOSE) || GLFW.glfwWindowShouldClose(id); }
|
||||||
|
public void finishFrame() { GLFW.glfwSwapBuffers(id); }
|
||||||
public void destroy() {
|
|
||||||
manager.removeWindow(id);
|
public void destroy() {
|
||||||
for(int i = 0,m=listeners.size();i<m;i++) {
|
manager.removeWindow(id);
|
||||||
listeners.get(i).onChanged(this, Reason.CLOSING);
|
for(int i = 0,m=listeners.size();i<m;i++) {
|
||||||
}
|
listeners.get(i).onChanged(this, Reason.CLOSING);
|
||||||
GLFW.glfwDestroyWindow(id);
|
}
|
||||||
callbacks.forEach(WindowCallback::destroy);
|
GLFW.glfwDestroyWindow(id);
|
||||||
callbacks.clear();
|
callbacks.forEach(WindowCallback::destroy);
|
||||||
}
|
callbacks.clear();
|
||||||
|
}
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T extends CallbackI> WindowCallback addCallback(T listener, ReloadFunction<T> function) {
|
@SuppressWarnings("unchecked")
|
||||||
WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
|
public <T extends CallbackI> WindowCallback addCallback(T listener, ReloadFunction<T> function) {
|
||||||
callbacks.add(callback);
|
WindowCallback callback = new WindowCallback(listener, (ReloadFunction<CallbackI>)function);
|
||||||
callback.load(id);
|
callbacks.add(callback);
|
||||||
return callback;
|
callback.load(id);
|
||||||
}
|
return callback;
|
||||||
|
}
|
||||||
public void removeCallback(WindowCallback callback) {
|
|
||||||
if(callbacks.remove(callback)) {
|
public void removeCallback(WindowCallback callback) {
|
||||||
callback.destroy();
|
if(callbacks.remove(callback)) {
|
||||||
}
|
callback.destroy();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void addListener(IWindowListener listener) {
|
|
||||||
listeners.add(listener);
|
public void addListener(IWindowListener listener) {
|
||||||
}
|
listeners.add(listener);
|
||||||
|
}
|
||||||
public void removeListener(IWindowListener listener) {
|
|
||||||
listeners.remove(listener);
|
public void removeListener(IWindowListener listener) {
|
||||||
}
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
public void title(String name) {
|
|
||||||
if(name == null || title.equals(name)) return;
|
public void title(String name) {
|
||||||
title = name;
|
if(name == null || title.equals(name)) return;
|
||||||
GLFW.glfwSetWindowTitle(id, title);
|
title = name;
|
||||||
}
|
GLFW.glfwSetWindowTitle(id, title);
|
||||||
|
}
|
||||||
public void vsync(boolean vsync) {
|
|
||||||
if(!flags.setFlag(VSYNC, vsync)) return;
|
public void vsync(boolean vsync) {
|
||||||
GLFW.glfwSwapInterval(vsync ? 1 : 0);
|
if(!flags.setFlag(VSYNC, vsync)) return;
|
||||||
}
|
GLFW.glfwSwapInterval(vsync ? 1 : 0);
|
||||||
|
}
|
||||||
public void fpsCap(boolean fpsCap) {
|
|
||||||
flags.setFlag(CPU_FPS_CAP, fpsCap);
|
public void fpsCap(boolean fpsCap) {
|
||||||
}
|
flags.setFlag(CPU_FPS_CAP, fpsCap);
|
||||||
|
}
|
||||||
public void visible(boolean visible) {
|
|
||||||
if(!flags.setFlag(VISIBLE, visible)) return;
|
public void visible(boolean visible) {
|
||||||
if(visible) GLFW.glfwShowWindow(id);
|
if(!flags.setFlag(VISIBLE, visible)) return;
|
||||||
else GLFW.glfwHideWindow(id);
|
if(visible) GLFW.glfwShowWindow(id);
|
||||||
}
|
else GLFW.glfwHideWindow(id);
|
||||||
|
}
|
||||||
public void floating(boolean floating) {
|
|
||||||
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(FLOATING, floating)) {
|
public void floating(boolean floating) {
|
||||||
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_FLOATING, floating ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(FLOATING, floating)) {
|
||||||
}
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_FLOATING, floating ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void maximized(boolean maximized) {
|
|
||||||
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(MAXIMIZED, maximized)) {
|
public void maximized(boolean maximized) {
|
||||||
if(maximized) {
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(MAXIMIZED, maximized)) {
|
||||||
backupSize();
|
if(maximized) {
|
||||||
GLFW.glfwMaximizeWindow(id);
|
backupSize();
|
||||||
}
|
GLFW.glfwMaximizeWindow(id);
|
||||||
else {
|
}
|
||||||
GLFW.glfwRestoreWindow(id);
|
else {
|
||||||
restoreSize();
|
GLFW.glfwRestoreWindow(id);
|
||||||
}
|
restoreSize();
|
||||||
fetchWindowBounds();
|
}
|
||||||
}
|
fetchWindowBounds();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void resizeable(boolean resizeable) {
|
|
||||||
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(RESIZABLE, resizeable)) {
|
public void resizeable(boolean resizeable) {
|
||||||
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_RESIZABLE, resizeable ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(RESIZABLE, resizeable)) {
|
||||||
}
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_RESIZABLE, resizeable ? GLFW.GLFW_TRUE : GLFW.GLFW_FALSE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void borderless(boolean borderless) {
|
|
||||||
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(BORDERLESS, borderless)) {
|
public void borderless(boolean borderless) {
|
||||||
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, borderless ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
if(flags.isFlagNotSet(FULL_SCREEN) && flags.setFlag(BORDERLESS, borderless)) {
|
||||||
if(flags.isFlagSet(MAXIMIZED)) {
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, borderless ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE);
|
||||||
GLFW.glfwRestoreWindow(id);
|
if(flags.isFlagSet(MAXIMIZED)) {
|
||||||
GLFW.glfwMaximizeWindow(id);
|
GLFW.glfwRestoreWindow(id);
|
||||||
fetchWindowBounds();
|
GLFW.glfwMaximizeWindow(id);
|
||||||
}
|
fetchWindowBounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void fullscreen(boolean fullscreen) {
|
|
||||||
if(flags.setFlag(FULL_SCREEN, fullscreen)) {
|
public void fullscreen(boolean fullscreen) {
|
||||||
if(fullscreen) {
|
if(flags.setFlag(FULL_SCREEN, fullscreen)) {
|
||||||
Monitor monitor = manager.getMonitorForWindow(this);
|
if(fullscreen) {
|
||||||
if(monitor == null) {
|
Monitor monitor = manager.getMonitorForWindow(this);
|
||||||
flags.clearFlag(FULL_SCREEN);
|
if(monitor == null) {
|
||||||
return;
|
flags.clearFlag(FULL_SCREEN);
|
||||||
}
|
return;
|
||||||
backupSize();
|
}
|
||||||
VideoMode mode = fullScreenMode == null || !monitor.has(fullScreenMode) ? monitor.defaultMode() : fullScreenMode;
|
backupSize();
|
||||||
x = 0;
|
VideoMode mode = fullScreenMode == null || !monitor.has(fullScreenMode) ? monitor.defaultMode() : fullScreenMode;
|
||||||
y = 0;
|
x = 0;
|
||||||
width = mode.width();
|
y = 0;
|
||||||
height = mode.height();
|
width = mode.width();
|
||||||
GLFW.glfwSetWindowMonitor(id, monitor.id(), 0, 0, mode.width(), mode.height(), mode.refreshrate());
|
height = mode.height();
|
||||||
}
|
GLFW.glfwSetWindowMonitor(id, monitor.id(), 0, 0, mode.width(), mode.height(), mode.refreshrate());
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
restoreSize();
|
{
|
||||||
GLFW.glfwSetWindowMonitor(id, 0, x, y, width, height, -1);
|
restoreSize();
|
||||||
if(flags.isFlagSet(BORDERLESS)) {
|
GLFW.glfwSetWindowMonitor(id, 0, x, y, width, height, -1);
|
||||||
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE);
|
if(flags.isFlagSet(BORDERLESS)) {
|
||||||
}
|
GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE);
|
||||||
if(flags.isFlagSet(MAXIMIZED)) {
|
}
|
||||||
GLFW.glfwMaximizeWindow(id);
|
if(flags.isFlagSet(MAXIMIZED)) {
|
||||||
}
|
GLFW.glfwMaximizeWindow(id);
|
||||||
}
|
}
|
||||||
fetchWindowBounds();
|
}
|
||||||
updateViewport();
|
fetchWindowBounds();
|
||||||
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
updateViewport();
|
||||||
}
|
GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
protected void backupSize() {
|
|
||||||
if(backupIndex >= backup.length) return;
|
protected void backupSize() {
|
||||||
backup[backupIndex++].set(x, y, width, height);
|
if(backupIndex >= backup.length) return;
|
||||||
}
|
backup[backupIndex++].set(x, y, width, height);
|
||||||
|
}
|
||||||
protected void restoreSize() {
|
|
||||||
if(backupIndex == 0) return;
|
protected void restoreSize() {
|
||||||
Vec4i prev = backup[--backupIndex];
|
if(backupIndex == 0) return;
|
||||||
x = prev.x();
|
Vec4i prev = backup[--backupIndex];
|
||||||
y = prev.y();
|
x = prev.x();
|
||||||
width = prev.z();
|
y = prev.y();
|
||||||
height = prev.w();
|
width = prev.z();
|
||||||
}
|
height = prev.w();
|
||||||
|
}
|
||||||
public boolean position(int x, int y) {
|
|
||||||
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.x == x && this.y == y)) return false;
|
public boolean position(int x, int y) {
|
||||||
this.x = x;
|
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.x == x && this.y == y)) return false;
|
||||||
this.y = y;
|
this.x = x;
|
||||||
GLFW.glfwSetWindowPos(id, x, y);
|
this.y = y;
|
||||||
flags.setFlag(WINDOW_CHANGE);
|
GLFW.glfwSetWindowPos(id, x, y);
|
||||||
return true;
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
public boolean size(int width, int height) {
|
|
||||||
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.width == width && this.height == height)) return false;
|
public boolean size(int width, int height) {
|
||||||
this.width = width;
|
if(flags.isAnyFlagSet(MAXIMIZED | FULL_SCREEN) || (this.width == width && this.height == height)) return false;
|
||||||
this.height = height;
|
this.width = width;
|
||||||
GLFW.glfwSetWindowSize(id, width, height);
|
this.height = height;
|
||||||
flags.setFlag(WINDOW_CHANGE);
|
GLFW.glfwSetWindowSize(id, width, height);
|
||||||
return true;
|
flags.setFlag(WINDOW_CHANGE);
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
public boolean width(int width) { return size(width, height); }
|
|
||||||
public boolean height(int height) { return size(width, height); }
|
public boolean width(int width) { return size(width, height); }
|
||||||
|
public boolean height(int height) { return size(width, height); }
|
||||||
public long id() { return id; }
|
|
||||||
public VideoMode desiredFullScreen() { return fullScreenMode; }
|
public long id() { return id; }
|
||||||
|
public VideoMode desiredFullScreen() { return fullScreenMode; }
|
||||||
public int x() { return x; }
|
|
||||||
public int y() { return y; }
|
public int x() { return x; }
|
||||||
public int width() { return frameWidth; }
|
public int y() { return y; }
|
||||||
public int height() { return frameHeight; }
|
public int width() { return frameWidth; }
|
||||||
public int screenWidth() { return width; }
|
public int height() { return frameHeight; }
|
||||||
public int screenHeight() { return height; }
|
public int screenWidth() { return width; }
|
||||||
public boolean changed() { return flags.isFlagSet(WINDOW_CHANGE); }
|
public int screenHeight() { return height; }
|
||||||
|
public boolean changed() { return flags.isFlagSet(WINDOW_CHANGE); }
|
||||||
public String title() { return title; }
|
|
||||||
public boolean isVsync() { return flags.isFlagSet(VSYNC); }
|
public String title() { return title; }
|
||||||
public boolean shouldFPSCap() { return flags.isFlagSet(CPU_FPS_CAP); }
|
public boolean isVsync() { return flags.isFlagSet(VSYNC); }
|
||||||
public boolean isVisible() { return flags.isFlagSet(VISIBLE); }
|
public boolean shouldFPSCap() { return flags.isFlagSet(CPU_FPS_CAP); }
|
||||||
public boolean isFloating() { return flags.isFlagSet(FLOATING); }
|
public boolean isVisible() { return flags.isFlagSet(VISIBLE); }
|
||||||
public boolean isMaximized() { return flags.isFlagSet(MAXIMIZED); }
|
public boolean isFloating() { return flags.isFlagSet(FLOATING); }
|
||||||
public boolean isResizeable() { return flags.isFlagSet(RESIZABLE); }
|
public boolean isMaximized() { return flags.isFlagSet(MAXIMIZED); }
|
||||||
public boolean isBorderless() { return flags.isFlagSet(BORDERLESS); }
|
public boolean isResizeable() { return flags.isFlagSet(RESIZABLE); }
|
||||||
public boolean isFullscreen() { return flags.isFlagSet(FULL_SCREEN); }
|
public boolean isBorderless() { return flags.isFlagSet(BORDERLESS); }
|
||||||
public int antialiasing() { return antialiasing; }
|
public boolean isFullscreen() { return flags.isFlagSet(FULL_SCREEN); }
|
||||||
}
|
public int antialiasing() { return antialiasing; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,266 +1,267 @@
|
|||||||
package speiger.src.coreengine.rendering.input.window;
|
package speiger.src.coreengine.rendering.input.window;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
import org.lwjgl.system.Callback;
|
import org.lwjgl.system.Callback;
|
||||||
import org.lwjgl.system.CallbackI;
|
import org.lwjgl.system.CallbackI;
|
||||||
|
|
||||||
import speiger.src.collections.longs.lists.LongArrayList;
|
import speiger.src.collections.longs.lists.LongArrayList;
|
||||||
import speiger.src.collections.longs.lists.LongList;
|
import speiger.src.collections.longs.lists.LongList;
|
||||||
import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap;
|
import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap;
|
||||||
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
|
import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
|
||||||
import speiger.src.collections.objects.lists.ObjectArrayList;
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
||||||
import speiger.src.coreengine.math.BitUtil;
|
import speiger.src.coreengine.graphics.api.core.Graphics;
|
||||||
import speiger.src.coreengine.rendering.input.devices.InputDevice;
|
import speiger.src.coreengine.math.BitUtil;
|
||||||
import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction;
|
import speiger.src.coreengine.rendering.input.devices.InputDevice;
|
||||||
|
import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction;
|
||||||
public class WindowManager {
|
|
||||||
Long2ObjectMap<Monitor> monitors;
|
public class WindowManager {
|
||||||
Long2ObjectMap<Window> windows = new Long2ObjectConcurrentOpenHashMap<>();
|
Long2ObjectMap<Monitor> monitors;
|
||||||
Window activeWindow;
|
Long2ObjectMap<Window> windows = new Long2ObjectConcurrentOpenHashMap<>();
|
||||||
Window primaryWindow;
|
Window activeWindow;
|
||||||
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
Window primaryWindow;
|
||||||
Callback monitorTracker;
|
List<WindowCallback> callbacks = new ObjectArrayList<>();
|
||||||
List<InputDevice> devices = new ObjectArrayList<>();
|
Callback monitorTracker;
|
||||||
|
List<InputDevice> devices = new ObjectArrayList<>();
|
||||||
public void initialize() {
|
|
||||||
monitors = Monitor.createMonitors();
|
public void initialize() {
|
||||||
addCallback(this::onMonitorChanged, GLFW::glfwSetMonitorCallback);
|
monitors = Monitor.createMonitors();
|
||||||
}
|
addCallback(this::onMonitorChanged, GLFW::glfwSetMonitorCallback);
|
||||||
|
}
|
||||||
private void onMonitorChanged(long monitor, int event) {
|
|
||||||
switch(event) {
|
private void onMonitorChanged(long monitor, int event) {
|
||||||
case GLFW.GLFW_CONNECTED -> monitors.put(monitor, new Monitor(monitor));
|
switch(event) {
|
||||||
case GLFW.GLFW_DISCONNECTED -> monitors.remove(monitor);
|
case GLFW.GLFW_CONNECTED -> monitors.put(monitor, new Monitor(monitor));
|
||||||
}
|
case GLFW.GLFW_DISCONNECTED -> monitors.remove(monitor);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public WindowBuilder builder() { return new WindowBuilder(this); }
|
|
||||||
private Window create(WindowBuilder builder) { return new Window(builder); }
|
public WindowBuilder builder() { return new WindowBuilder(this); }
|
||||||
|
private Window create(WindowBuilder builder, Graphics graphics) { return new Window(builder, graphics); }
|
||||||
public void addDevices(InputDevice...devices) {
|
|
||||||
for(InputDevice device : devices) addDevice(device);
|
public void addDevices(InputDevice...devices) {
|
||||||
}
|
for(InputDevice device : devices) addDevice(device);
|
||||||
public void addDevice(InputDevice device) {
|
}
|
||||||
devices.add(device);
|
public void addDevice(InputDevice device) {
|
||||||
windows.values().forEach(device::register);
|
devices.add(device);
|
||||||
}
|
windows.values().forEach(device::register);
|
||||||
public void removeDevice(InputDevice device) { devices.remove(device); }
|
}
|
||||||
public void processDevices(long windowId) {
|
public void removeDevice(InputDevice device) { devices.remove(device); }
|
||||||
for(int i = 0,m=devices.size();i<m;i++) {
|
public void processDevices(long windowId) {
|
||||||
devices.get(i).processInput(windowId);
|
for(int i = 0,m=devices.size();i<m;i++) {
|
||||||
}
|
devices.get(i).processInput(windowId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T extends CallbackI> WindowCallback addCallback(T listener, SimpleReloadFunction<T> function) {
|
@SuppressWarnings("unchecked")
|
||||||
WindowCallback callback = new WindowCallback(listener, (SimpleReloadFunction<CallbackI>)function);
|
public <T extends CallbackI> WindowCallback addCallback(T listener, SimpleReloadFunction<T> function) {
|
||||||
callbacks.add(callback);
|
WindowCallback callback = new WindowCallback(listener, (SimpleReloadFunction<CallbackI>)function);
|
||||||
callback.load(0L);
|
callbacks.add(callback);
|
||||||
return callback;
|
callback.load(0L);
|
||||||
}
|
return callback;
|
||||||
|
}
|
||||||
public void removeCallback(WindowCallback callback) {
|
|
||||||
if(callbacks.remove(callback)) {
|
public void removeCallback(WindowCallback callback) {
|
||||||
callback.destroy();
|
if(callbacks.remove(callback)) {
|
||||||
}
|
callback.destroy();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void addWindow(Window window) {
|
|
||||||
windows.put(window.id(), window);
|
void addWindow(Window window) {
|
||||||
for(int i = 0,m=devices.size();i<m;i++) {
|
windows.put(window.id(), window);
|
||||||
devices.get(i).register(window);
|
for(int i = 0,m=devices.size();i<m;i++) {
|
||||||
}
|
devices.get(i).register(window);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void updateWindow(long oldId) {
|
|
||||||
Window prev = windows.remove(oldId);
|
void updateWindow(long oldId) {
|
||||||
if(prev == null) return;
|
Window prev = windows.remove(oldId);
|
||||||
windows.put(prev.id(), prev);
|
if(prev == null) return;
|
||||||
}
|
windows.put(prev.id(), prev);
|
||||||
|
}
|
||||||
void removeWindow(long id) {
|
|
||||||
Window window = windows.remove(id);
|
void removeWindow(long id) {
|
||||||
if(window == null) return;
|
Window window = windows.remove(id);
|
||||||
if(window == activeWindow) activeWindow = null;
|
if(window == null) return;
|
||||||
if(window == primaryWindow) {
|
if(window == activeWindow) activeWindow = null;
|
||||||
Iterator<Window> iter = windows.values().iterator();
|
if(window == primaryWindow) {
|
||||||
primaryWindow = iter.hasNext() ? iter.next() : null;
|
Iterator<Window> iter = windows.values().iterator();
|
||||||
}
|
primaryWindow = iter.hasNext() ? iter.next() : null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void updateFocus(Window window, boolean focus) {
|
|
||||||
if(focus) this.activeWindow = window;
|
void updateFocus(Window window, boolean focus) {
|
||||||
else if(activeWindow == window) activeWindow = null;
|
if(focus) this.activeWindow = window;
|
||||||
}
|
else if(activeWindow == window) activeWindow = null;
|
||||||
|
}
|
||||||
void updateInputs(long windowId) {
|
|
||||||
for(int i = 0,m=devices.size();i<m;i++) {
|
void updateInputs(long windowId) {
|
||||||
InputDevice device = devices.get(i);
|
for(int i = 0,m=devices.size();i<m;i++) {
|
||||||
device.reset(windowId);
|
InputDevice device = devices.get(i);
|
||||||
device.processInput(windowId);
|
device.reset(windowId);
|
||||||
}
|
device.processInput(windowId);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void destroy() {
|
|
||||||
callbacks.forEach(WindowCallback::destroy);
|
public void destroy() {
|
||||||
callbacks.clear();
|
callbacks.forEach(WindowCallback::destroy);
|
||||||
}
|
callbacks.clear();
|
||||||
|
}
|
||||||
public long getActiveWindow() {
|
|
||||||
return activeWindow == null ? 0L : activeWindow.id();
|
public long getActiveWindow() {
|
||||||
}
|
return activeWindow == null ? 0L : activeWindow.id();
|
||||||
|
}
|
||||||
public long getPrimaryWindow() {
|
|
||||||
return primaryWindow == null ? 0 : primaryWindow.id();
|
public long getPrimaryWindow() {
|
||||||
}
|
return primaryWindow == null ? 0 : primaryWindow.id();
|
||||||
|
}
|
||||||
public Window getWindow(long window) {
|
|
||||||
return windows.get(window);
|
public Window getWindow(long window) {
|
||||||
}
|
return windows.get(window);
|
||||||
|
}
|
||||||
public Monitor getMonitor(long id) {
|
|
||||||
return monitors.get(id);
|
public Monitor getMonitor(long id) {
|
||||||
}
|
return monitors.get(id);
|
||||||
|
}
|
||||||
public Monitor getPriamryMonitor() {
|
|
||||||
return getMonitor(GLFW.glfwGetPrimaryMonitor());
|
public Monitor getPriamryMonitor() {
|
||||||
}
|
return getMonitor(GLFW.glfwGetPrimaryMonitor());
|
||||||
|
}
|
||||||
public Monitor getMonitorForWindow(Window window) {
|
|
||||||
long current = GLFW.glfwGetWindowMonitor(window.id());
|
public Monitor getMonitorForWindow(Window window) {
|
||||||
if(current != 0L) return getMonitor(current);
|
long current = GLFW.glfwGetWindowMonitor(window.id());
|
||||||
int minX = window.x();
|
if(current != 0L) return getMonitor(current);
|
||||||
int minY = window.y();
|
int minX = window.x();
|
||||||
int maxX = minX + window.screenWidth();
|
int minY = window.y();
|
||||||
int maxY = minY + window.screenHeight();
|
int maxX = minX + window.screenWidth();
|
||||||
int largest = 0;
|
int maxY = minY + window.screenHeight();
|
||||||
Monitor mon = null;
|
int largest = 0;
|
||||||
for(Monitor monitor : monitors.values()) {
|
Monitor mon = null;
|
||||||
int next = monitor.getOverlap(minX, minY, maxX, maxY);
|
for(Monitor monitor : monitors.values()) {
|
||||||
if(next > largest) {
|
int next = monitor.getOverlap(minX, minY, maxX, maxY);
|
||||||
largest = next;
|
if(next > largest) {
|
||||||
mon = monitor;
|
largest = next;
|
||||||
}
|
mon = monitor;
|
||||||
}
|
}
|
||||||
return mon;
|
}
|
||||||
}
|
return mon;
|
||||||
|
}
|
||||||
public static class WindowBuilder {
|
|
||||||
WindowManager manager;
|
public static class WindowBuilder {
|
||||||
long monitor;
|
WindowManager manager;
|
||||||
LongList windowHints = new LongArrayList();
|
long monitor;
|
||||||
VideoMode fullScreenTarget;
|
LongList windowHints = new LongArrayList();
|
||||||
String title = "";
|
VideoMode fullScreenTarget;
|
||||||
int width = 640;
|
String title = "";
|
||||||
int height = 480;
|
int width = 640;
|
||||||
int antiAlis = 4;
|
int height = 480;
|
||||||
boolean vsync = true;
|
int antiAlis = 4;
|
||||||
boolean fpsCap;
|
boolean vsync = true;
|
||||||
boolean fullScreen;
|
boolean fpsCap;
|
||||||
boolean maximized;
|
boolean fullScreen;
|
||||||
boolean resizable = true;
|
boolean maximized;
|
||||||
boolean floating;
|
boolean resizable = true;
|
||||||
boolean borderless;
|
boolean floating;
|
||||||
boolean center = true;
|
boolean borderless;
|
||||||
|
boolean center = true;
|
||||||
private WindowBuilder(WindowManager manager) {
|
|
||||||
this.manager = manager;
|
private WindowBuilder(WindowManager manager) {
|
||||||
monitor = GLFW.glfwGetPrimaryMonitor();
|
this.manager = manager;
|
||||||
}
|
monitor = GLFW.glfwGetPrimaryMonitor();
|
||||||
|
}
|
||||||
public WindowBuilder title(String title) {
|
|
||||||
this.title = Objects.requireNonNull(title);
|
public WindowBuilder title(String title) {
|
||||||
return this;
|
this.title = Objects.requireNonNull(title);
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder width(int width) {
|
|
||||||
this.width = Math.max(1, width);
|
public WindowBuilder width(int width) {
|
||||||
return this;
|
this.width = Math.max(1, width);
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder height(int height) {
|
|
||||||
this.height = Math.max(1, height);
|
public WindowBuilder height(int height) {
|
||||||
return this;
|
this.height = Math.max(1, height);
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder antialis(int antiAlis) {
|
|
||||||
this.antiAlis = Math.max(1, antiAlis);
|
public WindowBuilder antialis(int antiAlis) {
|
||||||
return this;
|
this.antiAlis = Math.max(1, antiAlis);
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder fullscreen(boolean fullScreen) {
|
|
||||||
this.fullScreen = fullScreen;
|
public WindowBuilder fullscreen(boolean fullScreen) {
|
||||||
borderless &= !fullScreen;
|
this.fullScreen = fullScreen;
|
||||||
floating &= !fullScreen;
|
borderless &= !fullScreen;
|
||||||
maximized &= !fullScreen;
|
floating &= !fullScreen;
|
||||||
center &= !fullScreen;
|
maximized &= !fullScreen;
|
||||||
return this;
|
center &= !fullScreen;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder maximized(boolean maximized) {
|
|
||||||
this.maximized = maximized;
|
public WindowBuilder maximized(boolean maximized) {
|
||||||
this.fullScreen &= !maximized;
|
this.maximized = maximized;
|
||||||
center &= !maximized;
|
this.fullScreen &= !maximized;
|
||||||
return this;
|
center &= !maximized;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder borderless(boolean borderless) {
|
|
||||||
this.borderless = borderless;
|
public WindowBuilder borderless(boolean borderless) {
|
||||||
fullScreen &= !borderless;
|
this.borderless = borderless;
|
||||||
return this;
|
fullScreen &= !borderless;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder floating(boolean floating) {
|
|
||||||
this.floating = floating;
|
public WindowBuilder floating(boolean floating) {
|
||||||
fullScreen &= !floating;
|
this.floating = floating;
|
||||||
return this;
|
fullScreen &= !floating;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder resizeable(boolean resizable) {
|
|
||||||
this.resizable = resizable;
|
public WindowBuilder resizeable(boolean resizable) {
|
||||||
return this;
|
this.resizable = resizable;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder centered(boolean center) {
|
|
||||||
this.center = center;
|
public WindowBuilder centered(boolean center) {
|
||||||
this.maximized &= !center;
|
this.center = center;
|
||||||
this.fullScreen &= !center;
|
this.maximized &= !center;
|
||||||
return this;
|
this.fullScreen &= !center;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder monitor(Monitor monitor) {
|
|
||||||
if(monitor == null || monitor.defaultMode() == null) return this;
|
public WindowBuilder monitor(Monitor monitor) {
|
||||||
this.monitor = monitor.id();
|
if(monitor == null || monitor.defaultMode() == null) return this;
|
||||||
return this;
|
this.monitor = monitor.id();
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder fullScreenMode(VideoMode mode) {
|
|
||||||
this.fullScreenTarget = mode;
|
public WindowBuilder fullScreenMode(VideoMode mode) {
|
||||||
return this;
|
this.fullScreenTarget = mode;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder vsync(boolean value) {
|
|
||||||
vsync = value;
|
public WindowBuilder vsync(boolean value) {
|
||||||
return this;
|
vsync = value;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder fpsCap(boolean cap) {
|
|
||||||
fpsCap = cap;
|
public WindowBuilder fpsCap(boolean cap) {
|
||||||
return this;
|
fpsCap = cap;
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public WindowBuilder addCustomHint(int key, int value) {
|
|
||||||
windowHints.add(BitUtil.toLong(key, value));
|
public WindowBuilder addCustomHint(int key, int value) {
|
||||||
return this;
|
windowHints.add(BitUtil.toLong(key, value));
|
||||||
}
|
return this;
|
||||||
|
}
|
||||||
public Window build() {
|
|
||||||
return manager.create(this);
|
public Window build(Graphics graphics) {
|
||||||
}
|
return manager.create(this, graphics);
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+191
-191
@@ -1,192 +1,192 @@
|
|||||||
package speiger.src.coreengine.rendering.textures.custom;
|
package speiger.src.coreengine.rendering.textures.custom;
|
||||||
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import speiger.src.collections.ints.collections.IntIterator;
|
import speiger.src.collections.ints.collections.IntIterator;
|
||||||
import speiger.src.collections.ints.sets.IntLinkedOpenHashSet;
|
import speiger.src.collections.ints.sets.IntLinkedOpenHashSet;
|
||||||
import speiger.src.collections.ints.sets.IntSet;
|
import speiger.src.collections.ints.sets.IntSet;
|
||||||
import speiger.src.coreengine.assets.base.IAssetProvider;
|
import speiger.src.coreengine.assets.base.IAssetProvider;
|
||||||
import speiger.src.coreengine.math.BitUtil;
|
import speiger.src.coreengine.math.BitUtil;
|
||||||
import speiger.src.coreengine.math.misc.ColorSpaces;
|
import speiger.src.coreengine.math.misc.ColorSpaces;
|
||||||
import speiger.src.coreengine.rendering.textures.base.BaseTexture;
|
import speiger.src.coreengine.rendering.textures.base.BaseTexture;
|
||||||
import speiger.src.coreengine.rendering.textures.base.TextureMetadata;
|
import speiger.src.coreengine.rendering.textures.base.TextureMetadata;
|
||||||
import speiger.src.coreengine.rendering.utils.GLFunctions;
|
import speiger.src.coreengine.rendering.utils.GLFunctions;
|
||||||
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
import speiger.src.coreengine.rendering.utils.GLStateTracker;
|
||||||
import speiger.src.coreengine.rendering.utils.values.GLDataType;
|
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.GLTextureFormat;
|
||||||
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter;
|
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter;
|
||||||
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue;
|
import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue;
|
||||||
|
|
||||||
public class DynamicTexture extends BaseTexture implements IDynamicTexture {
|
public class DynamicTexture extends BaseTexture implements IDynamicTexture {
|
||||||
public static final TextureMetadata DEFAULT_PARAMETERS = TextureMetadata.builder().internalFormat(GLTextureFormat.RGBAI).externalFormat(GLTextureFormat.RGBA).dataFormat(GLDataType.UNSIGNED_BYTE)
|
public static final TextureMetadata DEFAULT_PARAMETERS = TextureMetadata.builder().internalFormat(GLTextureFormat.RGBAI).externalFormat(GLTextureFormat.RGBA).dataFormat(GLDataType.UNSIGNED_BYTE)
|
||||||
.arguement(GLTextureParameter.MIN_FILTER, GLTextureValue.NEAREST).arguement(GLTextureParameter.MAG_FILTER, GLTextureValue.NEAREST)
|
.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();
|
.arguement(GLTextureParameter.WRAP_S, GLTextureValue.CLAMP_TO_EDGE).arguement(GLTextureParameter.WRAP_T, GLTextureValue.CLAMP_TO_EDGE).build();
|
||||||
IntSet dirtySections = new IntLinkedOpenHashSet();
|
IntSet dirtySections = new IntLinkedOpenHashSet();
|
||||||
TextureMetadata metadata;
|
TextureMetadata metadata;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
long data;
|
long data;
|
||||||
|
|
||||||
public DynamicTexture(int width, int height, TextureMetadata metadata) {
|
public DynamicTexture(int width, int height, TextureMetadata metadata) {
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
if(width % 16 != 0 || height % 16 != 0) throw new IllegalArgumentException("Texture must be a power of 16");
|
if(width % 16 != 0 || height % 16 != 0) throw new IllegalArgumentException("Texture must be a power of 16");
|
||||||
data = MemoryUtil.nmemAllocChecked(4L * width * height);
|
data = MemoryUtil.nmemAllocChecked(4L * width * height);
|
||||||
track();
|
track();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(IAssetProvider provider) {
|
public void load(IAssetProvider provider) {
|
||||||
createTexture();
|
createTexture();
|
||||||
metadata.applyArguments(id());
|
metadata.applyArguments(id());
|
||||||
GLFunctions.prepare2DImage(id(), 1, metadata, width, height);
|
GLFunctions.prepare2DImage(id(), 1, metadata, width, height);
|
||||||
dirtySections.clear();
|
dirtySections.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(boolean untrack) {
|
public void delete(boolean untrack) {
|
||||||
super.delete(untrack);
|
super.delete(untrack);
|
||||||
if(untrack && data != 0L) {
|
if(untrack && data != 0L) {
|
||||||
MemoryUtil.nmemFree(data);
|
MemoryUtil.nmemFree(data);
|
||||||
data = 0L;
|
data = 0L;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int width() { return width; }
|
public int width() { return width; }
|
||||||
@Override
|
@Override
|
||||||
public int height() { return height; }
|
public int height() { return height; }
|
||||||
@Override
|
@Override
|
||||||
public ColorSpaces colorspace() { return ColorSpaces.ABGR; }
|
public ColorSpaces colorspace() { return ColorSpaces.ABGR; }
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirty() { return !dirtySections.isEmpty(); }
|
public boolean isDirty() { return !dirtySections.isEmpty(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(boolean full) {
|
public void process(boolean full) {
|
||||||
if(full) {
|
if(full) {
|
||||||
GLFunctions.upload2DSubImage(id(), 0, 0, 0, width, height, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data);
|
GLFunctions.upload2DSubImage(id(), 0, 0, 0, width, height, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data);
|
||||||
dirtySections.clear();
|
dirtySections.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GLStateTracker tracker = GLStateTracker.instance();
|
GLStateTracker tracker = GLStateTracker.instance();
|
||||||
tracker.unpack_row_length.set(width());
|
tracker.unpack_row_length.set(width());
|
||||||
Thread thread = Thread.currentThread();
|
Thread thread = Thread.currentThread();
|
||||||
for(IntIterator iter = dirtySections.iterator();iter.hasNext() && !thread.isInterrupted();iter.remove()) {
|
for(IntIterator iter = dirtySections.iterator();iter.hasNext() && !thread.isInterrupted();iter.remove()) {
|
||||||
int key = iter.nextInt();
|
int key = iter.nextInt();
|
||||||
uploadPixels(tracker, BitUtil.shortKey(key) * 16, BitUtil.shortValue(key) * 16);
|
uploadPixels(tracker, BitUtil.shortKey(key) * 16, BitUtil.shortValue(key) * 16);
|
||||||
}
|
}
|
||||||
tracker.unpack_row_length.setDefault();
|
tracker.unpack_row_length.setDefault();
|
||||||
tracker.unpack_skip_pixel.setDefault();
|
tracker.unpack_skip_pixel.setDefault();
|
||||||
tracker.unpack_skip_rows.setDefault();
|
tracker.unpack_skip_rows.setDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void uploadPixels(GLStateTracker tracker, int x, int y) {
|
protected void uploadPixels(GLStateTracker tracker, int x, int y) {
|
||||||
tracker.unpack_skip_pixel.set(x);
|
tracker.unpack_skip_pixel.set(x);
|
||||||
tracker.unpack_skip_rows.set(y);
|
tracker.unpack_skip_rows.set(y);
|
||||||
GLFunctions.upload2DSubImage(id(), 0, x, y, 16, 16, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data);
|
GLFunctions.upload2DSubImage(id(), 0, x, y, 16, 16, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long offset(int x, int y) {
|
protected long offset(int x, int y) {
|
||||||
return ((y * width()) + x) << 2L;
|
return ((y * width()) + x) << 2L;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ensureValid(int index) {
|
protected void ensureValid(int index) {
|
||||||
ensureValid(index % width, index / width);
|
ensureValid(index % width, index / width);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ensureValid(int x, int y) {
|
protected void ensureValid(int x, int y) {
|
||||||
if(x < 0 || y < 0) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"]");
|
if(x < 0 || y < 0) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"]");
|
||||||
if(x > width || y > height) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"], width=["+width+"], height=["+height+"]");
|
if(x > width || y > height) throw new ArrayIndexOutOfBoundsException("Index out of bounds: X=["+x+"], Y=["+y+"], width=["+width+"], height=["+height+"]");
|
||||||
if(data == 0L) throw new IllegalStateException("Texture Data isn't bound");
|
if(data == 0L) throw new IllegalStateException("Texture Data isn't bound");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fill(int x, int y, int width, int height, int data) {
|
public void fill(int x, int y, int width, int height, int data) {
|
||||||
ensureValid(x, y);
|
ensureValid(x, y);
|
||||||
ensureValid(x+width, y+height);
|
ensureValid(x+width, y+height);
|
||||||
for(int xOff = 0;xOff<width;xOff++) {
|
for(int xOff = 0;xOff<width;xOff++) {
|
||||||
for(int yOff = 0;yOff<height;yOff++) {
|
for(int yOff = 0;yOff<height;yOff++) {
|
||||||
MemoryUtil.memPutInt(this.data + offset(x+xOff, y+yOff), data);
|
MemoryUtil.memPutInt(this.data + offset(x+xOff, y+yOff), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(id() == 0) return;
|
if(id() == 0) return;
|
||||||
for(int i = x>>4,m=width>>4;i<m;i++) {
|
for(int i = x>>4,m=width>>4;i<m;i++) {
|
||||||
for(int j = y>>4,n=height>>4;j<n;j++) {
|
for(int j = y>>4,n=height>>4;j<n;j++) {
|
||||||
dirtySections.add(BitUtil.toInt(i, j));
|
dirtySections.add(BitUtil.toInt(i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dirty(int x, int y) {
|
public void dirty(int x, int y) {
|
||||||
if(id() == 0) return;
|
if(id() == 0) return;
|
||||||
ensureValid(x, y);
|
ensureValid(x, y);
|
||||||
dirtySections.add(BitUtil.toInt(x >> 4, y >> 4));
|
dirtySections.add(BitUtil.toInt(x >> 4, y >> 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(int index, int data) {
|
public void set(int index, int data) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
MemoryUtil.memPutInt(this.data + index * 4L, data);
|
MemoryUtil.memPutInt(this.data + index * 4L, data);
|
||||||
dirty(index);
|
dirty(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setR(int index, int red) {
|
public void setR(int index, int red) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
MemoryUtil.memPutByte(data + index * 4L, (byte)(red & 0xFF));
|
MemoryUtil.memPutByte(data + index * 4L, (byte)(red & 0xFF));
|
||||||
dirty(index);
|
dirty(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setG(int index, int green) {
|
public void setG(int index, int green) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
MemoryUtil.memPutByte(data + index * 4L + 1L, (byte)(green & 0xFF));
|
MemoryUtil.memPutByte(data + index * 4L + 1L, (byte)(green & 0xFF));
|
||||||
dirty(index);
|
dirty(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setB(int index, int blue) {
|
public void setB(int index, int blue) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
MemoryUtil.memPutByte(data + index * 4L + 2L, (byte)(blue & 0xFF));
|
MemoryUtil.memPutByte(data + index * 4L + 2L, (byte)(blue & 0xFF));
|
||||||
dirty(index);
|
dirty(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setA(int index, int alpha) {
|
public void setA(int index, int alpha) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
MemoryUtil.memPutByte(data + index * 4L + 3L, (byte)(alpha & 0xFF));
|
MemoryUtil.memPutByte(data + index * 4L + 3L, (byte)(alpha & 0xFF));
|
||||||
dirty(index);
|
dirty(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int get(int index) {
|
public int get(int index) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
return MemoryUtil.memGetInt(data + index * 4L);
|
return MemoryUtil.memGetInt(data + index * 4L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getR(int index) {
|
public int getR(int index) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
return MemoryUtil.memGetByte(data + index * 4L);
|
return MemoryUtil.memGetByte(data + index * 4L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getG(int index) {
|
public int getG(int index) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
return MemoryUtil.memGetByte(data + index * 4L + 1L);
|
return MemoryUtil.memGetByte(data + index * 4L + 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getB(int index) {
|
public int getB(int index) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
return MemoryUtil.memGetByte(data + index * 4L + 2L);
|
return MemoryUtil.memGetByte(data + index * 4L + 2L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getA(int index) {
|
public int getA(int index) {
|
||||||
ensureValid(index);
|
ensureValid(index);
|
||||||
return MemoryUtil.memGetByte(data + index * 4L + 3L);
|
return MemoryUtil.memGetByte(data + index * 4L + 3L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#version 330
|
#version 420
|
||||||
|
|
||||||
in vec4 pass_color;
|
in vec4 pass_color;
|
||||||
in vec2 pass_tex;
|
in vec2 pass_tex;
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
uniform sampler2D texture;
|
layout(binding = 0) uniform sampler2D texture;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec4 color = texture2D(texture, pass_tex);
|
vec4 color = texture2D(texture, pass_tex);
|
||||||
frag_color = pass_color * vec4(1, 1, 1, color.r);
|
frag_color = pass_color * vec4(1, 1, 1, color.r);
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,19 @@
|
|||||||
#version 330
|
#version 420
|
||||||
|
|
||||||
layout(location = 0) in vec3 in_position;
|
layout(location = 0) in vec3 in_position;
|
||||||
layout(location = 1) in vec2 in_tex;
|
layout(location = 1) in vec2 in_tex;
|
||||||
layout(location = 2) in vec4 in_color;
|
layout(location = 2) in vec4 in_color;
|
||||||
|
|
||||||
out vec4 pass_color;
|
out vec4 pass_color;
|
||||||
out vec2 pass_tex;
|
out vec2 pass_tex;
|
||||||
|
|
||||||
uniform mat4 proViewMatrix;
|
layout(binding = 0) uniform Camera {
|
||||||
|
mat4 proViewMatrix;
|
||||||
void main()
|
} camera;
|
||||||
{
|
|
||||||
gl_Position = proViewMatrix * vec4(in_position, 1.0);
|
void main()
|
||||||
pass_color = in_color;
|
{
|
||||||
pass_tex = in_tex;
|
gl_Position = camera.proViewMatrix * vec4(in_position, 1.0);
|
||||||
|
pass_color = in_color;
|
||||||
|
pass_tex = in_tex;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user