mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-10-25 20:22:22 +00:00
Many bug fixes (#2017)
Co-authored-by: Martin Robertz <dream-master@gmx.net>
This commit is contained in:
1 parent
b2f597a73a
commit
22c9479946
89 files changed
+2820
-735
No files matched your search
@@ -161,6 +161,8 @@ DependencyHandlerScope.of(dependencies).apply {
|
||||
compileOnly(rfg.deobf("curse.maven:xaeros-minimap-263420:5060684"))
|
||||
compileOnly(rfg.deobf("curse.maven:security-craft-64760:2818228"))
|
||||
compileOnly("ganymedes01.etfuturum:Et-Futurum-Requiem:2.6.49-GTNH:dev")
|
||||
compileOnly("com.github.GTNewHorizons:OpenBlocks:1.12.19-GTNH:dev")
|
||||
compileOnly("com.github.GTNewHorizons:Chisel:2.17.31-GTNH:dev")
|
||||
compileOnly(rfg.deobf("curse.maven:biomes-o-plenty-220318:2499612"))
|
||||
|
||||
devOnlyNonPublishable("com.github.GTNewHorizons:CosmeticArmorReworked:1.0.6-GTNH:dev")
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.gtnewhorizons.angelica.glsm.stacks.PointStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.PolygonStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.StencilStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ViewPortStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
|
||||
@@ -181,6 +182,9 @@ class GLContextState {
|
||||
public int clientAttribStackPointer = 0;
|
||||
public final boolean[] restoreUnitChanged = new boolean[GLStateManager.MAX_TEXTURE_UNITS];
|
||||
public boolean restoreDepthChanged, restoreBlendChanged, restoreColorMaskChanged, restoreClearColorChanged, restoreDrawBufferChanged, restoreLogicOpChanged, restoreStencilChanged, restoreViewportChanged, restoreLineChanged, restorePointChanged, restorePolygonChanged, restoreActiveUnitChanged;
|
||||
public final BlendState vanillaBlendBefore = new BlendState();
|
||||
public final BlendState vanillaBlendAfter = new BlendState();
|
||||
public boolean vanillaBlendEnabledBefore;
|
||||
public int drawFramebuffer = 0;
|
||||
public int readFramebuffer = 0;
|
||||
public int texGenGeneration;
|
||||
|
||||
@@ -45,6 +45,8 @@ import com.gtnewhorizons.angelica.glsm.stacks.PointStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.PolygonStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.StencilStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ViewPortStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
|
||||
@@ -1302,12 +1304,16 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final BooleanStateStack blend = ctx().blendMode;
|
||||
final boolean wasEnabled = blend.isEffectivelyEnabled();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null && bh.isBlendLocked()) {
|
||||
blend.beforeModify();
|
||||
bh.deferBlendModeToggle(true);
|
||||
return;
|
||||
} else {
|
||||
blend.enable();
|
||||
}
|
||||
ctx().blendMode.enable();
|
||||
if (!wasEnabled && blend.isEffectivelyEnabled()) postVanillaBlendChange();
|
||||
}
|
||||
|
||||
public static void disableBlend() {
|
||||
@@ -1318,12 +1324,80 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final BooleanStateStack blend = ctx().blendMode;
|
||||
final boolean wasEnabled = blend.isEffectivelyEnabled();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null && bh.isBlendLocked()) {
|
||||
blend.beforeModify();
|
||||
bh.deferBlendModeToggle(false);
|
||||
return;
|
||||
} else {
|
||||
blend.disable();
|
||||
}
|
||||
ctx().blendMode.disable();
|
||||
if (wasEnabled && !blend.isEffectivelyEnabled()) postVanillaBlendChange();
|
||||
}
|
||||
|
||||
private static void postVanillaBlendChange() {
|
||||
if (GLSMHooks.VANILLA_BLEND_CHANGE.hasListeners()) {
|
||||
GLSMHooks.VANILLA_BLEND_CHANGE.post(GLSMHooks.vanillaBlendChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean snapshotVanillaBlendFunc() {
|
||||
if (!GLSMHooks.VANILLA_BLEND_CHANGE.hasListeners()) return false;
|
||||
final GLContextState glCtx = ctx();
|
||||
glCtx.blendState.readEffective(glCtx.vanillaBlendBefore);
|
||||
glCtx.vanillaBlendEnabledBefore = glCtx.blendMode.isEffectivelyEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void postVanillaBlendChangeIfMoved(boolean snapshotted) {
|
||||
if (!snapshotted) return;
|
||||
final GLContextState glCtx = ctx();
|
||||
final BlendState before = glCtx.vanillaBlendBefore;
|
||||
final BlendState after = glCtx.blendState.readEffective(glCtx.vanillaBlendAfter);
|
||||
if (glCtx.blendMode.isEffectivelyEnabled() != glCtx.vanillaBlendEnabledBefore
|
||||
|| after.getSrcRgb() != before.getSrcRgb()
|
||||
|| after.getDstRgb() != before.getDstRgb()
|
||||
|| after.getSrcAlpha() != before.getSrcAlpha()
|
||||
|| after.getDstAlpha() != before.getDstAlpha()) {
|
||||
postVanillaBlendChange();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEffectiveBlendEnabled() {
|
||||
return ctx().blendMode.isEffectivelyEnabled();
|
||||
}
|
||||
|
||||
public static BlendState getEffectiveBlendState(BlendState out) {
|
||||
return ctx().blendState.readEffective(out);
|
||||
}
|
||||
|
||||
public static boolean isEffectiveDepthMaskEnabled() {
|
||||
return ctx().depthState.isEffectiveMaskEnabled();
|
||||
}
|
||||
|
||||
public static boolean isEffectiveAlphaTestEnabled() {
|
||||
return ctx().alphaTest.isEffectivelyEnabled();
|
||||
}
|
||||
|
||||
public static AlphaState getEffectiveAlphaState(AlphaState out) {
|
||||
return ctx().alphaState.readEffective(out);
|
||||
}
|
||||
|
||||
private static int foreignDrawDepth;
|
||||
|
||||
public static void beginForeignDraw() {
|
||||
foreignDrawDepth++;
|
||||
}
|
||||
|
||||
public static void endForeignDraw() {
|
||||
if (foreignDrawDepth > 0 && --foreignDrawDepth == 0 && GLSMHooks.FOREIGN_DRAW_END.hasListeners()) {
|
||||
GLSMHooks.FOREIGN_DRAW_END.post(GLSMHooks.foreignDrawEndEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isForeignDraw() {
|
||||
return foreignDrawDepth > 0;
|
||||
}
|
||||
|
||||
public static void enableScissorTest() {
|
||||
@@ -1357,9 +1431,11 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final boolean snapshotted = snapshotVanillaBlendFunc();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null && bh.isBlendLocked()) {
|
||||
bh.deferBlendFunc(srcFactor, dstFactor, srcFactor, dstFactor);
|
||||
postVanillaBlendChangeIfMoved(snapshotted);
|
||||
return;
|
||||
}
|
||||
final boolean caching = isCachingEnabled();
|
||||
@@ -1373,6 +1449,7 @@ public class GLStateManager {
|
||||
GLSMHooks.blendFuncChangeEvent.dstAlpha = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
GLSMHooks.BLEND_FUNC_CHANGE.post(GLSMHooks.blendFuncChangeEvent);
|
||||
}
|
||||
postVanillaBlendChangeIfMoved(snapshotted);
|
||||
return;
|
||||
}
|
||||
final boolean bypass = !caching;
|
||||
@@ -1391,6 +1468,7 @@ public class GLStateManager {
|
||||
GLSMHooks.BLEND_FUNC_CHANGE.post(GLSMHooks.blendFuncChangeEvent);
|
||||
}
|
||||
}
|
||||
postVanillaBlendChangeIfMoved(snapshotted);
|
||||
}
|
||||
|
||||
public static void glBlendEquation(int mode) {
|
||||
@@ -1430,9 +1508,11 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
final boolean snapshotted = snapshotVanillaBlendFunc();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null && bh.isBlendLocked()) {
|
||||
bh.deferBlendFunc(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
postVanillaBlendChangeIfMoved(snapshotted);
|
||||
return;
|
||||
}
|
||||
if (GLSMConfig.hudCacheOverride && dstAlpha != GL11.GL_ONE_MINUS_SRC_ALPHA) {
|
||||
@@ -1452,6 +1532,7 @@ public class GLStateManager {
|
||||
GLSMHooks.BLEND_FUNC_CHANGE.post(GLSMHooks.blendFuncChangeEvent);
|
||||
}
|
||||
}
|
||||
postVanillaBlendChangeIfMoved(snapshotted);
|
||||
}
|
||||
|
||||
public static void glBlendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
|
||||
@@ -1746,6 +1827,7 @@ public class GLStateManager {
|
||||
}
|
||||
final DeferredAlphaHandler ah = GLSMHooks.alphaHandler;
|
||||
if (ah != null && ah.isAlphaTestLocked()) {
|
||||
glCtx.alphaTest.beforeModify();
|
||||
ah.deferAlphaTestToggle(true);
|
||||
return;
|
||||
}
|
||||
@@ -1767,6 +1849,7 @@ public class GLStateManager {
|
||||
}
|
||||
final DeferredAlphaHandler ah = GLSMHooks.alphaHandler;
|
||||
if (ah != null && ah.isAlphaTestLocked()) {
|
||||
glCtx.alphaTest.beforeModify();
|
||||
ah.deferAlphaTestToggle(false);
|
||||
return;
|
||||
}
|
||||
@@ -3532,6 +3615,9 @@ public class GLStateManager {
|
||||
final int mask = glCtx.attribs.popInt();
|
||||
glCtx.attribDepth--;
|
||||
|
||||
// Snapshot before the stacks pop, so applyRestoredState can tell whether vanilla blend actually moved.
|
||||
final boolean blendSnapshotted = (mask & (GL11.GL_COLOR_BUFFER_BIT | GL11.GL_ENABLE_BIT)) != 0 && snapshotVanillaBlendFunc();
|
||||
|
||||
// First: restore BooleanStateStack states that were actually modified (fast path)
|
||||
// These use lazy copy-on-write with global depth tracking
|
||||
final List<IStateStack<?>> modified = glCtx.modifiedAtDepth[glCtx.attribDepth];
|
||||
@@ -3550,7 +3636,12 @@ public class GLStateManager {
|
||||
|
||||
// Third: apply restored state to the GL driver. BooleanStateStacks already issue GL calls via setEnabled(); non-boolean stacks are pure data
|
||||
// containers, so we must explicitly drive GL here.
|
||||
applyRestoredState(mask);
|
||||
applyRestoredState(mask, blendSnapshotted);
|
||||
}
|
||||
|
||||
private static boolean isDepthColorOverridden() {
|
||||
final DeferredDepthColorHandler dch = GLSMHooks.depthColorHandler;
|
||||
return dch != null && dch.isOverrideHeld();
|
||||
}
|
||||
|
||||
private static void captureRestoreChanges(int mask) {
|
||||
@@ -3639,20 +3730,25 @@ public class GLStateManager {
|
||||
/**
|
||||
* After popping GLSM stacks, apply restored state to the GL driver.
|
||||
*/
|
||||
private static void applyRestoredState(int mask) {
|
||||
private static void applyRestoredState(int mask, boolean blendSnapshotted) {
|
||||
final GLContextState glCtx = ctx();
|
||||
if ((mask & GL11.GL_DEPTH_BUFFER_BIT) != 0 && glCtx.restoreDepthChanged) {
|
||||
RENDER_BACKEND.depthFunc(glCtx.depthState.getFunc());
|
||||
RENDER_BACKEND.depthMask(glCtx.depthState.isEnabled());
|
||||
if (!isDepthColorOverridden()) {
|
||||
RENDER_BACKEND.depthMask(glCtx.depthState.isEnabled());
|
||||
}
|
||||
RENDER_BACKEND.clearDepth(glCtx.depthState.getClearValue());
|
||||
}
|
||||
if ((mask & GL11.GL_COLOR_BUFFER_BIT) != 0) {
|
||||
if (glCtx.restoreBlendChanged) {
|
||||
RENDER_BACKEND.blendFuncSeparate(glCtx.blendState.getSrcRgb(), glCtx.blendState.getDstRgb(), glCtx.blendState.getSrcAlpha(), glCtx.blendState.getDstAlpha());
|
||||
final DeferredBlendHandler restoreBlendHandler = GLSMHooks.blendHandler;
|
||||
if (restoreBlendHandler == null || !restoreBlendHandler.isOverrideHeld()) {
|
||||
RENDER_BACKEND.blendFuncSeparate(glCtx.blendState.getSrcRgb(), glCtx.blendState.getDstRgb(), glCtx.blendState.getSrcAlpha(), glCtx.blendState.getDstAlpha());
|
||||
}
|
||||
RENDER_BACKEND.blendEquationSeparate(glCtx.blendState.getEquationRgb(), glCtx.blendState.getEquationAlpha());
|
||||
RENDER_BACKEND.blendColor(glCtx.blendState.getBlendColorR(), glCtx.blendState.getBlendColorG(), glCtx.blendState.getBlendColorB(), glCtx.blendState.getBlendColorA());
|
||||
}
|
||||
if (glCtx.restoreColorMaskChanged) {
|
||||
if (glCtx.restoreColorMaskChanged && !isDepthColorOverridden()) {
|
||||
RENDER_BACKEND.colorMask(glCtx.colorMask.red, glCtx.colorMask.green, glCtx.colorMask.blue, glCtx.colorMask.alpha);
|
||||
}
|
||||
if (glCtx.restoreClearColorChanged) {
|
||||
@@ -3737,6 +3833,8 @@ public class GLStateManager {
|
||||
glCtx.dirtyTexCoordAttrib = true;
|
||||
}
|
||||
}
|
||||
|
||||
postVanillaBlendChangeIfMoved(blendSnapshotted);
|
||||
}
|
||||
|
||||
public static void glClear(int mask) {
|
||||
@@ -4925,16 +5023,22 @@ public class GLStateManager {
|
||||
final ShaderManager ffp = ShaderManager.getInstance();
|
||||
if (program == 0 && ffp.isEnabled()) {
|
||||
final int prev = glCtx.activeProgram;
|
||||
final boolean caching = isCachingEnabled();
|
||||
if (prev != 0) glCtx.programGeneration++;
|
||||
final boolean changed = prev != 0;
|
||||
if (changed) glCtx.programGeneration++;
|
||||
glCtx.activeProgram = 0; // Track that FFP was requested
|
||||
if (GLSMHooks.PROGRAM_CHANGE.hasListeners()) {
|
||||
if (changed && GLSMHooks.PROGRAM_CHANGE.hasListeners()) {
|
||||
GLSMHooks.programChangeEvent.previousProgram = prev;
|
||||
GLSMHooks.programChangeEvent.newProgram = 0;
|
||||
GLSMHooks.programChangeEvent.postBind = false;
|
||||
GLSMHooks.PROGRAM_CHANGE.post(GLSMHooks.programChangeEvent);
|
||||
}
|
||||
ffp.activate();
|
||||
if (changed && GLSMHooks.PROGRAM_CHANGE.hasListeners()) {
|
||||
GLSMHooks.programChangeEvent.previousProgram = prev;
|
||||
GLSMHooks.programChangeEvent.newProgram = 0;
|
||||
GLSMHooks.programChangeEvent.postBind = true;
|
||||
GLSMHooks.PROGRAM_CHANGE.post(GLSMHooks.programChangeEvent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
public interface DeferredBlendHandler {
|
||||
boolean isBlendLocked();
|
||||
boolean isOverrideHeld();
|
||||
void deferBlendModeToggle(boolean enabled);
|
||||
void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha);
|
||||
void flushDeferredBlend();
|
||||
|
||||
+1
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
public interface DeferredDepthColorHandler {
|
||||
boolean isDepthColorLocked();
|
||||
boolean isOverrideHeld();
|
||||
void deferDepthEnable(boolean enabled);
|
||||
void deferColorMask(boolean r, boolean g, boolean b, boolean a);
|
||||
}
|
||||
@@ -6,6 +6,14 @@ public final class GLSMConfig {
|
||||
public static float lastBrightnessX;
|
||||
public static float lastBrightnessY;
|
||||
|
||||
public static int packBrightness(float x, float y) {
|
||||
return ((int) y << 16) | ((int) x & 0xFFFF);
|
||||
}
|
||||
|
||||
public static int packedLastBrightness() {
|
||||
return packBrightness(lastBrightnessX, lastBrightnessY);
|
||||
}
|
||||
|
||||
public static boolean hudCacheOverride;
|
||||
|
||||
public static volatile boolean expandVertexFormats;
|
||||
|
||||
@@ -25,6 +25,8 @@ public final class GLSMHooks {
|
||||
public static final EventBus<LightmapCoordsEvent> LIGHTMAP_COORDS = EventBus.create(LightmapCoordsEvent.class);
|
||||
public static final EventBus<AlphaStateChangeEvent> ALPHA_STATE_CHANGE = EventBus.create(AlphaStateChangeEvent.class);
|
||||
public static final EventBus<ShaderColorChangeEvent> SHADER_COLOR_CHANGE = EventBus.create(ShaderColorChangeEvent.class);
|
||||
public static final EventBus<ForeignDrawEndEvent> FOREIGN_DRAW_END = EventBus.create(ForeignDrawEndEvent.class);
|
||||
public static final EventBus<VanillaBlendChangeEvent> VANILLA_BLEND_CHANGE = EventBus.create(VanillaBlendChangeEvent.class);
|
||||
public static final EventBus<LoadingCheckpointEvent> LOADING_CHECKPOINT = EventBus.create(LoadingCheckpointEvent.class);
|
||||
|
||||
// Reusable event instances
|
||||
@@ -38,6 +40,8 @@ public final class GLSMHooks {
|
||||
public static final LightmapCoordsEvent lightmapCoordsEvent = new LightmapCoordsEvent();
|
||||
public static final AlphaStateChangeEvent alphaStateChangeEvent = new AlphaStateChangeEvent();
|
||||
public static final ShaderColorChangeEvent shaderColorChangeEvent = new ShaderColorChangeEvent();
|
||||
public static final ForeignDrawEndEvent foreignDrawEndEvent = new ForeignDrawEndEvent();
|
||||
public static final VanillaBlendChangeEvent vanillaBlendChangeEvent = new VanillaBlendChangeEvent();
|
||||
public static final LoadingCheckpointEvent loadingCheckpointEvent = new LoadingCheckpointEvent();
|
||||
|
||||
private GLSMHooks() {}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
public interface VanillaBooleanLayer {
|
||||
|
||||
boolean isOverrideHeld();
|
||||
boolean getVanilla();
|
||||
void setVanilla(boolean enabled);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks;
|
||||
|
||||
public interface VanillaStateLayer<T> {
|
||||
|
||||
boolean isOverrideHeld();
|
||||
void readVanilla(T into);
|
||||
void writeVanilla(T from);
|
||||
|
||||
static boolean isHeld(VanillaStateLayer<?> layer) {
|
||||
return layer != null && layer.isOverrideHeld();
|
||||
}
|
||||
|
||||
static <T> void capture(VanillaStateLayer<T> layer, T slot) {
|
||||
if (isHeld(layer)) layer.readVanilla(slot);
|
||||
}
|
||||
|
||||
static <T> boolean restore(VanillaStateLayer<T> layer, T saved) {
|
||||
if (!isHeld(layer)) return false;
|
||||
layer.writeVanilla(saved);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks.events;
|
||||
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class ForeignDrawEndEvent extends MutableEvent {
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks.events;
|
||||
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class VanillaBlendChangeEvent extends MutableEvent {
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package com.gtnewhorizons.angelica.glsm.stacks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import lombok.Setter;
|
||||
|
||||
public class AlphaStateStack extends AlphaState implements IStateStack<AlphaState> {
|
||||
|
||||
@@ -10,6 +12,8 @@ public class AlphaStateStack extends AlphaState implements IStateStack<AlphaStat
|
||||
|
||||
protected int pointer;
|
||||
|
||||
@Setter private VanillaStateLayer<AlphaState> vanillaLayer;
|
||||
|
||||
public AlphaStateStack() {
|
||||
stack = new AlphaState[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
|
||||
for (int i = 0; i < GLStateManager.MAX_ATTRIB_STACK_DEPTH; i++) {
|
||||
@@ -22,7 +26,7 @@ public class AlphaStateStack extends AlphaState implements IStateStack<AlphaStat
|
||||
throw new IllegalStateException("Stack overflow size " + (pointer + 1) + " reached");
|
||||
}
|
||||
|
||||
stack[pointer++].set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, stack[pointer++].set(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,10 +35,19 @@ public class AlphaStateStack extends AlphaState implements IStateStack<AlphaStat
|
||||
throw new IllegalStateException("Stack underflow");
|
||||
}
|
||||
|
||||
set(stack[--pointer]);
|
||||
final AlphaState saved = stack[--pointer];
|
||||
if (!VanillaStateLayer.restore(vanillaLayer, saved)) {
|
||||
set(saved);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlphaState readEffective(AlphaState out) {
|
||||
out.set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return pointer == 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.gtnewhorizons.angelica.glsm.stacks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import lombok.Setter;
|
||||
|
||||
public class BlendStateStack extends BlendState implements IStateStack<BlendStateStack> {
|
||||
|
||||
@@ -10,6 +12,8 @@ public class BlendStateStack extends BlendState implements IStateStack<BlendStat
|
||||
|
||||
protected int pointer;
|
||||
|
||||
@Setter private VanillaStateLayer<BlendState> vanillaLayer;
|
||||
|
||||
public BlendStateStack() {
|
||||
stack = new BlendState[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
|
||||
for (int i = 0; i < GLStateManager.MAX_ATTRIB_STACK_DEPTH; i++) {
|
||||
@@ -22,7 +26,7 @@ public class BlendStateStack extends BlendState implements IStateStack<BlendStat
|
||||
throw new IllegalStateException("Stack overflow size " + (pointer + 1) + " reached");
|
||||
}
|
||||
|
||||
stack[pointer++].set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, stack[pointer++].set(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,10 +35,21 @@ public class BlendStateStack extends BlendState implements IStateStack<BlendStat
|
||||
throw new IllegalStateException("Stack underflow");
|
||||
}
|
||||
|
||||
set(stack[--pointer]);
|
||||
final BlendState saved = stack[--pointer];
|
||||
if (VanillaStateLayer.restore(vanillaLayer, saved)) {
|
||||
setExceptFunc(saved);
|
||||
} else {
|
||||
set(saved);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlendState readEffective(BlendState out) {
|
||||
out.set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return pointer == 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.gtnewhorizons.angelica.glsm.stacks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaBooleanLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BooleanState;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* A stack for boolean GL state with lazy copy-on-write optimization.
|
||||
@@ -14,6 +16,7 @@ import com.gtnewhorizons.angelica.glsm.states.BooleanState;
|
||||
public class BooleanStateStack extends BooleanState implements IStateStack<BooleanStateStack> {
|
||||
|
||||
protected final boolean[] stack;
|
||||
@Setter private VanillaBooleanLayer vanillaLayer;
|
||||
|
||||
/**
|
||||
* The depth at which state has been saved. Compared against GLStateManager.getAttribDepth()
|
||||
@@ -56,7 +59,7 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
if (savedDepth >= stack.length) {
|
||||
throw new IllegalStateException("Stack overflow size " + (savedDepth + 1) + " reached");
|
||||
}
|
||||
stack[savedDepth++] = enabled;
|
||||
stack[savedDepth++] = vanillaValue();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -65,12 +68,26 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
if (savedDepth == 0) {
|
||||
throw new IllegalStateException("Stack underflow");
|
||||
}
|
||||
final boolean oldValue = stack[--savedDepth];
|
||||
// Call setEnabledDirect to avoid triggering beforeModify during restore
|
||||
setEnabledDirect(oldValue);
|
||||
restore(stack[--savedDepth]);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isEffectivelyEnabled() {
|
||||
return (vanillaLayer != null && vanillaLayer.isOverrideHeld()) ? vanillaLayer.getVanilla() : enabled;
|
||||
}
|
||||
|
||||
private boolean vanillaValue() {
|
||||
return isEffectivelyEnabled();
|
||||
}
|
||||
|
||||
private void restore(boolean value) {
|
||||
if (vanillaLayer != null && vanillaLayer.isOverrideHeld()) {
|
||||
vanillaLayer.setVanilla(value);
|
||||
} else {
|
||||
setEnabledDirect(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return savedDepth == 0;
|
||||
@@ -92,8 +109,7 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
public BooleanStateStack popDepth() {
|
||||
// We're only called if we were modified, so savedDepth should match
|
||||
if (savedDepth > 0) {
|
||||
final boolean oldValue = stack[--savedDepth];
|
||||
setEnabledDirect(oldValue);
|
||||
restore(stack[--savedDepth]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -106,7 +122,7 @@ public class BooleanStateStack extends BooleanState implements IStateStack<Boole
|
||||
public void beforeModify() {
|
||||
final int globalDepth = GLStateManager.getAttribDepth();
|
||||
if (savedDepth < globalDepth) {
|
||||
stack[savedDepth++] = enabled;
|
||||
stack[savedDepth++] = vanillaValue();
|
||||
GLStateManager.registerModifiedState(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.gtnewhorizons.angelica.glsm.stacks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ColorMask;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ColorMaskStack extends ColorMask implements IStateStack<ColorMaskStack> {
|
||||
|
||||
@@ -10,6 +12,8 @@ public class ColorMaskStack extends ColorMask implements IStateStack<ColorMaskSt
|
||||
|
||||
protected int pointer;
|
||||
|
||||
@Setter private VanillaStateLayer<ColorMask> vanillaLayer;
|
||||
|
||||
public ColorMaskStack() {
|
||||
stack = new ColorMask[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
|
||||
for (int i = 0; i < GLStateManager.MAX_ATTRIB_STACK_DEPTH; i++) {
|
||||
@@ -22,7 +26,7 @@ public class ColorMaskStack extends ColorMask implements IStateStack<ColorMaskSt
|
||||
throw new IllegalStateException("Stack overflow size " + (pointer + 1) + " reached");
|
||||
}
|
||||
|
||||
stack[pointer++].set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, stack[pointer++].set(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,7 +35,10 @@ public class ColorMaskStack extends ColorMask implements IStateStack<ColorMaskSt
|
||||
throw new IllegalStateException("Stack underflow");
|
||||
}
|
||||
|
||||
set(stack[--pointer]);
|
||||
final ColorMask saved = stack[--pointer];
|
||||
if (!VanillaStateLayer.restore(vanillaLayer, saved)) {
|
||||
set(saved);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.gtnewhorizons.angelica.glsm.stacks;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.stacks.IStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.DepthState;
|
||||
import lombok.Setter;
|
||||
|
||||
public class DepthStateStack extends DepthState implements IStateStack<DepthStateStack> {
|
||||
|
||||
@@ -10,6 +12,10 @@ public class DepthStateStack extends DepthState implements IStateStack<DepthStat
|
||||
|
||||
protected int pointer;
|
||||
|
||||
@Setter private VanillaStateLayer<DepthState> vanillaLayer;
|
||||
|
||||
private final DepthState effective = new DepthState();
|
||||
|
||||
public DepthStateStack() {
|
||||
stack = new DepthState[GLStateManager.MAX_ATTRIB_STACK_DEPTH];
|
||||
for (int i = 0; i < GLStateManager.MAX_ATTRIB_STACK_DEPTH; i++) {
|
||||
@@ -22,7 +28,7 @@ public class DepthStateStack extends DepthState implements IStateStack<DepthStat
|
||||
throw new IllegalStateException("Stack overflow size " + (pointer + 1) + " reached");
|
||||
}
|
||||
|
||||
stack[pointer++].set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, stack[pointer++].set(this));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,10 +37,21 @@ public class DepthStateStack extends DepthState implements IStateStack<DepthStat
|
||||
throw new IllegalStateException("Stack underflow");
|
||||
}
|
||||
|
||||
set(stack[--pointer]);
|
||||
final DepthState saved = stack[--pointer];
|
||||
if (VanillaStateLayer.restore(vanillaLayer, saved)) {
|
||||
setExceptMask(saved);
|
||||
} else {
|
||||
set(saved);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isEffectiveMaskEnabled() {
|
||||
if (!VanillaStateLayer.isHeld(vanillaLayer)) return isEnabled();
|
||||
vanillaLayer.readVanilla(effective);
|
||||
return effective.isEnabled();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return pointer == 0;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,15 @@ public class BlendState implements ISettableState<BlendState> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setExceptFunc(BlendState state) {
|
||||
final int sRgb = srcRgb, dRgb = dstRgb, sAlpha = srcAlpha, dAlpha = dstAlpha;
|
||||
set(state);
|
||||
this.srcRgb = sRgb;
|
||||
this.dstRgb = dRgb;
|
||||
this.srcAlpha = sAlpha;
|
||||
this.dstAlpha = dAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sameAs(Object state) {
|
||||
if (this == state) return true;
|
||||
|
||||
@@ -18,6 +18,12 @@ public class DepthState implements ISettableState<DepthState> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setExceptMask(DepthState state) {
|
||||
final boolean mask = enabled;
|
||||
set(state);
|
||||
this.enabled = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sameAs(Object state) {
|
||||
if (this == state) return true;
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class TessellatorStreamingDrawer {
|
||||
|
||||
final int defaultBrightness;
|
||||
if (!tess.hasBrightness) {
|
||||
defaultBrightness = ((int) GLSMConfig.lastBrightnessY << 16) | ((int) GLSMConfig.lastBrightnessX & 0xFFFF);
|
||||
defaultBrightness = GLSMConfig.packedLastBrightness();
|
||||
} else {
|
||||
defaultBrightness = 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FFPVertexLighting;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.PersistentStreamingBuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import com.gtnewhorizons.angelica.hudcaching.HUDCaching;
|
||||
@@ -17,9 +19,15 @@ import com.gtnewhorizons.angelica.rendering.tesr.ModelPartBatcher;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrBatchRenderer;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Setter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.PipelineManager;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
@@ -41,6 +49,8 @@ import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryStack.stackPush;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetByte;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memGetFloat;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutByte;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutFloat;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memPutShort;
|
||||
@@ -87,6 +97,7 @@ public class BatchingFontRenderer {
|
||||
private static class FontAAShader {
|
||||
|
||||
private static Program fontShader = null;
|
||||
|
||||
public static Program getProgram() {
|
||||
if (fontShader == null) {
|
||||
final String vsh = ShaderLoader.getShaderSource("angelica:fontFilter.vsh");
|
||||
@@ -172,6 +183,9 @@ public class BatchingFontRenderer {
|
||||
private int blendSrcRGB = GL11.GL_SRC_ALPHA;
|
||||
private int blendDstRGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
|
||||
private final BlendState blendStateBefore = new BlendState();
|
||||
private static final BlendState deferredBlendStateBefore = new BlendState();
|
||||
|
||||
private float lightmapU = 0.0f;
|
||||
private float lightmapV = 0.0f;
|
||||
private boolean lightmapActive = false;
|
||||
@@ -217,6 +231,7 @@ public class BatchingFontRenderer {
|
||||
|
||||
private static final class TextSegment {
|
||||
final Matrix4f mvp = new Matrix4f();
|
||||
final Matrix4f modelView = new Matrix4f();
|
||||
BatchingFontRenderer owner;
|
||||
int cmdStart;
|
||||
int cmdEnd;
|
||||
@@ -224,6 +239,9 @@ public class BatchingFontRenderer {
|
||||
float lightmapV;
|
||||
boolean lightmapActive;
|
||||
int lightmapTexture;
|
||||
int packedLight;
|
||||
float normalX, normalY, normalZ;
|
||||
int blockEntityId;
|
||||
}
|
||||
|
||||
// 16-bit EBO index range
|
||||
@@ -235,7 +253,6 @@ public class BatchingFontRenderer {
|
||||
private int deferredCmdWatermark;
|
||||
private static final ObjectArrayList<TextSegment> deferredSegments = ObjectArrayList.wrap(new TextSegment[16], 0);
|
||||
private static final ObjectArrayList<TextSegment> deferredSegmentPool = ObjectArrayList.wrap(new TextSegment[16], 0);
|
||||
private boolean deferCurrentBatch;
|
||||
|
||||
private final Matrix4f batchProj = new Matrix4f();
|
||||
private final Matrix4f batchModelView = new Matrix4f();
|
||||
@@ -467,6 +484,10 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveModelView(Matrix4f dest) {
|
||||
dest.set(batchMatrixValid ? batchModelView : GLStateManager.getModelViewMatrix());
|
||||
}
|
||||
|
||||
private void sealBatchSegment() {
|
||||
final int end = batchCommands.size();
|
||||
if (end == batchSealedEnd) return;
|
||||
@@ -475,10 +496,17 @@ public class BatchingFontRenderer {
|
||||
segment.cmdStart = batchSealedEnd;
|
||||
segment.cmdEnd = end;
|
||||
resolveMvp(segment.mvp);
|
||||
resolveModelView(segment.modelView);
|
||||
segment.lightmapActive = lightmapActive;
|
||||
segment.lightmapU = lightmapU;
|
||||
segment.lightmapV = lightmapV;
|
||||
segment.lightmapTexture = lightmapTextureId;
|
||||
segment.packedLight = GLSMConfig.packedLastBrightness();
|
||||
final Vector3f normal = ShaderManager.getCurrentNormal();
|
||||
segment.normalX = normal.x;
|
||||
segment.normalY = normal.y;
|
||||
segment.normalZ = normal.z;
|
||||
segment.blockEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
batchSegments.add(segment);
|
||||
batchSealedEnd = end;
|
||||
}
|
||||
@@ -499,27 +527,29 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
batchDepth--;
|
||||
if (batchDepth == 0) {
|
||||
// We finished any nested batches
|
||||
flushBatch();
|
||||
// We finished any nested batches.
|
||||
if (shouldDeferNow()) {
|
||||
deferBatch();
|
||||
} else {
|
||||
flushBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldDeferNow() {
|
||||
if (!GLStateManager.isMainThread()) return false;
|
||||
return TesrBatchRenderer.INSTANCE.hasPendingGeometry() || ModelPartBatcher.INSTANCE.isActive();
|
||||
}
|
||||
|
||||
public void beginDeferredBatch() {
|
||||
deferCurrentBatch = batchDepth == 0 && TesrBatchRenderer.INSTANCE.hasActivePass() || ModelPartBatcher.INSTANCE.isActive();
|
||||
if (deferCurrentBatch && deferredIdxPos / 6 > QUAD_BUDGET / 2) {
|
||||
if (batchDepth == 0 && shouldDeferNow() && deferredIdxPos / 6 > QUAD_BUDGET / 2) {
|
||||
flushDeferredText();
|
||||
}
|
||||
beginBatch();
|
||||
}
|
||||
|
||||
public void endDeferredBatch() {
|
||||
if (deferCurrentBatch && batchDepth == 1) {
|
||||
deferCurrentBatch = false;
|
||||
batchDepth = 0;
|
||||
deferBatch();
|
||||
} else {
|
||||
endBatch();
|
||||
}
|
||||
endBatch();
|
||||
}
|
||||
|
||||
private void deferBatch() {
|
||||
@@ -544,38 +574,123 @@ public class BatchingFontRenderer {
|
||||
public static void flushDeferredText() {
|
||||
if (deferredSegments.isEmpty()) return;
|
||||
|
||||
if (deferredSegments.getFirst().owner.shouldDrawThroughPipeline()) {
|
||||
flushDeferredThroughPipeline();
|
||||
return;
|
||||
}
|
||||
|
||||
GLStateManager.beginForeignDraw();
|
||||
try {
|
||||
flushDeferredTextInner();
|
||||
} finally {
|
||||
GLStateManager.endForeignDraw();
|
||||
}
|
||||
}
|
||||
|
||||
private static void flushDeferredThroughPipeline() {
|
||||
final BatchingFontRenderer first = deferredSegments.getFirst().owner;
|
||||
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.isEffectiveBlendEnabled();
|
||||
final boolean isAlphaTestEnabledBefore = GLStateManager.isEffectiveAlphaTestEnabled();
|
||||
GLStateManager.getEffectiveBlendState(deferredBlendStateBefore);
|
||||
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final boolean depthMaskBefore = GLStateManager.isEffectiveDepthMaskEnabled();
|
||||
final int prevBlockEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
boolean textureChanged = false;
|
||||
|
||||
GLStateManager.enableTexture();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(first.blendSrcRGB, first.blendDstRGB, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.glDepthMask(false);
|
||||
|
||||
final Boolean prevTranslucency = GbufferPrograms.beginTranslucencyDeclaration(Boolean.TRUE);
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
try {
|
||||
for (final TextSegment segment : deferredSegments) {
|
||||
final BatchingFontRenderer owner = segment.owner;
|
||||
if (segment.cmdStart == segment.cmdEnd) continue;
|
||||
|
||||
GLStateManager.setModelViewMatrix(segment.modelView);
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(segment.blockEntityId);
|
||||
|
||||
final FontDrawCmd[] cmdsData = owner.batchCommands.elements();
|
||||
Arrays.sort(cmdsData, segment.cmdStart, segment.cmdEnd, FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
|
||||
textureChanged |= emitRangeThroughPipeline(owner, cmdsData, segment.cmdStart, segment.cmdEnd,
|
||||
segment.packedLight, segment.normalX, segment.normalY, segment.normalZ);
|
||||
}
|
||||
} finally {
|
||||
GLStateManager.glPopMatrix();
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(prevBlockEntityId);
|
||||
GbufferPrograms.endTranslucencyDeclaration(prevTranslucency);
|
||||
|
||||
GLStateManager.glDepthMask(depthMaskBefore);
|
||||
if (isTextureEnabledBefore) {
|
||||
GLStateManager.enableTexture();
|
||||
} else {
|
||||
GLStateManager.disableTexture();
|
||||
}
|
||||
if (isBlendEnabledBefore) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
GLStateManager.tryBlendFuncSeparate(deferredBlendStateBefore.getSrcRgb(), deferredBlendStateBefore.getDstRgb(),
|
||||
deferredBlendStateBefore.getSrcAlpha(), deferredBlendStateBefore.getDstAlpha());
|
||||
if (isAlphaTestEnabledBefore) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
if (textureChanged) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, boundTextureBefore);
|
||||
}
|
||||
discardDeferredText();
|
||||
}
|
||||
}
|
||||
|
||||
private static void flushDeferredTextInner() {
|
||||
uploadVertexData(deferredVertexPos);
|
||||
|
||||
final int prevProgram = GLStateManager.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_BLEND);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.isEffectiveBlendEnabled();
|
||||
final boolean isAlphaTestEnabledBefore = GLStateManager.isEffectiveAlphaTestEnabled();
|
||||
GLStateManager.getEffectiveBlendState(deferredBlendStateBefore);
|
||||
final int shadeModelBefore = GLStateManager.glGetInteger(GL11.GL_SHADE_MODEL);
|
||||
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int lightmapBindingBefore = boundLightmapTexture();
|
||||
|
||||
final boolean depthTestBefore = GLStateManager.getDepthTest().isEnabled();
|
||||
final boolean depthMaskBefore = GLStateManager.getDepthState().isEnabled();
|
||||
final boolean depthMaskBefore = GLStateManager.isEffectiveDepthMaskEnabled();
|
||||
|
||||
deferredSegments.get(0).owner.setupFontDrawState();
|
||||
GLStateManager.glDepthMask(false);
|
||||
flushLastTexture = DUMMY_RESOURCE_LOCATION;
|
||||
flushTextureChanged = false;
|
||||
resetFlushLightmap();
|
||||
try (MemoryStack stack = stackPush()) {
|
||||
final FloatBuffer mvpBuf = stack.mallocFloat(16);
|
||||
for (int i = 0, n = deferredSegments.size(); i < n; i++) {
|
||||
final TextSegment segment = deferredSegments.get(i);
|
||||
mvpBuf.clear();
|
||||
segment.mvp.get(mvpBuf);
|
||||
GLStateManager.glUniformMatrix4(segment.owner.mvpMatrixLocation, false, mvpBuf);
|
||||
uploadLightmap(segment.owner.lightmapLocation, segment.lightmapActive, segment.lightmapU,
|
||||
segment.lightmapV, segment.lightmapTexture);
|
||||
drawCommands(segment.owner.batchCommands.elements(), segment.cmdStart, segment.cmdEnd, segment.owner);
|
||||
try {
|
||||
try (MemoryStack stack = stackPush()) {
|
||||
final FloatBuffer mvpBuf = stack.mallocFloat(16);
|
||||
for (final TextSegment segment : deferredSegments) {
|
||||
mvpBuf.clear();
|
||||
segment.mvp.get(mvpBuf);
|
||||
GLStateManager.glUniformMatrix4(segment.owner.mvpMatrixLocation, false, mvpBuf);
|
||||
uploadLightmap(segment.owner.lightmapLocation, segment.lightmapActive, segment.lightmapU,
|
||||
segment.lightmapV, segment.lightmapTexture);
|
||||
drawCommands(segment.owner.batchCommands.elements(), segment.cmdStart, segment.cmdEnd, segment.owner);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
restoreFontDrawState(prevProgram, isTextureEnabledBefore, isBlendEnabledBefore, boundTextureBefore,
|
||||
lightmapBindingBefore, isAlphaTestEnabledBefore, deferredBlendStateBefore, shadeModelBefore);
|
||||
restoreDepth(depthTestBefore, depthMaskBefore);
|
||||
discardDeferredText();
|
||||
}
|
||||
restoreFontDrawState(prevProgram, isTextureEnabledBefore, isBlendEnabledBefore, boundTextureBefore, lightmapBindingBefore);
|
||||
restoreDepth(depthTestBefore, depthMaskBefore);
|
||||
|
||||
discardDeferredText();
|
||||
}
|
||||
|
||||
public static void discardDeferredText() {
|
||||
@@ -614,18 +729,47 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
|
||||
private static final Matrix4f scratchMvp = new Matrix4f();
|
||||
private static final Matrix4f scratchModelView = new Matrix4f();
|
||||
private int fontAAModeLast = -1;
|
||||
private int fontAAStrengthLast = -1;
|
||||
|
||||
private void flushBatch() {
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
flushBatchInner();
|
||||
if (shouldDrawThroughPipeline()) {
|
||||
flushBatchThroughPipeline();
|
||||
} else {
|
||||
GLStateManager.beginForeignDraw();
|
||||
try {
|
||||
flushBatchInner();
|
||||
} finally {
|
||||
GLStateManager.endForeignDraw();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldDrawThroughPipeline() {
|
||||
if (FontConfig.fontAAMode != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GLStateManager.isMainThread()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PipelineManager pipelines = Iris.getPipelineManagerNullable();
|
||||
if (pipelines == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Tessellator.instance.isDrawing
|
||||
&& pipelines.getPipelineNullable() instanceof DeferredWorldRenderingPipeline drp
|
||||
&& drp.shouldOverrideShaders();
|
||||
}
|
||||
|
||||
private void flushBatchInner() {
|
||||
final int cmdCount = batchCommands.size();
|
||||
final int segmentCount = batchSegments.size();
|
||||
@@ -646,11 +790,14 @@ public class BatchingFontRenderer {
|
||||
Arrays.sort(cmds, batchSealedEnd, cmdCount, FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
|
||||
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_BLEND);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.isEffectiveBlendEnabled();
|
||||
final boolean isAlphaTestEnabledBefore = GLStateManager.isEffectiveAlphaTestEnabled();
|
||||
GLStateManager.getEffectiveBlendState(blendStateBefore);
|
||||
final int shadeModelBefore = GLStateManager.glGetInteger(GL11.GL_SHADE_MODEL);
|
||||
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int lightmapBindingBefore = boundLightmapTexture();
|
||||
final boolean depthTestBefore = GLStateManager.getDepthTest().isEnabled();
|
||||
final boolean depthMaskBefore = GLStateManager.getDepthState().isEnabled();
|
||||
final boolean depthMaskBefore = GLStateManager.isEffectiveDepthMaskEnabled();
|
||||
|
||||
setupFontDrawState();
|
||||
flushLastTexture = DUMMY_RESOURCE_LOCATION;
|
||||
@@ -675,7 +822,8 @@ public class BatchingFontRenderer {
|
||||
drawCommands(cmds, batchSealedEnd, cmdCount, this);
|
||||
}
|
||||
}
|
||||
restoreFontDrawState(prevProgram, isTextureEnabledBefore, isBlendEnabledBefore, boundTextureBefore, lightmapBindingBefore);
|
||||
restoreFontDrawState(prevProgram, isTextureEnabledBefore, isBlendEnabledBefore, boundTextureBefore,
|
||||
lightmapBindingBefore, isAlphaTestEnabledBefore, blendStateBefore, shadeModelBefore);
|
||||
restoreDepth(depthTestBefore, depthMaskBefore);
|
||||
|
||||
truncateBatchToWatermark();
|
||||
@@ -783,7 +931,9 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void restoreFontDrawState(int prevProgram, boolean textureEnabledBefore, boolean blendEnabledBefore, int boundTextureBefore, int lightmapBindingBefore) {
|
||||
private static void restoreFontDrawState(int prevProgram, boolean textureEnabledBefore, boolean blendEnabledBefore,
|
||||
int boundTextureBefore, int lightmapBindingBefore, boolean alphaTestEnabledBefore, BlendState blendBefore,
|
||||
int shadeModelBefore) {
|
||||
GLStateManager.glUseProgram(prevProgram);
|
||||
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
@@ -792,9 +942,19 @@ public class BatchingFontRenderer {
|
||||
if (textureEnabledBefore) {
|
||||
GLStateManager.glEnable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
if (!blendEnabledBefore) {
|
||||
if (blendEnabledBefore) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
GLStateManager.tryBlendFuncSeparate(blendBefore.getSrcRgb(), blendBefore.getDstRgb(),
|
||||
blendBefore.getSrcAlpha(), blendBefore.getDstAlpha());
|
||||
if (alphaTestEnabledBefore) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
GLStateManager.glShadeModel(shadeModelBefore);
|
||||
if (flushTextureChanged) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, boundTextureBefore);
|
||||
}
|
||||
@@ -803,11 +963,156 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private void flushBatchThroughPipeline() {
|
||||
final int cmdCount = batchCommands.size();
|
||||
final int segmentCount = batchSegments.size();
|
||||
if (segmentCount == 0 && (vertexDataPos == deferredVertexPos || cmdCount == deferredCmdWatermark)) {
|
||||
truncateBatchToWatermark();
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
|
||||
final boolean isBlendEnabledBefore = GLStateManager.isEffectiveBlendEnabled();
|
||||
final boolean isAlphaTestEnabledBefore = GLStateManager.isEffectiveAlphaTestEnabled();
|
||||
GLStateManager.getEffectiveBlendState(blendStateBefore);
|
||||
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int prevBlockEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
boolean textureChanged = false;
|
||||
|
||||
GLStateManager.enableTexture();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(blendSrcRGB, blendDstRGB, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
|
||||
final Boolean prevTranslucency = GbufferPrograms.beginTranslucencyDeclaration(Boolean.TRUE);
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
final FontDrawCmd[] cmdsData = batchCommands.elements();
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
final TextSegment segment = batchSegments.get(i);
|
||||
Arrays.sort(cmdsData, segment.cmdStart, segment.cmdEnd, FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
}
|
||||
Arrays.sort(cmdsData, batchSealedEnd, cmdCount, FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
|
||||
// The unsealed tail still belongs to the modelview live at flush time; capture it before the segments move it.
|
||||
resolveModelView(scratchModelView);
|
||||
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
try {
|
||||
for (int i = 0; i < segmentCount; i++) {
|
||||
final TextSegment segment = batchSegments.get(i);
|
||||
if (segment.cmdStart == segment.cmdEnd) continue;
|
||||
GLStateManager.setModelViewMatrix(segment.modelView);
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(segment.blockEntityId);
|
||||
textureChanged |= emitRangeThroughPipeline(this, cmdsData, segment.cmdStart, segment.cmdEnd,
|
||||
segment.packedLight, segment.normalX, segment.normalY, segment.normalZ);
|
||||
}
|
||||
if (batchSealedEnd < cmdCount) {
|
||||
GLStateManager.setModelViewMatrix(scratchModelView);
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(prevBlockEntityId);
|
||||
final Vector3f normal = ShaderManager.getCurrentNormal();
|
||||
textureChanged |= emitRangeThroughPipeline(this, cmdsData, batchSealedEnd, cmdCount,
|
||||
GLSMConfig.packedLastBrightness(), normal.x, normal.y, normal.z);
|
||||
}
|
||||
} finally {
|
||||
GLStateManager.glPopMatrix();
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(prevBlockEntityId);
|
||||
GbufferPrograms.endTranslucencyDeclaration(prevTranslucency);
|
||||
|
||||
if (isTextureEnabledBefore) {
|
||||
GLStateManager.enableTexture();
|
||||
} else {
|
||||
GLStateManager.disableTexture();
|
||||
}
|
||||
if (isBlendEnabledBefore) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
GLStateManager.tryBlendFuncSeparate(blendStateBefore.getSrcRgb(), blendStateBefore.getDstRgb(),
|
||||
blendStateBefore.getSrcAlpha(), blendStateBefore.getDstAlpha());
|
||||
if (isAlphaTestEnabledBefore) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
if (textureChanged) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, boundTextureBefore);
|
||||
}
|
||||
|
||||
truncateBatchToWatermark();
|
||||
}
|
||||
}
|
||||
|
||||
/** Replays one sealed command range through the Tessellator so Iris sees it as ordinary geometry. */
|
||||
private static boolean emitRangeThroughPipeline(BatchingFontRenderer owner, FontDrawCmd[] cmdsData, int from, int to,
|
||||
int packedLight, float normalX, float normalY, float normalZ) {
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
ResourceLocation lastTexture = DUMMY_RESOURCE_LOCATION;
|
||||
boolean textureChanged = false;
|
||||
boolean drawing = false;
|
||||
try {
|
||||
for (int i = from; i < to; i++) {
|
||||
final FontDrawCmd cmd = cmdsData[i];
|
||||
if (!Objects.equals(lastTexture, cmd.texture)) {
|
||||
if (drawing) {
|
||||
tessellator.draw();
|
||||
drawing = false;
|
||||
}
|
||||
if (cmd.texture == null) {
|
||||
GLStateManager.disableTexture();
|
||||
} else {
|
||||
GLStateManager.enableTexture();
|
||||
((FontRendererAccessor) owner.underlying).angelica$bindTexture(cmd.texture);
|
||||
textureChanged = true;
|
||||
}
|
||||
lastTexture = cmd.texture;
|
||||
}
|
||||
if (!drawing) {
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setBrightness(packedLight);
|
||||
tessellator.setNormal(normalX, normalY, normalZ);
|
||||
drawing = true;
|
||||
}
|
||||
owner.emitCommand(tessellator, cmd);
|
||||
}
|
||||
} finally {
|
||||
if (drawing) {
|
||||
tessellator.draw();
|
||||
}
|
||||
}
|
||||
return textureChanged;
|
||||
}
|
||||
|
||||
private void emitCommand(Tessellator tessellator, FontDrawCmd cmd) {
|
||||
final int firstVertex = cmd.startVtx / 6 * 4;
|
||||
final int quadCount = cmd.idxCount / 6;
|
||||
|
||||
for (int q = 0; q < quadCount; q++) {
|
||||
final long base = vertexDataAddress + (long) (firstVertex + q * 4) * VERTEX_SIZE;
|
||||
emitVertex(tessellator, base);
|
||||
emitVertex(tessellator, base + VERTEX_SIZE);
|
||||
emitVertex(tessellator, base + 3L * VERTEX_SIZE);
|
||||
emitVertex(tessellator, base + 2L * VERTEX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitVertex(Tessellator tessellator, long ptr) {
|
||||
tessellator.setColorRGBA(
|
||||
memGetByte(ptr + 16) & 0xFF,
|
||||
memGetByte(ptr + 17) & 0xFF,
|
||||
memGetByte(ptr + 18) & 0xFF,
|
||||
memGetByte(ptr + 19) & 0xFF);
|
||||
tessellator.addVertexWithUV(memGetFloat(ptr), memGetFloat(ptr + 4), 0.0D,
|
||||
memGetFloat(ptr + 8), memGetFloat(ptr + 12));
|
||||
}
|
||||
|
||||
private static void restoreDepth(boolean testBefore, boolean maskBefore) {
|
||||
if (testBefore != GLStateManager.getDepthTest().isEnabled()) {
|
||||
if (testBefore) GLStateManager.enableDepthTest(); else GLStateManager.disableDepthTest();
|
||||
}
|
||||
if (maskBefore != GLStateManager.getDepthState().isEnabled()) {
|
||||
if (maskBefore != GLStateManager.isEffectiveDepthMaskEnabled()) {
|
||||
GLStateManager.glDepthMask(maskBefore);
|
||||
}
|
||||
}
|
||||
@@ -865,7 +1170,7 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
|
||||
private static int hsvToRgb(float hue, float sat, float val) {
|
||||
int h = (int)(hue / 60f) % 6;
|
||||
int h = (int) (hue / 60f) % 6;
|
||||
float f = hue / 60f - h;
|
||||
float p = val * (1 - sat);
|
||||
float q = val * (1 - f * sat);
|
||||
@@ -879,11 +1184,12 @@ public class BatchingFontRenderer {
|
||||
case 4: r=t; g=p; b=val; break;
|
||||
default: r=val; g=p; b=q; break;
|
||||
}
|
||||
return ((int)(r*255) << 16) | ((int)(g*255) << 8) | (int)(b*255);
|
||||
return ((int) (r * 255) << 16) | ((int) (g * 255) << 8) | (int) (b * 255);
|
||||
}
|
||||
|
||||
private static final int RAINBOW_LUT_SIZE = 24;
|
||||
private static final int[] RAINBOW_LUT = new int[RAINBOW_LUT_SIZE];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < RAINBOW_LUT_SIZE; i++) {
|
||||
RAINBOW_LUT[i] = hsvToRgb(i * 15f, 1f, 1f);
|
||||
@@ -918,7 +1224,7 @@ public class BatchingFontRenderer {
|
||||
private static final float WAVE_FREQUENCY = 0.5f;
|
||||
|
||||
public float drawString(final float anchorX, final float anchorY, final int color, final boolean enableShadow,
|
||||
final boolean unicodeFlag, final CharSequence string, int stringOffset, int stringLength) {
|
||||
final boolean unicodeFlag, final CharSequence string, int stringOffset, int stringLength) {
|
||||
// noinspection SizeReplaceableByIsEmpty
|
||||
if (string == null || string.length() == 0) {
|
||||
return anchorX + (enableShadow ? 1.0f : 0.0f);
|
||||
@@ -1007,86 +1313,86 @@ public class BatchingFontRenderer {
|
||||
charIdx += SECTION_X_PAYLOAD;
|
||||
}
|
||||
} else {
|
||||
final boolean is09 = charInRange(fmtCode, '0', '9');
|
||||
final boolean isAF = charInRange(fmtCode, 'a', 'f');
|
||||
if (is09 || isAF) {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
curRainbow = false;
|
||||
curGradient = false;
|
||||
// wave/dinnerbone NOT reset — they're positional effects, independent of color
|
||||
|
||||
final int colorIdx = is09 ? (fmtCode - '0') : (fmtCode - 'a' + 10);
|
||||
final int rgb = this.colorCode[colorIdx];
|
||||
curColor = (curColor & 0xFF000000) | (rgb & 0x00FFFFFF);
|
||||
final int shadowRgb = this.colorCode[colorIdx + 16];
|
||||
curShadowColor = (curShadowColor & 0xFF000000) | (shadowRgb & 0x00FFFFFF);
|
||||
} else if (fmtCode == 'k') {
|
||||
curRandom = true;
|
||||
} else if (fmtCode == 'l') {
|
||||
curBold = true;
|
||||
} else if (fmtCode == 'm') {
|
||||
curStrikethrough = true;
|
||||
strikethroughStartX = curX - 1.0f;
|
||||
strikethroughEndX = strikethroughStartX;
|
||||
} else if (fmtCode == 'n') {
|
||||
curUnderline = true;
|
||||
underlineStartX = curX - 1.0f;
|
||||
underlineEndX = underlineStartX;
|
||||
} else if (fmtCode == 'o') {
|
||||
curItalic = true;
|
||||
} else if (fmtCode == 'q' && AngelicaConfig.enableRainbow) {
|
||||
curRainbow = true;
|
||||
curGradient = false;
|
||||
rainbowCharIndex = 0;
|
||||
} else if (fmtCode == 'z' && AngelicaConfig.enableWaveText) {
|
||||
curWave = !curWave;
|
||||
} else if (fmtCode == 'v' && AngelicaConfig.enableDinnerboneText) {
|
||||
curDinnerbone = !curDinnerbone;
|
||||
} else if (fmtCode == 'u' && AngelicaConfig.enableDropShadow) {
|
||||
int customRgb = (charIdx + SECTION_X_LENGTH < stringEnd)
|
||||
? ColorCodeUtils.parseSectionXAt(string, charIdx + 1)
|
||||
: -1;
|
||||
if (customRgb != -1) {
|
||||
curShadow = true;
|
||||
curShadowCustomColor = true;
|
||||
curShadowColorOverride = customRgb;
|
||||
charIdx += SECTION_X_LENGTH;
|
||||
} else {
|
||||
curShadow = !curShadow;
|
||||
if (!curShadow) curShadowCustomColor = false;
|
||||
}
|
||||
} else if (fmtCode == 'g' && AngelicaConfig.enableGradients && charIdx + GRADIENT_PAYLOAD < stringEnd) {
|
||||
int color1 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1);
|
||||
int color2 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1 + SECTION_X_LENGTH);
|
||||
if (color1 != -1 && color2 != -1) {
|
||||
curGradient = true;
|
||||
final boolean is09 = charInRange(fmtCode, '0', '9');
|
||||
final boolean isAF = charInRange(fmtCode, 'a', 'f');
|
||||
if (is09 || isAF) {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
curRainbow = false;
|
||||
gradientStartRgb = color1;
|
||||
gradientEndRgb = color2;
|
||||
gradientCharIndex = 0;
|
||||
gradientTotalChars = countVisibleChars(string, charIdx + 1 + GRADIENT_PAYLOAD, stringEnd);
|
||||
gradientStep = gradientTotalChars > 1 ? 1f / (gradientTotalChars - 1) : 0f;
|
||||
charIdx += GRADIENT_PAYLOAD;
|
||||
curGradient = false;
|
||||
// wave/dinnerbone NOT reset — they're positional effects, independent of color
|
||||
|
||||
final int colorIdx = is09 ? (fmtCode - '0') : (fmtCode - 'a' + 10);
|
||||
final int rgb = this.colorCode[colorIdx];
|
||||
curColor = (curColor & 0xFF000000) | (rgb & 0x00FFFFFF);
|
||||
final int shadowRgb = this.colorCode[colorIdx + 16];
|
||||
curShadowColor = (curShadowColor & 0xFF000000) | (shadowRgb & 0x00FFFFFF);
|
||||
} else if (fmtCode == 'k') {
|
||||
curRandom = true;
|
||||
} else if (fmtCode == 'l') {
|
||||
curBold = true;
|
||||
} else if (fmtCode == 'm') {
|
||||
curStrikethrough = true;
|
||||
strikethroughStartX = curX - 1.0f;
|
||||
strikethroughEndX = strikethroughStartX;
|
||||
} else if (fmtCode == 'n') {
|
||||
curUnderline = true;
|
||||
underlineStartX = curX - 1.0f;
|
||||
underlineEndX = underlineStartX;
|
||||
} else if (fmtCode == 'o') {
|
||||
curItalic = true;
|
||||
} else if (fmtCode == 'q' && AngelicaConfig.enableRainbow) {
|
||||
curRainbow = true;
|
||||
curGradient = false;
|
||||
rainbowCharIndex = 0;
|
||||
} else if (fmtCode == 'z' && AngelicaConfig.enableWaveText) {
|
||||
curWave = !curWave;
|
||||
} else if (fmtCode == 'v' && AngelicaConfig.enableDinnerboneText) {
|
||||
curDinnerbone = !curDinnerbone;
|
||||
} else if (fmtCode == 'u' && AngelicaConfig.enableDropShadow) {
|
||||
int customRgb = (charIdx + SECTION_X_LENGTH < stringEnd)
|
||||
? ColorCodeUtils.parseSectionXAt(string, charIdx + 1)
|
||||
: -1;
|
||||
if (customRgb != -1) {
|
||||
curShadow = true;
|
||||
curShadowCustomColor = true;
|
||||
curShadowColorOverride = customRgb;
|
||||
charIdx += SECTION_X_LENGTH;
|
||||
} else {
|
||||
curShadow = !curShadow;
|
||||
if (!curShadow) curShadowCustomColor = false;
|
||||
}
|
||||
} else if (fmtCode == 'g' && AngelicaConfig.enableGradients && charIdx + GRADIENT_PAYLOAD < stringEnd) {
|
||||
int color1 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1);
|
||||
int color2 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1 + SECTION_X_LENGTH);
|
||||
if (color1 != -1 && color2 != -1) {
|
||||
curGradient = true;
|
||||
curRainbow = false;
|
||||
gradientStartRgb = color1;
|
||||
gradientEndRgb = color2;
|
||||
gradientCharIndex = 0;
|
||||
gradientTotalChars = countVisibleChars(string, charIdx + 1 + GRADIENT_PAYLOAD, stringEnd);
|
||||
gradientStep = gradientTotalChars > 1 ? 1f / (gradientTotalChars - 1) : 0f;
|
||||
charIdx += GRADIENT_PAYLOAD;
|
||||
}
|
||||
} else if (fmtCode == 'r') {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
curRainbow = false;
|
||||
curWave = false;
|
||||
curDinnerbone = false;
|
||||
curGradient = false;
|
||||
curShadow = false;
|
||||
curShadowCustomColor = false;
|
||||
curColor = color;
|
||||
curShadowColor = shadowColor;
|
||||
}
|
||||
} else if (fmtCode == 'r') {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
curRainbow = false;
|
||||
curWave = false;
|
||||
curDinnerbone = false;
|
||||
curGradient = false;
|
||||
curShadow = false;
|
||||
curShadowCustomColor = false;
|
||||
curColor = color;
|
||||
curShadowColor = shadowColor;
|
||||
}
|
||||
} // close else block for non-§x codes
|
||||
|
||||
continue;
|
||||
@@ -1130,9 +1436,9 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
if (curGradient && gradientTotalChars > 0) {
|
||||
float t = Math.min(gradientCharIndex * gradientStep, 1f);
|
||||
int gr = (int)((gradientStartRgb >> 16 & 0xFF) * (1-t) + (gradientEndRgb >> 16 & 0xFF) * t);
|
||||
int gg = (int)((gradientStartRgb >> 8 & 0xFF) * (1-t) + (gradientEndRgb >> 8 & 0xFF) * t);
|
||||
int gb = (int)((gradientStartRgb & 0xFF) * (1-t) + (gradientEndRgb & 0xFF) * t);
|
||||
int gr = (int) ((gradientStartRgb >> 16 & 0xFF) * (1 - t) + (gradientEndRgb >> 16 & 0xFF) * t);
|
||||
int gg = (int) ((gradientStartRgb >> 8 & 0xFF) * (1 - t) + (gradientEndRgb >> 8 & 0xFF) * t);
|
||||
int gb = (int) ((gradientStartRgb & 0xFF) * (1 - t) + (gradientEndRgb & 0xFF) * t);
|
||||
int rgbEffect = (gr << 16) | (gg << 8) | gb;
|
||||
curColor = (curColor & 0xFF000000) | rgbEffect;
|
||||
curShadowColor = (curShadowColor & 0xFF000000) | ((rgbEffect & 0xFCFCFC) >> 2);
|
||||
@@ -1155,7 +1461,7 @@ public class BatchingFontRenderer {
|
||||
// Wave: Y offset via sine wave
|
||||
float renderY = heightNorth;
|
||||
if (curWave) {
|
||||
float time = HUDCaching.renderingCacheOverride ? 0f : (float)((System.nanoTime() & 0xFFFFFFFFFFFFL) * WAVE_TIME_SCALE);
|
||||
float time = HUDCaching.renderingCacheOverride ? 0f : (float) ((System.nanoTime() & 0xFFFFFFFFFFFFL) * WAVE_TIME_SCALE);
|
||||
renderY += (float) Math.sin(visibleCharIndex * WAVE_FREQUENCY + time) * AngelicaConfig.waveAmplitude;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import net.coderbot.batchedentityrendering.impl.BlendingStateHolder;
|
||||
import net.coderbot.batchedentityrendering.impl.TransparencyType;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.layer.PassOverride;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@@ -68,7 +69,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
return TRANSLUCENT;
|
||||
}
|
||||
|
||||
private static MultiPhaseParameters.Builder tesrMaterialPhases(ResourceLocation texture, TesrMaterial material) {
|
||||
private static MultiPhaseParameters.Builder tesrMaterialPhases(ResourceLocation texture, TesrMaterial material, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
final MultiPhaseParameters.Builder b = MultiPhaseParameters.builder();
|
||||
b.texture(texture != null ? new RenderPhase.Texture(texture, false, false) : NO_TEXTURE);
|
||||
if (material.isNoCull()) {
|
||||
@@ -92,6 +93,7 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
case GLINT -> b.transparency(GLINT_TRANSPARENCY);
|
||||
case OPAQUE -> b.transparency(NO_TRANSPARENCY);
|
||||
}
|
||||
boolean shaderPhaseTaken = true;
|
||||
switch (material.special()) {
|
||||
case GLINT -> b.shader(SPECIAL_GLINT);
|
||||
case BEACON_BEAM -> b.shader(SPECIAL_BEACON_BEAM);
|
||||
@@ -99,9 +101,15 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
final TesrShader shader = material.shader();
|
||||
if (shader != null) {
|
||||
b.shader(new RenderPhase.Shader("angelica_tesr_shader_" + shader.name(), shader.bind(), shader.release()));
|
||||
} else {
|
||||
shaderPhaseTaken = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!shaderPhaseTaken && pass != PassOverride.NONE) {
|
||||
b.shader(new RenderPhase.Shader("angelica_tesr_pass" + pass.nameSuffix(), pass::apply, pass::clear));
|
||||
}
|
||||
b.layering(polygonOffset(offsetFactor, offsetUnits));
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -113,12 +121,23 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
GbufferPrograms::teardownSpecialRenderCondition);
|
||||
|
||||
public static RenderLayer tesr(ResourceLocation texture, TesrMaterial material) {
|
||||
final MultiPhaseParameters.Builder b = tesrMaterialPhases(texture, material).shadeModel(SMOOTH_SHADE_MODEL);
|
||||
return tesr(texture, material, PassOverride.NONE, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
public static RenderLayer tesr(ResourceLocation texture, TesrMaterial material, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
final MultiPhaseParameters.Builder b = tesrMaterialPhases(texture, material, pass, offsetFactor, offsetUnits).shadeModel(SMOOTH_SHADE_MODEL);
|
||||
final boolean sortsTranslucent = material.transparency() != TesrMaterial.Transparency.OPAQUE;
|
||||
return of("angelica_tesr_" + material.transparency().name().toLowerCase(Locale.ROOT),
|
||||
return of("angelica_tesr_" + material.transparency().name().toLowerCase(Locale.ROOT) + pass.nameSuffix()
|
||||
+ (offsetFactor == 0.0f && offsetUnits == 0.0f ? "" : "_offset" + offsetFactor + "_" + offsetUnits),
|
||||
BatchVertexFormats.POSITION_COLOR_TEXTURE_LIGHTF_NORMAL, GL11.GL_QUADS, 65536, true, sortsTranslucent, b.build(false));
|
||||
}
|
||||
|
||||
public static RenderLayer tesrNoPass(ResourceLocation texture, TesrMaterial material) {
|
||||
return of("angelica_tesr_nopass_" + material.transparency().name().toLowerCase(Locale.ROOT),
|
||||
BatchVertexFormats.POSITION_COLOR_TEXTURE_LIGHTF_NORMAL, GL11.GL_QUADS, 65536, true, false,
|
||||
tesrMaterialPhases(texture, material, PassOverride.NONE, 0.0f, 0.0f).build(false));
|
||||
}
|
||||
|
||||
public static RenderLayer getOutline(ResourceLocation texture, RenderPhase.Cull cull) {
|
||||
return of("outline", DefaultVertexFormat.POSITION_COLOR_TEXTURE, 7, 256, RenderLayer.MultiPhaseParameters.builder().texture(new RenderPhase.Texture(texture, false, false)).cull(cull).depthTest(ALWAYS_DEPTH_TEST).alpha(ONE_TENTH_ALPHA).fog(NO_FOG).target(OUTLINE_TARGET).build(RenderLayer.OutlineMode.IS_OUTLINE));
|
||||
}
|
||||
@@ -313,6 +332,10 @@ public abstract class RenderLayer extends RenderPhase { // Aka: RenderType (Iris
|
||||
return this;
|
||||
}
|
||||
|
||||
public void layering(Layering layering) {
|
||||
this.layering = layering;
|
||||
}
|
||||
|
||||
public Builder shadeModel(RenderPhase.ShadeModel shadeModel) {
|
||||
this.shadeModel = shadeModel;
|
||||
return this;
|
||||
|
||||
@@ -9,7 +9,9 @@ import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@@ -77,6 +79,7 @@ public abstract class RenderPhase {
|
||||
protected static final WriteMaskState COLOR_MASK;
|
||||
protected static final WriteMaskState DEPTH_MASK;
|
||||
protected static final Layering NO_LAYERING;
|
||||
|
||||
protected static final Fog NO_FOG;
|
||||
protected static final Fog FOG;
|
||||
protected static final Fog BLACK_FOG;
|
||||
@@ -85,6 +88,22 @@ public abstract class RenderPhase {
|
||||
protected static final Target TRANSLUCENT_TARGET;
|
||||
protected static final Shader NO_SHADER = new Shader("no_shader", () -> {}, () -> {});
|
||||
|
||||
private static final Map<Long, Layering> POLYGON_OFFSET_LAYERINGS = new ConcurrentHashMap<>();
|
||||
|
||||
public static Layering polygonOffset(float factor, float units) {
|
||||
if (factor == 0.0f && units == 0.0f) {
|
||||
return NO_LAYERING;
|
||||
}
|
||||
final long key = ((long) Float.floatToIntBits(factor) << 32) | (Float.floatToIntBits(units) & 0xFFFFFFFFL);
|
||||
return POLYGON_OFFSET_LAYERINGS.computeIfAbsent(key, k -> new Layering("polygon_offset_" + factor + "_" + units, () -> {
|
||||
GLStateManager.glEnable(GL11.GL_POLYGON_OFFSET_FILL);
|
||||
GLStateManager.glPolygonOffset(factor, units);
|
||||
}, () -> {
|
||||
GLStateManager.glDisable(GL11.GL_POLYGON_OFFSET_FILL);
|
||||
GLStateManager.glPolygonOffset(0.0f, 0.0f);
|
||||
}));
|
||||
}
|
||||
|
||||
public RenderPhase(String name, Runnable beginAction, Runnable endAction) {
|
||||
this.name = name;
|
||||
this.beginAction = beginAction;
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.config;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.Config;
|
||||
import com.gtnewhorizons.angelica.rendering.culling.GpuCulling;
|
||||
import net.coderbot.iris.shadows.ShadowGraphGate;
|
||||
|
||||
@Config(modid = "angelica", filename = "angelica-modules")
|
||||
public class AngelicaConfig {
|
||||
@@ -347,6 +348,20 @@ public class AngelicaConfig {
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean shadowSkipInMeshTileEntities;
|
||||
|
||||
@Config.Comment({
|
||||
"How much a celestial body can move before the shadow map can update.",
|
||||
"",
|
||||
"Note this option is disabled when a shader pack utilizes voxelization features."
|
||||
})
|
||||
@Config.DefaultFloat(ShadowGraphGate.DEFAULT_ANGLE_DELTA_DEGREES)
|
||||
@Config.RangeFloat(min = 0f, max = 0.1f)
|
||||
public static float shadowGraphAngleDelta;
|
||||
|
||||
@Config.Comment("Adjusts the rate the shadow map rebuilds when when a celestial body is near the horizon. Rate is sinusoidal")
|
||||
@Config.DefaultFloat(ShadowGraphGate.DEFAULT_HORIZON_SCALE)
|
||||
@Config.RangeFloat(min = 0f, max = 1.0f)
|
||||
public static float shadowGraphHorizonScale;
|
||||
|
||||
@Config.Comment("ASM transformer exclusion narrowing for mod compatibility. Disable per-mod if narrowing causes class loading issues.")
|
||||
public static TransformerCompat transformerCompat = new TransformerCompat();
|
||||
|
||||
|
||||
@@ -56,7 +56,9 @@ public class FontConfig {
|
||||
@Config.RangeFloat(min = -2F, max = 2F)
|
||||
public static float glyphSpacing;
|
||||
|
||||
@Config.Comment("Controls font antialiasing. 0 = none, 1 = 4x MSAA, 2 = 16x MSAA.")
|
||||
@Config.Comment({
|
||||
"Controls font antialiasing. 0 = none, 1 = 4x MSAA, 2 = 16x MSAA.",
|
||||
"Turning off AA lets shaders pick up the text."})
|
||||
@Config.DefaultInt(2)
|
||||
@Config.RangeInt(min = 0, max = 2)
|
||||
public static int fontAAMode;
|
||||
|
||||
@@ -10,6 +10,9 @@ import com.gtnewhorizons.angelica.glsm.hooks.ShaderTransformPostProcessor;
|
||||
import com.gtnewhorizons.angelica.glsm.shader.ShaderType;
|
||||
import org.taumc.glsl.grammar.GLSLParser;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.ShaderWorkSubmitter;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaBooleanLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPUGate;
|
||||
import net.coderbot.iris.Iris;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -38,7 +41,20 @@ public class IrisGLSMBridge {
|
||||
private static Runnable fogDensityListener = null;
|
||||
private static Runnable colorModulatorListener = null;
|
||||
|
||||
private static boolean inputsDeferred = false;
|
||||
|
||||
private static boolean blendDeferred = false;
|
||||
|
||||
private static boolean programRestoreDeferred = false;
|
||||
|
||||
private static final Int2IntOpenHashMap programLastUpdatedFrame = new Int2IntOpenHashMap();
|
||||
|
||||
private static void refreshBlendCondition() {
|
||||
if (Iris.getPipelineManager().getPipelineNullable() instanceof DeferredWorldRenderingPipeline drp) {
|
||||
drp.onVanillaBlendChanged();
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
programLastUpdatedFrame.defaultReturnValue(-1);
|
||||
StateUpdateNotifiers.alphaFuncNotifier = listener -> alphaFuncListener = listener;
|
||||
@@ -72,6 +88,44 @@ public class IrisGLSMBridge {
|
||||
};
|
||||
}
|
||||
|
||||
private static VanillaBooleanLayer gated(VanillaBooleanLayer layer) {
|
||||
return new VanillaBooleanLayer() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return Iris.enabled && layer.isOverrideHeld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getVanilla() {
|
||||
return layer.getVanilla();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVanilla(boolean enabled) {
|
||||
layer.setVanilla(enabled);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> VanillaStateLayer<T> gated(VanillaStateLayer<T> layer) {
|
||||
return new VanillaStateLayer<>() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return Iris.enabled && layer.isOverrideHeld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVanilla(T into) {
|
||||
layer.readVanilla(into);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVanilla(T from) {
|
||||
layer.writeVanilla(from);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
GLSMConfig.expandVertexFormats = Iris.enabled;
|
||||
IrisSamplers.initRenderer();
|
||||
@@ -88,6 +142,11 @@ public class IrisGLSMBridge {
|
||||
return Iris.enabled && BlendModeStorage.isBlendLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return Iris.enabled && BlendModeStorage.isOverrideHeld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deferBlendModeToggle(boolean enabled) {
|
||||
BlendModeStorage.deferBlendModeToggle(enabled);
|
||||
@@ -104,6 +163,13 @@ public class IrisGLSMBridge {
|
||||
}
|
||||
};
|
||||
|
||||
GLStateManager.getBlendMode().setVanillaLayer(gated(BlendModeStorage.ENABLE_LAYER));
|
||||
GLStateManager.getBlendState().setVanillaLayer(gated(BlendModeStorage.FUNC_LAYER));
|
||||
GLStateManager.getAlphaTest().setVanillaLayer(gated(AlphaTestStorage.ENABLE_LAYER));
|
||||
GLStateManager.getAlphaState().setVanillaLayer(gated(AlphaTestStorage.FUNC_LAYER));
|
||||
GLStateManager.getDepthState().setVanillaLayer(gated(DepthColorStorage.DEPTH_LAYER));
|
||||
GLStateManager.getColorMask().setVanillaLayer(gated(DepthColorStorage.COLOR_LAYER));
|
||||
|
||||
GLSMHooks.alphaHandler = new DeferredAlphaHandler() {
|
||||
@Override
|
||||
public boolean isAlphaTestLocked() {
|
||||
@@ -127,6 +193,11 @@ public class IrisGLSMBridge {
|
||||
return Iris.enabled && DepthColorStorage.isDepthColorLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return Iris.enabled && DepthColorStorage.isOverrideHeld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deferDepthEnable(boolean enabled) {
|
||||
DepthColorStorage.deferDepthEnable(enabled);
|
||||
@@ -190,9 +261,41 @@ public class IrisGLSMBridge {
|
||||
StateTracker.INSTANCE.lightmapSampler = event.enabled;
|
||||
updatePipeline = true;
|
||||
}
|
||||
if (updatePipeline) {
|
||||
if (!updatePipeline) return;
|
||||
|
||||
if (GLStateManager.isForeignDraw()) {
|
||||
inputsDeferred = true;
|
||||
return;
|
||||
}
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs()));
|
||||
});
|
||||
|
||||
GLSMHooks.VANILLA_BLEND_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (GLStateManager.isForeignDraw()) {
|
||||
blendDeferred = true;
|
||||
return;
|
||||
}
|
||||
refreshBlendCondition();
|
||||
});
|
||||
|
||||
GLSMHooks.FOREIGN_DRAW_END.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (inputsDeferred) {
|
||||
inputsDeferred = false;
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setInputs(StateTracker.INSTANCE.getInputs()));
|
||||
}
|
||||
if (blendDeferred) {
|
||||
blendDeferred = false;
|
||||
refreshBlendCondition();
|
||||
}
|
||||
if (programRestoreDeferred) {
|
||||
programRestoreDeferred = false;
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (pipeline instanceof DeferredWorldRenderingPipeline drp && drp.shouldOverrideShaders()) {
|
||||
drp.restorePassAfterModProgram(GLStateManager.getActiveProgram());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
@@ -208,15 +311,29 @@ public class IrisGLSMBridge {
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (!(pipeline instanceof DeferredWorldRenderingPipeline drp)) return;
|
||||
if (!drp.shouldOverrideShaders()) return;
|
||||
if (drp.getActivePassProgramId() == -1) return;
|
||||
DepthColorStorage.unlockDepthColor();
|
||||
|
||||
if (DepthColorStorage.isOwnedProgram(event.newProgram)) {
|
||||
DepthColorStorage.unlockDepthColor();
|
||||
} else {
|
||||
if (event.newProgram != 0 && !DepthColorStorage.isOwnedProgram(event.newProgram)) {
|
||||
drp.onModProgramOverride();
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (!event.postBind) return;
|
||||
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (!(pipeline instanceof DeferredWorldRenderingPipeline drp)) return;
|
||||
if (!drp.shouldOverrideShaders()) return;
|
||||
|
||||
if (GLStateManager.isForeignDraw()) {
|
||||
programRestoreDeferred = true;
|
||||
return;
|
||||
}
|
||||
|
||||
drp.restorePassAfterModProgram(event.newProgram);
|
||||
});
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (!event.postBind) return;
|
||||
|
||||
@@ -417,11 +417,13 @@ public enum Mixins implements IMixins {
|
||||
.addClientMixins(
|
||||
"shaders.MixinDroppedItemGlintEdges"
|
||||
, "shaders.MixinHeldItemGlintEdges"
|
||||
, "shaders.MixinEffectRenderer_Particles"
|
||||
, "shaders.MixinEntityPickupFX"
|
||||
, "shaders.MixinEntityRenderer"
|
||||
, "shaders.MixinGuiIngameForge"
|
||||
, "shaders.MixinFramebuffer"
|
||||
, "shaders.MixinItem"
|
||||
, "shaders.MixinItemRenderer_ItemId"
|
||||
, "shaders.MixinLocale"
|
||||
, "shaders.MixinRender"
|
||||
, "shaders.MixinRenderBiped"
|
||||
@@ -744,6 +746,24 @@ public enum Mixins implements IMixins {
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins("client.etfuturum.MixinLayerBetterElytra")
|
||||
),
|
||||
ET_FUTURUM_BEACON_BEAM(new MixinBuilder("Iris Et Futurum Beacon Beam")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.ET_FUTURUM_REQUIEM)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins("client.etfuturum.MixinTileEntityNewBeaconRenderer")
|
||||
),
|
||||
OPENBLOCKS_TROPHY_ENTITY_GBUFFER(new MixinBuilder("Render OpenBlocks trophies with the entity gbuffer programs")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.OPENBLOCKS)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins("client.openblocks.MixinTileEntityTrophyRenderer")
|
||||
),
|
||||
DRAGONAPI_PARTICLE_SPLIT(new MixinBuilder("Split DragonAPI's replacement particle renderer between the particle gbuffer programs")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.DRAGON_API)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins("client.dragonapi.MixinThrottleableEffectRenderer")
|
||||
),
|
||||
MCPATCHER_FORGE(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableMCPatcherForgeFeatures)
|
||||
|
||||
@@ -23,6 +23,7 @@ public enum TargetedMod implements ITargetMod {
|
||||
NTM_SPACE("com.hbm.dim.SolarSystem"),
|
||||
IC2("ic2.core.coremod.IC2core", "IC2"),
|
||||
NATURA(null, "Natura"),
|
||||
OPENBLOCKS(null, "OpenBlocks"),
|
||||
SECURITYCRAFT(null, "securitycraft"),
|
||||
STARMINER("jp.mc.ancientred.starminer.core.SMPlugin", "modJ_StarMiner"),
|
||||
SUPERNOVA("com.mitchej123.supernova.core.SupernovaCore", "supernova"),
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.mixins.interfaces;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public interface ItemRendererAccessor {
|
||||
|
||||
ItemStack angelica$getItemToRender();
|
||||
}
|
||||
@@ -73,6 +73,9 @@ public final class SelectionBoxRenderer {
|
||||
public static void draw(AxisAlignedBB aabb, int color) {
|
||||
if (program == null || vao == null) return;
|
||||
|
||||
GLStateManager.enableDepthTest();
|
||||
GLStateManager.glDepthFunc(GL11.GL_LEQUAL);
|
||||
|
||||
final float minX = (float) aabb.minX, minY = (float) aabb.minY, minZ = (float) aabb.minZ;
|
||||
final float extX = (float) (aabb.maxX - aabb.minX);
|
||||
final float extY = (float) (aabb.maxY - aabb.minY);
|
||||
|
||||
@@ -123,11 +123,11 @@ public class DeferredEntityOverlay {
|
||||
GbufferPrograms.beginEntities();
|
||||
try {
|
||||
for (DeferredEntry entry : deferred) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(EntityIdHelper.getEntityId(entry.entity));
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(EntityIdHelper.getEntityId(entry.entity), 0);
|
||||
renderOverlay(entry);
|
||||
}
|
||||
} finally {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(-1, 0);
|
||||
GbufferPrograms.endEntities();
|
||||
}
|
||||
recycle();
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.gtnewhorizons.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizons.angelica.client.rendering.DeferredDrawBatcher;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.SpriteExtension;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.minecraft.client.particle.EntityCloudFX;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.particle.EntityFireworkOverlayFX;
|
||||
import net.minecraft.client.particle.EntityFireworkSparkFX;
|
||||
import net.minecraft.client.particle.EntityFireworkStarterFX;
|
||||
import net.minecraft.client.particle.EntitySpellParticleFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.sprite.SpriteTransparencyLevel;
|
||||
|
||||
/**
|
||||
* Splits a particle run between {@code gbuffers_particles} and {@code gbuffers_particles_translucent}.
|
||||
*/
|
||||
public final class ParticleRunSplitter {
|
||||
|
||||
private static boolean runTranslucent;
|
||||
|
||||
private ParticleRunSplitter() {}
|
||||
|
||||
public static void beginRun() {
|
||||
runTranslucent = false;
|
||||
GbufferPrograms.setTranslucencyDeclaration(Boolean.FALSE);
|
||||
}
|
||||
|
||||
public static void splitIfNeeded(EntityFX particle, Tessellator tessellator, float partialTicks) {
|
||||
final boolean translucent = isTranslucent(particle);
|
||||
if (translucent == runTranslucent) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean batcherWasActive = DeferredDrawBatcher.isActive();
|
||||
if (batcherWasActive) {
|
||||
DeferredDrawBatcher.exitAndFlush();
|
||||
}
|
||||
tessellator.draw();
|
||||
|
||||
runTranslucent = translucent;
|
||||
GbufferPrograms.setTranslucencyDeclaration(translucent);
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
tessellator.setBrightness(particle.getBrightnessForRender(partialTicks));
|
||||
if (batcherWasActive) {
|
||||
DeferredDrawBatcher.enter();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isTranslucent(EntityFX particle) {
|
||||
if (particle.particleIcon instanceof TextureAtlasSprite sprite) {
|
||||
return ((SpriteExtension) sprite).celeritas$getTransparencyLevel() == SpriteTransparencyLevel.TRANSLUCENT;
|
||||
}
|
||||
|
||||
return particle instanceof EntityFireworkSparkFX
|
||||
|| particle instanceof EntityFireworkOverlayFX
|
||||
|| particle instanceof EntityFireworkStarterFX
|
||||
|| particle instanceof EntitySpellParticleFX
|
||||
|| particle instanceof EntityCloudFX;
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ public final class PlayerReflectionCapture {
|
||||
private static final Matrix4f pendingModelView = new Matrix4f();
|
||||
private static int pendingSkin;
|
||||
private static int pendingEntityId;
|
||||
private static int pendingItemId;
|
||||
|
||||
private static int vbo;
|
||||
private static int vao;
|
||||
@@ -134,6 +135,7 @@ public final class PlayerReflectionCapture {
|
||||
pendingModelView.set(GLStateManager.getModelViewMatrix());
|
||||
pendingSkin = GLStateManager.getBoundTextureForServerState(0);
|
||||
pendingEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
pendingItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
pending = true;
|
||||
}
|
||||
|
||||
@@ -328,9 +330,10 @@ public final class PlayerReflectionCapture {
|
||||
final boolean prevDepthWrite = GLStateManager.getDepthState().isEnabled();
|
||||
|
||||
final int prevEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
final int prevItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
savedModelView.set(GLStateManager.getModelViewMatrix());
|
||||
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(pendingEntityId);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(pendingEntityId, pendingItemId);
|
||||
GLStateManager.setModelViewMatrix(pendingModelView);
|
||||
if (maskable) {
|
||||
GLStateManager.glColorMask(false, false, false, false);
|
||||
@@ -344,7 +347,7 @@ public final class PlayerReflectionCapture {
|
||||
GLStateManager.glColorMask(pr, pg, pb, pa);
|
||||
}
|
||||
GLStateManager.setModelViewMatrix(savedModelView);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(prevEntityId);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(prevEntityId, prevItemId);
|
||||
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, prevTexture);
|
||||
|
||||
+47
-10
@@ -28,6 +28,7 @@ import org.embeddedt.embeddium.impl.model.light.data.QuadLightData;
|
||||
import org.embeddedt.embeddium.impl.model.light.flat.FlatLightPipeline;
|
||||
import org.embeddedt.embeddium.impl.model.light.smooth.SmoothLightPipeline;
|
||||
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFacing;
|
||||
import org.embeddedt.embeddium.impl.model.quad.properties.ModelQuadFlags;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.ChunkColorWriter;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.RenderPassConfiguration;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.compile.ChunkBuildBuffers;
|
||||
@@ -43,6 +44,9 @@ import java.util.List;
|
||||
public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
public static final int NUM_PASSES = 2;
|
||||
|
||||
// Yoinked from Celeritas
|
||||
private static final int[] REVERSED_QUAD_ORDER = { 0, 3, 2, 1 };
|
||||
|
||||
private final TextureMapExtension textureAtlas;
|
||||
private final ChunkVertexEncoder.Vertex[] vertices = ChunkVertexEncoder.Vertex.uninitializedQuad();
|
||||
@Getter
|
||||
@@ -62,6 +66,8 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
private boolean lightPipelineReady = false;
|
||||
private int originX, originY, originZ;
|
||||
private float cachedSkylightSubtracted;
|
||||
private final float[] fluidQuadPos = new float[12];
|
||||
private ModelQuadFacing fluidQuadLightFace;
|
||||
|
||||
public AngelicaChunkBuildContext(RenderPassConfiguration<?> renderPassConfiguration, WorldClient world) {
|
||||
super(renderPassConfiguration);
|
||||
@@ -160,6 +166,7 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
boolean hasCachedMaterial = false;
|
||||
TextureAtlasSprite lastSprite = null;
|
||||
Material lastMaterial = null;
|
||||
this.fluidQuadLightFace = null;
|
||||
|
||||
for (int quadIdx = 0; quadIdx < numQuads; quadIdx++) {
|
||||
float uSum = 0, vSum = 0;
|
||||
@@ -201,11 +208,8 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
// Otherwise, we need to use the block's lightmap values as they are as the ISBRH may have
|
||||
// specified its own lightmaps for visual purposes (e.g. fullbright)
|
||||
if (useAoCalculation && (quadState & StateAwareTessellator.RENDERED_WITH_VANILLA_AO) != 0) {
|
||||
quadView.setup(trueNormal, blockX, blockY, blockZ);
|
||||
final ModelQuadFacing lightFace = quadView.getLightFace();
|
||||
final LightPipeline pipeline = blockAllowsSmoothLighting ? smoothLightPipeline : flatLightPipeline;
|
||||
final ModelQuadFacing cullFace = quadView.getCullFace();
|
||||
pipeline.calculate(quadView, worldX, worldY, worldZ, quadLightData, cullFace, lightFace, shouldApplyDiffuse, true);
|
||||
calculateQuadLight(trueNormal, blockX, blockY, blockZ, worldX, worldY, worldZ, isFluid,
|
||||
blockAllowsSmoothLighting, shouldApplyDiffuse);
|
||||
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
final var vertex = vertices[vIdx];
|
||||
@@ -227,11 +231,8 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
}
|
||||
|
||||
if (useAoCalculation && isFluid) {
|
||||
quadView.setup(trueNormal, blockX, blockY, blockZ);
|
||||
final ModelQuadFacing lightFace = quadView.getLightFace();
|
||||
final LightPipeline pipeline = blockAllowsSmoothLighting ? smoothLightPipeline : flatLightPipeline;
|
||||
final ModelQuadFacing cullFace = quadView.getCullFace();
|
||||
pipeline.calculate(quadView, worldX, worldY, worldZ, quadLightData, cullFace, lightFace, shouldApplyDiffuse, true);
|
||||
calculateQuadLight(trueNormal, blockX, blockY, blockZ, worldX, worldY, worldZ, true,
|
||||
blockAllowsSmoothLighting, shouldApplyDiffuse);
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
vertices[vIdx].light = quadLightData.lm[vIdx];
|
||||
}
|
||||
@@ -274,6 +275,42 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateQuadLight(int trueNormal, int blockX, int blockY, int blockZ, int worldX, int worldY,
|
||||
int worldZ, boolean isFluid, boolean blockAllowsSmoothLighting,
|
||||
boolean shouldApplyDiffuse) {
|
||||
final boolean isFlippedFluidCopy = isFluid && fluidQuadLightFace != null && isReversedFluidQuad();
|
||||
|
||||
quadView.setup(trueNormal, blockX, blockY, blockZ, isFluid ? ModelQuadFlags.IS_VANILLA_SHADED : 0,
|
||||
isFlippedFluidCopy ? fluidQuadLightFace : null);
|
||||
|
||||
final LightPipeline pipeline = blockAllowsSmoothLighting ? smoothLightPipeline : flatLightPipeline;
|
||||
pipeline.calculate(quadView, worldX, worldY, worldZ, quadLightData, quadView.getCullFace(),
|
||||
quadView.getLightFace(), shouldApplyDiffuse, true);
|
||||
|
||||
if (isFluid && !isFlippedFluidCopy) {
|
||||
fluidQuadLightFace = quadView.getLightFace();
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
final var vertex = vertices[vIdx];
|
||||
fluidQuadPos[vIdx * 3] = vertex.x;
|
||||
fluidQuadPos[vIdx * 3 + 1] = vertex.y;
|
||||
fluidQuadPos[vIdx * 3 + 2] = vertex.z;
|
||||
}
|
||||
} else if (!isFluid) {
|
||||
fluidQuadLightFace = null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReversedFluidQuad() {
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
final int src = REVERSED_QUAD_ORDER[vIdx] * 3;
|
||||
final var vertex = vertices[vIdx];
|
||||
if (vertex.x != fluidQuadPos[src] || vertex.y != fluidQuadPos[src + 1] || vertex.z != fluidQuadPos[src + 2]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void applyBlockLightTint(int x, int y, int z, ChunkVertexEncoder.Vertex[] vertices) {
|
||||
if (!hasColoredLight) return;
|
||||
final ExtQuadLightData ext = (ExtQuadLightData) quadLightData;
|
||||
|
||||
+8
-2
@@ -13,18 +13,24 @@ public class VertexArrayQuadView implements ModelQuadView {
|
||||
private int blockX, blockY, blockZ;
|
||||
private ModelQuadFacing lightFace;
|
||||
private int flags;
|
||||
private int extraFlags;
|
||||
|
||||
public VertexArrayQuadView(ChunkVertexEncoder.Vertex[] vertices) {
|
||||
this.vertices = vertices;
|
||||
}
|
||||
|
||||
public void setup(int trueNormal, int blockX, int blockY, int blockZ) {
|
||||
setup(trueNormal, blockX, blockY, blockZ, 0, null);
|
||||
}
|
||||
|
||||
public void setup(int trueNormal, int blockX, int blockY, int blockZ, int extraFlags, ModelQuadFacing forcedLightFace) {
|
||||
this.trueNormal = trueNormal;
|
||||
this.blockX = blockX;
|
||||
this.blockY = blockY;
|
||||
this.blockZ = blockZ;
|
||||
this.lightFace = null; // Reset cached lightFace
|
||||
this.lightFace = forcedLightFace;
|
||||
this.flags = 0;
|
||||
this.extraFlags = extraFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,7 +71,7 @@ public class VertexArrayQuadView implements ModelQuadView {
|
||||
@Override
|
||||
public int getFlags() {
|
||||
if (flags == 0) {
|
||||
flags = ModelQuadFlags.getQuadFlags(this, getLightFace());
|
||||
flags = ModelQuadFlags.getQuadFlags(this, getLightFace(), extraFlags);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
+12
-1
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas.light;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
|
||||
import lombok.Setter;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
@@ -9,6 +10,16 @@ import org.embeddedt.embeddium.impl.model.light.data.LightDataAccess;
|
||||
public class LightDataCache extends LightDataAccess {
|
||||
private IBlockAccess world;
|
||||
|
||||
/**
|
||||
* Doing this to force packs like Steadfast's water to work properly.
|
||||
*/
|
||||
private static int skyLight(IBlockAccess world, Block block, int x, int y, int z, int neighborMaxed) {
|
||||
if (world instanceof WorldSlice slice && block.getMaterial().isLiquid()) {
|
||||
return slice.getRawSkyLight(x, y, z);
|
||||
}
|
||||
return neighborMaxed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int compute(int x, int y, int z) {
|
||||
final IBlockAccess world = this.world;
|
||||
@@ -26,7 +37,7 @@ public class LightDataCache extends LightDataAccess {
|
||||
} else {
|
||||
final int packed = world.getLightBrightnessForSkyBlocks(x, y, z, 0);
|
||||
bl = (packed >> 4) & 0xF;
|
||||
sl = (packed >> 20) & 0xF;
|
||||
sl = skyLight(world, block, x, y, z, (packed >> 20) & 0xF);
|
||||
}
|
||||
|
||||
// AO value - blocks that emit light don't contribute to AO
|
||||
|
||||
@@ -276,6 +276,17 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
return skyBrightness << 20 | blockBrightness << 4;
|
||||
}
|
||||
|
||||
public int getRawSkyLight(int x, int y, int z) {
|
||||
final int minHeight = ModStatus.isCubicChunksLoaded ? CubicChunksAPI.getMinHeight(this.world) : 0;
|
||||
final int maxHeight = ModStatus.isCubicChunksLoaded ? CubicChunksAPI.getMaxHeight(this.world) : 256;
|
||||
|
||||
if (y < minHeight || y >= maxHeight || x < -30_000_000 || z < -30_000_000 || x >= 30_000_000 || z >= 30_000_000) {
|
||||
return 15;
|
||||
}
|
||||
|
||||
return this.getLightLevel(EnumSkyBlock.Sky, x, y, z);
|
||||
}
|
||||
|
||||
private int getSkyBlockTypeBrightness(EnumSkyBlock skyBlock, int x, int y, int z) {
|
||||
if (this.getBlock(x, y, z).getUseNeighborBrightness()) {
|
||||
int yp = this.getLightLevel(skyBlock, x, y + 1, z);
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PolygonState;
|
||||
import com.gtnewhorizons.angelica.profiling.BailClassCounts;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
@@ -24,6 +25,7 @@ import net.coderbot.batchedentityrendering.impl.AngelicaBufferSource;
|
||||
import net.coderbot.batchedentityrendering.impl.TransparencyType;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.layer.PassOverride;
|
||||
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.model.ModelBox;
|
||||
@@ -105,22 +107,34 @@ public final class ModelPartBatcher {
|
||||
private static final class LayerKey {
|
||||
ResourceLocation texture;
|
||||
TesrMaterial material;
|
||||
PassOverride pass;
|
||||
float offsetFactor;
|
||||
float offsetUnits;
|
||||
|
||||
LayerKey set(ResourceLocation texture, TesrMaterial material) {
|
||||
LayerKey set(ResourceLocation texture, TesrMaterial material, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
this.texture = texture;
|
||||
this.material = material;
|
||||
this.pass = pass;
|
||||
this.offsetFactor = offsetFactor;
|
||||
this.offsetUnits = offsetUnits;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof LayerKey other)) return false;
|
||||
return Objects.equals(texture, other.texture) && Objects.equals(material, other.material);
|
||||
return Objects.equals(texture, other.texture) && Objects.equals(material, other.material)
|
||||
&& Objects.equals(pass, other.pass)
|
||||
&& Float.floatToIntBits(offsetFactor) == Float.floatToIntBits(other.offsetFactor)
|
||||
&& Float.floatToIntBits(offsetUnits) == Float.floatToIntBits(other.offsetUnits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(texture) * 31 + Objects.hashCode(material);
|
||||
int h = (Objects.hashCode(texture) * 31 + Objects.hashCode(material)) * 31 + Objects.hashCode(pass);
|
||||
h = h * 31 + Float.floatToIntBits(offsetFactor);
|
||||
h = h * 31 + Float.floatToIntBits(offsetUnits);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +142,9 @@ public final class ModelPartBatcher {
|
||||
private final LayerKey scratchKey = new LayerKey();
|
||||
private ResourceLocation lastLayerTexture;
|
||||
private TesrMaterial lastLayerMaterial;
|
||||
private PassOverride lastLayerPass;
|
||||
private float lastLayerOffsetFactor;
|
||||
private float lastLayerOffsetUnits;
|
||||
private RenderLayer lastLayer;
|
||||
|
||||
private static ResourceLocation lastBoundLocation;
|
||||
@@ -177,7 +194,9 @@ public final class ModelPartBatcher {
|
||||
if (instancedThisCycle) {
|
||||
TesrBatchRenderer.INSTANCE.instancedRenderer.endFrame();
|
||||
}
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
if (!TesrBatchRenderer.INSTANCE.hasPendingGeometry()) {
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
}
|
||||
return;
|
||||
}
|
||||
final boolean inEntityLoop = mode == Mode.ENTITIES && Iris.enabled && GbufferPrograms.isEntityLoopActive();
|
||||
@@ -193,6 +212,9 @@ public final class ModelPartBatcher {
|
||||
if (instancedThisCycle) {
|
||||
TesrBatchRenderer.INSTANCE.instancedRenderer.endFrame();
|
||||
}
|
||||
if (!TesrBatchRenderer.INSTANCE.hasPendingGeometry()) {
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
@@ -278,11 +300,19 @@ public final class ModelPartBatcher {
|
||||
}
|
||||
}
|
||||
}
|
||||
final RenderLayer layer = layerFor(texture, material);
|
||||
final int entityId = mode == Mode.ENTITIES ? Math.max(0, CapturedRenderingState.INSTANCE.getCurrentRenderedEntity()) : CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
final PassOverride pass = shaderPipeline != null ? PassOverride.capture() : PassOverride.NONE;
|
||||
final boolean offset = GLStateManager.glIsEnabled(GL11.GL_POLYGON_OFFSET_FILL);
|
||||
final PolygonState polygon = GLStateManager.getPolygonState();
|
||||
final float offsetFactor = offset ? polygon.getOffsetFactor() : 0.0f;
|
||||
final float offsetUnits = offset ? polygon.getOffsetUnits() : 0.0f;
|
||||
final RenderLayer layer = layerFor(texture, material, pass, offsetFactor, offsetUnits);
|
||||
// Entities nested inside a TESR (mob spawner, OpenBlocks trophy) run in the block entity pass but carry an entity id
|
||||
final int entityId = mode == Mode.ENTITIES || pass.isEntityPhase()
|
||||
? Math.max(0, CapturedRenderingState.INSTANCE.getCurrentRenderedEntity())
|
||||
: CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
final Color4 color = GLStateManager.getColor();
|
||||
final int colorABGR = ColorABGR.pack(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
final int packedLight = ((int) GLSMConfig.lastBrightnessY << 16) | ((int) GLSMConfig.lastBrightnessX & 0xFFFF);
|
||||
final int packedLight = GLSMConfig.packedLastBrightness();
|
||||
final int mvGen = GLStateManager.getMvGeneration();
|
||||
if (!mvCaptured || mvGen != lastMvGeneration) {
|
||||
modelView.set(GLStateManager.getModelViewMatrix());
|
||||
@@ -349,17 +379,21 @@ public final class ModelPartBatcher {
|
||||
return entry;
|
||||
}
|
||||
|
||||
private RenderLayer layerFor(ResourceLocation texture, TesrMaterial material) {
|
||||
if (texture == lastLayerTexture && material == lastLayerMaterial) {
|
||||
private RenderLayer layerFor(ResourceLocation texture, TesrMaterial material, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
if (texture == lastLayerTexture && material == lastLayerMaterial && pass.equals(lastLayerPass)
|
||||
&& offsetFactor == lastLayerOffsetFactor && offsetUnits == lastLayerOffsetUnits) {
|
||||
return lastLayer;
|
||||
}
|
||||
RenderLayer layer = layers.get(scratchKey.set(texture, material));
|
||||
RenderLayer layer = layers.get(scratchKey.set(texture, material, pass, offsetFactor, offsetUnits));
|
||||
if (layer == null) {
|
||||
layer = RenderLayer.tesr(texture, material);
|
||||
layers.put(new LayerKey().set(texture, material), layer);
|
||||
layer = RenderLayer.tesr(texture, material, pass, offsetFactor, offsetUnits);
|
||||
layers.put(new LayerKey().set(texture, material, pass, offsetFactor, offsetUnits), layer);
|
||||
}
|
||||
lastLayerTexture = texture;
|
||||
lastLayerMaterial = material;
|
||||
lastLayerPass = pass;
|
||||
lastLayerOffsetFactor = offsetFactor;
|
||||
lastLayerOffsetUnits = offsetUnits;
|
||||
lastLayer = layer;
|
||||
return layer;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.gtnewhorizons.angelica.glsm.ffp.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PolygonState;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.coderbot.batchedentityrendering.impl.AngelicaBufferSource;
|
||||
@@ -19,6 +20,7 @@ import net.coderbot.batchedentityrendering.impl.SegmentedBufferBuilder;
|
||||
import net.coderbot.batchedentityrendering.impl.TransparencyType;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.layer.PassOverride;
|
||||
import net.coderbot.iris.pipeline.DeferredWorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
@@ -129,13 +131,23 @@ public final class TesrBatchRenderer {
|
||||
return activePass >= 0;
|
||||
}
|
||||
|
||||
public boolean hasPendingGeometry() {
|
||||
return activePass >= 0 || deferredFlushPending;
|
||||
}
|
||||
|
||||
public void queue(TemplateBuffer template, ResourceLocation texture, TesrMaterial material) {
|
||||
modelView.set(GLStateManager.getModelViewMatrix());
|
||||
final int packedLight = currentPackedLight(material);
|
||||
final int colorABGR = resolveColor(material);
|
||||
if (activePass >= 0) {
|
||||
final RenderLayer layer = layerFor(texture, material);
|
||||
final int blockEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
final boolean offset = GLStateManager.glIsEnabled(GL11.GL_POLYGON_OFFSET_FILL);
|
||||
final PolygonState polygon = GLStateManager.getPolygonState();
|
||||
final PassOverride pass = PassOverride.capture();
|
||||
final RenderLayer layer = layerFor(texture, material, pass,
|
||||
offset ? polygon.getOffsetFactor() : 0.0f, offset ? polygon.getOffsetUnits() : 0.0f);
|
||||
final int blockEntityId = pass.isEntityPhase()
|
||||
? Math.max(0, CapturedRenderingState.INSTANCE.getCurrentRenderedEntity())
|
||||
: CapturedRenderingState.INSTANCE.getCurrentRenderedBlockEntity();
|
||||
retained[activePass].queue(template, layer, material, modelView, packedLight, colorABGR, blockEntityId, captureTextureMatrix(), false);
|
||||
} else {
|
||||
drawImmediate(template, texture, material, packedLight, colorABGR);
|
||||
@@ -158,8 +170,12 @@ public final class TesrBatchRenderer {
|
||||
boolean depthEqual;
|
||||
TesrMaterial.SpecialRender special;
|
||||
TesrShader shader;
|
||||
boolean noPass;
|
||||
PassOverride pass;
|
||||
float offsetFactor;
|
||||
float offsetUnits;
|
||||
|
||||
LayerKey set(ResourceLocation texture, TesrMaterial.Transparency transparency, boolean noCull, boolean unlit, boolean noDepthWrite, boolean depthOnly, float cutoutAlpha, boolean depthEqual, TesrMaterial.SpecialRender special, TesrShader shader) {
|
||||
LayerKey set(ResourceLocation texture, TesrMaterial.Transparency transparency, boolean noCull, boolean unlit, boolean noDepthWrite, boolean depthOnly, float cutoutAlpha, boolean depthEqual, TesrMaterial.SpecialRender special, TesrShader shader, boolean noPass, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
this.texture = texture;
|
||||
this.transparency = transparency;
|
||||
this.noCull = noCull;
|
||||
@@ -170,11 +186,15 @@ public final class TesrBatchRenderer {
|
||||
this.depthEqual = depthEqual;
|
||||
this.special = special;
|
||||
this.shader = shader;
|
||||
this.noPass = noPass;
|
||||
this.pass = pass;
|
||||
this.offsetFactor = offsetFactor;
|
||||
this.offsetUnits = offsetUnits;
|
||||
return this;
|
||||
}
|
||||
|
||||
LayerKey copy() {
|
||||
return new LayerKey().set(texture, transparency, noCull, unlit, noDepthWrite, depthOnly, cutoutAlpha, depthEqual, special, shader);
|
||||
return new LayerKey().set(texture, transparency, noCull, unlit, noDepthWrite, depthOnly, cutoutAlpha, depthEqual, special, shader, noPass, pass, offsetFactor, offsetUnits);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,7 +204,10 @@ public final class TesrBatchRenderer {
|
||||
&& noCull == other.noCull && unlit == other.unlit && noDepthWrite == other.noDepthWrite
|
||||
&& depthOnly == other.depthOnly
|
||||
&& Float.floatToIntBits(cutoutAlpha) == Float.floatToIntBits(other.cutoutAlpha)
|
||||
&& depthEqual == other.depthEqual && special == other.special && shader == other.shader;
|
||||
&& depthEqual == other.depthEqual && special == other.special && shader == other.shader && noPass == other.noPass
|
||||
&& Objects.equals(pass, other.pass)
|
||||
&& Float.floatToIntBits(offsetFactor) == Float.floatToIntBits(other.offsetFactor)
|
||||
&& Float.floatToIntBits(offsetUnits) == Float.floatToIntBits(other.offsetUnits);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,6 +222,10 @@ public final class TesrBatchRenderer {
|
||||
h = h * 31 + (depthEqual ? 1 : 0);
|
||||
h = h * 31 + Objects.hashCode(special);
|
||||
h = h * 31 + System.identityHashCode(shader);
|
||||
h = h * 31 + (noPass ? 1 : 0);
|
||||
h = h * 31 + Objects.hashCode(pass);
|
||||
h = h * 31 + Float.floatToIntBits(offsetFactor);
|
||||
h = h * 31 + Float.floatToIntBits(offsetUnits);
|
||||
return h;
|
||||
}
|
||||
}
|
||||
@@ -207,24 +234,45 @@ public final class TesrBatchRenderer {
|
||||
private final LayerKey scratchKey = new LayerKey();
|
||||
private ResourceLocation lastLayerTexture;
|
||||
private TesrMaterial lastLayerMaterial;
|
||||
private PassOverride lastLayerPass;
|
||||
private float lastLayerOffsetFactor;
|
||||
private float lastLayerOffsetUnits;
|
||||
private RenderLayer lastLayer;
|
||||
private ResourceLocation lastImmediateTexture;
|
||||
private TesrMaterial lastImmediateMaterial;
|
||||
private RenderLayer lastImmediateLayer;
|
||||
|
||||
private RenderLayer layerFor(ResourceLocation texture, TesrMaterial material) {
|
||||
if (texture == lastLayerTexture && material == lastLayerMaterial) {
|
||||
private RenderLayer layerFor(ResourceLocation texture, TesrMaterial material, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
if (texture == lastLayerTexture && material == lastLayerMaterial && pass.equals(lastLayerPass)
|
||||
&& offsetFactor == lastLayerOffsetFactor && offsetUnits == lastLayerOffsetUnits) {
|
||||
return lastLayer;
|
||||
}
|
||||
final RenderLayer layer = layerLookup(texture, material);
|
||||
final RenderLayer layer = layerLookup(texture, material, false, pass, offsetFactor, offsetUnits);
|
||||
lastLayerTexture = texture;
|
||||
lastLayerMaterial = material;
|
||||
lastLayerPass = pass;
|
||||
lastLayerOffsetFactor = offsetFactor;
|
||||
lastLayerOffsetUnits = offsetUnits;
|
||||
lastLayer = layer;
|
||||
return layer;
|
||||
}
|
||||
|
||||
private RenderLayer layerLookup(ResourceLocation texture, TesrMaterial material) {
|
||||
final LayerKey key = scratchKey.set(texture, material.transparency(), material.isNoCull(), material.isUnlit(), material.isNoDepthWrite(), material.isDepthOnly(), material.cutoutAlpha(), material.isDepthEqual(), material.special(), material.shader());
|
||||
private RenderLayer noPassLayerFor(ResourceLocation texture, TesrMaterial material) {
|
||||
if (texture == lastImmediateTexture && material == lastImmediateMaterial) {
|
||||
return lastImmediateLayer;
|
||||
}
|
||||
final RenderLayer layer = layerLookup(texture, material, true, PassOverride.NONE, 0.0f, 0.0f);
|
||||
lastImmediateTexture = texture;
|
||||
lastImmediateMaterial = material;
|
||||
lastImmediateLayer = layer;
|
||||
return layer;
|
||||
}
|
||||
|
||||
private RenderLayer layerLookup(ResourceLocation texture, TesrMaterial material, boolean noPass, PassOverride pass, float offsetFactor, float offsetUnits) {
|
||||
final LayerKey key = scratchKey.set(texture, material.transparency(), material.isNoCull(), material.isUnlit(), material.isNoDepthWrite(), material.isDepthOnly(), material.cutoutAlpha(), material.isDepthEqual(), material.special(), material.shader(), noPass, pass, offsetFactor, offsetUnits);
|
||||
RenderLayer layer = layers.get(key);
|
||||
if (layer == null) {
|
||||
layer = RenderLayer.tesr(texture, material);
|
||||
layer = noPass ? RenderLayer.tesrNoPass(texture, material) : RenderLayer.tesr(texture, material, pass, offsetFactor, offsetUnits);
|
||||
layers.put(key.copy(), layer);
|
||||
}
|
||||
return layer;
|
||||
@@ -232,9 +280,9 @@ public final class TesrBatchRenderer {
|
||||
|
||||
private static int currentPackedLight(TesrMaterial material) {
|
||||
if (material.hasLightmap()) {
|
||||
return ((int) material.lightmapY() << 16) | ((int) material.lightmapX() & 0xFFFF);
|
||||
return GLSMConfig.packBrightness(material.lightmapX(), material.lightmapY());
|
||||
}
|
||||
return ((int) GLSMConfig.lastBrightnessY << 16) | ((int) GLSMConfig.lastBrightnessX & 0xFFFF);
|
||||
return GLSMConfig.packedLastBrightness();
|
||||
}
|
||||
|
||||
private static int resolveColor(TesrMaterial material) {
|
||||
@@ -290,6 +338,7 @@ public final class TesrBatchRenderer {
|
||||
try {
|
||||
final EntityRenderer entityRenderer = Minecraft.getMinecraft().entityRenderer;
|
||||
final boolean savedDepthMask = GLStateManager.getDepthState().isEnabled();
|
||||
final boolean savedDepthTest = GLStateManager.getDepthTest().isEnabled();
|
||||
final boolean savedBlend = GLStateManager.getBlendMode().isEnabled();
|
||||
final int savedSrcRgb = GLStateManager.getBlendState().getSrcRgb();
|
||||
final int savedDstRgb = GLStateManager.getBlendState().getDstRgb();
|
||||
@@ -312,11 +361,12 @@ public final class TesrBatchRenderer {
|
||||
bufferSource.endBatch(hook);
|
||||
instancedRenderer.endFrame();
|
||||
AngelicaBufferSource.rebindPass();
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
} finally {
|
||||
if (wrap) GbufferPrograms.endBlockEntities();
|
||||
entityRenderer.disableLightmap(0);
|
||||
GLStateManager.glDepthMask(savedDepthMask);
|
||||
if (savedDepthTest) GLStateManager.enableDepthTest(); else GLStateManager.disableDepthTest();
|
||||
if (savedBlend) GLStateManager.enableBlend(); else GLStateManager.disableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(savedSrcRgb, savedDstRgb, savedSrcAlpha, savedDstAlpha);
|
||||
if (savedAlphaTest) GLStateManager.enableAlphaTest(); else GLStateManager.disableAlphaTest();
|
||||
@@ -452,7 +502,7 @@ public final class TesrBatchRenderer {
|
||||
final long end = VertexTransform.writeInstance(addr, format, template, identity, scratchVec, colorABGR, packedLight, null);
|
||||
immediateScratch.position((int) (end - addr));
|
||||
immediateScratch.flip();
|
||||
final RenderLayer layer = layerFor(texture, material);
|
||||
final RenderLayer layer = noPassLayerFor(texture, material);
|
||||
GLStateManager.glPushAttrib(AngelicaBufferSource.SAVED_STATE_BITS);
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
layer.startDrawing();
|
||||
|
||||
@@ -11,8 +11,6 @@ import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import org.lwjgl.opengl.Display;
|
||||
|
||||
import com.cardinalstar.cubicchunks.api.compat.CubicChunksVideoSettings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
@@ -21,7 +19,6 @@ import com.gtnewhorizons.angelica.rendering.celeritas.MultiDrawModeResolver;
|
||||
import com.gtnewhorizons.angelica.rendering.culling.GpuCulling;
|
||||
import com.gtnewhorizons.angelica.config.GpuCullingMode;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import cpw.mods.fml.common.Optional.Method;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader;
|
||||
import jss.notfine.core.Settings;
|
||||
@@ -48,6 +45,7 @@ import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStor
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.SodiumOptionsStorage;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gui.option.IrisVideoSettings;
|
||||
import net.coderbot.iris.pipeline.ShadowRenderer;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.occlusion.AsyncOcclusionMode;
|
||||
|
||||
public class SodiumGameOptionPages {
|
||||
@@ -519,6 +517,36 @@ public class SodiumGameOptionPages {
|
||||
|
||||
.build());
|
||||
|
||||
if (Iris.enabled) {
|
||||
final OptionImpl<AngelicaConfig, Integer> shadowGraphAngleDelta =
|
||||
OptionImpl.createBuilder(int.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.shadowGraphAngleDelta"))
|
||||
.setTooltip(I18n.format("options.angelica.shadowGraphAngleDelta.tooltip"))
|
||||
.setControl(o -> new SliderControl(o, 0, 100, 1, ControlValueFormatter.shadowGraphAngleDelta()))
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setBinding((opts, value) -> AngelicaConfig.shadowGraphAngleDelta = value * 0.001f,
|
||||
opts -> Math.round(AngelicaConfig.shadowGraphAngleDelta * 1000.0f))
|
||||
.build();
|
||||
shadowGraphAngleDelta.iris$dynamicallyEnable(ShadowRenderer::shadowGraphGateIsNotBypassed);
|
||||
|
||||
final OptionImpl<AngelicaConfig, Integer> shadowGraphHorizonScale =
|
||||
OptionImpl.createBuilder(int.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.shadowGraphHorizonScale"))
|
||||
.setTooltip(I18n.format("options.angelica.shadowGraphHorizonScale.tooltip"))
|
||||
.setControl(o -> new SliderControl(o, 0, 100, 1, ControlValueFormatter.shadowGraphHorizonScale()))
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.setBinding((opts, value) -> AngelicaConfig.shadowGraphHorizonScale = value * 0.01f,
|
||||
opts -> Math.round(AngelicaConfig.shadowGraphHorizonScale * 100.0f))
|
||||
.build();
|
||||
shadowGraphHorizonScale.iris$dynamicallyEnable(
|
||||
() -> ShadowRenderer.shadowGraphGateIsNotBypassed() && shadowGraphAngleDelta.getValue() != 0);
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(shadowGraphAngleDelta)
|
||||
.add(shadowGraphHorizonScale)
|
||||
.build());
|
||||
}
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.hudCaching"))
|
||||
|
||||
+12
@@ -2,6 +2,8 @@ package me.jellysquid.mods.sodium.client.gui.options.control;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public interface ControlValueFormatter {
|
||||
static ControlValueFormatter guiScale() {
|
||||
return (v) -> (v == 0) ? I18n.format("options.guiScale.auto") : I18n.format(v + "x");
|
||||
@@ -47,4 +49,14 @@ public interface ControlValueFormatter {
|
||||
static ControlValueFormatter number() {
|
||||
return String::valueOf;
|
||||
}
|
||||
|
||||
static ControlValueFormatter shadowGraphAngleDelta() {
|
||||
return (v) -> v == 0
|
||||
? I18n.format("options.angelica.shadowGraphAngleDelta.always")
|
||||
: String.format(Locale.ROOT, "%.3f°", v * 0.001f);
|
||||
}
|
||||
|
||||
static ControlValueFormatter shadowGraphHorizonScale() {
|
||||
return (v) -> v == 100 ? I18n.format("options.angelica.shadowGraphHorizonScale.off") : v + "%";
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.coderbot.batchedentityrendering.impl.ordering.SimpleRenderOrderManager;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -159,15 +161,17 @@ public class AngelicaBufferSource implements Groupable {
|
||||
|
||||
private void clearCurrentId() {
|
||||
if (!anyIdSet) return;
|
||||
if (idKind == GroupIdKind.ENTITY) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityColor(0f, 0f, 0f, 0f);
|
||||
} else {
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(0);
|
||||
}
|
||||
// A pass can set either kind: nested entities inside a TESR write the entity id during a block entity pass
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(-1, 0);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityColor(0f, 0f, 0f, 0f);
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(0);
|
||||
anyIdSet = false;
|
||||
}
|
||||
|
||||
private GroupIdKind effectiveIdKind() {
|
||||
return GbufferPrograms.getCurrentPhase() == WorldRenderingPhase.ENTITIES ? GroupIdKind.ENTITY : idKind;
|
||||
}
|
||||
|
||||
private void drawLayer(RenderLayer layer, LayerDrawHook hook) {
|
||||
final List<BufferSegment> segments = typeToSegment.get(layer);
|
||||
final boolean hasDynamic = segments != null && !segments.isEmpty();
|
||||
@@ -184,7 +188,7 @@ public class AngelicaBufferSource implements Groupable {
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glLoadIdentity();
|
||||
SegmentedBufferBuilder.LayerBuffer bound = null;
|
||||
final boolean entityKind = idKind == GroupIdKind.ENTITY;
|
||||
final boolean entityKind = effectiveIdKind() == GroupIdKind.ENTITY;
|
||||
int currentId = Integer.MIN_VALUE;
|
||||
int currentColor = 0;
|
||||
boolean colorSet = false;
|
||||
@@ -271,8 +275,8 @@ public class AngelicaBufferSource implements Groupable {
|
||||
|
||||
public void applyIdAndRebind(int id) {
|
||||
anyIdSet = true;
|
||||
if (idKind == GroupIdKind.ENTITY) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(id);
|
||||
if (effectiveIdKind() == GroupIdKind.ENTITY) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(id, 0);
|
||||
rebindPass();
|
||||
} else {
|
||||
setBlockEntityAndRebind(id);
|
||||
@@ -281,8 +285,8 @@ public class AngelicaBufferSource implements Groupable {
|
||||
|
||||
public void applyIdNoRebind(int id) {
|
||||
anyIdSet = true;
|
||||
if (idKind == GroupIdKind.ENTITY) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(id);
|
||||
if (effectiveIdKind() == GroupIdKind.ENTITY) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(id, 0);
|
||||
} else {
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(id);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import net.minecraft.launchwrapper.Launch;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -919,6 +920,11 @@ public class Iris {
|
||||
return pipelineManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PipelineManager getPipelineManagerNullable() {
|
||||
return pipelineManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Optional<ShaderPack> getCurrentPack() {
|
||||
return Optional.ofNullable(currentPack);
|
||||
|
||||
@@ -69,13 +69,17 @@ public class CeleritasTerrainPipeline {
|
||||
IntFunction<ProgramImages> createTerrainImages,
|
||||
IntFunction<ProgramImages> createShadowImages,
|
||||
CustomUniforms customUniforms,
|
||||
Optional<ProgramSource> terrainSource,
|
||||
Optional<ProgramSource> terrainSolidSource,
|
||||
Optional<ProgramSource> terrainCutoutSource,
|
||||
Optional<ProgramSource> translucentSource,
|
||||
Optional<ProgramSource> shadowSource,
|
||||
Optional<ProgramSource> shadowSolidSource,
|
||||
Optional<ProgramSource> shadowCutoutSource,
|
||||
Optional<ProgramSource> shadowTranslucentSource,
|
||||
CompletableFuture<Map<PatchShaderType, String>> terrainFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> terrainSolidFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> terrainCutoutFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> translucentFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowSolidFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowCutoutFuture,
|
||||
CompletableFuture<Map<PatchShaderType, String>> shadowTranslucentFuture,
|
||||
RenderTargets renderTargets,
|
||||
ImmutableSet<Integer> flippedAfterPrepare,
|
||||
@@ -90,11 +94,12 @@ public class CeleritasTerrainPipeline {
|
||||
|
||||
// Build program source map (local - only needed during construction)
|
||||
final EnumMap<IrisTerrainPass, Optional<ProgramSource>> gbufferProgramSource = new EnumMap<>(IrisTerrainPass.class);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_SOLID, terrainSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_CUTOUT, terrainSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_TRANSLUCENT, translucentSource.isPresent() ? translucentSource : terrainSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW, shadowSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW_TRANSLUCENT, shadowTranslucentSource.isPresent() ? shadowTranslucentSource : shadowSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_SOLID, terrainSolidSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_CUTOUT, terrainCutoutSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.GBUFFER_TRANSLUCENT, translucentSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW, shadowSolidSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW_CUTOUT, shadowCutoutSource);
|
||||
gbufferProgramSource.put(IrisTerrainPass.SHADOW_TRANSLUCENT, shadowTranslucentSource);
|
||||
|
||||
// Initialize PassInfo, framebuffers, blend modes, and alpha in single pass
|
||||
for (IrisTerrainPass pass : IrisTerrainPass.VALUES) {
|
||||
@@ -103,10 +108,12 @@ public class CeleritasTerrainPipeline {
|
||||
|
||||
// Set up framebuffer, blend mode, and buffer blend overrides
|
||||
final ProgramId programId = switch (pass) {
|
||||
case GBUFFER_SOLID -> ProgramId.TerrainSolid;
|
||||
case GBUFFER_CUTOUT -> ProgramId.TerrainCutout;
|
||||
case GBUFFER_TRANSLUCENT -> ProgramId.Water;
|
||||
case SHADOW_TRANSLUCENT -> ProgramId.ShadowWater;
|
||||
case SHADOW, SHADOW_CUTOUT -> ProgramId.Shadow;
|
||||
default -> ProgramId.Terrain;
|
||||
case SHADOW -> ProgramId.ShadowSolid;
|
||||
case SHADOW_CUTOUT -> ProgramId.ShadowCutout;
|
||||
};
|
||||
|
||||
if (pass.isShadow()) {
|
||||
@@ -146,10 +153,12 @@ public class CeleritasTerrainPipeline {
|
||||
}
|
||||
|
||||
// Process and apply shader sources
|
||||
processShaderFuture(terrainFuture, terrainSource, passInfoMap.get(IrisTerrainPass.GBUFFER_SOLID), passInfoMap.get(IrisTerrainPass.GBUFFER_CUTOUT));
|
||||
processShaderFuture(terrainSolidFuture, terrainSolidSource, passInfoMap.get(IrisTerrainPass.GBUFFER_SOLID));
|
||||
processShaderFuture(terrainCutoutFuture, terrainCutoutSource, passInfoMap.get(IrisTerrainPass.GBUFFER_CUTOUT));
|
||||
processShaderFuture(translucentFuture, translucentSource, passInfoMap.get(IrisTerrainPass.GBUFFER_TRANSLUCENT));
|
||||
processShaderFuture(shadowFuture, shadowSource, passInfoMap.get(IrisTerrainPass.SHADOW), passInfoMap.get(IrisTerrainPass.SHADOW_CUTOUT));
|
||||
processShaderFuture(shadowTranslucentFuture, shadowTranslucentSource.isPresent() ? shadowTranslucentSource : shadowSource, passInfoMap.get(IrisTerrainPass.SHADOW_TRANSLUCENT));
|
||||
processShaderFuture(shadowSolidFuture, shadowSolidSource, passInfoMap.get(IrisTerrainPass.SHADOW));
|
||||
processShaderFuture(shadowCutoutFuture, shadowCutoutSource, passInfoMap.get(IrisTerrainPass.SHADOW_CUTOUT));
|
||||
processShaderFuture(shadowTranslucentFuture, shadowTranslucentSource, passInfoMap.get(IrisTerrainPass.SHADOW_TRANSLUCENT));
|
||||
}
|
||||
|
||||
private void processShaderFuture(@Nullable CompletableFuture<Map<PatchShaderType, String>> future, Optional<ProgramSource> source, PassInfo... targets) {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package net.coderbot.iris.fantastic;
|
||||
|
||||
// TODO: RenderType
|
||||
//public class IrisParticleRenderTypes {
|
||||
// public static final ParticleRenderType OPAQUE_TERRAIN = new ParticleRenderType() {
|
||||
// public void begin(BufferBuilder bufferBuilder, TextureManager textureManager) {
|
||||
// GL11.glDisable(GL11.GL_BLEND);
|
||||
// GL11.glDepthMask(true);
|
||||
// GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
// textureManager.bind(TextureAtlas.LOCATION_BLOCKS);
|
||||
// bufferBuilder.begin(7, DefaultVertexFormat.PARTICLE);
|
||||
// }
|
||||
//
|
||||
// public void end(Tesselator tesselator) {
|
||||
// tesselator.end();
|
||||
// }
|
||||
//
|
||||
// public String toString() {
|
||||
// return "OPAQUE_TERRAIN_SHEET";
|
||||
// }
|
||||
// };
|
||||
//}
|
||||
@@ -12,6 +12,8 @@ public enum RenderCondition {
|
||||
BEACON_BEAM,
|
||||
ENTITIES,
|
||||
ENTITIES_TRANSLUCENT,
|
||||
PARTICLES,
|
||||
PARTICLES_TRANSLUCENT,
|
||||
GLINT,
|
||||
ENTITY_EYES,
|
||||
HAND_OPAQUE,
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package net.coderbot.iris.gbuffer_overrides.matching;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Decides whether a draw is blending.
|
||||
*/
|
||||
public final class TranslucentBlendMatcher {
|
||||
|
||||
/** Render thread only. */
|
||||
private static final BlendState scratch = new BlendState();
|
||||
|
||||
private TranslucentBlendMatcher() {}
|
||||
|
||||
public static boolean matchesCurrentState() {
|
||||
if (!GLStateManager.isEffectiveBlendEnabled()) {
|
||||
return false;
|
||||
}
|
||||
GLStateManager.getEffectiveBlendState(scratch);
|
||||
return scratch.getSrcRgb() == GL11.GL_SRC_ALPHA && scratch.getDstRgb() == GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
}
|
||||
@@ -3,57 +3,114 @@ package net.coderbot.iris.gl.blending;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaTestFunction;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaBooleanLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import lombok.Getter;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class AlphaTestStorage {
|
||||
private static boolean originalAlphaTestEnable;
|
||||
private static AlphaTest originalAlphaTest;
|
||||
@Getter
|
||||
private static boolean vanillaEnabled;
|
||||
private static int vanillaFunction = GL11.GL_ALWAYS;
|
||||
private static float vanillaReference;
|
||||
|
||||
@Getter
|
||||
private static boolean alphaTestLocked;
|
||||
|
||||
private static boolean overrideHeld;
|
||||
|
||||
public static void overrideAlphaTest(AlphaTest override) {
|
||||
if (!alphaTestLocked) {
|
||||
if (!overrideHeld) {
|
||||
final AlphaState alphaState = GLStateManager.getAlphaState();
|
||||
|
||||
// Only save the previous state if the alpha test wasn't already locked
|
||||
originalAlphaTestEnable = GLStateManager.getAlphaTest().isEnabled();
|
||||
originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(alphaState.getFunction()).orElse(AlphaTestFunction.ALWAYS), alphaState.getReference());
|
||||
}
|
||||
// Only save the previous state if the alpha test wasn't already overridden
|
||||
vanillaEnabled = GLStateManager.getAlphaTest().isEnabled();
|
||||
vanillaFunction = alphaState.getFunction();
|
||||
vanillaReference = alphaState.getReference();
|
||||
}
|
||||
|
||||
alphaTestLocked = false;
|
||||
overrideHeld = true;
|
||||
|
||||
if (override == null) {
|
||||
GLStateManager.disableAlphaTest();
|
||||
} else {
|
||||
if (override == null) {
|
||||
apply(false, GL11.GL_ALWAYS, 0.0f);
|
||||
} else {
|
||||
apply(true, override.getFunction().getGlId(), override.getReference());
|
||||
}
|
||||
}
|
||||
|
||||
private static void apply(boolean enabled, int function, float reference) {
|
||||
alphaTestLocked = false;
|
||||
try {
|
||||
if (enabled) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.glAlphaFunc(function, reference);
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
} finally {
|
||||
alphaTestLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void deferAlphaTestToggle(boolean enabled) {
|
||||
vanillaEnabled = enabled;
|
||||
}
|
||||
|
||||
public static void deferAlphaFunc(int function, float reference) {
|
||||
vanillaFunction = function;
|
||||
vanillaReference = reference;
|
||||
}
|
||||
|
||||
public static void restoreAlphaTest() {
|
||||
if (!overrideHeld) {
|
||||
return;
|
||||
}
|
||||
|
||||
alphaTestLocked = false;
|
||||
|
||||
if (vanillaEnabled) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.glAlphaFunc(override.getFunction().getGlId(), override.getReference());
|
||||
}
|
||||
|
||||
alphaTestLocked = true;
|
||||
}
|
||||
|
||||
public static void deferAlphaTestToggle(boolean enabled) {
|
||||
originalAlphaTestEnable = enabled;
|
||||
}
|
||||
|
||||
public static void deferAlphaFunc(int function, float reference) {
|
||||
originalAlphaTest = new AlphaTest(AlphaTestFunction.fromGlId(function).get(), reference);
|
||||
}
|
||||
|
||||
public static void restoreAlphaTest() {
|
||||
if (!alphaTestLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
alphaTestLocked = false;
|
||||
|
||||
if (originalAlphaTestEnable) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
} else {
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
}
|
||||
|
||||
GLStateManager.glAlphaFunc(originalAlphaTest.getFunction().getGlId(), originalAlphaTest.getReference());
|
||||
}
|
||||
GLStateManager.glAlphaFunc(vanillaFunction, vanillaReference);
|
||||
overrideHeld = false;
|
||||
}
|
||||
|
||||
public static final VanillaBooleanLayer ENABLE_LAYER = new VanillaBooleanLayer() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getVanilla() {
|
||||
return vanillaEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVanilla(boolean enabled) {
|
||||
vanillaEnabled = enabled;
|
||||
}
|
||||
};
|
||||
|
||||
public static final VanillaStateLayer<AlphaState> FUNC_LAYER = new VanillaStateLayer<>() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVanilla(AlphaState into) {
|
||||
into.setFunction(vanillaFunction);
|
||||
into.setReference(vanillaReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVanilla(AlphaState from) {
|
||||
vanillaFunction = from.getFunction();
|
||||
vanillaReference = from.getReference();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -2,126 +2,187 @@ package net.coderbot.iris.gl.blending;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaBooleanLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import lombok.Getter;
|
||||
|
||||
public class BlendModeStorage {
|
||||
private static final int MAX_DRAW_BUFFERS = 8;
|
||||
private static final int MAX_DRAW_BUFFERS = 8;
|
||||
|
||||
private static boolean originalBlendEnable;
|
||||
private static final BlendState originalBlend = new BlendState();
|
||||
@Getter private static boolean blendLocked;
|
||||
@Getter private static boolean hasDeferredChanges;
|
||||
private static final int[] bufferOverrideIndices = new int[MAX_DRAW_BUFFERS];
|
||||
private static final boolean[] bufferOverrideIsDisable = new boolean[MAX_DRAW_BUFFERS];
|
||||
private static final BlendState[] bufferOverrideStates = new BlendState[MAX_DRAW_BUFFERS];
|
||||
private static int bufferOverrideCount;
|
||||
private static boolean vanillaBlendEnable;
|
||||
private static final BlendState vanillaBlend = new BlendState();
|
||||
|
||||
static {
|
||||
for (int i = 0; i < MAX_DRAW_BUFFERS; i++) {
|
||||
bufferOverrideStates[i] = new BlendState();
|
||||
}
|
||||
}
|
||||
@Getter
|
||||
private static boolean blendLocked;
|
||||
@Getter
|
||||
private static boolean overrideHeld;
|
||||
|
||||
private static boolean hasGlobalOverride;
|
||||
|
||||
private static boolean hasDeferredChanges;
|
||||
private static final int[] bufferOverrideIndices = new int[MAX_DRAW_BUFFERS];
|
||||
private static final boolean[] bufferOverrideIsDisable = new boolean[MAX_DRAW_BUFFERS];
|
||||
private static final BlendState[] bufferOverrideStates = new BlendState[MAX_DRAW_BUFFERS];
|
||||
private static int bufferOverrideCount;
|
||||
private static boolean bufferOverridesDirty;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < MAX_DRAW_BUFFERS; i++) {
|
||||
bufferOverrideStates[i] = new BlendState();
|
||||
}
|
||||
}
|
||||
|
||||
public static void overrideBlend(BlendState override) {
|
||||
if (!blendLocked) {
|
||||
// Only save the previous state if the blend mode wasn't already locked
|
||||
originalBlendEnable = GLStateManager.getBlendMode().isEnabled();
|
||||
originalBlend.set(GLStateManager.getBlendState());
|
||||
}
|
||||
captureVanilla();
|
||||
|
||||
bufferOverrideCount = 0;
|
||||
hasDeferredChanges = false;
|
||||
blendLocked = false;
|
||||
bufferOverrideCount = 0;
|
||||
bufferOverridesDirty = false;
|
||||
hasDeferredChanges = false;
|
||||
overrideHeld = true;
|
||||
hasGlobalOverride = true;
|
||||
|
||||
if (override == null) {
|
||||
GLStateManager.disableBlend();
|
||||
} else {
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
blendLocked = false;
|
||||
try {
|
||||
if (override == null) {
|
||||
GLStateManager.disableBlend();
|
||||
} else {
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
} finally {
|
||||
blendLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
blendLocked = true;
|
||||
}
|
||||
public static void overrideBufferBlend(int index, BlendState override) {
|
||||
captureVanilla();
|
||||
|
||||
public static void overrideBufferBlend(int index, BlendState override) {
|
||||
if (!blendLocked) {
|
||||
// Only save the previous state if the blend mode wasn't already locked
|
||||
originalBlendEnable = GLStateManager.getBlendMode().isEnabled();
|
||||
originalBlend.set(GLStateManager.getBlendState());
|
||||
}
|
||||
if (override == null) {
|
||||
RenderSystem.disableBufferBlend(index);
|
||||
} else {
|
||||
RenderSystem.enableBufferBlend(index);
|
||||
RenderSystem.blendFuncSeparatei(index, override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
|
||||
if (override == null) {
|
||||
RenderSystem.disableBufferBlend(index);
|
||||
} else {
|
||||
RenderSystem.enableBufferBlend(index);
|
||||
RenderSystem.blendFuncSeparatei(index, override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
if (bufferOverrideCount < MAX_DRAW_BUFFERS) {
|
||||
final int slot = bufferOverrideCount++;
|
||||
bufferOverrideIndices[slot] = index;
|
||||
bufferOverrideIsDisable[slot] = (override == null);
|
||||
if (override != null) {
|
||||
bufferOverrideStates[slot].setAll(override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
}
|
||||
overrideHeld = true;
|
||||
blendLocked = true;
|
||||
}
|
||||
|
||||
if (bufferOverrideCount < MAX_DRAW_BUFFERS) {
|
||||
final int slot = bufferOverrideCount++;
|
||||
bufferOverrideIndices[slot] = index;
|
||||
bufferOverrideIsDisable[slot] = (override == null);
|
||||
if (override != null) {
|
||||
bufferOverrideStates[slot].setAll(override.getSrcRgb(), override.getDstRgb(), override.getSrcAlpha(), override.getDstAlpha());
|
||||
}
|
||||
}
|
||||
blendLocked = true;
|
||||
}
|
||||
private static void captureVanilla() {
|
||||
if (!overrideHeld) {
|
||||
vanillaBlendEnable = GLStateManager.getBlendMode().isEnabled();
|
||||
vanillaBlend.set(GLStateManager.getBlendState());
|
||||
}
|
||||
}
|
||||
|
||||
public static void deferBlendModeToggle(boolean enabled) {
|
||||
originalBlendEnable = enabled;
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
public static void deferBlendModeToggle(boolean enabled) {
|
||||
vanillaBlendEnable = enabled;
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
|
||||
public static void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
originalBlend.setAll(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
public static void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
vanillaBlend.setAll(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
|
||||
public static void flushDeferredBlend() {
|
||||
if (!blendLocked || !hasDeferredChanges) return;
|
||||
hasDeferredChanges = false;
|
||||
blendLocked = false;
|
||||
public static void flushDeferredBlend() {
|
||||
if (!overrideHeld) return;
|
||||
|
||||
if (originalBlendEnable) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
GLStateManager.tryBlendFuncSeparate(
|
||||
originalBlend.getSrcRgb(), originalBlend.getDstRgb(),
|
||||
originalBlend.getSrcAlpha(), originalBlend.getDstAlpha());
|
||||
if (hasDeferredChanges && !hasGlobalOverride) {
|
||||
hasDeferredChanges = false;
|
||||
applyVanilla();
|
||||
bufferOverridesDirty = true;
|
||||
}
|
||||
|
||||
blendLocked = true;
|
||||
if (bufferOverridesDirty) {
|
||||
bufferOverridesDirty = false;
|
||||
reassertBufferOverrides();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bufferOverrideCount; i++) {
|
||||
final int idx = bufferOverrideIndices[i];
|
||||
if (bufferOverrideIsDisable[i]) {
|
||||
RenderSystem.disableBufferBlend(idx);
|
||||
} else {
|
||||
final BlendState s = bufferOverrideStates[i];
|
||||
RenderSystem.enableBufferBlend(idx);
|
||||
RenderSystem.blendFuncSeparatei(idx, s.getSrcRgb(), s.getDstRgb(), s.getSrcAlpha(), s.getDstAlpha());
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void reassertBufferOverrides() {
|
||||
for (int i = 0; i < bufferOverrideCount; i++) {
|
||||
final int idx = bufferOverrideIndices[i];
|
||||
if (bufferOverrideIsDisable[i]) {
|
||||
RenderSystem.disableBufferBlend(idx);
|
||||
} else {
|
||||
final BlendState s = bufferOverrideStates[i];
|
||||
RenderSystem.enableBufferBlend(idx);
|
||||
RenderSystem.blendFuncSeparatei(idx, s.getSrcRgb(), s.getDstRgb(), s.getSrcAlpha(), s.getDstAlpha());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void restoreBlend() {
|
||||
if (!blendLocked) {
|
||||
return;
|
||||
}
|
||||
public static void restoreBlend() {
|
||||
if (!overrideHeld) {
|
||||
return;
|
||||
}
|
||||
|
||||
blendLocked = false;
|
||||
hasDeferredChanges = false;
|
||||
bufferOverrideCount = 0;
|
||||
hasGlobalOverride = false;
|
||||
hasDeferredChanges = false;
|
||||
bufferOverrideCount = 0;
|
||||
bufferOverridesDirty = false;
|
||||
blendLocked = false;
|
||||
|
||||
if (originalBlendEnable) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
applyVanilla();
|
||||
overrideHeld = false;
|
||||
}
|
||||
|
||||
GLStateManager.tryBlendFuncSeparate(originalBlend.getSrcRgb(), originalBlend.getDstRgb(), originalBlend.getSrcAlpha(), originalBlend.getDstAlpha());
|
||||
}
|
||||
private static void applyVanilla() {
|
||||
final boolean wasLocked = blendLocked;
|
||||
blendLocked = false;
|
||||
try {
|
||||
if (vanillaBlendEnable) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
GLStateManager.tryBlendFuncSeparate(vanillaBlend.getSrcRgb(), vanillaBlend.getDstRgb(), vanillaBlend.getSrcAlpha(), vanillaBlend.getDstAlpha());
|
||||
} finally {
|
||||
blendLocked = wasLocked;
|
||||
}
|
||||
}
|
||||
|
||||
public static final VanillaBooleanLayer ENABLE_LAYER = new VanillaBooleanLayer() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getVanilla() {
|
||||
return vanillaBlendEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVanilla(boolean enabled) {
|
||||
deferBlendModeToggle(enabled);
|
||||
}
|
||||
};
|
||||
|
||||
public static final VanillaStateLayer<BlendState> FUNC_LAYER = new VanillaStateLayer<>() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVanilla(BlendState into) {
|
||||
into.setAll(vanillaBlend.getSrcRgb(), vanillaBlend.getDstRgb(), vanillaBlend.getSrcAlpha(), vanillaBlend.getDstAlpha());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVanilla(BlendState from) {
|
||||
deferBlendFunc(from.getSrcRgb(), from.getDstRgb(), from.getSrcAlpha(), from.getDstAlpha());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -3,64 +3,105 @@ package net.coderbot.iris.gl.blending;
|
||||
import com.gtnewhorizons.angelica.glsm.states.DepthState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ColorMask;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.VanillaStateLayer;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import lombok.Getter;
|
||||
|
||||
public class DepthColorStorage {
|
||||
private static boolean originalDepthEnable;
|
||||
private static net.coderbot.iris.gl.blending.ColorMask originalColor;
|
||||
@Getter
|
||||
private static boolean vanillaDepthEnable;
|
||||
private static final ColorMask vanillaColor = new ColorMask();
|
||||
|
||||
@Getter
|
||||
private static boolean depthColorLocked;
|
||||
|
||||
private static final IntOpenHashSet ownedPrograms = new IntOpenHashSet();
|
||||
@Getter
|
||||
private static boolean overrideHeld;
|
||||
|
||||
public static void registerOwnedProgram(int programId) {
|
||||
ownedPrograms.add(programId);
|
||||
}
|
||||
private static final IntOpenHashSet ownedPrograms = new IntOpenHashSet();
|
||||
|
||||
public static void unregisterOwnedProgram(int programId) {
|
||||
ownedPrograms.remove(programId);
|
||||
}
|
||||
public static void registerOwnedProgram(int programId) {
|
||||
ownedPrograms.add(programId);
|
||||
}
|
||||
|
||||
public static boolean isOwnedProgram(int programId) {
|
||||
return ownedPrograms.contains(programId);
|
||||
}
|
||||
public static void unregisterOwnedProgram(int programId) {
|
||||
ownedPrograms.remove(programId);
|
||||
}
|
||||
|
||||
public static boolean isOwnedProgram(int programId) {
|
||||
return ownedPrograms.contains(programId);
|
||||
}
|
||||
|
||||
public static void disableDepthColor() {
|
||||
if (!depthColorLocked) {
|
||||
// Only save the previous state if the depth and color mask wasn't already locked
|
||||
final ColorMask colorMask = GLStateManager.getColorMask();
|
||||
final DepthState depthState = GLStateManager.getDepthState();
|
||||
if (!overrideHeld) {
|
||||
final ColorMask colorMask = GLStateManager.getColorMask();
|
||||
final DepthState depthState = GLStateManager.getDepthState();
|
||||
|
||||
originalDepthEnable = depthState.isEnabled();
|
||||
originalColor = new net.coderbot.iris.gl.blending.ColorMask(colorMask.red, colorMask.green, colorMask.blue, colorMask.alpha);
|
||||
}
|
||||
vanillaDepthEnable = depthState.isEnabled();
|
||||
vanillaColor.set(colorMask);
|
||||
}
|
||||
|
||||
depthColorLocked = false;
|
||||
overrideHeld = true;
|
||||
|
||||
GLStateManager.glDepthMask(false);
|
||||
GLStateManager.glColorMask(false, false, false, false);
|
||||
depthColorLocked = false;
|
||||
try {
|
||||
GLStateManager.glDepthMask(false);
|
||||
GLStateManager.glColorMask(false, false, false, false);
|
||||
} finally {
|
||||
depthColorLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
depthColorLocked = true;
|
||||
}
|
||||
public static void deferDepthEnable(boolean enabled) {
|
||||
vanillaDepthEnable = enabled;
|
||||
}
|
||||
|
||||
public static void deferDepthEnable(boolean enabled) {
|
||||
originalDepthEnable = enabled;
|
||||
}
|
||||
public static void deferColorMask(boolean red, boolean green, boolean blue, boolean alpha) {
|
||||
vanillaColor.setAll(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
public static void deferColorMask(boolean red, boolean green, boolean blue, boolean alpha) {
|
||||
originalColor = new net.coderbot.iris.gl.blending.ColorMask(red, green, blue, alpha);
|
||||
}
|
||||
public static void unlockDepthColor() {
|
||||
if (!overrideHeld) {
|
||||
return;
|
||||
}
|
||||
|
||||
public static void unlockDepthColor() {
|
||||
if (!depthColorLocked) {
|
||||
return;
|
||||
}
|
||||
depthColorLocked = false;
|
||||
|
||||
depthColorLocked = false;
|
||||
GLStateManager.glDepthMask(vanillaDepthEnable);
|
||||
GLStateManager.glColorMask(vanillaColor.red, vanillaColor.green, vanillaColor.blue, vanillaColor.alpha);
|
||||
overrideHeld = false;
|
||||
}
|
||||
|
||||
GLStateManager.glDepthMask(originalDepthEnable);
|
||||
public static final VanillaStateLayer<DepthState> DEPTH_LAYER = new VanillaStateLayer<>() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
GLStateManager.glColorMask(originalColor.isRedMasked(), originalColor.isGreenMasked(), originalColor.isBlueMasked(), originalColor.isAlphaMasked());
|
||||
}
|
||||
@Override
|
||||
public void readVanilla(DepthState into) {
|
||||
into.setEnabled(vanillaDepthEnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVanilla(DepthState from) {
|
||||
vanillaDepthEnable = from.isEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
public static final VanillaStateLayer<ColorMask> COLOR_LAYER = new VanillaStateLayer<>() {
|
||||
@Override
|
||||
public boolean isOverrideHeld() {
|
||||
return overrideHeld;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVanilla(ColorMask into) {
|
||||
into.set(vanillaColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVanilla(ColorMask from) {
|
||||
vanillaColor.set(from);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -36,7 +36,6 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
@Getter
|
||||
private ShaderPackEntry applied = null;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private ShaderPackEntry selected = null;
|
||||
|
||||
@@ -203,6 +202,11 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelected(ShaderPackEntry selected) {
|
||||
this.selected = selected;
|
||||
this.screen.refreshScreenSwitchButton();
|
||||
}
|
||||
|
||||
public void select(String name) {
|
||||
for (BaseEntry entry : this.entries) {
|
||||
if (entry instanceof ShaderPackEntry shaderPackEntry && name.equals(shaderPackEntry.getPackName())) {
|
||||
|
||||
@@ -39,8 +39,10 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@@ -85,6 +87,8 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
private boolean guiHidden = false;
|
||||
private boolean dirty = false;
|
||||
|
||||
private final Map<String, Boolean> packOptionAvailability = new HashMap<>();
|
||||
|
||||
public ShaderPackScreen(GuiScreen parent) {
|
||||
this.title = I18n.format("options.iris.shaderPackSelection.title");
|
||||
|
||||
@@ -250,19 +254,7 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
I18n.format("options.iris.openShaderPackFolder"), button -> this.openShaderPackFolder()));
|
||||
|
||||
this.screenSwitchButton = new IrisButton(topCenter + 78, this.height - 51, 152, 20,
|
||||
I18n.format("options.iris.shaderPackList"), button -> {
|
||||
this.optionMenuOpen = !this.optionMenuOpen;
|
||||
|
||||
// UX: Apply changes before switching screens to avoid unintuitive behavior
|
||||
//
|
||||
// Not doing this leads to unintuitive behavior, since selecting a pack in the
|
||||
// list (but not applying) would open the settings for the previous pack, rather
|
||||
// than opening the settings for the selected (but not applied) pack.
|
||||
this.applyChanges();
|
||||
|
||||
initGui();
|
||||
}
|
||||
);
|
||||
I18n.format("options.iris.shaderPackList"), button -> this.toggleOptionMenu());
|
||||
this.buttonList.add(this.screenSwitchButton);
|
||||
|
||||
refreshScreenSwitchButton();
|
||||
@@ -299,6 +291,17 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
super.updateScreen();
|
||||
|
||||
if (this.notificationDialogTimer > 0) {
|
||||
this.notificationDialogTimer--;
|
||||
} else if (this.notificationDialog != null) {
|
||||
this.notificationDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mouse is clicked.
|
||||
*/
|
||||
@@ -346,10 +349,52 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches between the pack list and the pack settings, applying the pending pack first.
|
||||
* <p>
|
||||
* UX: Apply changes before switching screens to avoid unintuitive behavior. Not doing this leads to
|
||||
* unintuitive behavior, since selecting a pack in the list (but not applying) would open the settings
|
||||
* for the previous pack, rather than opening the settings for the selected (but not applied) pack.
|
||||
*/
|
||||
private void toggleOptionMenu() {
|
||||
final boolean opening = !this.optionMenuOpen;
|
||||
this.optionMenuOpen = opening;
|
||||
|
||||
this.applyChanges();
|
||||
|
||||
// The pack is only parsed by applyChanges, so this is the first point where an option-less
|
||||
// pack can be recognized. Stay on the list instead of opening an empty settings screen.
|
||||
if (opening && !currentPackHasOptions()) {
|
||||
this.optionMenuOpen = false;
|
||||
displayNotification(I18n.format("options.iris.shaderPackOptions.noOptions", Iris.getCurrentPackName()));
|
||||
}
|
||||
|
||||
initGui();
|
||||
}
|
||||
|
||||
private boolean canOpenOptionMenu() {
|
||||
if (!this.shaderPackList.getTopButtonRow().shadersEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ShaderPackEntry highlighted = this.shaderPackList.getSelected();
|
||||
final String name = highlighted != null ? highlighted.getPackName() : Iris.getCurrentPackName();
|
||||
|
||||
return name == null || this.packOptionAvailability.getOrDefault(name, Boolean.TRUE);
|
||||
}
|
||||
|
||||
private boolean currentPackHasOptions() {
|
||||
return Iris.getCurrentPack().map(p -> p.getMenuContainer().hasMenuElements()).orElse(false);
|
||||
}
|
||||
|
||||
public void refreshForChangedPack() {
|
||||
if (Iris.getCurrentPack().isPresent()) {
|
||||
final ShaderPack currentPack = Iris.getCurrentPack().get();
|
||||
|
||||
if (Iris.getCurrentPackName() != null) {
|
||||
this.packOptionAvailability.put(Iris.getCurrentPackName(), currentPack.getMenuContainer().hasMenuElements());
|
||||
}
|
||||
|
||||
this.navigation = new NavigationController();
|
||||
|
||||
if (this.shaderOptionList != null) {
|
||||
@@ -364,11 +409,10 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
}
|
||||
|
||||
public void refreshScreenSwitchButton() {
|
||||
if (this.screenSwitchButton != null) {
|
||||
if (this.screenSwitchButton != null && this.shaderPackList != null) {
|
||||
this.screenSwitchButton.displayString = optionMenuOpen ? I18n.format("options.iris.shaderPackList") : I18n.format("options.iris.shaderPackSettings");
|
||||
// Disable the settings switch when shaders are off or the selected pack exposes no options
|
||||
this.screenSwitchButton.enabled = optionMenuOpen || (shaderPackList.getTopButtonRow().shadersEnabled
|
||||
&& Iris.getCurrentPack().map(p -> !p.getMenuContainer().mainScreen.elements.isEmpty()).orElse(true));
|
||||
// Disable the settings switch when shaders are off or the highlighted pack exposes no options
|
||||
this.screenSwitchButton.enabled = optionMenuOpen || canOpenOptionMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,12 +479,8 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
return;
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_TAB) {
|
||||
final boolean canOpenOptions = shaderPackList.getTopButtonRow().shadersEnabled
|
||||
&& Iris.getCurrentPack().map(p -> !p.getMenuContainer().mainScreen.elements.isEmpty()).orElse(false);
|
||||
if (this.optionMenuOpen || canOpenOptions) {
|
||||
this.optionMenuOpen = !this.optionMenuOpen;
|
||||
this.applyChanges();
|
||||
this.initGui();
|
||||
if (this.optionMenuOpen || canOpenOptionMenu()) {
|
||||
toggleOptionMenu();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
package net.coderbot.iris.layer;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.AlphaState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import net.coderbot.iris.gl.shader.ProgramCreator;
|
||||
import net.coderbot.iris.gl.state.StateUpdateNotifiers;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GbufferPrograms {
|
||||
private static boolean entities;
|
||||
private static boolean blockEntities;
|
||||
private static boolean particles;
|
||||
private static boolean outline;
|
||||
private static boolean entityLoop;
|
||||
private static Runnable phaseChangeListener;
|
||||
|
||||
|
||||
static {
|
||||
StateUpdateNotifiers.phaseChangeNotifier = listener -> phaseChangeListener = listener;
|
||||
}
|
||||
|
||||
|
||||
private static void checkReentrancy() {
|
||||
if (entities || blockEntities || outline) {
|
||||
throw new IllegalStateException("GbufferPrograms in weird state, tried to call begin function when entities = "
|
||||
@@ -61,8 +69,18 @@ public class GbufferPrograms {
|
||||
throw new IllegalStateException("GbufferPrograms in weird state, tried to call endEntities when entities = false");
|
||||
}
|
||||
|
||||
setPhase(WorldRenderingPhase.NONE);
|
||||
entities = false;
|
||||
endPhase();
|
||||
}
|
||||
|
||||
private static void endPhase() {
|
||||
if (particles) {
|
||||
setPhase(WorldRenderingPhase.PARTICLES);
|
||||
} else if (entityLoop) {
|
||||
setPhase(WorldRenderingPhase.ENTITIES);
|
||||
} else {
|
||||
setPhase(WorldRenderingPhase.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void beginOutline() {
|
||||
@@ -76,10 +94,41 @@ public class GbufferPrograms {
|
||||
throw new IllegalStateException("GbufferPrograms in weird state, tried to call endOutline when outline = false");
|
||||
}
|
||||
|
||||
setPhase(WorldRenderingPhase.NONE);
|
||||
outline = false;
|
||||
endPhase();
|
||||
}
|
||||
|
||||
public static int beginParticles() {
|
||||
if (particleDepth == particlePhaseSaves.length) {
|
||||
particlePhaseSaves = Arrays.copyOf(particlePhaseSaves, particleDepth * 2);
|
||||
particleTranslucencySaves = Arrays.copyOf(particleTranslucencySaves, particleDepth * 2);
|
||||
}
|
||||
|
||||
particlePhaseSaves[particleDepth] = getCurrentPhase();
|
||||
particleTranslucencySaves[particleDepth] = beginTranslucencyDeclaration(Boolean.FALSE);
|
||||
|
||||
setPhase(WorldRenderingPhase.PARTICLES);
|
||||
particles = true;
|
||||
|
||||
return particleDepth++;
|
||||
}
|
||||
|
||||
public static void endParticles(int depth) {
|
||||
particleDepth = depth;
|
||||
|
||||
endTranslucencyDeclaration(particleTranslucencySaves[depth]);
|
||||
particleTranslucencySaves[depth] = null;
|
||||
|
||||
setPhase(particlePhaseSaves[depth]);
|
||||
particlePhaseSaves[depth] = null;
|
||||
|
||||
particles = particleDepth > 0;
|
||||
}
|
||||
|
||||
private static WorldRenderingPhase[] particlePhaseSaves = new WorldRenderingPhase[4];
|
||||
private static Boolean[] particleTranslucencySaves = new Boolean[4];
|
||||
private static int particleDepth;
|
||||
|
||||
public static void beginBlockEntities() {
|
||||
checkReentrancy();
|
||||
setPhase(WorldRenderingPhase.BLOCK_ENTITIES);
|
||||
@@ -92,8 +141,101 @@ public class GbufferPrograms {
|
||||
throw new IllegalStateException("GbufferPrograms in weird state, tried to call endBlockEntities when blockEntities = false");
|
||||
}
|
||||
|
||||
setPhase(WorldRenderingPhase.NONE);
|
||||
blockEntities = false;
|
||||
endPhase();
|
||||
}
|
||||
|
||||
public static void setCutoutDefaults() {
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
|
||||
final int previousUnit = GLStateManager.getActiveTextureUnitForServerState();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GLStateManager.enableTexture();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + previousUnit);
|
||||
}
|
||||
|
||||
public static long pushCutoutDefaults() {
|
||||
final long saved = packCutoutState();
|
||||
setCutoutDefaults();
|
||||
return saved;
|
||||
}
|
||||
|
||||
public static void popCutoutDefaults(long saved) {
|
||||
if ((saved & ALPHA_ENABLED_BIT) != 0) {
|
||||
GLStateManager.enableAlphaTest();
|
||||
} else {
|
||||
GLStateManager.disableAlphaTest();
|
||||
}
|
||||
GLStateManager.glAlphaFunc((int) ((saved >>> 32) & 0xFFFF), Float.intBitsToFloat((int) saved));
|
||||
|
||||
if ((saved & LIGHTMAP_ENABLED_BIT) == 0) {
|
||||
final int previousUnit = GLStateManager.getActiveTextureUnitForServerState();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
GLStateManager.disableTexture();
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0 + previousUnit);
|
||||
}
|
||||
}
|
||||
|
||||
public static int pushBlendState() {
|
||||
if (blendDepth == blendSaves.length) {
|
||||
blendSaves = Arrays.copyOf(blendSaves, blendDepth * 2);
|
||||
blendEnabledSaves = Arrays.copyOf(blendEnabledSaves, blendDepth * 2);
|
||||
}
|
||||
|
||||
BlendState saved = blendSaves[blendDepth];
|
||||
if (saved == null) {
|
||||
saved = new BlendState();
|
||||
blendSaves[blendDepth] = saved;
|
||||
}
|
||||
|
||||
GLStateManager.getEffectiveBlendState(saved);
|
||||
blendEnabledSaves[blendDepth] = GLStateManager.isEffectiveBlendEnabled();
|
||||
|
||||
return blendDepth++;
|
||||
}
|
||||
public static void popBlendState(int depth) {
|
||||
blendDepth = depth;
|
||||
|
||||
final boolean enabled = blendEnabledSaves[depth];
|
||||
if (enabled != GLStateManager.isEffectiveBlendEnabled()) {
|
||||
if (enabled) {
|
||||
GLStateManager.enableBlend();
|
||||
} else {
|
||||
GLStateManager.disableBlend();
|
||||
}
|
||||
}
|
||||
|
||||
final BlendState saved = blendSaves[depth];
|
||||
GLStateManager.getEffectiveBlendState(blendScratch);
|
||||
if (blendScratch.getSrcRgb() != saved.getSrcRgb() || blendScratch.getDstRgb() != saved.getDstRgb()
|
||||
|| blendScratch.getSrcAlpha() != saved.getSrcAlpha() || blendScratch.getDstAlpha() != saved.getDstAlpha()) {
|
||||
GLStateManager.tryBlendFuncSeparate(saved.getSrcRgb(), saved.getDstRgb(), saved.getSrcAlpha(), saved.getDstAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
public static void popBlendStateTop() {
|
||||
if (blendDepth > 0) {
|
||||
popBlendState(blendDepth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private static BlendState[] blendSaves = new BlendState[4];
|
||||
private static boolean[] blendEnabledSaves = new boolean[4];
|
||||
private static int blendDepth;
|
||||
private static final BlendState blendScratch = new BlendState();
|
||||
|
||||
private static final long ALPHA_ENABLED_BIT = 1L << 48;
|
||||
private static final long LIGHTMAP_ENABLED_BIT = 1L << 49;
|
||||
private static final AlphaState alphaScratch = new AlphaState();
|
||||
|
||||
private static long packCutoutState() {
|
||||
GLStateManager.getEffectiveAlphaState(alphaScratch);
|
||||
|
||||
return (Float.floatToRawIntBits(alphaScratch.getReference()) & 0xFFFFFFFFL)
|
||||
| ((long) (alphaScratch.getFunction() & 0xFFFF) << 32)
|
||||
| (GLStateManager.isEffectiveAlphaTestEnabled() ? ALPHA_ENABLED_BIT : 0L)
|
||||
| (GLStateManager.getTextures().getTextureUnitStates(1).isEnabled() ? LIGHTMAP_ENABLED_BIT : 0L);
|
||||
}
|
||||
|
||||
public static void setBlockEntityDefaults() {
|
||||
@@ -121,7 +263,23 @@ public class GbufferPrograms {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean beginNestedEntityPhase() {
|
||||
if (getCurrentPhase() != WorldRenderingPhase.BLOCK_ENTITIES) {
|
||||
return false;
|
||||
}
|
||||
setOverridePhase(WorldRenderingPhase.ENTITIES);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void endNestedEntityPhase(boolean pushed) {
|
||||
if (pushed) {
|
||||
setOverridePhase(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setOverridePhase(WorldRenderingPhase phase) {
|
||||
overridePhase = phase;
|
||||
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
|
||||
if (pipeline != null) {
|
||||
@@ -129,20 +287,62 @@ public class GbufferPrograms {
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
private static WorldRenderingPhase overridePhase;
|
||||
|
||||
public static Boolean beginTranslucencyDeclaration(Boolean translucent) {
|
||||
final Boolean previous = declaredTranslucent;
|
||||
declaredTranslucent = translucent;
|
||||
applyTranslucencyDeclaration();
|
||||
return previous;
|
||||
}
|
||||
|
||||
public static void endTranslucencyDeclaration(Boolean previous) {
|
||||
declaredTranslucent = previous;
|
||||
applyTranslucencyDeclaration();
|
||||
}
|
||||
|
||||
public static void setTranslucencyDeclaration(Boolean translucent) {
|
||||
declaredTranslucent = translucent;
|
||||
applyTranslucencyDeclaration();
|
||||
}
|
||||
|
||||
private static Boolean declaredTranslucent;
|
||||
|
||||
private static void applyTranslucencyDeclaration() {
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
|
||||
if (pipeline != null) {
|
||||
pipeline.setDeclaredTranslucency(declaredTranslucent);
|
||||
}
|
||||
}
|
||||
|
||||
private static SpecialCondition currentSpecial;
|
||||
|
||||
public static SpecialCondition getSpecialCondition() {
|
||||
return currentSpecial;
|
||||
}
|
||||
|
||||
public static Boolean getDeclaredTranslucency() {
|
||||
return declaredTranslucent;
|
||||
}
|
||||
|
||||
public static void setupSpecialRenderCondition(SpecialCondition override) {
|
||||
currentSpecial = override;
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(override));
|
||||
}
|
||||
|
||||
public static void teardownSpecialRenderCondition() {
|
||||
currentSpecial = null;
|
||||
Iris.getPipelineManager().getPipeline().ifPresent(p -> p.setSpecialCondition(null));
|
||||
}
|
||||
|
||||
|
||||
public static void runPhaseChangeNotifier() {
|
||||
if (phaseChangeListener != null) {
|
||||
phaseChangeListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void init() {
|
||||
// Empty initializer to run static
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package net.coderbot.iris.layer;
|
||||
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public record PassOverride(SpecialCondition special, Boolean translucent, WorldRenderingPhase phase) {
|
||||
|
||||
public static final PassOverride NONE = new PassOverride(null, null, null);
|
||||
|
||||
public PassOverride(SpecialCondition special, Boolean translucent) {
|
||||
this(special, translucent, null);
|
||||
}
|
||||
|
||||
public static PassOverride capture() {
|
||||
final SpecialCondition special = GbufferPrograms.getSpecialCondition();
|
||||
final Boolean translucent = GbufferPrograms.getDeclaredTranslucency();
|
||||
final WorldRenderingPhase phase = GbufferPrograms.getOverridePhase();
|
||||
return special == null && translucent == null && phase == null
|
||||
? NONE : new PassOverride(special, translucent, phase);
|
||||
}
|
||||
|
||||
public void apply() {
|
||||
GbufferPrograms.setupSpecialRenderCondition(special);
|
||||
GbufferPrograms.setTranslucencyDeclaration(translucent);
|
||||
GbufferPrograms.setOverridePhase(phase);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
GbufferPrograms.setupSpecialRenderCondition(null);
|
||||
GbufferPrograms.setTranslucencyDeclaration(null);
|
||||
GbufferPrograms.setOverridePhase(null);
|
||||
}
|
||||
|
||||
public boolean isEntityPhase() {
|
||||
return phase == WorldRenderingPhase.ENTITIES;
|
||||
}
|
||||
|
||||
public String nameSuffix() {
|
||||
if (special == null && translucent == null && phase == null) {
|
||||
return "";
|
||||
}
|
||||
return "_" + (special == null ? "plain" : special.name().toLowerCase(Locale.ROOT))
|
||||
+ (translucent == null ? "" : (translucent ? "_translucent" : "_opaque"))
|
||||
+ (phase == null ? "" : "_" + phase.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import net.coderbot.iris.features.FeatureFlags;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.InputAvailability;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.ProgramTable;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.RenderCondition;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.TranslucentBlendMatcher;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.gbuffer_overrides.state.RenderTargetStateListener;
|
||||
import net.coderbot.iris.gl.blending.AlphaTestOverride;
|
||||
@@ -127,9 +128,6 @@ import java.util.function.Supplier;
|
||||
* Encapsulates the compiled shader program objects for the currently loaded shaderpack.
|
||||
*/
|
||||
public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, RenderTargetStateListener {
|
||||
private final static int SRC_ALPHA = 770;
|
||||
private final static int ONE_MINUS_SRC_ALPHA = 771;
|
||||
private final static int ONE = 1;
|
||||
private final RenderTargets renderTargets;
|
||||
|
||||
@Nullable
|
||||
@@ -260,14 +258,31 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
final Map<Pair<String, InputAvailability>, CompletableFuture<Map<PatchShaderType, String>>> instancedTransformFutures = submitAttributeTransforms(resolver, INSTANCED_PROGRAM_IDS, true);
|
||||
|
||||
final Optional<ProgramSource> terrainSource = first(programs.getGbuffersTerrain(), programs.getGbuffersTexturedLit(), programs.getGbuffersTextured(), programs.getGbuffersBasic());
|
||||
final Optional<ProgramSource> terrainSolidOverride = programs.getGbuffersTerrainSolid();
|
||||
final Optional<ProgramSource> terrainCutoutOverride = programs.getGbuffersTerrainCutout();
|
||||
final Optional<ProgramSource> terrainSolidSource = first(terrainSolidOverride, terrainSource);
|
||||
final Optional<ProgramSource> terrainCutoutSource = first(terrainCutoutOverride, terrainSource);
|
||||
|
||||
final Optional<ProgramSource> translucentSource = first(programs.getGbuffersWater(), terrainSource);
|
||||
final Optional<ProgramSource> shadowSource = programs.getShadow();
|
||||
final Optional<ProgramSource> shadowSolidOverride = programs.getShadowSolid();
|
||||
final Optional<ProgramSource> shadowCutoutOverride = programs.getShadowCutout();
|
||||
final Optional<ProgramSource> shadowSolidSource = first(shadowSolidOverride, shadowSource);
|
||||
final Optional<ProgramSource> shadowCutoutSource = first(shadowCutoutOverride, shadowSource);
|
||||
final Optional<ProgramSource> shadowTranslucentSource = first(programs.getShadowWater(), shadowSource);
|
||||
|
||||
// Celeritas terrain transform futures
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTerrainFuture = terrainSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTerrainSolidFuture = terrainSolidOverride
|
||||
.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(celeritasTerrainFuture);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTerrainCutoutFuture = terrainCutoutOverride
|
||||
.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(celeritasTerrainFuture);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasTranslucentFuture = translucentSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowFuture = shadowSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowSolidFuture = shadowSolidOverride
|
||||
.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(celeritasShadowFuture);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowCutoutFuture = shadowCutoutOverride
|
||||
.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(celeritasShadowFuture);
|
||||
final CompletableFuture<Map<PatchShaderType, String>> celeritasShadowTranslucentFuture = shadowTranslucentSource.map(DeferredWorldRenderingPipeline::submitCeleritasTerrainTransform).orElse(null);
|
||||
|
||||
final Int2ObjectArrayMap<CompletableFuture<String>> setupComputeFutures = submitSetupComputeTransforms(programs.getSetup(), programs.getPackDirectives().getTextureMap());
|
||||
@@ -461,6 +476,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
ProgramId.BeaconBeam, ProgramId.BeaconBeam, ProgramId.BeaconBeam,
|
||||
ProgramId.Entities, ProgramId.Entities, ProgramId.Entities,
|
||||
ProgramId.EntitiesTrans, ProgramId.EntitiesTrans, ProgramId.EntitiesTrans,
|
||||
ProgramId.Particles, ProgramId.Particles, ProgramId.Particles,
|
||||
ProgramId.ParticlesTrans, ProgramId.ParticlesTrans, ProgramId.ParticlesTrans,
|
||||
null, ProgramId.ArmorGlint, ProgramId.ArmorGlint,
|
||||
null, ProgramId.SpiderEyes, ProgramId.SpiderEyes,
|
||||
ProgramId.Hand, ProgramId.Hand, ProgramId.Hand,
|
||||
@@ -697,11 +714,14 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
this.celeritasTerrainPipeline = new CeleritasTerrainPipeline(createTerrainSamplers,
|
||||
shadowRenderer == null ? null : createShadowTerrainSamplers, createTerrainImages,
|
||||
shadowRenderer == null ? null : createShadowTerrainImages, this.customUniforms,
|
||||
terrainSource,
|
||||
terrainSolidSource,
|
||||
terrainCutoutSource,
|
||||
translucentSource,
|
||||
shadowSource,
|
||||
shadowSolidSource,
|
||||
shadowCutoutSource,
|
||||
shadowTranslucentSource,
|
||||
celeritasTerrainFuture, celeritasTranslucentFuture, celeritasShadowFuture, celeritasShadowTranslucentFuture,
|
||||
celeritasTerrainSolidFuture, celeritasTerrainCutoutFuture, celeritasTranslucentFuture,
|
||||
celeritasShadowSolidFuture, celeritasShadowCutoutFuture, celeritasShadowTranslucentFuture,
|
||||
renderTargets, flippedAfterPrepare, flippedAfterTranslucent,
|
||||
celeritasShadowFb);
|
||||
|
||||
@@ -843,28 +863,18 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
|
||||
switch (phase) {
|
||||
case NONE, OUTLINE, DEBUG, PARTICLES:
|
||||
case NONE, OUTLINE, DEBUG:
|
||||
return RenderCondition.DEFAULT;
|
||||
case PARTICLES:
|
||||
return isTranslucentDraw() ? RenderCondition.PARTICLES_TRANSLUCENT : RenderCondition.PARTICLES;
|
||||
case SKY, SUNSET, CUSTOM_SKY, SUN, MOON, STARS, VOID:
|
||||
return RenderCondition.SKY;
|
||||
case TERRAIN_SOLID, TERRAIN_CUTOUT, TERRAIN_CUTOUT_MIPPED:
|
||||
return RenderCondition.TERRAIN_OPAQUE;
|
||||
case ENTITIES:
|
||||
if (GLStateManager.getBlendState().getSrcRgb() == SRC_ALPHA &&
|
||||
GLStateManager.getBlendState().getSrcAlpha() == ONE_MINUS_SRC_ALPHA &&
|
||||
GLStateManager.getBlendState().getDstRgb() == ONE &&
|
||||
GLStateManager.getBlendState().getDstAlpha() == ONE_MINUS_SRC_ALPHA)
|
||||
{
|
||||
return RenderCondition.ENTITIES_TRANSLUCENT;
|
||||
} else {
|
||||
return RenderCondition.ENTITIES;
|
||||
}
|
||||
return isTranslucentDraw() ? RenderCondition.ENTITIES_TRANSLUCENT : RenderCondition.ENTITIES;
|
||||
case BLOCK_ENTITIES:
|
||||
if (GLStateManager.getBlendState().getSrcRgb() == SRC_ALPHA &&
|
||||
GLStateManager.getBlendState().getDstRgb() == ONE_MINUS_SRC_ALPHA) {
|
||||
return RenderCondition.BLOCK_ENTITIES_TRANSLUCENT;
|
||||
}
|
||||
return RenderCondition.BLOCK_ENTITIES;
|
||||
return isTranslucentDraw() ? RenderCondition.BLOCK_ENTITIES_TRANSLUCENT : RenderCondition.BLOCK_ENTITIES;
|
||||
case DESTROY:
|
||||
return RenderCondition.DESTROY;
|
||||
case HAND_SOLID:
|
||||
@@ -884,6 +894,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTranslucentDraw() {
|
||||
return declaredTranslucent != null ? declaredTranslucent : TranslucentBlendMatcher.matchesCurrentState();
|
||||
}
|
||||
|
||||
public boolean shouldOverrideShaders() {
|
||||
return isRenderingLevelGeometry() && isMainBound;
|
||||
}
|
||||
@@ -906,10 +920,60 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
* Called when a mod overrides the GL program away from the active Iris pass
|
||||
*/
|
||||
public void onModProgramOverride() {
|
||||
if (current != null) {
|
||||
modProgramOverrode = true;
|
||||
programBeforeModOverride = getActivePassProgramId();
|
||||
}
|
||||
current = null;
|
||||
currentCondition = null;
|
||||
}
|
||||
|
||||
public void restorePassAfterModProgram(int newProgram) {
|
||||
if (refreshingPass || drivingProgram || !modProgramOverrode) {
|
||||
return;
|
||||
}
|
||||
if (newProgram != 0 && newProgram != programBeforeModOverride) {
|
||||
return;
|
||||
}
|
||||
refreshingPass = true;
|
||||
try {
|
||||
current = null;
|
||||
matchPass();
|
||||
} finally {
|
||||
modProgramOverrode = false;
|
||||
programBeforeModOverride = -1;
|
||||
refreshingPass = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean refreshingPass;
|
||||
private boolean modProgramOverrode;
|
||||
private int programBeforeModOverride = -1;
|
||||
|
||||
public void onVanillaBlendChanged() {
|
||||
if (matchingBlend || drivingProgram || refreshingPass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (declaredTranslucent != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final WorldRenderingPhase phase = getPhase();
|
||||
if (phase != WorldRenderingPhase.ENTITIES && phase != WorldRenderingPhase.BLOCK_ENTITIES) {
|
||||
return;
|
||||
}
|
||||
|
||||
matchingBlend = true;
|
||||
try {
|
||||
matchPass();
|
||||
} finally {
|
||||
matchingBlend = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchingBlend;
|
||||
|
||||
private void matchPass() {
|
||||
if (!shouldOverrideShaders()) {
|
||||
return;
|
||||
@@ -946,13 +1010,20 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
current = pass;
|
||||
|
||||
if (pass != null) {
|
||||
pass.use();
|
||||
} else {
|
||||
Program.unbind();
|
||||
drivingProgram = true;
|
||||
try {
|
||||
if (pass != null) {
|
||||
pass.use();
|
||||
} else {
|
||||
Program.unbind();
|
||||
}
|
||||
} finally {
|
||||
drivingProgram = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean drivingProgram;
|
||||
|
||||
@Override
|
||||
public void rebindCurrentPass() {
|
||||
final Pass pass = this.current;
|
||||
@@ -1631,6 +1702,9 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
@Nullable
|
||||
public ComputeProgram getShadowVoxelizationCompute() { return shadowVoxelizationCompute; }
|
||||
|
||||
@Nullable
|
||||
public ShadowRenderer getShadowRenderer() { return shadowRenderer; }
|
||||
|
||||
private GlUniformMatrix4f voxelizationModelView;
|
||||
private GlUniformMatrix3f voxelizationNormalMatrix;
|
||||
private final Matrix3f voxelizationNormalScratch = new Matrix3f();
|
||||
@@ -1772,6 +1846,14 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
@Override
|
||||
public void beginHand() {
|
||||
isRenderingFullScreenPass = true;
|
||||
beginPass(null);
|
||||
currentCondition = null;
|
||||
profiler.startSection("iris_center_depth");
|
||||
centerDepthSampler.sampleCenterDepth();
|
||||
profiler.endSection();
|
||||
isRenderingFullScreenPass = false;
|
||||
|
||||
if (!usesSampler(IrisSamplers.USAGE_DEPTHTEX2)) {
|
||||
return;
|
||||
}
|
||||
@@ -2005,10 +2087,6 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
isRenderingFullScreenPass = true;
|
||||
|
||||
profiler.startSection("iris_center_depth");
|
||||
centerDepthSampler.sampleCenterDepth();
|
||||
profiler.endSection();
|
||||
|
||||
profiler.startSection("iris_composites");
|
||||
GLDebug.pushGroup("composite");
|
||||
try {
|
||||
@@ -2110,6 +2188,15 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
matchPass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeclaredTranslucency(@Nullable Boolean translucent) {
|
||||
this.declaredTranslucent = translucent;
|
||||
matchPass();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Boolean declaredTranslucent;
|
||||
|
||||
@Override
|
||||
public RenderTargetStateListener getRenderTargetStateListener() {
|
||||
return this;
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.coderbot.iris.uniforms.FrameUpdateNotifier;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
@@ -83,6 +84,11 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeclaredTranslucency(@Nullable Boolean translucent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderTargetStateListener getRenderTargetStateListener() {
|
||||
return RenderTargetStateListener.NOP;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package net.coderbot.iris.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
|
||||
import com.gtnewhorizons.angelica.event.RenderHandEvent;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ItemRendererAccessor;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.BlockRenderLayer;
|
||||
import lombok.Getter;
|
||||
@@ -83,96 +85,133 @@ public class HandRenderer {
|
||||
!RenderHandEvent.post();
|
||||
}
|
||||
|
||||
public boolean isHandTranslucent(InteractionHand hand) {
|
||||
ItemStack heldItem = hand.getItemInHand(Minecraft.getMinecraft().thePlayer);
|
||||
|
||||
public boolean isItemTranslucent(ItemStack heldItem) {
|
||||
if (heldItem == null) return false;
|
||||
final Item item = heldItem.getItem();
|
||||
|
||||
if (item instanceof ItemBlock itemBlock) {
|
||||
final Block block = itemBlock.field_150939_a;
|
||||
if (block == null) return false;
|
||||
|
||||
final Map<Block, BlockRenderLayer> blockTypeIds = BlockRenderingSettings.INSTANCE.getBlockTypeIds();
|
||||
return blockTypeIds != null && blockTypeIds.get(itemBlock.field_150939_a) == BlockRenderLayer.TRANSLUCENT;
|
||||
final BlockRenderLayer override = blockTypeIds != null ? blockTypeIds.get(block) : null;
|
||||
final BlockRenderLayer layer = override != null ? override : BlockRenderLayer.fromVanillaPass(block.getRenderBlockPass());
|
||||
return layer == BlockRenderLayer.TRANSLUCENT;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isHandTranslucent(InteractionHand hand) {
|
||||
return isItemTranslucent(hand.getItemInHand(Minecraft.getMinecraft().thePlayer));
|
||||
}
|
||||
|
||||
private ItemStack mainHandItem() {
|
||||
return ((ItemRendererAccessor) Minecraft.getMinecraft().entityRenderer.itemRenderer).angelica$getItemToRender();
|
||||
}
|
||||
|
||||
public boolean isAnyHandTranslucent() {
|
||||
return isHandTranslucent(InteractionHand.MAIN_HAND) || isHandTranslucent(InteractionHand.OFF_HAND);
|
||||
return isItemTranslucent(mainHandItem())
|
||||
|| (ModStatus.isBackhandLoaded && isHandTranslucent(InteractionHand.OFF_HAND));
|
||||
}
|
||||
|
||||
public boolean isAnyHandSolid() {
|
||||
return !(isItemTranslucent(mainHandItem())
|
||||
&& (!ModStatus.isBackhandLoaded || isHandTranslucent(InteractionHand.OFF_HAND)));
|
||||
}
|
||||
|
||||
public void renderSolid(float tickDelta, Camera camera, RenderGlobal gameRenderer, WorldRenderingPipeline pipeline) {
|
||||
if (!canRender(camera, gameRenderer) || !IrisApi.getInstance().isShaderPackInUse()) {
|
||||
if (!IrisApi.getInstance().isShaderPackInUse() || !canRender(camera, gameRenderer) || !isAnyHandSolid()) {
|
||||
return;
|
||||
}
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
ACTIVE = true;
|
||||
|
||||
final int blendSave = GbufferPrograms.pushBlendState();
|
||||
final long cutoutSave = GbufferPrograms.pushCutoutDefaults();
|
||||
final boolean depthMaskBefore = GLStateManager.isEffectiveDepthMaskEnabled();
|
||||
|
||||
GLStateManager.disableBlend();
|
||||
GLStateManager.defaultBlendFunc();
|
||||
|
||||
pipeline.setPhase(WorldRenderingPhase.HAND_SOLID);
|
||||
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glDepthMask(true); // actually write to the depth buffer, it's normally disabled at this point
|
||||
|
||||
mc.mcProfiler.startSection("iris_hand");
|
||||
try {
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
renderingSolid = true;
|
||||
|
||||
renderingSolid = true;
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
mc.entityRenderer.disableLightmap(tickDelta);
|
||||
} finally {
|
||||
renderingSolid = false;
|
||||
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
mc.entityRenderer.disableLightmap(tickDelta);
|
||||
mc.mcProfiler.endSection();
|
||||
|
||||
GLStateManager.defaultBlendFunc();
|
||||
GLStateManager.glDepthMask(false);
|
||||
GLStateManager.glPopMatrix();
|
||||
GLStateManager.glPopMatrix();
|
||||
resetProjectionMatrix();
|
||||
|
||||
mc.mcProfiler.endSection();
|
||||
GLStateManager.glDepthMask(depthMaskBefore);
|
||||
GbufferPrograms.popCutoutDefaults(cutoutSave);
|
||||
GbufferPrograms.popBlendState(blendSave);
|
||||
|
||||
resetProjectionMatrix();
|
||||
pipeline.setPhase(WorldRenderingPhase.NONE);
|
||||
|
||||
renderingSolid = false;
|
||||
|
||||
pipeline.setPhase(WorldRenderingPhase.NONE);
|
||||
|
||||
ACTIVE = false;
|
||||
ACTIVE = false;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RenderType
|
||||
public void renderTranslucent(float tickDelta, Camera camera, RenderGlobal gameRenderer, WorldRenderingPipeline pipeline) {
|
||||
if (!canRender(camera, gameRenderer) || !isAnyHandTranslucent() || !IrisApi.getInstance().isShaderPackInUse()) {
|
||||
if (!IrisApi.getInstance().isShaderPackInUse() || !canRender(camera, gameRenderer) || !isAnyHandTranslucent()) {
|
||||
return;
|
||||
}
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
ACTIVE = true;
|
||||
|
||||
final int blendSave = GbufferPrograms.pushBlendState();
|
||||
final long cutoutSave = GbufferPrograms.pushCutoutDefaults();
|
||||
final boolean depthMaskBefore = GLStateManager.isEffectiveDepthMaskEnabled();
|
||||
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.defaultBlendFunc();
|
||||
|
||||
pipeline.setPhase(WorldRenderingPhase.HAND_TRANSLUCENT);
|
||||
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glDepthMask(false);
|
||||
|
||||
mc.mcProfiler.startSection("iris_hand_translucent");
|
||||
try {
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
|
||||
setupGlState(gameRenderer, camera, tickDelta);
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
mc.entityRenderer.disableLightmap(tickDelta);
|
||||
} finally {
|
||||
mc.mcProfiler.endSection();
|
||||
|
||||
mc.entityRenderer.enableLightmap(tickDelta);
|
||||
mc.entityRenderer.itemRenderer.renderItemInFirstPerson(tickDelta);
|
||||
mc.entityRenderer.disableLightmap(tickDelta);
|
||||
GLStateManager.glPopMatrix();
|
||||
resetProjectionMatrix();
|
||||
|
||||
GLStateManager.glPopMatrix();
|
||||
GLStateManager.glDepthMask(depthMaskBefore);
|
||||
GbufferPrograms.popCutoutDefaults(cutoutSave);
|
||||
GbufferPrograms.popBlendState(blendSave);
|
||||
|
||||
resetProjectionMatrix();
|
||||
pipeline.setPhase(WorldRenderingPhase.NONE);
|
||||
|
||||
Minecraft.getMinecraft().mcProfiler.endSection();
|
||||
|
||||
pipeline.setPhase(WorldRenderingPhase.NONE);
|
||||
|
||||
ACTIVE = false;
|
||||
ACTIVE = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void resetProjectionMatrix() {
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.AngelicaRenderSectionManager;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Setter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.gui.option.IrisVideoSettings;
|
||||
@@ -106,7 +107,8 @@ public class ShadowRenderer {
|
||||
private final ShadowCullState packCullingState;
|
||||
private final ShadowCompositeRenderer compositeRenderer;
|
||||
private boolean packHasVoxelization;
|
||||
private boolean playerReflectionCaptureEnabled = true;
|
||||
@Setter
|
||||
private boolean playerReflectionCaptureEnabled = true;
|
||||
private final boolean shouldRenderTerrain;
|
||||
private final boolean shouldRenderTranslucent;
|
||||
private final boolean shouldRenderEntities;
|
||||
@@ -148,10 +150,19 @@ public class ShadowRenderer {
|
||||
private boolean preSubmitActive;
|
||||
private float preSubmittedShadowAngle = Float.NaN;
|
||||
|
||||
private float shadowAngleDelta() {
|
||||
final Vector4f light = celestialUniforms.getShadowLightPositionInWorldSpace();
|
||||
final float x = light.x(), y = light.y(), z = light.z();
|
||||
final float length = (float) Math.sqrt(x * x + y * y + z * z);
|
||||
return ShadowGraphGate.deltaForElevation(length > 0.0f ? y / length : 1.0f,
|
||||
ShadowGraphGate.degreesToRotation(AngelicaConfig.shadowGraphAngleDelta),
|
||||
AngelicaConfig.shadowGraphHorizonScale);
|
||||
}
|
||||
|
||||
public void preSubmitGraphUpdate(int frame, boolean spectator) {
|
||||
final AngelicaRenderSectionManager rsm = CeleritasWorldRenderer.getInstance().getRenderSectionManager();
|
||||
final float currentShadowAngle = getShadowAngle();
|
||||
if (ShadowGraphGate.shouldMarkDirty(lastGraphShadowAngle, currentShadowAngle)) {
|
||||
if (ShadowGraphGate.shouldMarkDirty(lastGraphShadowAngle, currentShadowAngle, shadowAngleDelta())) {
|
||||
rsm.markShadowGraphDirty();
|
||||
lastGraphShadowAngle = currentShadowAngle;
|
||||
}
|
||||
@@ -235,13 +246,21 @@ public class ShadowRenderer {
|
||||
|
||||
public void setUsesImages(boolean usesImages) {
|
||||
this.packHasVoxelization = packHasVoxelization || usesImages;
|
||||
this.shadowWritesImages = usesImages;
|
||||
}
|
||||
|
||||
public void setPlayerReflectionCaptureEnabled(boolean enabled) {
|
||||
this.playerReflectionCaptureEnabled = enabled;
|
||||
private boolean shadowWritesImages;
|
||||
|
||||
public boolean shadowTerrainAlwaysRelays() {
|
||||
return !shouldRenderTerrain || voxelizationActive() || shadowWritesImages;
|
||||
}
|
||||
|
||||
public static MatrixStack createShadowModelView(float sunPathRotation, float intervalSize) {
|
||||
public static boolean shadowGraphGateIsNotBypassed() {
|
||||
return !(Iris.getPipelineManager().getPipelineNullable() instanceof DeferredWorldRenderingPipeline deferred)
|
||||
|| deferred.getShadowRenderer() == null || !deferred.getShadowRenderer().shadowTerrainAlwaysRelays();
|
||||
}
|
||||
|
||||
public static MatrixStack createShadowModelView(float sunPathRotation, float intervalSize) {
|
||||
// Use entity position for shadow matrix
|
||||
final Vector3d entityPos = Camera.INSTANCE.getEntityPos();
|
||||
|
||||
@@ -833,7 +852,7 @@ public class ShadowRenderer {
|
||||
globalTileEntities.clear();
|
||||
|
||||
final float currentShadowAngle = getShadowAngle();
|
||||
if (ShadowGraphGate.shouldMarkDirty(lastGraphShadowAngle, currentShadowAngle)) {
|
||||
if (ShadowGraphGate.shouldMarkDirty(lastGraphShadowAngle, currentShadowAngle, shadowAngleDelta())) {
|
||||
CeleritasWorldRenderer.getInstance().getRenderSectionManager().markShadowGraphDirty();
|
||||
lastGraphShadowAngle = currentShadowAngle;
|
||||
}
|
||||
@@ -843,8 +862,7 @@ public class ShadowRenderer {
|
||||
final boolean consumePreSubmit = preSubmitActive;
|
||||
preSubmitActive = false;
|
||||
|
||||
final boolean relayTerrain = !deferActive
|
||||
|| voxelizationActive()
|
||||
final boolean relayTerrain = shadowTerrainAlwaysRelays()
|
||||
|| !targets.isTerrainSnapshotValid()
|
||||
|| consumePreSubmit
|
||||
|| CeleritasWorldRenderer.getInstance().getRenderSectionManager().isShadowGraphDirty()
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.coderbot.iris.shaderpack.CloudSetting;
|
||||
import net.coderbot.iris.shaderpack.texture.TextureStage;
|
||||
import net.coderbot.iris.uniforms.FrameUpdateNotifier;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
@@ -31,6 +32,7 @@ public interface WorldRenderingPipeline {
|
||||
void setPhase(WorldRenderingPhase phase);
|
||||
void setInputs(InputAvailability availability);
|
||||
void setSpecialCondition(SpecialCondition special);
|
||||
void setDeclaredTranslucency(@Nullable Boolean translucent);
|
||||
RenderTargetStateListener getRenderTargetStateListener();
|
||||
|
||||
int getCurrentNormalTexture();
|
||||
|
||||
@@ -17,6 +17,8 @@ public class ProgramSet {
|
||||
private final PackDirectives packDirectives;
|
||||
|
||||
private final ProgramSource shadow;
|
||||
private final ProgramSource shadowSolid;
|
||||
private final ProgramSource shadowCutout;
|
||||
private final ProgramSource shadowWater;
|
||||
private final ComputeSource[] shadowCompute;
|
||||
|
||||
@@ -34,6 +36,8 @@ public class ProgramSet {
|
||||
private final ProgramSource gbuffersTextured;
|
||||
private final ProgramSource gbuffersTexturedLit;
|
||||
private final ProgramSource gbuffersTerrain;
|
||||
private final ProgramSource gbuffersTerrainSolid;
|
||||
private final ProgramSource gbuffersTerrainCutout;
|
||||
private ProgramSource gbuffersDamagedBlock;
|
||||
private final ProgramSource gbuffersSkyBasic;
|
||||
private final ProgramSource gbuffersSkyTextured;
|
||||
@@ -43,6 +47,8 @@ public class ProgramSet {
|
||||
private final ProgramSource gbuffersEntitiesTrans;
|
||||
private final ProgramSource gbuffersEntitiesGlowing;
|
||||
private final ProgramSource gbuffersLightning;
|
||||
private final ProgramSource gbuffersParticles;
|
||||
private final ProgramSource gbuffersParticlesTrans;
|
||||
private final ProgramSource gbuffersGlint;
|
||||
private final ProgramSource gbuffersEntityEyes;
|
||||
private final ProgramSource gbuffersBlock;
|
||||
@@ -83,6 +89,10 @@ public class ProgramSet {
|
||||
// - https://github.com/IrisShaders/Iris/issues/987
|
||||
this.shadow = readProgramSource(directory, sourceProvider, "shadow", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowSolid = readProgramSource(directory, sourceProvider, "shadow_solid", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowCutout = readProgramSource(directory, sourceProvider, "shadow_cutout", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowWater = readProgramSource(directory, sourceProvider, "shadow_water", this, shaderProperties,
|
||||
BlendModeOverride.OFF);
|
||||
this.shadowCompute = readComputeArray(directory, sourceProvider, "shadow");
|
||||
@@ -114,6 +124,8 @@ public class ProgramSet {
|
||||
this.gbuffersTextured = readProgramSource(directory, sourceProvider, "gbuffers_textured", this, shaderProperties);
|
||||
this.gbuffersTexturedLit = readProgramSource(directory, sourceProvider, "gbuffers_textured_lit", this, shaderProperties);
|
||||
this.gbuffersTerrain = readProgramSource(directory, sourceProvider, "gbuffers_terrain", this, shaderProperties);
|
||||
this.gbuffersTerrainSolid = readProgramSource(directory, sourceProvider, "gbuffers_terrain_solid", this, shaderProperties);
|
||||
this.gbuffersTerrainCutout = readProgramSource(directory, sourceProvider, "gbuffers_terrain_cutout", this, shaderProperties);
|
||||
this.gbuffersDamagedBlock = readProgramSource(directory, sourceProvider, "gbuffers_damagedblock", this, shaderProperties);
|
||||
this.gbuffersSkyBasic = readProgramSource(directory, sourceProvider, "gbuffers_skybasic", this, shaderProperties);
|
||||
this.gbuffersSkyTextured = readProgramSource(directory, sourceProvider, "gbuffers_skytextured", this, shaderProperties);
|
||||
@@ -123,6 +135,8 @@ public class ProgramSet {
|
||||
this.gbuffersEntitiesTrans = readProgramSource(directory, sourceProvider, "gbuffers_entities_translucent", this, shaderProperties);
|
||||
this.gbuffersEntitiesGlowing = readProgramSource(directory, sourceProvider, "gbuffers_entities_glowing", this, shaderProperties);
|
||||
this.gbuffersLightning = readProgramSource(directory, sourceProvider, "gbuffers_lightning", this, shaderProperties);
|
||||
this.gbuffersParticles = readProgramSource(directory, sourceProvider, "gbuffers_particles", this, shaderProperties);
|
||||
this.gbuffersParticlesTrans = readProgramSource(directory, sourceProvider, "gbuffers_particles_translucent", this, shaderProperties);
|
||||
this.gbuffersGlint = readProgramSource(directory, sourceProvider, "gbuffers_armor_glint", this, shaderProperties);
|
||||
this.gbuffersEntityEyes = readProgramSource(directory, sourceProvider, "gbuffers_spidereyes", this, shaderProperties);
|
||||
this.gbuffersBlock = readProgramSource(directory, sourceProvider, "gbuffers_block", this, shaderProperties);
|
||||
@@ -224,6 +238,8 @@ public class ProgramSet {
|
||||
List<ComputeSource> computes = new ArrayList<>();
|
||||
|
||||
programs.add(shadow);
|
||||
programs.add(shadowSolid);
|
||||
programs.add(shadowCutout);
|
||||
programs.add(shadowWater);
|
||||
programs.addAll(Arrays.asList(shadowcomp));
|
||||
programs.addAll(Arrays.asList(begin));
|
||||
@@ -231,8 +247,9 @@ public class ProgramSet {
|
||||
|
||||
programs.addAll (Arrays.asList(
|
||||
gbuffersBasic, gbuffersBeaconBeam, gbuffersTextured, gbuffersTexturedLit, gbuffersTerrain,
|
||||
gbuffersTerrainSolid, gbuffersTerrainCutout,
|
||||
gbuffersDamagedBlock, gbuffersSkyBasic, gbuffersSkyTextured, gbuffersClouds, gbuffersWeather,
|
||||
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersLightning, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
|
||||
gbuffersEntities, gbuffersEntitiesTrans, gbuffersEntitiesGlowing, gbuffersLightning, gbuffersParticles, gbuffersParticlesTrans, gbuffersGlint, gbuffersEntityEyes, gbuffersBlock, gbuffersBlockTrans,
|
||||
gbuffersHand, dhShadow, dhTerrain, dhGeneric, dhWater
|
||||
));
|
||||
|
||||
@@ -309,6 +326,14 @@ public class ProgramSet {
|
||||
return shadow.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getShadowSolid() {
|
||||
return shadowSolid.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getShadowCutout() {
|
||||
return shadowCutout.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getShadowWater() {
|
||||
return shadowWater.requireValid();
|
||||
}
|
||||
@@ -353,6 +378,14 @@ public class ProgramSet {
|
||||
return gbuffersTerrain.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersTerrainSolid() {
|
||||
return gbuffersTerrainSolid.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersTerrainCutout() {
|
||||
return gbuffersTerrainCutout.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersDamagedBlock() {
|
||||
return gbuffersDamagedBlock.requireValid();
|
||||
}
|
||||
@@ -389,6 +422,14 @@ public class ProgramSet {
|
||||
return gbuffersLightning.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersParticles() {
|
||||
return gbuffersParticles.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersParticlesTrans() {
|
||||
return gbuffersParticlesTrans.requireValid();
|
||||
}
|
||||
|
||||
public Optional<ProgramSource> getGbuffersGlint() {
|
||||
return gbuffersGlint.requireValid();
|
||||
}
|
||||
@@ -428,6 +469,8 @@ public class ProgramSet {
|
||||
public Optional<ProgramSource> get(ProgramId programId) {
|
||||
return switch (programId) {
|
||||
case Shadow -> getShadow();
|
||||
case ShadowSolid -> getShadowSolid();
|
||||
case ShadowCutout -> getShadowCutout();
|
||||
case ShadowWater -> first(getShadowWater(), getShadow());
|
||||
case Basic -> getGbuffersBasic();
|
||||
case Line -> gbuffersLine.requireValid();
|
||||
@@ -437,6 +480,8 @@ public class ProgramSet {
|
||||
case SkyTextured -> getGbuffersSkyTextured();
|
||||
case Clouds -> getGbuffersClouds();
|
||||
case Terrain -> getGbuffersTerrain();
|
||||
case TerrainSolid -> getGbuffersTerrainSolid();
|
||||
case TerrainCutout -> getGbuffersTerrainCutout();
|
||||
case DamagedBlock -> getGbuffersDamagedBlock();
|
||||
case Block -> getGbuffersBlock();
|
||||
case BlockTrans -> getGbuffersBlockTrans();
|
||||
@@ -445,6 +490,8 @@ public class ProgramSet {
|
||||
case EntitiesTrans -> getGbuffersEntitiesTrans();
|
||||
case EntitiesGlowing -> getGbuffersEntitiesGlowing();
|
||||
case Lightning -> getGbuffersLightning();
|
||||
case Particles -> getGbuffersParticles();
|
||||
case ParticlesTrans -> getGbuffersParticlesTrans();
|
||||
case ArmorGlint -> getGbuffersGlint();
|
||||
case SpiderEyes -> getGbuffersEntityEyes();
|
||||
case Hand -> getGbuffersHand();
|
||||
|
||||
@@ -27,7 +27,9 @@ public enum ProgramId {
|
||||
|
||||
Terrain(ProgramGroup.Gbuffers, "terrain", TexturedLit),
|
||||
TerrainSolid(ProgramGroup.Gbuffers, "terrain_solid", Terrain),
|
||||
TerrainCutoutMip(ProgramGroup.Gbuffers, "terrain_cutout_mip", Terrain),
|
||||
// terrain_cutout_mip program was removed in modern versions of Minecraft. As the goal is to be a faithful backport of Iris
|
||||
// we likely should just group cutout and cutout mipped into the same program.
|
||||
// CUTOUT_MIPPED essentially became CUTOUT and now everything uses mipmaps in modern. We don't as of writing.
|
||||
TerrainCutout(ProgramGroup.Gbuffers, "terrain_cutout", Terrain),
|
||||
DamagedBlock(ProgramGroup.Gbuffers, "damagedblock", Terrain),
|
||||
|
||||
@@ -40,6 +42,8 @@ public enum ProgramId {
|
||||
EntitiesTrans(ProgramGroup.Gbuffers, "entities_translucent", Entities),
|
||||
EntitiesGlowing(ProgramGroup.Gbuffers, "entities_glowing", Entities),
|
||||
Lightning(ProgramGroup.Gbuffers, "lightning", Entities),
|
||||
Particles(ProgramGroup.Gbuffers, "particles", TexturedLit),
|
||||
ParticlesTrans(ProgramGroup.Gbuffers, "particles_translucent", Particles),
|
||||
ArmorGlint(ProgramGroup.Gbuffers, "armor_glint", Textured),
|
||||
SpiderEyes(ProgramGroup.Gbuffers, "spidereyes", Textured,
|
||||
new BlendModeOverride(new BlendState(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE)),
|
||||
|
||||
@@ -82,6 +82,10 @@ public class OptionMenuContainer {
|
||||
|
||||
// Screens will call this when they contain a "*" element, so that the list of
|
||||
// unused options can be added after all other screens have been resolved
|
||||
public boolean hasMenuElements() {
|
||||
return !this.originalMainElements.isEmpty();
|
||||
}
|
||||
|
||||
public void queueForUnusedOptionDump(int index, List<OptionMenuElement> elementList) {
|
||||
this.unusedOptionDumpQueue.put(elementList, index);
|
||||
}
|
||||
|
||||
@@ -2,14 +2,24 @@ package net.coderbot.iris.shadows;
|
||||
|
||||
public final class ShadowGraphGate {
|
||||
|
||||
public static final float SHADOW_ANGLE_GRAPH_DELTA = 0.0005f;
|
||||
public static final float DEFAULT_ANGLE_DELTA_DEGREES = 0.03f;
|
||||
|
||||
public static final float DEFAULT_HORIZON_SCALE = 0.5f;
|
||||
|
||||
private ShadowGraphGate() {}
|
||||
|
||||
public static boolean shouldMarkDirty(float last, float current) {
|
||||
float delta = current - last;
|
||||
if (delta > 0.5f) delta -= 1.0f;
|
||||
if (delta < -0.5f) delta += 1.0f;
|
||||
return Float.isNaN(last) || Math.abs(delta) > SHADOW_ANGLE_GRAPH_DELTA;
|
||||
public static float degreesToRotation(float degrees) {
|
||||
return degrees / 360.0f;
|
||||
}
|
||||
|
||||
public static boolean shouldMarkDirty(float last, float current, float delta) {
|
||||
float d = current - last;
|
||||
if (d > 0.5f) d -= 1.0f;
|
||||
if (d < -0.5f) d += 1.0f;
|
||||
return Float.isNaN(last) || Math.abs(d) > delta;
|
||||
}
|
||||
|
||||
public static float deltaForElevation(float sinElevation, float baseDelta, float minElevationScale) {
|
||||
return baseDelta * Math.max(minElevationScale, sinElevation * sinElevation);
|
||||
}
|
||||
}
|
||||
@@ -54,13 +54,20 @@ public class CapturedRenderingState {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCurrentEntity(int entity) {
|
||||
private void setCurrentEntity(int entity) {
|
||||
this.currentRenderedEntity = entity;
|
||||
|
||||
if (this.entityIdListener != null) {
|
||||
this.entityIdListener.run();
|
||||
}
|
||||
setCurrentRenderedItem(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* I should have done this a while ago, better solution to not forget these exist in tandem.
|
||||
*/
|
||||
public void setCurrentEntityAndItem(int entity, int item) {
|
||||
setCurrentEntity(entity);
|
||||
setCurrentRenderedItem(item);
|
||||
}
|
||||
|
||||
public void setCurrentEntityColor(float r, float g, float b, float a) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import net.minecraft.util.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME;
|
||||
import static org.joml.Math.clamp;
|
||||
|
||||
public final class IdMapUniforms {
|
||||
|
||||
@@ -71,6 +72,13 @@ public final class IdMapUniforms {
|
||||
lightValue = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Damn you chisel beacon
|
||||
*/
|
||||
private static int clampEmission(int emission) {
|
||||
return clamp(0, 15, emission);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
EntityPlayer player = Minecraft.getMinecraft().thePlayer;
|
||||
|
||||
@@ -98,7 +106,7 @@ public final class IdMapUniforms {
|
||||
intID = itemIdMap.applyAsInt(new NamespacedId(heldItemId.getResourceDomain(), heldItemId.getResourcePath()));
|
||||
|
||||
IrisItemLightProvider lightProvider = (IrisItemLightProvider) heldItem;
|
||||
lightValue = lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, heldStack);
|
||||
lightValue = clampEmission(lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, heldStack));
|
||||
|
||||
if (applyOldHandLight) {
|
||||
lightProvider = applyOldHandLighting(player, lightProvider);
|
||||
@@ -119,7 +127,7 @@ public final class IdMapUniforms {
|
||||
}
|
||||
|
||||
IrisItemLightProvider lightProvider = (IrisItemLightProvider) offHandItem;
|
||||
int newEmission = lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, offHandStack);
|
||||
int newEmission = clampEmission(lightProvider.getLightEmission(Minecraft.getMinecraft().thePlayer, offHandStack));
|
||||
|
||||
if (lightValue < newEmission) {
|
||||
lightValue = newEmission;
|
||||
|
||||
@@ -31,7 +31,7 @@ public class ItemIdManager {
|
||||
* Set the item ID for a Block rendered outside of terrain.
|
||||
*/
|
||||
public static void setBlockId(Block block, int metadata) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentRenderedItem(Math.max(0, ItemMaterialHelper.getMaterialId(block, metadata)));
|
||||
CapturedRenderingState.INSTANCE.setCurrentRenderedItem(ItemMaterialHelper.getMaterialId(block, metadata));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,15 +27,13 @@ public class ItemMaterialHelper {
|
||||
|
||||
/**
|
||||
* Get the material ID for an ItemStack.
|
||||
* For ItemBlock: checks block.properties first, then item.properties.
|
||||
* For other items: checks item.properties only.
|
||||
* 0 if unmapped.
|
||||
*
|
||||
* @param itemStack The item stack to get material ID for
|
||||
* @return The material ID, or -1 if not found
|
||||
*/
|
||||
public static int getMaterialId(ItemStack itemStack) {
|
||||
if (itemStack == null || itemStack.getItem() == null) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check item NBT conditions first
|
||||
@@ -56,7 +54,7 @@ public class ItemMaterialHelper {
|
||||
|
||||
public static int getMaterialId(Item item, int metadata) {
|
||||
if (item == null) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check cache first
|
||||
@@ -84,11 +82,11 @@ public class ItemMaterialHelper {
|
||||
/**
|
||||
* Get the material ID for a Block rendered outside of terrain.
|
||||
*
|
||||
* @return The material ID, or -1 if not found
|
||||
* @return The material ID, or 0 if not found
|
||||
*/
|
||||
public static int getMaterialId(Block block, int metadata) {
|
||||
if (block == null) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int2IntMap metadataCache = BLOCK_MATERIAL_CACHE.get(block);
|
||||
@@ -112,60 +110,44 @@ public class ItemMaterialHelper {
|
||||
}
|
||||
|
||||
private static int lookupBlockMaterialId(Block block, int metadata) {
|
||||
Reference2ObjectMap<Block, Int2IntMap> blockMetaMatches = BlockRenderingSettings.INSTANCE.getBlockMetaMatches();
|
||||
if (blockMetaMatches != null) {
|
||||
Int2IntMap metaMap = blockMetaMatches.get(block);
|
||||
if (metaMap != null) {
|
||||
int id = BlockMaterialMapping.resolveId(metaMap, metadata);
|
||||
if (id != -1) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Item item = Item.getItemFromBlock(block);
|
||||
return item != null ? lookupItemPropertiesId(item) : -1;
|
||||
return lookupBlockPropertiesId(block, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual material ID lookup without caching.
|
||||
*
|
||||
* For block items (ItemBlock): use block.properties first, then fall back to item.properties.
|
||||
* For non-block items: use item.properties only.
|
||||
*
|
||||
* This matches modern Iris behavior where block items use block IDs and non-block items use item IDs.
|
||||
*/
|
||||
private static int lookupMaterialId(Item item, int metadata) {
|
||||
// For ItemBlock: check block.properties first
|
||||
if (item instanceof ItemBlock itemBlock) {
|
||||
final Block block = itemBlock.field_150939_a; // The block this item places
|
||||
|
||||
if (block != null) {
|
||||
Reference2ObjectMap<Block, Int2IntMap> blockMetaMatches = BlockRenderingSettings.INSTANCE.getBlockMetaMatches();
|
||||
if (blockMetaMatches != null) {
|
||||
Int2IntMap metaMap = blockMetaMatches.get(block);
|
||||
if (metaMap != null) {
|
||||
int id = BlockMaterialMapping.resolveId(metaMap, itemBlock.getMetadata(metadata));
|
||||
if (id != -1) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return block == null ? 0 : lookupBlockPropertiesId(block, itemBlock.getMetadata(metadata));
|
||||
}
|
||||
|
||||
// Fall back to item.properties
|
||||
return lookupItemPropertiesId(item);
|
||||
}
|
||||
|
||||
private static int lookupBlockPropertiesId(Block block, int metadata) {
|
||||
final Reference2ObjectMap<Block, Int2IntMap> blockMetaMatches = BlockRenderingSettings.INSTANCE.getBlockMetaMatches();
|
||||
if (blockMetaMatches == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final Int2IntMap metaMap = blockMetaMatches.get(block);
|
||||
if (metaMap == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int id = BlockMaterialMapping.resolveId(metaMap, metadata);
|
||||
return id == -1 ? 0 : id;
|
||||
}
|
||||
|
||||
private static int lookupItemPropertiesId(Item item) {
|
||||
final Object2IntFunction<NamespacedId> itemIds = BlockRenderingSettings.INSTANCE.getItemIds();
|
||||
if (itemIds == null) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
final NamespacedId name = getCachedItemName(item);
|
||||
return name == null ? -1 : itemIds.applyAsInt(name);
|
||||
return name == null ? 0 : itemIds.applyAsInt(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -130,6 +130,7 @@ options.iris.shaderPackSelection.failedAdd=Files were not valid Shader Packs
|
||||
options.iris.shaderPackSelection.failedAddSingle="%s" is not a valid Shader Pack
|
||||
options.iris.shaderPackSelection.copyError=Could not add Shader Pack "%s"
|
||||
options.iris.shaderPackSelection.copyErrorAlreadyExists="%s" is already in your Shader Packs folder!
|
||||
options.iris.shaderPackOptions.noOptions="%s" has no configurable settings
|
||||
options.iris.shaderPackOptions.tooManyFiles=Cannot import multiple Shader Settings files!
|
||||
options.iris.shaderPackOptions.failedImport=Failed to import Shader Settings file "%s"
|
||||
options.iris.shaderPackOptions.importedSettings=Imported Shader Settings from "%s"
|
||||
@@ -224,6 +225,12 @@ options.angelica.droppedItemLimit=Dropped Item Render Limit
|
||||
options.angelica.droppedItemLimit.tooltip=The maximum number of dropped items that will be rendered. Lower values can improve performance.
|
||||
options.angelica.mobSpawnerRenderDistance=Mob spawner render distance
|
||||
options.angelica.mobSpawnerRenderDistance.tooltip=Render distance for the spinning mob inside mod spawners
|
||||
options.angelica.shadowGraphAngleDelta=Shadow Graph Rebuild Threshold
|
||||
options.angelica.shadowGraphAngleDelta.tooltip=How much a celestial body can move before the shadow map can update. Note this option is disabled when a shader pack utilizes voxelization features.
|
||||
options.angelica.shadowGraphAngleDelta.always=Always
|
||||
options.angelica.shadowGraphHorizonScale=Shadow Graph Horizon Tightening
|
||||
options.angelica.shadowGraphHorizonScale.tooltip=Adjusts the rate the shadow map rebuilds when when a celestial body is near the horizon. Rate is sinusoidal.
|
||||
options.angelica.shadowGraphHorizonScale.off=OFF
|
||||
options.angelica.itemdisplaylistcount=Item Renderer Cache Limit
|
||||
options.angelica.itemdisplaylistcount.tooltip=The upper limit of VBO's to cache in the optimized item renderer. Higher values will significantly increase performance, but may result in increased VRAM usage.
|
||||
options.angelica.threadedChunkBuilding=Threaded Chunk Building
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.ParticleRunSplitter;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
/**
|
||||
* Splits the particle batch between {@code gbuffers_particles} and {@code gbuffers_particles_translucent}.
|
||||
*/
|
||||
@Mixin(EffectRenderer.class)
|
||||
public class MixinEffectRenderer_Particles {
|
||||
|
||||
@Redirect(
|
||||
method = "renderParticles",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V")
|
||||
)
|
||||
private void iris$beginRun(Tessellator tessellator) {
|
||||
ParticleRunSplitter.beginRun();
|
||||
tessellator.startDrawingQuads();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "renderParticles",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;getBrightnessForRender(F)I"),
|
||||
require = 1
|
||||
)
|
||||
private int iris$splitRun(EntityFX particle, float partialTicks) {
|
||||
ParticleRunSplitter.splitIfNeeded(particle, Tessellator.instance, partialTicks);
|
||||
return particle.getBrightnessForRender(partialTicks);
|
||||
}
|
||||
}
|
||||
+8
@@ -3,9 +3,11 @@ package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.minecraft.client.particle.EntityPickupFX;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
@@ -23,11 +25,17 @@ public class MixinEntityPickupFX {
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntityWithPosYaw(Lnet/minecraft/entity/Entity;DDDFF)Z")
|
||||
)
|
||||
private boolean iris$wrapPickupRender(RenderManager renderManager, Entity entity, double x, double y, double z, float yaw, float partialTicks, Operation<Boolean> original) {
|
||||
final Boolean translucent = entity instanceof EntityItem item
|
||||
? HandRenderer.INSTANCE.isItemTranslucent(item.getEntityItem())
|
||||
: null;
|
||||
|
||||
final Boolean previous = GbufferPrograms.beginTranslucencyDeclaration(translucent);
|
||||
GbufferPrograms.beginEntities();
|
||||
try {
|
||||
return original.call(renderManager, entity, x, y, z, yaw, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endEntities();
|
||||
GbufferPrograms.endTranslucencyDeclaration(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -11,6 +11,7 @@ import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.shaderpack.CloudSetting;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
@@ -18,12 +19,14 @@ import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.SystemTimeUniforms;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -142,4 +145,24 @@ public abstract class MixinEntityRenderer implements IResourceManagerReloadListe
|
||||
original.call(instance, tessellator, entity, partialTicks);
|
||||
pipeline.get().setPhase(WorldRenderingPhase.NONE);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;renderLitParticles(Lnet/minecraft/entity/Entity;F)V"))
|
||||
private void iris$litParticlePhase(EffectRenderer instance, Entity viewer, float partialTicks, Operation<Void> original) {
|
||||
final int depth = GbufferPrograms.beginParticles();
|
||||
try {
|
||||
original.call(instance, viewer, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endParticles(depth);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V"))
|
||||
private void iris$particlePhase(EffectRenderer instance, Entity viewer, float partialTicks, Operation<Void> original) {
|
||||
final int depth = GbufferPrograms.beginParticles();
|
||||
try {
|
||||
original.call(instance, viewer, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endParticles(depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-64
@@ -1,16 +1,10 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
@@ -31,14 +25,10 @@ public class MixinItemRenderer {
|
||||
*/
|
||||
@Inject(method = "renderItemInFirstPerson", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$setFirstPersonItemId(float partialTicks, CallbackInfo ci) {
|
||||
if (IrisApi.getInstance().isShaderPackInUse()) {
|
||||
boolean isHandTranslucent = HandRenderer.INSTANCE.isHandTranslucent(InteractionHand.MAIN_HAND);
|
||||
boolean isRenderingSolid = HandRenderer.INSTANCE.isRenderingSolid();
|
||||
|
||||
if (isRenderingSolid == isHandTranslucent) {
|
||||
ci.cancel();
|
||||
return; // Don't set item ID since we're cancelling
|
||||
}
|
||||
if (IrisApi.getInstance().isShaderPackInUse()
|
||||
&& HandRenderer.INSTANCE.isRenderingSolid() == HandRenderer.INSTANCE.isItemTranslucent(this.itemToRender)) {
|
||||
ci.cancel();
|
||||
return; // Don't set item ID since we're cancelling
|
||||
}
|
||||
|
||||
// Wait for hand to lower before setting ID
|
||||
@@ -56,54 +46,4 @@ public class MixinItemRenderer {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the item ID for any item rendered on an entity.
|
||||
*/
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At("HEAD"),
|
||||
remap = false
|
||||
)
|
||||
private void iris$setEntityItemId(EntityLivingBase entity, ItemStack itemStack, int renderPass, IItemRenderer.ItemRenderType type, CallbackInfo ci) {
|
||||
ItemIdManager.setItemId(itemStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the ID once the item is drawn.
|
||||
*/
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At("RETURN"),
|
||||
remap = false
|
||||
)
|
||||
private void iris$clearEntityItemId(EntityLivingBase entity, ItemStack itemStack, int renderPass, IItemRenderer.ItemRenderType type, CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate GLINT shader before rendering enchantment glint on held items (third person).
|
||||
*/
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 0),
|
||||
remap = false
|
||||
)
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
ShaderGlint.beginGlint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate GLINT shader after rendering enchantment glint on held items (third person).
|
||||
*/
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 1, shift = At.Shift.AFTER),
|
||||
remap = false
|
||||
)
|
||||
private void iris$glintEnd(CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
ShaderGlint.endGlint();
|
||||
}
|
||||
}
|
||||
+20
-16
@@ -4,39 +4,43 @@ import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.backhand.BackhandReflectionCompat;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemRenderer.class)
|
||||
public class MixinItemRendererBackhand {
|
||||
|
||||
@Shadow private ItemStack itemToRender;
|
||||
|
||||
@Inject(method = "renderItemInFirstPerson", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$skipTranslucentHands(float partialTicks, CallbackInfo ci) {
|
||||
if (IrisApi.getInstance().isShaderPackInUse()) {
|
||||
final boolean isHandTranslucent = HandRenderer.INSTANCE.isHandTranslucent(InteractionHand.MAIN_HAND);
|
||||
if (HandRenderer.INSTANCE.isRenderingSolid() && isHandTranslucent) {
|
||||
ci.cancel();
|
||||
BackhandReflectionCompat.renderOffhand(partialTicks);
|
||||
} else if (!HandRenderer.INSTANCE.isRenderingSolid() && !isHandTranslucent) {
|
||||
ci.cancel();
|
||||
BackhandReflectionCompat.renderOffhand(partialTicks);
|
||||
}
|
||||
if (IrisApi.getInstance().isShaderPackInUse()
|
||||
&& HandRenderer.INSTANCE.isRenderingSolid() == HandRenderer.INSTANCE.isItemTranslucent(this.itemToRender)) {
|
||||
ci.cancel();
|
||||
BackhandReflectionCompat.renderOffhand(partialTicks);
|
||||
return;
|
||||
}
|
||||
ItemIdManager.setItemId(this.itemToRender);
|
||||
}
|
||||
|
||||
@Inject(method = "renderItemInFirstPerson", at = @At("RETURN"), order = 800)
|
||||
private void iris$resetFirstPersonItemId(float partialTicks, CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
// change injection to before Backhand's inject
|
||||
@Inject(method = "renderItemInFirstPerson", at = @At("RETURN"), cancellable = true, order = 900)
|
||||
private void iris$skipTranslucentHandsBackhand(float partialTicks, CallbackInfo ci) {
|
||||
if (ModStatus.isBackhandLoaded && IrisApi.getInstance().isShaderPackInUse()) {
|
||||
final boolean isHandTranslucent = HandRenderer.INSTANCE.isHandTranslucent(InteractionHand.OFF_HAND);
|
||||
if (HandRenderer.INSTANCE.isRenderingSolid() && isHandTranslucent) {
|
||||
ci.cancel();
|
||||
} else if (!HandRenderer.INSTANCE.isRenderingSolid() && !isHandTranslucent) {
|
||||
ci.cancel();
|
||||
}
|
||||
if (ModStatus.isBackhandLoaded && IrisApi.getInstance().isShaderPackInUse()
|
||||
&& HandRenderer.INSTANCE.isRenderingSolid() == HandRenderer.INSTANCE.isHandTranslucent(InteractionHand.OFF_HAND)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ItemRendererAccessor;
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Item ID and glint handling for items rendered on entities.
|
||||
*/
|
||||
@Mixin(ItemRenderer.class)
|
||||
public class MixinItemRenderer_ItemId implements ItemRendererAccessor {
|
||||
|
||||
@Shadow private ItemStack itemToRender;
|
||||
|
||||
@Override
|
||||
public ItemStack angelica$getItemToRender() {
|
||||
return itemToRender;
|
||||
}
|
||||
|
||||
@WrapMethod(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
remap = false
|
||||
)
|
||||
private void iris$entityItemId(EntityLivingBase entity, ItemStack itemStack, int renderPass, IItemRenderer.ItemRenderType type, Operation<Void> original) {
|
||||
final int prevItemId = ItemIdManager.getItemId();
|
||||
final long prevCutout = GbufferPrograms.pushCutoutDefaults();
|
||||
|
||||
final Boolean prevTranslucency = GbufferPrograms.beginTranslucencyDeclaration(
|
||||
HandRenderer.INSTANCE.isItemTranslucent(itemStack));
|
||||
|
||||
ItemIdManager.setItemId(itemStack);
|
||||
try {
|
||||
original.call(entity, itemStack, renderPass, type);
|
||||
} finally {
|
||||
GbufferPrograms.endTranslucencyDeclaration(prevTranslucency);
|
||||
ItemIdManager.setItemIdRaw(prevItemId);
|
||||
GbufferPrograms.popCutoutDefaults(prevCutout);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 0),
|
||||
remap = false
|
||||
)
|
||||
private void iris$glintStart(CallbackInfo ci) {
|
||||
ItemIdManager.resetItemId();
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.GLINT);
|
||||
ShaderGlint.beginGlint();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderItem(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/item/ItemStack;ILnet/minecraftforge/client/IItemRenderer$ItemRenderType;)V",
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glDepthFunc(I)V", ordinal = 1, shift = At.Shift.AFTER),
|
||||
remap = false
|
||||
)
|
||||
private void iris$glintEnd(CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
ShaderGlint.endGlint();
|
||||
}
|
||||
}
|
||||
+23
-10
@@ -32,10 +32,19 @@ public abstract class MixinRenderDragon {
|
||||
private static final NamespacedId DRAGON_DEATH_RAY = new NamespacedId("minecraft", "dragon_death_rays");
|
||||
|
||||
@Unique
|
||||
private int angelica$previousEntityId = -1;
|
||||
private static final int NOTHING_SAVED = Integer.MIN_VALUE;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousDeathRayEntityId = -1;
|
||||
private int angelica$previousEntityId = NOTHING_SAVED;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousDeathRayEntityId = NOTHING_SAVED;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousItemId = 0;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousDeathRayItemId = 0;
|
||||
|
||||
@Unique
|
||||
private boolean angelica$deathBeamsActive = false;
|
||||
@@ -57,9 +66,10 @@ public abstract class MixinRenderDragon {
|
||||
if (entityIdMap != null) {
|
||||
// Save the current entity ID
|
||||
angelica$previousEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
angelica$previousItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
|
||||
int beamId = entityIdMap.applyAsInt(END_CRYSTAL_BEAM);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(beamId);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(beamId, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,9 +79,10 @@ public abstract class MixinRenderDragon {
|
||||
at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glPopMatrix()V", ordinal = 0, shift = At.Shift.BEFORE, remap = false)
|
||||
)
|
||||
private void iris$restoreEntityId(EntityDragon dragon, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) {
|
||||
if (angelica$previousEntityId != -1) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(angelica$previousEntityId);
|
||||
angelica$previousEntityId = -1;
|
||||
if (angelica$previousEntityId != NOTHING_SAVED) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(angelica$previousEntityId, angelica$previousItemId);
|
||||
angelica$previousEntityId = NOTHING_SAVED;
|
||||
angelica$previousItemId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +103,9 @@ public abstract class MixinRenderDragon {
|
||||
Object2IntFunction<NamespacedId> entityIdMap = BlockRenderingSettings.INSTANCE.getEntityIds();
|
||||
if (entityIdMap != null) {
|
||||
angelica$previousDeathRayEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
angelica$previousDeathRayItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
int deathRayId = entityIdMap.applyAsInt(DRAGON_DEATH_RAY);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(deathRayId);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(deathRayId, 0);
|
||||
}
|
||||
|
||||
angelica$depthPassReplay++;
|
||||
@@ -131,9 +143,10 @@ public abstract class MixinRenderDragon {
|
||||
private void angelica$endDeathBeamsLighting(EntityDragon dragon, float partialTicks, CallbackInfo ci) {
|
||||
if (angelica$depthPassReplay > 0) return;
|
||||
if (angelica$deathBeamsActive) {
|
||||
if (angelica$previousDeathRayEntityId != -1) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(angelica$previousDeathRayEntityId);
|
||||
angelica$previousDeathRayEntityId = -1;
|
||||
if (angelica$previousDeathRayEntityId != NOTHING_SAVED) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(angelica$previousDeathRayEntityId, angelica$previousDeathRayItemId);
|
||||
angelica$previousDeathRayEntityId = NOTHING_SAVED;
|
||||
angelica$previousDeathRayItemId = 0;
|
||||
}
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
angelica$deathBeamsActive = false;
|
||||
|
||||
+5
-4
@@ -1,11 +1,12 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.uniforms.SystemTimeUniforms;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.tileentity.RenderEndPortal;
|
||||
import net.minecraft.tileentity.TileEntityEndPortal;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -25,9 +26,9 @@ public class MixinRenderEndPortal {
|
||||
@Unique private static final float iris$GREEN = 0.15f;
|
||||
@Unique private static final float iris$BLUE = 0.2f;
|
||||
|
||||
@Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntityEndPortal;DDDF)V", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$renderShaderPortal(TileEntityEndPortal te, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
// Always use shader-based portal rendering — eliminates glTexGen dependency for core profile
|
||||
@Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDF)V", at = @At("HEAD"), cancellable = true)
|
||||
private void iris$renderShaderPortal(TileEntity te, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
if (Iris.getCurrentPack().isEmpty()) return;
|
||||
ci.cancel();
|
||||
|
||||
float progress = (SystemTimeUniforms.TIMER.getFrameTimeCounter() * 0.01f) % 1.0f;
|
||||
|
||||
+2
-2
@@ -25,13 +25,13 @@ public class MixinRenderEntityFlame {
|
||||
private void iris$setFlame(Entity entity, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
Object2IntFunction<NamespacedId> entityIdMap = BlockRenderingSettings.INSTANCE.getEntityIds();
|
||||
if (entityIdMap != null) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityIdMap.applyAsInt(flameId));
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(entityIdMap.applyAsInt(flameId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "renderEntityOnFire", at = @At("RETURN"))
|
||||
private void iris$resetFlame(Entity entity, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(0);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
+15
-10
@@ -1,12 +1,13 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.shadercompat.ShaderGlint;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.renderer.entity.RenderItem;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -19,16 +20,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public class MixinRenderItem {
|
||||
|
||||
/**
|
||||
* Set the item ID before rendering dropped items.
|
||||
* Checks both item.properties and block.properties.
|
||||
* Item ID and cutout draw state for dropped items.
|
||||
*/
|
||||
@Inject(
|
||||
method = "doRender(Lnet/minecraft/entity/item/EntityItem;DDDFF)V",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void iris$setItemIdBeforeRender(EntityItem entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) {
|
||||
ItemStack itemStack = entity.getEntityItem();
|
||||
ItemIdManager.setItemId(itemStack);
|
||||
@WrapMethod(method = "doRender(Lnet/minecraft/entity/item/EntityItem;DDDFF)V")
|
||||
private void iris$droppedItemRender(EntityItem entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
final int prevItemId = ItemIdManager.getItemId();
|
||||
final long prevCutout = GbufferPrograms.pushCutoutDefaults();
|
||||
|
||||
ItemIdManager.setItemId(entity.getEntityItem());
|
||||
try {
|
||||
original.call(entity, x, y, z, entityYaw, partialTicks);
|
||||
} finally {
|
||||
ItemIdManager.setItemIdRaw(prevItemId);
|
||||
GbufferPrograms.popCutoutDefaults(prevCutout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+31
-7
@@ -12,6 +12,7 @@ import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
/**
|
||||
* Mixin to handle entity ID and item ID for entities rendered through renderEntityWithPosYaw and renderEntityStatic.
|
||||
@@ -21,23 +22,46 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
@Mixin(RenderManager.class)
|
||||
public class MixinRenderManager {
|
||||
|
||||
@Redirect(
|
||||
method = "func_147939_a",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRenderShadowAndFire(Lnet/minecraft/entity/Entity;DDDFF)V")
|
||||
)
|
||||
private void iris$wrapShadowAndFire(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks) {
|
||||
final Boolean previous = GbufferPrograms.beginTranslucencyDeclaration(null);
|
||||
|
||||
try {
|
||||
render.doRenderShadowAndFire(entity, x, y, z, entityYaw, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endTranslucencyDeclaration(previous);
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(
|
||||
method = "func_147939_a",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V")
|
||||
)
|
||||
private void iris$wrapDoRender(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
final int prevEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
final int prevItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
final Class<?> prevRenderable = TesrAttribution.currentRenderable;
|
||||
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(EntityIdHelper.getEntityId(entity), 0);
|
||||
TesrAttribution.currentRenderable = entity != null ? entity.getClass() : null;
|
||||
final boolean lightning = EntityIdHelper.isLightningBolt(entity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.LIGHTNING);
|
||||
}
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
final boolean nestedInBlockEntity = GbufferPrograms.beginNestedEntityPhase();
|
||||
|
||||
try {
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endNestedEntityPhase(nestedInBlockEntity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(prevEntityId, prevItemId);
|
||||
TesrAttribution.currentRenderable = prevRenderable;
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
TesrAttribution.currentRenderable = null;
|
||||
}
|
||||
}
|
||||
+18
-6
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrAttribution;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
@@ -23,16 +24,27 @@ public class MixinRenderManagerDAPI {
|
||||
require = 1 // Require this if DAPI is present, which should be the case when this mixin is applied.
|
||||
)
|
||||
private void iris$wrapDoRenderDragonAPI(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
int entityId = EntityIdHelper.getEntityId(entity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(entityId);
|
||||
final int prevEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
final int prevItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
final Class<?> prevRenderable = TesrAttribution.currentRenderable;
|
||||
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(EntityIdHelper.getEntityId(entity), 0);
|
||||
TesrAttribution.currentRenderable = entity != null ? entity.getClass() : null;
|
||||
final boolean lightning = EntityIdHelper.isLightningBolt(entity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.LIGHTNING);
|
||||
}
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
final boolean nestedInBlockEntity = GbufferPrograms.beginNestedEntityPhase();
|
||||
|
||||
try {
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endNestedEntityPhase(nestedInBlockEntity);
|
||||
if (lightning) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(prevEntityId, prevItemId);
|
||||
TesrAttribution.currentRenderable = prevRenderable;
|
||||
}
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(-1);
|
||||
}
|
||||
}
|
||||
+13
-5
@@ -23,7 +23,13 @@ public class MixinRenderNameTag {
|
||||
private static final NamespacedId NAME_TAG_ID = new NamespacedId("minecraft", "name_tag");
|
||||
|
||||
@Unique
|
||||
private int angelica$previousEntityId = -1;
|
||||
private static final int NOTHING_SAVED = Integer.MIN_VALUE;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousEntityId = NOTHING_SAVED;
|
||||
|
||||
@Unique
|
||||
private int angelica$previousItemId = 0;
|
||||
|
||||
/**
|
||||
* Inject at the HEAD of func_147906_a to set the special name_tag entity ID before rendering.
|
||||
@@ -37,10 +43,11 @@ public class MixinRenderNameTag {
|
||||
Object2IntFunction<NamespacedId> entityIdMap = BlockRenderingSettings.INSTANCE.getEntityIds();
|
||||
if (entityIdMap != null) {
|
||||
angelica$previousEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
angelica$previousItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
|
||||
// Set the special name_tag entity ID
|
||||
int nameTagId = entityIdMap.applyAsInt(NAME_TAG_ID);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(nameTagId);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(nameTagId, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +59,10 @@ public class MixinRenderNameTag {
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void iris$restoreEntityId(Entity entity, String name, double x, double y, double z, int maxDistance, CallbackInfo ci) {
|
||||
if (angelica$previousEntityId != -1) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntity(angelica$previousEntityId);
|
||||
angelica$previousEntityId = -1;
|
||||
if (angelica$previousEntityId != NOTHING_SAVED) {
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(angelica$previousEntityId, angelica$previousItemId);
|
||||
angelica$previousEntityId = NOTHING_SAVED;
|
||||
angelica$previousItemId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.mixins.early.shaders;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.shaderpack.materialmap.NamespacedId;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
@@ -49,7 +50,7 @@ public class MixinRenderPlayerArmor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set "minecraft:player_cape" when rendering the player's cape.
|
||||
* Set "minecraft:player_cape" when rendering the player's cape, and declare the cape opaque.
|
||||
*/
|
||||
@WrapOperation(
|
||||
method = "renderEquippedItems(Lnet/minecraft/client/entity/AbstractClientPlayer;F)V",
|
||||
@@ -62,7 +63,12 @@ public class MixinRenderPlayerArmor {
|
||||
CapturedRenderingState.INSTANCE.setCurrentRenderedItem(capeId);
|
||||
}
|
||||
|
||||
original.call(modelBiped, scale);
|
||||
final Boolean previous = GbufferPrograms.beginTranslucencyDeclaration(Boolean.FALSE);
|
||||
try {
|
||||
original.call(modelBiped, scale);
|
||||
} finally {
|
||||
GbufferPrograms.endTranslucencyDeclaration(previous);
|
||||
}
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
}
|
||||
+32
-4
@@ -10,18 +10,28 @@ import net.coderbot.iris.uniforms.ItemIdManager;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.renderer.entity.RenderDragon;
|
||||
import net.minecraft.client.renderer.entity.RenderEnderman;
|
||||
import net.minecraft.client.renderer.entity.RenderPlayer;
|
||||
import net.minecraft.client.renderer.entity.RenderSpider;
|
||||
import net.minecraft.client.renderer.entity.RendererLivingEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RendererLivingEntity.class)
|
||||
public class MixinRendererLivingEntity {
|
||||
public abstract class MixinRendererLivingEntity {
|
||||
|
||||
@Shadow
|
||||
protected abstract void renderModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale);
|
||||
|
||||
@Shadow
|
||||
protected abstract int getColorMultiplier(EntityLivingBase entity, float brightness, float partialTicks);
|
||||
|
||||
/**
|
||||
* Reset ID before damage overlay renders, otherwise you get random shiny zombies
|
||||
*/
|
||||
@@ -33,15 +43,33 @@ public class MixinRendererLivingEntity {
|
||||
ItemIdManager.resetItemId();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "doRender(Lnet/minecraft/entity/EntityLivingBase;DDDFF)V",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;renderModel(Lnet/minecraft/entity/EntityLivingBase;FFFFFF)V")
|
||||
)
|
||||
private void iris$declarePlayerModelTranslucent(RendererLivingEntity instance, EntityLivingBase entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale) {
|
||||
if (!(instance instanceof RenderPlayer)) {
|
||||
renderModel(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
return;
|
||||
}
|
||||
|
||||
final Boolean previous = GbufferPrograms.beginTranslucencyDeclaration(Boolean.TRUE);
|
||||
try {
|
||||
renderModel(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale);
|
||||
} finally {
|
||||
GbufferPrograms.endTranslucencyDeclaration(previous);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture entity color for shader access.
|
||||
*/
|
||||
@WrapOperation(
|
||||
@Redirect(
|
||||
method = "doRender",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;getColorMultiplier(Lnet/minecraft/entity/EntityLivingBase;FF)I")
|
||||
)
|
||||
private int iris$setEntityColor(RendererLivingEntity instance, EntityLivingBase elb, float f0, float f1, Operation<Integer> original) {
|
||||
final int j = original.call(instance, elb, f0, f1);
|
||||
private int iris$setEntityColor(RendererLivingEntity instance, EntityLivingBase elb, float f0, float f1) {
|
||||
final int j = getColorMultiplier(elb, f0, f1);
|
||||
final float a = (j >> 24 & 255) / 255.0F;
|
||||
final float r = (j >> 16 & 255) / 255.0F;
|
||||
final float g = (j >> 8 & 255) / 255.0F;
|
||||
|
||||
+5
@@ -4,10 +4,12 @@ import com.gtnewhorizons.angelica.rendering.tesr.PassRebindGate;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrAttribution;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrProviderDispatch;
|
||||
import com.prupe.mcpatcher.ctm.CTMUtils;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -17,6 +19,7 @@ public class MixinTileEntityRendererDispatcher {
|
||||
|
||||
@Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDF)V", at = @At("HEAD"))
|
||||
private void iris$setBlockEntityId(TileEntity te, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
GbufferPrograms.pushBlendState();
|
||||
CTMUtils.clearCurrentCompact();
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(iris$resolveBlockEntityId(te));
|
||||
TesrAttribution.currentRenderable = te != null ? te.getClass() : null;
|
||||
@@ -25,6 +28,7 @@ public class MixinTileEntityRendererDispatcher {
|
||||
PassRebindGate.rebindIfDirty();
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static int iris$resolveBlockEntityId(TileEntity te) {
|
||||
return TesrProviderDispatch.resolveBlockEntityId(te);
|
||||
}
|
||||
@@ -34,5 +38,6 @@ public class MixinTileEntityRendererDispatcher {
|
||||
CTMUtils.clearCurrentCompact();
|
||||
CapturedRenderingState.INSTANCE.setCurrentBlockEntity(0);
|
||||
TesrAttribution.currentRenderable = null;
|
||||
GbufferPrograms.popBlendStateTop();
|
||||
}
|
||||
}
|
||||
+5
@@ -1,9 +1,11 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.chisel;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.world.World;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Pseudo;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -22,12 +24,15 @@ public class MixinRenderCarvableBeacon {
|
||||
|
||||
@Inject(method = "renderBeam(FLnet/minecraft/world/World;DDDIF)V", at = @At("HEAD"))
|
||||
private void angelica$beginBeaconBeam(float f1, World world, double x, double y, double z, int meta, float partialTicks, CallbackInfo ci) {
|
||||
// Chisel's beam leaves GL_CULL_FACE disabled behind it
|
||||
GLStateManager.pushState(GL11.GL_ENABLE_BIT);
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.BEACON_BEAM);
|
||||
}
|
||||
|
||||
@Inject(method = "renderBeam(FLnet/minecraft/world/World;DDDIF)V", at = @At("RETURN"))
|
||||
private void angelica$endBeaconBeam(float f1, World world, double x, double y, double z, int meta, float partialTicks, CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
GLStateManager.popState();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.client.dragonapi;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.ParticleRunSplitter;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Pseudo;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Pseudo
|
||||
@Mixin(targets = { "Reika/DragonAPI/Extras/ThrottleableEffectRenderer" }, remap = false)
|
||||
public class MixinThrottleableEffectRenderer {
|
||||
|
||||
@Redirect(
|
||||
method = "doRenderParticles",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;startDrawingQuads()V", remap = true)
|
||||
)
|
||||
private void angelica$beginRun(Tessellator tessellator) {
|
||||
ParticleRunSplitter.beginRun();
|
||||
tessellator.startDrawingQuads();
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "doRenderParticles",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EntityFX;getBrightnessForRender(F)I", remap = true),
|
||||
require = 1
|
||||
)
|
||||
private int angelica$splitRun(EntityFX particle, float partialTicks) {
|
||||
ParticleRunSplitter.splitIfNeeded(particle, Tessellator.instance, partialTicks);
|
||||
return particle.getBrightnessForRender(partialTicks);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.client.etfuturum;
|
||||
|
||||
import ganymedes01.etfuturum.client.renderer.tileentity.TileEntityNewBeaconRenderer;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
/**
|
||||
* Et Futurum's replaces the regular vanilla beacon with its own.
|
||||
*/
|
||||
@Mixin(value = TileEntityNewBeaconRenderer.class, remap = false)
|
||||
public class MixinTileEntityNewBeaconRenderer {
|
||||
|
||||
@Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDF)V", at = @At("HEAD"), remap = true)
|
||||
private void angelica$beginBeaconBeam(TileEntity te, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
GbufferPrograms.setupSpecialRenderCondition(SpecialCondition.BEACON_BEAM);
|
||||
}
|
||||
|
||||
@Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDF)V", at = @At("RETURN"), remap = true)
|
||||
private void angelica$endBeaconBeam(TileEntity te, double x, double y, double z, float partialTicks, CallbackInfo ci) {
|
||||
GbufferPrograms.teardownSpecialRenderCondition();
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.client.openblocks;
|
||||
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.uniforms.CapturedRenderingState;
|
||||
import net.coderbot.iris.uniforms.EntityIdHelper;
|
||||
import net.minecraft.client.renderer.entity.Render;
|
||||
import net.minecraft.entity.Entity;
|
||||
import openblocks.client.renderer.tileentity.TileEntityTrophyRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
/**
|
||||
* Trophies render a mob through {@link Render#doRender}, force entity phase here.
|
||||
*/
|
||||
@Mixin(value = TileEntityTrophyRenderer.class, remap = false)
|
||||
public class MixinTileEntityTrophyRenderer {
|
||||
|
||||
@WrapOperation(
|
||||
method = "renderTrophy",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V", remap = true))
|
||||
private static void angelica$renderTrophyAsEntity(Render render, Entity entity, double x, double y, double z, float entityYaw, float partialTicks, Operation<Void> original) {
|
||||
final int prevEntityId = CapturedRenderingState.INSTANCE.getCurrentRenderedEntity();
|
||||
final int prevItemId = CapturedRenderingState.INSTANCE.getCurrentRenderedItem();
|
||||
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(EntityIdHelper.getEntityId(entity), 0);
|
||||
|
||||
final boolean nestedInBlockEntity = GbufferPrograms.beginNestedEntityPhase();
|
||||
|
||||
try {
|
||||
original.call(render, entity, x, y, z, entityYaw, partialTicks);
|
||||
} finally {
|
||||
GbufferPrograms.endNestedEntityPhase(nestedInBlockEntity);
|
||||
CapturedRenderingState.INSTANCE.setCurrentEntityAndItem(prevEntityId, prevItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrMaterial;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrShader;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrShaders;
|
||||
import net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition;
|
||||
import net.coderbot.iris.layer.PassOverride;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -15,44 +17,72 @@ class TesrLayerKeyTest {
|
||||
private static final ResourceLocation TEX = new ResourceLocation("angelica", "textures/test.png");
|
||||
private static final TesrShader SHADER = TesrShaders.register("test:layer_key", () -> {}, () -> {});
|
||||
private static final TesrMaterial.SpecialRender NONE = TesrMaterial.SpecialRender.NONE;
|
||||
private static final PassOverride NO_PASS = PassOverride.NONE;
|
||||
private static final PassOverride EYES = new PassOverride(SpecialCondition.ENTITY_EYES, null);
|
||||
private static final PassOverride TRANSLUCENT = new PassOverride(null, Boolean.TRUE);
|
||||
|
||||
@Test
|
||||
void scratchProbeMatchesCopiedKey() {
|
||||
final TesrBatchRenderer.LayerKey scratch = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER);
|
||||
final TesrBatchRenderer.LayerKey scratch = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER, false, NO_PASS, 0.0f, 0.0f);
|
||||
final TesrBatchRenderer.LayerKey stored = scratch.copy();
|
||||
assertNotSame(scratch, stored);
|
||||
assertEquals(scratch, stored);
|
||||
assertEquals(scratch.hashCode(), stored.hashCode());
|
||||
|
||||
scratch.set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER);
|
||||
scratch.set(TEX, TesrMaterial.Transparency.OPAQUE, true, false, false, false, 0.1f, false, NONE, SHADER, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertEquals(stored, scratch, "re-set scratch still matches stored copy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void fieldChangesBreakEquality() {
|
||||
final TesrBatchRenderer.LayerKey base = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
|
||||
final TesrBatchRenderer.LayerKey base = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
final TesrBatchRenderer.LayerKey other = base.copy();
|
||||
|
||||
other.set(null, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
|
||||
other.set(null, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.TRANSLUCENT, false, false, false, false, 0f, false, NONE, null);
|
||||
other.set(TEX, TesrMaterial.Transparency.TRANSLUCENT, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0.5f, false, NONE, null);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0.5f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, true, 0f, false, NONE, null);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, true, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, TesrMaterial.SpecialRender.GLINT, null);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, TesrMaterial.SpecialRender.GLINT, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, SHADER);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, SHADER, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, true, NO_PASS, 0.0f, 0.0f);
|
||||
assertNotEquals(base, other);
|
||||
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null);
|
||||
other.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertEquals(base, other);
|
||||
}
|
||||
|
||||
@Test
|
||||
void passSeparatesOtherwiseIdenticalKeys() {
|
||||
final TesrBatchRenderer.LayerKey plain = new TesrBatchRenderer.LayerKey().set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
final TesrBatchRenderer.LayerKey eyes = plain.copy();
|
||||
eyes.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, EYES, 0.0f, 0.0f);
|
||||
assertNotEquals(plain, eyes);
|
||||
|
||||
final TesrBatchRenderer.LayerKey translucent = plain.copy();
|
||||
translucent.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, TRANSLUCENT, 0.0f, 0.0f);
|
||||
assertNotEquals(plain, translucent);
|
||||
assertNotEquals(eyes, translucent);
|
||||
|
||||
assertEquals(eyes, eyes.copy());
|
||||
assertEquals(eyes.hashCode(), eyes.copy().hashCode());
|
||||
|
||||
// Polygon offset is the other thing a batch outlives -- the coplanar eye overlay needs it at emit time.
|
||||
final TesrBatchRenderer.LayerKey offset = plain.copy();
|
||||
offset.set(TEX, TesrMaterial.Transparency.OPAQUE, false, false, false, false, 0f, false, NONE, null, false, NO_PASS, -1.0f, -1.0f);
|
||||
assertNotEquals(plain, offset);
|
||||
assertEquals(offset, offset.copy());
|
||||
assertEquals(offset.hashCode(), offset.copy().hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullTextureAndShaderHash() {
|
||||
final TesrBatchRenderer.LayerKey key = new TesrBatchRenderer.LayerKey().set(null, null, false, false, false, false, 0f, false, null, null);
|
||||
final TesrBatchRenderer.LayerKey key = new TesrBatchRenderer.LayerKey().set(null, null, false, false, false, false, 0f, false, null, null, false, NO_PASS, 0.0f, 0.0f);
|
||||
assertEquals(key, key.copy());
|
||||
assertEquals(key.hashCode(), key.copy().hashCode());
|
||||
}
|
||||
|
||||
@@ -3,32 +3,84 @@ package net.coderbot.iris.pipeline;
|
||||
import net.coderbot.iris.shadows.ShadowGraphGate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ShadowGraphGateTest {
|
||||
|
||||
private static final float OVERHEAD = ShadowGraphGate.degreesToRotation(ShadowGraphGate.DEFAULT_ANGLE_DELTA_DEGREES);
|
||||
|
||||
private static final float HORIZON_SCALE = ShadowGraphGate.DEFAULT_HORIZON_SCALE;
|
||||
|
||||
private static float deltaForElevation(float sinElevation) {
|
||||
return ShadowGraphGate.deltaForElevation(sinElevation, OVERHEAD, HORIZON_SCALE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nanAlwaysDirty() {
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(Float.NaN, 0.25f));
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(Float.NaN, 0.25f, OVERHEAD));
|
||||
}
|
||||
|
||||
@Test
|
||||
void smallDeltaClean() {
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.0004f));
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f - 0.0004f));
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.00006f, OVERHEAD));
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f - 0.00006f, OVERHEAD));
|
||||
}
|
||||
|
||||
@Test
|
||||
void thresholdDeltaDirty() {
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.001f));
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f - 0.001f));
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.0002f, OVERHEAD));
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f - 0.0002f, OVERHEAD));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aFullRotationIsThreeSixtyDegrees() {
|
||||
assertEquals(1.0f, ShadowGraphGate.degreesToRotation(360.0f), 1e-9f);
|
||||
assertEquals(0.25f, ShadowGraphGate.degreesToRotation(90.0f), 1e-9f);
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrapAroundIsNotADiscontinuity() {
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.9999f, 0.0001f), "0.0002 across the wrap is below threshold");
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.999f, 0.0006f), "0.0016 across the wrap is above threshold");
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.0001f, 0.9999f), "wrap works in both directions");
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.99997f, 0.00001f, OVERHEAD), "0.00004 across the wrap is below threshold");
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.999f, 0.0006f, OVERHEAD), "0.0016 across the wrap is above threshold");
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.00001f, 0.99997f, OVERHEAD), "wrap works in both directions");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overheadLightUsesTheFullTolerance() {
|
||||
assertEquals(OVERHEAD, deltaForElevation(1.0f), 1e-9f);
|
||||
}
|
||||
|
||||
@Test
|
||||
void toleranceTightensTowardsTheHorizon() {
|
||||
// The default floor is 0.5, so tightening only bites above sin^2 0.5
|
||||
final float high = deltaForElevation(0.8f);
|
||||
assertEquals(OVERHEAD * 0.64f, high, 1e-9f);
|
||||
assertTrue(high < deltaForElevation(1.0f));
|
||||
assertTrue(deltaForElevation(0.75f) < high);
|
||||
}
|
||||
|
||||
@Test
|
||||
void toleranceIsFlooredAtTheHorizon() {
|
||||
final float floor = OVERHEAD * HORIZON_SCALE;
|
||||
assertEquals(floor, deltaForElevation(0.0f), 1e-9f);
|
||||
assertEquals(floor, deltaForElevation(0.1f), 1e-9f, "sin^2 0.1 is below the floor");
|
||||
assertEquals(floor, deltaForElevation(0.7f), 1e-9f, "sin^2 0.7 is still below the floor");
|
||||
}
|
||||
|
||||
@Test
|
||||
void elevationBelowTheHorizonMirrorsAbove() {
|
||||
// The shadow light points down at night; sin^2 keeps the sign out of it
|
||||
assertEquals(deltaForElevation(1.0f), deltaForElevation(-1.0f), 1e-9f);
|
||||
assertEquals(deltaForElevation(0.8f), deltaForElevation(-0.8f), 1e-9f);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nearTheHorizonASmallStepIsDirty() {
|
||||
final float horizon = deltaForElevation(0.0f);
|
||||
assertFalse(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.00006f, OVERHEAD));
|
||||
assertTrue(ShadowGraphGate.shouldMarkDirty(0.25f, 0.25f + 0.00006f, horizon),
|
||||
"0.00006 clears the tightened horizon threshold even though it is clean overhead");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user