From cbd404913f56a080cf245f0641d9998c078c3c31 Mon Sep 17 00:00:00 2001 From: IMS212 Date: Sat, 21 Oct 2023 15:55:03 -0700 Subject: [PATCH] Rewrite framebuffers to look more decent --- .../glObject/texture/DHColorTexture.java | 154 ++++++++++++++++++ .../glObject/texture/DHDepthBufferFormat.java | 97 +++++++++++ .../glObject/texture/DHDepthTexture.java | 50 ++++++ .../glObject/texture/DHFramebuffer.java | 110 +++++++++++++ .../texture/DHInternalTextureFormat.java | 108 ++++++++++++ .../glObject/texture/DHPixelFormat.java | 53 ++++++ .../render/glObject/texture/DHPixelType.java | 55 +++++++ .../render/glObject/texture/GlVersion.java | 8 + .../core/render/renderer/LodRenderer.java | 106 ++++++------ 9 files changed, 681 insertions(+), 60 deletions(-) create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHColorTexture.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthBufferFormat.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthTexture.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHFramebuffer.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHInternalTextureFormat.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelFormat.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelType.java create mode 100644 core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/GlVersion.java diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHColorTexture.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHColorTexture.java new file mode 100644 index 000000000..7fa768366 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHColorTexture.java @@ -0,0 +1,154 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.joml.Vector2i; +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL13C; +import org.lwjgl.opengl.GL43C; + +import java.nio.ByteBuffer; + +public class DHColorTexture +{ + private final DHInternalTextureFormat internalFormat; + private final DHPixelFormat format; + private final DHPixelType type; + private int width; + private int height; + + private boolean isValid; + private final int texture; + + private static final ByteBuffer NULL_BUFFER = null; + + public DHColorTexture(Builder builder) { + this.isValid = true; + + this.internalFormat = builder.internalFormat; + this.format = builder.format; + this.type = builder.type; + + this.width = builder.width; + this.height = builder.height; + + this.texture = GL43C.glGenTextures(); + + boolean isPixelFormatInteger = builder.internalFormat.getPixelFormat().isInteger(); + setupTexture(texture, builder.width, builder.height, !isPixelFormatInteger); + + // Clean up after ourselves + // This is strictly defensive to ensure that other buggy code doesn't tamper with our textures + GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0); + } + + private void setupTexture(int texture, int width, int height, boolean allowsLinear) { + resizeTexture(texture, width, height); + + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, allowsLinear ? GL11C.GL_LINEAR : GL11C.GL_NEAREST); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE); + } + + private void resizeTexture(int texture, int width, int height) { + GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, texture); + GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, internalFormat.getGlFormat(), width, height, 0, format.getGlFormat(), type.getGlFormat(), NULL_BUFFER); + } + + void resize(Vector2i textureScaleOverride) { + this.resize(textureScaleOverride.x, textureScaleOverride.y); + } + + // Package private, call CompositeRenderTargets#resizeIfNeeded instead. + public void resize(int width, int height) { + requireValid(); + + this.width = width; + this.height = height; + + resizeTexture(texture, width, height); + } + + public DHInternalTextureFormat getInternalFormat() { + return internalFormat; + } + + public int getTexture() { + requireValid(); + + return texture; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void destroy() { + requireValid(); + isValid = false; + + GL43C.glDeleteTextures(texture); + } + + private void requireValid() { + if (!isValid) { + throw new IllegalStateException("Attempted to use a deleted composite render target"); + } + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private DHInternalTextureFormat internalFormat = DHInternalTextureFormat.RGBA8; + private int width = 0; + private int height = 0; + private DHPixelFormat format = DHPixelFormat.RGBA; + private DHPixelType type = DHPixelType.UNSIGNED_BYTE; + + private Builder() { + // No-op + } + + public Builder setInternalFormat(DHInternalTextureFormat format) { + this.internalFormat = format; + + return this; + } + + public Builder setDimensions(int width, int height) { + if (width <= 0) { + throw new IllegalArgumentException("Width must be greater than zero"); + } + + if (height <= 0) { + throw new IllegalArgumentException("Height must be greater than zero"); + } + + this.width = width; + this.height = height; + + return this; + } + + public Builder setPixelFormat(DHPixelFormat pixelFormat) { + this.format = pixelFormat; + + return this; + } + + public Builder setPixelType(DHPixelType pixelType) { + this.type = pixelType; + + return this; + } + + public DHColorTexture build() { + return new DHColorTexture(this); + } + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthBufferFormat.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthBufferFormat.java new file mode 100644 index 000000000..08277058f --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthBufferFormat.java @@ -0,0 +1,97 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL30C; +import org.lwjgl.opengl.GL43C; + +public enum DHDepthBufferFormat { + DEPTH(false), + DEPTH16(false), + DEPTH24(false), + DEPTH32(false), + DEPTH32F(false), + DEPTH_STENCIL(true), + DEPTH24_STENCIL8(true), + DEPTH32F_STENCIL8(true); + + private final boolean combinedStencil; + + DHDepthBufferFormat(boolean combinedStencil) { + this.combinedStencil = combinedStencil; + } + + @Nullable + public static DHDepthBufferFormat fromGlEnum(int glenum) { + switch (glenum) { + case GL30C.GL_DEPTH_COMPONENT: return DHDepthBufferFormat.DEPTH; + case GL30C.GL_DEPTH_COMPONENT16: return DHDepthBufferFormat.DEPTH16; + case GL30C.GL_DEPTH_COMPONENT24: return DHDepthBufferFormat.DEPTH24; + case GL30C.GL_DEPTH_COMPONENT32: return DHDepthBufferFormat.DEPTH32; + case GL30C.GL_DEPTH_COMPONENT32F: return DHDepthBufferFormat.DEPTH32F; + case GL30C.GL_DEPTH_STENCIL: return DHDepthBufferFormat.DEPTH_STENCIL; + case GL30C.GL_DEPTH24_STENCIL8: return DHDepthBufferFormat.DEPTH24_STENCIL8; + case GL30C.GL_DEPTH32F_STENCIL8: return DHDepthBufferFormat.DEPTH32F_STENCIL8; + default: return null; + } + } + + public static DHDepthBufferFormat fromGlEnumOrDefault(int glenum) { + DHDepthBufferFormat format = fromGlEnum(glenum); + if (format == null) { + // yolo, just assume it's GL_DEPTH_COMPONENT + return DHDepthBufferFormat.DEPTH; + } + return format; + } + + public int getGlInternalFormat() { + switch (this) { + case DEPTH: + return GL30C.GL_DEPTH_COMPONENT; + case DEPTH16: + return GL30C.GL_DEPTH_COMPONENT16; + case DEPTH24: + return GL30C.GL_DEPTH_COMPONENT24; + case DEPTH32: + return GL30C.GL_DEPTH_COMPONENT32; + case DEPTH32F: + return GL30C.GL_DEPTH_COMPONENT32F; + case DEPTH_STENCIL: + return GL30C.GL_DEPTH_STENCIL; + case DEPTH24_STENCIL8: + return GL30C.GL_DEPTH24_STENCIL8; + case DEPTH32F_STENCIL8: + return GL30C.GL_DEPTH32F_STENCIL8; + } + + throw new AssertionError("unreachable"); + } + + public int getGlType() { + return isCombinedStencil() ? GL30C.GL_DEPTH_STENCIL : GL30C.GL_DEPTH_COMPONENT; + } + + public int getGlFormat() { + switch (this) { + case DEPTH: + case DEPTH16: + return GL43C.GL_UNSIGNED_SHORT; + case DEPTH24: + case DEPTH32: + return GL43C.GL_UNSIGNED_INT; + case DEPTH32F: + return GL30C.GL_FLOAT; + case DEPTH_STENCIL: + case DEPTH24_STENCIL8: + return GL30C.GL_UNSIGNED_INT_24_8; + case DEPTH32F_STENCIL8: + return GL30C.GL_FLOAT_32_UNSIGNED_INT_24_8_REV; + } + + throw new AssertionError("unreachable"); + } + + public boolean isCombinedStencil() { + return combinedStencil; + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthTexture.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthTexture.java new file mode 100644 index 000000000..f799d8e65 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHDepthTexture.java @@ -0,0 +1,50 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL13C; +import org.lwjgl.opengl.GL43C; + +import java.nio.ByteBuffer; + +public class DHDepthTexture +{ + private int id; + public DHDepthTexture(int width, int height, DHDepthBufferFormat format) + { + this.id = GL43C.glGenTextures(); + + resize(width, height, format); + + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MIN_FILTER, GL11C.GL_NEAREST); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_MAG_FILTER, GL11C.GL_NEAREST); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_S, GL13C.GL_CLAMP_TO_EDGE); + GL43C.glTexParameteri(GL11C.GL_TEXTURE_2D, GL11C.GL_TEXTURE_WRAP_T, GL13C.GL_CLAMP_TO_EDGE); + + GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, 0); + } + + // For internal use by Iris for copying data. Do not use this in DH. + public DHDepthTexture(int id) { + this.id = id; + } + + public void resize(int width, int height, DHDepthBufferFormat format) + { + GL43C.glBindTexture(GL43C.GL_TEXTURE_2D, getTextureId()); + GL43C.glTexImage2D(GL11C.GL_TEXTURE_2D, 0, format.getGlInternalFormat(), width, height, 0, + format.getGlType(), format.getGlFormat(), (ByteBuffer) null); + } + + public int getTextureId() + { + if (id == -1) throw new IllegalStateException("Depth texture does not exist!"); + return id; + } + + public void destroy() + { + GL43C.glDeleteTextures(getTextureId()); + this.id = -1; + } + +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHFramebuffer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHFramebuffer.java new file mode 100644 index 000000000..81deef33d --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHFramebuffer.java @@ -0,0 +1,110 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import org.lwjgl.opengl.GL30C; +import org.lwjgl.opengl.GL43C; + +public class DHFramebuffer { + private final Int2IntMap attachments; + private final int maxDrawBuffers; + private final int maxColorAttachments; + private boolean hasDepthAttachment; + private int id; + + public DHFramebuffer() { + id = GL43C.glGenFramebuffers(); + + this.attachments = new Int2IntArrayMap(); + this.maxDrawBuffers = GL43C.glGetInteger(GL30C.GL_MAX_DRAW_BUFFERS); + this.maxColorAttachments = GL43C.glGetInteger(GL30C.GL_MAX_COLOR_ATTACHMENTS); + this.hasDepthAttachment = false; + } + + public void addDepthAttachment(int texture, DHDepthBufferFormat depthBufferFormat) { + bind(); + + if (depthBufferFormat.isCombinedStencil()) { + GL43C.glFramebufferTexture2D(GL30C.GL_FRAMEBUFFER, GL30C.GL_DEPTH_STENCIL_ATTACHMENT, GL30C.GL_TEXTURE_2D, texture, 0); + } else { + GL43C.glFramebufferTexture2D(GL30C.GL_FRAMEBUFFER, GL30C.GL_DEPTH_ATTACHMENT, GL30C.GL_TEXTURE_2D, texture, 0); + } + + this.hasDepthAttachment = true; + } + + public void addColorAttachment(int index, int texture) { + int fb = id; + bind(); + + GL43C.glFramebufferTexture2D(GL30C.GL_FRAMEBUFFER, GL30C.GL_COLOR_ATTACHMENT0 + index, GL30C.GL_TEXTURE_2D, texture, 0); + attachments.put(index, texture); + } + + public void noDrawBuffers() { + bind(); + GL43C.glDrawBuffers(new int[] { GL30C.GL_NONE }); + } + + public void drawBuffers(int[] buffers) { + int[] glBuffers = new int[buffers.length]; + int index = 0; + + if (buffers.length > maxDrawBuffers) { + throw new IllegalArgumentException("Cannot write to more than " + maxDrawBuffers + " draw buffers on this GPU"); + } + + for (int buffer : buffers) { + if (buffer >= maxColorAttachments) { + throw new IllegalArgumentException("Only " + maxColorAttachments + " color attachments are supported on this GPU, but an attempt was made to write to a color attachment with index " + buffer); + } + + glBuffers[index++] = GL30C.GL_COLOR_ATTACHMENT0 + buffer; + } + + bind(); + GL43C.glDrawBuffers(new int[] { GL30C.GL_NONE }); + } + + public void readBuffer(int buffer) { + bind(); + GL43C.glReadBuffer(GL30C.GL_COLOR_ATTACHMENT0 + buffer); + } + + public int getColorAttachment(int index) { + return attachments.get(index); + } + + public boolean hasDepthAttachment() { + return hasDepthAttachment; + } + + public void bind() { + if (id == -1) throw new IllegalStateException("Framebuffer does not exist!"); + GL43C.glBindFramebuffer(GL30C.GL_FRAMEBUFFER, id); + } + + public void bindAsReadBuffer() { + GL43C.glBindFramebuffer(GL30C.GL_READ_FRAMEBUFFER, id); + } + + public void bindAsDrawBuffer() { + GL43C.glBindFramebuffer(GL30C.GL_DRAW_FRAMEBUFFER, id); + } + + public void destroyInternal() { + GL43C.glDeleteFramebuffers(id); + this.id = -1; + } + + public int getStatus() { + bind(); + int status = GL43C.glCheckFramebufferStatus(GL30C.GL_FRAMEBUFFER); + + return status; + } + + public int getId() { + return id; + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHInternalTextureFormat.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHInternalTextureFormat.java new file mode 100644 index 000000000..853d914be --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHInternalTextureFormat.java @@ -0,0 +1,108 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL30C; +import org.lwjgl.opengl.GL31C; + +import java.util.Locale; +import java.util.Optional; + +public enum DHInternalTextureFormat { + // Default + // TODO: This technically shouldn't be exposed to shaders since it's not in the specification, it's the default anyways + RGBA(GL11C.GL_RGBA, GlVersion.GL_11, DHPixelFormat.RGBA), + // 8-bit normalized + R8(GL30C.GL_R8, GlVersion.GL_30, DHPixelFormat.RED), + RG8(GL30C.GL_RG8, GlVersion.GL_30, DHPixelFormat.RG), + RGB8(GL11C.GL_RGB8, GlVersion.GL_11, DHPixelFormat.RGB), + RGBA8(GL11C.GL_RGBA8, GlVersion.GL_11, DHPixelFormat.RGBA), + // 8-bit signed normalized + R8_SNORM(GL31C.GL_R8_SNORM, GlVersion.GL_31, DHPixelFormat.RED), + RG8_SNORM(GL31C.GL_RG8_SNORM, GlVersion.GL_31, DHPixelFormat.RG), + RGB8_SNORM(GL31C.GL_RGB8_SNORM, GlVersion.GL_31, DHPixelFormat.RGB), + RGBA8_SNORM(GL31C.GL_RGBA8_SNORM, GlVersion.GL_31, DHPixelFormat.RGBA), + // 16-bit normalized + R16(GL30C.GL_R16, GlVersion.GL_30, DHPixelFormat.RED), + RG16(GL30C.GL_RG16, GlVersion.GL_30, DHPixelFormat.RG), + RGB16(GL11C.GL_RGB16, GlVersion.GL_11, DHPixelFormat.RGB), + RGBA16(GL11C.GL_RGBA16, GlVersion.GL_11, DHPixelFormat.RGBA), + // 16-bit signed normalized + R16_SNORM(GL31C.GL_R16_SNORM, GlVersion.GL_31, DHPixelFormat.RED), + RG16_SNORM(GL31C.GL_RG16_SNORM, GlVersion.GL_31, DHPixelFormat.RG), + RGB16_SNORM(GL31C.GL_RGB16_SNORM, GlVersion.GL_31, DHPixelFormat.RGB), + RGBA16_SNORM(GL31C.GL_RGBA16_SNORM, GlVersion.GL_31, DHPixelFormat.RGBA), + // 16-bit float + R16F(GL30C.GL_R16F, GlVersion.GL_30, DHPixelFormat.RED), + RG16F(GL30C.GL_RG16F, GlVersion.GL_30, DHPixelFormat.RG), + RGB16F(GL30C.GL_RGB16F, GlVersion.GL_30, DHPixelFormat.RGB), + RGBA16F(GL30C.GL_RGBA16F, GlVersion.GL_30, DHPixelFormat.RGBA), + // 32-bit float + R32F(GL30C.GL_R32F, GlVersion.GL_30, DHPixelFormat.RED), + RG32F(GL30C.GL_RG32F, GlVersion.GL_30, DHPixelFormat.RG), + RGB32F(GL30C.GL_RGB32F, GlVersion.GL_30, DHPixelFormat.RGB), + RGBA32F(GL30C.GL_RGBA32F, GlVersion.GL_30, DHPixelFormat.RGBA), + // 8-bit integer + R8I(GL30C.GL_R8I, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG8I(GL30C.GL_RG8I, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB8I(GL30C.GL_RGB8I, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA8I(GL30C.GL_RGBA8I, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // 8-bit unsigned integer + R8UI(GL30C.GL_R8UI, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG8UI(GL30C.GL_RG8UI, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB8UI(GL30C.GL_RGB8UI, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA8UI(GL30C.GL_RGBA8UI, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // 16-bit integer + R16I(GL30C.GL_R16I, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG16I(GL30C.GL_RG16I, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB16I(GL30C.GL_RGB16I, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA16I(GL30C.GL_RGBA16I, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // 16-bit unsigned integer + R16UI(GL30C.GL_R16UI, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG16UI(GL30C.GL_RG16UI, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB16UI(GL30C.GL_RGB16UI, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA16UI(GL30C.GL_RGBA16UI, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // 32-bit integer + R32I(GL30C.GL_R32I, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG32I(GL30C.GL_RG32I, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB32I(GL30C.GL_RGB32I, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA32I(GL30C.GL_RGBA32I, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // 32-bit unsigned integer + R32UI(GL30C.GL_R32UI, GlVersion.GL_30, DHPixelFormat.RED_INTEGER), + RG32UI(GL30C.GL_RG32UI, GlVersion.GL_30, DHPixelFormat.RG_INTEGER), + RGB32UI(GL30C.GL_RGB32UI, GlVersion.GL_30, DHPixelFormat.RGB_INTEGER), + RGBA32UI(GL30C.GL_RGBA32UI, GlVersion.GL_30, DHPixelFormat.RGBA_INTEGER), + // Mixed + R3_G3_B2(GL11C.GL_R3_G3_B2, GlVersion.GL_11, DHPixelFormat.RGB), + RGB5_A1(GL11C.GL_RGB5_A1, GlVersion.GL_11, DHPixelFormat.RGBA), + RGB10_A2(GL11C.GL_RGB10_A2, GlVersion.GL_11, DHPixelFormat.RGBA), + R11F_G11F_B10F(GL30C.GL_R11F_G11F_B10F, GlVersion.GL_30, DHPixelFormat.RGB), + RGB9_E5(GL30C.GL_RGB9_E5, GlVersion.GL_30, DHPixelFormat.RGB); + + private final int glFormat; + private final GlVersion minimumGlVersion; + private final DHPixelFormat expectedPixelFormat; + + DHInternalTextureFormat(int glFormat, GlVersion minimumGlVersion, DHPixelFormat expectedPixelFormat) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + this.expectedPixelFormat = expectedPixelFormat; + } + + public static Optional fromString(String name) { + try { + return Optional.of(DHInternalTextureFormat.valueOf(name.toUpperCase(Locale.US))); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public DHPixelFormat getPixelFormat() { return expectedPixelFormat; } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelFormat.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelFormat.java new file mode 100644 index 000000000..6424e840a --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelFormat.java @@ -0,0 +1,53 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL12C; +import org.lwjgl.opengl.GL30C; + +import java.util.Locale; +import java.util.Optional; + +public enum DHPixelFormat { + RED(GL11C.GL_RED, GlVersion.GL_11, false), + RG(GL30C.GL_RG, GlVersion.GL_30, false), + RGB(GL11C.GL_RGB, GlVersion.GL_11, false), + BGR(GL12C.GL_BGR, GlVersion.GL_12, false), + RGBA(GL11C.GL_RGBA, GlVersion.GL_11, false), + BGRA(GL12C.GL_BGRA, GlVersion.GL_12, false), + RED_INTEGER(GL30C.GL_RED_INTEGER, GlVersion.GL_30, true), + RG_INTEGER(GL30C.GL_RG_INTEGER, GlVersion.GL_30, true), + RGB_INTEGER(GL30C.GL_RGB_INTEGER, GlVersion.GL_30, true), + BGR_INTEGER(GL30C.GL_BGR_INTEGER, GlVersion.GL_30, true), + RGBA_INTEGER(GL30C.GL_RGBA_INTEGER, GlVersion.GL_30, true), + BGRA_INTEGER(GL30C.GL_BGRA_INTEGER, GlVersion.GL_30, true); + + private final int glFormat; + private final GlVersion minimumGlVersion; + private final boolean isInteger; + + DHPixelFormat(int glFormat, GlVersion minimumGlVersion, boolean isInteger) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + this.isInteger = isInteger; + } + + public static Optional fromString(String name) { + try { + return Optional.of(DHPixelFormat.valueOf(name.toUpperCase(Locale.US))); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } + + public boolean isInteger() { + return isInteger; + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelType.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelType.java new file mode 100644 index 000000000..432bc5307 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/DHPixelType.java @@ -0,0 +1,55 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +import org.lwjgl.opengl.GL11C; +import org.lwjgl.opengl.GL12C; +import org.lwjgl.opengl.GL30C; + +import java.util.Locale; +import java.util.Optional; + +public enum DHPixelType { + BYTE(GL11C.GL_BYTE, GlVersion.GL_11), + SHORT(GL11C.GL_SHORT, GlVersion.GL_11), + INT(GL11C.GL_INT, GlVersion.GL_11), + HALF_FLOAT(GL30C.GL_HALF_FLOAT, GlVersion.GL_30), + FLOAT(GL11C.GL_FLOAT, GlVersion.GL_11), + UNSIGNED_BYTE(GL11C.GL_UNSIGNED_BYTE, GlVersion.GL_11), + UNSIGNED_BYTE_3_3_2(GL12C.GL_UNSIGNED_BYTE_3_3_2, GlVersion.GL_12), + UNSIGNED_BYTE_2_3_3_REV(GL12C.GL_UNSIGNED_BYTE_2_3_3_REV, GlVersion.GL_12), + UNSIGNED_SHORT(GL11C.GL_UNSIGNED_SHORT, GlVersion.GL_11), + UNSIGNED_SHORT_5_6_5(GL12C.GL_UNSIGNED_SHORT_5_6_5, GlVersion.GL_12), + UNSIGNED_SHORT_5_6_5_REV(GL12C.GL_UNSIGNED_SHORT_5_6_5_REV, GlVersion.GL_12), + UNSIGNED_SHORT_4_4_4_4(GL12C.GL_UNSIGNED_SHORT_4_4_4_4, GlVersion.GL_12), + UNSIGNED_SHORT_4_4_4_4_REV(GL12C.GL_UNSIGNED_SHORT_4_4_4_4_REV, GlVersion.GL_12), + UNSIGNED_SHORT_5_5_5_1(GL12C.GL_UNSIGNED_SHORT_5_5_5_1, GlVersion.GL_12), + UNSIGNED_SHORT_1_5_5_5_REV(GL12C.GL_UNSIGNED_SHORT_1_5_5_5_REV, GlVersion.GL_12), + UNSIGNED_INT(GL11C.GL_UNSIGNED_INT, GlVersion.GL_11), + UNSIGNED_INT_8_8_8_8(GL12C.GL_UNSIGNED_INT_8_8_8_8, GlVersion.GL_12), + UNSIGNED_INT_8_8_8_8_REV(GL12C.GL_UNSIGNED_INT_8_8_8_8_REV, GlVersion.GL_12), + UNSIGNED_INT_10_10_10_2(GL12C.GL_UNSIGNED_INT_10_10_10_2, GlVersion.GL_12), + UNSIGNED_INT_2_10_10_10_REV(GL12C.GL_UNSIGNED_INT_2_10_10_10_REV, GlVersion.GL_12); + + private final int glFormat; + private final GlVersion minimumGlVersion; + + DHPixelType(int glFormat, GlVersion minimumGlVersion) { + this.glFormat = glFormat; + this.minimumGlVersion = minimumGlVersion; + } + + public static Optional fromString(String name) { + try { + return Optional.of(DHPixelType.valueOf(name.toUpperCase(Locale.US))); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } + + public int getGlFormat() { + return glFormat; + } + + public GlVersion getMinimumGlVersion() { + return minimumGlVersion; + } +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/GlVersion.java b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/GlVersion.java new file mode 100644 index 000000000..5453e3000 --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/glObject/texture/GlVersion.java @@ -0,0 +1,8 @@ +package com.seibel.distanthorizons.core.render.glObject.texture; + +public enum GlVersion { + GL_11, + GL_12, + GL_30, + GL_31 +} diff --git a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java index 024eb70fa..5c6f14401 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/render/renderer/LodRenderer.java @@ -31,6 +31,7 @@ import com.seibel.distanthorizons.core.render.glObject.GLProxy; import com.seibel.distanthorizons.core.render.glObject.GLState; import com.seibel.distanthorizons.core.render.glObject.buffer.GLVertexBuffer; import com.seibel.distanthorizons.core.render.glObject.buffer.QuadElementBuffer; +import com.seibel.distanthorizons.core.render.glObject.texture.*; import com.seibel.distanthorizons.core.render.renderer.shaders.*; import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.util.RenderUtil; @@ -50,7 +51,6 @@ import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL32; import java.awt.*; -import java.nio.ByteBuffer; import java.time.Duration; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -85,6 +85,8 @@ public class LodRenderer private static int activeFramebufferId = -1; private static int activeColorTextureId = -1; private static int activeDepthTextureId = -1; + private int cachedWidth; + private int cachedHeight; @@ -150,9 +152,9 @@ public class LodRenderer public boolean isSetupComplete = false; // frameBuffer and texture ID's for this renderer - private int framebufferId = -1; - private int colorTextureId = -1; - private int depthTextureId = -1; + private DHFramebuffer framebuffer; + private DHColorTexture colorTexture; + private DHDepthTexture depthTexture; @@ -194,6 +196,11 @@ public class LodRenderer } } + public void resize(int width, int height) { + colorTexture.resize(width, height); + depthTexture.resize(width, height, DHDepthBufferFormat.DEPTH32F); + } + //===============// @@ -218,11 +225,13 @@ public class LodRenderer { if (IRIS_ACCESSOR != null && IRIS_ACCESSOR.isRenderingShadowPass()) { + // Do not do this while Iris compat is being worked on. + // We do not have a wy to properly render shader shadow pass, since they can // and often do change the projection entirely, as well as the output usage. //EVENT_LOGGER.debug("Skipping shadow pass render."); - return; + //return; } // Note: Since lightmapTexture is changing every frame, it's faster to recreate it than to reuse the old one. @@ -261,46 +270,17 @@ public class LodRenderer } } + if (MC_RENDER.getTargetFrameBufferViewportWidth() != cachedWidth || MC_RENDER.getTargetFrameBufferViewportHeight() != cachedHeight) { + this.cachedWidth = MC_RENDER.getTargetFrameBufferViewportWidth(); + this.cachedHeight = MC_RENDER.getTargetFrameBufferViewportHeight(); + resize(cachedWidth, cachedHeight); + } + this.setActiveFramebufferId(framebuffer.getId()); + this.setActiveDepthTextureId(depthTexture.getTextureId()); + this.setActiveColorTextureId(colorTexture.getTexture()); // Bind LOD frame buffer - GL32.glBindFramebuffer(GL32.GL_FRAMEBUFFER, this.framebufferId); - - this.setActiveFramebufferId(this.framebufferId); - - - // Bind LOD color texture - GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.colorTextureId); - GL32.glTexImage2D(GL32.GL_TEXTURE_2D, - 0, - GL32.GL_RGBA8, - MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(), - 0, - GL32.GL_RGBA, - GL32.GL_UNSIGNED_BYTE, - (ByteBuffer) null); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR); - GL32.glFramebufferTexture2D(GL32.GL_DRAW_FRAMEBUFFER, GL32.GL_COLOR_ATTACHMENT0, GL32.GL_TEXTURE_2D, this.colorTextureId, 0); - - this.setActiveColorTextureId(this.colorTextureId); - - - // bind LOD depth texture - GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.depthTextureId); - GL32.glTexImage2D(GL32.GL_TEXTURE_2D, - 0, - GL32.GL_DEPTH_COMPONENT32, - MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(), - 0, - GL32.GL_DEPTH_COMPONENT, - GL32.GL_UNSIGNED_BYTE, - (ByteBuffer) null); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MIN_FILTER, GL32.GL_LINEAR); - GL32.glTexParameteri(GL32.GL_TEXTURE_2D, GL32.GL_TEXTURE_MAG_FILTER, GL32.GL_LINEAR); - GL32.glFramebufferTexture2D(GL32.GL_DRAW_FRAMEBUFFER, GL32.GL_DEPTH_ATTACHMENT, GL32.GL_TEXTURE_2D, this.depthTextureId, 0); - - this.setActiveDepthTextureId(this.depthTextureId); - + this.framebuffer.bind(); // Clear LOD framebuffer and depth buffers GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT); @@ -308,14 +288,6 @@ public class LodRenderer GL32.glEnable(GL32.GL_DEPTH_TEST); GL32.glDepthFunc(GL32.GL_LESS); - - if(GL32.glCheckFramebufferStatus(GL32.GL_FRAMEBUFFER) != GL32.GL_FRAMEBUFFER_COMPLETE) - { - // This generally means something wasn't bound, IE missing either the color or depth texture - tickLogger.warn("FrameBuffer ["+this.framebufferId+"] isn't complete."); - } - - // Set OpenGL polygon mode boolean renderWireframe = Config.Client.Advanced.Debugging.renderWireframe.get(); if (renderWireframe) @@ -514,9 +486,26 @@ public class LodRenderer } // Generate framebuffer, color texture, and depth render buffer - this.framebufferId = GL32.glGenFramebuffers(); - this.colorTextureId = GL32.glGenTextures(); - this.depthTextureId = GL32.glGenTextures(); + this.framebuffer = new DHFramebuffer(); + this.colorTexture = DHColorTexture.builder().setDimensions(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight()) + .setInternalFormat(DHInternalTextureFormat.RGBA8) + .setPixelType(DHPixelType.UNSIGNED_BYTE) + .setPixelFormat(DHPixelFormat.RGBA) + .build(); + this.depthTexture = new DHDepthTexture(MC_RENDER.getTargetFrameBufferViewportWidth(), MC_RENDER.getTargetFrameBufferViewportHeight(), DHDepthBufferFormat.DEPTH32F); + + this.framebuffer.addDepthAttachment(depthTexture.getTextureId(), DHDepthBufferFormat.DEPTH32F); + this.framebuffer.addColorAttachment(0, colorTexture.getTexture()); + + this.cachedWidth = MC_RENDER.getTargetFrameBufferViewportWidth(); + this.cachedHeight = MC_RENDER.getTargetFrameBufferViewportHeight(); + + if(framebuffer.getStatus() != GL32.GL_FRAMEBUFFER_COMPLETE) + { + // This generally means something wasn't bound, IE missing either the color or depth texture + tickLogger.warn("FrameBuffer ["+this.framebuffer.getId()+"] isn't complete."); + } + EVENT_LOGGER.info("Renderer setup complete"); } @@ -600,12 +589,9 @@ public class LodRenderer } // Delete framebuffer, color texture, and depth texture - if (this.framebufferId != -1) - GL32.glDeleteFramebuffers(this.framebufferId); - if (this.colorTextureId != -1) - GL32.glDeleteTextures(this.colorTextureId); - if (this.depthTextureId != -1) - GL32.glDeleteTextures(this.depthTextureId); + this.framebuffer.destroyInternal(); + this.colorTexture.destroy(); + this.depthTexture.destroy(); EVENT_LOGGER.info("Renderer Cleanup Complete"); });