mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-26 14:24:30 +00:00
Custom images, textures, SSBO, and ShaderPack/ShaderProperties backports
This commit is contained in:
1 parent
6d60477b93
commit
bb52476d27
54 files changed
+2210
-494
No files matched your search
@@ -36,3 +36,4 @@ addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
local/
|
||||
@@ -421,6 +421,7 @@ public class GLStateManager {
|
||||
|
||||
public static void init() {
|
||||
RenderSystem.initRenderer();
|
||||
IrisSamplers.initRenderer();
|
||||
|
||||
if(BYPASS_CACHE) {
|
||||
LOGGER.info("GLStateManager cache bypassed");
|
||||
|
||||
@@ -10,14 +10,23 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3i;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.ARBBufferStorage;
|
||||
import org.lwjgl.opengl.ARBClearBufferObject;
|
||||
import org.lwjgl.opengl.ARBClearTexture;
|
||||
import org.lwjgl.opengl.ARBShaderImageLoadStore;
|
||||
import org.lwjgl.opengl.ARBShaderStorageBufferObject;
|
||||
import org.lwjgl.opengl.EXTShaderImageLoadStore;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
import org.lwjgl.opengl.GL40;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
import org.lwjgl.opengl.GL44;
|
||||
import org.lwjgl.opengl.NVXGpuMemoryInfo;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
@@ -31,6 +40,16 @@ public class RenderSystem {
|
||||
private static final Logger LOGGER = LogManager.getLogger("RenderSystem");
|
||||
private static DSAAccess dsaState;
|
||||
private static boolean supportsCompute;
|
||||
private static boolean supportsImageLoadStore;
|
||||
private static boolean supportsSSBO;
|
||||
private static boolean supportsBufferStorage;
|
||||
private static boolean supportsClearTexture;
|
||||
private static boolean supportsSamplerObjects;
|
||||
private static int maxImageUnits;
|
||||
private static int maxSSBOBindings;
|
||||
|
||||
// Sampler object state tracking (null if unsupported)
|
||||
private static int[] samplers;
|
||||
|
||||
private RenderSystem() {}
|
||||
|
||||
@@ -54,6 +73,46 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
supportsCompute = supportsCompute();
|
||||
|
||||
supportsImageLoadStore = GLStateManager.capabilities.OpenGL42 || GLStateManager.capabilities.GL_ARB_shader_image_load_store || GLStateManager.capabilities.GL_EXT_shader_image_load_store;
|
||||
supportsSSBO = GLStateManager.capabilities.OpenGL43 || GLStateManager.capabilities.GL_ARB_shader_storage_buffer_object;
|
||||
supportsBufferStorage = GLStateManager.capabilities.OpenGL44 || GLStateManager.capabilities.GL_ARB_buffer_storage;
|
||||
supportsClearTexture = GLStateManager.capabilities.OpenGL44 || GLStateManager.capabilities.GL_ARB_clear_texture;
|
||||
|
||||
// Cache maximum image units
|
||||
if (supportsImageLoadStore) {
|
||||
if (GLStateManager.capabilities.OpenGL42) {
|
||||
maxImageUnits = GL11.glGetInteger(GL42.GL_MAX_IMAGE_UNITS);
|
||||
} else if (GLStateManager.capabilities.GL_ARB_shader_image_load_store) {
|
||||
maxImageUnits = GL11.glGetInteger(ARBShaderImageLoadStore.GL_MAX_IMAGE_UNITS);
|
||||
} else {
|
||||
maxImageUnits = GL11.glGetInteger(EXTShaderImageLoadStore.GL_MAX_IMAGE_UNITS_EXT);
|
||||
}
|
||||
} else {
|
||||
maxImageUnits = 0;
|
||||
}
|
||||
|
||||
// Cache maximum SSBO bindings
|
||||
if (supportsSSBO) {
|
||||
if (GLStateManager.capabilities.OpenGL43) {
|
||||
maxSSBOBindings = GL11.glGetInteger(GL43.GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
|
||||
} else {
|
||||
maxSSBOBindings = GL11.glGetInteger(ARBShaderStorageBufferObject.GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
|
||||
}
|
||||
} else {
|
||||
maxSSBOBindings = 0;
|
||||
}
|
||||
|
||||
// Check for sampler objects support (GL 3.3+ or ARB extension)
|
||||
supportsSamplerObjects = GLStateManager.capabilities.OpenGL33
|
||||
|| GLStateManager.capabilities.GL_ARB_sampler_objects;
|
||||
if (supportsSamplerObjects) {
|
||||
samplers = new int[GL11.glGetInteger(GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)];
|
||||
}
|
||||
|
||||
LOGGER.info("Image Load/Store: {}, Max Image Units: {}", supportsImageLoadStore, maxImageUnits);
|
||||
LOGGER.info("SSBO: {}, Max SSBO Bindings: {}", supportsSSBO, maxSSBOBindings);
|
||||
LOGGER.info("Buffer Storage: {}, Clear Texture: {}, Sampler Objects: {}", supportsBufferStorage, supportsClearTexture, supportsSamplerObjects);
|
||||
}
|
||||
|
||||
public static void generateMipmaps(int texture, int mipmapTarget) {
|
||||
@@ -65,8 +124,8 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static void texImage2D(int texture, int target, int level, int internalformat, int width, int height, int border, int format, int type, @Nullable ByteBuffer pixels) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
GLStateManager.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL11.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void uniformMatrix4fv(int location, boolean transpose, FloatBuffer matrix) {
|
||||
@@ -147,6 +206,17 @@ public class RenderSystem {
|
||||
dsaState.textureSubImage2D(texture, target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
}
|
||||
|
||||
|
||||
public static void texImage1D(int texture, int target, int level, int internalformat, int width, int border, int format, int type, ByteBuffer pixels) {
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL11.glTexImage1D(target, level, internalformat, width, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static void texImage3D(int texture, int target, int level, int internalformat, int width, int height, int depth, int border, int format, int type, ByteBuffer pixels) {
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL12.glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels);
|
||||
}
|
||||
|
||||
public static String getProgramInfoLog(int program) {
|
||||
return GL20.glGetProgramInfoLog(program, GL20.glGetProgrami(program, GL20.GL_INFO_LOG_LENGTH));
|
||||
}
|
||||
@@ -208,13 +278,27 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static int getMaxImageUnits() {
|
||||
if (GLStateManager.capabilities.OpenGL42) {
|
||||
return GL11.glGetInteger(GL42.GL_MAX_IMAGE_UNITS);
|
||||
} else if (GLStateManager.capabilities.GL_EXT_shader_image_load_store) {
|
||||
return GL11.glGetInteger(EXTShaderImageLoadStore.GL_MAX_IMAGE_UNITS_EXT);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return maxImageUnits;
|
||||
}
|
||||
|
||||
public static boolean supportsImageLoadStore() {
|
||||
return supportsImageLoadStore;
|
||||
}
|
||||
|
||||
public static boolean supportsSSBO() {
|
||||
return supportsSSBO;
|
||||
}
|
||||
|
||||
public static boolean supportsBufferStorage() {
|
||||
return supportsBufferStorage;
|
||||
}
|
||||
|
||||
public static boolean supportsClearTexture() {
|
||||
return supportsClearTexture;
|
||||
}
|
||||
|
||||
public static int getMaxSSBOBindings() {
|
||||
return maxSSBOBindings;
|
||||
}
|
||||
|
||||
public static void getProgramiv(int program, int value, IntBuffer storage) {
|
||||
@@ -229,6 +313,14 @@ public class RenderSystem {
|
||||
GL43.glDispatchCompute(workGroups.x, workGroups.y, workGroups.z);
|
||||
}
|
||||
|
||||
public static void dispatchComputeIndirect(long offset) {
|
||||
GL43.glDispatchComputeIndirect(offset);
|
||||
}
|
||||
|
||||
public static void bindBuffer(int target, int buffer) {
|
||||
GL15.glBindBuffer(target, buffer);
|
||||
}
|
||||
|
||||
public static void memoryBarrier(int barriers) {
|
||||
if (supportsCompute) {
|
||||
GL42.glMemoryBarrier(barriers);
|
||||
@@ -255,6 +347,10 @@ public class RenderSystem {
|
||||
dsaState.bindTextureToUnit(unit, texture);
|
||||
}
|
||||
|
||||
public static void bindTextureToUnit(int target, int unit, int texture) {
|
||||
dsaState.bindTextureToUnit(target, unit, texture);
|
||||
}
|
||||
|
||||
public static final FloatBuffer PROJECTION_MATRIX_BUFFER = BufferUtils.createFloatBuffer(16);
|
||||
public static void setupProjectionMatrix(Matrix4f matrix) {
|
||||
GLStateManager.glMatrixMode(GL11.GL_PROJECTION);
|
||||
@@ -290,4 +386,100 @@ public class RenderSystem {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int createBuffers() {
|
||||
return GL15.glGenBuffers();
|
||||
}
|
||||
|
||||
public static void bindBufferBase(int target, int index, int buffer) {
|
||||
GL30.glBindBufferBase(target, index, buffer);
|
||||
}
|
||||
|
||||
public static void bufferStorage(int target, long size, int flags) {
|
||||
if (GLStateManager.capabilities.OpenGL44) {
|
||||
GL44.glBufferStorage(target, size, flags);
|
||||
} else if (GLStateManager.capabilities.GL_ARB_buffer_storage) {
|
||||
ARBBufferStorage.glBufferStorage(target, size, flags);
|
||||
} else {
|
||||
// Fallback: use mutable storage
|
||||
GL15.glBufferData(target, size, GL15.GL_DYNAMIC_DRAW);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, int[] data) {
|
||||
if (GLStateManager.capabilities.OpenGL43) {
|
||||
GL43.glClearBufferSubData(target, internalFormat, offset, size, format, type, (ByteBuffer) null);
|
||||
} else if (GLStateManager.capabilities.GL_ARB_clear_buffer_object) {
|
||||
ARBClearBufferObject.glClearBufferSubData(target, internalFormat, offset, size, format, type, (ByteBuffer) null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteBuffers(int buffer) {
|
||||
GL15.glDeleteBuffers(buffer);
|
||||
}
|
||||
|
||||
public static long getVRAM() {
|
||||
if (GLStateManager.capabilities.GL_NVX_gpu_memory_info) {
|
||||
return GL11.glGetInteger(NVXGpuMemoryInfo.GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX) * 1024L;
|
||||
} else {
|
||||
// Default to 4GB if we can't query VRAM
|
||||
return 4294967296L;
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearTexImage(int texture, int target, int level, int format, int type) {
|
||||
if (GLStateManager.capabilities.OpenGL44) {
|
||||
GL44.glClearTexImage(texture, level, format, type, (ByteBuffer) null);
|
||||
} else {
|
||||
ARBClearTexture.glClearTexImage(texture, level, format, type, (ByteBuffer) null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void textureStorage1D(int texture, int target, int levels, int internalFormat, int width) {
|
||||
dsaState.textureStorage1D(texture, target, levels, internalFormat, width);
|
||||
}
|
||||
|
||||
public static void textureStorage2D(int texture, int target, int levels, int internalFormat, int width, int height) {
|
||||
dsaState.textureStorage2D(texture, target, levels, internalFormat, width, height);
|
||||
}
|
||||
|
||||
public static void textureStorage3D(int texture, int target, int levels, int internalFormat, int width, int height, int depth) {
|
||||
dsaState.textureStorage3D(texture, target, levels, internalFormat, width, height, depth);
|
||||
}
|
||||
|
||||
public static boolean supportsSamplerObjects() {
|
||||
return supportsSamplerObjects;
|
||||
}
|
||||
|
||||
public static int genSampler() {
|
||||
if (!supportsSamplerObjects) return 0;
|
||||
return GL33.glGenSamplers();
|
||||
}
|
||||
|
||||
public static void destroySampler(int sampler) {
|
||||
if (!supportsSamplerObjects || sampler == 0) return;
|
||||
GL33.glDeleteSamplers(sampler);
|
||||
}
|
||||
|
||||
public static void samplerParameteri(int sampler, int pname, int param) {
|
||||
if (!supportsSamplerObjects || sampler == 0) return;
|
||||
GL33.glSamplerParameteri(sampler, pname, param);
|
||||
}
|
||||
|
||||
public static void bindSamplerToUnit(int unit, int sampler) {
|
||||
if (!supportsSamplerObjects) return;
|
||||
if (samplers[unit] == sampler) return;
|
||||
GL33.glBindSampler(unit, sampler);
|
||||
samplers[unit] = sampler;
|
||||
}
|
||||
|
||||
public static void unbindAllSamplers() {
|
||||
if (!supportsSamplerObjects) return;
|
||||
for (int i = 0; i < samplers.length; i++) {
|
||||
if (samplers[i] != 0) {
|
||||
GL33.glBindSampler(i, 0);
|
||||
samplers[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,11 @@ public class DSAARB extends DSAUnsupported {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTextureToUnit(int target, int unit, int texture) {
|
||||
bindTextureToUnit(unit, texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bufferStorage(int target, FloatBuffer data, int usage) {
|
||||
final int buffer = GL45.glCreateBuffers();
|
||||
@@ -121,4 +126,19 @@ public class DSAARB extends DSAUnsupported {
|
||||
public int createTexture(int target) {
|
||||
return ARBDirectStateAccess.glCreateTextures(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage1D(int texture, int target, int levels, int internalFormat, int width) {
|
||||
ARBDirectStateAccess.glTextureStorage1D(texture, levels, internalFormat, width);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage2D(int texture, int target, int levels, int internalFormat, int width, int height) {
|
||||
ARBDirectStateAccess.glTextureStorage2D(texture, levels, internalFormat, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage3D(int texture, int target, int levels, int internalFormat, int width, int height, int depth) {
|
||||
ARBDirectStateAccess.glTextureStorage3D(texture, levels, internalFormat, width, height, depth);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ public interface DSAAccess {
|
||||
void copyTexSubImage2D(int destTexture, int target, int i, int i1, int i2, int i3, int i4, int width, int height);
|
||||
|
||||
void bindTextureToUnit(int unit, int texture);
|
||||
void bindTextureToUnit(int target, int unit, int texture);
|
||||
|
||||
int bufferStorage(int target, FloatBuffer data, int usage);
|
||||
|
||||
@@ -37,4 +38,9 @@ public interface DSAAccess {
|
||||
|
||||
int createFramebuffer();
|
||||
int createTexture(int target);
|
||||
|
||||
// Texture storage methods for custom images
|
||||
void textureStorage1D(int texture, int target, int levels, int internalFormat, int width);
|
||||
void textureStorage2D(int texture, int target, int levels, int internalFormat, int width, int height);
|
||||
void textureStorage3D(int texture, int target, int levels, int internalFormat, int width, int height, int depth);
|
||||
}
|
||||
@@ -4,10 +4,13 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
@@ -113,6 +116,12 @@ public class DSAUnsupported implements DSAAccess {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindTextureToUnit(int target, int unit, int texture) {
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
GLStateManager.glBindTexture(target, texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bufferStorage(int target, FloatBuffer data, int usage) {
|
||||
final int buffer = GL15.glGenBuffers();
|
||||
@@ -150,4 +159,28 @@ public class DSAUnsupported implements DSAAccess {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage1D(int texture, int target, int levels, int internalFormat, int width) {
|
||||
final int previous = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_1D);
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL42.glTexStorage1D(target, levels, internalFormat, width);
|
||||
GL11.glBindTexture(target, previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage2D(int texture, int target, int levels, int internalFormat, int width, int height) {
|
||||
final int previous = (target == GL11.GL_TEXTURE_2D) ? GLStateManager.getBoundTextureForServerState() : GL11.glGetInteger(GL31.GL_TEXTURE_BINDING_RECTANGLE);
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL42.glTexStorage2D(target, levels, internalFormat, width, height);
|
||||
GL11.glBindTexture(target, previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void textureStorage3D(int texture, int target, int levels, int internalFormat, int width, int height, int depth) {
|
||||
final int previous = GL11.glGetInteger(GL12.GL_TEXTURE_BINDING_3D);
|
||||
GL11.glBindTexture(target, texture);
|
||||
GL42.glTexStorage3D(target, levels, internalFormat, width, height, depth);
|
||||
GL11.glBindTexture(target, previous);
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,10 @@ public class IrisLogging {
|
||||
this.logger.debug(debug);
|
||||
}
|
||||
|
||||
public void debug(String debug, Object... o) {
|
||||
this.logger.debug(debug, o);
|
||||
}
|
||||
|
||||
public void debug(String debug, Throwable t) {
|
||||
this.logger.debug(debug, t);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package net.coderbot.iris.compat.dh;
|
||||
|
||||
/**
|
||||
* Stub implementation of Distant Horizons compatibility.
|
||||
*/
|
||||
public class DHCompat {
|
||||
public int getDepthTex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getDepthTexNoTranslucent() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ public enum FeatureFlags {
|
||||
COMPUTE_SHADERS(() -> true, RenderSystem::supportsCompute),
|
||||
ENTITY_TRANSLUCENT(() -> true, () -> true),
|
||||
BLOCK_EMISSION_ATTRIBUTE(() -> true, () -> true),
|
||||
CUSTOM_IMAGES(() -> true, RenderSystem::supportsImageLoadStore),
|
||||
SSBO(() -> true, RenderSystem::supportsSSBO),
|
||||
UNKNOWN(() -> false, () -> false);
|
||||
|
||||
private final BooleanSupplier irisRequirement;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package net.coderbot.iris.gl.buffer;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.embeddedt.embeddium.impl.gl.debug.GLDebug;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public class ShaderStorageBuffer {
|
||||
protected final int index;
|
||||
protected final ShaderStorageInfo info;
|
||||
protected int id;
|
||||
|
||||
public ShaderStorageBuffer(int index, ShaderStorageInfo info) {
|
||||
this.id = RenderSystem.createBuffers();
|
||||
GLDebug.nameObject(GL43.GL_BUFFER, id, "SSBO " + index);
|
||||
this.index = index;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public final int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public final long getSize() {
|
||||
return info.size();
|
||||
}
|
||||
|
||||
protected void destroy() {
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, 0);
|
||||
RenderSystem.deleteBuffers(id);
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, id);
|
||||
}
|
||||
|
||||
public void resizeIfRelative(int width, int height) {
|
||||
if (!info.relative()) return;
|
||||
|
||||
RenderSystem.deleteBuffers(id);
|
||||
int newId = GL15.glGenBuffers();
|
||||
GL15.glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, newId);
|
||||
|
||||
// Calculation time
|
||||
int newWidth = (int) (width * info.scaleX());
|
||||
int newHeight = (int) (height * info.scaleY());
|
||||
int finalSize = (newHeight * newWidth) * info.size();
|
||||
RenderSystem.bufferStorage(GL43.GL_SHADER_STORAGE_BUFFER, finalSize, 0);
|
||||
RenderSystem.clearBufferSubData(GL43.GL_SHADER_STORAGE_BUFFER, GL30.GL_R8, 0, finalSize, GL11.GL_RED, GL11.GL_BYTE, new int[]{0});
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, newId);
|
||||
id = newId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package net.coderbot.iris.gl.buffer;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import net.coderbot.iris.gl.sampler.SamplerLimits;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class ShaderStorageBufferHolder {
|
||||
private int cachedWidth;
|
||||
private int cachedHeight;
|
||||
private ShaderStorageBuffer[] buffers;
|
||||
private boolean destroyed;
|
||||
|
||||
public ShaderStorageBufferHolder(Int2ObjectArrayMap<ShaderStorageInfo> overrides, int width, int height) {
|
||||
destroyed = false;
|
||||
cachedWidth = width;
|
||||
cachedHeight = height;
|
||||
buffers = new ShaderStorageBuffer[Collections.max(overrides.keySet()) + 1];
|
||||
overrides.forEach((index, bufferInfo) -> {
|
||||
if (bufferInfo.size() > RenderSystem.getVRAM()) {
|
||||
throw new OutOfVideoMemoryError("We only have " + toMib(RenderSystem.getVRAM()) + "MiB of RAM to work with, but the pack is requesting " + bufferInfo.size() + "! Can't continue.");
|
||||
}
|
||||
|
||||
if (index > SamplerLimits.get().getMaxShaderStorageUnits()) {
|
||||
throw new IllegalStateException("We don't have enough SSBO units??? (index: " + index + ", max: " + SamplerLimits.get().getMaxShaderStorageUnits());
|
||||
}
|
||||
|
||||
buffers[index] = new ShaderStorageBuffer(index, bufferInfo);
|
||||
int buffer = buffers[index].getId();
|
||||
|
||||
if (bufferInfo.relative()) {
|
||||
buffers[index].resizeIfRelative(width, height);
|
||||
} else {
|
||||
GL15.glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, buffer);
|
||||
RenderSystem.bufferStorage(GL43.GL_SHADER_STORAGE_BUFFER, bufferInfo.size(), 0);
|
||||
RenderSystem.clearBufferSubData(GL43.GL_SHADER_STORAGE_BUFFER, GL30.GL_R8, 0, bufferInfo.size(), GL11.GL_RED, GL11.GL_BYTE, new int[]{0});
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, buffer);
|
||||
}
|
||||
});
|
||||
GL15.glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, 0);
|
||||
}
|
||||
|
||||
private static long toMib(long x) {
|
||||
return x / 1024L / 1024L;
|
||||
}
|
||||
|
||||
public void hasResizedScreen(int width, int height) {
|
||||
if (width != cachedWidth || height != cachedHeight) {
|
||||
cachedWidth = width;
|
||||
cachedHeight = height;
|
||||
for (ShaderStorageBuffer buffer : buffers) {
|
||||
if (buffer != null) {
|
||||
buffer.resizeIfRelative(width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setupBuffers() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("Tried to use destroyed buffer objects");
|
||||
}
|
||||
|
||||
for (ShaderStorageBuffer buffer : buffers) {
|
||||
if (buffer != null) {
|
||||
buffer.bind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getBufferIndex(int index) {
|
||||
if (buffers.length < index || buffers[index] == null)
|
||||
throw new RuntimeException("Tried to query a buffer for indirect dispatch that doesn't exist!");
|
||||
|
||||
return buffers[index].getId();
|
||||
}
|
||||
|
||||
public void destroyBuffers() {
|
||||
for (ShaderStorageBuffer buffer : buffers) {
|
||||
if (buffer != null) {
|
||||
buffer.destroy();
|
||||
}
|
||||
}
|
||||
buffers = null;
|
||||
destroyed = true;
|
||||
}
|
||||
|
||||
private static class OutOfVideoMemoryError extends RuntimeException {
|
||||
public OutOfVideoMemoryError(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package net.coderbot.iris.gl.buffer;
|
||||
|
||||
public record ShaderStorageInfo(int size, boolean relative, float scaleX, float scaleY) {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.coderbot.iris.gl.framebuffer;
|
||||
|
||||
public record ViewportData(float scale, float viewportX, float viewportY) {
|
||||
private static final ViewportData DEFAULT = new ViewportData(1.0f, 0.0f, 0.0f);
|
||||
|
||||
public static ViewportData defaultValue() {
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package net.coderbot.iris.gl.image;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelType;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import org.embeddedt.embeddium.impl.gl.GlObject;
|
||||
import org.embeddedt.embeddium.impl.gl.debug.GLDebug;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
public class GlImage extends GlObject {
|
||||
protected final String name;
|
||||
protected final String samplerName;
|
||||
protected final TextureType target;
|
||||
protected final PixelFormat format;
|
||||
protected final InternalTextureFormat internalTextureFormat;
|
||||
protected final PixelType pixelType;
|
||||
private final boolean clear;
|
||||
|
||||
public GlImage(String name, String samplerName, TextureType target, PixelFormat format, InternalTextureFormat internalFormat, PixelType pixelType, boolean clear, int width, int height, int depth) {
|
||||
this.setHandle(RenderSystem.createTexture(target.getGlType()));
|
||||
|
||||
this.name = name;
|
||||
this.samplerName = samplerName;
|
||||
this.target = target;
|
||||
this.format = format;
|
||||
this.internalTextureFormat = internalFormat;
|
||||
this.pixelType = pixelType;
|
||||
this.clear = clear;
|
||||
|
||||
GLDebug.nameObject(GL11.GL_TEXTURE, handle(), name);
|
||||
|
||||
GL11.glBindTexture(target.getGlType(), handle());
|
||||
target.apply(handle(), width, height, depth, internalFormat.getGlFormat(), format.getGlFormat(), pixelType.getGlFormat(), null);
|
||||
|
||||
int texture = handle();
|
||||
|
||||
setup(texture, width, height, depth);
|
||||
|
||||
GL11.glBindTexture(target.getGlType(), 0);
|
||||
}
|
||||
|
||||
protected void setup(int texture, int width, int height, int depth) {
|
||||
boolean isInteger = internalTextureFormat.getPixelFormat().isInteger();
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_MIN_FILTER, isInteger ? GL11.GL_NEAREST : GL11.GL_LINEAR);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_MAG_FILTER, isInteger ? GL11.GL_NEAREST : GL11.GL_LINEAR);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (height > 0) {
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_WRAP_R, GL12.GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MIN_LOD, 0);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MAX_LOD, 0);
|
||||
RenderSystem.texParameterf(texture, target.getGlType(), GL14.GL_TEXTURE_LOD_BIAS, 0.0F);
|
||||
|
||||
RenderSystem.clearTexImage(texture, target.getGlType(), 0, format.getGlFormat(), pixelType.getGlFormat());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSamplerName() {
|
||||
return samplerName;
|
||||
}
|
||||
|
||||
public TextureType getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public boolean shouldClear() {
|
||||
return clear;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the texture to zero. Called each frame for images that need clearing.
|
||||
*/
|
||||
public void clear() {
|
||||
RenderSystem.clearTexImage(handle(), target.getGlType(), 0, format.getGlFormat(), pixelType.getGlFormat());
|
||||
}
|
||||
|
||||
/**
|
||||
* This makes the image aware of a new render target. Depending on the image's properties, it may not follow these targets.
|
||||
*
|
||||
* @param width The width of the main render target.
|
||||
* @param height The height of the main render target.
|
||||
*/
|
||||
public void updateNewSize(int width, int height) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyInternal() {
|
||||
GLStateManager.glDeleteTextures(handle());
|
||||
}
|
||||
|
||||
public InternalTextureFormat getInternalFormat() {
|
||||
return internalTextureFormat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GlImage name " + name + " format " + format + "internalformat " + internalTextureFormat + " pixeltype " + pixelType;
|
||||
}
|
||||
|
||||
public PixelFormat getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public PixelType getPixelType() {
|
||||
return pixelType;
|
||||
}
|
||||
|
||||
public static class Relative extends GlImage {
|
||||
|
||||
private final float relativeHeight;
|
||||
private final float relativeWidth;
|
||||
|
||||
public Relative(String name, String samplerName, PixelFormat format, InternalTextureFormat internalFormat, PixelType pixelType, boolean clear, float relativeWidth, float relativeHeight, int currentWidth, int currentHeight) {
|
||||
super(name, samplerName, TextureType.TEXTURE_2D, format, internalFormat, pixelType, clear, (int) (currentWidth * relativeWidth), (int) (currentHeight * relativeHeight), 0);
|
||||
|
||||
this.relativeWidth = relativeWidth;
|
||||
this.relativeHeight = relativeHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNewSize(int width, int height) {
|
||||
GL11.glBindTexture(target.getGlType(), handle());
|
||||
target.apply(handle(), (int) (width * relativeWidth), (int) (height * relativeHeight), 0, internalTextureFormat.getGlFormat(), format.getGlFormat(), pixelType.getGlFormat(), null);
|
||||
|
||||
int texture = handle();
|
||||
|
||||
setup(texture, width, height, 0);
|
||||
|
||||
GL11.glBindTexture(target.getGlType(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.coderbot.iris.gl.image;
|
||||
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelType;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
|
||||
public record ImageInformation(String name, String samplerName, TextureType target, PixelFormat format,
|
||||
InternalTextureFormat internalTextureFormat,
|
||||
PixelType type, int width, int height, int depth, boolean clear, boolean isRelative,
|
||||
float relativeWidth, float relativeHeight) {
|
||||
}
|
||||
@@ -4,10 +4,12 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.GlResource;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.shaderpack.FilledIndirectPointer;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3i;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
@@ -18,8 +20,8 @@ public final class ComputeProgram extends GlResource {
|
||||
private final ProgramImages images;
|
||||
private Vector3i absoluteWorkGroups;
|
||||
private Vector2f relativeWorkGroups;
|
||||
// private int[] localSize;
|
||||
private final IntBuffer localSizeBuffer;
|
||||
private FilledIndirectPointer indirectPointer;
|
||||
private final IntBuffer localSizeBuffer;
|
||||
private float cachedWidth;
|
||||
private float cachedHeight;
|
||||
private Vector3i cachedWorkGroups;
|
||||
@@ -34,19 +36,21 @@ public final class ComputeProgram extends GlResource {
|
||||
this.images = images;
|
||||
}
|
||||
|
||||
public void setWorkGroupInfo(Vector2f relativeWorkGroups, Vector3i absoluteWorkGroups) {
|
||||
public void setWorkGroupInfo(Vector2f relativeWorkGroups, Vector3i absoluteWorkGroups, FilledIndirectPointer indirectPointer) {
|
||||
this.relativeWorkGroups = relativeWorkGroups;
|
||||
this.absoluteWorkGroups = absoluteWorkGroups;
|
||||
this.indirectPointer = indirectPointer;
|
||||
}
|
||||
|
||||
public Vector3i getWorkGroups(float width, float height) {
|
||||
if (indirectPointer != null) return null;
|
||||
|
||||
if (cachedWidth != width || cachedHeight != height || cachedWorkGroups == null) {
|
||||
this.cachedWidth = width;
|
||||
this.cachedHeight = height;
|
||||
if (this.absoluteWorkGroups != null) {
|
||||
this.cachedWorkGroups = this.absoluteWorkGroups;
|
||||
} else if (relativeWorkGroups != null) {
|
||||
// TODO: This is my best guess at what Optifine does. Can this be confirmed?
|
||||
// Do not use actual localSize here, apparently that's not what we want.
|
||||
this.cachedWorkGroups = new Vector3i((int) Math.ceil(Math.ceil((width * relativeWorkGroups.x)) / localSizeBuffer.get(0)), (int) Math.ceil(Math.ceil((height * relativeWorkGroups.y)) / localSizeBuffer.get(1)), 1);
|
||||
} else {
|
||||
@@ -67,10 +71,15 @@ public final class ComputeProgram extends GlResource {
|
||||
|
||||
public void dispatch(float width, float height) {
|
||||
if (!Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::allowConcurrentCompute).orElse(false)) {
|
||||
RenderSystem.memoryBarrier(40);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
RenderSystem.dispatchCompute(getWorkGroups(width, height));
|
||||
if (indirectPointer != null) {
|
||||
RenderSystem.bindBuffer(GL43.GL_DISPATCH_INDIRECT_BUFFER, indirectPointer.buffer());
|
||||
RenderSystem.dispatchComputeIndirect(indirectPointer.offset());
|
||||
} else {
|
||||
RenderSystem.dispatchCompute(getWorkGroups(width, height));
|
||||
}
|
||||
}
|
||||
|
||||
public static void unbind() {
|
||||
|
||||
@@ -3,12 +3,14 @@ package net.coderbot.iris.gl.program;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.coderbot.iris.gl.image.ImageHolder;
|
||||
import net.coderbot.iris.gl.sampler.GlSampler;
|
||||
import net.coderbot.iris.gl.sampler.SamplerHolder;
|
||||
import net.coderbot.iris.gl.shader.GlShader;
|
||||
import net.coderbot.iris.gl.shader.ProgramCreator;
|
||||
import net.coderbot.iris.gl.shader.ShaderType;
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
@@ -106,17 +108,18 @@ public class ProgramBuilder extends ProgramUniforms.Builder implements SamplerHo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDefaultSampler(IntSupplier sampler, String... names) {
|
||||
return samplers.addDefaultSampler(sampler, names);
|
||||
public boolean addDefaultSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
return samplers.addDefaultSampler(type, texture, notifier, sampler, names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDynamicSampler(IntSupplier sampler, String... names) {
|
||||
return samplers.addDynamicSampler(sampler, names);
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, GlSampler sampler, String... names) {
|
||||
return samplers.addDynamicSampler(type, texture, sampler, names);
|
||||
}
|
||||
|
||||
public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) {
|
||||
return samplers.addDynamicSampler(sampler, notifier, names);
|
||||
@Override
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
return samplers.addDynamicSampler(type, texture, notifier, sampler, names);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,10 +5,13 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import net.coderbot.iris.gl.sampler.GlSampler;
|
||||
import net.coderbot.iris.gl.sampler.SamplerBinding;
|
||||
import net.coderbot.iris.gl.sampler.SamplerHolder;
|
||||
import net.coderbot.iris.gl.sampler.SamplerLimits;
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import net.coderbot.iris.shaderpack.PackRenderTargetDirectives;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
@@ -73,11 +76,11 @@ public class ProgramSamplers {
|
||||
return new Builder(program, reservedTextureUnits);
|
||||
}
|
||||
|
||||
public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, IntSupplier> customTextureIds) {
|
||||
public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, TextureAccess> customTextureIds) {
|
||||
return customTextureSamplerInterceptor(samplerHolder, customTextureIds, ImmutableSet.of());
|
||||
}
|
||||
|
||||
public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, IntSupplier> customTextureIds, ImmutableSet<Integer> flippedAtLeastOnceSnapshot) {
|
||||
public static CustomTextureSamplerInterceptor customTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, TextureAccess> customTextureIds, ImmutableSet<Integer> flippedAtLeastOnceSnapshot) {
|
||||
return new CustomTextureSamplerInterceptor(samplerHolder, customTextureIds, flippedAtLeastOnceSnapshot);
|
||||
}
|
||||
|
||||
@@ -145,35 +148,31 @@ public class ProgramSamplers {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDefaultSampler(IntSupplier sampler, String... names) {
|
||||
public boolean addDefaultSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
if (nextUnit != 0) {
|
||||
// TODO: Relax this restriction!
|
||||
throw new IllegalStateException("Texture unit 0 is already used.");
|
||||
}
|
||||
|
||||
return addDynamicSampler(sampler, true, null, names);
|
||||
if (notifier != null) {
|
||||
notifiersToReset.add(notifier);
|
||||
}
|
||||
|
||||
return addDynamicSampler(type, texture, sampler, true, notifier, names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sampler
|
||||
* @return false if this sampler is not active, true if at least one of the names referred to an active sampler
|
||||
*/
|
||||
@Override
|
||||
public boolean addDynamicSampler(IntSupplier sampler, String... names) {
|
||||
return addDynamicSampler(sampler, false, null, names);
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, GlSampler sampler, String... names) {
|
||||
return addDynamicSampler(type, texture, sampler, false, null, names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sampler
|
||||
* @return false if this sampler is not active, true if at least one of the names referred to an active sampler
|
||||
*/
|
||||
@Override
|
||||
public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) {
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
notifiersToReset.add(notifier);
|
||||
return addDynamicSampler(sampler, false, notifier, names);
|
||||
return addDynamicSampler(type, texture, sampler, false, notifier, names);
|
||||
}
|
||||
|
||||
private boolean addDynamicSampler(IntSupplier sampler, boolean used, ValueUpdateNotifier notifier, String... names) {
|
||||
private boolean addDynamicSampler(TextureType type, IntSupplier texture, GlSampler sampler, boolean used, ValueUpdateNotifier notifier, String... names) {
|
||||
for (String name : names) {
|
||||
int location = RenderSystem.getUniformLocation(program, name);
|
||||
|
||||
@@ -187,8 +186,6 @@ public class ProgramSamplers {
|
||||
throw new IllegalStateException("No more available texture units while activating sampler " + name);
|
||||
}
|
||||
|
||||
//System.out.println("Binding dynamic sampler " + name + " to texture unit " + nextUnit);
|
||||
|
||||
// Set up this sampler uniform to use this particular texture unit.
|
||||
calls.add(new GlUniform1iCall(location, nextUnit));
|
||||
|
||||
@@ -200,7 +197,7 @@ public class ProgramSamplers {
|
||||
return false;
|
||||
}
|
||||
|
||||
samplers.add(new SamplerBinding(nextUnit, sampler, notifier));
|
||||
samplers.add(new SamplerBinding(type, nextUnit, texture, sampler, notifier));
|
||||
|
||||
remainingUnits -= 1;
|
||||
nextUnit += 1;
|
||||
@@ -209,8 +206,6 @@ public class ProgramSamplers {
|
||||
nextUnit += 1;
|
||||
}
|
||||
|
||||
//System.out.println("The next unit is " + nextUnit + ", there are " + remainingUnits + " units remaining.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -221,10 +216,10 @@ public class ProgramSamplers {
|
||||
|
||||
public static final class CustomTextureSamplerInterceptor implements SamplerHolder {
|
||||
private final SamplerHolder samplerHolder;
|
||||
private final Object2ObjectMap<String, IntSupplier> customTextureIds;
|
||||
private final Object2ObjectMap<String, TextureAccess> customTextureIds;
|
||||
private final ImmutableSet<String> deactivatedOverrides;
|
||||
|
||||
private CustomTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, IntSupplier> customTextureIds, ImmutableSet<Integer> flippedAtLeastOnceSnapshot) {
|
||||
private CustomTextureSamplerInterceptor(SamplerHolder samplerHolder, Object2ObjectMap<String, TextureAccess> customTextureIds, ImmutableSet<Integer> flippedAtLeastOnceSnapshot) {
|
||||
this.samplerHolder = samplerHolder;
|
||||
this.customTextureIds = customTextureIds;
|
||||
|
||||
@@ -244,7 +239,7 @@ public class ProgramSamplers {
|
||||
private IntSupplier getOverride(IntSupplier existing, String... names) {
|
||||
for (String name : names) {
|
||||
if (customTextureIds.containsKey(name) && !deactivatedOverrides.contains(name)) {
|
||||
return customTextureIds.get(name);
|
||||
return customTextureIds.get(name).getTextureId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,24 +267,21 @@ public class ProgramSamplers {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDefaultSampler(IntSupplier sampler, String... names) {
|
||||
sampler = getOverride(sampler, names);
|
||||
|
||||
return samplerHolder.addDefaultSampler(sampler, names);
|
||||
public boolean addDefaultSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
texture = getOverride(texture, names);
|
||||
return samplerHolder.addDefaultSampler(type, texture, notifier, sampler, names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDynamicSampler(IntSupplier sampler, String... names) {
|
||||
sampler = getOverride(sampler, names);
|
||||
|
||||
return samplerHolder.addDynamicSampler(sampler, names);
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, GlSampler sampler, String... names) {
|
||||
texture = getOverride(texture, names);
|
||||
return samplerHolder.addDynamicSampler(type, texture, sampler, names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names) {
|
||||
sampler = getOverride(sampler, names);
|
||||
|
||||
return samplerHolder.addDynamicSampler(sampler, notifier, names);
|
||||
public boolean addDynamicSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names) {
|
||||
texture = getOverride(texture, names);
|
||||
return samplerHolder.addDynamicSampler(type, texture, notifier, sampler, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.coderbot.iris.gl.sampler;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.embeddedt.embeddium.impl.gl.GlObject;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
public class GlSampler extends GlObject {
|
||||
public GlSampler(boolean linear, boolean mipmapped, boolean shadow, boolean hardwareShadow) {
|
||||
if (!RenderSystem.supportsSamplerObjects()) {
|
||||
this.setHandle(0);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setHandle(RenderSystem.genSampler());
|
||||
|
||||
RenderSystem.samplerParameteri(getId(), GL11.GL_TEXTURE_MIN_FILTER, linear ? GL11.GL_LINEAR : GL11.GL_NEAREST);
|
||||
RenderSystem.samplerParameteri(getId(), GL11.GL_TEXTURE_MAG_FILTER, linear ? GL11.GL_LINEAR : GL11.GL_NEAREST);
|
||||
RenderSystem.samplerParameteri(getId(), GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
RenderSystem.samplerParameteri(getId(), GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (mipmapped) {
|
||||
RenderSystem.samplerParameteri(getId(), GL11.GL_TEXTURE_MIN_FILTER, linear ? GL11.GL_LINEAR_MIPMAP_LINEAR : GL11.GL_NEAREST_MIPMAP_NEAREST);
|
||||
}
|
||||
|
||||
if (hardwareShadow) {
|
||||
RenderSystem.samplerParameteri(getId(), GL14.GL_TEXTURE_COMPARE_MODE, GL30.GL_COMPARE_REF_TO_TEXTURE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyInternal() {
|
||||
RenderSystem.destroySampler(handle());
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle();
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,22 @@ package net.coderbot.iris.gl.sampler;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
public class SamplerBinding {
|
||||
private final TextureType textureType;
|
||||
private final int textureUnit;
|
||||
private final IntSupplier texture;
|
||||
private final int sampler;
|
||||
private final ValueUpdateNotifier notifier;
|
||||
|
||||
public SamplerBinding(int textureUnit, IntSupplier texture, ValueUpdateNotifier notifier) {
|
||||
public SamplerBinding(TextureType type, int textureUnit, IntSupplier texture, GlSampler sampler, ValueUpdateNotifier notifier) {
|
||||
this.textureType = type;
|
||||
this.textureUnit = textureUnit;
|
||||
this.texture = texture;
|
||||
this.sampler = sampler == null ? 0 : sampler.getId();
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
@@ -25,6 +30,7 @@ public class SamplerBinding {
|
||||
}
|
||||
|
||||
private void updateSampler() {
|
||||
RenderSystem.bindTextureToUnit(textureUnit, texture.getAsInt());
|
||||
RenderSystem.bindSamplerToUnit(textureUnit, sampler);
|
||||
RenderSystem.bindTextureToUnit(textureType.getGlType(), textureUnit, texture.getAsInt());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.gl.sampler;
|
||||
|
||||
import net.coderbot.iris.gl.state.ValueUpdateNotifier;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
@@ -15,7 +16,25 @@ public interface SamplerHolder {
|
||||
* Throws an exception if texture unit 0 is already allocated or reserved in some way. Do not call this
|
||||
* function after calls to addDynamicSampler, it must be called before any calls to addDynamicSampler.
|
||||
*/
|
||||
boolean addDefaultSampler(IntSupplier sampler, String... names);
|
||||
boolean addDynamicSampler(IntSupplier sampler, String... names);
|
||||
boolean addDynamicSampler(IntSupplier sampler, ValueUpdateNotifier notifier, String... names);
|
||||
default boolean addDefaultSampler(IntSupplier texture, String... names) {
|
||||
return addDefaultSampler(TextureType.TEXTURE_2D, texture, null, null, names);
|
||||
}
|
||||
|
||||
boolean addDefaultSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names);
|
||||
|
||||
default boolean addDynamicSampler(IntSupplier texture, String... names) {
|
||||
return addDynamicSampler(TextureType.TEXTURE_2D, texture, null, names);
|
||||
}
|
||||
|
||||
default boolean addDynamicSampler(TextureType type, IntSupplier texture, String... names) {
|
||||
return addDynamicSampler(type, texture, null, names);
|
||||
}
|
||||
|
||||
boolean addDynamicSampler(TextureType type, IntSupplier texture, GlSampler sampler, String... names);
|
||||
|
||||
default boolean addDynamicSampler(IntSupplier texture, ValueUpdateNotifier notifier, String... names) {
|
||||
return addDynamicSampler(TextureType.TEXTURE_2D, texture, notifier, null, names);
|
||||
}
|
||||
|
||||
boolean addDynamicSampler(TextureType type, IntSupplier texture, ValueUpdateNotifier notifier, GlSampler sampler, String... names);
|
||||
}
|
||||
@@ -1,16 +1,28 @@
|
||||
package net.coderbot.iris.gl.sampler;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public class SamplerLimits {
|
||||
private static SamplerLimits instance;
|
||||
private final int maxTextureUnits;
|
||||
private final int maxDrawBuffers;
|
||||
private static SamplerLimits instance;
|
||||
private final int maxShaderStorageUnits;
|
||||
|
||||
private SamplerLimits() {
|
||||
this.maxTextureUnits = GL11.glGetInteger(GL20.GL_MAX_TEXTURE_IMAGE_UNITS);
|
||||
this.maxDrawBuffers = GL11.glGetInteger(GL20.GL_MAX_DRAW_BUFFERS);
|
||||
this.maxShaderStorageUnits = RenderSystem.supportsSSBO() ? GL11.glGetInteger(GL43.GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS) : 0;
|
||||
}
|
||||
|
||||
public static SamplerLimits get() {
|
||||
if (instance == null) {
|
||||
instance = new SamplerLimits();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getMaxTextureUnits() {
|
||||
@@ -21,11 +33,7 @@ public class SamplerLimits {
|
||||
return maxDrawBuffers;
|
||||
}
|
||||
|
||||
public static SamplerLimits get() {
|
||||
if (instance == null) {
|
||||
instance = new SamplerLimits();
|
||||
}
|
||||
|
||||
return instance;
|
||||
public int getMaxShaderStorageUnits() {
|
||||
return maxShaderStorageUnits;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package net.coderbot.iris.gl.texture;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import net.coderbot.iris.shaderpack.texture.TextureFilteringData;
|
||||
import org.embeddedt.embeddium.impl.gl.GlObject;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
|
||||
public class GlTexture extends GlObject implements TextureAccess {
|
||||
private final TextureType target;
|
||||
|
||||
public GlTexture(TextureType target, int sizeX, int sizeY, int sizeZ, int internalFormat, int format, int pixelType, byte[] pixels, TextureFilteringData filteringData) {
|
||||
this.setHandle(GL11.glGenTextures());
|
||||
bindTextureForSetup(target.getGlType(), handle());
|
||||
|
||||
TextureUploadHelper.resetTextureUploadState();
|
||||
|
||||
final ByteBuffer buffer = memAlloc(pixels.length);
|
||||
buffer.put(pixels);
|
||||
buffer.flip();
|
||||
target.apply(this.handle(), sizeX, sizeY, sizeZ, internalFormat, format, pixelType, buffer);
|
||||
memFree(buffer);
|
||||
|
||||
final int texture = this.handle();
|
||||
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_MIN_FILTER, filteringData.shouldBlur() ? GL11.GL_LINEAR : GL11.GL_NEAREST);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_MAG_FILTER, filteringData.shouldBlur() ? GL11.GL_LINEAR : GL11.GL_NEAREST);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_WRAP_S, filteringData.shouldClamp() ? GL12.GL_CLAMP_TO_EDGE : GL11.GL_REPEAT);
|
||||
|
||||
if (sizeY > 0) {
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL11.GL_TEXTURE_WRAP_T, filteringData.shouldClamp() ? GL12.GL_CLAMP_TO_EDGE : GL11.GL_REPEAT);
|
||||
}
|
||||
|
||||
if (sizeZ > 0) {
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_WRAP_R, filteringData.shouldClamp() ? GL12.GL_CLAMP_TO_EDGE : GL11.GL_REPEAT);
|
||||
}
|
||||
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MIN_LOD, 0);
|
||||
RenderSystem.texParameteri(texture, target.getGlType(), GL12.GL_TEXTURE_MAX_LOD, 0);
|
||||
RenderSystem.texParameterf(texture, target.getGlType(), GL14.GL_TEXTURE_LOD_BIAS, 0.0F);
|
||||
|
||||
bindTextureForSetup(target.getGlType(), 0);
|
||||
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public static void bindTextureForSetup(int glType, int glId) {
|
||||
GL11.glBindTexture(glType, glId);
|
||||
}
|
||||
|
||||
public TextureType getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void bind(int unit) {
|
||||
RenderSystem.bindTextureToUnit(target.getGlType(), unit, handle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureType getType() {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSupplier getTextureId() {
|
||||
return this::handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyInternal() {
|
||||
GLStateManager.glDeleteTextures(handle());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.coderbot.iris.gl.texture;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
public interface TextureAccess {
|
||||
TextureType getType();
|
||||
|
||||
IntSupplier getTextureId();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.coderbot.iris.gl.texture;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public abstract class TextureDefinition {
|
||||
protected String name;
|
||||
|
||||
public static class PNGDefinition extends TextureDefinition {
|
||||
public PNGDefinition(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class RawDefinition extends TextureDefinition {
|
||||
private final TextureType target;
|
||||
private final int sizeX;
|
||||
private final int sizeY;
|
||||
private final int sizeZ;
|
||||
private final InternalTextureFormat internalFormat;
|
||||
private final PixelFormat format;
|
||||
private final PixelType pixelType;
|
||||
|
||||
public RawDefinition(String path, TextureType target, InternalTextureFormat internalFormat, int sizeX, int sizeY, int sizeZ, PixelFormat format, PixelType pixelType) {
|
||||
this.name = path;
|
||||
this.target = target;
|
||||
this.sizeX = sizeX;
|
||||
this.sizeY = sizeY;
|
||||
this.sizeZ = sizeZ;
|
||||
this.internalFormat = internalFormat;
|
||||
this.format = format;
|
||||
this.pixelType = pixelType;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.coderbot.iris.gl.texture;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum TextureType {
|
||||
TEXTURE_1D(GL11.GL_TEXTURE_1D),
|
||||
TEXTURE_2D(GL11.GL_TEXTURE_2D),
|
||||
TEXTURE_3D(GL12.GL_TEXTURE_3D),
|
||||
TEXTURE_RECTANGLE(GL31.GL_TEXTURE_RECTANGLE);
|
||||
|
||||
private final int glType;
|
||||
|
||||
TextureType(int glType) {
|
||||
this.glType = glType;
|
||||
}
|
||||
|
||||
public static Optional<TextureType> fromString(String name) {
|
||||
try {
|
||||
return Optional.of(TextureType.valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public int getGlType() {
|
||||
return glType;
|
||||
}
|
||||
|
||||
public void apply(int texture, int sizeX, int sizeY, int sizeZ, int internalFormat, int format, int pixelType, ByteBuffer pixels) {
|
||||
switch (this) {
|
||||
case TEXTURE_1D -> RenderSystem.texImage1D(texture, glType, 0, internalFormat, sizeX, 0, format, pixelType, pixels);
|
||||
case TEXTURE_2D, TEXTURE_RECTANGLE -> RenderSystem.texImage2D(texture, glType, 0, internalFormat, sizeX, sizeY, 0, format, pixelType, pixels);
|
||||
case TEXTURE_3D -> RenderSystem.texImage3D(texture, glType, 0, internalFormat, sizeX, sizeY, sizeZ, 0, format, pixelType, pixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.coderbot.iris.gl.texture;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
public class TextureWrapper implements TextureAccess {
|
||||
private final IntSupplier texture;
|
||||
private final TextureType type;
|
||||
|
||||
public TextureWrapper(IntSupplier texture, TextureType type) {
|
||||
this.texture = texture;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntSupplier getTextureId() {
|
||||
return this.texture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.coderbot.iris.helpers;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public record Tri<X, Y, Z>(X first, Y second, Z third) {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof Tri tri)) return false;
|
||||
return Objects.equals(tri.first, this.first) && Objects.equals(tri.second, this.second) && Objects.equals(tri.third, this.third);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "First: " + first.toString() + " Second: " + second.toString() + " Third: " + third.toString();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ public class GbufferPrograms {
|
||||
public static void beginEntities() {
|
||||
checkReentrancy();
|
||||
setPhase(WorldRenderingPhase.ENTITIES);
|
||||
setBlockEntityDefaults();
|
||||
entities = true;
|
||||
}
|
||||
|
||||
@@ -52,6 +53,7 @@ public class GbufferPrograms {
|
||||
public static void beginBlockEntities() {
|
||||
checkReentrancy();
|
||||
setPhase(WorldRenderingPhase.BLOCK_ENTITIES);
|
||||
setBlockEntityDefaults();
|
||||
blockEntities = true;
|
||||
}
|
||||
|
||||
@@ -68,6 +70,7 @@ public class GbufferPrograms {
|
||||
GL20.glVertexAttrib2s(ProgramCreator.MC_ENTITY, (short)-1, (short)-1);
|
||||
GL20.glVertexAttrib2f(ProgramCreator.MC_MID_TEX_COORD, 0.5f, 0.5f);
|
||||
GL20.glVertexAttrib4f(ProgramCreator.AT_TANGENT, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
GL20.glVertexAttrib4f(ProgramCreator.AT_MIDBLOCK, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public static WorldRenderingPhase getCurrentPhase() {
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package net.coderbot.iris.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.EntityRendererAccessor;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.texture.GlTexture;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import net.coderbot.iris.gl.texture.TextureWrapper;
|
||||
import net.coderbot.iris.rendertarget.NativeImageBackedCustomTexture;
|
||||
import net.coderbot.iris.rendertarget.NativeImageBackedNoiseTexture;
|
||||
import net.coderbot.iris.shaderpack.PackDirectives;
|
||||
@@ -29,24 +35,25 @@ import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
public class CustomTextureManager {
|
||||
private final EnumMap<TextureStage, Object2ObjectMap<String, IntSupplier>> customTextureIdMap = new EnumMap<>(TextureStage.class);
|
||||
private final IntSupplier noise;
|
||||
@Getter private final EnumMap<TextureStage, Object2ObjectMap<String, TextureAccess>> customTextureIdMap = new EnumMap<>(TextureStage.class);
|
||||
@Getter private final Object2ObjectMap<String, TextureAccess> irisCustomTextures = new Object2ObjectOpenHashMap<>();
|
||||
private final TextureAccess noise;
|
||||
|
||||
/**
|
||||
* List of all OpenGL texture objects owned by this CustomTextureManager that need to be deleted in order to avoid
|
||||
* leaks.
|
||||
* List of all OpenGL texture objects owned by this CustomTextureManager that need to be deleted in order to avoid leaks.
|
||||
* Make sure any textures added to this list call releaseId from the close method.
|
||||
*/
|
||||
private final List<AbstractTexture> ownedTextures = new ArrayList<>();
|
||||
private final List<GlTexture> ownedRawTextures = new ArrayList<>();
|
||||
|
||||
public CustomTextureManager(PackDirectives packDirectives,
|
||||
EnumMap<TextureStage, Object2ObjectMap<String, CustomTextureData>> customTextureDataMap,
|
||||
Object2ObjectMap<String, CustomTextureData> irisCustomTextureDataMap,
|
||||
Optional<CustomTextureData> customNoiseTextureData) {
|
||||
customTextureDataMap.forEach((textureStage, customTextureStageDataMap) -> {
|
||||
Object2ObjectMap<String, IntSupplier> customTextureIds = new Object2ObjectOpenHashMap<>();
|
||||
final Object2ObjectMap<String, TextureAccess> customTextureIds = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
customTextureStageDataMap.forEach((samplerName, textureData) -> {
|
||||
try {
|
||||
@@ -60,6 +67,14 @@ public class CustomTextureManager {
|
||||
customTextureIdMap.put(textureStage, customTextureIds);
|
||||
});
|
||||
|
||||
irisCustomTextureDataMap.forEach((name, texture) -> {
|
||||
try {
|
||||
irisCustomTextures.put(name, createCustomTexture(texture));
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Unable to parse the image data for the custom texture on sampler " + name, e);
|
||||
}
|
||||
});
|
||||
|
||||
noise = customNoiseTextureData.flatMap(textureData -> {
|
||||
try {
|
||||
return Optional.of(createCustomTexture(textureData));
|
||||
@@ -71,75 +86,85 @@ public class CustomTextureManager {
|
||||
}).orElseGet(() -> {
|
||||
final int noiseTextureResolution = packDirectives.getNoiseTextureResolution();
|
||||
|
||||
AbstractTexture texture = new NativeImageBackedNoiseTexture(noiseTextureResolution);
|
||||
final AbstractTexture texture = new NativeImageBackedNoiseTexture(noiseTextureResolution);
|
||||
ownedTextures.add(texture);
|
||||
|
||||
return texture::getGlTextureId;
|
||||
return new TextureWrapper(texture::getGlTextureId, TextureType.TEXTURE_2D);
|
||||
});
|
||||
}
|
||||
|
||||
private IntSupplier createCustomTexture(CustomTextureData textureData) throws IOException {
|
||||
private TextureAccess createCustomTexture(CustomTextureData textureData) throws IOException {
|
||||
if (textureData instanceof CustomTextureData.PngData) {
|
||||
AbstractTexture texture = new NativeImageBackedCustomTexture((CustomTextureData.PngData) textureData);
|
||||
final AbstractTexture texture = new NativeImageBackedCustomTexture((CustomTextureData.PngData) textureData);
|
||||
ownedTextures.add(texture);
|
||||
|
||||
return texture::getGlTextureId;
|
||||
}
|
||||
// TODO: Iris
|
||||
// else if (textureData instanceof CustomTextureData.LightmapMarker) {
|
||||
// // Special code path for the light texture. While shader packs hardcode the primary light texture, it's
|
||||
// // possible that a mod will create a different light texture, so this code path is robust to that.
|
||||
// return () -> ((LightTextureAccessor) Minecraft.getMinecraft().gameRenderer.lightTexture()).getLightTexture().getId();
|
||||
// }
|
||||
else if (textureData instanceof CustomTextureData.ResourceData) {
|
||||
CustomTextureData.ResourceData resourceData = (CustomTextureData.ResourceData) textureData;
|
||||
String namespace = resourceData.getNamespace();
|
||||
return new TextureWrapper(texture::getGlTextureId, TextureType.TEXTURE_2D);
|
||||
} else if (textureData instanceof CustomTextureData.LightmapMarker) {
|
||||
// Special code path for the light texture. While shader packs hardcode the primary light texture, it's possible that a mod will
|
||||
// create a different light texture, so this code path is robust to that.
|
||||
return new TextureWrapper(() -> ((EntityRendererAccessor) Minecraft.getMinecraft().entityRenderer).getLightmapTexture().getGlTextureId(), TextureType.TEXTURE_2D);
|
||||
} else if (textureData instanceof CustomTextureData.RawData1D rawData) {
|
||||
final GlTexture texture = new GlTexture(TextureType.TEXTURE_1D, rawData.getSizeX(), 0, 0, rawData.getInternalFormat().getGlFormat(), rawData.getPixelFormat().getGlFormat(), rawData.getPixelType().getGlFormat(), rawData.getContent(), rawData.getFilteringData());
|
||||
ownedRawTextures.add(texture);
|
||||
return texture;
|
||||
} else if (textureData instanceof CustomTextureData.RawDataRect rawData) {
|
||||
final GlTexture texture = new GlTexture(TextureType.TEXTURE_RECTANGLE, rawData.getSizeX(), rawData.getSizeY(), 0, rawData.getInternalFormat().getGlFormat(), rawData.getPixelFormat().getGlFormat(), rawData.getPixelType().getGlFormat(), rawData.getContent(), rawData.getFilteringData());
|
||||
ownedRawTextures.add(texture);
|
||||
return texture;
|
||||
} else if (textureData instanceof CustomTextureData.RawData2D rawData) {
|
||||
final GlTexture texture = new GlTexture(TextureType.TEXTURE_2D, rawData.getSizeX(), rawData.getSizeY(), 0, rawData.getInternalFormat().getGlFormat(), rawData.getPixelFormat().getGlFormat(), rawData.getPixelType().getGlFormat(), rawData.getContent(), rawData.getFilteringData());
|
||||
ownedRawTextures.add(texture);
|
||||
return texture;
|
||||
} else if (textureData instanceof CustomTextureData.RawData3D rawData) {
|
||||
final GlTexture texture = new GlTexture(TextureType.TEXTURE_3D, rawData.getSizeX(), rawData.getSizeY(), rawData.getSizeZ(), rawData.getInternalFormat().getGlFormat(), rawData.getPixelFormat().getGlFormat(), rawData.getPixelType().getGlFormat(), rawData.getContent(), rawData.getFilteringData());
|
||||
ownedRawTextures.add(texture);
|
||||
return texture;
|
||||
} else if (textureData instanceof CustomTextureData.ResourceData resourceData) {
|
||||
final String namespace = resourceData.getNamespace();
|
||||
String location = resourceData.getLocation();
|
||||
|
||||
String withoutExtension;
|
||||
int extensionIndex = FilenameUtils.indexOfExtension(location);
|
||||
final String withoutExtension;
|
||||
final int extensionIndex = FilenameUtils.indexOfExtension(location);
|
||||
if (extensionIndex != -1) {
|
||||
withoutExtension = location.substring(0, extensionIndex);
|
||||
} else {
|
||||
withoutExtension = location;
|
||||
}
|
||||
PBRType pbrType = PBRType.fromFileLocation(withoutExtension);
|
||||
final PBRType pbrType = PBRType.fromFileLocation(withoutExtension);
|
||||
|
||||
TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
|
||||
final TextureManager textureManager = Minecraft.getMinecraft().getTextureManager();
|
||||
|
||||
if (pbrType == null) {
|
||||
ResourceLocation textureLocation = new ResourceLocation(namespace, location);
|
||||
final ResourceLocation textureLocation = new ResourceLocation(namespace, location);
|
||||
|
||||
// NB: We have to re-query the TextureManager for the texture object every time. This is because the
|
||||
// AbstractTexture object could be removed / deleted from the TextureManager on resource reloads,
|
||||
// and we could end up holding on to a deleted texture unless we added special code to handle resource
|
||||
// reloads. Re-fetching the texture from the TextureManager every time is the most robust approach for
|
||||
// now.
|
||||
return () -> {
|
||||
ITextureObject texture = textureManager.getTexture(textureLocation);
|
||||
|
||||
// TODO: Should we give something else if the texture isn't there? This will need some thought
|
||||
return new TextureWrapper(() -> {
|
||||
final ITextureObject texture = textureManager.getTexture(textureLocation);
|
||||
return texture != null ? texture.getGlTextureId() : TextureUtil.missingTexture.getGlTextureId();
|
||||
};
|
||||
}, TextureType.TEXTURE_2D);
|
||||
} else {
|
||||
location = location.substring(0, extensionIndex - pbrType.getSuffix().length()) + location.substring(extensionIndex);
|
||||
ResourceLocation textureLocation = new ResourceLocation(namespace, location);
|
||||
final ResourceLocation textureLocation = new ResourceLocation(namespace, location);
|
||||
|
||||
return () -> {
|
||||
ITextureObject texture = textureManager.getTexture(textureLocation);
|
||||
return new TextureWrapper(() -> {
|
||||
final ITextureObject texture = textureManager.getTexture(textureLocation);
|
||||
|
||||
if (texture != null) {
|
||||
int id = texture.getGlTextureId();
|
||||
PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id);
|
||||
AbstractTexture pbrTexture = switch (pbrType) {
|
||||
final int id = texture.getGlTextureId();
|
||||
final PBRTextureHolder pbrHolder = PBRTextureManager.INSTANCE.getOrLoadHolder(id);
|
||||
final AbstractTexture pbrTexture = switch (pbrType) {
|
||||
case NORMAL -> pbrHolder.getNormalTexture();
|
||||
case SPECULAR -> pbrHolder.getSpecularTexture();
|
||||
default -> throw new Error("Unknown PBRType '" + pbrType + "'");
|
||||
default -> throw new IllegalArgumentException("Unknown PBRType '" + pbrType + "'");
|
||||
};
|
||||
|
||||
TextureFormat textureFormat = TextureFormatLoader.getFormat();
|
||||
final TextureFormat textureFormat = TextureFormatLoader.getFormat();
|
||||
if (textureFormat != null) {
|
||||
int previousBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int previousBinding = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, pbrTexture.getGlTextureId());
|
||||
textureFormat.setupTextureParameters(pbrType, pbrTexture);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, previousBinding);
|
||||
@@ -148,29 +173,26 @@ public class CustomTextureManager {
|
||||
return pbrTexture.getGlTextureId();
|
||||
}
|
||||
|
||||
// return MissingTextureAtlasSprite.getTexture().getId();
|
||||
return TextureUtil.missingTexture.getGlTextureId();
|
||||
};
|
||||
}, TextureType.TEXTURE_2D);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to handle custom texture data " + textureData);
|
||||
}
|
||||
throw new IllegalArgumentException("Unable to handle custom texture data " + textureData);
|
||||
}
|
||||
|
||||
public EnumMap<TextureStage, Object2ObjectMap<String, IntSupplier>> getCustomTextureIdMap() {
|
||||
return customTextureIdMap;
|
||||
}
|
||||
|
||||
public Object2ObjectMap<String, IntSupplier> getCustomTextureIdMap(TextureStage stage) {
|
||||
public Object2ObjectMap<String, TextureAccess> getCustomTextureIdMap(TextureStage stage) {
|
||||
return customTextureIdMap.getOrDefault(stage, Object2ObjectMaps.emptyMap());
|
||||
}
|
||||
|
||||
public IntSupplier getNoiseTexture() {
|
||||
public TextureAccess getNoiseTexture() {
|
||||
return noise;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// TODO :Iris
|
||||
// ownedTextures.forEach(AbstractTexture::close);
|
||||
public void destroy() {
|
||||
ownedTextures.forEach(AbstractTexture::deleteGlTexture);
|
||||
ownedTextures.clear();
|
||||
|
||||
ownedRawTextures.forEach(GlTexture::destroy);
|
||||
ownedRawTextures.clear();
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,18 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder;
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.image.ImageInformation;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.block_rendering.BlockMaterialMapping;
|
||||
import net.coderbot.iris.celeritas.CeleritasTerrainPipeline;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable;
|
||||
@@ -131,6 +138,13 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
private final ImmutableSet<Integer> flippedAfterTranslucent;
|
||||
|
||||
private final CeleritasTerrainPipeline celeritasTerrainPipeline;
|
||||
private final DHCompat dhCompat;
|
||||
|
||||
// Custom images and SSBOs
|
||||
private final Set<GlImage> customImages;
|
||||
private final GlImage[] imagesToClear;
|
||||
@Nullable
|
||||
private final ShaderStorageBufferHolder ssboHolder;
|
||||
|
||||
private final Map<Pair<String, InputAvailability>, Map<PatchShaderType, String>> attributeTransforms;
|
||||
|
||||
@@ -194,7 +208,9 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
this.shouldRenderSun = programs.getPackDirectives().shouldRenderSun();
|
||||
this.shouldRenderMoon = programs.getPackDirectives().shouldRenderMoon();
|
||||
this.shouldWriteRainAndSnowToDepthBuffer = programs.getPackDirectives().rainDepth();
|
||||
this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().areParticlesBeforeDeferred();
|
||||
this.shouldRenderParticlesBeforeDeferred = programs.getPackDirectives().getParticleRenderingSettings()
|
||||
.map(s -> s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.BEFORE || s == net.coderbot.iris.shaderpack.ParticleRenderingSettings.MIXED)
|
||||
.orElse(false);
|
||||
this.allowConcurrentCompute = programs.getPackDirectives().getConcurrentCompute();
|
||||
this.shouldRenderPrepareBeforeShadow = programs.getPackDirectives().isPrepareBeforeShadow();
|
||||
this.oldLighting = programs.getPackDirectives().isOldLighting();
|
||||
@@ -246,10 +262,46 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
// Don't clobber anything in texture unit 0. It probably won't cause issues, but we're just being cautious here.
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
|
||||
customTextureManager = new CustomTextureManager(programs.getPackDirectives(), programs.getPack().getCustomTextureDataMap(), programs.getPack().getCustomNoiseTexture());
|
||||
customTextureManager = new CustomTextureManager(programs.getPackDirectives(), programs.getPack().getCustomTextureDataMap(), programs.getPack().getIrisCustomTextureDataMap(), programs.getPack().getCustomNoiseTexture());
|
||||
|
||||
whitePixel = new NativeImageBackedSingleColorTexture(255, 255, 255, 255);
|
||||
|
||||
// Initialize custom images
|
||||
this.customImages = new HashSet<>();
|
||||
final var customImageInfos = programs.getPack().getCustomImages();
|
||||
Iris.logger.debug("[CustomImages] Found {} custom image definitions from shader pack", customImageInfos.size());
|
||||
final List<GlImage> clearList = new ArrayList<>();
|
||||
for (var entry : customImageInfos.object2ObjectEntrySet()) {
|
||||
ImageInformation info = entry.getValue();
|
||||
Iris.logger.debug("[CustomImages] Creating GlImage: {} with info: {}", entry.getKey(), info);
|
||||
GlImage image;
|
||||
if (info.isRelative()) {
|
||||
image = new GlImage.Relative(info.name(), info.samplerName(), info.format(), info.internalTextureFormat(),
|
||||
info.type(), info.clear(), info.relativeWidth(), info.relativeHeight(),
|
||||
main.framebufferWidth, main.framebufferHeight);
|
||||
} else {
|
||||
image = new GlImage(info.name(), info.samplerName(), info.target(), info.format(), info.internalTextureFormat(),
|
||||
info.type(), info.clear(), info.width(), info.height(), info.depth());
|
||||
}
|
||||
Iris.logger.debug("[CustomImages] Created GlImage: {} with texture ID: {}", entry.getKey(), image.getId());
|
||||
customImages.add(image);
|
||||
if (image.shouldClear()) {
|
||||
clearList.add(image);
|
||||
}
|
||||
}
|
||||
this.imagesToClear = clearList.toArray(new GlImage[0]);
|
||||
Iris.logger.debug("[CustomImages] Total GlImages created: {}, images to clear: {}", customImages.size(), imagesToClear.length);
|
||||
|
||||
// Initialize SSBOs
|
||||
final var bufferObjectInfos = programs.getPack().getBufferObjects();
|
||||
if (!bufferObjectInfos.isEmpty() && RenderSystem.supportsSSBO()) {
|
||||
Int2ObjectArrayMap<ShaderStorageInfo> ssboOverrides = new Int2ObjectArrayMap<>();
|
||||
bufferObjectInfos.forEach(ssboOverrides::put);
|
||||
this.ssboHolder = new ShaderStorageBufferHolder(ssboOverrides, main.framebufferWidth, main.framebufferHeight);
|
||||
} else {
|
||||
this.ssboHolder = null;
|
||||
}
|
||||
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
|
||||
this.flippedBeforeShadow = ImmutableSet.of();
|
||||
@@ -270,9 +322,9 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
PatchedShaderPrinter.resetPrintState();
|
||||
|
||||
final ProgramBuildContext prepareBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.PREPARE), customUniforms);
|
||||
final ProgramBuildContext deferredBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.DEFERRED), customUniforms);
|
||||
final ProgramBuildContext compositeBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), customUniforms);
|
||||
final ProgramBuildContext prepareBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.PREPARE), customUniforms, customImages, customTextureManager.getIrisCustomTextures(), this);
|
||||
final ProgramBuildContext deferredBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.DEFERRED), customUniforms, customImages, customTextureManager.getIrisCustomTextures(), this);
|
||||
final ProgramBuildContext compositeBuildContext = new ProgramBuildContext(renderTargets, customTextureManager.getNoiseTexture(), updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureManager.getCustomTextureIdMap(TextureStage.COMPOSITE_AND_FINAL), customUniforms, customImages, customTextureManager.getIrisCustomTextures(), this);
|
||||
this.prepareRenderer = new CompositeRenderer(programs.getPrepare(), programs.getPrepareCompute(), flipper, prepareBuildContext, programs.getPackDirectives().getExplicitFlips("prepare_pre"), prepareTransformFutures, "prepare");
|
||||
|
||||
flippedAfterPrepare = flipper.snapshot();
|
||||
@@ -405,13 +457,18 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramSamplers.Builder builder = ProgramSamplers.builder(programId, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
|
||||
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW));
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this);
|
||||
IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true));
|
||||
IrisSamplers.addWorldDepthSamplers(customTextureSamplerInterceptor, renderTargets);
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture());
|
||||
|
||||
// Bind custom images as samplers (for texture() access to voxel_sampler, floodfill_sampler, etc.)
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
// Bind custom textures (PNG files from shader pack)
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures());
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets));
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets), null, true);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
@@ -421,9 +478,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramImages.Builder builder = ProgramImages.builder(programId);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, flipped, renderTargets);
|
||||
// Bind custom images as image units (for imageLoad/imageStore)
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
if (IrisImages.hasShadowImages(builder)) {
|
||||
IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets));
|
||||
IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets), null);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
@@ -433,13 +492,18 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramSamplers.Builder builder = ProgramSamplers.builder(programId, IrisSamplers.WORLD_RESERVED_TEXTURE_UNITS);
|
||||
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(TextureStage.GBUFFERS_AND_SHADOW));
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flippedAfterPrepare, renderTargets, false);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flippedAfterPrepare, renderTargets, false, this);
|
||||
IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true));
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, customTextureManager.getNoiseTexture());
|
||||
|
||||
// Bind custom images as samplers (for texture() access to voxel_sampler, floodfill_sampler, etc.)
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
// Bind custom textures (PNG files from shader pack)
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, customTextureManager.getIrisCustomTextures());
|
||||
|
||||
// Only initialize these samplers if the shadow map renderer exists. Otherwise, this program shouldn't be used at all?
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets));
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, Objects.requireNonNull(shadowRenderTargets), null, true);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
@@ -448,9 +512,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramImages.Builder builder = ProgramImages.builder(programId);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, () -> flippedAfterPrepare, renderTargets);
|
||||
// Bind custom images as image units (for imageLoad/imageStore - voxelization uses this in shadow pass)
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
if (IrisImages.hasShadowImages(builder)) {
|
||||
IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets));
|
||||
IrisImages.addShadowColorImages(builder, Objects.requireNonNull(shadowRenderTargets), null);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
@@ -471,6 +537,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
celeritasTerrainFuture, celeritasTranslucentFuture, celeritasShadowFuture,
|
||||
renderTargets, flippedAfterPrepare, flippedAfterTranslucent,
|
||||
celeritasShadowFb, celeritasTerrainDrawBuffers);
|
||||
|
||||
this.dhCompat = new DHCompat();
|
||||
}
|
||||
|
||||
private RenderTargets getRenderTargets() {
|
||||
@@ -674,7 +742,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramSamplers.customTextureSamplerInterceptor(builder,
|
||||
customTextureManager.getCustomTextureIdMap(textureStage));
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this);
|
||||
IrisImages.addRenderTargetImages(builder, flipped, renderTargets);
|
||||
|
||||
if (!shouldBindPBR) {
|
||||
@@ -695,8 +763,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
|
||||
if (shadowRenderTargets != null) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets);
|
||||
IrisImages.addShadowColorImages(builder, shadowRenderTargets);
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets, null, true);
|
||||
IrisImages.addShadowColorImages(builder, shadowRenderTargets, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -890,6 +958,17 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
// Destroy custom textures and the static samplers (normals, specular, and noise)
|
||||
customTextureManager.destroy();
|
||||
// whitePixel.releaseId();
|
||||
|
||||
// Destroy custom images
|
||||
for (GlImage image : customImages) {
|
||||
image.destroy();
|
||||
}
|
||||
customImages.clear();
|
||||
|
||||
// Destroy SSBOs
|
||||
if (ssboHolder != null) {
|
||||
ssboHolder.destroyBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
private static void destroyPasses(ProgramTable<Pass> table) {
|
||||
@@ -974,6 +1053,16 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
this.clearPassesFull = ClearPassCreator.createClearPasses(renderTargets, true, packDirectives.getRenderTargetDirectives());
|
||||
this.clearPasses = ClearPassCreator.createClearPasses(renderTargets, false, packDirectives.getRenderTargetDirectives());
|
||||
|
||||
// Resize custom images if needed
|
||||
for (GlImage image : customImages) {
|
||||
image.updateNewSize(main.framebufferWidth, main.framebufferHeight);
|
||||
}
|
||||
|
||||
// Resize SSBOs if needed
|
||||
if (ssboHolder != null) {
|
||||
ssboHolder.hasResizedScreen(main.framebufferWidth, main.framebufferHeight);
|
||||
}
|
||||
}
|
||||
|
||||
final ImmutableList<ClearPass> passes;
|
||||
@@ -1027,7 +1116,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor =
|
||||
ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureManager.getCustomTextureIdMap(textureStage));
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, flipped, renderTargets, false, this);
|
||||
IrisImages.addRenderTargetImages(builder, flipped, renderTargets);
|
||||
|
||||
IrisSamplers.addLevelSamplers(customTextureSamplerInterceptor, this, whitePixel, new InputAvailability(true, true));
|
||||
@@ -1036,8 +1125,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
if (shadowRenderTargets != null) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets);
|
||||
IrisImages.addShadowColorImages(builder, shadowRenderTargets);
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowRenderTargets, null, true);
|
||||
IrisImages.addShadowColorImages(builder, shadowRenderTargets, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,7 +1134,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
this.customUniforms.mapholderToPass(builder, programs[i]);
|
||||
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups());
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups(), null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1170,6 +1259,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
// Get ready for world rendering
|
||||
prepareRenderTargets();
|
||||
|
||||
// Clear custom images that need clearing each frame
|
||||
for (GlImage image : imagesToClear) {
|
||||
image.clear();
|
||||
}
|
||||
|
||||
setPhase(WorldRenderingPhase.SKY);
|
||||
|
||||
// Render our horizon box before actual sky rendering to avoid being broken by mods that do weird things
|
||||
@@ -1227,6 +1321,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
return updateNotifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DHCompat getDHCompat() {
|
||||
return dhCompat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldRenderingPhase getPhase() {
|
||||
if (overridePhase != null) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.coderbot.iris.pipeline;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.celeritas.CeleritasTerrainPipeline;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener;
|
||||
@@ -123,6 +124,13 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli
|
||||
return new FrameUpdateNotifier();
|
||||
}
|
||||
|
||||
private static final DHCompat DH_COMPAT = new DHCompat();
|
||||
|
||||
@Override
|
||||
public DHCompat getDHCompat() {
|
||||
return DH_COMPAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableVanillaEntityShadows() {
|
||||
return false;
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.gtnewhorizons.angelica.compat.toremove.RenderLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -114,6 +115,8 @@ public class HandRenderer {
|
||||
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
renderingSolid = true;
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
@@ -151,6 +154,8 @@ public class HandRenderer {
|
||||
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
mc.entityRenderer.disableLightmap(tickDelta);
|
||||
|
||||
@@ -17,8 +17,8 @@ import java.util.Objects;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.gui.option.IrisVideoSettings;
|
||||
import net.coderbot.iris.shaderpack.OptionalBoolean;
|
||||
import net.coderbot.iris.shaderpack.PackDirectives;
|
||||
import net.coderbot.iris.shaderpack.ShadowCullState;
|
||||
import net.coderbot.iris.shaderpack.PackShadowDirectives;
|
||||
import net.coderbot.iris.shaderpack.ProgramSource;
|
||||
import net.coderbot.iris.shadow.ShadowMatrices;
|
||||
@@ -79,7 +79,7 @@ public class ShadowRenderer {
|
||||
private final float intervalSize;
|
||||
private final Float fov;
|
||||
private final ShadowRenderTargets targets;
|
||||
private final OptionalBoolean packCullingState;
|
||||
private final ShadowCullState packCullingState;
|
||||
private boolean packHasVoxelization;
|
||||
private final boolean shouldRenderTerrain;
|
||||
private final boolean shouldRenderTranslucent;
|
||||
@@ -141,7 +141,7 @@ public class ShadowRenderer {
|
||||
this.packCullingState = shadowDirectives.getCullingState();
|
||||
} else {
|
||||
this.packHasVoxelization = false;
|
||||
this.packCullingState = OptionalBoolean.DEFAULT;
|
||||
this.packCullingState = ShadowCullState.DEFAULT;
|
||||
}
|
||||
|
||||
this.sunPathRotation = directives.getSunPathRotation();
|
||||
@@ -286,12 +286,12 @@ public class ShadowRenderer {
|
||||
// TODO: Cull entities / block entities with Advanced Frustum Culling even if voxelization is detected.
|
||||
String distanceInfo;
|
||||
String cullingInfo;
|
||||
if ((packCullingState == OptionalBoolean.FALSE || packHasVoxelization) && packCullingState != OptionalBoolean.TRUE) {
|
||||
if ((packCullingState == ShadowCullState.DISTANCE || packHasVoxelization) && packCullingState != ShadowCullState.ADVANCED) {
|
||||
double distance = halfPlaneLength * renderMultiplier;
|
||||
|
||||
String reason;
|
||||
|
||||
if (packCullingState == OptionalBoolean.FALSE) {
|
||||
if (packCullingState == ShadowCullState.DISTANCE) {
|
||||
reason = "(set by shader pack)";
|
||||
} else /*if (packHasVoxelization)*/ {
|
||||
reason = "(voxelization detected)";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener;
|
||||
@@ -39,6 +40,7 @@ public interface WorldRenderingPipeline {
|
||||
|
||||
CeleritasTerrainPipeline getCeleritasTerrainPipeline();
|
||||
FrameUpdateNotifier getFrameUpdateNotifier();
|
||||
DHCompat getDHCompat();
|
||||
|
||||
boolean shouldDisableVanillaEntityShadows();
|
||||
boolean shouldDisableDirectionalShading();
|
||||
|
||||
@@ -204,8 +204,12 @@ public class ShaderTransformer {
|
||||
hacky120Patches.add(transformer);
|
||||
}
|
||||
|
||||
// Extract extensions from the pre-parsed content (version + extensions before main code)
|
||||
// This preserves #extension directives that the shader pack declares
|
||||
var extensions = versionPattern.matcher(getFormattedShader(parsedShader.pre(), "")).replaceFirst("").trim();
|
||||
|
||||
types.put(type, transformer);
|
||||
prepatched.put(type, profileString);
|
||||
prepatched.put(type, profileString + (extensions.isEmpty() ? "" : "\n" + extensions));
|
||||
}
|
||||
CompatibilityTransformer.transformGrouped(types, parameters);
|
||||
for (var entry : types.entrySet()) {
|
||||
@@ -394,8 +398,10 @@ public class ShaderTransformer {
|
||||
stringBuilder.deleteCharAt(stringBuilder.length() - 2);
|
||||
}
|
||||
tabHolder[0] = "";
|
||||
stringBuilder.append(" \n");
|
||||
} else {
|
||||
stringBuilder.append(text.equals(";") ? " \n" + tabHolder[0] : " ");
|
||||
}
|
||||
stringBuilder.append(text.equals(";") ? " \n" + tabHolder[0] : " ");
|
||||
} else {
|
||||
for (int i = 0; i < tree.getChildCount(); ++i) {
|
||||
getFormattedShader(tree.getChild(i), stringBuilder, tabHolder);
|
||||
|
||||
@@ -8,13 +8,17 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
|
||||
import net.coderbot.iris.gl.framebuffer.ViewportData;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.program.ComputeProgram;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.coderbot.iris.gl.program.ProgramSamplers;
|
||||
import net.coderbot.iris.gl.program.ProgramUniforms;
|
||||
import net.coderbot.iris.gl.sampler.SamplerLimits;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.transform.PatchShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.TransformPatcher;
|
||||
import net.coderbot.iris.rendertarget.RenderTarget;
|
||||
@@ -32,6 +36,7 @@ import net.coderbot.iris.uniforms.custom.CustomUniforms;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
@@ -39,31 +44,34 @@ import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CompositeRenderer {
|
||||
private final RenderTargets renderTargets;
|
||||
|
||||
private final ImmutableList<Pass> passes;
|
||||
private final IntSupplier noiseTexture;
|
||||
private final TextureAccess noiseTexture;
|
||||
private final FrameUpdateNotifier updateNotifier;
|
||||
private final CenterDepthSampler centerDepthSampler;
|
||||
private final CustomUniforms customUniforms;
|
||||
private final Object2ObjectMap<String, IntSupplier> customTextureIds;
|
||||
private final Object2ObjectMap<String, TextureAccess> customTextureIds;
|
||||
@Nullable private final Set<GlImage> customImages;
|
||||
@Nullable private final Object2ObjectMap<String, TextureAccess> irisCustomTextures;
|
||||
@Nullable private final WorldRenderingPipeline pipeline;
|
||||
@Getter
|
||||
private final ImmutableSet<Integer> flippedAtLeastOnceFinal;
|
||||
|
||||
public CompositeRenderer(PackDirectives packDirectives, ProgramSource[] sources, ComputeSource[][] computes, RenderTargets renderTargets,
|
||||
IntSupplier noiseTexture, FrameUpdateNotifier updateNotifier,
|
||||
TextureAccess noiseTexture, FrameUpdateNotifier updateNotifier,
|
||||
CenterDepthSampler centerDepthSampler, BufferFlipper bufferFlipper,
|
||||
Supplier<ShadowRenderTargets> shadowTargetsSupplier,
|
||||
Object2ObjectMap<String, IntSupplier> customTextureIds, ImmutableMap<Integer, Boolean> explicitPreFlips,
|
||||
Object2ObjectMap<String, TextureAccess> customTextureIds, ImmutableMap<Integer, Boolean> explicitPreFlips,
|
||||
CustomUniforms customUniforms,
|
||||
Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> precomputedTransformFutures) {
|
||||
this(sources, computes, bufferFlipper, new ProgramBuildContext(renderTargets, noiseTexture, updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureIds, customUniforms), explicitPreFlips, precomputedTransformFutures, "unknown");
|
||||
this(sources, computes, bufferFlipper, new ProgramBuildContext(renderTargets, noiseTexture, updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureIds, customUniforms, null, null, null), explicitPreFlips, precomputedTransformFutures, "unknown");
|
||||
}
|
||||
|
||||
public CompositeRenderer(ProgramSource[] sources, ComputeSource[][] computes, BufferFlipper bufferFlipper, ProgramBuildContext context, ImmutableMap<Integer, Boolean> explicitPreFlips, Map<Integer, CompletableFuture<Map<PatchShaderType, String>>> precomputedTransformFutures, String stageName) {
|
||||
@@ -73,6 +81,9 @@ public class CompositeRenderer {
|
||||
this.renderTargets = context.renderTargets();
|
||||
this.customTextureIds = context.customTextureIds();
|
||||
this.customUniforms = context.customUniforms();
|
||||
this.customImages = context.customImages();
|
||||
this.irisCustomTextures = context.irisCustomTextures();
|
||||
this.pipeline = context.pipeline();
|
||||
|
||||
final ImmutableList.Builder<Pass> passes = ImmutableList.builder();
|
||||
final ImmutableSet.Builder<Integer> flippedAtLeastOnce = new ImmutableSet.Builder<>();
|
||||
@@ -205,7 +216,7 @@ public class CompositeRenderer {
|
||||
GlFramebuffer framebuffer;
|
||||
ImmutableSet<Integer> stageReadsFromAlt;
|
||||
ImmutableSet<Integer> mipmappedBuffers;
|
||||
float viewportScale;
|
||||
ViewportData viewportScale;
|
||||
|
||||
protected void destroy() {
|
||||
this.program.destroy();
|
||||
@@ -264,9 +275,11 @@ public class CompositeRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
final float scaledWidth = renderPass.viewWidth * renderPass.viewportScale;
|
||||
final float scaledHeight = renderPass.viewHeight * renderPass.viewportScale;
|
||||
GL11.glViewport(0, 0, (int) scaledWidth, (int) scaledHeight);
|
||||
final float scaledWidth = renderPass.viewWidth * renderPass.viewportScale.scale();
|
||||
final float scaledHeight = renderPass.viewHeight * renderPass.viewportScale.scale();
|
||||
final float viewportX = renderPass.viewWidth * renderPass.viewportScale.viewportX();
|
||||
final float viewportY = renderPass.viewHeight * renderPass.viewportScale.viewportY();
|
||||
GL11.glViewport((int) viewportX, (int) viewportY, (int) scaledWidth, (int) scaledHeight);
|
||||
|
||||
renderPass.framebuffer.bind();
|
||||
renderPass.program.use();
|
||||
@@ -345,15 +358,19 @@ public class CompositeRenderer {
|
||||
|
||||
ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot);
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true, pipeline);
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, irisCustomTextures);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets);
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture);
|
||||
IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets);
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get());
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get());
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, false);
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get(), null);
|
||||
}
|
||||
|
||||
// TODO: Don't duplicate this with FinalPassRenderer
|
||||
@@ -390,15 +407,19 @@ public class CompositeRenderer {
|
||||
|
||||
this.customUniforms.assignTo(builder);
|
||||
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true, pipeline);
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, irisCustomTextures);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets);
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture);
|
||||
IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets);
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get());
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get());
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, false);
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get(), null);
|
||||
}
|
||||
|
||||
// TODO: Don't duplicate this with FinalPassRenderer
|
||||
@@ -408,7 +429,7 @@ public class CompositeRenderer {
|
||||
|
||||
customUniforms.mapholderToPass(builder, programs[i]);
|
||||
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups());
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@ import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.program.ComputeProgram;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.coderbot.iris.gl.program.ProgramSamplers;
|
||||
import net.coderbot.iris.gl.program.ProgramUniforms;
|
||||
import net.coderbot.iris.gl.sampler.SamplerLimits;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.transform.PatchShaderType;
|
||||
import net.coderbot.iris.pipeline.transform.TransformPatcher;
|
||||
import net.coderbot.iris.rendertarget.IRenderTargetExt;
|
||||
@@ -40,9 +43,9 @@ import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class FinalPassRenderer {
|
||||
@@ -55,20 +58,23 @@ public class FinalPassRenderer {
|
||||
private final GlFramebuffer colorHolder;
|
||||
private int lastColorTextureId;
|
||||
private int lastColorTextureVersion;
|
||||
private final IntSupplier noiseTexture;
|
||||
private final TextureAccess noiseTexture;
|
||||
private final FrameUpdateNotifier updateNotifier;
|
||||
private final CenterDepthSampler centerDepthSampler;
|
||||
private final Object2ObjectMap<String, IntSupplier> customTextureIds;
|
||||
private final Object2ObjectMap<String, TextureAccess> customTextureIds;
|
||||
private final CustomUniforms customUniforms;
|
||||
@Nullable private final Set<GlImage> customImages;
|
||||
@Nullable private final Object2ObjectMap<String, TextureAccess> irisCustomTextures;
|
||||
@Nullable private final WorldRenderingPipeline pipeline;
|
||||
|
||||
public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, IntSupplier noiseTexture,
|
||||
public FinalPassRenderer(ProgramSet pack, RenderTargets renderTargets, TextureAccess noiseTexture,
|
||||
FrameUpdateNotifier updateNotifier, ImmutableSet<Integer> flippedBuffers,
|
||||
CenterDepthSampler centerDepthSampler,
|
||||
Supplier<ShadowRenderTargets> shadowTargetsSupplier,
|
||||
Object2ObjectMap<String, IntSupplier> customTextureIds,
|
||||
Object2ObjectMap<String, TextureAccess> customTextureIds,
|
||||
ImmutableSet<Integer> flippedAtLeastOnce, CustomUniforms customUniforms,
|
||||
CompletableFuture<Map<PatchShaderType, String>> precomputedTransformFuture) {
|
||||
this(pack, new ProgramBuildContext(renderTargets, noiseTexture, updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureIds, customUniforms), flippedBuffers, flippedAtLeastOnce, precomputedTransformFuture, "final");
|
||||
this(pack, new ProgramBuildContext(renderTargets, noiseTexture, updateNotifier, centerDepthSampler, shadowTargetsSupplier, customTextureIds, customUniforms, null, null, null), flippedBuffers, flippedAtLeastOnce, precomputedTransformFuture, "final");
|
||||
}
|
||||
|
||||
public FinalPassRenderer(ProgramSet pack, ProgramBuildContext context, ImmutableSet<Integer> flippedBuffers, ImmutableSet<Integer> flippedAtLeastOnce, CompletableFuture<Map<PatchShaderType, String>> precomputedTransformFuture, String stageName) {
|
||||
@@ -79,6 +85,9 @@ public class FinalPassRenderer {
|
||||
this.noiseTexture = context.noiseTexture();
|
||||
this.renderTargets = context.renderTargets();
|
||||
this.customUniforms = context.customUniforms();
|
||||
this.customImages = context.customImages();
|
||||
this.irisCustomTextures = context.irisCustomTextures();
|
||||
this.pipeline = context.pipeline();
|
||||
this.finalPass = pack.getCompositeFinal().filter(ProgramSource::isValid).map(source -> {
|
||||
final Pass pass = new Pass();
|
||||
final ProgramDirectives directives = source.getDirectives();
|
||||
@@ -359,14 +368,22 @@ public class FinalPassRenderer {
|
||||
final ProgramSamplers.CustomTextureSamplerInterceptor customTextureSamplerInterceptor = ProgramSamplers.customTextureSamplerInterceptor(builder, customTextureIds, flippedAtLeastOnceSnapshot);
|
||||
|
||||
CommonUniforms.addDynamicUniforms(builder);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true, pipeline);
|
||||
// Bind custom images as samplers BEFORE render target images
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
// Bind custom textures (PNG files from shader pack)
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, irisCustomTextures);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets);
|
||||
// Bind custom images as image units AFTER render target images
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture);
|
||||
IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets);
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get());
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get());
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, false);
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get(), null);
|
||||
}
|
||||
|
||||
// TODO: Don't duplicate this with CompositeRenderer
|
||||
@@ -402,15 +419,19 @@ public class FinalPassRenderer {
|
||||
customUniforms.assignTo(builder);
|
||||
|
||||
CommonUniforms.addDynamicUniforms(builder);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true);
|
||||
IrisSamplers.addRenderTargetSamplers(customTextureSamplerInterceptor, () -> flipped, renderTargets, true, pipeline);
|
||||
IrisSamplers.addCustomImages(customTextureSamplerInterceptor, customImages);
|
||||
IrisSamplers.addCustomTextures(customTextureSamplerInterceptor, irisCustomTextures);
|
||||
|
||||
IrisImages.addRenderTargetImages(builder, () -> flipped, renderTargets);
|
||||
IrisImages.addCustomImages(builder, customImages);
|
||||
|
||||
IrisSamplers.addNoiseSampler(customTextureSamplerInterceptor, noiseTexture);
|
||||
IrisSamplers.addCompositeSamplers(customTextureSamplerInterceptor, renderTargets);
|
||||
|
||||
if (IrisSamplers.hasShadowSamplers(customTextureSamplerInterceptor)) {
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get());
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get());
|
||||
IrisSamplers.addShadowSamplers(customTextureSamplerInterceptor, shadowTargetsSupplier.get(), null, false);
|
||||
IrisImages.addShadowColorImages(builder, shadowTargetsSupplier.get(), null);
|
||||
}
|
||||
|
||||
// TODO: Don't duplicate this with FinalPassRenderer
|
||||
@@ -420,7 +441,7 @@ public class FinalPassRenderer {
|
||||
|
||||
this.customUniforms.mapholderToPass(builder, programs[i]);
|
||||
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups());
|
||||
programs[i].setWorkGroupInfo(source.getWorkGroupRelative(), source.getWorkGroups(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,22 +2,29 @@ package net.coderbot.iris.postprocess;
|
||||
|
||||
import com.github.bsideup.jabel.Desugar;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.rendertarget.RenderTargets;
|
||||
import net.coderbot.iris.shadows.ShadowRenderTargets;
|
||||
import net.coderbot.iris.uniforms.FrameUpdateNotifier;
|
||||
import net.coderbot.iris.uniforms.custom.CustomUniforms;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Desugar
|
||||
public record ProgramBuildContext(
|
||||
@NotNull RenderTargets renderTargets,
|
||||
@NotNull IntSupplier noiseTexture,
|
||||
@NotNull TextureAccess noiseTexture,
|
||||
@NotNull FrameUpdateNotifier updateNotifier,
|
||||
@NotNull CenterDepthSampler centerDepthSampler,
|
||||
@NotNull Supplier<ShadowRenderTargets> shadowTargetsSupplier,
|
||||
@NotNull Object2ObjectMap<String, IntSupplier> customTextureIds,
|
||||
@NotNull CustomUniforms customUniforms
|
||||
@NotNull Object2ObjectMap<String, TextureAccess> customTextureIds,
|
||||
@NotNull CustomUniforms customUniforms,
|
||||
@Nullable Set<GlImage> customImages,
|
||||
@Nullable Object2ObjectMap<String, TextureAccess> irisCustomTextures,
|
||||
@Nullable WorldRenderingPipeline pipeline
|
||||
) {}
|
||||
@@ -1,12 +1,14 @@
|
||||
package net.coderbot.iris.samplers;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.image.ImageHolder;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.rendertarget.RenderTarget;
|
||||
import net.coderbot.iris.rendertarget.RenderTargets;
|
||||
import net.coderbot.iris.shadows.ShadowRenderTargets;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -16,10 +18,14 @@ public class IrisImages {
|
||||
for (int i = 0; i < renderTargets.getRenderTargetCount(); i++) {
|
||||
final int index = i;
|
||||
|
||||
final String name = "colorimg" + i;
|
||||
|
||||
if (!images.hasImage(name)) continue;
|
||||
|
||||
// Note: image bindings *are* impacted by buffer flips.
|
||||
IntSupplier textureID = () -> {
|
||||
ImmutableSet<Integer> flippedBuffers = flipped.get();
|
||||
RenderTarget target = renderTargets.get(index);
|
||||
final IntSupplier textureID = () -> {
|
||||
final ImmutableSet<Integer> flippedBuffers = flipped.get();
|
||||
final RenderTarget target = renderTargets.get(index);
|
||||
|
||||
if (flippedBuffers.contains(index)) {
|
||||
return target.getAltTexture();
|
||||
@@ -29,7 +35,6 @@ public class IrisImages {
|
||||
};
|
||||
|
||||
final InternalTextureFormat internalFormat = renderTargets.get(i).getInternalFormat();
|
||||
final String name = "colorimg" + i;
|
||||
|
||||
images.addTextureImage(textureID, internalFormat, name);
|
||||
}
|
||||
@@ -37,17 +42,43 @@ public class IrisImages {
|
||||
|
||||
public static boolean hasShadowImages(ImageHolder images) {
|
||||
// TODO: Generalize
|
||||
if (images == null) {
|
||||
return false;
|
||||
}
|
||||
return images.hasImage("shadowcolorimg0") || images.hasImage("shadowcolorimg1");
|
||||
}
|
||||
|
||||
public static void addShadowColorImages(ImageHolder images, ShadowRenderTargets shadowRenderTargets) {
|
||||
public static boolean hasRenderTargetImages(ImageHolder images, RenderTargets targets) {
|
||||
for (int i = 0; i < targets.getRenderTargetCount(); i++) {
|
||||
if (images != null && images.hasImage("colorimg" + i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void addShadowColorImages(ImageHolder images, ShadowRenderTargets shadowRenderTargets, ImmutableSet<Integer> flipped) {
|
||||
if (images == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < shadowRenderTargets.getNumColorTextures(); i++) {
|
||||
final int index = i;
|
||||
|
||||
IntSupplier textureID = () -> shadowRenderTargets.getColorTextureId(index);
|
||||
IntSupplier textureID;
|
||||
if (flipped == null) {
|
||||
textureID = () -> shadowRenderTargets.getColorTextureId(index);
|
||||
} else {
|
||||
textureID = () -> flipped.contains(index) ? shadowRenderTargets.get(index).getAltTexture() : shadowRenderTargets.get(index).getMainTexture();
|
||||
}
|
||||
InternalTextureFormat format = shadowRenderTargets.getColorTextureFormat(index);
|
||||
|
||||
images.addTextureImage(textureID, format, "shadowcolorimg" + i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addCustomImages(ImageHolder images, Set<GlImage> customImages) {
|
||||
customImages.forEach(image -> {
|
||||
images.addTextureImage(image::getId, image.getInternalFormat(), image.getName());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,24 @@ package net.coderbot.iris.samplers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.gl.image.GlImage;
|
||||
import net.coderbot.iris.gl.sampler.GlSampler;
|
||||
import net.coderbot.iris.gl.sampler.SamplerHolder;
|
||||
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
|
||||
import net.coderbot.iris.gl.texture.TextureAccess;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.rendertarget.RenderTarget;
|
||||
import net.coderbot.iris.rendertarget.RenderTargets;
|
||||
import net.coderbot.iris.shaderpack.PackRenderTargetDirectives;
|
||||
import net.coderbot.iris.shaderpack.PackShadowDirectives;
|
||||
import net.coderbot.iris.shadows.ShadowRenderTargets;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -25,22 +33,35 @@ public class IrisSamplers {
|
||||
// We need a way to restore these texture bindings.
|
||||
public static final ImmutableSet<Integer> COMPOSITE_RESERVED_TEXTURE_UNITS = ImmutableSet.of(1);
|
||||
|
||||
private static GlSampler SHADOW_SAMPLER_NEAREST;
|
||||
private static GlSampler SHADOW_SAMPLER_LINEAR;
|
||||
|
||||
private IrisSamplers() {
|
||||
// no construction allowed
|
||||
}
|
||||
|
||||
public static void initRenderer() {
|
||||
if (!RenderSystem.supportsSamplerObjects()) {
|
||||
// Leave as null - callers handle null gracefully
|
||||
return;
|
||||
}
|
||||
SHADOW_SAMPLER_NEAREST = new GlSampler(false, false, true, true);
|
||||
SHADOW_SAMPLER_LINEAR = new GlSampler(true, false, true, true);
|
||||
}
|
||||
|
||||
public static void addRenderTargetSamplers(SamplerHolder samplers, Supplier<ImmutableSet<Integer>> flipped,
|
||||
RenderTargets renderTargets, boolean isFullscreenPass) {
|
||||
RenderTargets renderTargets, boolean isFullscreenPass,
|
||||
WorldRenderingPipeline pipeline) {
|
||||
// colortex0,1,2,3 are only able to be sampled from fullscreen passes.
|
||||
// Iris could lift this restriction, though I'm not sure if it could cause issues.
|
||||
int startIndex = isFullscreenPass ? 0 : 4;
|
||||
final int startIndex = isFullscreenPass ? 0 : 4;
|
||||
|
||||
for (int i = startIndex; i < renderTargets.getRenderTargetCount(); i++) {
|
||||
final int index = i;
|
||||
|
||||
IntSupplier sampler = () -> {
|
||||
ImmutableSet<Integer> flippedBuffers = flipped.get();
|
||||
RenderTarget target = renderTargets.get(index);
|
||||
final IntSupplier texture = () -> {
|
||||
final ImmutableSet<Integer> flippedBuffers = flipped.get();
|
||||
final RenderTarget target = renderTargets.get(index);
|
||||
|
||||
if (flippedBuffers.contains(index)) {
|
||||
return target.getAltTexture();
|
||||
@@ -54,32 +75,43 @@ public class IrisSamplers {
|
||||
// TODO: How do custom textures interact with aliases?
|
||||
|
||||
if (i < PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.size()) {
|
||||
String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(i);
|
||||
final String legacyName = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS.get(i);
|
||||
|
||||
// colortex0 is the default sampler in fullscreen passes
|
||||
if (i == 0 && isFullscreenPass) {
|
||||
samplers.addDefaultSampler(sampler, name, legacyName);
|
||||
samplers.addDefaultSampler(texture, name, legacyName);
|
||||
} else {
|
||||
samplers.addDynamicSampler(sampler, name, legacyName);
|
||||
samplers.addDynamicSampler(texture, name, legacyName);
|
||||
}
|
||||
} else {
|
||||
samplers.addDynamicSampler(sampler, name);
|
||||
samplers.addDynamicSampler(texture, name);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the DH depth textures (stub implementation returns 0 until DH is integrated)
|
||||
if (pipeline != null) {
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, () -> pipeline.getDHCompat().getDepthTex(), (GlSampler) null, "dhDepthTex", "dhDepthTex0");
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, () -> pipeline.getDHCompat().getDepthTexNoTranslucent(), (GlSampler) null, "dhDepthTex1");
|
||||
}
|
||||
}
|
||||
|
||||
public static void addNoiseSampler(SamplerHolder samplers, IntSupplier sampler) {
|
||||
samplers.addDynamicSampler(sampler, "noisetex");
|
||||
public static void addNoiseSampler(SamplerHolder samplers, TextureAccess sampler) {
|
||||
samplers.addDynamicSampler(sampler.getTextureId(), "noisetex");
|
||||
}
|
||||
|
||||
public static boolean hasShadowSamplers(SamplerHolder samplers) {
|
||||
// TODO: Keep this up to date with the actual definitions.
|
||||
// TODO: Don't query image presence using the sampler interface even though the current underlying implementation
|
||||
// is the same.
|
||||
ImmutableList<String> shadowSamplers = ImmutableList.of("shadowtex0", "shadowtex0HW", "shadowtex1", "shadowtex1HW", "shadow", "watershadow",
|
||||
"shadowcolor", "shadowcolor0", "shadowcolor1", "shadowcolorimg0", "shadowcolorimg1");
|
||||
final ImmutableList.Builder<String> shadowSamplers = ImmutableList.<String>builder()
|
||||
.add("shadowtex0", "shadowtex0HW", "shadowtex0DH", "shadowtex1", "shadowtex1HW", "shadowtex1DH", "shadow", "watershadow", "shadowcolor");
|
||||
|
||||
for (String samplerName : shadowSamplers) {
|
||||
for (int i = 0; i < PackShadowDirectives.MAX_SHADOW_COLOR_BUFFERS; i++) {
|
||||
shadowSamplers.add("shadowcolor" + i);
|
||||
shadowSamplers.add("shadowcolorimg" + i);
|
||||
}
|
||||
|
||||
for (String samplerName : shadowSamplers.build()) {
|
||||
if (samplers.hasSampler(samplerName)) {
|
||||
return true;
|
||||
}
|
||||
@@ -88,31 +120,61 @@ public class IrisSamplers {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean addShadowSamplers(SamplerHolder samplers, ShadowRenderTargets shadowRenderTargets) {
|
||||
public static boolean addShadowSamplers(SamplerHolder samplers, ShadowRenderTargets shadowRenderTargets, ImmutableSet<Integer> flipped, boolean separateHardwareSamplers) {
|
||||
boolean usesShadows;
|
||||
|
||||
// TODO: figure this out from parsing the shader source code to be 100% compatible with the legacy
|
||||
// shader packs that rely on this behavior.
|
||||
boolean waterShadowEnabled = samplers.hasSampler("watershadow");
|
||||
final boolean waterShadowEnabled = samplers.hasSampler("watershadow");
|
||||
|
||||
// Get the appropriate sampler for hardware filtering
|
||||
// If separateHardwareSamplers is true, we don't apply HW filtering to the main samplers
|
||||
final GlSampler sampler0 = separateHardwareSamplers ? null : (shadowRenderTargets.isHardwareFiltered(0) ? (shadowRenderTargets.isLinearFiltered(0) ? SHADOW_SAMPLER_LINEAR : SHADOW_SAMPLER_NEAREST) : null);
|
||||
final GlSampler sampler1 = separateHardwareSamplers ? null : (shadowRenderTargets.isHardwareFiltered(1) ? (shadowRenderTargets.isLinearFiltered(1) ? SHADOW_SAMPLER_LINEAR : SHADOW_SAMPLER_NEAREST) : null);
|
||||
|
||||
if (waterShadowEnabled) {
|
||||
usesShadows = true;
|
||||
samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "watershadow");
|
||||
samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1", "shadow");
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTexture()::getTextureId, sampler0, "shadowtex0", "watershadow");
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, sampler1, "shadowtex1", "shadow");
|
||||
} else {
|
||||
usesShadows = samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0", "shadow");
|
||||
usesShadows |= samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1");
|
||||
usesShadows = samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTexture()::getTextureId, sampler0, "shadowtex0", "shadow");
|
||||
usesShadows |= samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, sampler1, "shadowtex1");
|
||||
}
|
||||
|
||||
samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(0), "shadowcolor", "shadowcolor0");
|
||||
samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(1), "shadowcolor1");
|
||||
|
||||
if (shadowRenderTargets.isHardwareFiltered(0)) {
|
||||
samplers.addDynamicSampler(shadowRenderTargets.getDepthTexture()::getTextureId, "shadowtex0HW");
|
||||
// Shadow color textures with flip support
|
||||
if (flipped == null) {
|
||||
// No flip tracking - use getColorTextureId which handles internal flip state
|
||||
if (samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(0), "shadowcolor")) {
|
||||
shadowRenderTargets.createIfEmpty(0);
|
||||
}
|
||||
for (int i = 0; i < shadowRenderTargets.getRenderTargetCount(); i++) {
|
||||
final int finalI = i;
|
||||
if (samplers.addDynamicSampler(() -> shadowRenderTargets.getColorTextureId(finalI), "shadowcolor" + i)) {
|
||||
shadowRenderTargets.createIfEmpty(finalI);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// With flip tracking - check provided flipped set
|
||||
if (samplers.addDynamicSampler(() -> flipped.contains(0) ? shadowRenderTargets.get(0).getAltTexture() : shadowRenderTargets.get(0).getMainTexture(), "shadowcolor")) {
|
||||
shadowRenderTargets.createIfEmpty(0);
|
||||
}
|
||||
for (int i = 0; i < shadowRenderTargets.getRenderTargetCount(); i++) {
|
||||
final int finalI = i;
|
||||
if (samplers.addDynamicSampler(() -> flipped.contains(finalI) ? shadowRenderTargets.get(finalI).getAltTexture() : shadowRenderTargets.get(finalI).getMainTexture(), "shadowcolor" + finalI)) {
|
||||
shadowRenderTargets.createIfEmpty(finalI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shadowRenderTargets.isHardwareFiltered(1)) {
|
||||
samplers.addDynamicSampler(shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, "shadowtex1HW");
|
||||
// Hardware-filtered shadow samplers for separate HW sampler access
|
||||
if (shadowRenderTargets.isHardwareFiltered(0) && separateHardwareSamplers) {
|
||||
final GlSampler hwSampler0 = shadowRenderTargets.isLinearFiltered(0) ? SHADOW_SAMPLER_LINEAR : SHADOW_SAMPLER_NEAREST;
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTexture()::getTextureId, hwSampler0, "shadowtex0HW");
|
||||
}
|
||||
|
||||
if (shadowRenderTargets.isHardwareFiltered(1) && separateHardwareSamplers) {
|
||||
final GlSampler hwSampler1 = shadowRenderTargets.isLinearFiltered(1) ? SHADOW_SAMPLER_LINEAR : SHADOW_SAMPLER_NEAREST;
|
||||
samplers.addDynamicSampler(TextureType.TEXTURE_2D, shadowRenderTargets.getDepthTextureNoTranslucents()::getTextureId, hwSampler1, "shadowtex1HW");
|
||||
}
|
||||
|
||||
return usesShadows;
|
||||
@@ -151,4 +213,18 @@ public class IrisSamplers {
|
||||
samplers.addDynamicSampler(renderTargets.getDepthTextureNoTranslucents()::getTextureId, "depthtex1");
|
||||
samplers.addDynamicSampler(renderTargets.getDepthTextureNoHand()::getTextureId, "depthtex2");
|
||||
}
|
||||
|
||||
public static void addCustomTextures(SamplerHolder samplers, Object2ObjectMap<String, TextureAccess> irisCustomTextures) {
|
||||
irisCustomTextures.forEach((name, texture) -> {
|
||||
samplers.addDynamicSampler(texture.getType(), texture.getTextureId(), name);
|
||||
});
|
||||
}
|
||||
|
||||
public static void addCustomImages(SamplerHolder images, Set<GlImage> customImages) {
|
||||
customImages.forEach(image -> {
|
||||
if (image.getSamplerName() != null) {
|
||||
images.addDynamicSampler(image.getTarget(), image::getId, image.getSamplerName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,40 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.joml.Vector2f;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ComputeSource {
|
||||
private final String name;
|
||||
@Getter private final String name;
|
||||
private final String source;
|
||||
private final ProgramSet parent;
|
||||
private Vector3i workGroups;
|
||||
private Vector2f workGroupRelative;
|
||||
@Getter private final ProgramSet parent;
|
||||
@Getter private final IndirectPointer indirectPointer;
|
||||
@Getter @Setter private Vector3i workGroups;
|
||||
@Getter @Setter private Vector2f workGroupRelative;
|
||||
|
||||
public ComputeSource(String name, String source, ProgramSet parent) {
|
||||
this(name, source, parent, null);
|
||||
}
|
||||
|
||||
public ComputeSource(String name, String source, ProgramSet parent, ShaderProperties properties) {
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
this.parent = parent;
|
||||
this.indirectPointer = properties != null ? properties.getIndirectPointers().get(name) : null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Optional<String> getSource() {
|
||||
public Optional<String> getSource() {
|
||||
return Optional.ofNullable(source);
|
||||
}
|
||||
|
||||
public ProgramSet getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
public boolean isValid() {
|
||||
return source != null;
|
||||
}
|
||||
|
||||
public void setWorkGroups(Vector3i workGroups) {
|
||||
this.workGroups = workGroups;
|
||||
}
|
||||
|
||||
public void setWorkGroupRelative(Vector2f workGroupRelative) {
|
||||
this.workGroupRelative = workGroupRelative;
|
||||
}
|
||||
|
||||
public Vector2f getWorkGroupRelative() {
|
||||
return workGroupRelative;
|
||||
}
|
||||
|
||||
public Vector3i getWorkGroups() {
|
||||
return workGroups;
|
||||
}
|
||||
|
||||
public Optional<ComputeSource> requireValid() {
|
||||
public Optional<ComputeSource> requireValid() {
|
||||
if (this.isValid()) {
|
||||
return Optional.of(this);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageBufferHolder;
|
||||
|
||||
public record FilledIndirectPointer(int buffer, long offset) {
|
||||
public static FilledIndirectPointer basedOff(ShaderStorageBufferHolder holder, IndirectPointer pointer) {
|
||||
if (pointer == null || holder == null) return null;
|
||||
|
||||
return new FilledIndirectPointer(holder.getBufferIndex(pointer.buffer()), pointer.offset());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
public record IndirectPointer(int buffer, long offset) {
|
||||
}
|
||||
@@ -1,64 +1,69 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMaps;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
|
||||
import net.coderbot.iris.gl.texture.TextureScaleOverride;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import net.coderbot.iris.helpers.Tri;
|
||||
import net.coderbot.iris.shaderpack.texture.TextureStage;
|
||||
import org.joml.Vector2i;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class PackDirectives {
|
||||
@Getter
|
||||
private int noiseTextureResolution;
|
||||
@Getter
|
||||
private float sunPathRotation;
|
||||
@Getter
|
||||
private float ambientOcclusionLevel;
|
||||
@Getter
|
||||
private float wetnessHalfLife;
|
||||
@Getter
|
||||
private float drynessHalfLife;
|
||||
@Getter
|
||||
private float eyeBrightnessHalfLife;
|
||||
@Getter
|
||||
private float centerDepthHalfLife;
|
||||
@Getter
|
||||
private CloudSetting cloudSetting;
|
||||
@Getter private int noiseTextureResolution;
|
||||
@Getter private float sunPathRotation;
|
||||
@Getter private float ambientOcclusionLevel;
|
||||
@Getter private float wetnessHalfLife;
|
||||
@Getter private float drynessHalfLife;
|
||||
@Getter private float eyeBrightnessHalfLife;
|
||||
@Getter private float centerDepthHalfLife;
|
||||
@Getter private CloudSetting cloudSetting;
|
||||
@Getter private CloudSetting dhCloudSetting;
|
||||
private boolean underwaterOverlay;
|
||||
private boolean vignette;
|
||||
private boolean sun;
|
||||
private boolean moon;
|
||||
private boolean rainDepth;
|
||||
private boolean separateAo;
|
||||
@Getter
|
||||
private boolean oldLighting;
|
||||
private boolean voxelizeLightBlocks;
|
||||
private boolean separateEntityDraws;
|
||||
private boolean frustumCulling;
|
||||
private boolean occlusionCulling;
|
||||
@Getter private boolean oldLighting;
|
||||
private boolean concurrentCompute;
|
||||
@Getter
|
||||
private boolean oldHandLight;
|
||||
private boolean particlesBeforeDeferred;
|
||||
@Getter
|
||||
private boolean prepareBeforeShadow;
|
||||
@Getter private boolean oldHandLight;
|
||||
@Getter private boolean prepareBeforeShadow;
|
||||
@Getter private boolean supportsColorCorrection;
|
||||
@Getter private int fallbackTex;
|
||||
private Object2ObjectMap<String, Object2BooleanMap<String>> explicitFlips = new Object2ObjectOpenHashMap<>();
|
||||
private Object2ObjectMap<String, TextureScaleOverride> scaleOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> textureMap;
|
||||
@Getter private Int2ObjectMap<ShaderStorageInfo> bufferObjects;
|
||||
@Getter private Optional<ParticleRenderingSettings> particleRenderingSettings;
|
||||
|
||||
@Getter
|
||||
private final PackRenderTargetDirectives renderTargetDirectives;
|
||||
@Getter
|
||||
private final PackShadowDirectives shadowDirectives;
|
||||
@Getter private final PackRenderTargetDirectives renderTargetDirectives;
|
||||
@Getter private final PackShadowDirectives shadowDirectives;
|
||||
|
||||
private PackDirectives(Set<Integer> supportedRenderTargets, PackShadowDirectives packShadowDirectives) {
|
||||
noiseTextureResolution = 256;
|
||||
sunPathRotation = 0.0F;
|
||||
supportsColorCorrection = false;
|
||||
ambientOcclusionLevel = 1.0F;
|
||||
wetnessHalfLife = 600.0f;
|
||||
drynessHalfLife = 200.0f;
|
||||
eyeBrightnessHalfLife = 10.0f;
|
||||
centerDepthHalfLife = 1.0F;
|
||||
bufferObjects = new Int2ObjectOpenHashMap<>();
|
||||
renderTargetDirectives = new PackRenderTargetDirectives(supportedRenderTargets);
|
||||
shadowDirectives = packShadowDirectives;
|
||||
}
|
||||
@@ -66,31 +71,46 @@ public class PackDirectives {
|
||||
PackDirectives(Set<Integer> supportedRenderTargets, ShaderProperties properties) {
|
||||
this(supportedRenderTargets, new PackShadowDirectives(properties));
|
||||
cloudSetting = properties.getCloudSetting();
|
||||
dhCloudSetting = properties.getDhCloudSetting();
|
||||
underwaterOverlay = properties.getUnderwaterOverlay().orElse(false);
|
||||
vignette = properties.getVignette().orElse(false);
|
||||
sun = properties.getSun().orElse(true);
|
||||
moon = properties.getMoon().orElse(true);
|
||||
rainDepth = properties.getRainDepth().orElse(false);
|
||||
separateAo = false; //properties.getSeparateAo().orElse(false);
|
||||
voxelizeLightBlocks = properties.getVoxelizeLightBlocks().orElse(false);
|
||||
separateEntityDraws = properties.getSeparateEntityDraws().orElse(false);
|
||||
frustumCulling = properties.getFrustumCulling().orElse(true);
|
||||
occlusionCulling = properties.getOcclusionCulling().orElse(true);
|
||||
oldLighting = properties.getOldLighting().orElse(false);
|
||||
fallbackTex = properties.getFallbackTex();
|
||||
supportsColorCorrection = properties.getSupportsColorCorrection().orElse(false);
|
||||
concurrentCompute = properties.getConcurrentCompute().orElse(false);
|
||||
oldHandLight = properties.getOldHandLight().orElse(true);
|
||||
explicitFlips = properties.getExplicitFlips();
|
||||
scaleOverrides = properties.getTextureScaleOverrides();
|
||||
particlesBeforeDeferred = properties.getParticlesBeforeDeferred().orElse(false);
|
||||
prepareBeforeShadow = properties.getPrepareBeforeShadow().orElse(false);
|
||||
particleRenderingSettings = properties.getParticleRenderingSettings();
|
||||
textureMap = properties.getCustomTexturePatching();
|
||||
bufferObjects = properties.getBufferObjects();
|
||||
}
|
||||
|
||||
PackDirectives(Set<Integer> supportedRenderTargets, PackDirectives directives) {
|
||||
this(supportedRenderTargets, new PackShadowDirectives(directives.getShadowDirectives()));
|
||||
cloudSetting = directives.cloudSetting;
|
||||
separateAo = directives.separateAo;
|
||||
voxelizeLightBlocks = directives.voxelizeLightBlocks;
|
||||
separateEntityDraws = directives.separateEntityDraws;
|
||||
frustumCulling = directives.frustumCulling;
|
||||
occlusionCulling = directives.occlusionCulling;
|
||||
oldLighting = directives.oldLighting;
|
||||
concurrentCompute = directives.concurrentCompute;
|
||||
explicitFlips = directives.explicitFlips;
|
||||
scaleOverrides = directives.scaleOverrides;
|
||||
particlesBeforeDeferred = directives.particlesBeforeDeferred;
|
||||
prepareBeforeShadow = directives.prepareBeforeShadow;
|
||||
particleRenderingSettings = directives.particleRenderingSettings;
|
||||
textureMap = directives.textureMap;
|
||||
bufferObjects = directives.bufferObjects;
|
||||
}
|
||||
|
||||
public boolean underwaterOverlay() {
|
||||
@@ -117,8 +137,20 @@ public class PackDirectives {
|
||||
return separateAo;
|
||||
}
|
||||
|
||||
public boolean areParticlesBeforeDeferred() {
|
||||
return particlesBeforeDeferred;
|
||||
public boolean shouldVoxelizeLightBlocks() {
|
||||
return voxelizeLightBlocks;
|
||||
}
|
||||
|
||||
public boolean shouldUseSeparateEntityDraws() {
|
||||
return separateEntityDraws;
|
||||
}
|
||||
|
||||
public boolean shouldUseFrustumCulling() {
|
||||
return frustumCulling;
|
||||
}
|
||||
|
||||
public boolean shouldUseOcclusionCulling() {
|
||||
return occlusionCulling;
|
||||
}
|
||||
|
||||
public boolean getConcurrentCompute() {
|
||||
@@ -133,30 +165,17 @@ public class PackDirectives {
|
||||
renderTargetDirectives.acceptDirectives(directives);
|
||||
shadowDirectives.acceptDirectives(directives);
|
||||
|
||||
directives.acceptConstIntDirective("noiseTextureResolution",
|
||||
noiseTextureResolution -> this.noiseTextureResolution = noiseTextureResolution);
|
||||
|
||||
directives.acceptConstFloatDirective("sunPathRotation",
|
||||
sunPathRotation -> this.sunPathRotation = sunPathRotation);
|
||||
|
||||
directives.acceptConstFloatDirective("ambientOcclusionLevel",
|
||||
ambientOcclusionLevel -> this.ambientOcclusionLevel = clamp(ambientOcclusionLevel, 0.0f, 1.0f));
|
||||
|
||||
directives.acceptConstFloatDirective("wetnessHalflife",
|
||||
wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife);
|
||||
|
||||
directives.acceptConstFloatDirective("drynessHalflife",
|
||||
wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife);
|
||||
|
||||
directives.acceptConstFloatDirective("eyeBrightnessHalflife",
|
||||
eyeBrightnessHalfLife -> this.eyeBrightnessHalfLife = eyeBrightnessHalfLife);
|
||||
|
||||
directives.acceptConstFloatDirective("centerDepthHalflife",
|
||||
centerDepthHalfLife -> this.centerDepthHalfLife = centerDepthHalfLife);
|
||||
directives.acceptConstIntDirective("noiseTextureResolution", noiseTextureResolution -> this.noiseTextureResolution = noiseTextureResolution);
|
||||
directives.acceptConstFloatDirective("sunPathRotation", sunPathRotation -> this.sunPathRotation = sunPathRotation);
|
||||
directives.acceptConstFloatDirective("ambientOcclusionLevel", ambientOcclusionLevel -> this.ambientOcclusionLevel = clamp(ambientOcclusionLevel, 0.0f, 1.0f));
|
||||
directives.acceptConstFloatDirective("wetnessHalflife", wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife);
|
||||
directives.acceptConstFloatDirective("drynessHalflife", wetnessHalfLife -> this.wetnessHalfLife = wetnessHalfLife);
|
||||
directives.acceptConstFloatDirective("eyeBrightnessHalflife", eyeBrightnessHalfLife -> this.eyeBrightnessHalfLife = eyeBrightnessHalfLife);
|
||||
directives.acceptConstFloatDirective("centerDepthHalflife", centerDepthHalfLife -> this.centerDepthHalfLife = centerDepthHalfLife);
|
||||
}
|
||||
|
||||
public ImmutableMap<Integer, Boolean> getExplicitFlips(String pass) {
|
||||
ImmutableMap.Builder<Integer, Boolean> explicitFlips = ImmutableMap.builder();
|
||||
final ImmutableMap.Builder<Integer, Boolean> explicitFlips = ImmutableMap.builder();
|
||||
|
||||
Object2BooleanMap<String> explicitFlipsStr = this.explicitFlips.get(pass);
|
||||
|
||||
@@ -180,8 +199,7 @@ public class PackDirectives {
|
||||
if (index != -1) {
|
||||
explicitFlips.put(index, shouldFlip);
|
||||
} else {
|
||||
Iris.logger.warn("Unknown buffer with ID " + buffer + " specified in flip directive for pass "
|
||||
+ pass);
|
||||
Iris.logger.warn("Unknown buffer with ID " + buffer + " specified in flip directive for pass " + pass);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import org.joml.Vector4f;
|
||||
@@ -29,7 +30,7 @@ public class PackShadowDirectives {
|
||||
private final boolean shouldRenderEntities;
|
||||
private final boolean shouldRenderPlayer;
|
||||
private final boolean shouldRenderBlockEntities;
|
||||
private final OptionalBoolean cullingState;
|
||||
@Getter private final ShadowCullState cullingState;
|
||||
|
||||
private final ImmutableList<DepthSamplingSettings> depthSamplingSettings;
|
||||
private final ImmutableList<SamplingSettings> colorSamplingSettings;
|
||||
@@ -159,11 +160,7 @@ public class PackShadowDirectives {
|
||||
return shouldRenderBlockEntities;
|
||||
}
|
||||
|
||||
public OptionalBoolean getCullingState() {
|
||||
return cullingState;
|
||||
}
|
||||
|
||||
public OptionalBoolean isShadowEnabled() {
|
||||
public OptionalBoolean isShadowEnabled() {
|
||||
return shadowEnabled;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public enum ParticleRenderingSettings {
|
||||
BEFORE,
|
||||
MIXED,
|
||||
AFTER;
|
||||
|
||||
public static Optional<ParticleRenderingSettings> fromString(String name) {
|
||||
try {
|
||||
return Optional.of(ParticleRenderingSettings.valueOf(name));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Iris.logger.warn("Invalid particle rendering settings! " + name);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
|
||||
import net.coderbot.iris.gl.blending.AlphaTestOverride;
|
||||
import net.coderbot.iris.gl.blending.BlendModeOverride;
|
||||
import net.coderbot.iris.gl.blending.BufferBlendInformation;
|
||||
import net.coderbot.iris.gl.framebuffer.ViewportData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -20,7 +21,7 @@ public class ProgramDirectives {
|
||||
private static final ImmutableList<String> LEGACY_RENDER_TARGETS = PackRenderTargetDirectives.LEGACY_RENDER_TARGETS;
|
||||
|
||||
private final int[] drawBuffers;
|
||||
private final float viewportScale;
|
||||
private final ViewportData viewportScale;
|
||||
@Nullable
|
||||
private final AlphaTestOverride alphaTestOverride;
|
||||
|
||||
@@ -29,7 +30,7 @@ public class ProgramDirectives {
|
||||
private final ImmutableSet<Integer> mipmappedBuffers;
|
||||
private final ImmutableMap<Integer, Boolean> explicitFlips;
|
||||
|
||||
private ProgramDirectives(int[] drawBuffers, float viewportScale, @Nullable AlphaTestOverride alphaTestOverride,
|
||||
private ProgramDirectives(int[] drawBuffers, ViewportData viewportScale, @Nullable AlphaTestOverride alphaTestOverride,
|
||||
Optional<BlendModeOverride> blendModeOverride, List<BufferBlendInformation> bufferBlendInformations, ImmutableSet<Integer> mipmappedBuffers,
|
||||
ImmutableMap<Integer, Boolean> explicitFlips) {
|
||||
this.drawBuffers = drawBuffers;
|
||||
@@ -41,8 +42,7 @@ public class ProgramDirectives {
|
||||
this.explicitFlips = explicitFlips;
|
||||
}
|
||||
|
||||
ProgramDirectives(ProgramSource source, ShaderProperties properties, Set<Integer> supportedRenderTargets,
|
||||
@Nullable BlendModeOverride defaultBlendOverride) {
|
||||
ProgramDirectives(ProgramSource source, ShaderProperties properties, Set<Integer> supportedRenderTargets, @Nullable BlendModeOverride defaultBlendOverride) {
|
||||
// DRAWBUFFERS is only detected in the fragment shader source code (.fsh).
|
||||
// If there's no explicit declaration, then by default /* DRAWBUFFERS:0 */ is inferred.
|
||||
// For SEUS v08 and SEUS v10 to work, this will need to be set to 01234567. However, doing this causes
|
||||
@@ -50,10 +50,10 @@ public class ProgramDirectives {
|
||||
// undefined data to be written to colortex7.
|
||||
//
|
||||
// TODO: Figure out how to infer the DRAWBUFFERS directive when it is missing.
|
||||
Optional<CommentDirective> optionalDrawbuffersDirective = findDrawbuffersDirective(source.getFragmentSource());
|
||||
Optional<CommentDirective> optionalRendertargetsDirective = findRendertargetsDirective(source.getFragmentSource());
|
||||
final Optional<CommentDirective> optionalDrawbuffersDirective = findDrawbuffersDirective(source.getFragmentSource());
|
||||
final Optional<CommentDirective> optionalRendertargetsDirective = findRendertargetsDirective(source.getFragmentSource());
|
||||
|
||||
Optional<CommentDirective> optionalCommentDirective = getAppliedDirective(optionalDrawbuffersDirective, optionalRendertargetsDirective);
|
||||
final Optional<CommentDirective> optionalCommentDirective = getAppliedDirective(optionalDrawbuffersDirective, optionalRendertargetsDirective);
|
||||
drawBuffers = optionalCommentDirective.map(commentDirective -> {
|
||||
if (commentDirective.getType() == CommentDirective.Type.DRAWBUFFERS) {
|
||||
return parseDigits(commentDirective.getDirective().toCharArray());
|
||||
@@ -65,28 +65,28 @@ public class ProgramDirectives {
|
||||
}).orElse(new int[] { 0 });
|
||||
|
||||
if (properties != null) {
|
||||
viewportScale = properties.getViewportScaleOverrides().getOrDefault(source.getName(), 1.0f);
|
||||
viewportScale = properties.getViewportScaleOverrides().getOrDefault(source.getName(), ViewportData.defaultValue());
|
||||
alphaTestOverride = properties.getAlphaTestOverrides().get(source.getName());
|
||||
|
||||
BlendModeOverride blendModeOverride = properties.getBlendModeOverrides().get(source.getName());
|
||||
List<BufferBlendInformation> bufferBlendInformations = properties.getBufferBlendOverrides().get(source.getName());
|
||||
final BlendModeOverride blendModeOverride = properties.getBlendModeOverrides().get(source.getName());
|
||||
final List<BufferBlendInformation> bufferBlendInformations = properties.getBufferBlendOverrides().get(source.getName());
|
||||
this.blendModeOverride = Optional.ofNullable(blendModeOverride != null ? blendModeOverride : defaultBlendOverride);
|
||||
this.bufferBlendInformations = bufferBlendInformations != null ? bufferBlendInformations : Collections.emptyList();
|
||||
|
||||
explicitFlips = source.getParent().getPackDirectives().getExplicitFlips(source.getName());
|
||||
} else {
|
||||
viewportScale = 1.0f;
|
||||
viewportScale = ViewportData.defaultValue();
|
||||
alphaTestOverride = null;
|
||||
blendModeOverride = Optional.ofNullable(defaultBlendOverride);
|
||||
bufferBlendInformations = Collections.emptyList();
|
||||
explicitFlips = ImmutableMap.of();
|
||||
}
|
||||
|
||||
HashSet<Integer> mipmappedBuffers = new HashSet<>();
|
||||
DispatchingDirectiveHolder directiveHolder = new DispatchingDirectiveHolder();
|
||||
final HashSet<Integer> mipmappedBuffers = new HashSet<>();
|
||||
final DispatchingDirectiveHolder directiveHolder = new DispatchingDirectiveHolder();
|
||||
|
||||
supportedRenderTargets.forEach(index -> {
|
||||
BooleanConsumer mipmapHandler = shouldMipmap -> {
|
||||
final BooleanConsumer mipmapHandler = shouldMipmap -> {
|
||||
if (shouldMipmap) {
|
||||
mipmappedBuffers.add(index);
|
||||
} else {
|
||||
@@ -160,7 +160,7 @@ public class ProgramDirectives {
|
||||
return drawBuffers;
|
||||
}
|
||||
|
||||
public float getViewportScale() {
|
||||
public ViewportData getViewportScale() {
|
||||
return viewportScale;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,15 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.features.FeatureFlags;
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
|
||||
import net.coderbot.iris.gl.image.ImageInformation;
|
||||
import net.coderbot.iris.gl.texture.TextureDefinition;
|
||||
import net.coderbot.iris.shaderpack.include.AbsolutePackPath;
|
||||
import net.coderbot.iris.shaderpack.include.IncludeGraph;
|
||||
import net.coderbot.iris.shaderpack.include.IncludeProcessor;
|
||||
@@ -51,22 +55,19 @@ public class ShaderPack {
|
||||
public final CustomUniforms.Builder customUniforms;
|
||||
|
||||
private final ProgramSet base;
|
||||
@Nullable
|
||||
private final ProgramSet overworld;
|
||||
@Nullable private final ProgramSet overworld;
|
||||
private final ProgramSet nether;
|
||||
private final ProgramSet end;
|
||||
|
||||
@Getter
|
||||
private final IdMap idMap;
|
||||
@Getter
|
||||
private final LanguageMap languageMap;
|
||||
@Getter
|
||||
private final EnumMap<TextureStage, Object2ObjectMap<String, CustomTextureData>> customTextureDataMap = new EnumMap<>(TextureStage.class);
|
||||
@Getter private final IdMap idMap;
|
||||
@Getter private final LanguageMap languageMap;
|
||||
@Getter private final EnumMap<TextureStage, Object2ObjectMap<String, CustomTextureData>> customTextureDataMap = new EnumMap<>(TextureStage.class);
|
||||
@Getter private final Object2ObjectMap<String, CustomTextureData> irisCustomTextureDataMap = new Object2ObjectOpenHashMap<>();
|
||||
private final CustomTextureData customNoiseTexture;
|
||||
@Getter
|
||||
private final ShaderPackOptions shaderPackOptions;
|
||||
@Getter
|
||||
private final OptionMenuContainer menuContainer;
|
||||
@Getter private final Object2ObjectMap<String, ImageInformation> customImages;
|
||||
@Getter private final Int2ObjectMap<ShaderStorageInfo> bufferObjects;
|
||||
@Getter private final ShaderPackOptions shaderPackOptions;
|
||||
@Getter private final OptionMenuContainer menuContainer;
|
||||
|
||||
private final ProfileSet.ProfileResult profile;
|
||||
private final String profileInfo;
|
||||
@@ -88,20 +89,14 @@ public class ShaderPack {
|
||||
Objects.requireNonNull(root);
|
||||
|
||||
|
||||
ImmutableList.Builder<AbsolutePackPath> starts = ImmutableList.builder();
|
||||
ImmutableList<String> potentialFileNames = ShaderPackSourceNames.POTENTIAL_STARTS;
|
||||
final ImmutableList.Builder<AbsolutePackPath> starts = ImmutableList.builder();
|
||||
final ImmutableList<String> potentialFileNames = ShaderPackSourceNames.POTENTIAL_STARTS;
|
||||
|
||||
ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/"),
|
||||
potentialFileNames);
|
||||
ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/"), potentialFileNames);
|
||||
|
||||
boolean hasWorld0 = ShaderPackSourceNames.findPresentSources(starts, root,
|
||||
AbsolutePackPath.fromAbsolutePath("/world0"), potentialFileNames);
|
||||
|
||||
boolean hasNether = ShaderPackSourceNames.findPresentSources(starts, root,
|
||||
AbsolutePackPath.fromAbsolutePath("/world-1"), potentialFileNames);
|
||||
|
||||
boolean hasEnd = ShaderPackSourceNames.findPresentSources(starts, root,
|
||||
AbsolutePackPath.fromAbsolutePath("/world1"), potentialFileNames);
|
||||
final boolean hasWorld0 = ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/world0"), potentialFileNames);
|
||||
final boolean hasNether = ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/world-1"), potentialFileNames);
|
||||
final boolean hasEnd = ShaderPackSourceNames.findPresentSources(starts, root, AbsolutePackPath.fromAbsolutePath("/world1"), potentialFileNames);
|
||||
|
||||
// Read all files and included files recursively
|
||||
IncludeGraph graph = new IncludeGraph(root, starts.build());
|
||||
@@ -236,18 +231,30 @@ public class ShaderPack {
|
||||
|
||||
shaderProperties.getCustomTextures().forEach((textureStage, customTexturePropertiesMap) -> {
|
||||
Object2ObjectMap<String, CustomTextureData> innerCustomTextureDataMap = new Object2ObjectOpenHashMap<>();
|
||||
customTexturePropertiesMap.forEach((samplerName, path) -> {
|
||||
customTexturePropertiesMap.forEach((samplerName, definition) -> {
|
||||
try {
|
||||
innerCustomTextureDataMap.put(samplerName, readTexture(root, path));
|
||||
innerCustomTextureDataMap.put(samplerName, readTexture(root, definition));
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Unable to read the custom texture at " + path, e);
|
||||
Iris.logger.error("Unable to read the custom texture at " + definition.getName(), e);
|
||||
}
|
||||
});
|
||||
|
||||
customTextureDataMap.put(textureStage, innerCustomTextureDataMap);
|
||||
});
|
||||
|
||||
// Process irisCustomTextures (direct custom textures via customTexture.<name>=<path>)
|
||||
shaderProperties.getIrisCustomTextures().forEach((samplerName, definition) -> {
|
||||
try {
|
||||
irisCustomTextureDataMap.put(samplerName, readTexture(root, definition));
|
||||
Iris.logger.debug("[CustomTextures] Loaded customTexture.{} from {}", samplerName, definition.getName());
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Unable to read custom texture for sampler " + samplerName + " at " + definition.getName(), e);
|
||||
}
|
||||
});
|
||||
|
||||
this.customUniforms = shaderProperties.getCustomUniforms();
|
||||
this.customImages = shaderProperties.getCustomImages();
|
||||
this.bufferObjects = shaderProperties.getBufferObjects();
|
||||
}
|
||||
|
||||
private String getCurrentProfileName() {
|
||||
@@ -278,7 +285,73 @@ public class ShaderPack {
|
||||
return Optional.of(fileContents);
|
||||
}
|
||||
|
||||
// TODO: Implement raw texture data types
|
||||
/**
|
||||
* Reads a texture from a TextureDefinition. Handles both PNG and raw texture types.
|
||||
*/
|
||||
public CustomTextureData readTexture(Path root, TextureDefinition definition) throws IOException {
|
||||
if (definition instanceof TextureDefinition.RawDefinition rawDef) {
|
||||
return readRawTexture(root, rawDef);
|
||||
} else {
|
||||
// PNG definition - use the path-based method
|
||||
return readTexture(root, definition.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a raw texture from a RawDefinition.
|
||||
*/
|
||||
private CustomTextureData readRawTexture(Path root, TextureDefinition.RawDefinition rawDef) throws IOException {
|
||||
String path = rawDef.getName();
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
// Read mcmeta for filtering data
|
||||
boolean blur = false;
|
||||
boolean clamp = false;
|
||||
|
||||
String mcMetaPath = path + ".mcmeta";
|
||||
Path mcMetaResolvedPath = root.resolve(mcMetaPath);
|
||||
|
||||
if (Files.exists(mcMetaResolvedPath)) {
|
||||
try {
|
||||
JsonObject meta = loadMcMeta(mcMetaResolvedPath);
|
||||
if (meta.get("texture") != null) {
|
||||
if (meta.get("texture").getAsJsonObject().get("blur") != null) {
|
||||
blur = meta.get("texture").getAsJsonObject().get("blur").getAsBoolean();
|
||||
}
|
||||
if (meta.get("texture").getAsJsonObject().get("clamp") != null) {
|
||||
clamp = meta.get("texture").getAsJsonObject().get("clamp").getAsBoolean();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Unable to read the custom texture mcmeta at " + mcMetaPath + ", ignoring: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] content = Files.readAllBytes(root.resolve(path));
|
||||
TextureFilteringData filteringData = new TextureFilteringData(blur, clamp);
|
||||
|
||||
return switch (rawDef.getTarget()) {
|
||||
case TEXTURE_1D -> new CustomTextureData.RawData1D(content, filteringData,
|
||||
rawDef.getInternalFormat(), rawDef.getFormat(), rawDef.getPixelType(),
|
||||
rawDef.getSizeX());
|
||||
case TEXTURE_2D -> new CustomTextureData.RawData2D(content, filteringData,
|
||||
rawDef.getInternalFormat(), rawDef.getFormat(), rawDef.getPixelType(),
|
||||
rawDef.getSizeX(), rawDef.getSizeY());
|
||||
case TEXTURE_3D -> new CustomTextureData.RawData3D(content, filteringData,
|
||||
rawDef.getInternalFormat(), rawDef.getFormat(), rawDef.getPixelType(),
|
||||
rawDef.getSizeX(), rawDef.getSizeY(), rawDef.getSizeZ());
|
||||
case TEXTURE_RECTANGLE -> new CustomTextureData.RawDataRect(content, filteringData,
|
||||
rawDef.getInternalFormat(), rawDef.getFormat(), rawDef.getPixelType(),
|
||||
rawDef.getSizeX(), rawDef.getSizeY());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a texture from a path string (for PNG textures and resource locations).
|
||||
*/
|
||||
public CustomTextureData readTexture(Path root, String path) throws IOException {
|
||||
CustomTextureData customTextureData;
|
||||
if (path.contains(":")) {
|
||||
@@ -294,7 +367,6 @@ public class ShaderPack {
|
||||
customTextureData = new CustomTextureData.ResourceData(parts[0], parts[1]);
|
||||
}
|
||||
} else {
|
||||
// TODO: Make sure the resulting path is within the shaderpack?
|
||||
if (path.startsWith("/")) {
|
||||
// NB: This does not guarantee the resulting path is in the shaderpack as a double slash could be used,
|
||||
// this just fixes shaderpacks like Continuum 2.0.4 that use a leading slash in texture paths
|
||||
|
||||
@@ -3,12 +3,20 @@ package net.coderbot.iris.shaderpack;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanConsumer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2FloatMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.coderbot.iris.gl.buffer.ShaderStorageInfo;
|
||||
import net.coderbot.iris.gl.framebuffer.ViewportData;
|
||||
import net.coderbot.iris.gl.image.ImageInformation;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelType;
|
||||
import net.coderbot.iris.gl.texture.TextureDefinition;
|
||||
import net.coderbot.iris.gl.texture.TextureType;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.blending.AlphaTest;
|
||||
@@ -18,6 +26,7 @@ import net.coderbot.iris.gl.blending.BlendModeFunction;
|
||||
import net.coderbot.iris.gl.blending.BlendModeOverride;
|
||||
import net.coderbot.iris.gl.blending.BufferBlendInformation;
|
||||
import net.coderbot.iris.gl.texture.TextureScaleOverride;
|
||||
import net.coderbot.iris.helpers.Tri;
|
||||
import net.coderbot.iris.pipeline.PatchedShaderPrinter;
|
||||
import net.coderbot.iris.shaderpack.option.ShaderPackOptions;
|
||||
import net.coderbot.iris.shaderpack.preprocessor.PropertiesPreprocessor;
|
||||
@@ -35,6 +44,7 @@ import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
@@ -47,16 +57,19 @@ import java.util.function.Consumer;
|
||||
* values in here & the values parsed from shader source code.
|
||||
*/
|
||||
public class ShaderProperties {
|
||||
@Getter private final CustomUniforms.Builder customUniforms = new CustomUniforms.Builder();
|
||||
@Getter private final CustomUniforms.Builder customUniforms = new CustomUniforms.Builder();
|
||||
@Getter private CloudSetting cloudSetting = CloudSetting.DEFAULT;
|
||||
@Getter private CloudSetting dhCloudSetting = CloudSetting.DEFAULT;
|
||||
@Getter private OptionalBoolean oldHandLight = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean dynamicHandLight = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean supportsColorCorrection = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean oldLighting = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowTerrain = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowTranslucent = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowEntities = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowPlayer = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowBlockEntities = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowLightBlockEntities = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean underwaterOverlay = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean sun = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean moon = OptionalBoolean.DEFAULT;
|
||||
@@ -69,10 +82,14 @@ public class ShaderProperties {
|
||||
@Getter private OptionalBoolean concurrentCompute = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean beaconBeamDepth = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean separateAo = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean voxelizeLightBlocks = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean separateEntityDraws = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean frustumCulling = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowCulling = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean occlusionCulling = OptionalBoolean.DEFAULT;
|
||||
@Getter private ShadowCullState shadowCulling = ShadowCullState.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowEnabled = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean particlesBeforeDeferred = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean dhShadowEnabled = OptionalBoolean.DEFAULT;
|
||||
private Optional<ParticleRenderingSettings> particleRenderingSettings = Optional.empty();
|
||||
@Getter private OptionalBoolean prepareBeforeShadow = OptionalBoolean.DEFAULT;
|
||||
@Getter private List<String> sliderOptions = new ArrayList<>();
|
||||
@Getter private final Map<String, List<String>> profiles = new LinkedHashMap<>();
|
||||
@@ -80,19 +97,26 @@ public class ShaderProperties {
|
||||
@Getter private final Map<String, List<String>> subScreenOptions = new HashMap<>();
|
||||
private Integer mainScreenColumnCount = null;
|
||||
@Getter private final Map<String, Integer> subScreenColumnCount = new HashMap<>();
|
||||
@Getter private int fallbackTex = 0;
|
||||
// TODO: private Map<String, String> optifineVersionRequirements;
|
||||
// TODO: Parse custom uniforms / variables
|
||||
@Getter private final Object2ObjectMap<String, AlphaTestOverride> alphaTestOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2FloatMap<String> viewportScaleOverrides = new Object2FloatOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, ViewportData> viewportScaleOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, TextureScaleOverride> textureScaleOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, BlendModeOverride> blendModeOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, IndirectPointer> indirectPointers = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, ArrayList<BufferBlendInformation>> bufferBlendOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final EnumMap<TextureStage, Object2ObjectMap<String, String>> customTextures = new EnumMap<>(TextureStage.class);
|
||||
@Getter private final EnumMap<TextureStage, Object2ObjectMap<String, TextureDefinition>> customTextures = new EnumMap<>(TextureStage.class);
|
||||
@Getter private final Object2ObjectMap<Tri<String, TextureType, TextureStage>, String> customTexturePatching = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, Object2BooleanMap<String>> explicitFlips = new Object2ObjectOpenHashMap<>();
|
||||
private String noiseTexturePath = null;
|
||||
@Getter private Object2ObjectMap<String, String> conditionallyEnabledPrograms = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private List<String> requiredFeatureFlags = new ArrayList<>();
|
||||
@Getter private List<String> optionalFeatureFlags = new ArrayList<>();
|
||||
@Getter private final Object2ObjectMap<String, ImageInformation> customImages = new Object2ObjectOpenHashMap<>();
|
||||
@Getter private final Int2ObjectMap<ShaderStorageInfo> bufferObjects = new Int2ObjectOpenHashMap<>();
|
||||
@Getter private final Object2ObjectMap<String, TextureDefinition> irisCustomTextures = new Object2ObjectOpenHashMap<>();
|
||||
private int customTexAmount;
|
||||
|
||||
private ShaderProperties() {
|
||||
// empty
|
||||
@@ -139,6 +163,32 @@ public class ShaderProperties {
|
||||
} else {
|
||||
Iris.logger.error("Unrecognized clouds setting: " + value);
|
||||
}
|
||||
|
||||
if (dhCloudSetting == CloudSetting.DEFAULT) {
|
||||
dhCloudSetting = cloudSetting;
|
||||
}
|
||||
}
|
||||
|
||||
if ("dhClouds".equals(key)) {
|
||||
if ("off".equals(value)) {
|
||||
dhCloudSetting = CloudSetting.OFF;
|
||||
} else if ("on".equals(value) || "fancy".equals(value)) {
|
||||
dhCloudSetting = CloudSetting.FANCY;
|
||||
} else {
|
||||
Iris.logger.error("Unrecognized DH clouds setting (need off, on): " + value);
|
||||
}
|
||||
}
|
||||
|
||||
if ("shadow.culling".equals(key)) {
|
||||
if ("false".equals(value)) {
|
||||
shadowCulling = ShadowCullState.DISTANCE;
|
||||
} else if ("true".equals(value)) {
|
||||
shadowCulling = ShadowCullState.ADVANCED;
|
||||
} else if ("reversed".equals(value)) {
|
||||
shadowCulling = ShadowCullState.REVERSED;
|
||||
} else {
|
||||
Iris.logger.error("Unrecognized shadow culling setting: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
handleBooleanDirective(key, value, "oldHandLight", bool -> oldHandLight = bool);
|
||||
@@ -149,6 +199,7 @@ public class ShaderProperties {
|
||||
handleBooleanDirective(key, value, "shadowEntities", bool -> shadowEntities = bool);
|
||||
handleBooleanDirective(key, value, "shadowPlayer", bool -> shadowPlayer = bool);
|
||||
handleBooleanDirective(key, value, "shadowBlockEntities", bool -> shadowBlockEntities = bool);
|
||||
handleBooleanDirective(key, value, "shadowLightBlockEntities", bool -> shadowLightBlockEntities = bool);
|
||||
handleBooleanDirective(key, value, "underwaterOverlay", bool -> underwaterOverlay = bool);
|
||||
handleBooleanDirective(key, value, "sun", bool -> sun = bool);
|
||||
handleBooleanDirective(key, value, "moon", bool -> moon = bool);
|
||||
@@ -161,25 +212,50 @@ public class ShaderProperties {
|
||||
handleBooleanDirective(key, value, "allowConcurrentCompute", bool -> concurrentCompute = bool);
|
||||
handleBooleanDirective(key, value, "beacon.beam.depth", bool -> beaconBeamDepth = bool);
|
||||
handleBooleanDirective(key, value, "separateAo", bool -> separateAo = bool);
|
||||
handleBooleanDirective(key, value, "voxelizeLightBlocks", bool -> voxelizeLightBlocks = bool);
|
||||
handleBooleanDirective(key, value, "separateEntityDraws", bool -> separateEntityDraws = bool);
|
||||
handleBooleanDirective(key, value, "frustum.culling", bool -> frustumCulling = bool);
|
||||
handleBooleanDirective(key, value, "shadow.culling", bool -> shadowCulling = bool);
|
||||
handleBooleanDirective(key, value, "particles.before.deferred", bool -> particlesBeforeDeferred = bool);
|
||||
handleBooleanDirective(key, value, "occlusion.culling", bool -> occlusionCulling = bool);
|
||||
handleBooleanDirective(key, value, "shadow.enabled", bool -> shadowEnabled = bool);
|
||||
handleBooleanDirective(key, value, "dhShadow.enabled", bool -> dhShadowEnabled = bool);
|
||||
handleBooleanDirective(key, value, "particles.before.deferred", bool -> {
|
||||
if (bool.orElse(false) && particleRenderingSettings.isEmpty()) {
|
||||
particleRenderingSettings = Optional.of(ParticleRenderingSettings.BEFORE);
|
||||
}
|
||||
});
|
||||
handleBooleanDirective(key, value, "prepareBeforeShadow", bool -> prepareBeforeShadow = bool);
|
||||
handleBooleanDirective(key, value, "supportsColorCorrection", bool -> supportsColorCorrection = bool);
|
||||
handleIntDirective(key, value, "fallbackTex", val -> fallbackTex = val);
|
||||
|
||||
if (key.startsWith("particles.ordering")) {
|
||||
Optional<ParticleRenderingSettings> settings = ParticleRenderingSettings.fromString(value.trim().toUpperCase(Locale.ROOT));
|
||||
if (settings.isPresent()) {
|
||||
particleRenderingSettings = settings;
|
||||
} else {
|
||||
throw new RuntimeException("Failed to parse particle rendering order! " + value);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Min optifine versions, shader options layout / appearance / profiles
|
||||
// TODO: Custom uniforms
|
||||
|
||||
handlePassDirective("scale.", key, value, pass -> {
|
||||
final float scale;
|
||||
float scale, offsetX = 0.0f, offsetY = 0.0f;
|
||||
String[] parts = value.split(" ");
|
||||
|
||||
try {
|
||||
scale = Float.parseFloat(value);
|
||||
} catch (NumberFormatException e) {
|
||||
scale = Float.parseFloat(parts[0]);
|
||||
|
||||
if (parts.length > 1) {
|
||||
offsetX = Float.parseFloat(parts[1]);
|
||||
offsetY = Float.parseFloat(parts[2]);
|
||||
}
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
Iris.logger.error("Unable to parse scale directive for " + pass + ": " + value, e);
|
||||
return;
|
||||
}
|
||||
|
||||
viewportScaleOverrides.put(pass, scale);
|
||||
viewportScaleOverrides.put(pass, new ViewportData(scale, offsetX, offsetY));
|
||||
});
|
||||
|
||||
handlePassDirective("size.buffer.", key, value, pass -> {
|
||||
@@ -291,26 +367,76 @@ public class ShaderProperties {
|
||||
conditionallyEnabledPrograms.put(program, value);
|
||||
});
|
||||
|
||||
handleTwoArgDirective("texture.", key, value, (stageName, samplerName) -> {
|
||||
final String[] parts = value.split(" ");
|
||||
|
||||
// TODO: Support raw textures
|
||||
if (parts.length > 1) {
|
||||
Iris.logger.warn("Custom texture directive for stage " + stageName + ", sampler " + samplerName + " contains more parts than we expected: " + value);
|
||||
return;
|
||||
handlePassDirective("indirect.", key, value, pass -> {
|
||||
try {
|
||||
String[] locations = value.split(" ");
|
||||
indirectPointers.put(pass, new IndirectPointer(Integer.parseInt(locations[0]), Long.parseLong(locations[1])));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
|
||||
Iris.logger.fatal("Failed to parse indirect command for " + pass + "! " + value);
|
||||
}
|
||||
});
|
||||
|
||||
final Optional<TextureStage> optionalTextureStage = TextureStage.parse(stageName);
|
||||
handleTwoArgDirective("texture.", key, value, (stageName, samplerName) -> {
|
||||
String[] parts = value.split(" ");
|
||||
// Handle sampler names with dots by taking only the first part
|
||||
samplerName = samplerName.split("\\.")[0];
|
||||
|
||||
final Optional<TextureStage> optionalTextureStage = TextureStage.parse(stageName);
|
||||
|
||||
if (!optionalTextureStage.isPresent()) {
|
||||
Iris.logger.warn("Unknown texture stage " + "\"" + stageName + "\"," + " ignoring custom texture directive for " + key);
|
||||
return;
|
||||
}
|
||||
|
||||
final TextureStage stage = optionalTextureStage.get();
|
||||
final TextureStage stage = optionalTextureStage.get();
|
||||
|
||||
if (parts.length > 1) {
|
||||
// Raw texture - create internal sampler name and store mapping
|
||||
String newSamplerName = "customtex" + customTexAmount;
|
||||
customTexAmount++;
|
||||
TextureType type = null;
|
||||
|
||||
// Raw texture handling based on number of parts
|
||||
if (parts.length == 6) {
|
||||
// 1D texture handling
|
||||
type = TextureType.TEXTURE_1D;
|
||||
irisCustomTextures.put(newSamplerName, new TextureDefinition.RawDefinition(parts[0],
|
||||
TextureType.valueOf(parts[1].toUpperCase(Locale.ROOT)),
|
||||
InternalTextureFormat.fromString(parts[2]).orElseThrow(IllegalArgumentException::new),
|
||||
Integer.parseInt(parts[3]), 0, 0,
|
||||
PixelFormat.fromString(parts[4]).orElseThrow(IllegalArgumentException::new),
|
||||
PixelType.fromString(parts[5]).orElseThrow(IllegalArgumentException::new)));
|
||||
} else if (parts.length == 7) {
|
||||
// 2D texture handling
|
||||
type = TextureType.valueOf(parts[1].toUpperCase(Locale.ROOT));
|
||||
irisCustomTextures.put(newSamplerName, new TextureDefinition.RawDefinition(parts[0],
|
||||
TextureType.valueOf(parts[1].toUpperCase(Locale.ROOT)),
|
||||
InternalTextureFormat.fromString(parts[2]).orElseThrow(IllegalArgumentException::new),
|
||||
Integer.parseInt(parts[3]), Integer.parseInt(parts[4]), 0,
|
||||
PixelFormat.fromString(parts[5]).orElseThrow(IllegalArgumentException::new),
|
||||
PixelType.fromString(parts[6]).orElseThrow(IllegalArgumentException::new)));
|
||||
} else if (parts.length == 8) {
|
||||
// 3D texture handling
|
||||
type = TextureType.TEXTURE_3D;
|
||||
irisCustomTextures.put(newSamplerName, new TextureDefinition.RawDefinition(parts[0],
|
||||
TextureType.valueOf(parts[1].toUpperCase(Locale.ROOT)),
|
||||
InternalTextureFormat.fromString(parts[2]).orElseThrow(IllegalArgumentException::new),
|
||||
Integer.parseInt(parts[3]), Integer.parseInt(parts[4]), Integer.parseInt(parts[5]),
|
||||
PixelFormat.fromString(parts[6]).orElseThrow(IllegalArgumentException::new),
|
||||
PixelType.fromString(parts[7]).orElseThrow(IllegalArgumentException::new)));
|
||||
} else {
|
||||
Iris.logger.warn("Unknown texture directive for " + key + ": " + value);
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
customTexturePatching.put(new Tri<>(samplerName, type, stage), newSamplerName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// PNG texture
|
||||
customTextures.computeIfAbsent(stage, _stage -> new Object2ObjectOpenHashMap<>())
|
||||
.put(samplerName, value);
|
||||
.put(samplerName, new TextureDefinition.PNGDefinition(value));
|
||||
});
|
||||
|
||||
handleTwoArgDirective("flip.", key, value, (pass, buffer) -> {
|
||||
@@ -324,6 +450,25 @@ public class ShaderProperties {
|
||||
handleWhitespacedListDirective(key, value, "iris.features.required", options -> requiredFeatureFlags = options);
|
||||
handleWhitespacedListDirective(key, value, "iris.features.optional", options -> optionalFeatureFlags = options);
|
||||
|
||||
// Parse custom images: image.<name> = <sampler> <pixelFormat> <internalFormat> <pixelType> <clear> <relative> [dimensions...]
|
||||
handlePassDirective("image.", key, value, imageName -> {
|
||||
parseCustomImage(imageName, value);
|
||||
});
|
||||
|
||||
// Parse buffer objects: bufferObject.<index> = <size> [relative <scaleX> <scaleY>]
|
||||
handlePassDirective("bufferObject.", key, value, indexStr -> {
|
||||
parseBufferObject(indexStr, value);
|
||||
});
|
||||
|
||||
// Parse custom textures: customTexture.<name> = <path> [type format sizeX [sizeY [sizeZ]] pixelFormat pixelType]
|
||||
handlePassDirective("customTexture.", key, value, samplerName -> {
|
||||
final TextureDefinition definition = parseTextureDefinition("customTexture." + samplerName, value);
|
||||
if (definition != null) {
|
||||
irisCustomTextures.put(samplerName, definition);
|
||||
Iris.logger.debug("[CustomTextures] Parsed customTexture.{} = {}", samplerName, value);
|
||||
}
|
||||
});
|
||||
|
||||
handlePassDirective("variable.", key, value, pass -> {
|
||||
String[] parts = pass.split("\\.");
|
||||
if (parts.length != 2) {
|
||||
@@ -497,4 +642,258 @@ public class ShaderProperties {
|
||||
return Optional.ofNullable(mainScreenColumnCount);
|
||||
}
|
||||
|
||||
public Optional<ParticleRenderingSettings> getParticleRenderingSettings() {
|
||||
// MIXED is implied if separateEntityDraws is true.
|
||||
if (separateEntityDraws == OptionalBoolean.TRUE) {
|
||||
return Optional.of(ParticleRenderingSettings.MIXED);
|
||||
}
|
||||
return particleRenderingSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a custom image directive.
|
||||
* Format: image.<name> = <sampler_name> <pixel_format> <internal_format> <pixel_type> <clear> <relative> [width height [depth]] | [relativeX relativeY]
|
||||
*/
|
||||
private void parseCustomImage(String imageName, String value) {
|
||||
if (customImages.size() >= 16) {
|
||||
Iris.logger.error("Maximum of 16 custom images exceeded, cannot add: " + imageName);
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] parts = value.split("\\s+");
|
||||
|
||||
if (parts.length < 6) {
|
||||
Iris.logger.error("Invalid custom image directive for " + imageName + ": expected at least 6 parts, got " + parts.length);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
String samplerName = parts[0];
|
||||
if (samplerName.equals("none") || samplerName.equals("null") || samplerName.isEmpty()) {
|
||||
samplerName = null;
|
||||
}
|
||||
|
||||
final Optional<PixelFormat> pixelFormatOpt = PixelFormat.fromString(parts[1].toUpperCase());
|
||||
if (!pixelFormatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel format for custom image {}: {}", imageName, parts[1]);
|
||||
return;
|
||||
}
|
||||
final PixelFormat pixelFormat = pixelFormatOpt.get();
|
||||
|
||||
final Optional<InternalTextureFormat> internalFormatOpt = InternalTextureFormat.fromString(parts[2].toUpperCase());
|
||||
if (!internalFormatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid internal format for custom image {}: {}", imageName, parts[2]);
|
||||
return;
|
||||
}
|
||||
final InternalTextureFormat internalFormat = internalFormatOpt.get();
|
||||
|
||||
final Optional<PixelType> pixelTypeOpt = PixelType.fromString(parts[3].toUpperCase());
|
||||
if (!pixelTypeOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel type for custom image {}: {}", imageName, parts[3]);
|
||||
return;
|
||||
}
|
||||
final PixelType pixelType = pixelTypeOpt.get();
|
||||
|
||||
final boolean clear = Boolean.parseBoolean(parts[4]);
|
||||
final boolean relative = Boolean.parseBoolean(parts[5]);
|
||||
|
||||
ImageInformation imageInfo;
|
||||
|
||||
if (parts.length == 7) {
|
||||
// 1D texture: width only
|
||||
int width = Integer.parseInt(parts[6]);
|
||||
imageInfo = new ImageInformation(imageName, samplerName, TextureType.TEXTURE_1D, pixelFormat, internalFormat, pixelType, width, 1, 1, clear, false, 1.0f, 1.0f);
|
||||
} else if (parts.length == 8) {
|
||||
if (relative) {
|
||||
// Relative 2D: relativeWidth relativeHeight
|
||||
float relativeWidth = Float.parseFloat(parts[6]);
|
||||
float relativeHeight = Float.parseFloat(parts[7]);
|
||||
imageInfo = new ImageInformation(imageName, samplerName, TextureType.TEXTURE_2D, pixelFormat, internalFormat, pixelType, 0, 0, 1, clear, true, relativeWidth, relativeHeight);
|
||||
} else {
|
||||
// Absolute 2D: width height
|
||||
int width = Integer.parseInt(parts[6]);
|
||||
int height = Integer.parseInt(parts[7]);
|
||||
imageInfo = new ImageInformation(imageName, samplerName, TextureType.TEXTURE_2D, pixelFormat, internalFormat, pixelType, width, height, 1, clear, false, 1.0f, 1.0f);
|
||||
}
|
||||
} else if (parts.length >= 9) {
|
||||
// 3D texture: width height depth
|
||||
int width = Integer.parseInt(parts[6]);
|
||||
int height = Integer.parseInt(parts[7]);
|
||||
int depth = Integer.parseInt(parts[8]);
|
||||
imageInfo = new ImageInformation(imageName, samplerName, TextureType.TEXTURE_3D, pixelFormat, internalFormat, pixelType, width, height, depth, clear, false, 1.0f, 1.0f);
|
||||
} else {
|
||||
Iris.logger.error("Invalid custom image directive for {}: expected dimensions", imageName);
|
||||
return;
|
||||
}
|
||||
|
||||
customImages.put(imageName, imageInfo);
|
||||
Iris.logger.debug("[CustomImages] Parsed custom image: {} -> {}", imageName, imageInfo);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
Iris.logger.error("Failed to parse dimensions for custom image {}: {}", imageName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a buffer object directive.
|
||||
* Format: bufferObject.<index> = <size> [relative <scaleX> <scaleY>]
|
||||
*/
|
||||
private void parseBufferObject(String indexStr, String value) {
|
||||
try {
|
||||
final int index = Integer.parseInt(indexStr);
|
||||
|
||||
if (index > 8) {
|
||||
Iris.logger.error("SSBO index " + index + " exceeds maximum of 8, buffers 9+ are reserved");
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] parts = value.split("\\s+");
|
||||
|
||||
if (parts.length < 1) {
|
||||
Iris.logger.error("Invalid buffer object directive for index " + index + ": expected size");
|
||||
return;
|
||||
}
|
||||
|
||||
final int size = Integer.parseInt(parts[0]);
|
||||
|
||||
// Size < 1 means the shader dev intended to disable the buffer
|
||||
if (size < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShaderStorageInfo info;
|
||||
|
||||
if (parts.length >= 4 && "true".equalsIgnoreCase(parts[1])) {
|
||||
// Relative: size relative scaleX scaleY
|
||||
float scaleX = Float.parseFloat(parts[2]);
|
||||
float scaleY = Float.parseFloat(parts[3]);
|
||||
info = new ShaderStorageInfo(size, true, scaleX, scaleY);
|
||||
} else {
|
||||
// Absolute: size only
|
||||
info = new ShaderStorageInfo(size, false, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
bufferObjects.put(index, info);
|
||||
Iris.logger.debug("Parsed buffer object: " + index + " -> " + info);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
Iris.logger.error("Failed to parse buffer object " + indexStr + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a texture definition from a shaders.properties value.
|
||||
* Format can be:
|
||||
* - PNG: path
|
||||
* - Raw 1D: path type format sizeX pixelFormat pixelType
|
||||
* - Raw 2D: path type format sizeX sizeY pixelFormat pixelType
|
||||
* - Raw 3D: path type format sizeX sizeY sizeZ pixelFormat pixelType
|
||||
*/
|
||||
private TextureDefinition parseTextureDefinition(String key, String value) {
|
||||
final String[] parts = value.split(" ");
|
||||
|
||||
if (parts.length == 1) {
|
||||
// PNG texture - just a path
|
||||
return new TextureDefinition.PNGDefinition(value);
|
||||
}
|
||||
|
||||
try {
|
||||
if (parts.length == 6) {
|
||||
// 1D raw texture: path type format sizeX pixelFormat pixelType
|
||||
final Optional<TextureType> targetOpt = TextureType.fromString(parts[1].toUpperCase(Locale.ROOT));
|
||||
if (!targetOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid texture type for {}: {}", key, parts[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<InternalTextureFormat> internalFormatOpt = InternalTextureFormat.fromString(parts[2].toUpperCase(Locale.ROOT));
|
||||
if (!internalFormatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid internal format for {}: {}", key, parts[2]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelFormat> formatOpt = PixelFormat.fromString(parts[4].toUpperCase(Locale.ROOT));
|
||||
if (!formatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel format for {}: {}", key, parts[4]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelType> pixelTypeOpt = PixelType.fromString(parts[5].toUpperCase(Locale.ROOT));
|
||||
if (!pixelTypeOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel type for {}: {}", key, parts[5]);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TextureDefinition.RawDefinition(parts[0], targetOpt.get(), internalFormatOpt.get(),
|
||||
Integer.parseInt(parts[3]), 0, 0, formatOpt.get(), pixelTypeOpt.get());
|
||||
|
||||
} else if (parts.length == 7) {
|
||||
// 2D raw texture: path type format sizeX sizeY pixelFormat pixelType
|
||||
final Optional<TextureType> targetOpt = TextureType.fromString(parts[1].toUpperCase(Locale.ROOT));
|
||||
if (!targetOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid texture type for {}: {}", key, parts[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<InternalTextureFormat> internalFormatOpt = InternalTextureFormat.fromString(parts[2].toUpperCase(Locale.ROOT));
|
||||
if (!internalFormatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid internal format for {}: {}", key, parts[2]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelFormat> formatOpt = PixelFormat.fromString(parts[5].toUpperCase(Locale.ROOT));
|
||||
if (!formatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel format for {}: {}", key, parts[5]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelType> pixelTypeOpt = PixelType.fromString(parts[6].toUpperCase(Locale.ROOT));
|
||||
if (!pixelTypeOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel type for {}: {}", key, parts[6]);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TextureDefinition.RawDefinition(parts[0], targetOpt.get(), internalFormatOpt.get(),
|
||||
Integer.parseInt(parts[3]), Integer.parseInt(parts[4]), 0, formatOpt.get(), pixelTypeOpt.get());
|
||||
|
||||
} else if (parts.length == 8) {
|
||||
// 3D raw texture: path type format sizeX sizeY sizeZ pixelFormat pixelType
|
||||
final Optional<TextureType> targetOpt = TextureType.fromString(parts[1].toUpperCase(Locale.ROOT));
|
||||
if (!targetOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid texture type for {}: {}", key, parts[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<InternalTextureFormat> internalFormatOpt = InternalTextureFormat.fromString(parts[2].toUpperCase(Locale.ROOT));
|
||||
if (!internalFormatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid internal format for {}: {}", key, parts[2]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelFormat> formatOpt = PixelFormat.fromString(parts[6].toUpperCase(Locale.ROOT));
|
||||
if (!formatOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel format for {}: {}", key, parts[6]);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Optional<PixelType> pixelTypeOpt = PixelType.fromString(parts[7].toUpperCase(Locale.ROOT));
|
||||
if (!pixelTypeOpt.isPresent()) {
|
||||
Iris.logger.error("Invalid pixel type for {}: {}", key, parts[7]);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TextureDefinition.RawDefinition(parts[0], targetOpt.get(), internalFormatOpt.get(),
|
||||
Integer.parseInt(parts[3]), Integer.parseInt(parts[4]), Integer.parseInt(parts[5]),
|
||||
formatOpt.get(), pixelTypeOpt.get());
|
||||
|
||||
} else {
|
||||
Iris.logger.warn("Unknown texture directive format for {}: {} (expected 1, 6, 7, or 8 parts, got {})",
|
||||
key, value, parts.length);
|
||||
return null;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Iris.logger.error("Failed to parse texture dimensions for {}: {}", key, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.coderbot.iris.shaderpack;
|
||||
|
||||
public enum ShadowCullState {
|
||||
DEFAULT,
|
||||
ADVANCED,
|
||||
REVERSED,
|
||||
DISTANCE
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
package net.coderbot.iris.shaderpack.texture;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.gl.texture.InternalTextureFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelFormat;
|
||||
import net.coderbot.iris.gl.texture.PixelType;
|
||||
|
||||
public abstract class CustomTextureData {
|
||||
private CustomTextureData() {
|
||||
|
||||
CustomTextureData() {
|
||||
}
|
||||
|
||||
public static final class PngData extends CustomTextureData {
|
||||
@Getter
|
||||
public static final class PngData extends CustomTextureData {
|
||||
private final TextureFilteringData filteringData;
|
||||
private final byte[] content;
|
||||
|
||||
@@ -18,14 +19,7 @@ public abstract class CustomTextureData {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public TextureFilteringData getFilteringData() {
|
||||
return filteringData;
|
||||
}
|
||||
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class LightmapMarker extends CustomTextureData {
|
||||
@Override
|
||||
@@ -39,123 +33,80 @@ public abstract class CustomTextureData {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ResourceData extends CustomTextureData {
|
||||
private final String namespace;
|
||||
private final String location;
|
||||
@Getter
|
||||
public static final class ResourceData extends CustomTextureData {
|
||||
private final String namespace;
|
||||
private final String location;
|
||||
|
||||
public ResourceData(String namespace, String location) {
|
||||
this.namespace = namespace;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The namespace of the texture. The caller is responsible for checking whether this is actually
|
||||
* a valid namespace.
|
||||
*/
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The path / location of the texture. The caller is responsible for checking whether this is actually
|
||||
* a valid path.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public abstract static class RawData extends CustomTextureData {
|
||||
private final byte[] content;
|
||||
private final TextureFilteringData filteringData;
|
||||
private final InternalTextureFormat internalFormat;
|
||||
private final PixelFormat pixelFormat;
|
||||
private final PixelType pixelType;
|
||||
|
||||
private RawData(byte[] content, InternalTextureFormat internalFormat,
|
||||
PixelFormat pixelFormat, PixelType pixelType) {
|
||||
protected RawData(byte[] content, TextureFilteringData filteringData, InternalTextureFormat internalFormat, PixelFormat pixelFormat, PixelType pixelType) {
|
||||
this.content = content;
|
||||
this.filteringData = filteringData;
|
||||
this.internalFormat = internalFormat;
|
||||
this.pixelFormat = pixelFormat;
|
||||
this.pixelType = pixelType;
|
||||
}
|
||||
|
||||
public final byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public final InternalTextureFormat getInternalFormat() {
|
||||
return internalFormat;
|
||||
}
|
||||
|
||||
public final PixelFormat getPixelFormat() {
|
||||
return pixelFormat;
|
||||
}
|
||||
|
||||
public final PixelType getPixelType() {
|
||||
return pixelType;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class RawData1D extends RawData {
|
||||
@Getter
|
||||
public static final class RawData1D extends RawData {
|
||||
private final int sizeX;
|
||||
|
||||
private RawData1D(byte[] content, InternalTextureFormat internalFormat,
|
||||
PixelFormat pixelFormat, PixelType pixelType, int sizeX) {
|
||||
super(content, internalFormat, pixelFormat, pixelType);
|
||||
public RawData1D(byte[] content, TextureFilteringData filteringData, InternalTextureFormat internalFormat, PixelFormat pixelFormat, PixelType pixelType, int sizeX) {
|
||||
super(content, filteringData, internalFormat, pixelFormat, pixelType);
|
||||
|
||||
this.sizeX = sizeX;
|
||||
}
|
||||
|
||||
public int getSizeX() {
|
||||
return sizeX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class RawData2D extends RawData {
|
||||
int sizeX;
|
||||
int sizeY;
|
||||
@Getter
|
||||
public static class RawData2D extends RawData {
|
||||
private final int sizeX;
|
||||
private final int sizeY;
|
||||
|
||||
private RawData2D(byte[] content, InternalTextureFormat internalFormat,
|
||||
PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY) {
|
||||
super(content, internalFormat, pixelFormat, pixelType);
|
||||
public RawData2D(byte[] content, TextureFilteringData filteringData, InternalTextureFormat internalFormat, PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY) {
|
||||
super(content, filteringData, internalFormat, pixelFormat, pixelType);
|
||||
|
||||
this.sizeX = sizeX;
|
||||
this.sizeY = sizeY;
|
||||
}
|
||||
|
||||
public int getSizeX() {
|
||||
return sizeX;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSizeY() {
|
||||
return sizeY;
|
||||
}
|
||||
}
|
||||
@Getter
|
||||
public static final class RawData3D extends RawData {
|
||||
private final int sizeX;
|
||||
private final int sizeY;
|
||||
private final int sizeZ;
|
||||
|
||||
public static final class RawData3D extends RawData {
|
||||
int sizeX;
|
||||
int sizeY;
|
||||
int sizeZ;
|
||||
|
||||
private RawData3D(byte[] content, InternalTextureFormat internalFormat,
|
||||
PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY, int sizeZ) {
|
||||
super(content, internalFormat, pixelFormat, pixelType);
|
||||
public RawData3D(byte[] content, TextureFilteringData filteringData, InternalTextureFormat internalFormat, PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY, int sizeZ) {
|
||||
super(content, filteringData, internalFormat, pixelFormat, pixelType);
|
||||
|
||||
this.sizeX = sizeX;
|
||||
this.sizeY = sizeY;
|
||||
this.sizeZ = sizeZ;
|
||||
}
|
||||
|
||||
public int getSizeX() {
|
||||
return sizeX;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSizeY() {
|
||||
return sizeY;
|
||||
}
|
||||
|
||||
public int getSizeZ() {
|
||||
return sizeZ;
|
||||
public static final class RawDataRect extends RawData2D {
|
||||
public RawDataRect(byte[] content, TextureFilteringData filteringData, InternalTextureFormat internalFormat, PixelFormat pixelFormat, PixelType pixelType, int sizeX, int sizeY) {
|
||||
super(content, filteringData, internalFormat, pixelFormat, pixelType, sizeX, sizeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,18 @@ package net.coderbot.iris.shaderpack.texture;
|
||||
import java.util.Optional;
|
||||
|
||||
public enum TextureStage {
|
||||
/**
|
||||
* The setup passes.
|
||||
*
|
||||
* Exclusive to Iris 1.6.
|
||||
*/
|
||||
SETUP,
|
||||
/**
|
||||
* The begin pass.
|
||||
*
|
||||
* Exclusive to Iris 1.6.
|
||||
*/
|
||||
BEGIN,
|
||||
/**
|
||||
* The shadowcomp passes.
|
||||
*
|
||||
@@ -29,13 +41,15 @@ public enum TextureStage {
|
||||
COMPOSITE_AND_FINAL;
|
||||
|
||||
public static Optional<TextureStage> parse(String name) {
|
||||
return switch (name) {
|
||||
case "shadowcomp" -> Optional.of(SHADOWCOMP);
|
||||
case "prepare" -> Optional.of(PREPARE);
|
||||
case "gbuffers" -> Optional.of(GBUFFERS_AND_SHADOW);
|
||||
case "deferred" -> Optional.of(DEFERRED);
|
||||
case "composite" -> Optional.of(COMPOSITE_AND_FINAL);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
return switch (name) {
|
||||
case "setup" -> Optional.of(SETUP);
|
||||
case "begin" -> Optional.of(BEGIN);
|
||||
case "shadowcomp" -> Optional.of(SHADOWCOMP);
|
||||
case "prepare" -> Optional.of(PREPARE);
|
||||
case "gbuffers" -> Optional.of(GBUFFERS_AND_SHADOW);
|
||||
case "deferred" -> Optional.of(DEFERRED);
|
||||
case "composite" -> Optional.of(COMPOSITE_AND_FINAL);
|
||||
default -> Optional.empty();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import java.util.List;
|
||||
|
||||
public class ShadowRenderTargets {
|
||||
private final RenderTarget[] targets;
|
||||
private final PackShadowDirectives shadowDirectives;
|
||||
private final DepthTexture mainDepth;
|
||||
private final DepthTexture noTranslucents;
|
||||
private final GlFramebuffer depthSourceFb;
|
||||
@@ -29,42 +30,41 @@ public class ShadowRenderTargets {
|
||||
|
||||
private boolean fullClearRequired;
|
||||
private boolean translucentDepthDirty;
|
||||
private boolean[] hardwareFiltered;
|
||||
private InternalTextureFormat[] formats;
|
||||
private IntList buffersToBeCleared;
|
||||
private final boolean[] hardwareFiltered;
|
||||
private final boolean[] linearFiltered;
|
||||
private final InternalTextureFormat[] formats;
|
||||
private final IntList buffersToBeCleared;
|
||||
|
||||
public ShadowRenderTargets(int resolution, PackShadowDirectives shadowDirectives) {
|
||||
targets = new RenderTarget[shadowDirectives.getColorSamplingSettings().size()];
|
||||
formats = new InternalTextureFormat[shadowDirectives.getColorSamplingSettings().size()];
|
||||
flipped = new boolean[shadowDirectives.getColorSamplingSettings().size()];
|
||||
hardwareFiltered = new boolean[shadowDirectives.getColorSamplingSettings().size()];
|
||||
this.shadowDirectives = shadowDirectives;
|
||||
this.resolution = resolution;
|
||||
|
||||
final int size = shadowDirectives.getColorSamplingSettings().size();
|
||||
targets = new RenderTarget[size];
|
||||
formats = new InternalTextureFormat[size];
|
||||
flipped = new boolean[size];
|
||||
hardwareFiltered = new boolean[shadowDirectives.getDepthSamplingSettings().size()];
|
||||
linearFiltered = new boolean[shadowDirectives.getDepthSamplingSettings().size()];
|
||||
buffersToBeCleared = new IntArrayList();
|
||||
|
||||
this.mainDepth = new DepthTexture(resolution, resolution, DepthBufferFormat.DEPTH);
|
||||
this.noTranslucents = new DepthTexture(resolution, resolution, DepthBufferFormat.DEPTH);
|
||||
|
||||
for (int i = 0; i < shadowDirectives.getColorSamplingSettings().size(); i++) {
|
||||
PackShadowDirectives.SamplingSettings settings = shadowDirectives.getColorSamplingSettings().get(i);
|
||||
targets[i] = RenderTarget.builder().setDimensions(resolution, resolution)
|
||||
.setInternalFormat(settings.getFormat())
|
||||
.setPixelFormat(settings.getFormat().getPixelFormat()).build();
|
||||
formats[i] = settings.getFormat();
|
||||
|
||||
if (settings.getClear()) {
|
||||
buffersToBeCleared.add(i);
|
||||
}
|
||||
|
||||
this.hardwareFiltered[i] = shadowDirectives.getDepthSamplingSettings().get(i).getHardwareFiltering();
|
||||
}
|
||||
|
||||
this.resolution = resolution;
|
||||
|
||||
this.ownedFramebuffers = new ArrayList<>();
|
||||
|
||||
// Populate hardware/linear filtering settings from depth sampling settings
|
||||
for (int i = 0; i < shadowDirectives.getDepthSamplingSettings().size(); i++) {
|
||||
this.hardwareFiltered[i] = shadowDirectives.getDepthSamplingSettings().get(i).getHardwareFiltering();
|
||||
this.linearFiltered[i] = !shadowDirectives.getDepthSamplingSettings().get(i).getNearest();
|
||||
}
|
||||
|
||||
// NB: Make sure all buffers are cleared so that they don't contain undefined
|
||||
// data. Otherwise very weird things can happen.
|
||||
fullClearRequired = true;
|
||||
|
||||
// Create target 0 eagerly - it's needed for framebuffer creation and almost always used
|
||||
createIfEmpty(0);
|
||||
|
||||
this.depthSourceFb = createFramebufferWritingToMain(new int[] {0});
|
||||
|
||||
this.noTranslucentsDestFb = createFramebufferWritingToMain(new int[] {0});
|
||||
@@ -73,6 +73,36 @@ public class ShadowRenderTargets {
|
||||
this.translucentDepthDirty = true;
|
||||
}
|
||||
|
||||
private void create(int index) {
|
||||
if (index >= targets.length) {
|
||||
throw new IllegalStateException("Tried to create shadow color buffer " + index + " but only " + targets.length + " are supported.");
|
||||
}
|
||||
|
||||
PackShadowDirectives.SamplingSettings settings = shadowDirectives.getColorSamplingSettings().get(index);
|
||||
targets[index] = RenderTarget.builder()
|
||||
.setDimensions(resolution, resolution)
|
||||
.setInternalFormat(settings.getFormat())
|
||||
.setPixelFormat(settings.getFormat().getPixelFormat()).build();
|
||||
formats[index] = settings.getFormat();
|
||||
|
||||
if (settings.getClear()) {
|
||||
buffersToBeCleared.add(index);
|
||||
}
|
||||
|
||||
fullClearRequired = true;
|
||||
}
|
||||
|
||||
public void createIfEmpty(int index) {
|
||||
if (targets[index] == null) {
|
||||
create(index);
|
||||
}
|
||||
}
|
||||
|
||||
public RenderTarget getOrCreate(int index) {
|
||||
createIfEmpty(index);
|
||||
return targets[index];
|
||||
}
|
||||
|
||||
// TODO: Actually flip. This is required for shadow composites!
|
||||
public void flip(int target) {
|
||||
flipped[target] = !flipped[target];
|
||||
@@ -88,9 +118,12 @@ public class ShadowRenderTargets {
|
||||
}
|
||||
|
||||
for (RenderTarget target : targets) {
|
||||
target.destroy();
|
||||
if (target != null) {
|
||||
target.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
mainDepth.destroy();
|
||||
noTranslucents.destroy();
|
||||
}
|
||||
|
||||
@@ -165,7 +198,7 @@ public class ShadowRenderTargets {
|
||||
|
||||
// NB: Before OpenGL 3.0, all framebuffers are required to have a color
|
||||
// attachment no matter what.
|
||||
framebuffer.addColorAttachment(0, get(0).getMainTexture());
|
||||
framebuffer.addColorAttachment(0, getOrCreate(0).getMainTexture());
|
||||
framebuffer.noDrawBuffers();
|
||||
|
||||
return framebuffer;
|
||||
@@ -224,7 +257,7 @@ public class ShadowRenderTargets {
|
||||
+ getRenderTargetCount() + " render targets are supported.");
|
||||
}
|
||||
|
||||
RenderTarget target = this.get(drawBuffers[i]);
|
||||
RenderTarget target = this.getOrCreate(drawBuffers[i]);
|
||||
|
||||
int textureId = stageWritesToMain.contains(drawBuffers[i]) ? target.getMainTexture() : target.getAltTexture();
|
||||
|
||||
@@ -242,13 +275,21 @@ public class ShadowRenderTargets {
|
||||
}
|
||||
|
||||
public int getColorTextureId(int i) {
|
||||
return isFlipped(i) ? get(i).getAltTexture() : get(i).getMainTexture();
|
||||
RenderTarget target = get(i);
|
||||
if (target == null) {
|
||||
return 0;
|
||||
}
|
||||
return isFlipped(i) ? target.getAltTexture() : target.getMainTexture();
|
||||
}
|
||||
|
||||
public boolean isHardwareFiltered(int i) {
|
||||
return hardwareFiltered[i];
|
||||
}
|
||||
|
||||
public boolean isLinearFiltered(int i) {
|
||||
return linearFiltered[i];
|
||||
}
|
||||
|
||||
public int getNumColorTextures() {
|
||||
return targets.length;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user