diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index 8171053..76702c8 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -5,7 +5,7 @@ connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 gradle.user.home= -java.home=C\:/Program Files/Eclipse Adoptium/jdk25 +java.home=C\:/Program Files/Java/jdk25 jvm.arguments= offline.mode=false override.workspace.settings=true diff --git a/gradle.properties b/gradle.properties index 84c3308..b261586 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx2G -lwjglVersion = 3.3.4 +lwjglVersion = 3.4.2 lwjglNatives = natives-windows \ No newline at end of file diff --git a/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java b/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java index a20344f..6424ec4 100644 --- a/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java +++ b/src/assets/java/speiger/src/coreengine/assets/api/IAssetPackage.java @@ -1,6 +1,8 @@ package speiger.src.coreengine.assets.api; import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; @@ -12,7 +14,9 @@ import java.util.function.Consumer; import org.jspecify.annotations.NullMarked; 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.ZipAssetPackage; @NullMarked public interface IAssetPackage extends AutoCloseable { @@ -23,6 +27,23 @@ public interface IAssetPackage extends AutoCloseable { IAsset get(ID location); void getAll(ID folder, BiConsumer 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 AssetIdentity(Path path) throws IOException { diff --git a/src/assets/java/speiger/src/coreengine/assets/api/ID.java b/src/assets/java/speiger/src/coreengine/assets/api/ID.java index a4a2156..ecabdd1 100644 --- a/src/assets/java/speiger/src/coreengine/assets/api/ID.java +++ b/src/assets/java/speiger/src/coreengine/assets/api/ID.java @@ -43,8 +43,8 @@ public record ID(String domain, String path) implements Comparable { public static final ID of(String location) { Objects.requireNonNull(location); int index = location.indexOf(":"); - String domain = location.substring(0, index); - String path = location.substring(index + 1); + String domain = index == -1 ? "base" : location.substring(0, index); + 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(!isValidPath(path)) throw new IllegalArgumentException("Non [a-zA-Z0-9/_.-] Character found in path of location ["+domain+":"+path+"]"); return new ID(domain, path); diff --git a/src/assets/java/speiger/src/coreengine/assets/impl/parsers/Checksums.java b/src/assets/java/speiger/src/coreengine/assets/impl/parsers/Checksums.java index dec7b5e..75fbba0 100644 --- a/src/assets/java/speiger/src/coreengine/assets/impl/parsers/Checksums.java +++ b/src/assets/java/speiger/src/coreengine/assets/impl/parsers/Checksums.java @@ -18,7 +18,7 @@ public class Checksums { public static class CRC implements IAssetParser { @Override public String parse(Path path) throws IOException { - Map files = Files.readAttributes(path, "crc"); + Map files = Files.readAttributes(path, "*"); if(files.containsKey("crc")) return Long.toHexString(((Long)files.get("crc")) & 0xFFFFFFFFL); CRC32C crc = new CRC32C(); crc.update(Files.readAllBytes(path)); diff --git a/src/assets/java/speiger/src/coreengine/assets/manager/AssetManager.java b/src/assets/java/speiger/src/coreengine/assets/manager/AssetManager.java index 5e0cebb..8107bdd 100644 --- a/src/assets/java/speiger/src/coreengine/assets/manager/AssetManager.java +++ b/src/assets/java/speiger/src/coreengine/assets/manager/AssetManager.java @@ -4,6 +4,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Predicate; @@ -27,6 +28,7 @@ public class AssetManager { List packages; ReloadTracker tracker = new ReloadTracker(); ReloadManager manager; + AtomicInteger InUse = new AtomicInteger(); public AssetManager(BaseProvider provider) { setPackages(provider); @@ -89,21 +91,29 @@ public class AssetManager { } 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 { BaseProvider provider; + AutoCloseable closer; - public WrappedProvider(BaseProvider provider) { + public WrappedProvider(BaseProvider provider, AutoCloseable closer) { this.provider = provider; + this.closer = closer; } @Override public void close() throws Exception { - BaseProvider provider = this.provider; + if(provider == null) return; this.provider = null; - provider.close(); + closer.close(); } @Override diff --git a/src/assets/java/speiger/src/coreengine/assets/providers/BaseProvider.java b/src/assets/java/speiger/src/coreengine/assets/providers/BaseProvider.java index 5252684..2b355be 100644 --- a/src/assets/java/speiger/src/coreengine/assets/providers/BaseProvider.java +++ b/src/assets/java/speiger/src/coreengine/assets/providers/BaseProvider.java @@ -5,6 +5,6 @@ import java.util.List; import speiger.src.coreengine.assets.api.IAssetPackage; import speiger.src.coreengine.assets.api.IAssetProvider; -public interface BaseProvider extends IAssetProvider, AutoCloseable { +public interface BaseProvider extends IAssetProvider { List packages(); } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/VertexBuffer.java b/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/VertexBuffer.java index 6d84b2d..f1700bc 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/VertexBuffer.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/buffer/VertexBuffer.java @@ -38,13 +38,21 @@ public abstract class VertexBuffer implements GraphicsResource { public abstract VertexBuffer allocate(int totalBytes); public abstract VertexBuffer set(long pointer, int totalBytes); - public VertexBuffer set(ByteBuffer buffer) { - return set(MemoryUtil.memAddress(buffer), buffer.remaining()); + public VertexBuffer set(ByteBuffer buffer) { 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 VertexBuffer fill(int offset, ByteBuffer buffer) { - return fill(MemoryUtil.memAddress(buffer), buffer.remaining(), offset); + public VertexBuffer fill(int offset, ByteBuffer buffer) { 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); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandBuffer.java b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandBuffer.java index 19cd9c7..a5b5a5c 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandBuffer.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandBuffer.java @@ -13,10 +13,13 @@ public interface GraphicsCommandBuffer extends GraphicsResource { GraphicsCommandBuffer pipeline(ShaderPipeline pipeline); GraphicsCommandBuffer mesh(Mesh mesh); - GraphicsCommandBuffer texture(int set, int binding, Texture texture, Sampler sampler); - GraphicsCommandBuffer uniform(int set, int binding, VertexBuffer buffer); + GraphicsCommandBuffer texture(int binding, Texture texture, Sampler sampler); - 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 popScissors(); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java index cc7a27b..c74ab6b 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsCommandQueue.java @@ -1,34 +1,31 @@ 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.texture.Texture; +import speiger.src.coreengine.graphics.api.texture.states.TextureFormat; import speiger.src.coreengine.graphics.api.utils.PushableResource; import speiger.src.coreengine.math.vector.floats.Vec4f; public interface GraphicsCommandQueue { public static final int CLEAR_COLOR = 1; public static final int CLEAR_DEPTH = 2; + public static final int CLEAR_BOTH = 3; public PushableResource putClearColor(Vec4f color); public PushableResource putClearDepth(double value); 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 x, int y, int width, int height, int clearParam); public void clearTexture(Texture texture, int clearParam); public void clearTexture(Texture texture, int x, int y, int width, int height, int clearParam); - public void writeToTexture(Texture target, int x, int y, int width, int height, long source); - public void readFromTexture(Texture source, int x, int y, int width, int height, long target); + public void writeToTexture(Texture target, TextureFormat format, GraphicsDataType dataType, long source); + 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 record DrawArea(int x, int y, int width, int height) { - public boolean fits(int x, int y, int width, int height) { - return x >= x() && y >= y() && x + width < width() && y + height < height(); - } - - public boolean fills(int width, int height) { - return x == 0 && y == 0 && width == width() && height == height(); - } - } } \ No newline at end of file diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java index 20a8f11..0ac718d 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/core/GraphicsDevice.java @@ -1,24 +1,28 @@ 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.states.BufferState; import speiger.src.coreengine.graphics.api.buffer.states.BufferType; 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.shader.ShaderPipeline; import speiger.src.coreengine.graphics.api.texture.Texture; import speiger.src.coreengine.graphics.api.texture.TextureSettings; import speiger.src.coreengine.graphics.api.utils.ExecutionType; import speiger.src.coreengine.rendering.input.window.Window; public interface GraphicsDevice { - public Window getWindow(); - public GraphicsSurface createSurface(); - public GraphicsCommandBuffer createCommandBuffer(ExecutionType type); - public GraphicsCommandQueue getQueue(); - public VertexBuffer createBuffer(BufferType type, BufferState state); - public VertexBuffer createBuffer(BufferType type, BufferState state, int allocatedBytes); - public Texture createTexture(TextureSettings data, int width, int height); - public Sampler createSampler(SamplerSettings settings); - public Mesh createMesh(Mesh.Builder builder); + Window window(); + GraphicsSurface createSurface(); + GraphicsCommandBuffer createCommandBuffer(ExecutionType type); + GraphicsCommandQueue queue(); + VertexBuffer createBuffer(BufferType type, BufferState state); + VertexBuffer createBuffer(BufferType type, BufferState state, int allocatedBytes); + Texture createTexture(TextureSettings data, int width, int height); + Sampler createSampler(SamplerSettings settings); + Mesh createMesh(Mesh.Builder builder); + void preloadPipelines(List pipelines); } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/sampler/SamplerSettings.java b/src/graphics/java/speiger/src/coreengine/graphics/api/sampler/SamplerSettings.java index 9dc31a0..61b8038 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/sampler/SamplerSettings.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/sampler/SamplerSettings.java @@ -16,6 +16,10 @@ public record SamplerSettings(BorderMode wrapS, BorderMode wrapT, Optional shaders, List> swizzle, Optional stencilType) { +public record TextureSettings(TextureType type, TextureFormat internal, boolean generateMipmapping, OptionalInt baseLevel, OptionalInt maxLevel, ImmutableObjectList> swizzle, Optional stencilType) { public TextureSettings { Objects.requireNonNull(type, "Texture Type 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(maxLevel); Objects.requireNonNull(swizzle); @@ -33,9 +32,8 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF } public static class Builder { - TextureFormat internalFormat; - TextureFormat externalFormat; - TextureType type; + TextureFormat internalFormat = TextureFormat.RGBA; + TextureType type = TextureType.TEXTURE_2D; boolean generateMipmapping = false; OptionalInt baseLevel = OptionalInt.empty(); OptionalInt maxLevel = OptionalInt.empty(); @@ -47,7 +45,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF private Builder(TextureSettings settings) { type = settings.type; internalFormat = settings.internal; - externalFormat = settings.external; generateMipmapping = settings.generateMipmapping; baseLevel = settings.baseLevel; maxLevel = settings.maxLevel; @@ -58,8 +55,7 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF public TextureSettings build() { return new TextureSettings( Objects.requireNonNull(type, "Texture Type shouldn't be null"), - Objects.requireNonNull(internalFormat, "Internal Format shouldn't be null"), - Objects.requireNonNull(externalFormat, "External Format shouldn't be null"), + Objects.requireNonNull(internalFormat, "Internal Format shouldn't be null"), generateMipmapping, baseLevel, maxLevel, new ImmutableObjectList<>(swizzle), stencilType); } @@ -70,7 +66,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF public Builder format(TextureFormat format) { this.internalFormat = format; - this.externalFormat = format; return this; } @@ -79,11 +74,6 @@ public record TextureSettings(TextureType type, TextureFormat internal, TextureF return this; } - public Builder external(TextureFormat format) { - this.externalFormat = format; - return this; - } - public Builder swizzle(SwizzleMask red, SwizzleMask green, SwizzleMask blue, SwizzleMask alpha) { swizzle[0] = Optional.ofNullable(red); swizzle[1] = Optional.ofNullable(green); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/texture/states/TextureFormat.java b/src/graphics/java/speiger/src/coreengine/graphics/api/texture/states/TextureFormat.java index 5b3b91a..1d20f34 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/texture/states/TextureFormat.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/texture/states/TextureFormat.java @@ -1,11 +1,22 @@ package speiger.src.coreengine.graphics.api.texture.states; public enum TextureFormat { - R, - RGB, - RGBA, - DEPTH, - DEPTH_STENCIL, - LUMINANCE, - LUMINANCE_ALPHA + R(1), + RG(2), + RGB(3), + RGBA(4), + DEPTH(1), + DEPTH_STENCIL(2), + LUMINANCE(1), + LUMINANCE_ALPHA(2); + + int components; + + private TextureFormat(int components) { + this.components = components; + } + + public int components() { + return components; + } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java b/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java index df5ee2f..1859d43 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/utils/ScissorsManager.java @@ -1,18 +1,29 @@ 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.utils.Stack; import speiger.src.coreengine.math.vector.ints.Vec4i; public class ScissorsManager { + IScissorsHandler handler; Stack stack = new ObjectArrayList<>(); + boolean withRoot = false; int limit; - public ScissorsManager(int limit) { + public ScissorsManager(int limit, IScissorsHandler handler) { if(limit <= 0) throw new IllegalStateException("Limit is negative"); 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) { @@ -22,12 +33,18 @@ public class ScissorsManager { } if(stack.isEmpty()) { stack.push(Vec4i.of(x, y, x + width, y + height)); - GL11.glEnable(GL11.GL_SCISSOR_TEST); - GL11.glScissor(x, y, width, height); + handler.enable(); + handler.apply(x, y, width, height); return; } Vec4i top = stack.top(); - stack.push(Vec4i.of(Math.max(x, top.x()), Math.max(y, top.y()), Math.min(x + width, top.z()), Math.min(y + height, top.w()))); + 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) { @@ -39,14 +56,39 @@ public class ScissorsManager { } public void pop() { - if(stack.isEmpty()) { + if(stack.size() <= (withRoot ? 1 : 0)) { //TODO implement logging return; } 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() { 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) {} + } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/api/vertex/VertexLayout.java b/src/graphics/java/speiger/src/coreengine/graphics/api/vertex/VertexLayout.java index a40d349..1660a12 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/api/vertex/VertexLayout.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/api/vertex/VertexLayout.java @@ -40,7 +40,7 @@ public class VertexLayout implements ObjectIterable { private void add(Element element) { if(mapped.put(element.name(), element) != null) throw new IllegalStateException("Duplicated Names are not allowed"); elements.add(element); - offsets.add(stride); + offsets.add(bytes); int size = element.size(); stride += size; bytes += element.type().size(size); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/buffer/GLVertexBuffer.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/buffer/GLVertexBuffer.java index e299f49..068f288 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/buffer/GLVertexBuffer.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/buffer/GLVertexBuffer.java @@ -29,6 +29,7 @@ public class GLVertexBuffer extends VertexBuffer { } public int id() { + if(id == 0) throw new IllegalStateException("Buffer is already removed"); return id; } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java index 6a03d2e..3d5bfbe 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLCommandQueue.java @@ -7,17 +7,24 @@ import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL45; -import speiger.src.coreengine.assets.AssetLocation; +import speiger.src.coreengine.assets.api.ID; import speiger.src.coreengine.graphics.api.core.GraphicsCommandBuffer; 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.ScreenTarget; import speiger.src.coreengine.graphics.api.target.TextureTarget; 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.opengl.texture.FrameBufferCache; 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.ints.Vec4i; import speiger.src.coreengine.rendering.input.window.Window; public class GLCommandQueue implements GraphicsCommandQueue { @@ -25,12 +32,14 @@ public class GLCommandQueue implements GraphicsCommandQueue { FrameBufferCache fboCache = new FrameBufferCache(); RenderTarget renderTarget = ScreenTarget.INSTANCE; ScreenBuffer targetFBO; + int tempWriteFBO; Vec4f clearColor = Vec4f.mutable(0F, 0F, 0F, 1F); double clearDepth = 0D; public GLCommandQueue(GLGraphicsDevice 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 @@ -48,6 +57,22 @@ public class GLCommandQueue implements GraphicsCommandQueue { 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) { if(clearColor.equals(value)) return value; clearColor.set(value); @@ -67,10 +92,10 @@ public class GLCommandQueue implements GraphicsCommandQueue { this.renderTarget = target; targetFBO = switch(target) { case ScreenTarget _ -> { - Window window = device.getWindow(); + Window window = device.window(); 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); if(color != null) { GL45.glNamedFramebufferTexture(fbo, GL30.GL_COLOR_ATTACHMENT0, ((GLTexture)color).id(), 0); @@ -90,26 +115,61 @@ public class GLCommandQueue implements GraphicsCommandQueue { @Override 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 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 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 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 - 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 - 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 original, T applying, Supplier current, Consumer apply) implements PushableResource { @@ -122,9 +182,4 @@ public class GLCommandQueue implements GraphicsCommandQueue { } private record ScreenBuffer(int fbo, int width, int height) {} - - @Override - public void submitCommands(GraphicsCommandBuffer buffer) { - - } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphics.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphics.java index 8e531c8..feafd72 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphics.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphics.java @@ -1,12 +1,19 @@ package speiger.src.coreengine.graphics.opengl.core; 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.rendering.input.window.Window; public class GLGraphics implements Graphics { + AssetManager manager; + public GLGraphics(AssetManager manager) { + this.manager = manager; + } + @Override public String getName() { return "OpenGL"; @@ -14,6 +21,9 @@ public class GLGraphics implements Graphics { @Override 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_MINOR, 0); GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE); @@ -22,7 +32,7 @@ public class GLGraphics implements Graphics { @Override public GLGraphicsDevice createDevice(Window window) { - return new GLGraphicsDevice(window); + return new GLGraphicsDevice(window, manager, GL.createCapabilities()); } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java index c71f18c..4e3f215 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLGraphicsDevice.java @@ -1,19 +1,41 @@ package speiger.src.coreengine.graphics.opengl.core; +import java.nio.ByteBuffer; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.OptionalInt; +import java.util.function.IntPredicate; +import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; +import org.lwjgl.opengl.GL20; +import org.lwjgl.opengl.GL31; import org.lwjgl.opengl.GL33; +import org.lwjgl.opengl.GL41; import org.lwjgl.opengl.GL43; 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.Int2ObjectOpenHashMap; 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.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.states.BufferState; 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.LayoutInfo; 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.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.states.SwizzleMask; +import speiger.src.coreengine.graphics.api.texture.states.TextureType; import speiger.src.coreengine.graphics.api.utils.ExecutionType; 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.ShaderCache; 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.utils.GLFunctions; +import speiger.src.coreengine.graphics.opengl.utils.GLStates; import speiger.src.coreengine.graphics.opengl.utils.GLUtils; import speiger.src.coreengine.rendering.input.window.Window; public class GLGraphicsDevice implements GraphicsDevice { + static final Map IMPORTS = Object2ObjectMap.builder().map().synchronize(); + Object2IntMap shaderCache = new Object2IntOpenHashMap<>(); + Object2ObjectMap programCache = new Object2ObjectOpenHashMap<>(); + AssetManager manager; + GLCapabilities capabilities; + GLStates states = new GLStates(); + ShaderCache cache = new ShaderCache(); GLCommandQueue queue; Window owner; - public GLGraphicsDevice(Window owner) { + public GLGraphicsDevice(Window owner, AssetManager manager, GLCapabilities capbilities) { this.owner = owner; + this.manager = manager; + this.capabilities = capbilities; this.queue = new GLCommandQueue(this); } @Override - public Window getWindow() { + public Window window() { return owner; } @@ -56,11 +98,11 @@ public class GLGraphicsDevice implements GraphicsDevice { @Override public GraphicsCommandBuffer createCommandBuffer(ExecutionType type) { - return null; + return type == ExecutionType.IMMEDIATE ? new GLImmidateCommandBuffer(this) : new GLRecordingCommandBuffer(this); } @Override - public GLCommandQueue getQueue() { + public GLCommandQueue queue() { return queue; } @@ -79,6 +121,7 @@ public class GLGraphicsDevice implements GraphicsDevice { public GLTexture createTexture(TextureSettings settings, int width, int height) { if(width < 0) throw new IllegalArgumentException("Width ["+width+"] 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()); 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)); @@ -92,6 +135,7 @@ public class GLGraphicsDevice implements GraphicsDevice { 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); } @@ -116,7 +160,162 @@ public class GLGraphicsDevice implements GraphicsDevice { return new GLMesh(builder.info(), new Int2ObjectOpenHashMap<>(), null, null, false); } - public ShaderInstance createShader(ShaderPipeline line, IAssetProvider provider) { - return null; + @Override + public void preloadPipelines(List 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 map = Object2ObjectMap.builder().map(); + assets.forEach(map, (K, V) -> K.put(V.location(), V)); + IntList shaders = new IntArrayList(); + for(Entry 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 uniforms = new ShaderStorage<>(); + ShaderStorage 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 ""; + } + }); } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLImmidateCommandBuffer.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLImmidateCommandBuffer.java index a166bcd..b8b5de6 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLImmidateCommandBuffer.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLImmidateCommandBuffer.java @@ -1,85 +1,206 @@ 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.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.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 { + GLGraphicsDevice device; + boolean removed = false; boolean recording = false; - ShaderPipeline pipeline; - Mesh mesh; 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() { + if(removed) throw new IllegalStateException("CommandBuffer is removed"); if(!recording) throw new IllegalStateException("CommandBuffer isn't recording"); } @Override - public boolean isRemoved() { return false; } + public boolean isRemoved() { return removed; } @Override - public void remove() {} + public void remove() { + clear(); + device = null; + removed = true; + recorded = 0; + } @Override public GraphicsCommandBuffer begin() { + if(removed) throw new IllegalStateException("CommandBuffer is removed"); if(recording) throw new IllegalStateException("CommandBuffer already recording"); recording = true; + recorded = 0; 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); + 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; } @Override 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; } @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; } @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; } @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; } @Override public GraphicsCommandBuffer pushScissors(int x, int y, int width, int height) { + ensureDrawing(); + scissors.push(x, y, width, height); return this; } @Override public GraphicsCommandBuffer popScissors() { + ensureDrawing(); + scissors.pop(); return this; } @Override public GraphicsCommandBuffer end() { if(!recording) throw new IllegalStateException("Already Stopped Recording"); - pipeline = null; - mesh = null; - recording = false; + clear(); return this; } + private void clear() { + recording = false; + pipeline = null; + shader = null; + mesh = null; + scissors.clear(); + } + @Override public int commandCount() { return recorded; } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLRecordingCommandBuffer.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLRecordingCommandBuffer.java new file mode 100644 index 0000000..e025481 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLRecordingCommandBuffer.java @@ -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 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); + } + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLSurface.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLSurface.java index 679dcec..7d4a41f 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLSurface.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/core/GLSurface.java @@ -1,6 +1,7 @@ package speiger.src.coreengine.graphics.opengl.core; import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL11; import speiger.src.coreengine.graphics.api.core.GraphicsSurface; import speiger.src.coreengine.rendering.input.window.Window; @@ -19,6 +20,9 @@ public class GLSurface implements GraphicsSurface { @Override public void beginFrame() { + GL11.glClearColor(0.2F, 0.55F, 0.66F, 1F); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + window.beginFrame(); GLFW.glfwPollEvents(); } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/mesh/GLMesh.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/mesh/GLMesh.java index 18105ce..14d9f39 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/mesh/GLMesh.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/mesh/GLMesh.java @@ -1,6 +1,7 @@ package speiger.src.coreengine.graphics.opengl.mesh; import org.jspecify.annotations.Nullable; +import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL45; 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 public boolean isRemoved() { return vao == 0; } @@ -47,6 +64,7 @@ public class GLMesh extends Mesh { } private void bindElement() { + indeciesBuffer.bind(); GL45.glVertexArrayElementBuffer(vao, ((GLVertexBuffer)indeciesBuffer).id()); } @@ -54,6 +72,7 @@ public class GLMesh extends Mesh { LayoutInfo info = layouts.get(binding); VertexLayout layout = info.layout(); GLVertexBuffer buffer = (GLVertexBuffer)buffers.get(binding); + buffer.bind(); GL45.glVertexArrayVertexBuffer(vao, binding, buffer.id(), 0, layout.bytes()); if(info.instanceCount() > 0) GL45.glVertexArrayBindingDivisor(vao, binding, info.instanceCount()); int index = 0; diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/sampler/GLSampler.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/sampler/GLSampler.java index 8f37ae8..fecbe09 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/sampler/GLSampler.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/sampler/GLSampler.java @@ -27,6 +27,10 @@ public class GLSampler extends Sampler { GL45.glSamplerParameteri(id, GL11.GL_TEXTURE_MAG_FILTER, GLUtils.toGL(settings.magSample())); } + public int id() { + return id; + } + @Override public boolean isRemoved() { return id == 0; diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java index 0562a23..179bbed 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderCache.java @@ -2,10 +2,14 @@ package speiger.src.coreengine.graphics.opengl.shader; import java.io.BufferedReader; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.function.Supplier; + +import org.lwjgl.system.MemoryUtil; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -62,12 +66,16 @@ public class ShaderCache { catch(Exception e) { e.printStackTrace(); } } - public byte[] get(ID shaderId, String fileHash) { + public ByteBuffer get(ID shaderId, Supplier fileHash) { + if(cache == null) return null; 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); 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(); } return null; } @@ -76,6 +84,7 @@ public class ShaderCache { Objects.requireNonNull(shaderId); Objects.requireNonNull(fileHash); Objects.requireNonNull(shader); + if(cache == null) return; hashCache.put(shaderId, fileHash); try { Path file = toFile(shaderId); @@ -89,6 +98,7 @@ public class ShaderCache { } public void delete(ID shaderId) { + if(cache == null) return; if(hashCache.remove(shaderId) == null) return; try { Files.deleteIfExists(toFile(shaderId)); } catch(Exception e) { e.printStackTrace(); } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java index 23f9dd1..53d6269 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderInstance.java @@ -2,8 +2,29 @@ package speiger.src.coreengine.graphics.opengl.shader; import java.util.Map; -public record ShaderInstance(int programId, Map uniforms, Map 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 uniforms, ShaderStorage samplers) { public record UniformObject(int slot) {} public record SamplerObject(int unit) {} + + public static class ShaderStorage { + Map byName = new Object2ObjectOpenHashMap<>(); + Int2ObjectMap 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); + } + } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderTracker.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderTracker.java new file mode 100644 index 0000000..cc2dea7 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/shader/ShaderTracker.java @@ -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 knownShaders = new ObjectArrayList(); + 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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java index e15d84d..e128bae 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/texture/FrameBufferCache.java @@ -4,16 +4,16 @@ import org.lwjgl.opengl.GL45; import speiger.src.collections.objects.maps.impl.hash.Object2IntOpenHashMap; import speiger.src.collections.objects.maps.interfaces.Object2IntMap; -import speiger.src.coreengine.assets.AssetLocation; +import speiger.src.coreengine.assets.api.ID; public class FrameBufferCache { - Object2IntMap fboCache = new Object2IntOpenHashMap<>(); + Object2IntMap fboCache = new Object2IntOpenHashMap<>(); - public int getOrCreateFBO(AssetLocation id) { + public int getOrCreateFBO(ID id) { return fboCache.supplyIntIfAbsent(id, GL45::glCreateFramebuffers); } - public void deleteFBO(AssetLocation id) { + public void deleteFBO(ID id) { int fbo = fboCache.rem(id); if(fbo == -1) return; GL45.glDeleteFramebuffers(fbo); diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLScissorsHandler.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLScissorsHandler.java new file mode 100644 index 0000000..5be7292 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLScissorsHandler.java @@ -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)); } +} \ No newline at end of file diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLStates.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLStates.java new file mode 100644 index 0000000..341ac08 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLStates.java @@ -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)); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLUtils.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLUtils.java index ececee8..fcdfcb9 100644 --- a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLUtils.java +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/GLUtils.java @@ -5,6 +5,7 @@ import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL21; import org.lwjgl.opengl.GL30; 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.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.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.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.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.utils.AlphaFunction; -public class GLUtils { - //Buffer Begin - +public class GLUtils { public static int toGL(BufferType type) { return switch(type) { case ARRAY_BUFFER -> GL15.GL_ARRAY_BUFFER; @@ -58,9 +63,7 @@ public class GLUtils { case DYNAMIC_COPY -> GL15.GL_DYNAMIC_COPY; }; } - - //Texture Begin - + public static int toGL(TextureType type) { return switch(type) { 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) { return switch(mask) { 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; }; } + + 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; + }; + } } diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/ViewPortStack.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/ViewPortStack.java new file mode 100644 index 0000000..3236797 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/ViewPortStack.java @@ -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 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(); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/BlendState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/BlendState.java new file mode 100644 index 0000000..f30e339 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/BlendState.java @@ -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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/CullState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/CullState.java new file mode 100644 index 0000000..95d97c5 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/CullState.java @@ -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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/FloatState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/FloatState.java new file mode 100644 index 0000000..d7b34c2 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/FloatState.java @@ -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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLPolygon.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLPolygon.java new file mode 100644 index 0000000..18290cc --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLPolygon.java @@ -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)); + } +} \ No newline at end of file diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLState.java new file mode 100644 index 0000000..51ca008 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/GLState.java @@ -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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/IGLState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/IGLState.java new file mode 100644 index 0000000..45845fd --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/IGLState.java @@ -0,0 +1,7 @@ +package speiger.src.coreengine.graphics.opengl.utils.states; + +public interface IGLState +{ + public void setDefault(); + public void reapply(); +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/PixelState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/PixelState.java new file mode 100644 index 0000000..53ac6a2 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/PixelState.java @@ -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); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/SamplerState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/SamplerState.java new file mode 100644 index 0000000..a44e4a5 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/SamplerState.java @@ -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); + } +} \ No newline at end of file diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/ScissorState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/ScissorState.java new file mode 100644 index 0000000..53567ab --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/ScissorState.java @@ -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()); + } +} diff --git a/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/TextureState.java b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/TextureState.java new file mode 100644 index 0000000..81dee46 --- /dev/null +++ b/src/graphics/java/speiger/src/coreengine/graphics/opengl/utils/states/TextureState.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/NewInputTest.java b/src/main/java/speiger/src/coreengine/NewInputTest.java index 9ace68e..77865af 100644 --- a/src/main/java/speiger/src/coreengine/NewInputTest.java +++ b/src/main/java/speiger/src/coreengine/NewInputTest.java @@ -76,8 +76,8 @@ public class NewInputTest { Joystick.INSTANCE.init(manager, bus); FileDrop.INSTANCE.init(bus); 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 secondWindow = manager.builder().title("Second Window 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(null); Thread.ofPlatform().start(() -> drawSecondScreen(secondWindow)); window.setupContext(); shaderTest.register(); diff --git a/src/main/java/speiger/src/coreengine/NewRenderEngineTest.java b/src/main/java/speiger/src/coreengine/NewRenderEngineTest.java new file mode 100644 index 0000000..6ddf43a --- /dev/null +++ b/src/main/java/speiger/src/coreengine/NewRenderEngineTest.java @@ -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(); + } + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/input/window/Window.java b/src/main/java/speiger/src/coreengine/rendering/input/window/Window.java index a4dbb40..98a8c24 100644 --- a/src/main/java/speiger/src/coreengine/rendering/input/window/Window.java +++ b/src/main/java/speiger/src/coreengine/rendering/input/window/Window.java @@ -1,341 +1,342 @@ -package speiger.src.coreengine.rendering.input.window; - -import java.util.List; - -import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL; -import org.lwjgl.opengl.GLCapabilities; -import org.lwjgl.system.CallbackI; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.math.BitUtil; -import speiger.src.coreengine.math.vector.ints.Vec4i; -import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason; -import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction; -import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder; -import speiger.src.coreengine.rendering.utils.GLStateTracker; -import speiger.src.coreengine.utils.collections.FlagHolder; - -public class Window { - static final int VISIBLE = 1; - static final int VSYNC = 2; - static final int FOCUS = 4; - static final int CPU_FPS_CAP = 8; - static final int FULL_SCREEN = 16; - static final int MAXIMIZED = 32; - static final int BORDERLESS = 64; - static final int RESIZABLE = 128; - static final int FLOATING = 256; - static final int CLOSE = 512; - static final int WINDOW_CHANGE = 1024; - WindowManager manager; - FlagHolder flags = new FlagHolder(); - long id; - VideoMode fullScreenMode; - String title = ""; - int x; - int y; - int width; - int height; - - int frameWidth; - int frameHeight; - - Vec4i[] backup = new Vec4i[] {Vec4i.mutable(), Vec4i.mutable()}; - int backupIndex = 0; - - final int antialiasing; - List callbacks = new ObjectArrayList<>(); - List listeners = new ObjectArrayList<>(); - GLCapabilities capabilities; - - protected Window(WindowBuilder builder) { - manager = builder.manager; - title = builder.title; - frameWidth = width = builder.width; - frameHeight = height = builder.height; - antialiasing = builder.antiAlis; - fullScreenMode = builder.fullScreenTarget; - flags.setFlag(BORDERLESS, builder.borderless); - flags.setFlag(FULL_SCREEN, builder.fullScreen); - flags.setFlag(FLOATING, builder.floating); - flags.setFlag(RESIZABLE, builder.resizable); - flags.setFlag(VSYNC, builder.vsync); - flags.setFlag(CPU_FPS_CAP, builder.fpsCap); - createDefaultWindowHints(); - for(int i = 0,m=builder.windowHints.size();i WindowCallback addCallback(T listener, ReloadFunction function) { - WindowCallback callback = new WindowCallback(listener, (ReloadFunction)function); - callbacks.add(callback); - callback.load(id); - return callback; - } - - public void removeCallback(WindowCallback callback) { - if(callbacks.remove(callback)) { - callback.destroy(); - } - } - - public void addListener(IWindowListener listener) { - listeners.add(listener); - } - - public void removeListener(IWindowListener listener) { - listeners.remove(listener); - } - - public void title(String name) { - if(name == null || title.equals(name)) return; - title = name; - GLFW.glfwSetWindowTitle(id, title); - } - - public void vsync(boolean vsync) { - if(!flags.setFlag(VSYNC, vsync)) return; - GLFW.glfwSwapInterval(vsync ? 1 : 0); - } - - public void fpsCap(boolean fpsCap) { - flags.setFlag(CPU_FPS_CAP, fpsCap); - } - - public void visible(boolean visible) { - if(!flags.setFlag(VISIBLE, visible)) return; - if(visible) GLFW.glfwShowWindow(id); - else GLFW.glfwHideWindow(id); - } - - public void floating(boolean floating) { - 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)) { - if(maximized) { - backupSize(); - GLFW.glfwMaximizeWindow(id); - } - else { - GLFW.glfwRestoreWindow(id); - restoreSize(); - } - fetchWindowBounds(); - } - } - - public void resizeable(boolean resizeable) { - 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)) { - GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, borderless ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE); - if(flags.isFlagSet(MAXIMIZED)) { - GLFW.glfwRestoreWindow(id); - GLFW.glfwMaximizeWindow(id); - fetchWindowBounds(); - } - } - } - - public void fullscreen(boolean fullscreen) { - if(flags.setFlag(FULL_SCREEN, fullscreen)) { - if(fullscreen) { - Monitor monitor = manager.getMonitorForWindow(this); - if(monitor == null) { - flags.clearFlag(FULL_SCREEN); - return; - } - backupSize(); - VideoMode mode = fullScreenMode == null || !monitor.has(fullScreenMode) ? monitor.defaultMode() : fullScreenMode; - x = 0; - y = 0; - width = mode.width(); - height = mode.height(); - GLFW.glfwSetWindowMonitor(id, monitor.id(), 0, 0, mode.width(), mode.height(), mode.refreshrate()); - } - else - { - restoreSize(); - GLFW.glfwSetWindowMonitor(id, 0, x, y, width, height, -1); - if(flags.isFlagSet(BORDERLESS)) { - GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE); - } - if(flags.isFlagSet(MAXIMIZED)) { - GLFW.glfwMaximizeWindow(id); - } - } - fetchWindowBounds(); - updateViewport(); - GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0); - } - } - - protected void backupSize() { - if(backupIndex >= backup.length) return; - backup[backupIndex++].set(x, y, width, height); - } - - protected void restoreSize() { - if(backupIndex == 0) return; - Vec4i prev = backup[--backupIndex]; - x = prev.x(); - y = prev.y(); - 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; - this.x = x; - this.y = y; - GLFW.glfwSetWindowPos(id, x, y); - 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; - this.width = width; - this.height = height; - GLFW.glfwSetWindowSize(id, width, height); - 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 long id() { return id; } - public VideoMode desiredFullScreen() { return fullScreenMode; } - - public int x() { return x; } - public int y() { return y; } - public int width() { return frameWidth; } - public int height() { return frameHeight; } - public int screenWidth() { return width; } - 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 boolean shouldFPSCap() { return flags.isFlagSet(CPU_FPS_CAP); } - public boolean isVisible() { return flags.isFlagSet(VISIBLE); } - public boolean isFloating() { return flags.isFlagSet(FLOATING); } - public boolean isMaximized() { return flags.isFlagSet(MAXIMIZED); } - public boolean isResizeable() { return flags.isFlagSet(RESIZABLE); } - public boolean isBorderless() { return flags.isFlagSet(BORDERLESS); } - public boolean isFullscreen() { return flags.isFlagSet(FULL_SCREEN); } - public int antialiasing() { return antialiasing; } -} +package speiger.src.coreengine.rendering.input.window; + +import java.util.List; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.system.CallbackI; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.graphics.api.core.Graphics; +import speiger.src.coreengine.math.BitUtil; +import speiger.src.coreengine.math.vector.ints.Vec4i; +import speiger.src.coreengine.rendering.input.window.IWindowListener.Reason; +import speiger.src.coreengine.rendering.input.window.WindowCallback.ReloadFunction; +import speiger.src.coreengine.rendering.input.window.WindowManager.WindowBuilder; +import speiger.src.coreengine.utils.collections.FlagHolder; + +public class Window { + static final int VISIBLE = 1; + static final int VSYNC = 2; + static final int FOCUS = 4; + static final int CPU_FPS_CAP = 8; + static final int FULL_SCREEN = 16; + static final int MAXIMIZED = 32; + static final int BORDERLESS = 64; + static final int RESIZABLE = 128; + static final int FLOATING = 256; + static final int CLOSE = 512; + static final int WINDOW_CHANGE = 1024; + WindowManager manager; + FlagHolder flags = new FlagHolder(); + long id; + VideoMode fullScreenMode; + String title = ""; + int x; + int y; + int width; + int height; + + int frameWidth; + int frameHeight; + + Vec4i[] backup = new Vec4i[] {Vec4i.mutable(), Vec4i.mutable()}; + int backupIndex = 0; + + final int antialiasing; + List callbacks = new ObjectArrayList<>(); + List listeners = new ObjectArrayList<>(); + GLCapabilities capabilities; + + protected Window(WindowBuilder builder, Graphics graphics) { + manager = builder.manager; + title = builder.title; + frameWidth = width = builder.width; + frameHeight = height = builder.height; + antialiasing = builder.antiAlis; + fullScreenMode = builder.fullScreenTarget; + flags.setFlag(BORDERLESS, builder.borderless); + flags.setFlag(FULL_SCREEN, builder.fullScreen); + flags.setFlag(FLOATING, builder.floating); + flags.setFlag(RESIZABLE, builder.resizable); + flags.setFlag(VSYNC, builder.vsync); + flags.setFlag(CPU_FPS_CAP, builder.fpsCap); + if(graphics != null) graphics.setupWindowArguments(); + else createDefaultWindowHints(); + for(int i = 0,m=builder.windowHints.size();i WindowCallback addCallback(T listener, ReloadFunction function) { + WindowCallback callback = new WindowCallback(listener, (ReloadFunction)function); + callbacks.add(callback); + callback.load(id); + return callback; + } + + public void removeCallback(WindowCallback callback) { + if(callbacks.remove(callback)) { + callback.destroy(); + } + } + + public void addListener(IWindowListener listener) { + listeners.add(listener); + } + + public void removeListener(IWindowListener listener) { + listeners.remove(listener); + } + + public void title(String name) { + if(name == null || title.equals(name)) return; + title = name; + GLFW.glfwSetWindowTitle(id, title); + } + + public void vsync(boolean vsync) { + if(!flags.setFlag(VSYNC, vsync)) return; + GLFW.glfwSwapInterval(vsync ? 1 : 0); + } + + public void fpsCap(boolean fpsCap) { + flags.setFlag(CPU_FPS_CAP, fpsCap); + } + + public void visible(boolean visible) { + if(!flags.setFlag(VISIBLE, visible)) return; + if(visible) GLFW.glfwShowWindow(id); + else GLFW.glfwHideWindow(id); + } + + public void floating(boolean floating) { + 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)) { + if(maximized) { + backupSize(); + GLFW.glfwMaximizeWindow(id); + } + else { + GLFW.glfwRestoreWindow(id); + restoreSize(); + } + fetchWindowBounds(); + } + } + + public void resizeable(boolean resizeable) { + 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)) { + GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, borderless ? GLFW.GLFW_FALSE : GLFW.GLFW_TRUE); + if(flags.isFlagSet(MAXIMIZED)) { + GLFW.glfwRestoreWindow(id); + GLFW.glfwMaximizeWindow(id); + fetchWindowBounds(); + } + } + } + + public void fullscreen(boolean fullscreen) { + if(flags.setFlag(FULL_SCREEN, fullscreen)) { + if(fullscreen) { + Monitor monitor = manager.getMonitorForWindow(this); + if(monitor == null) { + flags.clearFlag(FULL_SCREEN); + return; + } + backupSize(); + VideoMode mode = fullScreenMode == null || !monitor.has(fullScreenMode) ? monitor.defaultMode() : fullScreenMode; + x = 0; + y = 0; + width = mode.width(); + height = mode.height(); + GLFW.glfwSetWindowMonitor(id, monitor.id(), 0, 0, mode.width(), mode.height(), mode.refreshrate()); + } + else + { + restoreSize(); + GLFW.glfwSetWindowMonitor(id, 0, x, y, width, height, -1); + if(flags.isFlagSet(BORDERLESS)) { + GLFW.glfwSetWindowAttrib(id, GLFW.GLFW_DECORATED, GLFW.GLFW_FALSE); + } + if(flags.isFlagSet(MAXIMIZED)) { + GLFW.glfwMaximizeWindow(id); + } + } + fetchWindowBounds(); + updateViewport(); + GLFW.glfwSwapInterval(flags.isFlagSet(VSYNC) ? 1 : 0); + } + } + + protected void backupSize() { + if(backupIndex >= backup.length) return; + backup[backupIndex++].set(x, y, width, height); + } + + protected void restoreSize() { + if(backupIndex == 0) return; + Vec4i prev = backup[--backupIndex]; + x = prev.x(); + y = prev.y(); + 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; + this.x = x; + this.y = y; + GLFW.glfwSetWindowPos(id, x, y); + 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; + this.width = width; + this.height = height; + GLFW.glfwSetWindowSize(id, width, height); + 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 long id() { return id; } + public VideoMode desiredFullScreen() { return fullScreenMode; } + + public int x() { return x; } + public int y() { return y; } + public int width() { return frameWidth; } + public int height() { return frameHeight; } + public int screenWidth() { return width; } + 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 boolean shouldFPSCap() { return flags.isFlagSet(CPU_FPS_CAP); } + public boolean isVisible() { return flags.isFlagSet(VISIBLE); } + public boolean isFloating() { return flags.isFlagSet(FLOATING); } + public boolean isMaximized() { return flags.isFlagSet(MAXIMIZED); } + public boolean isResizeable() { return flags.isFlagSet(RESIZABLE); } + public boolean isBorderless() { return flags.isFlagSet(BORDERLESS); } + public boolean isFullscreen() { return flags.isFlagSet(FULL_SCREEN); } + public int antialiasing() { return antialiasing; } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/input/window/WindowManager.java b/src/main/java/speiger/src/coreengine/rendering/input/window/WindowManager.java index dcfbe71..41b5816 100644 --- a/src/main/java/speiger/src/coreengine/rendering/input/window/WindowManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/input/window/WindowManager.java @@ -1,266 +1,267 @@ -package speiger.src.coreengine.rendering.input.window; - -import java.util.Iterator; -import java.util.List; -import java.util.Objects; - -import org.lwjgl.glfw.GLFW; -import org.lwjgl.system.Callback; -import org.lwjgl.system.CallbackI; - -import speiger.src.collections.longs.lists.LongArrayList; -import speiger.src.collections.longs.lists.LongList; -import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap; -import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.math.BitUtil; -import speiger.src.coreengine.rendering.input.devices.InputDevice; -import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction; - -public class WindowManager { - Long2ObjectMap monitors; - Long2ObjectMap windows = new Long2ObjectConcurrentOpenHashMap<>(); - Window activeWindow; - Window primaryWindow; - List callbacks = new ObjectArrayList<>(); - Callback monitorTracker; - List devices = new ObjectArrayList<>(); - - public void initialize() { - monitors = Monitor.createMonitors(); - addCallback(this::onMonitorChanged, GLFW::glfwSetMonitorCallback); - } - - private void onMonitorChanged(long monitor, int event) { - switch(event) { - 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 void addDevices(InputDevice...devices) { - for(InputDevice device : devices) addDevice(device); - } - public void addDevice(InputDevice device) { - devices.add(device); - windows.values().forEach(device::register); - } - public void removeDevice(InputDevice device) { devices.remove(device); } - public void processDevices(long windowId) { - for(int i = 0,m=devices.size();i WindowCallback addCallback(T listener, SimpleReloadFunction function) { - WindowCallback callback = new WindowCallback(listener, (SimpleReloadFunction)function); - callbacks.add(callback); - callback.load(0L); - return callback; - } - - public void removeCallback(WindowCallback callback) { - if(callbacks.remove(callback)) { - callback.destroy(); - } - } - - void addWindow(Window window) { - windows.put(window.id(), window); - for(int i = 0,m=devices.size();i iter = windows.values().iterator(); - primaryWindow = iter.hasNext() ? iter.next() : null; - } - } - - void updateFocus(Window window, boolean focus) { - if(focus) this.activeWindow = window; - else if(activeWindow == window) activeWindow = null; - } - - void updateInputs(long windowId) { - for(int i = 0,m=devices.size();i largest) { - largest = next; - mon = monitor; - } - } - return mon; - } - - public static class WindowBuilder { - WindowManager manager; - long monitor; - LongList windowHints = new LongArrayList(); - VideoMode fullScreenTarget; - String title = ""; - int width = 640; - int height = 480; - int antiAlis = 4; - boolean vsync = true; - boolean fpsCap; - boolean fullScreen; - boolean maximized; - boolean resizable = true; - boolean floating; - boolean borderless; - boolean center = true; - - private WindowBuilder(WindowManager manager) { - this.manager = manager; - monitor = GLFW.glfwGetPrimaryMonitor(); - } - - public WindowBuilder title(String title) { - this.title = Objects.requireNonNull(title); - return this; - } - - public WindowBuilder width(int width) { - this.width = Math.max(1, width); - return this; - } - - public WindowBuilder height(int height) { - this.height = Math.max(1, height); - return this; - } - - public WindowBuilder antialis(int antiAlis) { - this.antiAlis = Math.max(1, antiAlis); - return this; - } - - public WindowBuilder fullscreen(boolean fullScreen) { - this.fullScreen = fullScreen; - borderless &= !fullScreen; - floating &= !fullScreen; - maximized &= !fullScreen; - center &= !fullScreen; - return this; - } - - public WindowBuilder maximized(boolean maximized) { - this.maximized = maximized; - this.fullScreen &= !maximized; - center &= !maximized; - return this; - } - - public WindowBuilder borderless(boolean borderless) { - this.borderless = borderless; - fullScreen &= !borderless; - return this; - } - - public WindowBuilder floating(boolean floating) { - this.floating = floating; - fullScreen &= !floating; - return this; - } - - public WindowBuilder resizeable(boolean resizable) { - this.resizable = resizable; - return this; - } - - public WindowBuilder centered(boolean center) { - this.center = center; - this.maximized &= !center; - this.fullScreen &= !center; - return this; - } - - public WindowBuilder monitor(Monitor monitor) { - if(monitor == null || monitor.defaultMode() == null) return this; - this.monitor = monitor.id(); - return this; - } - - public WindowBuilder fullScreenMode(VideoMode mode) { - this.fullScreenTarget = mode; - return this; - } - - public WindowBuilder vsync(boolean value) { - vsync = value; - return this; - } - - public WindowBuilder fpsCap(boolean cap) { - fpsCap = cap; - return this; - } - - public WindowBuilder addCustomHint(int key, int value) { - windowHints.add(BitUtil.toLong(key, value)); - return this; - } - - public Window build() { - return manager.create(this); - } - - } -} +package speiger.src.coreengine.rendering.input.window; + +import java.util.Iterator; +import java.util.List; +import java.util.Objects; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.system.Callback; +import org.lwjgl.system.CallbackI; + +import speiger.src.collections.longs.lists.LongArrayList; +import speiger.src.collections.longs.lists.LongList; +import speiger.src.collections.longs.maps.impl.concurrent.Long2ObjectConcurrentOpenHashMap; +import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap; +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.graphics.api.core.Graphics; +import speiger.src.coreengine.math.BitUtil; +import speiger.src.coreengine.rendering.input.devices.InputDevice; +import speiger.src.coreengine.rendering.input.window.WindowCallback.SimpleReloadFunction; + +public class WindowManager { + Long2ObjectMap monitors; + Long2ObjectMap windows = new Long2ObjectConcurrentOpenHashMap<>(); + Window activeWindow; + Window primaryWindow; + List callbacks = new ObjectArrayList<>(); + Callback monitorTracker; + List devices = new ObjectArrayList<>(); + + public void initialize() { + monitors = Monitor.createMonitors(); + addCallback(this::onMonitorChanged, GLFW::glfwSetMonitorCallback); + } + + private void onMonitorChanged(long monitor, int event) { + switch(event) { + 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, Graphics graphics) { return new Window(builder, graphics); } + + public void addDevices(InputDevice...devices) { + for(InputDevice device : devices) addDevice(device); + } + public void addDevice(InputDevice device) { + devices.add(device); + windows.values().forEach(device::register); + } + public void removeDevice(InputDevice device) { devices.remove(device); } + public void processDevices(long windowId) { + for(int i = 0,m=devices.size();i WindowCallback addCallback(T listener, SimpleReloadFunction function) { + WindowCallback callback = new WindowCallback(listener, (SimpleReloadFunction)function); + callbacks.add(callback); + callback.load(0L); + return callback; + } + + public void removeCallback(WindowCallback callback) { + if(callbacks.remove(callback)) { + callback.destroy(); + } + } + + void addWindow(Window window) { + windows.put(window.id(), window); + for(int i = 0,m=devices.size();i iter = windows.values().iterator(); + primaryWindow = iter.hasNext() ? iter.next() : null; + } + } + + void updateFocus(Window window, boolean focus) { + if(focus) this.activeWindow = window; + else if(activeWindow == window) activeWindow = null; + } + + void updateInputs(long windowId) { + for(int i = 0,m=devices.size();i largest) { + largest = next; + mon = monitor; + } + } + return mon; + } + + public static class WindowBuilder { + WindowManager manager; + long monitor; + LongList windowHints = new LongArrayList(); + VideoMode fullScreenTarget; + String title = ""; + int width = 640; + int height = 480; + int antiAlis = 4; + boolean vsync = true; + boolean fpsCap; + boolean fullScreen; + boolean maximized; + boolean resizable = true; + boolean floating; + boolean borderless; + boolean center = true; + + private WindowBuilder(WindowManager manager) { + this.manager = manager; + monitor = GLFW.glfwGetPrimaryMonitor(); + } + + public WindowBuilder title(String title) { + this.title = Objects.requireNonNull(title); + return this; + } + + public WindowBuilder width(int width) { + this.width = Math.max(1, width); + return this; + } + + public WindowBuilder height(int height) { + this.height = Math.max(1, height); + return this; + } + + public WindowBuilder antialis(int antiAlis) { + this.antiAlis = Math.max(1, antiAlis); + return this; + } + + public WindowBuilder fullscreen(boolean fullScreen) { + this.fullScreen = fullScreen; + borderless &= !fullScreen; + floating &= !fullScreen; + maximized &= !fullScreen; + center &= !fullScreen; + return this; + } + + public WindowBuilder maximized(boolean maximized) { + this.maximized = maximized; + this.fullScreen &= !maximized; + center &= !maximized; + return this; + } + + public WindowBuilder borderless(boolean borderless) { + this.borderless = borderless; + fullScreen &= !borderless; + return this; + } + + public WindowBuilder floating(boolean floating) { + this.floating = floating; + fullScreen &= !floating; + return this; + } + + public WindowBuilder resizeable(boolean resizable) { + this.resizable = resizable; + return this; + } + + public WindowBuilder centered(boolean center) { + this.center = center; + this.maximized &= !center; + this.fullScreen &= !center; + return this; + } + + public WindowBuilder monitor(Monitor monitor) { + if(monitor == null || monitor.defaultMode() == null) return this; + this.monitor = monitor.id(); + return this; + } + + public WindowBuilder fullScreenMode(VideoMode mode) { + this.fullScreenTarget = mode; + return this; + } + + public WindowBuilder vsync(boolean value) { + vsync = value; + return this; + } + + public WindowBuilder fpsCap(boolean cap) { + fpsCap = cap; + return this; + } + + public WindowBuilder addCustomHint(int key, int value) { + windowHints.add(BitUtil.toLong(key, value)); + return this; + } + + public Window build(Graphics graphics) { + return manager.create(this, graphics); + } + + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java b/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java index 0600113..748af47 100644 --- a/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java +++ b/src/main/java/speiger/src/coreengine/rendering/textures/custom/DynamicTexture.java @@ -1,192 +1,192 @@ -package speiger.src.coreengine.rendering.textures.custom; - -import org.lwjgl.system.MemoryUtil; - -import speiger.src.collections.ints.collections.IntIterator; -import speiger.src.collections.ints.sets.IntLinkedOpenHashSet; -import speiger.src.collections.ints.sets.IntSet; -import speiger.src.coreengine.assets.base.IAssetProvider; -import speiger.src.coreengine.math.BitUtil; -import speiger.src.coreengine.math.misc.ColorSpaces; -import speiger.src.coreengine.rendering.textures.base.BaseTexture; -import speiger.src.coreengine.rendering.textures.base.TextureMetadata; -import speiger.src.coreengine.rendering.utils.GLFunctions; -import speiger.src.coreengine.rendering.utils.GLStateTracker; -import speiger.src.coreengine.rendering.utils.values.GLDataType; -import speiger.src.coreengine.rendering.utils.values.textures.GLTextureFormat; -import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter; -import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue; - -public class DynamicTexture extends BaseTexture implements IDynamicTexture { - 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.WRAP_S, GLTextureValue.CLAMP_TO_EDGE).arguement(GLTextureParameter.WRAP_T, GLTextureValue.CLAMP_TO_EDGE).build(); - IntSet dirtySections = new IntLinkedOpenHashSet(); - TextureMetadata metadata; - int width; - int height; - long data; - - public DynamicTexture(int width, int height, TextureMetadata metadata) { - this.metadata = metadata; - this.width = width; - this.height = height; - if(width % 16 != 0 || height % 16 != 0) throw new IllegalArgumentException("Texture must be a power of 16"); - data = MemoryUtil.nmemAllocChecked(4L * width * height); - track(); - } - - @Override - public void load(IAssetProvider provider) { - createTexture(); - metadata.applyArguments(id()); - GLFunctions.prepare2DImage(id(), 1, metadata, width, height); - dirtySections.clear(); - } - - @Override - public void delete(boolean untrack) { - super.delete(untrack); - if(untrack && data != 0L) { - MemoryUtil.nmemFree(data); - data = 0L; - } - } - - @Override - public int width() { return width; } - @Override - public int height() { return height; } - @Override - public ColorSpaces colorspace() { return ColorSpaces.ABGR; } - @Override - public boolean isDirty() { return !dirtySections.isEmpty(); } - - @Override - public void process(boolean full) { - if(full) { - GLFunctions.upload2DSubImage(id(), 0, 0, 0, width, height, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data); - dirtySections.clear(); - return; - } - GLStateTracker tracker = GLStateTracker.instance(); - tracker.unpack_row_length.set(width()); - Thread thread = Thread.currentThread(); - for(IntIterator iter = dirtySections.iterator();iter.hasNext() && !thread.isInterrupted();iter.remove()) { - int key = iter.nextInt(); - uploadPixels(tracker, BitUtil.shortKey(key) * 16, BitUtil.shortValue(key) * 16); - } - tracker.unpack_row_length.setDefault(); - tracker.unpack_skip_pixel.setDefault(); - tracker.unpack_skip_rows.setDefault(); - } - - protected void uploadPixels(GLStateTracker tracker, int x, int y) { - tracker.unpack_skip_pixel.set(x); - tracker.unpack_skip_rows.set(y); - GLFunctions.upload2DSubImage(id(), 0, x, y, 16, 16, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data); - } - - protected long offset(int x, int y) { - return ((y * width()) + x) << 2L; - } - - protected void ensureValid(int index) { - ensureValid(index % width, index / width); - } - - 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 > 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"); - } - - @Override - public void fill(int x, int y, int width, int height, int data) { - ensureValid(x, y); - ensureValid(x+width, y+height); - for(int xOff = 0;xOff>4,m=width>>4;i>4,n=height>>4;j> 4, y >> 4)); - } - - @Override - public void set(int index, int data) { - ensureValid(index); - MemoryUtil.memPutInt(this.data + index * 4L, data); - dirty(index); - } - - @Override - public void setR(int index, int red) { - ensureValid(index); - MemoryUtil.memPutByte(data + index * 4L, (byte)(red & 0xFF)); - dirty(index); - } - - @Override - public void setG(int index, int green) { - ensureValid(index); - MemoryUtil.memPutByte(data + index * 4L + 1L, (byte)(green & 0xFF)); - dirty(index); - } - - @Override - public void setB(int index, int blue) { - ensureValid(index); - MemoryUtil.memPutByte(data + index * 4L + 2L, (byte)(blue & 0xFF)); - dirty(index); - } - - @Override - public void setA(int index, int alpha) { - ensureValid(index); - MemoryUtil.memPutByte(data + index * 4L + 3L, (byte)(alpha & 0xFF)); - dirty(index); - } - - @Override - public int get(int index) { - ensureValid(index); - return MemoryUtil.memGetInt(data + index * 4L); - } - - @Override - public int getR(int index) { - ensureValid(index); - return MemoryUtil.memGetByte(data + index * 4L); - } - - @Override - public int getG(int index) { - ensureValid(index); - return MemoryUtil.memGetByte(data + index * 4L + 1L); - } - - @Override - public int getB(int index) { - ensureValid(index); - return MemoryUtil.memGetByte(data + index * 4L + 2L); - } - - @Override - public int getA(int index) { - ensureValid(index); - return MemoryUtil.memGetByte(data + index * 4L + 3L); - } +package speiger.src.coreengine.rendering.textures.custom; + +import org.lwjgl.system.MemoryUtil; + +import speiger.src.collections.ints.collections.IntIterator; +import speiger.src.collections.ints.sets.IntLinkedOpenHashSet; +import speiger.src.collections.ints.sets.IntSet; +import speiger.src.coreengine.assets.base.IAssetProvider; +import speiger.src.coreengine.math.BitUtil; +import speiger.src.coreengine.math.misc.ColorSpaces; +import speiger.src.coreengine.rendering.textures.base.BaseTexture; +import speiger.src.coreengine.rendering.textures.base.TextureMetadata; +import speiger.src.coreengine.rendering.utils.GLFunctions; +import speiger.src.coreengine.rendering.utils.GLStateTracker; +import speiger.src.coreengine.rendering.utils.values.GLDataType; +import speiger.src.coreengine.rendering.utils.values.textures.GLTextureFormat; +import speiger.src.coreengine.rendering.utils.values.textures.GLTextureParameter; +import speiger.src.coreengine.rendering.utils.values.textures.GLTextureValue; + +public class DynamicTexture extends BaseTexture implements IDynamicTexture { + 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.WRAP_S, GLTextureValue.CLAMP_TO_EDGE).arguement(GLTextureParameter.WRAP_T, GLTextureValue.CLAMP_TO_EDGE).build(); + IntSet dirtySections = new IntLinkedOpenHashSet(); + TextureMetadata metadata; + int width; + int height; + long data; + + public DynamicTexture(int width, int height, TextureMetadata metadata) { + this.metadata = metadata; + this.width = width; + this.height = height; + if(width % 16 != 0 || height % 16 != 0) throw new IllegalArgumentException("Texture must be a power of 16"); + data = MemoryUtil.nmemAllocChecked(4L * width * height); + track(); + } + + @Override + public void load(IAssetProvider provider) { + createTexture(); + metadata.applyArguments(id()); + GLFunctions.prepare2DImage(id(), 1, metadata, width, height); + dirtySections.clear(); + } + + @Override + public void delete(boolean untrack) { + super.delete(untrack); + if(untrack && data != 0L) { + MemoryUtil.nmemFree(data); + data = 0L; + } + } + + @Override + public int width() { return width; } + @Override + public int height() { return height; } + @Override + public ColorSpaces colorspace() { return ColorSpaces.ABGR; } + @Override + public boolean isDirty() { return !dirtySections.isEmpty(); } + + @Override + public void process(boolean full) { + if(full) { + GLFunctions.upload2DSubImage(id(), 0, 0, 0, width, height, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data); + dirtySections.clear(); + return; + } + GLStateTracker tracker = GLStateTracker.instance(); + tracker.unpack_row_length.set(width()); + Thread thread = Thread.currentThread(); + for(IntIterator iter = dirtySections.iterator();iter.hasNext() && !thread.isInterrupted();iter.remove()) { + int key = iter.nextInt(); + uploadPixels(tracker, BitUtil.shortKey(key) * 16, BitUtil.shortValue(key) * 16); + } + tracker.unpack_row_length.setDefault(); + tracker.unpack_skip_pixel.setDefault(); + tracker.unpack_skip_rows.setDefault(); + } + + protected void uploadPixels(GLStateTracker tracker, int x, int y) { + tracker.unpack_skip_pixel.set(x); + tracker.unpack_skip_rows.set(y); + GLFunctions.upload2DSubImage(id(), 0, x, y, 16, 16, GLTextureFormat.RGBA, GLDataType.UNSIGNED_BYTE, data); + } + + protected long offset(int x, int y) { + return ((y * width()) + x) << 2L; + } + + protected void ensureValid(int index) { + ensureValid(index % width, index / width); + } + + 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 > 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"); + } + + @Override + public void fill(int x, int y, int width, int height, int data) { + ensureValid(x, y); + ensureValid(x+width, y+height); + for(int xOff = 0;xOff>4,m=width>>4;i>4,n=height>>4;j> 4, y >> 4)); + } + + @Override + public void set(int index, int data) { + ensureValid(index); + MemoryUtil.memPutInt(this.data + index * 4L, data); + dirty(index); + } + + @Override + public void setR(int index, int red) { + ensureValid(index); + MemoryUtil.memPutByte(data + index * 4L, (byte)(red & 0xFF)); + dirty(index); + } + + @Override + public void setG(int index, int green) { + ensureValid(index); + MemoryUtil.memPutByte(data + index * 4L + 1L, (byte)(green & 0xFF)); + dirty(index); + } + + @Override + public void setB(int index, int blue) { + ensureValid(index); + MemoryUtil.memPutByte(data + index * 4L + 2L, (byte)(blue & 0xFF)); + dirty(index); + } + + @Override + public void setA(int index, int alpha) { + ensureValid(index); + MemoryUtil.memPutByte(data + index * 4L + 3L, (byte)(alpha & 0xFF)); + dirty(index); + } + + @Override + public int get(int index) { + ensureValid(index); + return MemoryUtil.memGetInt(data + index * 4L); + } + + @Override + public int getR(int index) { + ensureValid(index); + return MemoryUtil.memGetByte(data + index * 4L); + } + + @Override + public int getG(int index) { + ensureValid(index); + return MemoryUtil.memGetByte(data + index * 4L + 1L); + } + + @Override + public int getB(int index) { + ensureValid(index); + return MemoryUtil.memGetByte(data + index * 4L + 2L); + } + + @Override + public int getA(int index) { + ensureValid(index); + return MemoryUtil.memGetByte(data + index * 4L + 3L); + } } \ No newline at end of file diff --git a/src/main/resources/assets/base/shader/testGui/fragment.fs b/src/main/resources/assets/base/shader/testGui/fragment.fs index 05d5a14..fa0103c 100644 --- a/src/main/resources/assets/base/shader/testGui/fragment.fs +++ b/src/main/resources/assets/base/shader/testGui/fragment.fs @@ -1,14 +1,14 @@ -#version 330 - -in vec4 pass_color; -in vec2 pass_tex; - -out vec4 frag_color; - -uniform sampler2D texture; - -void main() -{ - vec4 color = texture2D(texture, pass_tex); - frag_color = pass_color * vec4(1, 1, 1, color.r); +#version 420 + +in vec4 pass_color; +in vec2 pass_tex; + +out vec4 frag_color; + +layout(binding = 0) uniform sampler2D texture; + +void main() +{ + vec4 color = texture2D(texture, pass_tex); + frag_color = pass_color * vec4(1, 1, 1, color.r); } \ No newline at end of file diff --git a/src/main/resources/assets/base/shader/testGui/vertex.vs b/src/main/resources/assets/base/shader/testGui/vertex.vs index 743718a..0605710 100644 --- a/src/main/resources/assets/base/shader/testGui/vertex.vs +++ b/src/main/resources/assets/base/shader/testGui/vertex.vs @@ -1,17 +1,19 @@ -#version 330 - -layout(location = 0) in vec3 in_position; -layout(location = 1) in vec2 in_tex; -layout(location = 2) in vec4 in_color; - -out vec4 pass_color; -out vec2 pass_tex; - -uniform mat4 proViewMatrix; - -void main() -{ - gl_Position = proViewMatrix * vec4(in_position, 1.0); - pass_color = in_color; - pass_tex = in_tex; +#version 420 + +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec2 in_tex; +layout(location = 2) in vec4 in_color; + +out vec4 pass_color; +out vec2 pass_tex; + +layout(binding = 0) uniform Camera { + mat4 proViewMatrix; +} camera; + +void main() +{ + gl_Position = camera.proViewMatrix * vec4(in_position, 1.0); + pass_color = in_color; + pass_tex = in_tex; } \ No newline at end of file