mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
996fb54cb0 | ||
|
|
d1e7838cf9 | ||
|
|
a12d2bb4b0 | ||
|
|
60d1a3de3c | ||
|
|
367f9d9161 |
No files matched your search
@@ -186,6 +186,8 @@ DependencyHandlerScope.of(dependencies).apply {
|
||||
|
||||
compileOnly("mega:fluidlogged-mc1.7.10:0.1.2")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:LiquidLogged:0.2.0:dev") { isTransitive = false }
|
||||
|
||||
compileOnly("com.cardinalstar.cubicchunks:CubicChunks1710:v0.1.5-alpha:dev") { isTransitive = false }
|
||||
}
|
||||
|
||||
@@ -210,6 +212,7 @@ afterEvaluate {
|
||||
glsmTestFixtures(testFixtures(project(":glsm")) as ModuleDependency) { isTransitive = false }
|
||||
testCompileOnly(testFixtures(project(":glsm")))
|
||||
testImplementation("mega:fluidlogged-mc1.7.10:0.1.2")
|
||||
testImplementation("com.github.GTNewHorizons:LiquidLogged:0.2.0:dev") { isTransitive = false }
|
||||
|
||||
testRuntimeOnly(libs.fastutil)
|
||||
testRuntimeOnly(libs.joml)
|
||||
|
||||
@@ -66,6 +66,8 @@ public final class SystemProperties {
|
||||
public static final String FLYBY_COMMANDS = System.getProperty("angelica.flyby.commands", "");
|
||||
public static final String FLYBY_ORIGIN = System.getProperty("angelica.flyby.origin", "");
|
||||
public static final Integer FLYBY_DIMENSION = Integer.getInteger("angelica.flyby.dimension");
|
||||
public static final String FLYBY_BIOME = System.getProperty("angelica.flyby.biome", "");
|
||||
public static final boolean FLYBY_SURVIVAL = Boolean.getBoolean("angelica.flyby.survival");
|
||||
public static final FlybyPacing FLYBY_PACING = parseEnum("angelica.flyby.pacing", FlybyPacing.UNCAPPED, FlybyPacing.UNCAPPED, FlybyPacing.class);
|
||||
public static final FlybyWeather FLYBY_WEATHER = parseEnum("angelica.flyby.weather", FlybyWeather.CLEAR, FlybyWeather.CLEAR, FlybyWeather.class);
|
||||
public static final FlybyCamera FLYBY_CAMERA = parseEnum("angelica.flyby.camera", FlybyCamera.FIRST_PERSON, FlybyCamera.FIRST_PERSON, FlybyCamera.class);
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ColorMaskStack;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/// A draw between [#beginTracking] and [#endTracking] is left to the caller's replay instead of repeated. A replay
|
||||
/// ignores the depth mask, which a previous renderer may leak differently into the pass and the replay, and repeats
|
||||
/// set GL state through the backend, never the GLSM cache.
|
||||
public final class DepthEcho {
|
||||
|
||||
private static int framebuffer;
|
||||
private static int source;
|
||||
private static boolean echoed;
|
||||
private static boolean tracking;
|
||||
private static boolean hit;
|
||||
private static int immediate;
|
||||
private static boolean replaying;
|
||||
private static boolean replayDepthWrite;
|
||||
|
||||
private DepthEcho() {}
|
||||
|
||||
public static void arm(int framebuffer, int source) {
|
||||
DepthEcho.framebuffer = framebuffer;
|
||||
DepthEcho.source = source;
|
||||
}
|
||||
|
||||
public static void disarm() {
|
||||
framebuffer = 0;
|
||||
tracking = false;
|
||||
hit = false;
|
||||
endReplay();
|
||||
}
|
||||
|
||||
public static boolean armed() {
|
||||
return framebuffer != 0;
|
||||
}
|
||||
|
||||
public static void beginTracking() {
|
||||
tracking = framebuffer != 0;
|
||||
hit = false;
|
||||
}
|
||||
|
||||
public static boolean endTracking() {
|
||||
tracking = false;
|
||||
final boolean was = hit;
|
||||
hit = false;
|
||||
return was;
|
||||
}
|
||||
|
||||
public static void beginImmediate() {
|
||||
immediate++;
|
||||
}
|
||||
|
||||
public static void endImmediate() {
|
||||
immediate--;
|
||||
}
|
||||
|
||||
public static void beginReplay() {
|
||||
replaying = true;
|
||||
}
|
||||
|
||||
public static void endReplay() {
|
||||
replaying = false;
|
||||
restoreReplayDepthMask();
|
||||
}
|
||||
|
||||
public static boolean replaying() {
|
||||
return replaying;
|
||||
}
|
||||
|
||||
public static boolean takeEchoed() {
|
||||
final boolean was = echoed;
|
||||
echoed = false;
|
||||
return was;
|
||||
}
|
||||
|
||||
public static boolean skipsCall() {
|
||||
return replaySkips() && !DisplayListManager.isRecording();
|
||||
}
|
||||
|
||||
public static boolean skipsDraw() {
|
||||
if (!replaying) return false;
|
||||
if (replaySkips()) return true;
|
||||
if (!GLSMDepthStencilAlpha.getDepthState().isEnabled()) {
|
||||
RENDER_BACKEND.depthMask(true);
|
||||
replayDepthWrite = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean replaySkips() {
|
||||
return replaying && !(blendsVisibly() && GLSMFramebuffer.getDrawFramebuffer() == framebuffer);
|
||||
}
|
||||
|
||||
public static boolean begin() {
|
||||
if (replayDepthWrite) {
|
||||
restoreReplayDepthMask();
|
||||
return false;
|
||||
}
|
||||
if (framebuffer == 0 || GLSMDepthStencilAlpha.getDepthState().isEnabled() || !blendsVisibly() || GLSMFramebuffer.getDrawFramebuffer() != source) return false;
|
||||
echoed = true;
|
||||
if (tracking && immediate == 0 && !BatchStateGuard.isSuspended()) {
|
||||
hit = true;
|
||||
return false;
|
||||
}
|
||||
RENDER_BACKEND.bindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, framebuffer);
|
||||
RENDER_BACKEND.depthMask(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void end() {
|
||||
RENDER_BACKEND.depthMask(false);
|
||||
RENDER_BACKEND.bindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, source);
|
||||
}
|
||||
|
||||
private static void restoreReplayDepthMask() {
|
||||
if (!replayDepthWrite) return;
|
||||
replayDepthWrite = false;
|
||||
RENDER_BACKEND.depthMask(GLSMDepthStencilAlpha.getDepthState().isEnabled());
|
||||
}
|
||||
|
||||
private static boolean blendsVisibly() {
|
||||
if (!GLSMDepthStencilAlpha.getDepthTest().isEnabled() || !GLSMBlend.getBlendMode().isEnabled()) return false;
|
||||
if (GLSMDepthStencilAlpha.getDepthState().getFunc() == GL11.GL_EQUAL) return false;
|
||||
final ColorMaskStack mask = GLSMBlend.getColorMask();
|
||||
return mask.red || mask.green || mask.blue || mask.alpha;
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.BlendStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ColorMaskStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.DepthStateStack;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/// Per-draw state for depth peeling. Color passes skip the depth test but keep the draw's depth writes, so the target
|
||||
/// ends with the nearest peeled depth and the rest pass's own test keeps only what is in front of it. Depth and rest
|
||||
/// passes discard fragments that would not change the target under the draw's blend, so transparent texels do not take
|
||||
/// a peel. Draws with an application program cannot run [#GLSL], so they skip the peels and draw unsorted afterwards.
|
||||
public final class DepthPeel {
|
||||
|
||||
public static final int TEXTURE_UNIT = 15;
|
||||
public static final int SCENE_TEXTURE_UNIT = 14;
|
||||
|
||||
private static final int PASS_DEPTH = 0;
|
||||
private static final int PASS_COLOR = 1;
|
||||
private static final int PASS_REST = 2;
|
||||
private static final int UNBOUNDED = 4;
|
||||
private static final int COVER_ALPHA = 0;
|
||||
private static final int COVER_RGB = 8;
|
||||
private static final int COVER_RGB_ALPHA = 16;
|
||||
private static final int COVER_ALL = 24;
|
||||
|
||||
public static final String GLSL = "#define PEEL_PASS_COLOR " + PASS_COLOR + "\n"
|
||||
+ "#define PEEL_UNBOUNDED " + UNBOUNDED + "\n"
|
||||
+ "#define PEEL_COVER_MASK " + COVER_ALL + "\n"
|
||||
+ "#define PEEL_COVER_RGB " + COVER_RGB + "\n"
|
||||
+ "#define PEEL_COVER_RGB_ALPHA " + COVER_RGB_ALPHA + "\n"
|
||||
+ "#define PEEL_COVER_ALL " + COVER_ALL + "\n"
|
||||
+ "#define PEEL_SCENE_TOLERANCE 6.0e-8\n"
|
||||
+ "#define PEEL_WINDOW 2.4e-7\n"
|
||||
+ "#define PEEL_MIN_COVERAGE 0.004\n"
|
||||
+ """
|
||||
uniform sampler2D u_PeelDepth;
|
||||
uniform sampler2D u_PeelScene;
|
||||
uniform int u_PeelMode;
|
||||
void peelTest(vec4 c) {
|
||||
ivec2 texel = ivec2(gl_FragCoord.xy);
|
||||
float z = gl_FragCoord.z;
|
||||
if (z > texelFetch(u_PeelScene, texel, 0).r + PEEL_SCENE_TOLERANCE) discard;
|
||||
float bound = texelFetch(u_PeelDepth, texel, 0).r;
|
||||
if ((u_PeelMode & 3) == PEEL_PASS_COLOR) {
|
||||
if (z > bound || z < bound - PEEL_WINDOW) discard;
|
||||
return;
|
||||
}
|
||||
if ((u_PeelMode & PEEL_UNBOUNDED) == 0 && z >= bound - PEEL_WINDOW) discard;
|
||||
int cover = u_PeelMode & PEEL_COVER_MASK;
|
||||
float rgb = max(c.r, max(c.g, c.b));
|
||||
float coverage = cover == PEEL_COVER_ALL ? 1.0 : cover == PEEL_COVER_RGB ? rgb : cover == PEEL_COVER_RGB_ALPHA ? rgb * c.a : c.a;
|
||||
if (coverage < PEEL_MIN_COVERAGE) discard;
|
||||
}
|
||||
""";
|
||||
|
||||
public enum Pass { OFF, DEPTH, COLOR, REST, APPLICATION }
|
||||
|
||||
private static Pass pass = Pass.OFF;
|
||||
private static boolean unbounded;
|
||||
private static boolean overridden;
|
||||
private static boolean skippedApplicationDraws;
|
||||
|
||||
private DepthPeel() {}
|
||||
|
||||
public static void setPass(Pass next, boolean unbounded) {
|
||||
if (pass == Pass.OFF) skippedApplicationDraws = false;
|
||||
pass = next;
|
||||
DepthPeel.unbounded = unbounded;
|
||||
GLSMConfig.depthPeel = next == Pass.DEPTH || next == Pass.COLOR || next == Pass.REST;
|
||||
}
|
||||
|
||||
public static boolean active() {
|
||||
return pass != Pass.OFF;
|
||||
}
|
||||
|
||||
public static boolean skippedApplicationDraws() {
|
||||
return skippedApplicationDraws;
|
||||
}
|
||||
|
||||
public static int shaderMode() {
|
||||
return switch (pass) {
|
||||
case DEPTH -> PASS_DEPTH | coverage() | (unbounded ? UNBOUNDED : 0);
|
||||
case COLOR -> PASS_COLOR;
|
||||
default -> PASS_REST | coverage();
|
||||
};
|
||||
}
|
||||
|
||||
private static int coverage() {
|
||||
if (!GLSMBlend.getBlendMode().isEnabled()) return COVER_ALL;
|
||||
final BlendStateStack blend = GLStateManager.ctx().blendState;
|
||||
if (blend.getDstRgb() != GL11.GL_ONE) return COVER_ALPHA;
|
||||
return blend.getSrcRgb() == GL11.GL_SRC_ALPHA ? COVER_RGB_ALPHA : COVER_RGB;
|
||||
}
|
||||
|
||||
public static boolean begin() {
|
||||
if (pass == Pass.OFF) return true;
|
||||
final boolean fixedFunction = GLSMPrograms.getActiveProgram() == 0;
|
||||
if (pass == Pass.APPLICATION) return !fixedFunction;
|
||||
if (!fixedFunction) {
|
||||
skippedApplicationDraws = true;
|
||||
return false;
|
||||
}
|
||||
if (pass == Pass.DEPTH) {
|
||||
RENDER_BACKEND.colorMask(false, false, false, false);
|
||||
RENDER_BACKEND.depthMask(true);
|
||||
RENDER_BACKEND.depthFunc(GL11.GL_GREATER);
|
||||
overridden = true;
|
||||
} else if (pass == Pass.COLOR) {
|
||||
RENDER_BACKEND.depthFunc(GL11.GL_ALWAYS);
|
||||
overridden = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void end() {
|
||||
if (!overridden) return;
|
||||
overridden = false;
|
||||
final ColorMaskStack mask = GLSMBlend.getColorMask();
|
||||
final DepthStateStack depth = GLSMDepthStencilAlpha.getDepthState();
|
||||
RENDER_BACKEND.colorMask(mask.red, mask.green, mask.blue, mask.alpha);
|
||||
RENDER_BACKEND.depthMask(depth.isEnabled());
|
||||
RENDER_BACKEND.depthFunc(depth.getFunc());
|
||||
}
|
||||
}
|
||||
@@ -149,46 +149,19 @@ public final class GLSMBlend {
|
||||
}
|
||||
|
||||
static void issueBlendFunc(BlendStateStack blend) {
|
||||
RENDER_BACKEND.blendFuncSeparate(blend.getSrcRgb(), blend.getDstRgb(), emittedSrcAlpha(blend), emittedDstAlpha(blend));
|
||||
}
|
||||
|
||||
private static boolean addsWithoutCoverage(BlendStateStack blend) {
|
||||
return blend.getDstRgb() == GL11.GL_ONE;
|
||||
}
|
||||
|
||||
private static int emittedSrcAlpha(BlendStateStack blend) {
|
||||
if (GLSMConfig.layerBlending) return addsWithoutCoverage(blend) ? GL11.GL_ZERO : GL11.GL_ONE;
|
||||
return GLSMConfig.hudCacheOverride ? GL11.GL_ONE : blend.getSrcAlpha();
|
||||
}
|
||||
|
||||
private static int emittedDstAlpha(BlendStateStack blend) {
|
||||
if (GLSMConfig.layerBlending) return addsWithoutCoverage(blend) ? GL11.GL_ONE : GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
return GLSMConfig.hudCacheOverride ? GL11.GL_ONE_MINUS_SRC_ALPHA : blend.getDstAlpha();
|
||||
if (GLSMConfig.hudCacheOverride) {
|
||||
RENDER_BACKEND.blendFuncSeparate(blend.getSrcRgb(), blend.getDstRgb(), GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
} else {
|
||||
RENDER_BACKEND.blendFuncSeparate(blend.getSrcRgb(), blend.getDstRgb(), blend.getSrcAlpha(), blend.getDstAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
public static void setHudCacheOverride(boolean enabled) {
|
||||
if (GLSMConfig.hudCacheOverride == enabled) return;
|
||||
GLSMConfig.hudCacheOverride = enabled;
|
||||
reissueBlendFunc();
|
||||
}
|
||||
|
||||
public static void setLayerBlending(boolean enabled) {
|
||||
if (GLSMConfig.layerBlending == enabled) return;
|
||||
GLSMConfig.layerBlending = enabled;
|
||||
reissueBlendFunc();
|
||||
}
|
||||
|
||||
public static boolean isLayerBlending() {
|
||||
return GLSMConfig.layerBlending;
|
||||
}
|
||||
|
||||
private static void reissueBlendFunc() {
|
||||
final BlendStateStack blend = ctx().blendState;
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null && bh.isOverrideHeld()) {
|
||||
blend.setFuncUnknownState();
|
||||
return;
|
||||
}
|
||||
if (bh != null && bh.isOverrideHeld()) return;
|
||||
final BlendStateStack blend = ctx().blendState;
|
||||
issueBlendFunc(blend);
|
||||
blend.clearFuncUnknownState();
|
||||
}
|
||||
@@ -253,10 +226,11 @@ public final class GLSMBlend {
|
||||
glCtx.blendState.clearFuncUnknownState();
|
||||
issueBlendFunc(glCtx.blendState);
|
||||
if (GLSMHooks.BLEND_FUNC_CHANGE.hasListeners()) {
|
||||
final boolean hudCache = GLSMConfig.hudCacheOverride;
|
||||
GLSMHooks.blendFuncChangeEvent.srcRgb = srcRgb;
|
||||
GLSMHooks.blendFuncChangeEvent.dstRgb = dstRgb;
|
||||
GLSMHooks.blendFuncChangeEvent.srcAlpha = emittedSrcAlpha(glCtx.blendState);
|
||||
GLSMHooks.blendFuncChangeEvent.dstAlpha = emittedDstAlpha(glCtx.blendState);
|
||||
GLSMHooks.blendFuncChangeEvent.srcAlpha = hudCache ? GL11.GL_ONE : srcAlpha;
|
||||
GLSMHooks.blendFuncChangeEvent.dstAlpha = hudCache ? GL11.GL_ONE_MINUS_SRC_ALPHA : dstAlpha;
|
||||
GLSMHooks.BLEND_FUNC_CHANGE.post(GLSMHooks.blendFuncChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.gtnewhorizons.angelica.glsm.DisplayListManager.RecordMode;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.GLDebugMessageListener;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CommandRecorder;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.ImmediateModeRecorder;
|
||||
@@ -77,7 +76,6 @@ public final class GLSMDraws {
|
||||
ImmediateModeRecorder.begin(mode);
|
||||
return;
|
||||
}
|
||||
BatchStateGuard.beforeDraw();
|
||||
ImmediateModeRecorder.beginLive(mode);
|
||||
}
|
||||
|
||||
@@ -143,7 +141,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ByteBuffer indices) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
CommandRecorder savedRecorder = null;
|
||||
@@ -177,7 +174,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, IntBuffer indices) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
CommandRecorder savedRecorder = null;
|
||||
@@ -211,7 +207,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ShortBuffer indices) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
CommandRecorder savedRecorder = null;
|
||||
@@ -245,7 +240,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
CommandRecorder savedRecorder = null;
|
||||
@@ -279,7 +273,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, int indices_count, int type, long indices_buffer_offset) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
final GLContextState glCtx = ctx();
|
||||
drawCalls++;
|
||||
@@ -336,14 +329,12 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawElementsBaseVertex(int mode, int count, int type, long indices, int basevertex) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
RENDER_BACKEND.drawElementsBaseVertex(mode, count, type, indices, basevertex);
|
||||
}
|
||||
|
||||
public static void glDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
final GLContextState glCtx = ctx();
|
||||
@@ -362,7 +353,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
final GLContextState glCtx = ctx();
|
||||
@@ -387,7 +377,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawRangeElements(int mode, int start, int end, int count, int type, long indices) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
final GLContextState glCtx = ctx();
|
||||
final boolean locked = acquireDrawLock();
|
||||
@@ -404,13 +393,11 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawRangeElementsBaseVertex(int mode, int start, int end, int count, int type, long indices, int baseVertex) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
RENDER_BACKEND.drawRangeElementsBaseVertex(mode, start, end, count, type, indices, baseVertex);
|
||||
}
|
||||
|
||||
public static void glMultiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
final GLContextState glCtx = ctx();
|
||||
final boolean locked = acquireDrawLock();
|
||||
@@ -436,7 +423,6 @@ public final class GLSMDraws {
|
||||
}
|
||||
|
||||
public static void glDrawArrays(int mode, int first, int count) {
|
||||
if (DepthEcho.skipsCall()) return;
|
||||
rejectExitCapture();
|
||||
drawCalls++;
|
||||
CommandRecorder savedRecorder = null;
|
||||
@@ -535,7 +521,6 @@ public final class GLSMDraws {
|
||||
|
||||
public static void glCallList(int list) {
|
||||
rejectExitCapture();
|
||||
if (!DisplayListManager.isRecording()) BatchStateGuard.beforeDraw();
|
||||
if (!GLDebug.isActive()) {
|
||||
DisplayListManager.glCallList(list);
|
||||
return;
|
||||
|
||||
@@ -64,7 +64,6 @@ public final class GLSMFramebuffer {
|
||||
private static long firstClearBlockNanos;
|
||||
|
||||
public static void glClear(int mask) {
|
||||
if (DepthEcho.replaying() && !DisplayListManager.isRecording()) return;
|
||||
rejectExitCapture();
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
@@ -316,7 +315,6 @@ public final class GLSMFramebuffer {
|
||||
}
|
||||
|
||||
public static void glBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
if (DepthEcho.replaying() && !DisplayListManager.isRecording()) return;
|
||||
rejectExitCapture();
|
||||
RENDER_BACKEND.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
|
||||
@@ -503,8 +503,8 @@ public final class GLSMQueries {
|
||||
return RENDER_BACKEND.genQueries();
|
||||
}
|
||||
public static void glDeleteQueries(int id) { rejectExitCapture(); RENDER_BACKEND.deleteQueries(id); }
|
||||
public static void glBeginQuery(int target, int id) { rejectExitCapture(); if (!DepthEcho.replaying()) RENDER_BACKEND.beginQuery(target, id); }
|
||||
public static void glEndQuery(int target) { rejectExitCapture(); if (!DepthEcho.replaying()) RENDER_BACKEND.endQuery(target); }
|
||||
public static void glBeginQuery(int target, int id) { rejectExitCapture(); RENDER_BACKEND.beginQuery(target, id); }
|
||||
public static void glEndQuery(int target) { rejectExitCapture(); RENDER_BACKEND.endQuery(target); }
|
||||
public static void glGetQueryObjectui(int id, int pname, IntBuffer params) { rejectExitCapture(); RENDER_BACKEND.getQueryObjectui(id, pname, params); }
|
||||
public static int glGetQueryObjecti(int id, int pname) { rejectExitCapture(); return RENDER_BACKEND.getQueryObjecti(id, pname); }
|
||||
public static void glQueryCounter(int id, int target) { rejectExitCapture(); RENDER_BACKEND.queryCounter(id, target); }
|
||||
|
||||
@@ -6,8 +6,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class StateSet {
|
||||
|
||||
public static final int R_DEPTH = 1;
|
||||
@@ -81,47 +79,28 @@ public final class StateSet {
|
||||
public static final StateSet CUTOUT = buildCutout();
|
||||
public static final StateSet MASKS = buildMasks();
|
||||
public static final StateSet CULL = buildCull();
|
||||
public static final StateSet BLOCK_ENTITY_PASS = buildBlockEntityPass();
|
||||
|
||||
private static CowStateStack<?>[] batchMembers() {
|
||||
return new CowStateStack<?>[] {
|
||||
GLSMBlend.getBlendState(), GLSMDepthStencilAlpha.getAlphaState(), GLSMDepthStencilAlpha.getDepthState(),
|
||||
GLSMBlend.getColorMask(), GLSMRasterizer.getPolygonState(),
|
||||
GLSMTextures.getTextures().getTextureUnitBindings(0), GLSMTextures.getTextures().getTextureUnitBindings(1),
|
||||
GLSMTextures.getActiveTextureUnitStack(),
|
||||
GLSMBlend.getBlendMode(), GLSMDepthStencilAlpha.getAlphaTest(), GLSMDepthStencilAlpha.getDepthTest(),
|
||||
GLSMLighting.getLightingState(), GLSMRasterizer.getCullState(), GLSMRasterizer.getPolygonOffsetFillState(),
|
||||
GLSMTextures.getTextures().getTextureUnitStates(0), GLSMTextures.getTextures().getTextureUnitStates(1),
|
||||
GLSMLighting.getLightStates()[0], GLSMLighting.getLightStates()[1],
|
||||
GLSMLighting.getLightDataStates()[0], GLSMLighting.getLightDataStates()[1],
|
||||
GLSMLighting.getColorMaterial(), GLSMLighting.getColorMaterialFace(), GLSMLighting.getColorMaterialParameter(),
|
||||
GLSMLighting.getLightModel(), GLSMLighting.getFrontMaterial(), GLSMLighting.getBackMaterial(),
|
||||
GLSMLighting.getNormalizeState(), GLSMLighting.getRescaleNormalState()
|
||||
};
|
||||
}
|
||||
|
||||
private static StateSet buildBatch() {
|
||||
return new StateSet(0,
|
||||
ids(batchMembers()),
|
||||
ids(
|
||||
GLSMBlend.getBlendState(), GLSMDepthStencilAlpha.getAlphaState(), GLSMDepthStencilAlpha.getDepthState(),
|
||||
GLSMBlend.getColorMask(), GLSMRasterizer.getPolygonState(),
|
||||
GLSMTextures.getTextures().getTextureUnitBindings(0), GLSMTextures.getTextures().getTextureUnitBindings(1),
|
||||
GLSMTextures.getActiveTextureUnitStack(),
|
||||
GLSMBlend.getBlendMode(), GLSMDepthStencilAlpha.getAlphaTest(), GLSMDepthStencilAlpha.getDepthTest(),
|
||||
GLSMLighting.getLightingState(), GLSMRasterizer.getCullState(), GLSMRasterizer.getPolygonOffsetFillState(),
|
||||
GLSMTextures.getTextures().getTextureUnitStates(0), GLSMTextures.getTextures().getTextureUnitStates(1),
|
||||
GLSMLighting.getLightStates()[0], GLSMLighting.getLightStates()[1],
|
||||
GLSMLighting.getLightDataStates()[0], GLSMLighting.getLightDataStates()[1],
|
||||
GLSMLighting.getColorMaterial(), GLSMLighting.getColorMaterialFace(), GLSMLighting.getColorMaterialParameter(),
|
||||
GLSMLighting.getLightModel(), GLSMLighting.getFrontMaterial(), GLSMLighting.getBackMaterial(),
|
||||
GLSMLighting.getNormalizeState(), GLSMLighting.getRescaleNormalState()
|
||||
),
|
||||
R_BLEND | R_DEPTH | R_COLOR_MASK | R_POLYGON | R_TEXTURE | R_ACTIVE_UNIT,
|
||||
B_FRAG_COLORBUF | B_LIGHTING,
|
||||
true);
|
||||
}
|
||||
|
||||
private static StateSet buildBlockEntityPass() {
|
||||
final CowStateStack<?>[] batch = batchMembers();
|
||||
final CowStateStack<?>[] all = Arrays.copyOf(batch, batch.length + 4);
|
||||
all[batch.length] = GLSMCurrentAttribs.getColor();
|
||||
all[batch.length + 1] = GLSMFog.getFogState();
|
||||
all[batch.length + 2] = GLSMFog.getFogMode();
|
||||
all[batch.length + 3] = GLSMRasterizer.getShadeModelState();
|
||||
return new StateSet(0,
|
||||
ids(all),
|
||||
R_BLEND | R_DEPTH | R_COLOR_MASK | R_POLYGON | R_TEXTURE | R_ACTIVE_UNIT,
|
||||
B_FRAG_COLORBUF | B_LIGHTING | B_CURRENT | B_FRAG_FOG,
|
||||
true);
|
||||
}
|
||||
|
||||
private static StateSet buildFont() {
|
||||
return new StateSet(0,
|
||||
ids(
|
||||
|
||||
+12
-12
@@ -323,42 +323,42 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawArrays(int mode, int first, int count) {
|
||||
public void drawArrays(int mode, int first, int count) {
|
||||
GL11.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, int count, int type, long indices) {
|
||||
public void drawElements(int mode, int count, int type, long indices) {
|
||||
GL11.glDrawElements(mode, count, type, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, ByteBuffer indices) {
|
||||
public void drawElements(int mode, ByteBuffer indices) {
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, IntBuffer indices) {
|
||||
public void drawElements(int mode, IntBuffer indices) {
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, ShortBuffer indices) {
|
||||
public void drawElements(int mode, ShortBuffer indices) {
|
||||
GL11.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
public void drawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
GL11.glDrawElements(mode, count, type, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
public void drawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
GL31.glDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
public void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
GL31.glDrawArraysInstanced(mode, first, count, primcount);
|
||||
}
|
||||
|
||||
@@ -368,7 +368,7 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
public void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
GL43.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
@@ -378,12 +378,12 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
public void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
GL32.glDrawElementsBaseVertex(mode, count, type, indices, baseVertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
public void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
for (int i = 0; i < drawcount; i++) {
|
||||
GL32.glDrawElementsBaseVertex(mode, memGetInt(pCount + 4L * i), type, memGetAddress(pIndices + (long) i * POINTER_SIZE), memGetInt(pBaseVertex + 4L * i));
|
||||
}
|
||||
@@ -1715,7 +1715,7 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
public void multiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
GL14.glMultiDrawArrays(mode, firsts, counts);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.glsm.backend;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthPeel;
|
||||
import com.gtnewhorizons.angelica.glsm.GLESFormatRemap;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMAttribStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
@@ -323,221 +321,28 @@ public abstract class RenderBackend {
|
||||
public abstract void logicOp(int opcode);
|
||||
public abstract void hint(int target, int mode);
|
||||
|
||||
public abstract void drawArrays(int mode, int first, int count);
|
||||
public abstract void drawElements(int mode, int count, int type, long indices);
|
||||
public void drawElements(int mode, ByteBuffer indices) {}
|
||||
public void drawElements(int mode, IntBuffer indices) {}
|
||||
public void drawElements(int mode, ShortBuffer indices) {}
|
||||
public void drawElements(int mode, int count, int type, ByteBuffer indices) {}
|
||||
public abstract void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride);
|
||||
public void multiDrawArraysIndirectCount(int mode, long indirect, long drawcount, int maxdrawcount, int stride) { throw new UnsupportedOperationException(getName() + ": indirect draw-count buffers unsupported"); }
|
||||
public void multiDrawElementsIndirectCount(int mode, int type, long indirect, long drawcount, int maxdrawcount, int stride) { throw new UnsupportedOperationException(getName() + ": indirect draw-count buffers unsupported"); }
|
||||
public abstract void copyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size);
|
||||
public abstract void drawElementsInstanced(int mode, int count, int type, long indices, int primcount);
|
||||
public abstract void drawArraysInstanced(int mode, int first, int count, int primcount);
|
||||
public void provokingVertex(int provokeMode) {}
|
||||
|
||||
public final void drawArrays(int mode, int first, int count) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawArrays(mode, first, count);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawArrays(mode, first, count);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElements(int mode, int count, int type, long indices) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElements(mode, count, type, indices);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElements(mode, count, type, indices);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElements(int mode, ByteBuffer indices) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElements(int mode, IntBuffer indices) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElements(int mode, ShortBuffer indices) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElements(mode, indices);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElements(mode, count, type, indices);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElements(mode, count, type, indices);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawArraysInstanced(mode, first, count, primcount);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawArraysInstanced(mode, first, count, primcount);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueDrawElementsBaseVertex(mode, count, type, indices, baseVertex);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueDrawElementsBaseVertex(mode, count, type, indices, baseVertex);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueMultiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueMultiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void multiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
if (DepthEcho.skipsDraw() || !DepthPeel.begin()) return;
|
||||
try {
|
||||
issueMultiDrawArrays(mode, firsts, counts);
|
||||
} finally {
|
||||
DepthPeel.end();
|
||||
}
|
||||
if (DepthEcho.begin()) {
|
||||
try {
|
||||
issueMultiDrawArrays(mode, firsts, counts);
|
||||
} finally {
|
||||
DepthEcho.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void issueDrawArrays(int mode, int first, int count);
|
||||
protected abstract void issueDrawElements(int mode, int count, int type, long indices);
|
||||
protected void issueDrawElements(int mode, ByteBuffer indices) {}
|
||||
protected void issueDrawElements(int mode, IntBuffer indices) {}
|
||||
protected void issueDrawElements(int mode, ShortBuffer indices) {}
|
||||
protected void issueDrawElements(int mode, int count, int type, ByteBuffer indices) {}
|
||||
protected abstract void issueMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride);
|
||||
protected abstract void issueDrawElementsInstanced(int mode, int count, int type, long indices, int primcount);
|
||||
protected abstract void issueDrawArraysInstanced(int mode, int first, int count, int primcount);
|
||||
protected abstract void issueDrawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex);
|
||||
protected abstract void issueMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex);
|
||||
protected abstract void issueMultiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts);
|
||||
public abstract void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex);
|
||||
public abstract void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex);
|
||||
public void drawRangeElements(int mode, int start, int end, int count, int type, long indices) {
|
||||
drawElements(mode, count, type, indices);
|
||||
}
|
||||
public void drawRangeElementsBaseVertex(int mode, int start, int end, int count, int type, long indices, int baseVertex) {
|
||||
drawElementsBaseVertex(mode, count, type, indices, baseVertex);
|
||||
}
|
||||
public abstract void multiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts);
|
||||
public abstract void primitiveRestartIndex(int index);
|
||||
public abstract void pointParameterf(int pname, float param);
|
||||
public abstract void pointParameteri(int pname, int param);
|
||||
|
||||
@@ -108,11 +108,13 @@ public final class FFPUniformBlock {
|
||||
public static final int FOG_PARAMS = vec4("u_FogParams");
|
||||
public static final int FOG_COLOR = vec4("u_FogColor");
|
||||
|
||||
// Rain and snow, for Instancing.WEATHER. 0 = (translate.xyz, 1/radius),
|
||||
// 1 = (cameraFrac.xy, partialTicks, age), 2 = (rainScroll, snowScroll, rainStrength, unused).
|
||||
// Weather columns, for Instancing.WEATHER. 0 = (translate.xyz, 1/radius),
|
||||
// 1 = (cameraFrac.xy, partialTicks, age), 2 = (vanillaTick, providerTick, rainStrength, providerAge),
|
||||
// 3 = (provider 1/radius, unused, unused, unused).
|
||||
public static final int WEATHER_PARAMS_0 = vec4("u_WeatherParams0");
|
||||
public static final int WEATHER_PARAMS_1 = vec4("u_WeatherParams1");
|
||||
public static final int WEATHER_PARAMS_2 = vec4("u_WeatherParams2");
|
||||
public static final int WEATHER_PARAMS_3 = vec4("u_WeatherParams3");
|
||||
|
||||
public static final int SIZE;
|
||||
public static final String GLSL_DECL;
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.util.Arrays;
|
||||
import com.gtnewhorizons.angelica.glsm.GLContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMRasterizer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TexEnvState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
@@ -17,24 +16,24 @@ import org.lwjgl.opengl.GL13;
|
||||
* Packed-long fragment shader permutation key for FFP emulation.
|
||||
*
|
||||
* Layout:
|
||||
* long[0]: global bits (14) + unit 0 (45 bits at offset 14), depth peel (60), combined glint (61), glint alpha (62), clip discard (63)
|
||||
* long[1..3]: unit 1..3 (45 bits each, low-aligned)
|
||||
* long[0]: global bits (14) + unit 0 (47 bits at offset 14)
|
||||
* long[1..3]: unit 1..3 (47 bits each, low-aligned)
|
||||
* Only max(1, nrEnabledUnits) longs are significant.
|
||||
*
|
||||
* Per-unit packing (45 bits):
|
||||
* Per-unit packing (47 bits):
|
||||
* 0: enabled
|
||||
* 1-3: mode (MODULATE=0..COMBINE=5)
|
||||
* 4: needsEnvColor
|
||||
* 5-7: combineRgb (encoded 0-7)
|
||||
* 8-10: combineAlpha (encoded 0-7)
|
||||
* 11-12: scaleShiftRgb
|
||||
* 13-14: scaleShiftAlpha
|
||||
* 15-19: arg0 RGB (source:3 + operand:2)
|
||||
* 20-24: arg1 RGB
|
||||
* 25-29: arg2 RGB
|
||||
* 30-34: arg0 Alpha
|
||||
* 35-39: arg1 Alpha
|
||||
* 40-44: arg2 Alpha
|
||||
* 5-8: combineRgb (encoded 0-7)
|
||||
* 9-12: combineAlpha (encoded 0-7)
|
||||
* 13-14: scaleShiftRgb
|
||||
* 15-16: scaleShiftAlpha
|
||||
* 17-21: arg0 RGB (source:3 + operand:2)
|
||||
* 22-26: arg1 RGB
|
||||
* 27-31: arg2 RGB
|
||||
* 32-36: arg0 Alpha
|
||||
* 37-41: arg1 Alpha
|
||||
* 42-46: arg2 Alpha
|
||||
*/
|
||||
public final class FragmentKey {
|
||||
public static final int TEX_ENV_MODULATE = 0;
|
||||
@@ -79,7 +78,6 @@ public final class FragmentKey {
|
||||
}
|
||||
|
||||
private static final int GLOBAL_BITS = 14;
|
||||
private static final int BIT_DEPTH_PEEL = 60;
|
||||
private static final int BIT_COMBINED_GLINT = 61;
|
||||
private static final int BIT_GLINT_REPLACE_ALPHA = 62;
|
||||
private static final int BIT_CLIP_DISCARD = 63;
|
||||
@@ -96,16 +94,16 @@ public final class FragmentKey {
|
||||
private static final int U_ENABLED = 0;
|
||||
private static final int U_MODE = 1; // 3 bits
|
||||
private static final int U_NEEDS_ENV_COLOR = 4; // 1 bit
|
||||
private static final int U_COMBINE_RGB = 5; // 3 bits
|
||||
private static final int U_COMBINE_ALPHA = 8; // 3 bits
|
||||
private static final int U_SCALE_RGB = 11; // 2 bits
|
||||
private static final int U_SCALE_ALPHA = 13; // 2 bits
|
||||
private static final int U_ARG0_RGB = 15; // 5 bits (source:3 + operand:2)
|
||||
private static final int U_ARG1_RGB = 20; // 5 bits
|
||||
private static final int U_ARG2_RGB = 25; // 5 bits
|
||||
private static final int U_ARG0_ALPHA = 30; // 5 bits
|
||||
private static final int U_ARG1_ALPHA = 35; // 5 bits
|
||||
private static final int U_ARG2_ALPHA = 40; // 5 bits
|
||||
private static final int U_COMBINE_RGB = 5; // 4 bits
|
||||
private static final int U_COMBINE_ALPHA = 9; // 4 bits
|
||||
private static final int U_SCALE_RGB = 13; // 2 bits
|
||||
private static final int U_SCALE_ALPHA = 15; // 2 bits
|
||||
private static final int U_ARG0_RGB = 17; // 5 bits (source:3 + operand:2)
|
||||
private static final int U_ARG1_RGB = 22; // 5 bits
|
||||
private static final int U_ARG2_RGB = 27; // 5 bits
|
||||
private static final int U_ARG0_ALPHA = 32; // 5 bits
|
||||
private static final int U_ARG1_ALPHA = 37; // 5 bits
|
||||
private static final int U_ARG2_ALPHA = 42; // 5 bits
|
||||
|
||||
static final int MAX_UNITS = 4;
|
||||
|
||||
@@ -129,7 +127,6 @@ public final class FragmentKey {
|
||||
public static int packFromState(long[] out, GLContextState glCtx) {
|
||||
long global = 0;
|
||||
if (CombinedGlint.isActive()) global |= 1L << BIT_COMBINED_GLINT;
|
||||
if (GLSMConfig.depthPeel) global |= 1L << BIT_DEPTH_PEEL;
|
||||
if (CombinedGlint.replacesAlpha()) global |= 1L << BIT_GLINT_REPLACE_ALPHA;
|
||||
if (GLSMRasterizer.clipEmulationActive(glCtx)) global |= 1L << BIT_CLIP_DISCARD;
|
||||
|
||||
@@ -203,8 +200,8 @@ public final class FragmentKey {
|
||||
if (mode == TEX_ENV_COMBINE) {
|
||||
final int combRgb = encodeCombineFunc(envState.combineRgb);
|
||||
final int combAlpha = encodeCombineFunc(envState.combineAlpha);
|
||||
bits |= ((long) (combRgb & 0x7)) << U_COMBINE_RGB;
|
||||
bits |= ((long) (combAlpha & 0x7)) << U_COMBINE_ALPHA;
|
||||
bits |= ((long) (combRgb & 0xF)) << U_COMBINE_RGB;
|
||||
bits |= ((long) (combAlpha & 0xF)) << U_COMBINE_ALPHA;
|
||||
bits |= ((long) (encodeScale(envState.scaleRgb) & 0x3)) << U_SCALE_RGB;
|
||||
bits |= ((long) (encodeScale(envState.scaleAlpha) & 0x3)) << U_SCALE_ALPHA;
|
||||
|
||||
@@ -267,7 +264,6 @@ public final class FragmentKey {
|
||||
public boolean combinedGlint() { return (packed[0] & (1L << BIT_COMBINED_GLINT)) != 0; }
|
||||
public boolean clipDiscard() { return (packed[0] & (1L << BIT_CLIP_DISCARD)) != 0; }
|
||||
public boolean glintReplaceAlpha() { return (packed[0] & (1L << BIT_GLINT_REPLACE_ALPHA)) != 0; }
|
||||
public boolean depthPeel() { return (packed[0] & (1L << BIT_DEPTH_PEEL)) != 0; }
|
||||
public int textureSupersamplingSamples() { return 1 << (int) ((packed[0] >> BIT_TEXTURE_SUPERSAMPLING) & 0x7); }
|
||||
public boolean alphaTestEnabled() { return ((packed[0] >> BIT_ALPHA_TEST) & 1) != 0; }
|
||||
public int alphaTestFunc() { return (int) ((packed[0] >> BIT_ALPHA_FUNC) & 0x7); }
|
||||
@@ -285,8 +281,8 @@ public final class FragmentKey {
|
||||
public boolean unitEnabled(int i) { return (unitBits(i) & 1) != 0; }
|
||||
public int unitMode(int i) { return (int) ((unitBits(i) >> U_MODE) & 0x7); }
|
||||
public boolean unitNeedsEnvColor(int i) { return ((unitBits(i) >> U_NEEDS_ENV_COLOR) & 1) != 0; }
|
||||
public int unitCombineRgb(int i) { return (int) ((unitBits(i) >> U_COMBINE_RGB) & 0x7); }
|
||||
public int unitCombineAlpha(int i) { return (int) ((unitBits(i) >> U_COMBINE_ALPHA) & 0x7); }
|
||||
public int unitCombineRgb(int i) { return (int) ((unitBits(i) >> U_COMBINE_RGB) & 0xF); }
|
||||
public int unitCombineAlpha(int i) { return (int) ((unitBits(i) >> U_COMBINE_ALPHA) & 0xF); }
|
||||
public int unitScaleShiftRgb(int i) { return (int) ((unitBits(i) >> U_SCALE_RGB) & 0x3); }
|
||||
public int unitScaleShiftAlpha(int i) { return (int) ((unitBits(i) >> U_SCALE_ALPHA) & 0x3); }
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DepthPeel;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
|
||||
@@ -25,7 +24,6 @@ public final class FragmentShaderGenerator {
|
||||
sb.append("#define GLINT_ALPHA_FUNC ").append(key.alphaTestEnabled() ? key.alphaTestFunc() : 7).append('\n');
|
||||
sb.append("#define GLINT_OVERLAY ").append(key.overlayInstanced() ? 2 : key.overlayEnabled() ? 1 : 0).append('\n');
|
||||
sb.append("#define GLINT_LIGHTMAP ").append(key.nrEnabledUnits() > 1 && key.unitEnabled(1) ? 1 : 0).append('\n');
|
||||
if (key.depthPeel()) sb.append("#define DEPTH_PEEL 1\n");
|
||||
sb.append(ShaderLoader.getShaderSource("angelica:combined_glint.frag.glsl"));
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -45,7 +43,6 @@ public final class FragmentShaderGenerator {
|
||||
emitSpecularAdd(sb, key);
|
||||
emitAlphaTest(sb, key);
|
||||
emitFog(sb, key);
|
||||
emitDepthPeel(sb, key);
|
||||
sb.append(" fragColor = color;\n");
|
||||
sb.append("}\n");
|
||||
|
||||
@@ -92,15 +89,10 @@ public final class FragmentShaderGenerator {
|
||||
sb.append("uniform sampler2D u_Sampler").append(i).append(";\n");
|
||||
}
|
||||
}
|
||||
if (key.depthPeel()) sb.append(DepthPeel.GLSL);
|
||||
sb.append(FFPUniformBlock.GLSL_DECL);
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
private static void emitDepthPeel(StringBuilder sb, FragmentKey key) {
|
||||
if (key.depthPeel()) sb.append(" peelTest(color);\n");
|
||||
}
|
||||
|
||||
private static void emitTextureSampling(StringBuilder sb, FragmentKey key) {
|
||||
for (int i = 0; i < key.nrEnabledUnits(); i++) {
|
||||
if (!key.unitEnabled(i)) continue;
|
||||
|
||||
@@ -39,17 +39,16 @@ public final class InstancedGlslHelpers {
|
||||
vec2 {p}wColumn = {span}.xy;
|
||||
float {p}wBottom = {span}.z;
|
||||
float {p}wTop = {span}.w;
|
||||
vec2 {p}wLightmap = {params}.xy;
|
||||
float {p}wHash = {params}.z;
|
||||
bool {p}wSnow = {params}.w > 0.5;
|
||||
float {p}wLightV = floor({params}.x / 65536.0);
|
||||
vec2 {p}wLightmap = vec2({params}.x - {p}wLightV * 65536.0, {p}wLightV);
|
||||
bool {p}wProvider = {params}.w > 0.5;
|
||||
vec3 {p}wTranslate = {p}WeatherParams0.xyz;
|
||||
float {p}wInvRadius = {p}WeatherParams0.w;
|
||||
float {p}wInvRadius = {p}wProvider ? {p}WeatherParams3.x : {p}WeatherParams0.w;
|
||||
vec2 {p}wCameraFrac = {p}WeatherParams1.xy;
|
||||
float {p}wPartialTicks = {p}WeatherParams1.z;
|
||||
float {p}wAge = {p}WeatherParams1.w;
|
||||
float {p}wRainScroll = {p}WeatherParams2.x;
|
||||
float {p}wSnowScroll = {p}WeatherParams2.y;
|
||||
float {p}wStrength = {p}WeatherParams2.z;
|
||||
float {p}wAge = {p}wProvider ? {p}WeatherParams2.w : {p}WeatherParams1.w;
|
||||
float {p}wTick = {p}wProvider ? {p}WeatherParams2.y : {p}WeatherParams2.x;
|
||||
float {p}wStrength = {p}wProvider ? 1.0 : {p}WeatherParams2.z;
|
||||
|
||||
vec2 {p}wHalfWidth = vec2(-{p}wColumn.y, {p}wColumn.x) * (0.5 / sqrt(dot({p}wColumn, {p}wColumn)));
|
||||
vec2 {p}wCornerXZ = {p}wColumn + vec2(0.5) + ({corner}.x * 2.0 - 1.0) * {p}wHalfWidth;
|
||||
@@ -58,22 +57,13 @@ public final class InstancedGlslHelpers {
|
||||
|
||||
float {p}wDistance = length({p}wColumn + vec2(0.5) - {p}wCameraFrac) * {p}wInvRadius;
|
||||
float {p}wFade = 1.0 - {p}wDistance * {p}wDistance;
|
||||
float {p}wScroll;
|
||||
vec2 {p}wDrift;
|
||||
float {p}wAlpha;
|
||||
if ({p}wSnow) {
|
||||
{p}wScroll = ({p}wSnowScroll + {p}wPartialTicks) / 512.0;
|
||||
{p}wDrift = vec2({jitter}.x + {p}wAge * 0.01 * {jitter}.y, {jitter}.z + {p}wAge * {jitter}.w * 0.001);
|
||||
{p}wAlpha = {p}wFade * 0.3 + 0.5;
|
||||
} else {
|
||||
{p}wScroll = (mod({p}wRainScroll + {p}wHash, 32.0) + {p}wPartialTicks) / 32.0 * (3.0 + {jitter}.x);
|
||||
{p}wDrift = vec2(0.0);
|
||||
{p}wAlpha = {p}wFade * 0.5 + 0.5;
|
||||
}
|
||||
float {p}wScroll = (mod({p}wTick + {params}.y, {layer}.x) + {p}wPartialTicks) / {layer}.x * {params}.z;
|
||||
vec2 {p}wDrift = vec2({jitter}.x + {p}wAge * {layer}.y * {jitter}.y, {jitter}.z + {p}wAge * {layer}.z * {jitter}.w);
|
||||
float {p}wAlpha = {p}wFade * {layer}.w + 0.5;
|
||||
|
||||
{tex0} = vec4({corner}.x + {p}wDrift.x, {p}wCornerY * 0.25 + {p}wScroll + {p}wDrift.y, 0.0, 1.0);
|
||||
{tex1} = vec4({p}wLightmap, 0.0, 1.0);
|
||||
{color} = vec4(1.0, 1.0, 1.0, {p}wAlpha * {p}wStrength);""";
|
||||
{color} = floor(clamp(vec4({colorAttr}.rgb, {p}wAlpha * {colorAttr}.a * {p}wStrength), 0.0, 1.0) * 255.0) / 255.0;""";
|
||||
|
||||
public static String weatherPrologue(String uniformPrefix, String attribPrefix, String corner,
|
||||
String vertex, String color, String tex0, String tex1, String sep) {
|
||||
@@ -82,6 +72,8 @@ public final class InstancedGlslHelpers {
|
||||
.replace("{span}", attribPrefix + "InstColumnSpan")
|
||||
.replace("{jitter}", attribPrefix + "InstJitter")
|
||||
.replace("{params}", attribPrefix + "InstWeatherParams")
|
||||
.replace("{layer}", attribPrefix + "InstWeatherLayer")
|
||||
.replace("{colorAttr}", attribPrefix + "InstWeatherColor")
|
||||
.replace("{corner}", corner)
|
||||
.replace("{vertex}", vertex)
|
||||
.replace("{color}", color)
|
||||
@@ -125,6 +117,8 @@ public final class InstancedGlslHelpers {
|
||||
decls.add(decl(WeatherInstancedAttribs.LOC_COLUMN_SPAN, "vec4", prefix + "InstColumnSpan"));
|
||||
decls.add(decl(WeatherInstancedAttribs.LOC_JITTER, "vec4", prefix + "InstJitter"));
|
||||
decls.add(decl(WeatherInstancedAttribs.LOC_PARAMS, "vec4", prefix + "InstWeatherParams"));
|
||||
decls.add(decl(WeatherInstancedAttribs.LOC_COLOR, "vec4", prefix + "InstWeatherColor"));
|
||||
decls.add(decl(WeatherInstancedAttribs.LOC_LAYER, "vec4", prefix + "InstWeatherLayer"));
|
||||
}
|
||||
}
|
||||
return decls.toArray(String[]::new);
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.CompatShaderTransformer;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthPeel;
|
||||
import com.gtnewhorizons.angelica.glsm.GLDebug;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMPrograms;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
@@ -36,10 +35,6 @@ public class Program {
|
||||
@Getter private final FragmentKey fragmentKey;
|
||||
|
||||
public final int[] locSampler = { -1, -1, -1, -1 };
|
||||
public final int locPeelDepth;
|
||||
public final int locPeelScene;
|
||||
private final int locPeelMode;
|
||||
private int peelMode = -1;
|
||||
|
||||
Program(int programId, VertexKey vertexKey, FragmentKey fragmentKey) {
|
||||
this.programId = programId;
|
||||
@@ -48,19 +43,6 @@ public class Program {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
locSampler[i] = RENDER_BACKEND.getUniformLocation(programId, "u_Sampler" + i);
|
||||
}
|
||||
locPeelDepth = RENDER_BACKEND.getUniformLocation(programId, "u_PeelDepth");
|
||||
locPeelScene = RENDER_BACKEND.getUniformLocation(programId, "u_PeelScene");
|
||||
locPeelMode = RENDER_BACKEND.getUniformLocation(programId, "u_PeelMode");
|
||||
}
|
||||
|
||||
boolean peels() {
|
||||
return locPeelMode != -1;
|
||||
}
|
||||
|
||||
void syncPeelMode(int mode) {
|
||||
if (peelMode == mode) return;
|
||||
RENDER_BACKEND.uniform1i(locPeelMode, mode);
|
||||
peelMode = mode;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@@ -117,8 +99,6 @@ public class Program {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ffpProgram.locSampler[i] != -1) backend.uniform1i(ffpProgram.locSampler[i], i);
|
||||
}
|
||||
if (ffpProgram.locPeelDepth != -1) backend.uniform1i(ffpProgram.locPeelDepth, DepthPeel.TEXTURE_UNIT);
|
||||
if (ffpProgram.locPeelScene != -1) backend.uniform1i(ffpProgram.locPeelScene, DepthPeel.SCENE_TEXTURE_UNIT);
|
||||
if (previousProgram != 0) {
|
||||
backend.useProgram(previousProgram);
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFormat;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.CompatUniformManager;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthPeel;
|
||||
import com.gtnewhorizons.angelica.glsm.GLContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMCurrentAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
@@ -189,7 +188,6 @@ public final class ShaderManager {
|
||||
private void uploadUniforms(GLContextState glCtx) {
|
||||
if (currentProgram != null) {
|
||||
uniforms.upload(glCtx);
|
||||
if (currentProgram.peels()) currentProgram.syncPeelMode(DepthPeel.shaderMode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -391,8 +391,9 @@ public class Uniforms {
|
||||
WeatherParams.translateZ, WeatherParams.invRadius);
|
||||
putVec4(FFPUniformBlock.WEATHER_PARAMS_1, WeatherParams.cameraFracX, WeatherParams.cameraFracZ,
|
||||
WeatherParams.partialTicks, WeatherParams.age);
|
||||
putVec4(FFPUniformBlock.WEATHER_PARAMS_2, WeatherParams.rainScroll, WeatherParams.snowScroll,
|
||||
WeatherParams.rainStrength, 0.0f);
|
||||
putVec4(FFPUniformBlock.WEATHER_PARAMS_2, WeatherParams.vanillaTick, WeatherParams.providerTick,
|
||||
WeatherParams.rainStrength, WeatherParams.providerAge);
|
||||
putVec4(FFPUniformBlock.WEATHER_PARAMS_3, WeatherParams.providerInvRadius, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
private void putVec4(int offset, Vector4f v) {
|
||||
|
||||
+47
-2
@@ -3,31 +3,76 @@ package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMVertexInput;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* One rain or snow column per instance.
|
||||
* One weather column per instance.
|
||||
*/
|
||||
public final class WeatherInstancedAttribs {
|
||||
|
||||
public static final int LOC_COLUMN_SPAN = ParticleInstancedAttribs.LOC_CENTER_HALF;
|
||||
public static final int LOC_JITTER = ParticleInstancedAttribs.LOC_UV;
|
||||
public static final int LOC_PARAMS = InstancedAttribs.LOC_COLOR;
|
||||
public static final int LOC_COLOR = InstancedAttribs.LOC_ROW2;
|
||||
public static final int LOC_LAYER = InstancedAttribs.LOC_OVERLAY;
|
||||
|
||||
public static final int OFFSET_COLUMN_SPAN = 0;
|
||||
public static final int OFFSET_JITTER = 16;
|
||||
public static final int OFFSET_PARAMS = 32;
|
||||
public static final int STRIDE = 48;
|
||||
public static final int OFFSET_COLOR = 48;
|
||||
public static final int OFFSET_LAYER = 64;
|
||||
public static final int STRIDE = 80;
|
||||
|
||||
public static final int RAIN_PERIOD = 32;
|
||||
public static final float RAIN_SCROLL_BASE = 3.0F;
|
||||
public static final float RAIN_FADE = 0.5F;
|
||||
public static final int SNOW_PERIOD = 512;
|
||||
public static final float SNOW_U_DRIFT = 0.01F;
|
||||
public static final float SNOW_V_DRIFT = 0.001F;
|
||||
public static final float SNOW_FADE = 0.3F;
|
||||
public static final float SOURCE_VANILLA = 0.0F;
|
||||
public static final float SOURCE_PROVIDER = 1.0F;
|
||||
|
||||
public static void putColumn(ByteBuffer data, int index, float x, float z, float bottom, float top, float uBase, float uDrift,
|
||||
float vBase, float vDrift, float brightness, int scrollOffset, float scrollScale, float source, float r, float g, float b,
|
||||
float a, int period, float uDriftScale, float vDriftScale, float fadeScale) {
|
||||
final int base = index * STRIDE;
|
||||
data.putFloat(base + OFFSET_COLUMN_SPAN, x);
|
||||
data.putFloat(base + OFFSET_COLUMN_SPAN + 4, z);
|
||||
data.putFloat(base + OFFSET_COLUMN_SPAN + 8, bottom);
|
||||
data.putFloat(base + OFFSET_COLUMN_SPAN + 12, top);
|
||||
data.putFloat(base + OFFSET_JITTER, uBase);
|
||||
data.putFloat(base + OFFSET_JITTER + 4, uDrift);
|
||||
data.putFloat(base + OFFSET_JITTER + 8, vBase);
|
||||
data.putFloat(base + OFFSET_JITTER + 12, vDrift);
|
||||
data.putFloat(base + OFFSET_PARAMS, brightness);
|
||||
data.putFloat(base + OFFSET_PARAMS + 4, scrollOffset & (period - 1));
|
||||
data.putFloat(base + OFFSET_PARAMS + 8, scrollScale);
|
||||
data.putFloat(base + OFFSET_PARAMS + 12, source);
|
||||
data.putFloat(base + OFFSET_COLOR, r);
|
||||
data.putFloat(base + OFFSET_COLOR + 4, g);
|
||||
data.putFloat(base + OFFSET_COLOR + 8, b);
|
||||
data.putFloat(base + OFFSET_COLOR + 12, a);
|
||||
data.putFloat(base + OFFSET_LAYER, period);
|
||||
data.putFloat(base + OFFSET_LAYER + 4, uDriftScale);
|
||||
data.putFloat(base + OFFSET_LAYER + 8, vDriftScale);
|
||||
data.putFloat(base + OFFSET_LAYER + 12, fadeScale);
|
||||
}
|
||||
|
||||
public static void pointInstanceAttribs(long base) {
|
||||
GLSMVertexInput.glVertexAttribPointer(LOC_COLUMN_SPAN, 4, GL11.GL_FLOAT, false, STRIDE, base + OFFSET_COLUMN_SPAN);
|
||||
GLSMVertexInput.glVertexAttribPointer(LOC_JITTER, 4, GL11.GL_FLOAT, false, STRIDE, base + OFFSET_JITTER);
|
||||
GLSMVertexInput.glVertexAttribPointer(LOC_PARAMS, 4, GL11.GL_FLOAT, false, STRIDE, base + OFFSET_PARAMS);
|
||||
GLSMVertexInput.glVertexAttribPointer(LOC_COLOR, 4, GL11.GL_FLOAT, false, STRIDE, base + OFFSET_COLOR);
|
||||
GLSMVertexInput.glVertexAttribPointer(LOC_LAYER, 4, GL11.GL_FLOAT, false, STRIDE, base + OFFSET_LAYER);
|
||||
}
|
||||
|
||||
static void enableInstanceArrays() {
|
||||
InstancedAttribs.enableInstanced(LOC_COLUMN_SPAN);
|
||||
InstancedAttribs.enableInstanced(LOC_JITTER);
|
||||
InstancedAttribs.enableInstanced(LOC_PARAMS);
|
||||
InstancedAttribs.enableInstanced(LOC_COLOR);
|
||||
InstancedAttribs.enableInstanced(LOC_LAYER);
|
||||
}
|
||||
|
||||
private WeatherInstancedAttribs() {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
/**
|
||||
* The per-frame half of the rain and snow instancing, set once per weather draw.
|
||||
* The per-frame half of the weather column instancing, set once per frame.
|
||||
*/
|
||||
public final class WeatherParams {
|
||||
|
||||
@@ -15,9 +15,14 @@ public final class WeatherParams {
|
||||
public static float partialTicks;
|
||||
public static float age;
|
||||
|
||||
public static float rainScroll;
|
||||
public static float snowScroll;
|
||||
public static float vanillaTick;
|
||||
public static float providerTick;
|
||||
public static float rainStrength;
|
||||
public static float providerAge;
|
||||
|
||||
public static float providerInvRadius;
|
||||
|
||||
public static final int TICK_WRAP = 1024;
|
||||
|
||||
public static int generation;
|
||||
|
||||
@@ -25,7 +30,7 @@ public final class WeatherParams {
|
||||
|
||||
public static void set(float translateX, float translateY, float translateZ, float invRadius,
|
||||
float cameraFracX, float cameraFracZ, float partialTicks, float age,
|
||||
float rainScroll, float snowScroll, float rainStrength) {
|
||||
int vanillaTick, float rainStrength, int providerTick, float providerAge, float providerInvRadius) {
|
||||
WeatherParams.translateX = translateX;
|
||||
WeatherParams.translateY = translateY;
|
||||
WeatherParams.translateZ = translateZ;
|
||||
@@ -34,9 +39,11 @@ public final class WeatherParams {
|
||||
WeatherParams.cameraFracZ = cameraFracZ;
|
||||
WeatherParams.partialTicks = partialTicks;
|
||||
WeatherParams.age = age;
|
||||
WeatherParams.rainScroll = rainScroll;
|
||||
WeatherParams.snowScroll = snowScroll;
|
||||
WeatherParams.vanillaTick = vanillaTick & (TICK_WRAP - 1);
|
||||
WeatherParams.providerTick = providerTick & (TICK_WRAP - 1);
|
||||
WeatherParams.rainStrength = rainStrength;
|
||||
WeatherParams.providerAge = providerAge;
|
||||
WeatherParams.providerInvRadius = providerInvRadius;
|
||||
generation++;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* The four corners every rain and snow column is expanded from. x picks the end of the billboard, y picks
|
||||
* The four corners every weather column is expanded from. x picks the end of the billboard, y picks
|
||||
* the bottom or top edge.
|
||||
*/
|
||||
public final class WeatherQuadMesh {
|
||||
@@ -49,14 +49,6 @@ public final class WeatherQuadMesh {
|
||||
return vao;
|
||||
}
|
||||
|
||||
public static void bindInstanceBuffer(int bufferId) {
|
||||
GLSMVertexInput.glBindVertexArray(vao());
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
WeatherInstancedAttribs.pointInstanceAttribs(0L);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
public static void delete() {
|
||||
if (vbo != 0) {
|
||||
GLSMBuffers.glDeleteBuffers(vbo);
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.gtnewhorizons.angelica.glsm.recording.CommandRecorder;
|
||||
/** Drains deferred geometry before changing state that is not stored with each batch. */
|
||||
public final class BatchStateGuard {
|
||||
public static Runnable flush;
|
||||
public static Runnable drawFlush;
|
||||
private static int suspended;
|
||||
|
||||
private BatchStateGuard() {}
|
||||
@@ -17,20 +16,12 @@ public final class BatchStateGuard {
|
||||
public static boolean isSuspended() { return suspended != 0; }
|
||||
|
||||
public static void beforeChange() {
|
||||
run(flush);
|
||||
}
|
||||
|
||||
public static void beforeDraw() {
|
||||
run(drawFlush);
|
||||
}
|
||||
|
||||
private static void run(Runnable action) {
|
||||
if (action == null || suspended != 0 || !GLStateManager.isMainThread()
|
||||
if (flush == null || suspended != 0 || !GLStateManager.isMainThread()
|
||||
|| DisplayListManager.getRecordMode() == DisplayListManager.RecordMode.COMPILE) return;
|
||||
final CommandRecorder recorder = DisplayListManager.isRecording() ? DisplayListManager.pauseRecording() : null;
|
||||
suspend();
|
||||
try {
|
||||
action.run();
|
||||
flush.run();
|
||||
} finally {
|
||||
resume();
|
||||
if (recorder != null) DisplayListManager.resumeRecording(recorder);
|
||||
|
||||
@@ -15,8 +15,6 @@ public final class GLSMConfig {
|
||||
}
|
||||
|
||||
public static boolean hudCacheOverride;
|
||||
public static boolean layerBlending;
|
||||
public static boolean depthPeel;
|
||||
|
||||
public static boolean extendedAttribsExpected;
|
||||
public static volatile boolean expandVertexFormats;
|
||||
|
||||
@@ -12,8 +12,7 @@ final class GLSMOwners {
|
||||
"getColorLogicOpState", "getColorMask", "getEffectiveBlendState", "getEffectiveColorMask",
|
||||
"getIndexLogicOpState", "getLogicOpMode", "glBlendColor", "glBlendEquation", "glBlendEquationSeparate",
|
||||
"glBlendFunc", "glBlendFuncSeparate", "glBlendFuncSeparatei", "glClearColor", "glColorMask", "glLogicOp",
|
||||
"isEffectiveBlendEnabled", "isLayerBlending", "setHudCacheOverride", "setLayerBlending",
|
||||
"tryBlendFuncSeparate"},
|
||||
"isEffectiveBlendEnabled", "setHudCacheOverride", "tryBlendFuncSeparate"},
|
||||
{"com/gtnewhorizons/angelica/glsm/GLSMBuffers",
|
||||
"getBoundCopyReadBuffer", "getBoundCopyWriteBuffer", "getBoundVBO", "getIndexedBufferBinding",
|
||||
"glBindBuffer", "glBindBufferBase", "glBindBufferRange", "glBufferData", "glBufferStorage",
|
||||
|
||||
@@ -53,7 +53,4 @@ void main() {
|
||||
#if GLINT_REPLACE_ALPHA
|
||||
fragColor.a = visible1 ? b.a : a.a;
|
||||
#endif
|
||||
#ifdef DEPTH_PEEL
|
||||
peelTest(fragColor);
|
||||
#endif
|
||||
}
|
||||
-119
@@ -1,119 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.DeferredBlendHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@GLCoreTest
|
||||
public class GLSM_BlendAlphaOverride_GLTest {
|
||||
|
||||
private static void assertDriverFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
assertEquals(srcRgb, GL11.glGetInteger(GL14.GL_BLEND_SRC_RGB));
|
||||
assertEquals(dstRgb, GL11.glGetInteger(GL14.GL_BLEND_DST_RGB));
|
||||
assertEquals(srcAlpha, GL11.glGetInteger(GL14.GL_BLEND_SRC_ALPHA));
|
||||
assertEquals(dstAlpha, GL11.glGetInteger(GL14.GL_BLEND_DST_ALPHA));
|
||||
}
|
||||
|
||||
private static void assertCachedFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
assertEquals(srcRgb, GLSMQueries.glGetInteger(GL14.GL_BLEND_SRC_RGB));
|
||||
assertEquals(dstRgb, GLSMQueries.glGetInteger(GL14.GL_BLEND_DST_RGB));
|
||||
assertEquals(srcAlpha, GLSMQueries.glGetInteger(GL14.GL_BLEND_SRC_ALPHA));
|
||||
assertEquals(dstAlpha, GLSMQueries.glGetInteger(GL14.GL_BLEND_DST_ALPHA));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void resetOverrides() {
|
||||
GLSMHooks.blendHandler = null;
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
GLSMBlend.setLayerBlending(false);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideChangesTheDriverFuncButNotTheCache() {
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertCachedFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
assertCachedFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void popUnderOverrideKeepsTheOverriddenAlphaOnTheDriver() {
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
final int d = GLSMAttribStack.pushState(StateSet.BLEND);
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
GLSMBlend.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
|
||||
GLSMAttribStack.popStateTo(d);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
void separateAlphaIsForcedEvenWhenDstAlphaAlreadyMatches() {
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
static Stream<Arguments> layerBlendRows() {
|
||||
return Stream.of(
|
||||
Arguments.of("translucent over", GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA),
|
||||
Arguments.of("alpha additive", GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE));
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource("layerBlendRows")
|
||||
void layerBlendingAccumulatesCoverageAndKeepsAdditiveCoverageFree(String name, int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
GLSMBlend.setLayerBlending(true);
|
||||
GLSMBlend.glBlendFunc(srcRgb, dstRgb);
|
||||
assertCachedFunc(srcRgb, dstRgb, srcRgb, dstRgb);
|
||||
assertDriverFunc(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
GLSMBlend.setLayerBlending(false);
|
||||
assertDriverFunc(srcRgb, dstRgb, srcRgb, dstRgb);
|
||||
}
|
||||
|
||||
@Test
|
||||
void togglingWhileABlendOverrideIsHeldReemitsOnTheNextUnchangedFunc() {
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLSMHooks.blendHandler = new HeldOverride();
|
||||
GLSMBlend.setLayerBlending(true);
|
||||
GLSMHooks.blendHandler = null;
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
private static final class HeldOverride implements DeferredBlendHandler {
|
||||
@Override public boolean isBlendLocked() { return false; }
|
||||
@Override public boolean isOverrideHeld() { return true; }
|
||||
@Override public void deferBlendModeToggle(boolean enabled) {}
|
||||
@Override public void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {}
|
||||
@Override public void flushDeferredBlend() {}
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@GLCoreTest
|
||||
public class GLSM_HudCacheBlendOverride_GLTest {
|
||||
|
||||
private static void assertDriverFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
assertEquals(srcRgb, GL11.glGetInteger(GL14.GL_BLEND_SRC_RGB));
|
||||
assertEquals(dstRgb, GL11.glGetInteger(GL14.GL_BLEND_DST_RGB));
|
||||
assertEquals(srcAlpha, GL11.glGetInteger(GL14.GL_BLEND_SRC_ALPHA));
|
||||
assertEquals(dstAlpha, GL11.glGetInteger(GL14.GL_BLEND_DST_ALPHA));
|
||||
}
|
||||
|
||||
private static void assertCachedFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
assertEquals(srcRgb, GLSMQueries.glGetInteger(GL14.GL_BLEND_SRC_RGB));
|
||||
assertEquals(dstRgb, GLSMQueries.glGetInteger(GL14.GL_BLEND_DST_RGB));
|
||||
assertEquals(srcAlpha, GLSMQueries.glGetInteger(GL14.GL_BLEND_SRC_ALPHA));
|
||||
assertEquals(dstAlpha, GLSMQueries.glGetInteger(GL14.GL_BLEND_DST_ALPHA));
|
||||
}
|
||||
|
||||
@Test
|
||||
void overrideChangesTheDriverFuncButNotTheCache() {
|
||||
try {
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_SRC_ALPHA, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertCachedFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
assertCachedFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
assertDriverFunc(GL11.GL_DST_COLOR, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
} finally {
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void popUnderOverrideKeepsTheOverriddenAlphaOnTheDriver() {
|
||||
try {
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
final int d = GLSMAttribStack.pushState(StateSet.BLEND);
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
GLSMBlend.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
|
||||
GLSMAttribStack.popStateTo(d);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
} finally {
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void separateAlphaIsForcedEvenWhenDstAlphaAlreadyMatches() {
|
||||
try {
|
||||
GLSMBlend.setHudCacheOverride(true);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
assertCachedFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
assertDriverFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
} finally {
|
||||
GLSMBlend.setHudCacheOverride(false);
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,33 +167,6 @@ public class GLSM_StateSet_GLTest {
|
||||
|| GLSMBlend.getColorMask().blue || GLSMBlend.getColorMask().alpha, "cache color mask - not a HAND member, must stay toggled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blockEntityPassRestoresColorFogAndShadeModelOnTopOfBatchButNotStencil() {
|
||||
GLSMCurrentAttribs.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
GLSMFog.disableFog();
|
||||
GLSMFog.glFogf(GL11.GL_FOG_END, 64.0f);
|
||||
GLSMRasterizer.glShadeModel(GL11.GL_SMOOTH);
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
GLSMEnable.glDisable(GL11.GL_STENCIL_TEST);
|
||||
|
||||
final int d = GLSMAttribStack.pushState(StateSet.BLOCK_ENTITY_PASS);
|
||||
GLSMCurrentAttribs.glColor4f(0.2f, 0.4f, 0.6f, 0.8f);
|
||||
GLSMFog.enableFog();
|
||||
GLSMFog.glFogf(GL11.GL_FOG_END, 8.0f);
|
||||
GLSMRasterizer.glShadeModel(GL11.GL_FLAT);
|
||||
GLSMDepthStencilAlpha.glDepthMask(false);
|
||||
GLSMEnable.glEnable(GL11.GL_STENCIL_TEST);
|
||||
GLSMAttribStack.popStateTo(d);
|
||||
|
||||
assertEquals(1.0f, GLSMCurrentAttribs.getColor().getRed(), "cache color red");
|
||||
assertEquals(1.0f, GLSMCurrentAttribs.getColor().getAlpha(), "cache color alpha");
|
||||
assertFalse(GLSMFog.getFogMode().isEnabled(), "fog enable restored by BLOCK_ENTITY_PASS pop");
|
||||
assertEquals(64.0f, GLSMFog.getFogState().getEnd(), "cache fog end");
|
||||
assertEquals(GL11.GL_SMOOTH, GLSMRasterizer.getShadeModelState().getValue(), "cache shade model");
|
||||
assertTrue(GLSMDepthStencilAlpha.getDepthState().isEnabled(), "depth mask restored, as in BATCH");
|
||||
verifyIsEnabled(GL11.GL_STENCIL_TEST, true, "Stencil test - not a BLOCK_ENTITY_PASS member, must stay toggled");
|
||||
}
|
||||
|
||||
@Test
|
||||
void masksRestoresDepthMaskAndColorMaskButNotDepthTestEnable() {
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
|
||||
@@ -100,6 +100,7 @@ class InstancedFFPDrawGLTest {
|
||||
CubeParityFixture.disableDirectionalLight();
|
||||
CubeParityFixture.deleteResources();
|
||||
ParticleParityFixture.deleteResources();
|
||||
WeatherParityFixture.deleteResources();
|
||||
if (templateVbo != 0) { GLSMBuffers.glDeleteBuffers(templateVbo); templateVbo = 0; }
|
||||
if (instanceVbo != 0) { GLSMBuffers.glDeleteBuffers(instanceVbo); instanceVbo = 0; }
|
||||
if (vao != 0) { GLSMVertexInput.glDeleteVertexArrays(vao); vao = 0; }
|
||||
@@ -196,6 +197,27 @@ class InstancedFFPDrawGLTest {
|
||||
ParticleParityFixture.assertPixelParity(reference, instanced, PARITY_SIZE, 0xFF000000, pixel -> "0x" + Integer.toHexString(pixel));
|
||||
}
|
||||
|
||||
@Test
|
||||
void weatherColumnsMatchTessellatedReference() {
|
||||
GLSMRasterizer.glViewport(0, 0, PARITY_SIZE, PARITY_SIZE);
|
||||
WeatherParityFixture.setupScene();
|
||||
|
||||
FfpFixture.activateFfp();
|
||||
|
||||
final WeatherParityFixture.Spec[] specs = WeatherParityFixture.specs();
|
||||
|
||||
FfpFixture.clear();
|
||||
WeatherParityFixture.drawReference(specs);
|
||||
final int[] reference = FfpFixture.readRegion(PARITY_SIZE);
|
||||
|
||||
FfpFixture.clear();
|
||||
WeatherParityFixture.drawInstanced(specs);
|
||||
final int[] instanced = FfpFixture.readRegion(PARITY_SIZE);
|
||||
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "parity draws must not raise a GL error");
|
||||
WeatherParityFixture.assertPixelParity(reference, instanced, PARITY_SIZE, 0xFF000000, pixel -> "0x" + Integer.toHexString(pixel));
|
||||
}
|
||||
|
||||
@Test
|
||||
void entityAttribSelectsColorPerInstance() {
|
||||
GLSMRasterizer.glViewport(0, 0, INTEGER_WIDTH, INTEGER_HEIGHT);
|
||||
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.VertexFlags;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBuffers;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDraws;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMEnable;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMMatrices;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMPrograms;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMVertexInput;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
public final class WeatherParityFixture {
|
||||
|
||||
public record Spec(float x, float z, float bottom, float top, float uBase, float uDrift, float vBase, float vDrift,
|
||||
int brightness, int scrollOffset, float scrollScale, float source,
|
||||
float r, float g, float b, float a, int period, float uDriftScale, float vDriftScale, float fadeScale) {}
|
||||
|
||||
private static final int TICK = 2650;
|
||||
private static final float PARTIAL_TICKS = 0.375f;
|
||||
private static final float TRANSLATE_X = 0.37f;
|
||||
private static final float TRANSLATE_Y = -62.25f;
|
||||
private static final float TRANSLATE_Z = -0.61f;
|
||||
private static final float INV_RADIUS = 1.0f / 6.0f;
|
||||
private static final float CAMERA_FRAC_X = 0.3f;
|
||||
private static final float CAMERA_FRAC_Z = 0.7f;
|
||||
private static final float STRENGTH = 0.8f;
|
||||
private static final int PROVIDER_TICK = 1777;
|
||||
private static final float PROVIDER_INV_RADIUS = 1.0f / 9.0f;
|
||||
|
||||
private static final float[] CORNER_X = { 0.0f, 1.0f, 1.0f, 0.0f };
|
||||
private static final float[] CORNER_Y = { 0.0f, 0.0f, 1.0f, 1.0f };
|
||||
|
||||
private static final int REF_STRIDE = 44;
|
||||
|
||||
private static int referenceVao;
|
||||
private static int referenceVbo;
|
||||
private static int instanceVbo;
|
||||
private static int weatherTexture;
|
||||
private static int lightmapTexture;
|
||||
|
||||
private WeatherParityFixture() {}
|
||||
|
||||
private static Spec rain(float x, float z, float bottom, float top, float j0, int hash, int brightness) {
|
||||
return new Spec(x, z, bottom, top, 0f, 0f, 0f, 0f, brightness, hash, WeatherInstancedAttribs.RAIN_SCROLL_BASE + j0, WeatherInstancedAttribs.SOURCE_VANILLA,
|
||||
1f, 1f, 1f, 1f, WeatherInstancedAttribs.RAIN_PERIOD, 0f, 0f, WeatherInstancedAttribs.RAIN_FADE);
|
||||
}
|
||||
|
||||
private static Spec snow(float x, float z, float bottom, float top, float j0, float j1, float j2, float j3, int brightness) {
|
||||
return new Spec(x, z, bottom, top, j0, j1, j2, j3, brightness, 0, 1f, WeatherInstancedAttribs.SOURCE_VANILLA,
|
||||
1f, 1f, 1f, 1f, WeatherInstancedAttribs.SNOW_PERIOD, WeatherInstancedAttribs.SNOW_U_DRIFT, WeatherInstancedAttribs.SNOW_V_DRIFT,
|
||||
WeatherInstancedAttribs.SNOW_FADE);
|
||||
}
|
||||
|
||||
private static Spec provider(float x, float z, float bottom, float top, float uBase, float uDrift, float vBase, float vDrift,
|
||||
int brightness, int scrollOffset, float scrollScale, float r, float g, float b, float a,
|
||||
int period, float uDriftScale, float vDriftScale, float fadeScale) {
|
||||
return new Spec(x, z, bottom, top, uBase, uDrift, vBase, vDrift, brightness, scrollOffset, scrollScale, WeatherInstancedAttribs.SOURCE_PROVIDER, r, g, b, a,
|
||||
period, uDriftScale, vDriftScale, fadeScale);
|
||||
}
|
||||
|
||||
public static Spec[] specs() {
|
||||
return new Spec[] {
|
||||
rain(-4f, -3f, 58f, 66f, 0.31f, 5, 0x00F00030),
|
||||
rain(2f, -4f, 60f, 67f, 0.77f, 19, 0x00A000D0),
|
||||
rain(-2f, 3f, 57f, 65f, 0.05f, 62, 0x0060F0A0),
|
||||
rain(4f, 2f, 59f, 64f, 0.58f, 11, 0x00D01090),
|
||||
rain(1f, 4f, 56f, 66f, 0.93f, 24, 0x0080C0F0),
|
||||
snow(-5f, 1f, 58f, 66f, 0.12f, 0.47f, 0.83f, 0.29f, 0x00E02070),
|
||||
snow(3f, -2f, 60f, 68f, 0.66f, 0.91f, 0.18f, 0.74f, 0x00B0B0B0),
|
||||
snow(-1f, -5f, 57f, 63f, 0.39f, 0.25f, 0.52f, 0.96f, 0x0040E0C0),
|
||||
snow(5f, 4f, 59f, 67f, 0.84f, 0.63f, 0.07f, 0.41f, 0x00F0F0F0),
|
||||
snow(-3f, 5f, 55f, 65f, 0.22f, 0.78f, 0.35f, 0.58f, 0x00109050),
|
||||
provider(-5f, -4f, 58f, 66f, 0.14f, 0.52f, 0.71f, 0.33f, 0x00C06040, 0, 1f, 1f, 1f, 1f, 1f, 512, 0.03f, 0.001f, 0.3f),
|
||||
provider(4f, -3f, 59f, 67f, 0.61f, 0.27f, 0.09f, 0.88f, 0x00F020B0, 0, 1f, 1f, 1f, 1f, 1f, 512, 0.03f, 0.001f, 0.3f),
|
||||
provider(-4f, 2f, 57f, 65f, 0.42f, 0.36f, 0.64f, 0.19f, 0x0090D070, 0, 0f, 0.12f, 0.27f, 0.18f, 2.0f, 512, 0.03f, 0.003f, 0f),
|
||||
provider(2f, 5f, 60f, 66f, 0.83f, 0.74f, 0.25f, 0.57f, 0x0050A0E0, 0, 0f, 0.29f, 0.14f, 0.21f, 2.0f, 512, 0.03f, 0.003f, 0f),
|
||||
provider(-2f, -5f, 56f, 64f, 0.07f, 0.45f, 0.93f, 0.62f, 0x00B0F040, 0, -1f, 0.83f, 0.92f, 0.88f, 1f, 1024, 0.001f, 0.001f, 0.3f),
|
||||
provider(5f, 1f, 58f, 68f, 0.55f, 0.16f, 0.38f, 0.81f, 0x007070F0, 0, -1f, 0.97f, 0.86f, 0.81f, 1f, 1024, 0.001f, 0.001f, 0.3f),
|
||||
provider(-5f, 4f, 59f, 66f, 0f, 0.68f, 0f, 0.23f, 0x00E0E050, 0, -1f, 1f, 1f, 1f, 0.35f, 512, 0f, 0.01f, 0.3f),
|
||||
provider(3f, 3f, 57f, 67f, 0f, 0.49f, 0f, 0.91f, 0x0030C0A0, 0, -1f, 1f, 1f, 1f, 0.82f, 512, 0f, 0.01f, 0.3f),
|
||||
provider(0f, -4f, 58f, 65f, 0.26f, 0.12f, 0.67f, 0.44f, 0x00A0A0A0, 21, 3.46f, 1f, 1f, 1f, 1f, 32, 0f, 0f, 0.3f),
|
||||
provider(1f, 3f, 60f, 66f, 0.89f, 0.31f, 0.15f, 0.76f, 0x00F0A040, 7, 3.81f, 1f, 1f, 1f, 1f, 32, 0f, 0f, 0.3f),
|
||||
provider(-3f, 0f, 56f, 67f, 0.33f, 0.85f, 0.48f, 0.13f, 0x00D0D0D0, 0, 1f, 1f, 1f, 1f, 0.24f, 512, 0.01f, 0.01f, 0.3f),
|
||||
provider(0f, 5f, 58f, 64f, 0.72f, 0.04f, 0.59f, 0.97f, 0x0010F0F0, 0, 1f, 1f, 1f, 1f, 0.67f, 512, 0.01f, 0.01f, 0.3f),
|
||||
};
|
||||
}
|
||||
|
||||
private static float mod(float x, float y) {
|
||||
return x - y * (float) Math.floor(x / y);
|
||||
}
|
||||
|
||||
public static void setupScene() {
|
||||
GLSMEnable.glDisable(GL11.GL_FOG);
|
||||
GLSMEnable.glDisable(GL11.GL_ALPHA_TEST);
|
||||
GLSMEnable.glDisable(GL11.GL_DEPTH_TEST);
|
||||
GLSMEnable.glDisable(GL11.GL_CULL_FACE);
|
||||
GLSMEnable.glDisable(GL11.GL_LIGHTING);
|
||||
GLSMEnable.glEnable(GL11.GL_BLEND);
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_PROJECTION);
|
||||
GLSMMatrices.glLoadIdentity();
|
||||
GLSMMatrices.glOrtho(-8.0, 8.0, -8.0, 8.0, -64.0, 64.0);
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLSMMatrices.glLoadIdentity();
|
||||
GLSMMatrices.glRotatef(30.0f, 1.0f, 0.0f, 0.0f);
|
||||
GLSMMatrices.glRotatef(35.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
lightmapTexture = createTexture(GL13.GL_TEXTURE1, 16, GL11.GL_LINEAR, GL11.GL_CLAMP);
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_TEXTURE);
|
||||
GLSMMatrices.glLoadIdentity();
|
||||
GLSMMatrices.glScalef(0.00390625f, 0.00390625f, 0.00390625f);
|
||||
GLSMMatrices.glTranslatef(8.0f, 8.0f, 8.0f);
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
|
||||
weatherTexture = createTexture(GL13.GL_TEXTURE0, 4, GL11.GL_NEAREST, GL11.GL_REPEAT);
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_TEXTURE);
|
||||
GLSMMatrices.glLoadIdentity();
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
}
|
||||
|
||||
private static int createTexture(int unit, int size, int filter, int wrap) {
|
||||
final int id = GLSMTextures.glGenTextures();
|
||||
GLSMTextures.glActiveTexture(unit);
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, id);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap);
|
||||
final ByteBuffer texels = BufferUtils.createByteBuffer(size * size * 4);
|
||||
for (int y = 0; y < size; y++) {
|
||||
for (int x = 0; x < size; x++) {
|
||||
texels.put((byte) (40 + x * (200 / size)));
|
||||
texels.put((byte) (40 + y * (200 / size)));
|
||||
texels.put((byte) (255 - (x + y) * (100 / size)));
|
||||
texels.put((byte) 255);
|
||||
}
|
||||
}
|
||||
texels.flip();
|
||||
GLSMTextures.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, size, size, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, texels);
|
||||
GLSMEnable.glEnable(GL11.GL_TEXTURE_2D);
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void putVertex(ByteBuffer data, float px, float py, float pz, float r, float g, float b, float a,
|
||||
float u, float v, float lmX, float lmY) {
|
||||
final int base = data.position();
|
||||
data.putFloat(base, px);
|
||||
data.putFloat(base + 4, py);
|
||||
data.putFloat(base + 8, pz);
|
||||
data.putFloat(base + 12, r);
|
||||
data.putFloat(base + 16, g);
|
||||
data.putFloat(base + 20, b);
|
||||
data.putFloat(base + 24, a);
|
||||
data.putFloat(base + 28, u);
|
||||
data.putFloat(base + 32, v);
|
||||
data.putFloat(base + 36, lmX);
|
||||
data.putFloat(base + 40, lmY);
|
||||
data.position(base + REF_STRIDE);
|
||||
}
|
||||
|
||||
private static float tessellatorByte(float channel) {
|
||||
final int value = (int) (channel * 255.0F);
|
||||
return Math.max(0, Math.min(255, value)) / 255.0f;
|
||||
}
|
||||
|
||||
private static void addColumn(ByteBuffer data, Spec s) {
|
||||
final boolean provider = s.source() == WeatherInstancedAttribs.SOURCE_PROVIDER;
|
||||
final int tick = provider ? PROVIDER_TICK : TICK;
|
||||
final float age = tick + PARTIAL_TICKS;
|
||||
final float invRadius = provider ? PROVIDER_INV_RADIUS : INV_RADIUS;
|
||||
final float strength = provider ? 1.0f : STRENGTH;
|
||||
|
||||
final float halfScale = 0.5f / (float) Math.sqrt(s.x() * s.x() + s.z() * s.z());
|
||||
final float halfX = -s.z() * halfScale;
|
||||
final float halfZ = s.x() * halfScale;
|
||||
|
||||
final float dx = s.x() + 0.5f - CAMERA_FRAC_X;
|
||||
final float dz = s.z() + 0.5f - CAMERA_FRAC_Z;
|
||||
final float distance = (float) Math.sqrt(dx * dx + dz * dz) * invRadius;
|
||||
final float fade = 1.0f - distance * distance;
|
||||
|
||||
final float scroll = (mod((float) tick + s.scrollOffset(), s.period()) + PARTIAL_TICKS) / s.period() * s.scrollScale();
|
||||
final float driftU = s.uBase() + age * s.uDriftScale() * s.uDrift();
|
||||
final float driftV = s.vBase() + age * s.vDriftScale() * s.vDrift();
|
||||
final float alpha = fade * s.fadeScale() + 0.5f;
|
||||
|
||||
final float r = tessellatorByte(s.r());
|
||||
final float g = tessellatorByte(s.g());
|
||||
final float b = tessellatorByte(s.b());
|
||||
final float a = tessellatorByte(alpha * s.a() * strength);
|
||||
final float lmX = s.brightness() & 0xFFFF;
|
||||
final float lmY = s.brightness() >> 16 & 0xFFFF;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
final float side = CORNER_X[i] * 2.0f - 1.0f;
|
||||
final float cornerX = s.x() + 0.5f + side * halfX;
|
||||
final float cornerZ = s.z() + 0.5f + side * halfZ;
|
||||
final float cornerY = s.bottom() * (1.0f - CORNER_Y[i]) + s.top() * CORNER_Y[i];
|
||||
putVertex(data, cornerX + TRANSLATE_X, cornerY + TRANSLATE_Y, cornerZ + TRANSLATE_Z, r, g, b, a,
|
||||
CORNER_X[i] + driftU, cornerY * 0.25f + scroll + driftV, lmX, lmY);
|
||||
}
|
||||
}
|
||||
|
||||
private static ByteBuffer buildReferenceData(Spec[] specs) {
|
||||
final ByteBuffer data = BufferUtils.createByteBuffer(specs.length * 4 * REF_STRIDE);
|
||||
for (Spec s : specs) {
|
||||
addColumn(data, s);
|
||||
}
|
||||
data.flip();
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void drawReference(Spec[] specs) {
|
||||
final ByteBuffer data = buildReferenceData(specs);
|
||||
if (referenceVao == 0) referenceVao = GLSMVertexInput.glGenVertexArrays();
|
||||
GLSMVertexInput.glBindVertexArray(referenceVao);
|
||||
if (referenceVbo == 0) referenceVbo = GLSMBuffers.glGenBuffers();
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, referenceVbo);
|
||||
GLSMBuffers.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
FfpFixture.attrib(0, 3, GL11.GL_FLOAT, false, REF_STRIDE, 0);
|
||||
FfpFixture.attrib(1, 4, GL11.GL_FLOAT, false, REF_STRIDE, 12);
|
||||
FfpFixture.attrib(2, 2, GL11.GL_FLOAT, false, REF_STRIDE, 28);
|
||||
FfpFixture.attrib(3, 2, GL11.GL_FLOAT, false, REF_STRIDE, 36);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
VAOManager.setCurrentVertexFlags(VertexFlags.COLOR_BIT | VertexFlags.TEXTURE_BIT | VertexFlags.BRIGHTNESS_BIT);
|
||||
|
||||
GLSMDraws.glDrawArrays(GL11.GL_QUADS, 0, specs.length * 4);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
public static void drawInstanced(Spec[] specs) {
|
||||
final ByteBuffer records = BufferUtils.createByteBuffer(specs.length * WeatherInstancedAttribs.STRIDE);
|
||||
for (int i = 0; i < specs.length; i++) {
|
||||
final Spec s = specs[i];
|
||||
WeatherInstancedAttribs.putColumn(records, i, s.x(), s.z(), s.bottom(), s.top(), s.uBase(), s.uDrift(), s.vBase(), s.vDrift(),
|
||||
s.brightness(), s.scrollOffset(), s.scrollScale(), s.source(), s.r(), s.g(), s.b(), s.a(),
|
||||
s.period(), s.uDriftScale(), s.vDriftScale(), s.fadeScale());
|
||||
}
|
||||
|
||||
WeatherParams.set(TRANSLATE_X, TRANSLATE_Y, TRANSLATE_Z, INV_RADIUS, CAMERA_FRAC_X, CAMERA_FRAC_Z,
|
||||
PARTIAL_TICKS, TICK + PARTIAL_TICKS, TICK, STRENGTH, PROVIDER_TICK, PROVIDER_TICK + PARTIAL_TICKS, PROVIDER_INV_RADIUS);
|
||||
|
||||
GLSMVertexInput.glBindVertexArray(WeatherQuadMesh.vao());
|
||||
if (instanceVbo == 0) instanceVbo = GLSMBuffers.glGenBuffers();
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceVbo);
|
||||
GLSMBuffers.glBufferData(GL15.GL_ARRAY_BUFFER, records, GL15.GL_STREAM_DRAW);
|
||||
WeatherInstancedAttribs.pointInstanceAttribs(0L);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
VAOManager.setCurrentVertexFlags(WeatherQuadMesh.VERTEX_FLAGS);
|
||||
GLSMPrograms.setFfpInstancing(Instancing.WEATHER);
|
||||
GLSMDraws.glDrawArraysInstanced(GL11.GL_TRIANGLE_FAN, 0, WeatherQuadMesh.VERTEX_COUNT, specs.length);
|
||||
GLSMPrograms.setFfpInstancing(Instancing.NONE);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
public static void assertPixelParity(int[] reference, int[] instanced, int size, int background, IntFunction<String> describe) {
|
||||
FfpFixture.assertPixelParity("instanced weather columns", reference, instanced, size, background, 16, 0, describe);
|
||||
}
|
||||
|
||||
public static void deleteResources() {
|
||||
if (instanceVbo != 0) {
|
||||
GLSMBuffers.glDeleteBuffers(instanceVbo);
|
||||
instanceVbo = 0;
|
||||
}
|
||||
if (referenceVbo != 0) {
|
||||
GLSMBuffers.glDeleteBuffers(referenceVbo);
|
||||
referenceVbo = 0;
|
||||
}
|
||||
if (referenceVao != 0) {
|
||||
GLSMVertexInput.glDeleteVertexArrays(referenceVao);
|
||||
referenceVao = 0;
|
||||
}
|
||||
if (weatherTexture != 0) {
|
||||
GLSMTextures.glDeleteTextures(weatherTexture);
|
||||
weatherTexture = 0;
|
||||
}
|
||||
if (lightmapTexture != 0) {
|
||||
GLSMTextures.glDeleteTextures(lightmapTexture);
|
||||
lightmapTexture = 0;
|
||||
}
|
||||
WeatherQuadMesh.delete();
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -493,42 +493,42 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawArrays(int mode, int first, int count) {
|
||||
public void drawArrays(int mode, int first, int count) {
|
||||
GL11C.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, int count, int type, long indices) {
|
||||
public void drawElements(int mode, int count, int type, long indices) {
|
||||
GL11C.glDrawElements(mode, count, type, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, ByteBuffer indices) {
|
||||
public void drawElements(int mode, ByteBuffer indices) {
|
||||
GL11C.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, IntBuffer indices) {
|
||||
public void drawElements(int mode, IntBuffer indices) {
|
||||
GL11C.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, ShortBuffer indices) {
|
||||
public void drawElements(int mode, ShortBuffer indices) {
|
||||
GL11C.glDrawElements(mode, indices);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
public void drawElements(int mode, int count, int type, ByteBuffer indices) {
|
||||
GL11C.glDrawElements(mode, count, type, MemoryUtil.memAddress(indices));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
public void drawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
GL31C.glDrawElementsInstanced(mode, count, type, indices, primcount);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
public void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
GL31C.glDrawArraysInstanced(mode, first, count, primcount);
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
public void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
GL43C.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
@@ -549,12 +549,12 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
public void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
GL32C.glDrawElementsBaseVertex(mode, count, type, indices, baseVertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
public void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
GL32C.nglMultiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex);
|
||||
}
|
||||
|
||||
@@ -1884,7 +1884,7 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
public void multiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
GL14C.glMultiDrawArrays(mode, firsts, counts);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
# extra - passed through to gradle; -Dangelica.* reaches the client (e.g. -Dangelica.flyby.timeOfDay=1500).
|
||||
# -Dangelica.flyby.camera=FIRST_PERSON|THIRD_PERSON_BACK|THIRD_PERSON_FRONT (default FIRST_PERSON).
|
||||
# -Dangelica.flyby.dimension=<id> moves the player there first (1 = End), after world saving is off.
|
||||
# -Dangelica.flyby.biome=<name> pins the origin to the 44x44-block area of that biome nearest to 0,0 (BiomeGenBase.biomeName), searched in the target dimension.
|
||||
# -Dangelica.flyby.survival=true runs the flight in survival with flying and no damage, restoring the original game mode afterwards.
|
||||
# -PclientJvmVendor=adoptium (macOS) picks the JVM vendor for runClient17/21/25.
|
||||
#
|
||||
# FLYBY_SPEED - blocks per tick. (0.5 ~= creative flight).
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Translucent TESR ordering scene for a generated superflat (windows-flyby-kit/make_world.py). Needs
|
||||
# -Dangelica.debug.testBlocks=true. $x $y $z is the flight start; ground-standing level is $y-2. Start facing south (yaw 0),
|
||||
# pitch 15. Blocks: test_tesr_provider (0 translucent red, 1 additive purple), test_tesr_model (0 box pane,
|
||||
# 1 Tessellator pane, 2 stacked A/B/A panes), test_tesr_decal, test_tesr_glow; metadata + 8 draws in the solid pass.
|
||||
|
||||
gamerule doMobSpawning false
|
||||
|
||||
# translucent pass: three rows, materials shifted per row so every column stacks three different ones
|
||||
setblock $x-2 $y $z+6 angelica:test_tesr_provider 0 replace
|
||||
setblock $x-1 $y $z+6 angelica:test_tesr_provider 1 replace
|
||||
setblock $x+0 $y $z+6 angelica:test_tesr_model 0 replace
|
||||
setblock $x+1 $y $z+6 angelica:test_tesr_model 1 replace
|
||||
setblock $x-2 $y $z+8 angelica:test_tesr_provider 1 replace
|
||||
setblock $x-1 $y $z+8 angelica:test_tesr_model 0 replace
|
||||
setblock $x+0 $y $z+8 angelica:test_tesr_model 1 replace
|
||||
setblock $x+1 $y $z+8 angelica:test_tesr_provider 0 replace
|
||||
setblock $x-2 $y $z+10 angelica:test_tesr_model 0 replace
|
||||
setblock $x-1 $y $z+10 angelica:test_tesr_model 1 replace
|
||||
setblock $x+0 $y $z+10 angelica:test_tesr_provider 0 replace
|
||||
setblock $x+1 $y $z+10 angelica:test_tesr_provider 1 replace
|
||||
|
||||
# solid pass: the same rows two blocks higher
|
||||
setblock $x-2 $y+2 $z+6 angelica:test_tesr_provider 8 replace
|
||||
setblock $x-1 $y+2 $z+6 angelica:test_tesr_provider 9 replace
|
||||
setblock $x+0 $y+2 $z+6 angelica:test_tesr_model 8 replace
|
||||
setblock $x+1 $y+2 $z+6 angelica:test_tesr_model 9 replace
|
||||
setblock $x-2 $y+2 $z+8 angelica:test_tesr_provider 9 replace
|
||||
setblock $x-1 $y+2 $z+8 angelica:test_tesr_model 8 replace
|
||||
setblock $x+0 $y+2 $z+8 angelica:test_tesr_model 9 replace
|
||||
setblock $x+1 $y+2 $z+8 angelica:test_tesr_provider 8 replace
|
||||
setblock $x-2 $y+2 $z+10 angelica:test_tesr_model 8 replace
|
||||
setblock $x-1 $y+2 $z+10 angelica:test_tesr_model 9 replace
|
||||
setblock $x+0 $y+2 $z+10 angelica:test_tesr_provider 8 replace
|
||||
setblock $x+1 $y+2 $z+10 angelica:test_tesr_provider 9 replace
|
||||
|
||||
# one tile entity submitting translucent A, additive B, translucent A; a depth-equal decal
|
||||
setblock $x-7 $y $z+8 angelica:test_tesr_model 2 replace
|
||||
setblock $x-7 $y+1 $z+8 angelica:test_tesr_decal 0 replace
|
||||
|
||||
# light blue glass wall: glow and provider panes in front, a provider pane behind. The panes behind the wall and
|
||||
# under the water show only when block entities draw before translucent terrain.
|
||||
setblock $x+5 $y-1 $z+14 stained_glass 3 replace
|
||||
setblock $x+5 $y $z+14 stained_glass 3 replace
|
||||
setblock $x+5 $y+1 $z+14 stained_glass 3 replace
|
||||
setblock $x+6 $y-1 $z+14 stained_glass 3 replace
|
||||
setblock $x+6 $y $z+14 stained_glass 3 replace
|
||||
setblock $x+6 $y+1 $z+14 stained_glass 3 replace
|
||||
setblock $x+7 $y-1 $z+14 stained_glass 3 replace
|
||||
setblock $x+7 $y $z+14 stained_glass 3 replace
|
||||
setblock $x+7 $y+1 $z+14 stained_glass 3 replace
|
||||
setblock $x+8 $y-1 $z+14 stained_glass 3 replace
|
||||
setblock $x+8 $y $z+14 stained_glass 3 replace
|
||||
setblock $x+8 $y+1 $z+14 stained_glass 3 replace
|
||||
setblock $x+9 $y-1 $z+14 stained_glass 3 replace
|
||||
setblock $x+9 $y $z+14 stained_glass 3 replace
|
||||
setblock $x+9 $y+1 $z+14 stained_glass 3 replace
|
||||
setblock $x+6 $y $z+13 angelica:test_tesr_glow 0 replace
|
||||
setblock $x+8 $y $z+13 angelica:test_tesr_provider 0 replace
|
||||
setblock $x+7 $y $z+15 angelica:test_tesr_provider 0 replace
|
||||
|
||||
# water pool with a provider pane under the surface
|
||||
setblock $x-10 $y-4 $z+12 water 0 replace
|
||||
setblock $x-10 $y-3 $z+12 water 0 replace
|
||||
setblock $x-10 $y-4 $z+13 water 0 replace
|
||||
setblock $x-10 $y-3 $z+13 water 0 replace
|
||||
setblock $x-10 $y-4 $z+14 water 0 replace
|
||||
setblock $x-10 $y-3 $z+14 water 0 replace
|
||||
setblock $x-9 $y-4 $z+12 water 0 replace
|
||||
setblock $x-9 $y-3 $z+12 water 0 replace
|
||||
setblock $x-9 $y-4 $z+13 water 0 replace
|
||||
setblock $x-9 $y-3 $z+13 water 0 replace
|
||||
setblock $x-9 $y-4 $z+14 water 0 replace
|
||||
setblock $x-9 $y-3 $z+14 water 0 replace
|
||||
setblock $x-8 $y-4 $z+12 water 0 replace
|
||||
setblock $x-8 $y-3 $z+12 water 0 replace
|
||||
setblock $x-8 $y-4 $z+13 water 0 replace
|
||||
setblock $x-8 $y-3 $z+13 water 0 replace
|
||||
setblock $x-8 $y-4 $z+14 water 0 replace
|
||||
setblock $x-8 $y-3 $z+14 water 0 replace
|
||||
setblock $x-9 $y-4 $z+13 angelica:test_tesr_provider 0 replace
|
||||
|
||||
# control: a lone pane with sky behind it
|
||||
setblock $x+5 $y+2 $z+8 angelica:test_tesr_provider 0 replace
|
||||
@@ -1,58 +0,0 @@
|
||||
# Translucency layer scene for a generated superflat (windows-flyby-kit/make_world.py). $x $y $z is the flight start;
|
||||
# ground-standing level is $y-2. Start facing south (yaw 0), pitch 15. Use with -Dangelica.flyby.weather=RAIN. Torch
|
||||
# flame and smoke and rain fall in front of a light blue glass wall and a water pool; one torch row stands behind the glass.
|
||||
|
||||
gamerule doMobSpawning false
|
||||
|
||||
# glass wall
|
||||
setblock $x-1 $y-2 $z+9 stained_glass 3 replace
|
||||
setblock $x-1 $y-1 $z+9 stained_glass 3 replace
|
||||
setblock $x-1 $y+0 $z+9 stained_glass 3 replace
|
||||
setblock $x+0 $y-2 $z+9 stained_glass 3 replace
|
||||
setblock $x+0 $y-1 $z+9 stained_glass 3 replace
|
||||
setblock $x+0 $y+0 $z+9 stained_glass 3 replace
|
||||
setblock $x+1 $y-2 $z+9 stained_glass 3 replace
|
||||
setblock $x+1 $y-1 $z+9 stained_glass 3 replace
|
||||
setblock $x+1 $y+0 $z+9 stained_glass 3 replace
|
||||
setblock $x+2 $y-2 $z+9 stained_glass 3 replace
|
||||
setblock $x+2 $y-1 $z+9 stained_glass 3 replace
|
||||
setblock $x+2 $y+0 $z+9 stained_glass 3 replace
|
||||
setblock $x+3 $y-2 $z+9 stained_glass 3 replace
|
||||
setblock $x+3 $y-1 $z+9 stained_glass 3 replace
|
||||
setblock $x+3 $y+0 $z+9 stained_glass 3 replace
|
||||
|
||||
# torches in front of and behind the glass
|
||||
setblock $x-1 $y-2 $z+7 torch 5 replace
|
||||
setblock $x-1 $y-2 $z+11 torch 5 replace
|
||||
setblock $x+0 $y-2 $z+7 torch 5 replace
|
||||
setblock $x+0 $y-2 $z+11 torch 5 replace
|
||||
setblock $x+1 $y-2 $z+7 torch 5 replace
|
||||
setblock $x+1 $y-2 $z+11 torch 5 replace
|
||||
setblock $x+2 $y-2 $z+7 torch 5 replace
|
||||
setblock $x+2 $y-2 $z+11 torch 5 replace
|
||||
setblock $x+3 $y-2 $z+7 torch 5 replace
|
||||
setblock $x+3 $y-2 $z+11 torch 5 replace
|
||||
|
||||
# water pool with torches in front of it
|
||||
setblock $x-6 $y-3 $z+7 water 0 replace
|
||||
setblock $x-6 $y-3 $z+8 water 0 replace
|
||||
setblock $x-6 $y-3 $z+9 water 0 replace
|
||||
setblock $x-6 $y-3 $z+10 water 0 replace
|
||||
setblock $x-5 $y-3 $z+7 water 0 replace
|
||||
setblock $x-5 $y-3 $z+8 water 0 replace
|
||||
setblock $x-5 $y-3 $z+9 water 0 replace
|
||||
setblock $x-5 $y-3 $z+10 water 0 replace
|
||||
setblock $x-4 $y-3 $z+7 water 0 replace
|
||||
setblock $x-4 $y-3 $z+8 water 0 replace
|
||||
setblock $x-4 $y-3 $z+9 water 0 replace
|
||||
setblock $x-4 $y-3 $z+10 water 0 replace
|
||||
setblock $x-3 $y-3 $z+7 water 0 replace
|
||||
setblock $x-3 $y-3 $z+8 water 0 replace
|
||||
setblock $x-3 $y-3 $z+9 water 0 replace
|
||||
setblock $x-3 $y-3 $z+10 water 0 replace
|
||||
setblock $x-2 $y-3 $z+7 water 0 replace
|
||||
setblock $x-2 $y-3 $z+8 water 0 replace
|
||||
setblock $x-2 $y-3 $z+9 water 0 replace
|
||||
setblock $x-2 $y-3 $z+10 water 0 replace
|
||||
setblock $x-5 $y-2 $z+6 torch 5 replace
|
||||
setblock $x-3 $y-2 $z+6 torch 5 replace
|
||||
@@ -1228,7 +1228,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void issueDrawArrays(int mode, int first, int count) {
|
||||
@Override public void drawArrays(int mode, int first, int count) {
|
||||
if (count <= 0) return;
|
||||
final ContextState st = s();
|
||||
if (st.rasterizerDiscard) return;
|
||||
@@ -1250,7 +1250,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
captureVertexWrites(st, first, count, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override protected void issueDrawElements(int mode, int count, int type, long indices) {
|
||||
@Override public void drawElements(int mode, int count, int type, long indices) {
|
||||
final ContextState st = s();
|
||||
final long rp = prepareIndexedDrawBind(st, mode, type, "drawElements");
|
||||
if (rp == 0) return;
|
||||
@@ -1260,7 +1260,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
captureVertexWrites(st, 0, count, 1, type, indices, 0);
|
||||
}
|
||||
|
||||
@Override protected void issueDrawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
@Override public void drawElementsInstanced(int mode, int count, int type, long indices, int primcount) {
|
||||
final ContextState st = s();
|
||||
final long rp = prepareIndexedDrawBind(st, mode, type, "drawElementsInstanced");
|
||||
if (rp == 0) return;
|
||||
@@ -1272,7 +1272,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
|
||||
@Override protected void issueDrawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
@Override public void drawElementsBaseVertex(int mode, int count, int type, long indices, int baseVertex) {
|
||||
final ContextState st = s();
|
||||
final long rp = prepareIndexedDrawBind(st, mode, type, "drawElementsBaseVertex");
|
||||
if (rp == 0) return;
|
||||
@@ -1297,7 +1297,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
return rp;
|
||||
}
|
||||
|
||||
@Override protected void issueMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
@Override public void multiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) {
|
||||
if (drawcount <= 0) return;
|
||||
final ContextState st = s();
|
||||
final long rp = prepareIndexedDrawBind(st, mode, type, "multiDrawElementsBaseVertex");
|
||||
@@ -1317,7 +1317,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void issueMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
@Override public void multiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
final ContextState cs = s();
|
||||
if (drawcount <= 0) return;
|
||||
Tracy.beginZone(Z_SDL_INDIRECT_DRAW);
|
||||
@@ -4670,7 +4670,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueDrawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
public void drawArraysInstanced(int mode, int first, int count, int primcount) {
|
||||
if (count <= 0 || primcount <= 0) return;
|
||||
final ContextState st = s();
|
||||
if (st.rasterizerDiscard) return;
|
||||
@@ -4688,11 +4688,11 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void issueMultiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
public void multiDrawArrays(int mode, IntBuffer firsts, IntBuffer counts) {
|
||||
if (firsts == null || counts == null) return;
|
||||
final int n = Math.min(firsts.remaining(), counts.remaining());
|
||||
for (int i = 0; i < n; i++) {
|
||||
issueDrawArrays(mode, firsts.get(firsts.position() + i), counts.get(counts.position() + i));
|
||||
drawArrays(mode, firsts.get(firsts.position() + i), counts.get(counts.position() + i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.api.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.GlowReplayExclusions;
|
||||
|
||||
/// Under Fancy translucency, block entities drawing glows (blended draws without depth writes) in the translucent
|
||||
/// pass are rendered a second time. Renderers that advance state per call opt out here.
|
||||
public final class TesrGlowDepth {
|
||||
|
||||
private TesrGlowDepth() {}
|
||||
|
||||
/// Excludes block entities of `type`, or rendered by a renderer of `type`, including subclasses.
|
||||
public static void excludeFromReplay(Class<?> type) {
|
||||
GlowReplayExclusions.exclude(type);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/** TESR mesh cache/batch API (Render thread only) */
|
||||
@API(owner = "angelica", provides = "angelica|tesr", apiVersion = "4")
|
||||
@API(owner = "angelica", provides = "angelica|tesr", apiVersion = "3")
|
||||
package com.gtnewhorizons.angelica.api.tesr;
|
||||
|
||||
import cpw.mods.fml.common.API;
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizons.angelica.api.weather;
|
||||
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
|
||||
public interface WeatherColumnProvider {
|
||||
|
||||
// False suppresses vanilla rain and snow in this dimension.
|
||||
boolean rendersVanillaWeather();
|
||||
|
||||
// Called each instanced weather frame before columnRevision and collectColumns; returns the tick counter that drives scroll and drift.
|
||||
int beginFrame(WorldClient world, EntityLivingBase view, float partialTicks);
|
||||
|
||||
// Must change whenever any collected column changes; columns are re-collected only then or when the dimension or the player's block X/Z changes.
|
||||
int columnRevision();
|
||||
|
||||
// Finite positive block distance d0 in alpha = ((1 - (d / d0)^2) * fadeScale + 0.5) * a.
|
||||
float fadeRadius();
|
||||
|
||||
void collectColumns(WeatherColumnSink sink);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.gtnewhorizons.angelica.api.weather;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface WeatherColumnSink {
|
||||
|
||||
// scrollPeriod is a power of two no greater than 1024.
|
||||
void beginLayer(ResourceLocation texture, int scrollPeriod, float uDriftScale, float vDriftScale, float fadeScale);
|
||||
|
||||
// x and z are world block coordinates; brightness is a packed lightmap coordinate below 2^24.
|
||||
void column(int x, int z, float bottom, float top, float uBase, float uDrift, float vBase, float vDrift, int brightness, int scrollOffset, float scrollScale, float r, float g, float b, float a);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@API(owner = "angelica", provides = "angelica|weather", apiVersion = "1")
|
||||
package com.gtnewhorizons.angelica.api.weather;
|
||||
|
||||
import cpw.mods.fml.common.API;
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.common;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class BlockTesrTranslucentTest extends Block {
|
||||
|
||||
private final Supplier<TileEntity> tile;
|
||||
|
||||
public BlockTesrTranslucentTest(Supplier<TileEntity> tile) {
|
||||
super(Material.glass);
|
||||
this.tile = tile;
|
||||
setHardness(0.3f);
|
||||
setLightOpacity(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renderAsNormalBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderType() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTileEntity(int metadata) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity createTileEntity(World world, int metadata) {
|
||||
return tile.get();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.common;
|
||||
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public abstract class TileTesrTranslucentTest extends TileEntity {
|
||||
|
||||
private static final int SOLID_PASS = 8;
|
||||
|
||||
public int variant() {
|
||||
return getBlockMetadata() & ~SOLID_PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderInPass(int pass) {
|
||||
return pass == ((getBlockMetadata() & SOLID_PASS) != 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Provider extends TileTesrTranslucentTest {}
|
||||
|
||||
public static class Model extends TileTesrTranslucentTest {}
|
||||
|
||||
public static class Decal extends TileTesrTranslucentTest {}
|
||||
|
||||
public static class Glow extends TileTesrTranslucentTest {}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public class ModStatus {
|
||||
public static boolean isBaublesLoaded;
|
||||
public static boolean isCosmeticArmorReworkedLoaded;
|
||||
public static boolean isFluidLoggedLoaded;
|
||||
public static boolean isLiquidLoggedLoaded;
|
||||
public static boolean isCubicChunksLoaded;
|
||||
public static boolean isBOPLoaded;
|
||||
public static boolean isEtFuturumLoaded;
|
||||
@@ -51,6 +52,7 @@ public class ModStatus {
|
||||
isBaublesLoaded = Loader.isModLoaded("Baubles");
|
||||
isCosmeticArmorReworkedLoaded = Loader.isModLoaded("cosmeticarmorreworked");
|
||||
isFluidLoggedLoaded = Loader.isModLoaded("fluidlogged");
|
||||
isLiquidLoggedLoaded = Loader.isModLoaded("liquidlogged");
|
||||
isCubicChunksLoaded = Loader.isModLoaded("cubicchunks");
|
||||
isEtFuturumLoaded = Loader.isModLoaded("etfuturum");
|
||||
|
||||
|
||||
@@ -177,11 +177,6 @@ public class AngelicaConfig {
|
||||
@Config.RequiresMcRestart
|
||||
public static String[] entityShadowReplayExcludedClasses;
|
||||
|
||||
@Config.Comment("Tile entity or renderer classes whose glows Fancy translucency records as they draw instead of rendering the tile entity a second time. For renderers that advance an animation or other state on each render.")
|
||||
@Config.DefaultStringList({})
|
||||
@Config.RequiresMcRestart
|
||||
public static String[] glowDepthReplayExcludedClasses;
|
||||
|
||||
@Config.Comment("Skip the end-of-frame shader buffer copy by ping-ponging buffers. Disable if a shader pack misrenders.")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.gtnewhorizons.angelica.rendering.FpsReducer;
|
||||
import com.gtnewhorizons.angelica.rendering.FramePacer;
|
||||
import com.gtnewhorizons.angelica.rendering.IsbrhTestRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
|
||||
import com.prupe.mcpatcher.mal.biome.BiomeAPI;
|
||||
import com.sun.management.OperatingSystemMXBean;
|
||||
import com.sun.management.ThreadMXBean;
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
@@ -24,6 +25,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.entity.EntityClientPlayerMP;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiSelectWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.server.integrated.IntegratedServer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -34,8 +36,12 @@ import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ScreenShotHelper;
|
||||
import net.minecraft.world.MinecraftException;
|
||||
import net.minecraft.world.Teleporter;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.IChunkProvider;
|
||||
import net.minecraft.world.storage.ThreadedFileIOBase;
|
||||
@@ -66,6 +72,8 @@ public final class FlybyRunner {
|
||||
|
||||
private enum State { IDLE, WAITING, PREPARING, WARMUP, RUNNING, SETTLE, EXITING, MENU, DONE }
|
||||
|
||||
private static final int BIOME_WINDOW = 11;
|
||||
private static final int BIOME_SEARCH_CELLS = 512;
|
||||
private static final int EXIT_TICKS = 20;
|
||||
private static final int SETTLE_TICKS = 40;
|
||||
private static final int MENU_SETTLE_TICKS = 20;
|
||||
@@ -93,6 +101,16 @@ public final class FlybyRunner {
|
||||
private final AtomicReference<String> pendingDimensionPlayer = new AtomicReference<>();
|
||||
private boolean dimensionRequested;
|
||||
private volatile boolean dimensionAbandoned;
|
||||
private final AtomicReference<String> pendingBiomePlayer = new AtomicReference<>();
|
||||
private boolean biomeRequested;
|
||||
private volatile boolean biomeAbandoned;
|
||||
private volatile FlybyOrigin biomeOrigin;
|
||||
private BiomeGenBase[] biomeScratch;
|
||||
private volatile boolean survivalRestoreRequested;
|
||||
private boolean survivalApplied;
|
||||
private String survivalPlayerName;
|
||||
private String survivalWorld;
|
||||
private WorldSettings.GameType survivalRestoreType;
|
||||
private FlybyRequest activeRequest;
|
||||
private String[] sceneCommands = NO_COMMANDS;
|
||||
private volatile boolean sceneClearRequested;
|
||||
@@ -229,6 +247,10 @@ public final class FlybyRunner {
|
||||
this.exitWhenDone = false;
|
||||
this.dimensionRequested = false;
|
||||
this.dimensionAbandoned = false;
|
||||
this.biomeRequested = false;
|
||||
this.biomeAbandoned = false;
|
||||
this.biomeOrigin = null;
|
||||
if (SystemProperties.FLYBY_SURVIVAL) this.survivalRestoreRequested = true;
|
||||
this.jfr = false;
|
||||
this.armed = false;
|
||||
this.fixedOrigin = null;
|
||||
@@ -305,6 +327,7 @@ public final class FlybyRunner {
|
||||
return;
|
||||
}
|
||||
if (this.awaitingDimension(mc, player)) return;
|
||||
if (this.awaitingBiome(mc, player)) return;
|
||||
this.begin(mc, player);
|
||||
}
|
||||
case PREPARING -> {
|
||||
@@ -390,6 +413,26 @@ public final class FlybyRunner {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean awaitingBiome(Minecraft mc, EntityClientPlayerMP player) {
|
||||
final String biome = SystemProperties.FLYBY_BIOME;
|
||||
if (!this.startedFromProperties || biome.isEmpty() || this.biomeAbandoned) return false;
|
||||
final FlybyOrigin found = this.biomeOrigin;
|
||||
if (found != null) {
|
||||
this.fixedOrigin = this.fixedOrigin == null ? found : new FlybyOrigin(found.x(), found.z(), this.fixedOrigin.yaw());
|
||||
return false;
|
||||
}
|
||||
if (mc.getIntegratedServer() == null) {
|
||||
LOGGER.warn("Flyby: not singleplayer, ignoring biome '{}'", biome);
|
||||
this.biomeAbandoned = true;
|
||||
return false;
|
||||
}
|
||||
if (!this.biomeRequested) {
|
||||
this.biomeRequested = true;
|
||||
this.pendingBiomePlayer.set(player.getCommandSenderName());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void overridePauseOnLostFocus(Minecraft mc) {
|
||||
if (this.pauseOnLostFocusOverridden) return;
|
||||
this.pauseOnLostFocusSaved = mc.gameSettings.pauseOnLostFocus;
|
||||
@@ -657,7 +700,7 @@ public final class FlybyRunner {
|
||||
public void onServerTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase != TickEvent.Phase.END) return;
|
||||
final boolean clear = this.sceneClearRequested;
|
||||
if (!clear && this.pendingRequest.get() == null && this.pendingDimensionPlayer.get() == null && this.sceneDeferred.isEmpty()) return;
|
||||
if (!clear && this.pendingRequest.get() == null && this.pendingDimensionPlayer.get() == null && this.pendingBiomePlayer.get() == null && !this.survivalRestoreRequested && this.sceneDeferred.isEmpty()) return;
|
||||
|
||||
final MinecraftServer server = MinecraftServer.getServer();
|
||||
if (server == null) return;
|
||||
@@ -670,10 +713,23 @@ public final class FlybyRunner {
|
||||
LOGGER.warn("Flyby: no server player named '{}', staying in the current dimension", traveller);
|
||||
this.dimensionAbandoned = true;
|
||||
} else {
|
||||
server.getConfigurationManager().transferPlayerToDimension(player, SystemProperties.FLYBY_DIMENSION);
|
||||
final int dimension = SystemProperties.FLYBY_DIMENSION;
|
||||
final WorldServer target = server.worldServerForDimension(dimension);
|
||||
server.getConfigurationManager().transferPlayerToDimension(player, dimension,
|
||||
target.provider.hasNoSky ? target.getDefaultTeleporter() : new SurfaceTeleporter(target));
|
||||
}
|
||||
}
|
||||
|
||||
final String seeker = this.pendingBiomePlayer.getAndSet(null);
|
||||
if (seeker != null) {
|
||||
this.findBiome(server, seeker);
|
||||
}
|
||||
|
||||
if (this.survivalRestoreRequested) {
|
||||
this.survivalRestoreRequested = false;
|
||||
this.restoreGameType(server);
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
this.sceneClearRequested = false;
|
||||
this.clearScene(server);
|
||||
@@ -688,11 +744,104 @@ public final class FlybyRunner {
|
||||
final double feetY = this.flightFeetY(server, request);
|
||||
request.feetY().complete(feetY);
|
||||
this.applyFreeze(server);
|
||||
if (SystemProperties.FLYBY_SURVIVAL) {
|
||||
if (this.survivalApplied) {
|
||||
LOGGER.warn("Flyby: game mode restore pending for world '{}', flying without survival", this.survivalWorld);
|
||||
} else {
|
||||
this.applySurvival(server, request.playerName());
|
||||
}
|
||||
}
|
||||
if (request.scene()) {
|
||||
this.runScene(server, request, feetY);
|
||||
}
|
||||
}
|
||||
|
||||
private void applySurvival(MinecraftServer server, String playerName) {
|
||||
final EntityPlayerMP player = server.getConfigurationManager().func_152612_a(playerName);
|
||||
if (player == null) {
|
||||
LOGGER.warn("Flyby: no server player named '{}', staying in the current game mode", playerName);
|
||||
return;
|
||||
}
|
||||
this.survivalRestoreType = player.theItemInWorldManager.getGameType();
|
||||
player.setGameType(WorldSettings.GameType.SURVIVAL);
|
||||
player.capabilities.allowFlying = player.capabilities.isFlying = player.capabilities.disableDamage = true;
|
||||
player.sendPlayerAbilities();
|
||||
this.survivalApplied = true;
|
||||
this.survivalPlayerName = playerName;
|
||||
this.survivalWorld = server.getFolderName();
|
||||
}
|
||||
|
||||
private void restoreGameType(MinecraftServer server) {
|
||||
if (!this.survivalApplied) return;
|
||||
final EntityPlayerMP player = server.getFolderName().equals(this.survivalWorld)
|
||||
? server.getConfigurationManager().func_152612_a(this.survivalPlayerName) : null;
|
||||
if (player == null) {
|
||||
this.survivalRestoreRequested = true;
|
||||
return;
|
||||
}
|
||||
player.setGameType(this.survivalRestoreType);
|
||||
this.survivalApplied = false;
|
||||
}
|
||||
|
||||
private void findBiome(MinecraftServer server, String playerName) {
|
||||
final String name = SystemProperties.FLYBY_BIOME;
|
||||
final EntityPlayerMP player = server.getConfigurationManager().func_152612_a(playerName);
|
||||
if (player == null) {
|
||||
LOGGER.warn("Flyby: no server player named '{}', ignoring biome '{}'", playerName, name);
|
||||
this.biomeAbandoned = true;
|
||||
return;
|
||||
}
|
||||
final BiomeGenBase target = BiomeAPI.findBiomeByName(name);
|
||||
if (target == null) {
|
||||
LOGGER.error("Flyby: unknown biome '{}'", name);
|
||||
this.biomeAbandoned = true;
|
||||
return;
|
||||
}
|
||||
final FlybyOrigin found = this.scanForBiome(player.worldObj.getWorldChunkManager(), target);
|
||||
this.biomeScratch = null;
|
||||
if (found == null) {
|
||||
LOGGER.error("Flyby: biome '{}' not found within {} blocks", name, BIOME_SEARCH_CELLS * 4);
|
||||
this.biomeAbandoned = true;
|
||||
return;
|
||||
}
|
||||
LOGGER.info("Flyby: biome '{}' found at {} {}", name, found.x(), found.z());
|
||||
this.biomeOrigin = found;
|
||||
}
|
||||
|
||||
private FlybyOrigin scanForBiome(WorldChunkManager manager, BiomeGenBase target) {
|
||||
FlybyOrigin found = this.scanStrip(manager, target, 0, 0, 0, 0);
|
||||
for (int r = 1; found == null && r <= BIOME_SEARCH_CELLS; r++) {
|
||||
found = this.scanStrip(manager, target, -r, -r, r, -r);
|
||||
if (found == null) found = this.scanStrip(manager, target, -r, r, r, r);
|
||||
if (found == null) found = this.scanStrip(manager, target, -r, 1 - r, -r, r - 1);
|
||||
if (found == null) found = this.scanStrip(manager, target, r, 1 - r, r, r - 1);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private FlybyOrigin scanStrip(WorldChunkManager manager, BiomeGenBase target, int minX, int minZ, int maxX, int maxZ) {
|
||||
final int half = BIOME_WINDOW / 2;
|
||||
final int width = maxX - minX + BIOME_WINDOW;
|
||||
this.biomeScratch = manager.getBiomesForGeneration(this.biomeScratch, minX - half, minZ - half, width, maxZ - minZ + BIOME_WINDOW);
|
||||
for (int cz = minZ; cz <= maxZ; cz++) {
|
||||
for (int cx = minX; cx <= maxX; cx++) {
|
||||
if (this.windowMatches(target, width, minX - half, minZ - half, cx, cz)) return new FlybyOrigin(cx * 4 + 2, cz * 4 + 2, 0.0F);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean windowMatches(BiomeGenBase target, int width, int originX, int originZ, int cx, int cz) {
|
||||
final int half = BIOME_WINDOW / 2;
|
||||
for (int dz = -half; dz <= half; dz++) {
|
||||
final int row = (cz + dz - originZ) * width - originX + cx;
|
||||
for (int dx = -half; dx <= half; dx++) {
|
||||
if (this.biomeScratch[row + dx] != target) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void discardWorldChanges(MinecraftServer server) {
|
||||
if (worldChangesDiscarded) return;
|
||||
|
||||
@@ -864,6 +1013,7 @@ public final class FlybyRunner {
|
||||
|
||||
private void finish(Minecraft mc, EntityClientPlayerMP player) {
|
||||
this.state = State.SETTLE;
|
||||
if (SystemProperties.FLYBY_SURVIVAL) this.survivalRestoreRequested = true;
|
||||
this.tick = 0;
|
||||
final long elapsedNs = System.nanoTime() - this.runStartNs;
|
||||
Tracy.sectionLeave(this.legSection);
|
||||
@@ -1140,6 +1290,7 @@ public final class FlybyRunner {
|
||||
this.sceneClearRequested = this.sceneCommands.length > 0;
|
||||
this.restorePacing(mc);
|
||||
}
|
||||
if (SystemProperties.FLYBY_SURVIVAL) this.survivalRestoreRequested = true;
|
||||
}
|
||||
|
||||
public boolean startedFromProperties() {
|
||||
@@ -1147,4 +1298,20 @@ public final class FlybyRunner {
|
||||
}
|
||||
|
||||
private record FlybyRequest(double[] pathX, double[] pathZ, double originX, double originZ, double parkedFeetY, String playerName, boolean sampleTerrain, boolean scene, CompletableFuture<Double> feetY) {}
|
||||
|
||||
private static final class SurfaceTeleporter extends Teleporter {
|
||||
private final WorldServer world;
|
||||
|
||||
SurfaceTeleporter(WorldServer world) {
|
||||
super(world);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeInPortal(Entity entity, double x, double y, double z, float yaw) {
|
||||
final int top = this.world.getTopSolidOrLiquidBlock(MathHelper.floor_double(entity.posX), MathHelper.floor_double(entity.posZ));
|
||||
entity.setLocationAndAngles(entity.posX, top > 0 ? top : entity.posY, entity.posZ, entity.rotationYaw, entity.rotationPitch);
|
||||
entity.motionX = entity.motionY = entity.motionZ = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,15 +301,6 @@ public enum Mixins implements IMixins {
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_GLOW_DEPTH_REPLAY(new MixinBuilder("Drop particles and sounds a block entity renderer starts while Fancy translucency replays it into the glow depth")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addClientMixins(
|
||||
"angelica.tesr.MixinEffectRenderer_GlowDepthReplay",
|
||||
"angelica.tesr.MixinSoundHandler_GlowDepthReplay"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_TESR_PROVIDER_DISPATCH(new MixinBuilder("Route TesrMeshProvider renderers through the batched mesh cache, and observe renderers that mix model parts with their own draws")
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableTESRProviderDispatch || AngelicaConfig.enableEntityBatching)
|
||||
@@ -560,8 +551,6 @@ public enum Mixins implements IMixins {
|
||||
, "shaders.MixinEntityRenderer"
|
||||
, "shaders.MixinGuiIngameForge"
|
||||
, "shaders.MixinFramebuffer"
|
||||
, "angelica.rendering.MixinEntityRenderer_TranslucencyLayers"
|
||||
, "angelica.rendering.MixinFramebuffer_TranslucencyLayers"
|
||||
, "shaders.MixinItem"
|
||||
, "shaders.MixinItemRenderer_ItemId"
|
||||
, "shaders.MixinLocale"
|
||||
@@ -911,6 +900,18 @@ public enum Mixins implements IMixins {
|
||||
"MixinBlockTFMagicLeaves"
|
||||
))
|
||||
),
|
||||
NOTFINE_BIOMES_O_PLENTY_COMPAT(new MixinBuilder()
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableNotFineFeatures)
|
||||
.addRequiredMod(TargetedMod.BIOMES_O_PLENTY)
|
||||
.addClientMixins(addPrefix("notfine.leaves.biomesoplenty.",
|
||||
"MixinBlockBOPLeaves",
|
||||
"MixinBlockBOPColorizedLeaves",
|
||||
"MixinBlockBOPAppleLeaves",
|
||||
"MixinBlockBOPPersimmonLeaves",
|
||||
"MixinColorizedLeavesRenderer"
|
||||
))
|
||||
),
|
||||
ET_FUTURUM_ELYTRA_CAPE(new MixinBuilder("Set custom item ID for elytra with cape texture")
|
||||
.setPhase(Phase.LATE)
|
||||
.addRequiredMod(TargetedMod.ET_FUTURUM_REQUIEM)
|
||||
|
||||
@@ -40,7 +40,6 @@ import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.common.BlockError;
|
||||
import com.gtnewhorizons.angelica.common.BlockIsbrhTest;
|
||||
import com.gtnewhorizons.angelica.common.TileEntityClipPlaneTest;
|
||||
import com.gtnewhorizons.angelica.common.TileTesrTranslucentTest;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.bettercrashes.BetterCrashesCompat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
@@ -76,7 +75,6 @@ import com.gtnewhorizons.angelica.rendering.ClipPlaneTestRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.FpsReducer;
|
||||
import com.gtnewhorizons.angelica.rendering.FramePacer;
|
||||
import com.gtnewhorizons.angelica.rendering.IsbrhTestRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.TesrTranslucentTestRenderers;
|
||||
import com.gtnewhorizons.angelica.rendering.TextureSamplers;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasSetup;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
|
||||
@@ -152,10 +150,6 @@ public final class ClientProxy extends CommonProxy {
|
||||
BlockIsbrhTest.renderId = RenderingRegistry.getNextAvailableRenderId();
|
||||
RenderingRegistry.registerBlockHandler(BlockIsbrhTest.renderId, new IsbrhTestRenderer());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityClipPlaneTest.class, new ClipPlaneTestRenderer());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileTesrTranslucentTest.Provider.class, new TesrTranslucentTestRenderers.Provider());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileTesrTranslucentTest.Model.class, new TesrTranslucentTestRenderers.Model());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileTesrTranslucentTest.Decal.class, new TesrTranslucentTestRenderers.Decal());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileTesrTranslucentTest.Glow.class, new TesrTranslucentTestRenderers.Glow());
|
||||
}
|
||||
AngelicaJar.configureShaderDiskCache(event.getSourceFile());
|
||||
if (AngelicaConfig.enableIris) {
|
||||
|
||||
@@ -2,18 +2,13 @@ package com.gtnewhorizons.angelica.proxy;
|
||||
|
||||
import com.gtnewhorizons.angelica.common.BlockClipPlaneTest;
|
||||
import com.gtnewhorizons.angelica.common.BlockIsbrhTest;
|
||||
import com.gtnewhorizons.angelica.common.BlockTesrTranslucentTest;
|
||||
import com.gtnewhorizons.angelica.common.BlockTest;
|
||||
import com.gtnewhorizons.angelica.common.TileEntityClipPlaneTest;
|
||||
import com.gtnewhorizons.angelica.common.TileTesrTranslucentTest;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CommonProxy {
|
||||
|
||||
@@ -23,18 +18,9 @@ public class CommonProxy {
|
||||
GameRegistry.registerBlock(new BlockIsbrhTest(), "test_isbrh");
|
||||
GameRegistry.registerBlock(new BlockClipPlaneTest(), "test_clip_plane");
|
||||
GameRegistry.registerTileEntity(TileEntityClipPlaneTest.class, "angelica:test_clip_plane");
|
||||
registerTesrTest("test_tesr_provider", TileTesrTranslucentTest.Provider.class, TileTesrTranslucentTest.Provider::new);
|
||||
registerTesrTest("test_tesr_model", TileTesrTranslucentTest.Model.class, TileTesrTranslucentTest.Model::new);
|
||||
registerTesrTest("test_tesr_decal", TileTesrTranslucentTest.Decal.class, TileTesrTranslucentTest.Decal::new);
|
||||
registerTesrTest("test_tesr_glow", TileTesrTranslucentTest.Glow.class, TileTesrTranslucentTest.Glow::new);
|
||||
}
|
||||
}
|
||||
|
||||
private static void registerTesrTest(String name, Class<? extends TileEntity> tile, Supplier<TileEntity> factory) {
|
||||
GameRegistry.registerBlock(new BlockTesrTranslucentTest(factory), name);
|
||||
GameRegistry.registerTileEntity(tile, "angelica:" + name);
|
||||
}
|
||||
|
||||
public void init(FMLInitializationEvent event) {}
|
||||
|
||||
public void postInit(FMLPostInitializationEvent event) {}
|
||||
|
||||
@@ -103,12 +103,8 @@ public class PanoramaRenderer {
|
||||
}
|
||||
|
||||
public static <T> GlProgram<T> loadProgram(String name, String vertBase, String fragBase, Function<ShaderBindingContext, T> factory) {
|
||||
return loadProgram(name, vertBase, fragBase, ShaderConstants.EMPTY, factory);
|
||||
}
|
||||
|
||||
public static <T> GlProgram<T> loadProgram(String name, String vertBase, String fragBase, ShaderConstants fragConstants, Function<ShaderBindingContext, T> factory) {
|
||||
final GlShader vert = ShaderLoader.loadShader(ShaderType.VERTEX, vertBase + ".vert", ShaderConstants.EMPTY);
|
||||
final GlShader frag = ShaderLoader.loadShader(ShaderType.FRAGMENT, fragBase + ".frag", fragConstants);
|
||||
final GlShader frag = ShaderLoader.loadShader(ShaderType.FRAGMENT, fragBase + ".frag", ShaderConstants.EMPTY);
|
||||
try {
|
||||
final GlProgram<T> program = GlProgram.builder(name).attachShader(vert).attachShader(frag).link(factory);
|
||||
program.bind();
|
||||
|
||||
@@ -134,29 +134,12 @@ public final class WeatherColumns {
|
||||
return height[slotOf(x, z)];
|
||||
}
|
||||
|
||||
public int hashAt(int x, int z) {
|
||||
return hash[slotOf(x, z)];
|
||||
}
|
||||
|
||||
public float temperatureAt(int x, int z, int y) {
|
||||
final int slot = slotOf(x, z);
|
||||
if (y <= 64) return temperatureBelow65[slot];
|
||||
return temperatureAtReference[slot] - (y - TEMPERATURE_REFERENCE_Y) * TEMPERATURE_PER_BLOCK;
|
||||
}
|
||||
|
||||
public int lightAt(WorldClient world, int x, int z, int y) {
|
||||
final int slot = slotOf(x, z);
|
||||
if (lightY[slot] != y) {
|
||||
lightY[slot] = y;
|
||||
light[slot] = world.getLightBrightnessForSkyBlocks(x, y, z, 0);
|
||||
}
|
||||
return light[slot];
|
||||
}
|
||||
|
||||
public float jitterAt(int x, int z, int index) {
|
||||
return jitter[slotOf(x, z) * 4 + index];
|
||||
}
|
||||
|
||||
private int slotOf(int x, int z) {
|
||||
return Math.floorMod(x, size) * size + Math.floorMod(z, size);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import com.gtnewhorizons.angelica.api.weather.WeatherColumnProvider;
|
||||
import com.gtnewhorizons.angelica.api.weather.WeatherColumnSink;
|
||||
import com.gtnewhorizons.angelica.compat.dragonapi.DragonAPICompat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
@@ -27,27 +29,30 @@ import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.particle.EntityRainFX;
|
||||
import net.minecraft.client.particle.EntitySmokeFX;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraftforge.client.IRenderHandler;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Replaces EntityRenderer.renderRainSnow.
|
||||
*
|
||||
* <p>The whole grid is one instanced draw per precipitation type. Everything that varies per frame
|
||||
* <p>The whole grid is one instanced draw per layer: vanilla rain, vanilla snow, and each provider layer. Everything that varies per frame
|
||||
* (billboard axis, distance falloff, texture scroll, snow drift) happens in the vertex shader, and the
|
||||
* instance buffer is only rebuilt when the camera changes block or {@link WeatherColumns} actually
|
||||
* resamples something. Per-column data comes from that cache rather than being recomputed every frame.
|
||||
* {@link WeatherColumnProvider} columns are collected from the provider instead, and re-collected only when its revision,
|
||||
* the dimension, or the player's block X/Z changes.
|
||||
*/
|
||||
public final class WeatherRenderer {
|
||||
|
||||
@@ -63,17 +68,18 @@ public final class WeatherRenderer {
|
||||
private static final long P_REBUILDS = Tracy.plotHandle("weather.rebuilds");
|
||||
private static final long P_PARTICLE_MICROS = Tracy.plotHandle("weather.particleMicros");
|
||||
private static final long P_PARTICLES_SPAWNED = Tracy.plotHandle("weather.particlesSpawned");
|
||||
private static final long P_PROVIDER_COLUMNS = Tracy.plotHandle("weather.providerColumns");
|
||||
private static final long P_PROVIDER_DRAWS = Tracy.plotHandle("weather.providerDraws");
|
||||
private static final long P_PROVIDER_REBUILDS = Tracy.plotHandle("weather.providerRebuilds");
|
||||
private static final long P_LEGACY_HANDLER = Tracy.plotHandle("weather.legacyHandler");
|
||||
|
||||
private static final WeatherColumns columns = new WeatherColumns();
|
||||
|
||||
private static float[] axisX;
|
||||
private static float[] axisZ;
|
||||
|
||||
private static int instanceBuffer;
|
||||
private static ByteBuffer instanceData;
|
||||
private static int instanceCapacity;
|
||||
private static int instanceCount;
|
||||
private static int rainInstances;
|
||||
private static final WeatherBatch VANILLA = new WeatherBatch();
|
||||
private static final WeatherBatch PROVIDER = new WeatherBatch();
|
||||
|
||||
private static int builtRevision = Integer.MIN_VALUE;
|
||||
private static int builtX = Integer.MIN_VALUE;
|
||||
@@ -84,6 +90,32 @@ public final class WeatherRenderer {
|
||||
private static int builtCameraY = Integer.MIN_VALUE;
|
||||
private static boolean rebuiltThisFrame;
|
||||
|
||||
private static int builtProviderRevision = Integer.MIN_VALUE;
|
||||
private static int builtProviderDimension = Integer.MIN_VALUE;
|
||||
private static int builtProviderX = Integer.MIN_VALUE;
|
||||
private static int builtProviderZ = Integer.MIN_VALUE;
|
||||
private static boolean providerRebuiltThisFrame;
|
||||
|
||||
private static int frameQuads;
|
||||
private static int frameDrawCalls;
|
||||
private static int providerColumns;
|
||||
private static int providerDraws;
|
||||
private static boolean legacyHandler;
|
||||
|
||||
private static int entityBlockX;
|
||||
private static int entityBlockY;
|
||||
private static int entityBlockZ;
|
||||
private static double cameraX;
|
||||
private static double cameraY;
|
||||
private static double cameraZ;
|
||||
private static int cameraBlockY;
|
||||
private static double viewPosX;
|
||||
private static double viewPosZ;
|
||||
private static int updateCount;
|
||||
private static int radius;
|
||||
private static float rainStrength;
|
||||
private static float partialTicks;
|
||||
|
||||
private static final int PARTICLE_RADIUS = 10;
|
||||
private static final Random particleRandom = new Random();
|
||||
private static int rainSoundCounter;
|
||||
@@ -181,180 +213,180 @@ public final class WeatherRenderer {
|
||||
}
|
||||
|
||||
public static boolean render(float partialTicks) {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
final WorldClient world = mc.theWorld;
|
||||
final long startNanos = System.nanoTime();
|
||||
if (!AngelicaConfig.enableInstancedWeather) return false;
|
||||
if (world.provider.getWeatherRenderer() != null) {
|
||||
Tracy.plot(P_STRENGTH, 0.0);
|
||||
report(0, 0, startNanos);
|
||||
return false;
|
||||
}
|
||||
if (DragonAPICompat.forcingSeasonalSnow) {
|
||||
report(0, 0, startNanos);
|
||||
return false;
|
||||
}
|
||||
final float rainStrength = world.getRainStrength(partialTicks);
|
||||
Tracy.plot(P_STRENGTH, rainStrength);
|
||||
frameQuads = 0;
|
||||
frameDrawCalls = 0;
|
||||
providerColumns = 0;
|
||||
providerDraws = 0;
|
||||
legacyHandler = false;
|
||||
final boolean handled = renderFrame(partialTicks);
|
||||
report(startNanos);
|
||||
return handled;
|
||||
}
|
||||
|
||||
final int radius = SettingsManager.downfallDistance;
|
||||
if (rainStrength <= 0.0F || radius <= 0) {
|
||||
report(0, 0, startNanos);
|
||||
private static boolean renderFrame(float partialTicks) {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
final WorldClient world = mc.theWorld;
|
||||
final IRenderHandler handler = world.provider.getWeatherRenderer();
|
||||
final WeatherColumnProvider provider;
|
||||
if (handler == null) {
|
||||
if (DragonAPICompat.forcingSeasonalSnow) return false;
|
||||
provider = null;
|
||||
} else if (handler instanceof WeatherColumnProvider columnProvider) {
|
||||
provider = columnProvider;
|
||||
} else {
|
||||
return useLegacyHandler();
|
||||
}
|
||||
|
||||
rainStrength = provider == null || provider.rendersVanillaWeather() ? world.getRainStrength(partialTicks) : 0.0F;
|
||||
radius = SettingsManager.downfallDistance;
|
||||
final boolean vanillaActive = rainStrength > 0.0F && radius > 0;
|
||||
if (provider == null && !vanillaActive) {
|
||||
Tracy.plot(P_STRENGTH, rainStrength);
|
||||
return true;
|
||||
}
|
||||
buildAxisTable();
|
||||
|
||||
final EntityLivingBase view = mc.renderViewEntity;
|
||||
final int entityBlockX = MathHelper.floor_double(view.posX);
|
||||
final int entityBlockY = MathHelper.floor_double(view.posY);
|
||||
final int entityBlockZ = MathHelper.floor_double(view.posZ);
|
||||
|
||||
final double cameraX = view.lastTickPosX + (view.posX - view.lastTickPosX) * partialTicks;
|
||||
final double cameraY = view.lastTickPosY + (view.posY - view.lastTickPosY) * partialTicks;
|
||||
final double cameraZ = view.lastTickPosZ + (view.posZ - view.lastTickPosZ) * partialTicks;
|
||||
final int cameraBlockY = MathHelper.floor_double(cameraY);
|
||||
|
||||
final int updateCount = ((EntityRendererAccessor) mc.entityRenderer).getRendererUpdateCount();
|
||||
columns.update(world, entityBlockX, entityBlockZ, radius, updateCount);
|
||||
WeatherRenderer.partialTicks = partialTicks;
|
||||
entityBlockX = MathHelper.floor_double(view.posX);
|
||||
entityBlockY = MathHelper.floor_double(view.posY);
|
||||
entityBlockZ = MathHelper.floor_double(view.posZ);
|
||||
cameraX = view.lastTickPosX + (view.posX - view.lastTickPosX) * partialTicks;
|
||||
cameraY = view.lastTickPosY + (view.posY - view.lastTickPosY) * partialTicks;
|
||||
cameraZ = view.lastTickPosZ + (view.posZ - view.lastTickPosZ) * partialTicks;
|
||||
cameraBlockY = MathHelper.floor_double(cameraY);
|
||||
viewPosX = view.posX;
|
||||
viewPosZ = view.posZ;
|
||||
updateCount = ((EntityRendererAccessor) mc.entityRenderer).getRendererUpdateCount();
|
||||
|
||||
final DeferredWorldRenderingPipeline deferred = deferredPipeline();
|
||||
mc.entityRenderer.enableLightmap(partialTicks);
|
||||
GLSMRasterizer.disableCull();
|
||||
GLSMCurrentAttribs.glNormal3f(0.0F, 1.0F, 0.0F);
|
||||
GLSMBlend.enableBlend();
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
GLSMCurrentAttribs.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
if (deferred != null && !deferred.supportsInstancing(Instancing.WEATHER)) {
|
||||
renderTessellator(mc, world, view, partialTicks, rainStrength, radius, updateCount,
|
||||
entityBlockX, entityBlockY, entityBlockZ, cameraX, cameraY, cameraZ, cameraBlockY, startNanos);
|
||||
return true;
|
||||
final boolean instanced;
|
||||
if (deferred == null) {
|
||||
instanced = true;
|
||||
} else if (deferred.supportsInstancing(Instancing.WEATHER)) {
|
||||
deferred.rebindCurrentPass();
|
||||
instanced = deferred.hasInstancedVariant(Instancing.WEATHER);
|
||||
} else {
|
||||
instanced = false;
|
||||
}
|
||||
if (provider != null && !instanced) {
|
||||
exitState(mc, partialTicks);
|
||||
return useLegacyHandler();
|
||||
}
|
||||
Tracy.plot(P_STRENGTH, rainStrength);
|
||||
|
||||
if (vanillaActive) {
|
||||
buildAxisTable();
|
||||
columns.update(world, entityBlockX, entityBlockZ, radius, updateCount);
|
||||
if (instanced) {
|
||||
final boolean rebuild = SystemProperties.WEATHER_REBUILD_ALWAYS
|
||||
|| updateCount - builtUpdateCount >= REBUILD_TICKS
|
||||
|| columns.revision() != builtRevision
|
||||
|| entityBlockX != builtX || entityBlockY != builtY || entityBlockZ != builtZ
|
||||
|| cameraBlockY != builtCameraY
|
||||
|| radius != builtRadius;
|
||||
if (rebuild) {
|
||||
VANILLA.begin(entityBlockX, entityBlockZ, WeatherInstancedAttribs.SOURCE_VANILLA);
|
||||
VANILLA.beginLayer(RAIN_TEXTURE, WeatherInstancedAttribs.RAIN_PERIOD, 0.0F, 0.0F, WeatherInstancedAttribs.RAIN_FADE);
|
||||
writeColumns(world, true);
|
||||
VANILLA.beginLayer(SNOW_TEXTURE, WeatherInstancedAttribs.SNOW_PERIOD, WeatherInstancedAttribs.SNOW_U_DRIFT, WeatherInstancedAttribs.SNOW_V_DRIFT, WeatherInstancedAttribs.SNOW_FADE);
|
||||
writeColumns(world, false);
|
||||
VANILLA.upload();
|
||||
builtCameraY = cameraBlockY;
|
||||
builtRevision = columns.revision();
|
||||
builtX = entityBlockX;
|
||||
builtY = entityBlockY;
|
||||
builtZ = entityBlockZ;
|
||||
builtRadius = radius;
|
||||
builtUpdateCount = updateCount;
|
||||
}
|
||||
rebuiltThisFrame = rebuild;
|
||||
} else {
|
||||
renderTessellator(mc, world);
|
||||
}
|
||||
}
|
||||
|
||||
renderInstanced(mc, world, view, deferred, partialTicks, rainStrength, radius, updateCount,
|
||||
entityBlockX, entityBlockY, entityBlockZ, cameraX, cameraY, cameraZ, cameraBlockY, startNanos);
|
||||
int providerTick = 0;
|
||||
float providerAge = 0.0F;
|
||||
float providerInvRadius = 0.0F;
|
||||
if (provider != null) {
|
||||
providerTick = provider.beginFrame(world, view, partialTicks);
|
||||
final int revision = provider.columnRevision();
|
||||
final float fadeRadius = provider.fadeRadius();
|
||||
if (!Float.isFinite(fadeRadius) || fadeRadius <= 0.0F) {
|
||||
throw new IllegalArgumentException("Weather fade radius must be finite and positive");
|
||||
}
|
||||
final int dimension = world.provider.dimensionId;
|
||||
if (SystemProperties.WEATHER_REBUILD_ALWAYS
|
||||
|| revision != builtProviderRevision || dimension != builtProviderDimension
|
||||
|| entityBlockX != builtProviderX || entityBlockZ != builtProviderZ) {
|
||||
PROVIDER.begin(entityBlockX, entityBlockZ, WeatherInstancedAttribs.SOURCE_PROVIDER);
|
||||
provider.collectColumns(PROVIDER);
|
||||
PROVIDER.upload();
|
||||
builtProviderRevision = revision;
|
||||
builtProviderDimension = dimension;
|
||||
builtProviderX = entityBlockX;
|
||||
builtProviderZ = entityBlockZ;
|
||||
providerRebuiltThisFrame = true;
|
||||
}
|
||||
providerAge = providerTick + partialTicks;
|
||||
providerInvRadius = 1.0F / fadeRadius;
|
||||
}
|
||||
|
||||
if (instanced && (vanillaActive && VANILLA.count > 0 || provider != null && PROVIDER.count > 0)) {
|
||||
WeatherParams.set((float) (entityBlockX - cameraX), (float) -cameraY, (float) (entityBlockZ - cameraZ),
|
||||
radius > 0 ? 1.0F / radius : 0.0F,
|
||||
(float) (viewPosX - entityBlockX), (float) (viewPosZ - entityBlockZ), partialTicks,
|
||||
updateCount + partialTicks,
|
||||
updateCount, rainStrength, providerTick, providerAge, providerInvRadius);
|
||||
|
||||
GLSMVertexInput.glBindVertexArray(WeatherQuadMesh.vao());
|
||||
if (deferred == null) GLSMPrograms.setFfpInstancing(Instancing.WEATHER);
|
||||
if (vanillaActive) {
|
||||
frameDrawCalls += VANILLA.draw(mc, deferred);
|
||||
frameQuads += VANILLA.count;
|
||||
}
|
||||
if (provider != null) {
|
||||
providerDraws = PROVIDER.draw(mc, deferred);
|
||||
providerColumns = PROVIDER.count;
|
||||
}
|
||||
if (deferred == null) GLSMPrograms.setFfpInstancing(Instancing.NONE);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
if (deferred != null) deferred.rebindCurrentPass();
|
||||
}
|
||||
exitState(mc, partialTicks);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean useLegacyHandler() {
|
||||
Tracy.plot(P_STRENGTH, 0.0);
|
||||
legacyHandler = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void exitState(Minecraft mc, float partialTicks) {
|
||||
GLSMRasterizer.enableCull();
|
||||
GLSMBlend.disableBlend();
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
mc.entityRenderer.disableLightmap(partialTicks);
|
||||
}
|
||||
|
||||
private static DeferredWorldRenderingPipeline deferredPipeline() {
|
||||
if (!AngelicaConfig.enableIris || !Iris.enabled) return null;
|
||||
return Iris.getPipelineManager().getPipelineNullable() instanceof DeferredWorldRenderingPipeline pipeline
|
||||
? pipeline : null;
|
||||
}
|
||||
|
||||
private static void renderInstanced(Minecraft mc, WorldClient world, EntityLivingBase view,
|
||||
DeferredWorldRenderingPipeline deferred, float partialTicks, float rainStrength, int radius,
|
||||
int updateCount, int entityBlockX, int entityBlockY, int entityBlockZ, double cameraX,
|
||||
double cameraY, double cameraZ, int cameraBlockY, long startNanos) {
|
||||
|
||||
final boolean rebuild = SystemProperties.WEATHER_REBUILD_ALWAYS
|
||||
|| updateCount - builtUpdateCount >= REBUILD_TICKS
|
||||
|| columns.revision() != builtRevision
|
||||
|| entityBlockX != builtX || entityBlockY != builtY || entityBlockZ != builtZ
|
||||
|| cameraBlockY != builtCameraY
|
||||
|| radius != builtRadius;
|
||||
if (rebuild) {
|
||||
rebuildInstances(world, radius, entityBlockX, entityBlockY, entityBlockZ, cameraBlockY);
|
||||
builtCameraY = cameraBlockY;
|
||||
builtRevision = columns.revision();
|
||||
builtX = entityBlockX;
|
||||
builtY = entityBlockY;
|
||||
builtZ = entityBlockZ;
|
||||
builtRadius = radius;
|
||||
builtUpdateCount = updateCount;
|
||||
}
|
||||
rebuiltThisFrame = rebuild;
|
||||
|
||||
if (instanceCount == 0) {
|
||||
report(0, 0, startNanos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (deferred != null) {
|
||||
deferred.rebindCurrentPass();
|
||||
if (!deferred.hasInstancedVariant(Instancing.WEATHER)) {
|
||||
renderTessellator(mc, world, view, partialTicks, rainStrength, radius, updateCount,
|
||||
entityBlockX, entityBlockY, entityBlockZ, cameraX, cameraY, cameraZ, cameraBlockY, startNanos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WeatherParams.set((float) (entityBlockX - cameraX), (float) -cameraY, (float) (entityBlockZ - cameraZ),
|
||||
1.0F / radius,
|
||||
(float) (view.posX - entityBlockX), (float) (view.posZ - entityBlockZ), partialTicks,
|
||||
updateCount + partialTicks,
|
||||
updateCount & 31, updateCount & 511, rainStrength);
|
||||
|
||||
mc.entityRenderer.enableLightmap(partialTicks);
|
||||
GLSMRasterizer.disableCull();
|
||||
GLSMCurrentAttribs.glNormal3f(0.0F, 1.0F, 0.0F);
|
||||
GLSMBlend.enableBlend();
|
||||
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
GLSMCurrentAttribs.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
int drawCalls = 0;
|
||||
drawCalls += drawRange(mc, deferred, RAIN_TEXTURE, 0, rainInstances);
|
||||
drawCalls += drawRange(mc, deferred, SNOW_TEXTURE, rainInstances, instanceCount - rainInstances);
|
||||
|
||||
GLSMRasterizer.enableCull();
|
||||
GLSMBlend.disableBlend();
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
mc.entityRenderer.disableLightmap(partialTicks);
|
||||
|
||||
report(instanceCount, drawCalls, startNanos);
|
||||
}
|
||||
|
||||
private static int drawRange(Minecraft mc, DeferredWorldRenderingPipeline deferred,
|
||||
ResourceLocation texture, int first, int count) {
|
||||
if (count <= 0) return 0;
|
||||
mc.getTextureManager().bindTexture(texture);
|
||||
|
||||
if (deferred != null) {
|
||||
deferred.rebindCurrentPass();
|
||||
if (!deferred.hasInstancedVariant(Instancing.WEATHER)) return 0;
|
||||
deferred.bindInstancedVariant(Instancing.WEATHER);
|
||||
}
|
||||
|
||||
GLSMVertexInput.glBindVertexArray(WeatherQuadMesh.vao());
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceBuffer);
|
||||
WeatherInstancedAttribs.pointInstanceAttribs((long) first * WeatherInstancedAttribs.STRIDE);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
VAOManager.setCurrentVertexFlags(WeatherQuadMesh.VERTEX_FLAGS);
|
||||
if (deferred == null) GLSMPrograms.setFfpInstancing(Instancing.WEATHER);
|
||||
GLSMDraws.glDrawArraysInstanced(GL11.GL_TRIANGLE_FAN, 0, WeatherQuadMesh.VERTEX_COUNT, count);
|
||||
GLSMPrograms.setFfpInstancing(Instancing.NONE);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
|
||||
if (deferred != null) deferred.rebindCurrentPass();
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void rebuildInstances(WorldClient world, int radius, int entityBlockX, int entityBlockY,
|
||||
int entityBlockZ, int cameraBlockY) {
|
||||
final int slots = (radius * 2 + 1) * (radius * 2 + 1);
|
||||
final int stride = WeatherInstancedAttribs.STRIDE;
|
||||
if (instanceCapacity < slots) {
|
||||
instanceCapacity = slots;
|
||||
instanceData = ByteBuffer.allocateDirect(slots * stride).order(ByteOrder.nativeOrder());
|
||||
if (instanceBuffer == 0) instanceBuffer = GLSMBuffers.glGenBuffers();
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceBuffer);
|
||||
GLSMBuffers.glBufferData(GL15.GL_ARRAY_BUFFER, (long) slots * stride, GL15.GL_DYNAMIC_DRAW);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
WeatherQuadMesh.bindInstanceBuffer(instanceBuffer);
|
||||
}
|
||||
|
||||
int count = writeColumns(world, radius, entityBlockX, entityBlockY, entityBlockZ, cameraBlockY, true, 0);
|
||||
rainInstances = count;
|
||||
count = writeColumns(world, radius, entityBlockX, entityBlockY, entityBlockZ, cameraBlockY, false, count);
|
||||
instanceCount = count;
|
||||
if (count == 0) return;
|
||||
|
||||
instanceData.position(0);
|
||||
instanceData.limit(count * stride);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, instanceBuffer);
|
||||
GLSMBuffers.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0L, instanceData);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
instanceData.clear();
|
||||
}
|
||||
|
||||
private static int writeColumns(WorldClient world, int radius, int entityBlockX, int entityBlockY,
|
||||
int entityBlockZ, int cameraBlockY, boolean wantRain, int count) {
|
||||
final int stride = WeatherInstancedAttribs.STRIDE;
|
||||
private static void writeColumns(WorldClient world, boolean wantRain) {
|
||||
final WorldChunkManager chunkManager = world.getWorldChunkManager();
|
||||
for (int z = entityBlockZ - radius; z <= entityBlockZ + radius; z++) {
|
||||
for (int x = entityBlockX - radius; x <= entityBlockX + radius; x++) {
|
||||
@@ -371,68 +403,48 @@ public final class WeatherRenderer {
|
||||
if (rain != wantRain) continue;
|
||||
|
||||
final int lightY = Math.max(precipitationHeight, cameraBlockY);
|
||||
int brightness = columns.lightAtSlot(world, slot, x, z, lightY);
|
||||
if (!rain) brightness = (brightness * 3 + 15728880) / 4;
|
||||
final int light = columns.lightAtSlot(world, slot, x, z, lightY);
|
||||
|
||||
final int base = count * stride;
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_COLUMN_SPAN, x - entityBlockX);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_COLUMN_SPAN + 4, z - entityBlockZ);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_COLUMN_SPAN + 8, bottom);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_COLUMN_SPAN + 12, top);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_JITTER, columns.jitterAtSlot(slot, 0));
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_JITTER + 4, columns.jitterAtSlot(slot, 1));
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_JITTER + 8, columns.jitterAtSlot(slot, 2));
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_JITTER + 12, columns.jitterAtSlot(slot, 3));
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_PARAMS, brightness & 0xFFFF);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_PARAMS + 4, brightness >> 16 & 0xFFFF);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_PARAMS + 8, columns.hashAtSlot(slot) & 31);
|
||||
instanceData.putFloat(base + WeatherInstancedAttribs.OFFSET_PARAMS + 12, rain ? 0.0F : 1.0F);
|
||||
count++;
|
||||
final float j0 = columns.jitterAtSlot(slot, 0);
|
||||
VANILLA.put(x, z, bottom, top,
|
||||
rain ? 0.0F : j0, rain ? 0.0F : columns.jitterAtSlot(slot, 1),
|
||||
rain ? 0.0F : columns.jitterAtSlot(slot, 2), rain ? 0.0F : columns.jitterAtSlot(slot, 3),
|
||||
rain ? light : snowBrightness(light), rain ? columns.hashAtSlot(slot) : 0,
|
||||
rain ? WeatherInstancedAttribs.RAIN_SCROLL_BASE + j0 : 1.0F,
|
||||
1.0F, 1.0F, 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void renderTessellator(Minecraft mc, WorldClient world, EntityLivingBase view,
|
||||
float partialTicks, float rainStrength, int radius, int updateCount, int entityBlockX,
|
||||
int entityBlockY, int entityBlockZ, double cameraX, double cameraY, double cameraZ,
|
||||
int cameraBlockY, long startNanos) {
|
||||
|
||||
mc.entityRenderer.enableLightmap(partialTicks);
|
||||
|
||||
private static void renderTessellator(Minecraft mc, WorldClient world) {
|
||||
final float age = updateCount + partialTicks;
|
||||
GLSMRasterizer.disableCull();
|
||||
GLSMCurrentAttribs.glNormal3f(0.0F, 1.0F, 0.0F);
|
||||
GLSMBlend.enableBlend();
|
||||
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
GLSMCurrentAttribs.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
final Tessellator tessellator = Tessellator.instance;
|
||||
final WorldChunkManager chunkManager = world.getWorldChunkManager();
|
||||
int bound = -1;
|
||||
int quads = 0;
|
||||
int drawCalls = 0;
|
||||
|
||||
for (int z = entityBlockZ - radius; z <= entityBlockZ + radius; z++) {
|
||||
for (int x = entityBlockX - radius; x <= entityBlockX + radius; x++) {
|
||||
if (!columns.precipitates(x, z)) continue;
|
||||
final int slot = columns.slotAt(x, z);
|
||||
if (!columns.precipitatesAtSlot(slot)) continue;
|
||||
|
||||
final int precipitationHeight = columns.heightAt(x, z);
|
||||
final int precipitationHeight = columns.heightAtSlot(slot);
|
||||
final int bottom = Math.max(entityBlockY - radius, precipitationHeight);
|
||||
final int top = Math.max(entityBlockY + radius, precipitationHeight);
|
||||
if (bottom == top) continue;
|
||||
|
||||
final int lightY = Math.max(precipitationHeight, cameraBlockY);
|
||||
final float temperature = columns.temperatureAt(x, z, bottom);
|
||||
final boolean rain = world.getWorldChunkManager()
|
||||
.getTemperatureAtHeight(temperature, precipitationHeight) >= 0.15F;
|
||||
final int light = columns.lightAtSlot(world, slot, x, z, lightY);
|
||||
final float temperature = columns.temperatureAtSlot(slot, bottom);
|
||||
final boolean rain = chunkManager.getTemperatureAtHeight(temperature, precipitationHeight) >= 0.15F;
|
||||
|
||||
final int axis = (z - entityBlockZ + 16) * 32 + x - entityBlockX + 16;
|
||||
final float halfX = axisX[axis] * 0.5F;
|
||||
final float halfZ = axisZ[axis] * 0.5F;
|
||||
|
||||
final double offsetX = (x + 0.5F) - view.posX;
|
||||
final double offsetZ = (z + 0.5F) - view.posZ;
|
||||
final double offsetX = (x + 0.5F) - viewPosX;
|
||||
final double offsetZ = (z + 0.5F) - viewPosZ;
|
||||
final float distance = MathHelper.sqrt_double(offsetX * offsetX + offsetZ * offsetZ) / radius;
|
||||
|
||||
if (rain) {
|
||||
@@ -445,13 +457,12 @@ public final class WeatherRenderer {
|
||||
mc.getTextureManager().bindTexture(RAIN_TEXTURE);
|
||||
tessellator.startDrawingQuads();
|
||||
}
|
||||
final float scroll = ((updateCount + columns.hashAt(x, z) & 31) + partialTicks) / 32.0F
|
||||
* (3.0F + columns.jitterAt(x, z, 0));
|
||||
tessellator.setBrightness(columns.lightAt(world, x, z, lightY));
|
||||
final float scroll = ((updateCount + columns.hashAtSlot(slot) & WeatherInstancedAttribs.RAIN_PERIOD - 1) + partialTicks)
|
||||
/ WeatherInstancedAttribs.RAIN_PERIOD * (WeatherInstancedAttribs.RAIN_SCROLL_BASE + columns.jitterAtSlot(slot, 0));
|
||||
tessellator.setBrightness(light);
|
||||
tessellator.setColorRGBA_F(1.0F, 1.0F, 1.0F,
|
||||
((1.0F - distance * distance) * 0.5F + 0.5F) * rainStrength);
|
||||
emit(tessellator, x, z, bottom, top, halfX, halfZ, scroll, 0.0F, 0.0F,
|
||||
cameraX, cameraY, cameraZ);
|
||||
((1.0F - distance * distance) * WeatherInstancedAttribs.RAIN_FADE + 0.5F) * rainStrength);
|
||||
emit(tessellator, x, z, bottom, top, halfX, halfZ, scroll, 0.0F, 0.0F);
|
||||
} else {
|
||||
if (bound != 1) {
|
||||
if (bound == 0) {
|
||||
@@ -462,14 +473,14 @@ public final class WeatherRenderer {
|
||||
mc.getTextureManager().bindTexture(SNOW_TEXTURE);
|
||||
tessellator.startDrawingQuads();
|
||||
}
|
||||
final float scroll = ((updateCount & 511) + partialTicks) / 512.0F;
|
||||
final float driftU = columns.jitterAt(x, z, 0) + age * 0.01F * columns.jitterAt(x, z, 1);
|
||||
final float driftV = columns.jitterAt(x, z, 2) + age * columns.jitterAt(x, z, 3) * 0.001F;
|
||||
tessellator.setBrightness((columns.lightAt(world, x, z, lightY) * 3 + 15728880) / 4);
|
||||
final float scroll = ((updateCount & WeatherInstancedAttribs.SNOW_PERIOD - 1) + partialTicks)
|
||||
/ WeatherInstancedAttribs.SNOW_PERIOD;
|
||||
final float driftU = columns.jitterAtSlot(slot, 0) + age * WeatherInstancedAttribs.SNOW_U_DRIFT * columns.jitterAtSlot(slot, 1);
|
||||
final float driftV = columns.jitterAtSlot(slot, 2) + age * columns.jitterAtSlot(slot, 3) * WeatherInstancedAttribs.SNOW_V_DRIFT;
|
||||
tessellator.setBrightness(snowBrightness(light));
|
||||
tessellator.setColorRGBA_F(1.0F, 1.0F, 1.0F,
|
||||
((1.0F - distance * distance) * 0.3F + 0.5F) * rainStrength);
|
||||
emit(tessellator, x, z, bottom, top, halfX, halfZ, scroll, driftU, driftV,
|
||||
cameraX, cameraY, cameraZ);
|
||||
((1.0F - distance * distance) * WeatherInstancedAttribs.SNOW_FADE + 0.5F) * rainStrength);
|
||||
emit(tessellator, x, z, bottom, top, halfX, halfZ, scroll, driftU, driftV);
|
||||
}
|
||||
quads++;
|
||||
}
|
||||
@@ -480,16 +491,16 @@ public final class WeatherRenderer {
|
||||
drawCalls++;
|
||||
}
|
||||
|
||||
GLSMRasterizer.enableCull();
|
||||
GLSMBlend.disableBlend();
|
||||
GLSMDepthStencilAlpha.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
mc.entityRenderer.disableLightmap(partialTicks);
|
||||
frameQuads += quads;
|
||||
frameDrawCalls += drawCalls;
|
||||
}
|
||||
|
||||
report(quads, drawCalls, startNanos);
|
||||
private static int snowBrightness(int light) {
|
||||
return (light * 3 + 15728880) / 4;
|
||||
}
|
||||
|
||||
private static void emit(Tessellator tessellator, int x, int z, int bottom, int top, float halfX,
|
||||
float halfZ, float scroll, float driftU, float driftV, double cameraX, double cameraY, double cameraZ) {
|
||||
float halfZ, float scroll, float driftU, float driftV) {
|
||||
tessellator.setTranslation(-cameraX, -cameraY, -cameraZ);
|
||||
tessellator.addVertexWithUV(x - halfX + 0.5D, bottom, z - halfZ + 0.5D, driftU, bottom / 4.0F + scroll + driftV);
|
||||
tessellator.addVertexWithUV(x + halfX + 0.5D, bottom, z + halfZ + 0.5D, 1.0F + driftU, bottom / 4.0F + scroll + driftV);
|
||||
@@ -498,12 +509,17 @@ public final class WeatherRenderer {
|
||||
tessellator.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
|
||||
private static void report(int quads, int drawCalls, long startNanos) {
|
||||
Tracy.plotInt(P_QUADS, quads);
|
||||
Tracy.plotInt(P_DRAW_CALLS, drawCalls);
|
||||
private static void report(long startNanos) {
|
||||
Tracy.plotInt(P_QUADS, frameQuads);
|
||||
Tracy.plotInt(P_DRAW_CALLS, frameDrawCalls);
|
||||
Tracy.plotInt(P_REBUILDS, rebuiltThisFrame ? 1 : 0);
|
||||
Tracy.plotInt(P_PROVIDER_COLUMNS, providerColumns);
|
||||
Tracy.plotInt(P_PROVIDER_DRAWS, providerDraws);
|
||||
Tracy.plotInt(P_PROVIDER_REBUILDS, providerRebuiltThisFrame ? 1 : 0);
|
||||
Tracy.plotInt(P_LEGACY_HANDLER, legacyHandler ? 1 : 0);
|
||||
Tracy.plot(P_MICROS, (System.nanoTime() - startNanos) / 1000.0);
|
||||
rebuiltThisFrame = false;
|
||||
providerRebuiltThisFrame = false;
|
||||
}
|
||||
|
||||
private static void buildAxisTable() {
|
||||
@@ -522,14 +538,145 @@ public final class WeatherRenderer {
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
VANILLA.release();
|
||||
PROVIDER.release();
|
||||
WeatherQuadMesh.delete();
|
||||
if (instanceBuffer != 0) {
|
||||
GLSMBuffers.glDeleteBuffers(instanceBuffer);
|
||||
instanceBuffer = 0;
|
||||
builtRevision = Integer.MIN_VALUE;
|
||||
builtX = Integer.MIN_VALUE;
|
||||
builtY = Integer.MIN_VALUE;
|
||||
builtZ = Integer.MIN_VALUE;
|
||||
builtRadius = -1;
|
||||
builtUpdateCount = Integer.MIN_VALUE;
|
||||
builtCameraY = Integer.MIN_VALUE;
|
||||
builtProviderRevision = Integer.MIN_VALUE;
|
||||
builtProviderDimension = Integer.MIN_VALUE;
|
||||
builtProviderX = Integer.MIN_VALUE;
|
||||
builtProviderZ = Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
private static final class WeatherBatch implements WeatherColumnSink {
|
||||
|
||||
private static final int STRIDE = WeatherInstancedAttribs.STRIDE;
|
||||
private static final int MIN_CAPACITY = 256;
|
||||
|
||||
private ByteBuffer data;
|
||||
private int capacity;
|
||||
private int count;
|
||||
private ResourceLocation[] textures = new ResourceLocation[4];
|
||||
private int[] firsts = new int[4];
|
||||
private int layers;
|
||||
private int originX;
|
||||
private int originZ;
|
||||
private float source;
|
||||
private int period;
|
||||
private float uDriftScale;
|
||||
private float vDriftScale;
|
||||
private float fadeScale;
|
||||
private int buffer;
|
||||
private int bufferCapacity;
|
||||
|
||||
void begin(int originX, int originZ, float source) {
|
||||
this.originX = originX;
|
||||
this.originZ = originZ;
|
||||
this.source = source;
|
||||
Arrays.fill(textures, 0, layers, null);
|
||||
layers = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
void upload() {
|
||||
if (count == 0) return;
|
||||
if (buffer == 0) buffer = GLSMBuffers.glGenBuffers();
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, buffer);
|
||||
if (bufferCapacity < count) {
|
||||
bufferCapacity = capacity;
|
||||
GLSMBuffers.glBufferData(GL15.GL_ARRAY_BUFFER, (long) bufferCapacity * STRIDE, GL15.GL_DYNAMIC_DRAW);
|
||||
}
|
||||
data.position(0);
|
||||
data.limit(count * STRIDE);
|
||||
GLSMBuffers.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0L, data);
|
||||
data.clear();
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
int draw(Minecraft mc, DeferredWorldRenderingPipeline deferred) {
|
||||
int draws = 0;
|
||||
for (int layer = 0; layer < layers; layer++) {
|
||||
final int first = firsts[layer];
|
||||
final int layerCount = (layer + 1 < layers ? firsts[layer + 1] : count) - first;
|
||||
if (layerCount == 0) continue;
|
||||
mc.getTextureManager().bindTexture(textures[layer]);
|
||||
if (deferred != null) deferred.bindInstancedVariant(Instancing.WEATHER);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, buffer);
|
||||
WeatherInstancedAttribs.pointInstanceAttribs((long) first * STRIDE);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
VAOManager.setCurrentVertexFlags(WeatherQuadMesh.VERTEX_FLAGS);
|
||||
GLSMDraws.glDrawArraysInstanced(GL11.GL_TRIANGLE_FAN, 0, WeatherQuadMesh.VERTEX_COUNT, layerCount);
|
||||
draws++;
|
||||
}
|
||||
return draws;
|
||||
}
|
||||
|
||||
void release() {
|
||||
begin(0, 0, 0.0F);
|
||||
data = null;
|
||||
capacity = 0;
|
||||
if (buffer != 0) {
|
||||
GLSMBuffers.glDeleteBuffers(buffer);
|
||||
buffer = 0;
|
||||
}
|
||||
bufferCapacity = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginLayer(ResourceLocation texture, int scrollPeriod, float uDriftScale, float vDriftScale, float fadeScale) {
|
||||
if (texture == null) throw new IllegalArgumentException("Weather layer texture must not be null");
|
||||
if (scrollPeriod < 1 || scrollPeriod > WeatherParams.TICK_WRAP || (scrollPeriod & scrollPeriod - 1) != 0) {
|
||||
throw new IllegalArgumentException("Weather layer scroll period must be a power of two between 1 and " + WeatherParams.TICK_WRAP);
|
||||
}
|
||||
if (!Float.isFinite(uDriftScale) || !Float.isFinite(vDriftScale) || !Float.isFinite(fadeScale)) {
|
||||
throw new IllegalArgumentException("Weather layer scales must be finite");
|
||||
}
|
||||
if (layers == textures.length) {
|
||||
textures = Arrays.copyOf(textures, layers * 2);
|
||||
firsts = Arrays.copyOf(firsts, layers * 2);
|
||||
}
|
||||
textures[layers] = texture;
|
||||
firsts[layers] = count;
|
||||
layers++;
|
||||
period = scrollPeriod;
|
||||
this.uDriftScale = uDriftScale;
|
||||
this.vDriftScale = vDriftScale;
|
||||
this.fadeScale = fadeScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void column(int x, int z, float bottom, float top, float uBase, float uDrift, float vBase, float vDrift,
|
||||
int brightness, int scrollOffset, float scrollScale, float r, float g, float b, float a) {
|
||||
if (layers == 0) throw new IllegalStateException("Weather column written before beginLayer");
|
||||
if (brightness < 0 || brightness >= 1 << 24) {
|
||||
throw new IllegalArgumentException("Weather column brightness must be a packed lightmap coordinate below 2^24");
|
||||
}
|
||||
put(x, z, bottom, top, uBase, uDrift, vBase, vDrift, brightness, scrollOffset, scrollScale, r, g, b, a);
|
||||
}
|
||||
|
||||
void put(int x, int z, float bottom, float top, float uBase, float uDrift, float vBase, float vDrift, int brightness, int scrollOffset, float scrollScale, float r, float g, float b, float a) {
|
||||
if (count == capacity) grow();
|
||||
WeatherInstancedAttribs.putColumn(data, count, x - originX, z - originZ, bottom, top, uBase, uDrift, vBase, vDrift, brightness, scrollOffset, scrollScale, source, r, g, b, a, period, uDriftScale, vDriftScale, fadeScale);
|
||||
count++;
|
||||
}
|
||||
|
||||
private void grow() {
|
||||
final int grownCapacity = Math.max(MIN_CAPACITY, capacity * 2);
|
||||
final ByteBuffer grown = ByteBuffer.allocateDirect(grownCapacity * STRIDE).order(ByteOrder.nativeOrder());
|
||||
if (count > 0) {
|
||||
data.position(0);
|
||||
data.limit(count * STRIDE);
|
||||
grown.put(data);
|
||||
grown.clear();
|
||||
}
|
||||
data = grown;
|
||||
capacity = grownCapacity;
|
||||
}
|
||||
instanceData = null;
|
||||
instanceCapacity = 0;
|
||||
instanceCount = 0;
|
||||
rainInstances = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrMaterial;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrMeshProvider;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrMeshSink;
|
||||
import com.gtnewhorizons.angelica.common.TileTesrTranslucentTest;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMCurrentAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDepthStencilAlpha;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMEnable;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMMatrices;
|
||||
import com.gtnewhorizons.angelica.utils.WorkaroundUtils;
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
import net.minecraft.client.model.ModelRenderer;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public final class TesrTranslucentTestRenderers {
|
||||
|
||||
private static final double HALF = 0.4375;
|
||||
|
||||
private TesrTranslucentTestRenderers() {}
|
||||
|
||||
private static void pane(Tessellator t, double half) {
|
||||
rect(t, -half, -half, half, half);
|
||||
}
|
||||
|
||||
private static void rect(Tessellator t, double x0, double y0, double x1, double y1) {
|
||||
t.setNormal(0f, 0f, -1f);
|
||||
t.addVertexWithUV(0.5 + x0, 0.5 + y0, 0.5, 0, 1);
|
||||
t.addVertexWithUV(0.5 + x0, 0.5 + y1, 0.5, 0, 0);
|
||||
t.addVertexWithUV(0.5 + x1, 0.5 + y1, 0.5, 1, 0);
|
||||
t.addVertexWithUV(0.5 + x1, 0.5 + y0, 0.5, 1, 1);
|
||||
}
|
||||
|
||||
private static void drawPane(double half) {
|
||||
final Tessellator t = Tessellator.instance;
|
||||
t.startDrawingQuads();
|
||||
pane(t, half);
|
||||
t.draw();
|
||||
}
|
||||
|
||||
private static void apply(TesrMaterial material) {
|
||||
if (material.transparency() == TesrMaterial.Transparency.ADDITIVE) {
|
||||
GLSMBlend.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
|
||||
} else {
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
GLSMCurrentAttribs.glColor4f(material.colorRed(), material.colorGreen(), material.colorBlue(), material.colorAlpha());
|
||||
}
|
||||
|
||||
private abstract static class PaneRenderer extends TileEntitySpecialRenderer {
|
||||
|
||||
void begin(double x, double y, double z) {
|
||||
bindTexture(WorkaroundUtils.GL_TEXTURE_2D_WORKAROUND);
|
||||
GLSMMatrices.glPushMatrix();
|
||||
GLSMMatrices.glTranslated(x, y, z);
|
||||
GLSMEnable.glDisable(GL11.GL_CULL_FACE);
|
||||
GLSMEnable.glEnable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
static void end() {
|
||||
GLSMCurrentAttribs.glColor4f(1f, 1f, 1f, 1f);
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
GLSMEnable.glDisable(GL11.GL_BLEND);
|
||||
GLSMEnable.glEnable(GL11.GL_CULL_FACE);
|
||||
GLSMMatrices.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Provider extends PaneRenderer implements TesrMeshProvider {
|
||||
|
||||
private static final TesrMaterial[] MATERIALS = {
|
||||
TesrMaterial.builder().color(1f, 0f, 0f, 0.5f).translucent().noCull().build(),
|
||||
TesrMaterial.builder().color(0.5f, 0f, 0.5f, 1f).additive().noCull().build() };
|
||||
private static final Object[] KEYS = { new Object(), new Object() };
|
||||
|
||||
private static int kind(TileEntity te) {
|
||||
return ((TileTesrTranslucentTest) te).variant() == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object angelica$meshKey(TileEntity te) {
|
||||
return KEYS[kind(te)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void angelica$build(TesrMeshSink sink, TileEntity te) {
|
||||
pane(sink.angelica$bucket(DefaultVertexFormat.POSITION_TEXTURE_NORMAL, WorkaroundUtils.GL_TEXTURE_2D_WORKAROUND, MATERIALS[kind(te)]), HALF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTicks) {
|
||||
begin(x, y, z);
|
||||
apply(MATERIALS[kind(te)]);
|
||||
drawPane(HALF);
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Model extends PaneRenderer {
|
||||
|
||||
private static final TesrMaterial TRANSLUCENT_GREEN = TesrMaterial.builder().color(0f, 1f, 0f, 0.5f).translucent().build();
|
||||
private static final TesrMaterial TRANSLUCENT_YELLOW = TesrMaterial.builder().color(1f, 1f, 0f, 0.5f).translucent().build();
|
||||
private static final TesrMaterial TRANSLUCENT_MAGENTA = TesrMaterial.builder().color(1f, 0f, 1f, 0.5f).translucent().build();
|
||||
private static final TesrMaterial ADDITIVE_CYAN = TesrMaterial.builder().color(0f, 0.6f, 0.6f, 1f).additive().build();
|
||||
|
||||
private final ModelBase model = new ModelBase() {};
|
||||
private final ModelRenderer base = new ModelRenderer(model, 0, 0);
|
||||
private final ModelRenderer pane = paneAt(0f);
|
||||
private final ModelRenderer paneFar = paneAt(0.16f);
|
||||
private final ModelRenderer paneNear = paneAt(-0.16f);
|
||||
|
||||
public Model() {
|
||||
base.addBox(-1f, 7f, -1f, 2, 1, 2);
|
||||
}
|
||||
|
||||
private ModelRenderer paneAt(float z) {
|
||||
final ModelRenderer renderer = new ModelRenderer(model, 0, 0);
|
||||
renderer.addBox(-7f, -7f, z, 14, 14, 0);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTicks) {
|
||||
final float scale = 1f / 16f;
|
||||
bindTexture(WorkaroundUtils.GL_TEXTURE_2D_WORKAROUND);
|
||||
GLSMMatrices.glPushMatrix();
|
||||
GLSMMatrices.glTranslated(x + 0.5, y + 0.5, z + 0.5);
|
||||
GLSMCurrentAttribs.glColor4f(1f, 1f, 1f, 1f);
|
||||
base.render(scale);
|
||||
GLSMEnable.glEnable(GL11.GL_BLEND);
|
||||
switch (((TileTesrTranslucentTest) te).variant()) {
|
||||
case 0 -> {
|
||||
apply(TRANSLUCENT_GREEN);
|
||||
pane.render(scale);
|
||||
}
|
||||
case 1 -> {
|
||||
apply(TRANSLUCENT_YELLOW);
|
||||
GLSMMatrices.glTranslated(-0.5, -0.5, -0.5);
|
||||
drawPane(HALF);
|
||||
}
|
||||
default -> {
|
||||
apply(TRANSLUCENT_MAGENTA);
|
||||
paneFar.render(scale);
|
||||
apply(ADDITIVE_CYAN);
|
||||
pane.render(scale);
|
||||
apply(TRANSLUCENT_GREEN);
|
||||
paneNear.render(scale);
|
||||
}
|
||||
}
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Decal extends PaneRenderer implements TesrMeshProvider {
|
||||
|
||||
private static final TesrMaterial WRITER = TesrMaterial.builder().color(1f, 1f, 1f, 0.5f).translucent().noCull().build();
|
||||
private static final TesrMaterial DECAL = TesrMaterial.builder().color(0f, 0f, 0f, 0.8f).translucent().depthEqual().noCull().build();
|
||||
private static final Object KEY = new Object();
|
||||
private static final double INNER = HALF / 2;
|
||||
|
||||
private static void writer(Tessellator t) {
|
||||
rect(t, -HALF, INNER, HALF, HALF);
|
||||
rect(t, -HALF, -HALF, HALF, -INNER);
|
||||
rect(t, -HALF, -INNER, -INNER, INNER);
|
||||
rect(t, INNER, -INNER, HALF, INNER);
|
||||
pane(t, INNER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object angelica$meshKey(TileEntity te) {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void angelica$build(TesrMeshSink sink, TileEntity te) {
|
||||
writer(sink.angelica$bucket(DefaultVertexFormat.POSITION_TEXTURE_NORMAL, WorkaroundUtils.GL_TEXTURE_2D_WORKAROUND, WRITER));
|
||||
pane(sink.angelica$bucket(DefaultVertexFormat.POSITION_TEXTURE_NORMAL, WorkaroundUtils.GL_TEXTURE_2D_WORKAROUND, DECAL), INNER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTicks) {
|
||||
begin(x, y, z);
|
||||
apply(WRITER);
|
||||
final Tessellator t = Tessellator.instance;
|
||||
t.startDrawingQuads();
|
||||
writer(t);
|
||||
t.draw();
|
||||
GLSMDepthStencilAlpha.glDepthFunc(GL11.GL_EQUAL);
|
||||
apply(DECAL);
|
||||
drawPane(INNER);
|
||||
GLSMDepthStencilAlpha.glDepthFunc(GL11.GL_LEQUAL);
|
||||
end();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Glow extends PaneRenderer {
|
||||
|
||||
private static final TesrMaterial TRANSLUCENT_ORANGE = TesrMaterial.builder().color(1f, 0.5f, 0f, 0.6f).translucent().build();
|
||||
|
||||
@Override
|
||||
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float partialTicks) {
|
||||
begin(x, y, z);
|
||||
apply(TRANSLUCENT_ORANGE);
|
||||
GLSMDepthStencilAlpha.glDepthMask(false);
|
||||
drawPane(HALF);
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
end();
|
||||
}
|
||||
}
|
||||
}
|
||||
+73
-34
@@ -14,12 +14,16 @@ import com.gtnewhorizons.angelica.rendering.celeritas.iris.ContextAwareChunkVert
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.threading.RenderPassHelper;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.SectionBuiltBlockEntity;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.utils.NaturalTextureUtils;
|
||||
import com.gtnewhorizons.liquidlogged.api.LiquidLoggedAPI;
|
||||
import com.gtnewhorizons.liquidlogged.api.LiquidLoggedRenderAPI;
|
||||
import com.prupe.mcpatcher.mal.block.RenderBlocksUtils;
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||
import mega.fluidlogged.api.FLBlockAccess;
|
||||
import net.coderbot.iris.block_rendering.BlockMaterialMapping;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.block_rendering.NbtConditionalIdMap;
|
||||
@@ -39,6 +43,7 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.RenderSection;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.compile.ChunkBuildBuffers;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.compile.ChunkBuildContext;
|
||||
@@ -254,39 +259,13 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
|
||||
final boolean canRenderOffThread = !handoff || !isDeferred(deferredMask, x, y, z);
|
||||
|
||||
// Check for shader pack override
|
||||
final BlockRenderLayer override = blockTypeIds != null ? blockTypeIds.get(block) : null;
|
||||
int deferredPasses = 0;
|
||||
Material deferredOverride = null;
|
||||
renderBlockPasses(block, meta, x, y, z, canRenderOffThread, blockTypeIds, deferredBlocks, tessellator, renderBlocks, buffers, buildContext, blockRenderContext, minX, minY, minZ, teMap, currentTick);
|
||||
|
||||
for (int pass = 0; pass < AngelicaChunkBuildContext.NUM_PASSES; pass++) {
|
||||
final boolean canRender;
|
||||
Material materialOverride = null;
|
||||
|
||||
if (override != null) {
|
||||
// Shader pack override controls both pass and material
|
||||
canRender = (pass == override.toVanillaPass());
|
||||
if (canRender) {
|
||||
materialOverride = buffers.getRenderPassConfiguration().getMaterialForRenderType(override);
|
||||
}
|
||||
} else {
|
||||
// Normal block rendering
|
||||
canRender = !canRenderOffThread || block.canRenderInPass(pass);
|
||||
}
|
||||
|
||||
if (canRender) {
|
||||
final boolean isShaderPackOverride = materialOverride != null;
|
||||
if (!canRenderOffThread) {
|
||||
deferredPasses |= 1 << pass;
|
||||
deferredOverride = materialOverride;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderBlock(block, meta, x, y, z, pass, tessellator, renderBlocks, buffers, buildContext, blockRenderContext, minX, minY, minZ, materialOverride, isShaderPackOverride, teMap, currentTick);
|
||||
}
|
||||
}
|
||||
if (deferredPasses != 0) {
|
||||
deferredBlocks.add(new DeferredBlock(x, y, z, block, meta, deferredPasses, deferredOverride));
|
||||
// FluidLogged stores the fluid apart from the block, and this loop only sees the block
|
||||
final Block loggedFluid = getLoggedFluidBlock(region, x, y, z);
|
||||
if (loggedFluid != null) {
|
||||
if (reportingSlice != null) reportingSlice.setRenderingBlock(loggedFluid);
|
||||
renderBlockPasses(loggedFluid, 0, x, y, z, canRenderOffThread, blockTypeIds, deferredBlocks, tessellator, renderBlocks, buffers, buildContext, blockRenderContext, minX, minY, minZ, teMap, currentTick);
|
||||
}
|
||||
|
||||
if (block.isOpaqueCube()) {
|
||||
@@ -345,7 +324,11 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
final Block block = region.getBlock(minX + x, minY + y, minZ + z);
|
||||
if (block != Blocks.air && !canRenderOffThread(block)) {
|
||||
if (block == Blocks.air) {
|
||||
continue;
|
||||
}
|
||||
final Block loggedFluid = getLoggedFluidBlock(region, minX + x, minY + y, minZ + z);
|
||||
if (!canRenderOffThread(block) || (loggedFluid != null && !canRenderOffThread(loggedFluid))) {
|
||||
final int bit = (y << 8) | (z << 4) | x;
|
||||
mask[bit >>> 6] |= 1L << bit;
|
||||
any = true;
|
||||
@@ -361,6 +344,18 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
return (mask[bit >>> 6] & (1L << bit)) != 0;
|
||||
}
|
||||
|
||||
private static Block getLoggedFluidBlock(IBlockAccess region, int x, int y, int z) {
|
||||
final Fluid fluid;
|
||||
if (ModStatus.isLiquidLoggedLoaded) {
|
||||
fluid = LiquidLoggedAPI.getFluid(region, x, y, z);
|
||||
} else if (ModStatus.isFluidLoggedLoaded && region instanceof FLBlockAccess fluidAccess) {
|
||||
fluid = fluidAccess.fl$getFluid(x, y, z);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return fluid != null ? fluid.getBlock() : null;
|
||||
}
|
||||
|
||||
ChunkJobResult<ChunkBuildOutput> captureDeferred(DeferredSectionMesh m) {
|
||||
final long start = System.nanoTime();
|
||||
|
||||
@@ -497,6 +492,43 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
return new ChunkBuildOutput(this.render, renderData, meshes, this.buildTime);
|
||||
}
|
||||
|
||||
private void renderBlockPasses(Block block, int meta, int x, int y, int z, boolean canRenderOffThread, Map<Block, BlockRenderLayer> blockTypeIds, List<DeferredBlock> deferredBlocks, Tessellator tessellator, RenderBlocks renderBlocks, ChunkBuildBuffers buffers, AngelicaChunkBuildContext buildContext, BlockRenderContext blockRenderContext, int originX, int originY, int originZ, NbtConditionalIdMap<Block> teMap, long currentTick) {
|
||||
// Check for shader pack override
|
||||
final BlockRenderLayer override = blockTypeIds != null ? blockTypeIds.get(block) : null;
|
||||
int deferredPasses = 0;
|
||||
Material deferredOverride = null;
|
||||
|
||||
for (int pass = 0; pass < AngelicaChunkBuildContext.NUM_PASSES; pass++) {
|
||||
final boolean canRender;
|
||||
Material materialOverride = null;
|
||||
|
||||
if (override != null) {
|
||||
// Shader pack override controls both pass and material
|
||||
canRender = (pass == override.toVanillaPass());
|
||||
if (canRender) {
|
||||
materialOverride = buffers.getRenderPassConfiguration().getMaterialForRenderType(override);
|
||||
}
|
||||
} else {
|
||||
// Normal block rendering
|
||||
canRender = !canRenderOffThread || block.canRenderInPass(pass);
|
||||
}
|
||||
|
||||
if (canRender) {
|
||||
final boolean isShaderPackOverride = materialOverride != null;
|
||||
if (!canRenderOffThread) {
|
||||
deferredPasses |= 1 << pass;
|
||||
deferredOverride = materialOverride;
|
||||
continue;
|
||||
}
|
||||
|
||||
renderBlock(block, meta, x, y, z, pass, tessellator, renderBlocks, buffers, buildContext, blockRenderContext, originX, originY, originZ, materialOverride, isShaderPackOverride, teMap, currentTick);
|
||||
}
|
||||
}
|
||||
if (deferredPasses != 0) {
|
||||
deferredBlocks.add(new DeferredBlock(x, y, z, block, meta, deferredPasses, deferredOverride));
|
||||
}
|
||||
}
|
||||
|
||||
protected void renderBlock(Block block, int metadata, int x, int y, int z, int pass, Tessellator tessellator, RenderBlocks renderBlocks, ChunkBuildBuffers buffers, AngelicaChunkBuildContext buildContext, BlockRenderContext blockRenderContext, int originX, int originY, int originZ, Material materialOverride, boolean isShaderPackOverride, NbtConditionalIdMap<Block> teMap, long currentTick) {
|
||||
final Material passMaterial = resolvePassMaterial(block, pass, buffers, materialOverride);
|
||||
final int teBlockId = resolveTeBlockId(teMap, renderBlocks.blockAccess, block, metadata, x, y, z, buffers, pass, materialOverride, currentTick);
|
||||
@@ -587,7 +619,14 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
if (applyNaturalTex) { renderBlocks.uvRotateTop = NaturalTextureUtils.getTopRotation(x, y, z); }
|
||||
|
||||
tessellator.startDrawingQuads();
|
||||
renderBlocks.renderBlockByRenderType(block, x, y, z);
|
||||
// A block that differs from the cell's own block is the fluid stored in it
|
||||
final boolean storedFluid = ModStatus.isLiquidLoggedLoaded && renderBlocks.blockAccess.getBlock(x, y, z) != block;
|
||||
if (storedFluid) LiquidLoggedRenderAPI.beginStoredFluid();
|
||||
try {
|
||||
renderBlocks.renderBlockByRenderType(block, x, y, z);
|
||||
} finally {
|
||||
if (storedFluid) LiquidLoggedRenderAPI.endStoredFluid();
|
||||
}
|
||||
|
||||
if (applyNaturalTex) { renderBlocks.uvRotateTop = 0; } // Reset
|
||||
}
|
||||
|
||||
-3
@@ -13,7 +13,6 @@ import com.gtnewhorizons.angelica.rendering.TextureSamplers;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProvider;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHolder;
|
||||
import com.gtnewhorizons.angelica.rendering.culling.GpuCulling;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import me.jellysquid.mods.sodium.client.gui.SodiumGameOptions;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.MultiDrawMode;
|
||||
import com.gtnewhorizons.angelica.rendering.voxelization.SdlShadowVoxelizationSink;
|
||||
@@ -197,7 +196,6 @@ class AngelicaChunkRenderer extends DefaultChunkRenderer {
|
||||
if (program != null) {
|
||||
program.bind();
|
||||
program.getInterface().setupState(pass);
|
||||
if (pass == AngelicaRenderPassConfiguration.TRANSLUCENT_PASS) TranslucencyLayers.INSTANCE.beginTerrainSplit(program.handle());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +204,6 @@ class AngelicaChunkRenderer extends DefaultChunkRenderer {
|
||||
if (irisProgram != null) {
|
||||
endIrisPass(pass);
|
||||
} else {
|
||||
if (pass == AngelicaRenderPassConfiguration.TRANSLUCENT_PASS) TranslucencyLayers.INSTANCE.endTerrainSplit();
|
||||
super.end(pass);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -80,8 +80,7 @@ public class AngelicaRenderPassConfiguration {
|
||||
TRANSLUCENT_PASS = builderForRenderType(1, false, translucentCutoff, vertexType)
|
||||
.name("translucent")
|
||||
.useReverseOrder(true)
|
||||
.useTranslucencySorting(ClientProxy.options().performance.translucencyMode.sorts())
|
||||
.extraDefine("TRANSLUCENCY_SPLIT", "")
|
||||
.useTranslucencySorting(ClientProxy.options().performance.translucencySorting)
|
||||
.build();
|
||||
|
||||
TRANSLUCENT_MATERIAL = new Material(TRANSLUCENT_PASS, translucentCutoff, true);
|
||||
|
||||
+38
-156
@@ -1,19 +1,19 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.bop.FogBiomeCache;
|
||||
import com.gtnewhorizons.angelica.render.CloudRenderer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
@@ -37,22 +37,15 @@ import org.embeddedt.embeddium.impl.render.viewport.frustum.SimpleFrustum;
|
||||
import org.joml.FrustumIntersection;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.compat.cubicchunks.CubicChunksAPI;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.IDynamicLightWorldRenderer;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMAttribStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMCurrentAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDepthStencilAlpha;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMMatrices;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMRasterizer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.StateSet;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ITileEntityBoundingBoxCache;
|
||||
@@ -65,8 +58,6 @@ import com.gtnewhorizons.angelica.rendering.culling.GpuCulling;
|
||||
import com.gtnewhorizons.angelica.render.WeatherRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.culling.GpuTerrainCuller;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.AngelicaTesrMeshCache;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.GlowReplayExclusions;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.ImmediateDrawOrder;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.ModelPartBatcher;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.PendingTesrDraws;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.SectionBuiltBlockEntity;
|
||||
@@ -75,12 +66,6 @@ import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHold
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrAttribution;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrBatchRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrLifecycle;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrProviderDispatch;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TranslucentPeel;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucentLayer;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.ShadowRenderer;
|
||||
|
||||
public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, AngelicaRenderSectionManager, BlockRenderLayer, TileEntity, CeleritasWorldRenderer.TileEntityRenderContext> implements IDynamicLightWorldRenderer {
|
||||
@@ -90,7 +75,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
private static final Tracy.ZoneId Z_TESR_DISPATCH = Tracy.zoneId("tesrDispatch", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_MODEL_PARTS = Tracy.zoneId("tesrModelParts", Tracy.COLOR_CLIENT);
|
||||
private static final Tracy.ZoneId Z_TESR_RENDER_TE = Tracy.zoneId("tesrRenderTE", Tracy.COLOR_CLIENT);
|
||||
private static final long P_BLOCK_ENTITIES_RENDERED = Tracy.plotHandle("blockEntitiesRendered");
|
||||
|
||||
private final Minecraft mc;
|
||||
private static CeleritasWorldRenderer instance;
|
||||
@@ -110,13 +94,10 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
|
||||
private final ObjectArrayList<TileEntity> frameTEs = new ObjectArrayList<>();
|
||||
private final ObjectArrayList<TileEntity> frameOverride = new ObjectArrayList<>();
|
||||
private final ObjectArrayList<TileEntity> glowReplay = new ObjectArrayList<>();
|
||||
|
||||
private final TileEntityDepthOrder depthOrder = new TileEntityDepthOrder();
|
||||
private final Matrix4f savedTextureMatrix = new Matrix4f();
|
||||
private PassOne passOne = PassOne.NONE;
|
||||
|
||||
private enum PassOne { NONE, PENDING, DRAWN_EARLY }
|
||||
// For sorting transparent TESRs
|
||||
private final TileEntityOrderer tileEntityOrderer = new TileEntityOrderer();
|
||||
private final ArrayList<TileEntity> sortedTileEntities = new ArrayList<>();
|
||||
|
||||
private CeleritasWorldRenderer(Minecraft mc) {
|
||||
// Private constructor for singleton
|
||||
@@ -191,6 +172,7 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
DynamicLights.setActiveRenderer(null);
|
||||
this.frameTEs.clear();
|
||||
this.frameOverride.clear();
|
||||
this.sortedTileEntities.clear();
|
||||
ShadowRenderer.visibleTileEntities.clear();
|
||||
ShadowRenderer.globalTileEntities.clear();
|
||||
TesrLifecycle.reset();
|
||||
@@ -403,15 +385,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
return camera;
|
||||
}
|
||||
|
||||
public boolean hasVisibleLayer(BlockRenderLayer renderLayer) {
|
||||
final Collection<TerrainRenderPass> passes = this.renderSectionManager.getRenderPassConfiguration().vanillaRenderStages().get(renderLayer);
|
||||
if (passes == null) return false;
|
||||
for (final TerrainRenderPass pass : passes) {
|
||||
if (this.renderSectionManager.getRenderLists().hasPass(pass)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawChunkLayer(BlockRenderLayer renderLayer, double x, double y, double z) {
|
||||
if (DEBUG_WIREFRAME_MODE) {
|
||||
@@ -435,116 +408,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
GLSMCurrentAttribs.glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
public void renderBlockEntitiesBeforeTranslucent(float partialTicks) {
|
||||
if (passOne != PassOne.PENDING) return;
|
||||
passOne = PassOne.DRAWN_EARLY;
|
||||
glowReplay.clear();
|
||||
if (!anyRendersInPassOne()) return;
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
final boolean layered = TranslucencyLayers.INSTANCE.active();
|
||||
final int previousPass = MinecraftForgeClient.getRenderPass();
|
||||
final int depth = GLSMAttribStack.pushState(StateSet.BLOCK_ENTITY_PASS);
|
||||
savedTextureMatrix.set(GLSMTextures.getTextures().getTextureUnitMatrix(0));
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLSMMatrices.glPushMatrix();
|
||||
try {
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
GLSMDepthStencilAlpha.enableAlphaTest();
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
GLSMTextures.enableTexture();
|
||||
GLSMCurrentAttribs.glColor4f(1f, 1f, 1f, 1f);
|
||||
// A layer reads its color as premultiplied, which a blend-disabled draw does not write (TranslucencyLayers).
|
||||
if (layered) {
|
||||
GLSMBlend.enableBlend();
|
||||
GLSMBlend.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
} else if (mc.gameSettings.fancyGraphics) {
|
||||
GLSMBlend.disableBlend();
|
||||
}
|
||||
if (mc.gameSettings.fancyGraphics) GLSMRasterizer.glShadeModel(GL11.GL_FLAT);
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
mc.entityRenderer.enableLightmap(partialTicks);
|
||||
ForgeHooksClient.setRenderPass(1);
|
||||
if (layered) TranslucencyLayers.INSTANCE.begin(TranslucentLayer.BLOCK_ENTITIES);
|
||||
try {
|
||||
renderBlockEntitiesInPhase(partialTicks);
|
||||
if (layered) replayGlowDepth(partialTicks);
|
||||
} finally {
|
||||
if (layered) TranslucencyLayers.INSTANCE.end();
|
||||
}
|
||||
} finally {
|
||||
ForgeHooksClient.setRenderPass(previousPass);
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLSMMatrices.glPopMatrix();
|
||||
GLSMMatrices.setTextureMatrix(0, savedTextureMatrix);
|
||||
GLSMAttribStack.popStateTo(depth);
|
||||
}
|
||||
}
|
||||
|
||||
private void replayGlowDepth(float partialTicks) {
|
||||
if (glowReplay.isEmpty()) return;
|
||||
try {
|
||||
if (!TranslucencyLayers.INSTANCE.beginGlowReplay()) return;
|
||||
try {
|
||||
for (int i = 0; i < glowReplay.size(); i++) {
|
||||
replayTE(glowReplay.get(i), partialTicks);
|
||||
}
|
||||
} finally {
|
||||
TranslucencyLayers.INSTANCE.endGlowReplay();
|
||||
}
|
||||
} finally {
|
||||
glowReplay.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls the renderer directly, since a depth-only replay must not feed the dispatcher's lighting or
|
||||
/// batch-eligibility tracking.
|
||||
private static void replayTE(TileEntity tileEntity, float partialTicks) {
|
||||
final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRenderer(tileEntity);
|
||||
if (renderer == null) return;
|
||||
final double x = tileEntity.xCoord - TileEntityRendererDispatcher.staticPlayerX;
|
||||
final double y = tileEntity.yCoord - TileEntityRendererDispatcher.staticPlayerY;
|
||||
final double z = tileEntity.zCoord - TileEntityRendererDispatcher.staticPlayerZ;
|
||||
final int depth = GLSMAttribStack.pushState(StateSet.BLEND);
|
||||
GLSMCurrentAttribs.glColor4f(1f, 1f, 1f, 1f);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
TesrBatchRenderer.INSTANCE.beginScope();
|
||||
try {
|
||||
if (AngelicaConfig.enableTESRProviderDispatch && TesrProviderDispatch.tryRender(renderer, tileEntity, x, y, z)) return;
|
||||
renderer.renderTileEntityAt(tileEntity, x, y, z, partialTicks);
|
||||
} catch (RuntimeException e) {
|
||||
if (!tileEntity.isInvalid()) throw e;
|
||||
} finally {
|
||||
TesrBatchRenderer.INSTANCE.endScope();
|
||||
GLSMAttribStack.popStateTo(depth);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean anyRendersInPassOne() {
|
||||
for (int i = 0; i < frameOverride.size(); i++) {
|
||||
if (frameOverride.get(i).shouldRenderInPass(1)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean takeLatePassOne() {
|
||||
final boolean late = passOne != PassOne.DRAWN_EARLY;
|
||||
passOne = PassOne.NONE;
|
||||
return late;
|
||||
}
|
||||
|
||||
public void renderBlockEntitiesInPhase(float partialTicks) {
|
||||
if (Iris.enabled) {
|
||||
GbufferPrograms.beginBlockEntities();
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
}
|
||||
try {
|
||||
final int rendered = renderBlockEntities(partialTicks);
|
||||
if (Tracy.ENABLED) Tracy.plotInt(P_BLOCK_ENTITIES_RENDERED, rendered);
|
||||
} finally {
|
||||
if (Iris.enabled) GbufferPrograms.endBlockEntities();
|
||||
}
|
||||
}
|
||||
|
||||
public int renderBlockEntities(float partialTicks) {
|
||||
AngelicaTesrMeshCache.INSTANCE.tick();
|
||||
final int pass = MinecraftForgeClient.getRenderPass();
|
||||
@@ -557,8 +420,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
TileEntityRendererDispatcher.staticPlayerZ);
|
||||
ModelPartBatcher.INSTANCE.begin(ModelPartBatcher.Mode.BLOCK_ENTITIES);
|
||||
PendingTesrDraws.beginPass();
|
||||
ImmediateDrawOrder.beginPass();
|
||||
TranslucentPeel.beginPass();
|
||||
int count = 0;
|
||||
if (pass == 0) {
|
||||
teRenderContext.set(partialTicks, pass);
|
||||
@@ -581,9 +442,6 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
this.teTransform = null;
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_DISPATCH);
|
||||
try {
|
||||
if (ClientProxy.options().performance.translucencyMode.sorts()) {
|
||||
depthOrder.sortBackToFront(frameTEs, teCamX, teCamY, teCamZ);
|
||||
}
|
||||
for (int i = 0; i < frameTEs.size(); i++) {
|
||||
final TileEntity te = frameTEs.get(i);
|
||||
if (!(te instanceof OverridesShouldRenderInPass)) {
|
||||
@@ -600,24 +458,28 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
} finally {
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
}
|
||||
passOne = PassOne.PENDING;
|
||||
} else {
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_DISPATCH);
|
||||
try {
|
||||
sortedTileEntities.clear();
|
||||
for (int i = 0; i < frameOverride.size(); i++) {
|
||||
final TileEntity te = frameOverride.get(i);
|
||||
if (te.shouldRenderInPass(pass)) {
|
||||
dispatchTE(te, partialTicks);
|
||||
count++;
|
||||
sortedTileEntities.add(te);
|
||||
}
|
||||
}
|
||||
if (sortedTileEntities.size() > 1 && ClientProxy.options().performance.translucencySorting) {
|
||||
sortedTileEntities.sort(tileEntityOrderer.setLastCameraState(lastCameraState));
|
||||
}
|
||||
for (int i = 0; i < sortedTileEntities.size(); i++) {
|
||||
dispatchTE(sortedTileEntities.get(i), partialTicks);
|
||||
}
|
||||
count = sortedTileEntities.size();
|
||||
} finally {
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
}
|
||||
}
|
||||
ImmediateDrawOrder.endPass();
|
||||
PendingTesrDraws.endPass();
|
||||
TranslucentPeel.flush();
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_MODEL_PARTS);
|
||||
try {
|
||||
ModelPartBatcher.INSTANCE.flush();
|
||||
@@ -756,17 +618,14 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
}
|
||||
}
|
||||
PendingTesrDraws.beforeTileEntity(tileEntity);
|
||||
TranslucentPeel.beforeBlockEntity();
|
||||
try {
|
||||
final long start = Tracy.ENABLED ? System.nanoTime() : 0L;
|
||||
final boolean attribute = Tracy.ENABLED && TesrAttribution.currentRenderable == null;
|
||||
if (attribute) TesrAttribution.currentRenderable = tileEntity.getClass();
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_RENDER_TE);
|
||||
if (DepthEcho.armed() && !GlowReplayExclusions.excludes(tileEntity)) DepthEcho.beginTracking();
|
||||
try {
|
||||
TileEntityRendererDispatcher.instance.renderTileEntity(tileEntity, partialTicks);
|
||||
} finally {
|
||||
if (DepthEcho.endTracking()) glowReplay.add(tileEntity);
|
||||
if (Tracy.ENABLED) Tracy.endZone();
|
||||
if (attribute) TesrAttribution.currentRenderable = null;
|
||||
if (Tracy.ENABLED) RenderClassTimings.TESR.add(teLabelClass(tileEntity), System.nanoTime() - start);
|
||||
@@ -814,4 +673,27 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TileEntityOrderer implements Comparator<TileEntity> {
|
||||
public CameraState lastCameraState;
|
||||
|
||||
public TileEntityOrderer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TileEntityOrderer setLastCameraState(CameraState lastCameraState) {
|
||||
this.lastCameraState = lastCameraState;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(TileEntity te1, TileEntity te2) {
|
||||
final double x = this.lastCameraState.x();
|
||||
final double y = this.lastCameraState.y();
|
||||
final double z = this.lastCameraState.z();
|
||||
final double d1 = te1.getDistanceFrom(x, y, z);
|
||||
final double d2 = te2.getDistanceFrom(x, y, z);
|
||||
return Double.compare(d2, d1);
|
||||
}
|
||||
}
|
||||
}
|
||||
-79
@@ -1,79 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
final class TileEntityDepthOrder {
|
||||
|
||||
private static final int RADIX_BITS = 8;
|
||||
private static final int BUCKETS = 1 << RADIX_BITS;
|
||||
|
||||
private final int[] counts = new int[BUCKETS];
|
||||
private int[] keys = new int[0];
|
||||
private int[] keysScratch = new int[0];
|
||||
private int[] order = new int[0];
|
||||
private int[] orderScratch = new int[0];
|
||||
private TileEntity[] entities = new TileEntity[0];
|
||||
|
||||
void sortBackToFront(ObjectArrayList<TileEntity> list, double camX, double camY, double camZ) {
|
||||
final int n = list.size();
|
||||
if (n < 2) return;
|
||||
final Object[] source = list.elements();
|
||||
if (keys.length < n) {
|
||||
final int capacity = source.length;
|
||||
keys = new int[capacity];
|
||||
keysScratch = new int[capacity];
|
||||
order = new int[capacity];
|
||||
orderScratch = new int[capacity];
|
||||
entities = new TileEntity[capacity];
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
final TileEntity te = (TileEntity) source[i];
|
||||
final double dx = te.xCoord + 0.5 - camX;
|
||||
final double dy = te.yCoord + 0.5 - camY;
|
||||
final double dz = te.zCoord + 0.5 - camZ;
|
||||
keys[i] = Integer.MAX_VALUE - Float.floatToRawIntBits((float) (dx * dx + dy * dy + dz * dz));
|
||||
order[i] = i;
|
||||
entities[i] = te;
|
||||
}
|
||||
final int[] sorted = sortOrder(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
source[i] = entities[sorted[i]];
|
||||
entities[sorted[i]] = null;
|
||||
}
|
||||
}
|
||||
|
||||
private int[] sortOrder(int n) {
|
||||
int[] keyIn = keys, keyOut = keysScratch;
|
||||
int[] idxIn = order, idxOut = orderScratch;
|
||||
for (int shift = 0; shift < Integer.SIZE; shift += RADIX_BITS) {
|
||||
Arrays.fill(counts, 0);
|
||||
for (int i = 0; i < n; i++) counts[(keyIn[i] >>> shift) & (BUCKETS - 1)]++;
|
||||
if (counts[(keyIn[0] >>> shift) & (BUCKETS - 1)] == n) continue;
|
||||
int sum = 0;
|
||||
for (int b = 0; b < BUCKETS; b++) {
|
||||
final int c = counts[b];
|
||||
counts[b] = sum;
|
||||
sum += c;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
final int dst = counts[(keyIn[i] >>> shift) & (BUCKETS - 1)]++;
|
||||
keyOut[dst] = keyIn[i];
|
||||
idxOut[dst] = idxIn[i];
|
||||
}
|
||||
final int[] k = keyIn;
|
||||
keyIn = keyOut;
|
||||
keyOut = k;
|
||||
final int[] x = idxIn;
|
||||
idxIn = idxOut;
|
||||
idxOut = x;
|
||||
}
|
||||
keys = keyIn;
|
||||
keysScratch = keyOut;
|
||||
order = idxIn;
|
||||
orderScratch = idxOut;
|
||||
return idxIn;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import com.gtnewhorizons.angelica.rendering.celeritas.SmoothBiomeColorCache;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ChunkRenderContext;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSection;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSectionCache;
|
||||
import com.gtnewhorizons.liquidlogged.api.LiquidLoggedBlockAccess;
|
||||
import cpw.mods.fml.common.Optional;
|
||||
import mega.fluidlogged.api.FLBlockAccess;
|
||||
|
||||
@@ -45,8 +46,11 @@ import mega.fluidlogged.api.FLBlockAccess;
|
||||
*
|
||||
* Object pooling should be used to avoid huge allocations as this class contains many large arrays.
|
||||
*/
|
||||
@Optional.Interface(iface = "mega.fluidlogged.api.FLBlockAccess", modid = "fluidlogged")
|
||||
public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
@Optional.InterfaceList({
|
||||
@Optional.Interface(iface = "mega.fluidlogged.api.FLBlockAccess", modid = "fluidlogged"),
|
||||
@Optional.Interface(iface = "com.gtnewhorizons.liquidlogged.api.LiquidLoggedBlockAccess", modid = "liquidlogged")
|
||||
})
|
||||
public class WorldSlice implements IBlockAccessExtended, FLBlockAccess, LiquidLoggedBlockAccess {
|
||||
|
||||
private static final EnumSkyBlock[] LIGHT_TYPES = EnumSkyBlock.values();
|
||||
|
||||
@@ -179,7 +183,7 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
this.lightArrays = new NibbleArray[SECTION_TABLE_ARRAY_SIZE][LIGHT_TYPES.length];
|
||||
this.sectionLightData = new SectionLightData[SECTION_TABLE_ARRAY_SIZE];
|
||||
|
||||
if (ModStatus.isFluidLoggedLoaded) {
|
||||
if (ModStatus.isFluidLoggedLoaded || ModStatus.isLiquidLoggedLoaded) {
|
||||
this.fluidArrays = new Fluid[SECTION_TABLE_ARRAY_SIZE][];
|
||||
} else {
|
||||
this.fluidArrays = null;
|
||||
@@ -193,7 +197,7 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
Arrays.fill(this.blockArrays[i], Blocks.air);
|
||||
this.metadataArrays[i] = new int[SECTION_BLOCK_COUNT];
|
||||
|
||||
if (ModStatus.isFluidLoggedLoaded && this.fluidArrays != null) {
|
||||
if (this.fluidArrays != null) {
|
||||
this.fluidArrays[i] = new Fluid[SECTION_BLOCK_COUNT];
|
||||
}
|
||||
}
|
||||
@@ -239,7 +243,7 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
|
||||
this.unpackBlockData(this.blockArrays[idx], this.metadataArrays[idx], section, context.getVolume());
|
||||
|
||||
if (ModStatus.isFluidLoggedLoaded && this.fluidArrays != null) {
|
||||
if (this.fluidArrays != null) {
|
||||
this.unpackFluidLoggedData(this.fluidArrays[idx], section, context.getVolume());
|
||||
}
|
||||
|
||||
@@ -457,6 +461,12 @@ public class WorldSlice implements IBlockAccessExtended, FLBlockAccess {
|
||||
return this.fluidArrays[getLocalSectionIndex(relX >> 4, relY >> 4, relZ >> 4)][getLocalBlockIndex(relX & 15, relY & 15, relZ & 15)];
|
||||
}
|
||||
|
||||
// LiquidLogged API support
|
||||
|
||||
public @Nullable Fluid liquidlogged$getFluid(int x, int y, int z) {
|
||||
return fl$getFluid(x, y, z);
|
||||
}
|
||||
|
||||
public void fl$setFluid(int x, int y, int z, @Nullable Fluid fluid) {
|
||||
throw new UnsupportedOperationException("Cannot set fluids in a world slice. WorldSlice is read-only");
|
||||
}
|
||||
|
||||
+24
@@ -9,6 +9,8 @@ import com.gtnewhorizons.angelica.compat.cubicchunks.CubicChunksAPI;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.ChunkSectionPos;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IChunkTileEntityMapHolder;
|
||||
import com.gtnewhorizons.angelica.utils.ConcurrentTileEntityMap;
|
||||
import com.gtnewhorizons.liquidlogged.api.LiquidLoggedAPI;
|
||||
import com.gtnewhorizons.liquidlogged.api.SectionFluidsView;
|
||||
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
|
||||
import mega.fluidlogged.internal.mixin.hook.FLSubChunk;
|
||||
|
||||
@@ -41,6 +43,9 @@ public class ClonedChunkSection {
|
||||
private SectionLightData sectionLightData;
|
||||
private final Short2ObjectOpenHashMap<TileEntity> tileEntities;
|
||||
|
||||
// Fluids stored in blocks by LiquidLogged, indexed y << 8 | z << 4 | x; null when the section holds none
|
||||
private Fluid[] liquidLoggedFluids;
|
||||
|
||||
private long lastUsedTimestamp = Long.MAX_VALUE;
|
||||
|
||||
int refs;
|
||||
@@ -79,6 +84,10 @@ public class ClonedChunkSection {
|
||||
this.data.copyFrom(chunk, section);
|
||||
}
|
||||
|
||||
if (ModStatus.isLiquidLoggedLoaded) {
|
||||
copyLiquidLoggedFluids(section);
|
||||
}
|
||||
|
||||
copyBlockEntities(chunk, pos);
|
||||
|
||||
fillBiomeData(chunk);
|
||||
@@ -130,7 +139,22 @@ public class ClonedChunkSection {
|
||||
return data.getExtBlockMetadata(x, y, z);
|
||||
}
|
||||
|
||||
private void copyLiquidLoggedFluids(ExtendedBlockStorage section) {
|
||||
final SectionFluidsView view = LiquidLoggedAPI.getSection(section);
|
||||
if (view == null || view.isEmpty()) {
|
||||
this.liquidLoggedFluids = null;
|
||||
return;
|
||||
}
|
||||
if (this.liquidLoggedFluids == null) {
|
||||
this.liquidLoggedFluids = new Fluid[SECTION_BLOCK_LENGTH * SECTION_BLOCK_LENGTH * SECTION_BLOCK_LENGTH];
|
||||
}
|
||||
view.copyTo(this.liquidLoggedFluids);
|
||||
}
|
||||
|
||||
public Fluid getFluid(int x, int y, int z) {
|
||||
if (ModStatus.isLiquidLoggedLoaded) {
|
||||
return this.liquidLoggedFluids != null ? this.liquidLoggedFluids[y << 8 | z << 4 | x] : null;
|
||||
}
|
||||
if (ModStatus.isFluidLoggedLoaded) {
|
||||
return ((FLSubChunk) data).fl$getFluid(x, y, z);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ final class BatchStateFallback {
|
||||
final long before = GLSMDraws.drawCalls;
|
||||
try {
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
if (models.hasQueuedGeometry() || tesrs.hasQueuedGeometry()) TranslucentPeel.flush();
|
||||
models.flushForStateChange();
|
||||
tesrs.flushForStateChange();
|
||||
} finally {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public final class GlowReplayExclusions {
|
||||
|
||||
private static final ReferenceOpenHashSet<Class<?>> registered = new ReferenceOpenHashSet<>();
|
||||
private static final Reference2ObjectOpenHashMap<Class<?>, Boolean> excluded = new Reference2ObjectOpenHashMap<>();
|
||||
|
||||
private GlowReplayExclusions() {}
|
||||
|
||||
public static void exclude(Class<?> type) {
|
||||
if (registered.add(type)) excluded.clear();
|
||||
}
|
||||
|
||||
public static boolean excludes(TileEntity tileEntity) {
|
||||
final Class<? extends TileEntity> type = tileEntity.getClass();
|
||||
Boolean result = excluded.get(type);
|
||||
if (result == null) {
|
||||
final TileEntitySpecialRenderer renderer = TileEntityRendererDispatcher.instance.getSpecialRendererByClass(type);
|
||||
result = matches(type) || renderer != null && matches(renderer.getClass());
|
||||
excluded.put(type, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean matches(Class<?> type) {
|
||||
final String[] names = AngelicaConfig.glowDepthReplayExcludedClasses;
|
||||
for (Class<?> c = type; c != null && c != Object.class; c = c.getSuperclass()) {
|
||||
if (registered.contains(c)) return true;
|
||||
if (names != null) for (String name : names) {
|
||||
if (c.getName().equals(name)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMMatrices;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
/// Draws what the batchers have queued before a blended `glBegin`, display list, Tessellator or unbatched template draw
|
||||
/// of a block entity, which would otherwise land under batched geometry dispatched before it. Vertex array and buffer
|
||||
/// draws are not hooked.
|
||||
public final class ImmediateDrawOrder {
|
||||
|
||||
private static final Runnable FLUSH = ImmediateDrawOrder::flush;
|
||||
|
||||
private ImmediateDrawOrder() {}
|
||||
|
||||
public static void beginPass() {
|
||||
if (!ClientProxy.options().performance.translucencyMode.sorts() || TesrBatchRenderer.deferredPipeline() != null) return;
|
||||
BatchStateGuard.drawFlush = FLUSH;
|
||||
}
|
||||
|
||||
public static void endPass() {
|
||||
BatchStateGuard.drawFlush = null;
|
||||
}
|
||||
|
||||
static void flush() {
|
||||
if (!GLSMBlend.getBlendMode().isEnabled()) return;
|
||||
// A Tessellator draw triggers this from inside Tessellator.draw, and pending draws use the Tessellator
|
||||
if (!Tessellator.instance.isDrawing) PendingTesrDraws.flush();
|
||||
final ModelPartBatcher models = ModelPartBatcher.INSTANCE;
|
||||
final TesrBatchRenderer tesrs = TesrBatchRenderer.INSTANCE;
|
||||
if (!models.hasQueuedGeometry() && !tesrs.hasQueuedGeometry()) return;
|
||||
final int mode = GLSMMatrices.getMatrixMode().getMode();
|
||||
final int unit = GLSMTextures.getActiveTextureUnit();
|
||||
try {
|
||||
GLSMMatrices.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
TranslucentPeel.flush();
|
||||
models.flushForStateChange();
|
||||
tesrs.flushAndContinue();
|
||||
} finally {
|
||||
GLSMMatrices.glMatrixMode(mode);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-20
@@ -144,14 +144,6 @@ final class InstancedTemplateRenderer {
|
||||
* Draws a base run's recorded template upload again, every instance in one color.
|
||||
*/
|
||||
int redrawTemplates(TexRun base, int colorABGR) {
|
||||
return redrawTemplates(base, true, colorABGR);
|
||||
}
|
||||
|
||||
int replayTemplates(TexRun run) {
|
||||
return redrawTemplates(run, false, 0);
|
||||
}
|
||||
|
||||
private int redrawTemplates(TexRun base, boolean constantColor, int colorABGR) {
|
||||
long recordOffset = base.uploadOffset;
|
||||
neutralizeExtendedAttribs();
|
||||
GLSMPrograms.setFfpInstancing(Instancing.TEMPLATE);
|
||||
@@ -161,9 +153,9 @@ final class InstancedTemplateRenderer {
|
||||
bindRingTo(mesh.vao, TEMPLATE_FLAGS);
|
||||
InstancedAttribs.pointTemplate(recordOffset);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
if (constantColor) setConstantColor(colorABGR);
|
||||
setConstantColor(colorABGR);
|
||||
GLSMDraws.glDrawArraysInstanced(mesh.drawMode, 0, mesh.vertexCount, count);
|
||||
if (constantColor) GLSMVertexInput.glEnableVertexAttribArray(InstancedAttribs.LOC_COLOR);
|
||||
GLSMVertexInput.glEnableVertexAttribArray(InstancedAttribs.LOC_COLOR);
|
||||
recordOffset += (long) count * InstancedAttribs.STRIDE;
|
||||
}
|
||||
GLSMPrograms.setFfpInstancing(Instancing.NONE);
|
||||
@@ -228,23 +220,15 @@ final class InstancedTemplateRenderer {
|
||||
}
|
||||
|
||||
void redrawCubes(long offset, int instances, int colorABGR) {
|
||||
redrawCubes(offset, instances, true, colorABGR);
|
||||
}
|
||||
|
||||
void replayCubes(long offset, int instances) {
|
||||
redrawCubes(offset, instances, false, 0);
|
||||
}
|
||||
|
||||
private void redrawCubes(long offset, int instances, boolean constantColor, int colorABGR) {
|
||||
neutralizeExtendedAttribs();
|
||||
bindRingTo(UnitCubeMesh.vao(), UnitCubeMesh.VERTEX_FLAGS);
|
||||
CubeInstancedAttribs.pointInstanceAttribs(offset);
|
||||
GLSMBuffers.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
if (constantColor) setConstantColor(colorABGR);
|
||||
setConstantColor(colorABGR);
|
||||
GLSMPrograms.setFfpInstancing(Instancing.CUBE);
|
||||
GLSMDraws.glDrawArraysInstanced(GL11.GL_QUADS, 0, UnitCubeMesh.VERTEX_COUNT, instances);
|
||||
GLSMPrograms.setFfpInstancing(Instancing.NONE);
|
||||
if (constantColor) GLSMVertexInput.glEnableVertexAttribArray(InstancedAttribs.LOC_COLOR);
|
||||
GLSMVertexInput.glEnableVertexAttribArray(InstancedAttribs.LOC_COLOR);
|
||||
GLSMVertexInput.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -329,39 +329,13 @@ public final class ModelPartBatcher {
|
||||
}
|
||||
}
|
||||
|
||||
void queueShadows() {
|
||||
if (active && mode == Mode.BLOCK_ENTITIES && !shadow) shadows.flush(activeSource);
|
||||
}
|
||||
|
||||
void drawOpaque() {
|
||||
if (active && mode == Mode.BLOCK_ENTITIES && !shadow) activeSource.endBatchWithType(TransparencyType.OPAQUE, activeGroups);
|
||||
}
|
||||
|
||||
boolean beginPeel() {
|
||||
if (!active || mode != Mode.BLOCK_ENTITIES || shadow) return false;
|
||||
if (!activeSource.hasPendingLayers()) return false;
|
||||
activeSource.openDrawState();
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawPeeled(boolean replay) {
|
||||
activeGroups.setPeelReplay(!replay, replay);
|
||||
activeSource.drawPending(activeGroups);
|
||||
}
|
||||
|
||||
void endPeel() {
|
||||
if (!active || mode != Mode.BLOCK_ENTITIES || shadow) return;
|
||||
activeGroups.setPeelReplay(false, false);
|
||||
activeSource.discard();
|
||||
}
|
||||
|
||||
void flushForStateChange() {
|
||||
if (!active) return;
|
||||
flushNow(false);
|
||||
active = true;
|
||||
mvCaptured = false;
|
||||
texCaptured = false;
|
||||
activeGroups.continuePass(identity, 0, 0, 0, instancedThisCycle ? TesrBatchRenderer.INSTANCE.instancedRenderer : null, shaderPipeline);
|
||||
activeGroups.beginPass(identity, 0, 0, 0, instancedThisCycle ? TesrBatchRenderer.INSTANCE.instancedRenderer : null, shaderPipeline);
|
||||
}
|
||||
|
||||
private void flushNow(boolean allowHold) {
|
||||
@@ -886,7 +860,6 @@ public final class ModelPartBatcher {
|
||||
return result;
|
||||
}
|
||||
case DRAW_NOW_EXPECTED -> {
|
||||
BatchStateGuard.beforeDraw();
|
||||
BatchEligibility.beginExpectedDraws(GLSMDraws.drawCalls);
|
||||
try {
|
||||
return TessellatorStreamingDrawer.draw(tess);
|
||||
@@ -895,7 +868,6 @@ public final class ModelPartBatcher {
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
BatchStateGuard.beforeDraw();
|
||||
return TessellatorStreamingDrawer.draw(tess);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
/**
|
||||
@@ -41,12 +40,7 @@ public final class PendingTesrDraws {
|
||||
final Pending owner = pending;
|
||||
if (owner == null) return;
|
||||
pending = null;
|
||||
DepthEcho.beginImmediate();
|
||||
try {
|
||||
owner.flush();
|
||||
} finally {
|
||||
DepthEcho.endImmediate();
|
||||
}
|
||||
owner.flush();
|
||||
}
|
||||
|
||||
public interface Pending {
|
||||
|
||||
@@ -66,13 +66,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
private final TemplateBuffer[] budgetSeen = new TemplateBuffer[PROMOTE_MAX_TEMPLATES];
|
||||
private double camX, camY, camZ;
|
||||
private long frameMark;
|
||||
/// `frameMark` advances per segment, so limits measured in frames count passes here.
|
||||
private long passMark;
|
||||
private int segment;
|
||||
private boolean peelRecording;
|
||||
private boolean peelReplaying;
|
||||
private final ObjectArrayList<Group> deferredPromotions = new ObjectArrayList<>();
|
||||
private final ObjectArrayList<DepthEqualSet> deferredSwitches = new ObjectArrayList<>();
|
||||
GlintCapture glintCapture;
|
||||
|
||||
long rebakes;
|
||||
@@ -444,11 +437,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SegmentGroups {
|
||||
final ObjectArrayList<Group> groups = new ObjectArrayList<>();
|
||||
long frameMark = -1;
|
||||
}
|
||||
|
||||
static final class Group {
|
||||
final RenderLayer layer;
|
||||
final TesrMaterial material;
|
||||
@@ -463,7 +451,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
final Anchor anchor = new Anchor();
|
||||
boolean anchored;
|
||||
long frameMark = -1;
|
||||
long passMark = -1;
|
||||
long lastUsedMs;
|
||||
final int entityColor;
|
||||
final int itemId;
|
||||
@@ -636,7 +623,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
|
||||
private final Reference2ObjectOpenHashMap<RenderLayer, Reference2ObjectOpenHashMap<TesrMaterial, Object2ObjectOpenHashMap<DrawStateKey, Group>>> groups = new Reference2ObjectOpenHashMap<>();
|
||||
private final Reference2ObjectOpenHashMap<RenderLayer, ObjectArrayList<Group>> byLayer = new Reference2ObjectOpenHashMap<>();
|
||||
private final Reference2ObjectOpenHashMap<RenderLayer, SegmentGroups> segmentGroups = new Reference2ObjectOpenHashMap<>();
|
||||
private long openScope;
|
||||
private DepthEqualSet openDepthEqualSet;
|
||||
private final ObjectArrayList<Group> openWriters = new ObjectArrayList<>();
|
||||
@@ -662,18 +648,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
|
||||
void beginPass(Matrix4f base, double camX, double camY, double camZ, InstancedTemplateRenderer instancedRenderer, TesrInstancingPipeline deferred) {
|
||||
startSegment(base, camX, camY, camZ, instancedRenderer, deferred);
|
||||
passMark++;
|
||||
segment = 0;
|
||||
}
|
||||
|
||||
void continuePass(Matrix4f base, double camX, double camY, double camZ, InstancedTemplateRenderer instancedRenderer, TesrInstancingPipeline deferred) {
|
||||
startSegment(base, camX, camY, camZ, instancedRenderer, deferred);
|
||||
// Baked groups are keyed by segment, so a group split by a flush keeps one mesh per side instead of rebaking
|
||||
segment++;
|
||||
}
|
||||
|
||||
private void startSegment(Matrix4f base, double camX, double camY, double camZ, InstancedTemplateRenderer instancedRenderer, TesrInstancingPipeline deferred) {
|
||||
if (glintCapture != null) glintCapture.invalidate();
|
||||
glintCapture = null;
|
||||
baseMV.set(base);
|
||||
@@ -696,28 +670,27 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
|
||||
/** Mutable lookup avoids allocating a key for each queued model part. Stored keys are never mutated. */
|
||||
private static final class DrawStateKey {
|
||||
int entity, block, item, color, segment;
|
||||
int entity, block, item, color;
|
||||
|
||||
DrawStateKey set(int entity, int block, int item, int color, int segment) {
|
||||
DrawStateKey set(int entity, int block, int item, int color) {
|
||||
this.entity = entity;
|
||||
this.block = block;
|
||||
this.item = item;
|
||||
this.color = color;
|
||||
this.segment = segment;
|
||||
return this;
|
||||
}
|
||||
|
||||
boolean matches(int entity, int block, int item, int color, int segment) {
|
||||
return this.entity == entity && this.block == block && this.item == item && this.color == color && this.segment == segment;
|
||||
boolean matches(int entity, int block, int item, int color) {
|
||||
return this.entity == entity && this.block == block && this.item == item && this.color == color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof DrawStateKey key && matches(key.entity, key.block, key.item, key.color, key.segment);
|
||||
return other instanceof DrawStateKey key && matches(key.entity, key.block, key.item, key.color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() { return (((entity * 31 + block) * 31 + item) * 31 + color) * 31 + segment; }
|
||||
public int hashCode() { return ((entity * 31 + block) * 31 + item) * 31 + color; }
|
||||
}
|
||||
|
||||
private final DrawStateKey lookupState = new DrawStateKey();
|
||||
@@ -756,7 +729,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
group = byState.get(lookupState);
|
||||
if (group == null) {
|
||||
final DrawStateKey key = new DrawStateKey().set(lookupState.entity, lookupState.block, lookupState.item, lookupState.color, lookupState.segment);
|
||||
final DrawStateKey key = new DrawStateKey().set(lookupState.entity, lookupState.block, lookupState.item, lookupState.color);
|
||||
group = new Group(layer, material, perInstance ? 0 : id, key);
|
||||
group.lastUsedMs = nowMs;
|
||||
byState.put(key, group);
|
||||
@@ -773,13 +746,13 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
|
||||
private void keyLookup(boolean perInstance, int id) {
|
||||
if (perInstance) {
|
||||
lookupState.set(0, 0, 0, 0, 0);
|
||||
lookupState.set(0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
final CapturedRenderingState captured = CapturedRenderingState.INSTANCE;
|
||||
final boolean entityKind = source.effectiveIdKind() == AngelicaBufferSource.GroupIdKind.ENTITY;
|
||||
lookupState.set(entityKind ? id : captured.getCurrentRenderedEntity(), entityKind ? captured.getCurrentRenderedBlockEntity() : id,
|
||||
captured.getCurrentRenderedItem(), AngelicaBufferSource.packEntityColor(captured.getCurrentEntityColor()), segment);
|
||||
captured.getCurrentRenderedItem(), AngelicaBufferSource.packEntityColor(captured.getCurrentEntityColor()));
|
||||
}
|
||||
|
||||
void forceStreaming(RenderLayer layer, TesrMaterial material, int blockEntityId) {
|
||||
@@ -893,8 +866,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
resetPromotion(group);
|
||||
}
|
||||
}
|
||||
// touch recorded this geometry as stream segments, but it draws with the baked columns
|
||||
TranslucentPeel.queued(layer, this, group);
|
||||
}
|
||||
toAnchorRelative(group, currentMV);
|
||||
final Matrix4f bakedTexMatrix = atlasSlot != null ? atlasSlot.uvMatrix : texMatrix;
|
||||
@@ -1020,7 +991,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
adoptAnchor(group, set);
|
||||
} else if (set.anchorFrame < 0) {
|
||||
set.anchor.set(group.anchor);
|
||||
set.anchorFrame = passMark;
|
||||
set.anchorFrame = frameMark;
|
||||
for (int i = 0, n = set.members.size(); i < n; i++) {
|
||||
final Group member = set.members.get(i);
|
||||
if (member.frameMark == frameMark && !member.queuedThisFrame) adoptAnchor(member, set);
|
||||
@@ -1052,13 +1023,13 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
|
||||
private void refresh(DepthEqualSet set) {
|
||||
if (set.checkedFrame == passMark) return;
|
||||
set.checkedFrame = passMark;
|
||||
if (set.anchorFrame != passMark && set.anchor.stale(camX, camY, camZ)) set.anchor.moveTo(camX, camY, camZ);
|
||||
set.anchorFrame = passMark;
|
||||
if (set.checkedFrame == frameMark) return;
|
||||
set.checkedFrame = frameMark;
|
||||
if (set.anchorFrame != frameMark && set.anchor.stale(camX, camY, camZ)) set.anchor.moveTo(camX, camY, camZ);
|
||||
set.anchorFrame = frameMark;
|
||||
if ((set.streamMembers > 0 || set.instanced) && set.instanced != allCanInstance(set)) {
|
||||
set.instanced = !set.instanced;
|
||||
set.effectiveFrame = passMark - 1;
|
||||
set.effectiveFrame = frameMark - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1181,7 +1152,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
if (group.frameMark != frameMark) {
|
||||
final DepthEqualSet set = activeDepthEqualSet(group);
|
||||
if (set != null) refresh(set);
|
||||
if (passMark - group.passMark > IDLE_RESET_FRAMES) {
|
||||
if (frameMark - group.frameMark > IDLE_RESET_FRAMES) {
|
||||
resetPromotion(group);
|
||||
} else if (promoted(group)) {
|
||||
final boolean pinned = set != null && set.streamMembers > 0;
|
||||
@@ -1200,14 +1171,12 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
}
|
||||
if (set != null) {
|
||||
if (passMark > set.effectiveFrame) adopt(group, set.instanced);
|
||||
if (frameMark > set.effectiveFrame) adopt(group, set.instanced);
|
||||
} else if (group.stream && !group.streamPath) {
|
||||
resetPromotion(group);
|
||||
}
|
||||
group.queuedThisFrame = false;
|
||||
group.frameMark = frameMark;
|
||||
group.passMark = passMark;
|
||||
addToSegment(group);
|
||||
group.lastUsedMs = nowMs;
|
||||
group.dirty = false;
|
||||
group.clearInstances();
|
||||
@@ -1220,37 +1189,12 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
source.declareUse(layer);
|
||||
}
|
||||
if (drawsInstanced(group)) {
|
||||
TranslucentPeel.queuedUnordered(layer);
|
||||
} else if (group.streamPath) {
|
||||
TranslucentPeel.queued(layer, source, layer);
|
||||
} else {
|
||||
TranslucentPeel.queued(layer, this, group);
|
||||
}
|
||||
}
|
||||
|
||||
private void addToSegment(Group group) {
|
||||
SegmentGroups entry = segmentGroups.get(group.layer);
|
||||
if (entry == null) {
|
||||
entry = new SegmentGroups();
|
||||
segmentGroups.put(group.layer, entry);
|
||||
}
|
||||
if (entry.frameMark != frameMark) {
|
||||
entry.groups.clear();
|
||||
entry.frameMark = frameMark;
|
||||
}
|
||||
entry.groups.add(group);
|
||||
}
|
||||
|
||||
private ObjectArrayList<Group> segmentGroups(RenderLayer layer) {
|
||||
final SegmentGroups entry = segmentGroups.get(layer);
|
||||
return entry != null && entry.frameMark == frameMark ? entry.groups : null;
|
||||
}
|
||||
|
||||
private void switchSetNextFrame(DepthEqualSet set, boolean instanced) {
|
||||
if (set.instanced == instanced) return;
|
||||
set.instanced = instanced;
|
||||
set.effectiveFrame = passMark;
|
||||
set.effectiveFrame = frameMark;
|
||||
}
|
||||
|
||||
private static DepthEqualSet activeDepthEqualSet(Group group) {
|
||||
@@ -1261,7 +1205,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
private boolean allStable(DepthEqualSet set) {
|
||||
for (int i = 0, n = set.members.size(); i < n; i++) {
|
||||
final Group member = set.members.get(i);
|
||||
if (member.streamPath && passMark - member.passMark <= IDLE_RESET_FRAMES && (member.probe == null || member.probe.stableProbes < DEMOTE_AFTER_STABLE_PROBES)) return false;
|
||||
if (member.streamPath && frameMark - member.frameMark <= IDLE_RESET_FRAMES && (member.probe == null || member.probe.stableProbes < DEMOTE_AFTER_STABLE_PROBES)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1286,7 +1230,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
|
||||
@Override
|
||||
public boolean hasDraws(RenderLayer layer) {
|
||||
final ObjectArrayList<Group> list = segmentGroups(layer);
|
||||
final ObjectArrayList<Group> list = byLayer.get(layer);
|
||||
if (list == null) return false;
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
if (live(list.get(i))) return true;
|
||||
@@ -1297,7 +1241,7 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
@Override
|
||||
public void drawLayer(RenderLayer layer) {
|
||||
if (glintCapture != null) glintCapture.invalidate();
|
||||
final ObjectArrayList<Group> list = segmentGroups(layer);
|
||||
final ObjectArrayList<Group> list = byLayer.get(layer);
|
||||
if (list == null) return;
|
||||
boolean matrixAvailable = true;
|
||||
boolean cubeAvailable = true;
|
||||
@@ -1430,10 +1374,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
|
||||
private void drawRetained(Group group) {
|
||||
if (peelReplaying) {
|
||||
draw(group);
|
||||
return;
|
||||
}
|
||||
final InstanceColumns cols = group.templateColumns;
|
||||
final Snapshot snapshot = group.snapshot;
|
||||
boolean instanceChanged = false;
|
||||
@@ -1454,13 +1394,9 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
if (instanceChanged && !group.stream && !group.streamPath && rebakesTooOften(group) && withinTemplateBudget(cols.templates)) {
|
||||
final DepthEqualSet set = activeDepthEqualSet(group);
|
||||
if (set != null) {
|
||||
if (set.streamMembers == 0 && allCanInstance(set)) {
|
||||
if (peelRecording) deferredSwitches.add(set);
|
||||
else switchSetNextFrame(set, true);
|
||||
}
|
||||
if (set.streamMembers == 0 && allCanInstance(set)) switchSetNextFrame(set, true);
|
||||
} else if (canInstance(group) || group.opaque && templatesMatchLayerDrawMode(group)) {
|
||||
if (peelRecording) deferredPromotions.add(group);
|
||||
else promote(group);
|
||||
promote(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1503,21 +1439,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
return ++group.promoteWindowRebakes >= PROMOTE_AFTER_REBAKES;
|
||||
}
|
||||
|
||||
void setPeelReplay(boolean recording, boolean replaying) {
|
||||
peelRecording = recording;
|
||||
peelReplaying = replaying;
|
||||
// Promoting deletes the mesh the peel replays draw, so promotions wait until the peel ends
|
||||
if (recording || replaying) return;
|
||||
for (int i = 0, n = deferredPromotions.size(); i < n; i++) promote(deferredPromotions.get(i));
|
||||
for (int i = 0, n = deferredSwitches.size(); i < n; i++) switchSetNextFrame(deferredSwitches.get(i), true);
|
||||
deferredPromotions.clear();
|
||||
deferredSwitches.clear();
|
||||
}
|
||||
|
||||
private boolean replays(TexRun run) {
|
||||
return peelReplaying && run.uploadPass == frameMark && instanced.canRedraw(run.uploadRingEpoch, run.uploadBuffer);
|
||||
}
|
||||
|
||||
private void drawTemplateRuns(InstanceColumns cols, boolean combineGlint, boolean itemStencil) {
|
||||
for (int r = 0, n = cols.runs.size(); r < n; r++) {
|
||||
final TexRun run = cols.runs.get(r);
|
||||
@@ -1536,13 +1457,9 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
if (canRedraw(run)) {
|
||||
instancedDraws += instanced.redrawTemplates(run.sourceRun, run.color);
|
||||
redrawnInstances += run.parts;
|
||||
} else if (replays(run)) {
|
||||
instancedDraws += instanced.replayTemplates(run);
|
||||
redrawnInstances += run.parts;
|
||||
} else {
|
||||
final boolean record = run.glintBase || peelRecording;
|
||||
instancedDraws += instanced.drawTemplates(cols, run, nowMs, record);
|
||||
if (record) recordUpload(run);
|
||||
instancedDraws += instanced.drawTemplates(cols, run, nowMs, run.glintBase);
|
||||
if (run.glintBase) recordUpload(run);
|
||||
}
|
||||
instancedInstances += run.parts;
|
||||
} finally {
|
||||
@@ -1563,12 +1480,9 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
if (canRedraw(run)) {
|
||||
instanced.redrawCubes(run.sourceRun.uploadOffset, run.instances, run.color);
|
||||
redrawnInstances += run.instances;
|
||||
} else if (replays(run)) {
|
||||
instanced.replayCubes(run.uploadOffset, run.instances);
|
||||
redrawnInstances += run.instances;
|
||||
} else {
|
||||
run.uploadOffset = instanced.drawCubes(cols, run);
|
||||
if (run.glintBase || peelRecording) recordUpload(run);
|
||||
if (run.glintBase) recordUpload(run);
|
||||
}
|
||||
instancedDraws++;
|
||||
cubeInstances += run.instances;
|
||||
@@ -1724,7 +1638,6 @@ final class RetainedTesrGroups implements AngelicaBufferSource.LayerDrawHook {
|
||||
}
|
||||
}
|
||||
byLayer.clear();
|
||||
segmentGroups.clear();
|
||||
groups.clear();
|
||||
openScope = 0;
|
||||
openDepthEqualSet = null;
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.gtnewhorizons.angelica.api.tesr.TesrMaterial;
|
||||
import com.gtnewhorizons.angelica.api.tesr.TesrShader;
|
||||
import com.gtnewhorizons.angelica.client.font.BatchingFontRenderer;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.RenderLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMAttribStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMCurrentAttribs;
|
||||
@@ -83,9 +82,6 @@ public final class TesrBatchRenderer {
|
||||
private RetainedTesrGroups pendingDeferredHook;
|
||||
|
||||
private final Matrix4f modelView = new Matrix4f();
|
||||
private final Matrix4f passBase = new Matrix4f();
|
||||
private double passCamX, passCamY, passCamZ;
|
||||
private InstancedTemplateRenderer passInstanced;
|
||||
private final Matrix4f identity = new Matrix4f();
|
||||
private final Vector3f scratchVec = new Vector3f();
|
||||
|
||||
@@ -116,12 +112,7 @@ public final class TesrBatchRenderer {
|
||||
bufferSource.capturePassLighting();
|
||||
BatchDrawDefaults.capturePassFramebuffer();
|
||||
final DeferredWorldRenderingPipeline deferred = deferredPipeline();
|
||||
passBase.set(baseMV);
|
||||
passCamX = camX;
|
||||
passCamY = camY;
|
||||
passCamZ = camZ;
|
||||
passInstanced = instancedCapable() ? instancedRenderer : null;
|
||||
retained[passKey].beginPass(baseMV, camX, camY, camZ, passInstanced, deferred);
|
||||
retained[passKey].beginPass(baseMV, camX, camY, camZ, instancedCapable() ? instancedRenderer : null, deferred);
|
||||
if (passKey == PASS_MAIN_0) {
|
||||
instancedRenderer.releaseRetired();
|
||||
final long now = System.currentTimeMillis();
|
||||
@@ -203,7 +194,6 @@ public final class TesrBatchRenderer {
|
||||
}
|
||||
|
||||
public void queue(TemplateBuffer template, ResourceLocation texture, TesrMaterial material) {
|
||||
if (DepthEcho.replaying() && cannotBlend(material)) return;
|
||||
modelView.set(GLSMMatrices.getModelViewMatrix());
|
||||
final int packedLight = currentPackedLight(material);
|
||||
final int colorABGR = resolveColor(material);
|
||||
@@ -226,13 +216,6 @@ public final class TesrBatchRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean cannotBlend(TesrMaterial material) {
|
||||
if (material == TesrMaterial.CURRENT_STATE) return false;
|
||||
final TesrMaterial.Transparency transparency = material.transparency();
|
||||
return transparency == TesrMaterial.Transparency.OPAQUE || transparency == TesrMaterial.Transparency.GLINT || material.special().isGlint()
|
||||
|| material.isDepthEqual() || material.isDepthOnly();
|
||||
}
|
||||
|
||||
private static Matrix4f captureTextureMatrix() {
|
||||
final Matrix4f texMatrix = GLSMTextures.getTextures().getTextureUnitMatrix(0);
|
||||
return MatrixHelper.isIdentity(texMatrix) ? null : texMatrix;
|
||||
@@ -418,37 +401,6 @@ public final class TesrBatchRenderer {
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
}
|
||||
|
||||
void drawOpaque() {
|
||||
if (activePass >= 0) bufferSource.endBatchWithType(TransparencyType.OPAQUE, retained[activePass]);
|
||||
}
|
||||
|
||||
boolean beginPeel() {
|
||||
if (activePass < 0) return false;
|
||||
if (!bufferSource.hasPendingLayers()) return false;
|
||||
bufferSource.openDrawState();
|
||||
return true;
|
||||
}
|
||||
|
||||
void drawPeeled(boolean replay) {
|
||||
retained[activePass].setPeelReplay(!replay, replay);
|
||||
bufferSource.drawPending(retained[activePass]);
|
||||
}
|
||||
|
||||
void endPeel() {
|
||||
if (activePass < 0) return;
|
||||
retained[activePass].setPeelReplay(false, false);
|
||||
bufferSource.discard();
|
||||
}
|
||||
|
||||
void flushAndContinue() {
|
||||
if (activePass < 0) return;
|
||||
final RetainedTesrGroups hook = retained[activePass];
|
||||
bufferSource.endBatchWithType(TransparencyType.OPAQUE, hook);
|
||||
bufferSource.endBatch(hook);
|
||||
BatchingFontRenderer.flushDeferredText();
|
||||
hook.continuePass(passBase, passCamX, passCamY, passCamZ, passInstanced, null);
|
||||
}
|
||||
|
||||
private void flushNow() {
|
||||
final RetainedTesrGroups hook = activePass >= 0 ? retained[activePass] : null;
|
||||
if (Tracy.ENABLED) Tracy.beginZone(Z_TESR_OPAQUE);
|
||||
@@ -661,7 +613,6 @@ public final class TesrBatchRenderer {
|
||||
try {
|
||||
layer.startDrawing();
|
||||
layerStarted = true;
|
||||
BatchStateGuard.beforeDraw();
|
||||
immediateMesh.upload(format, template.drawMode, immediateScratch, vertexCount);
|
||||
immediateMesh.render();
|
||||
} catch (Throwable t) {
|
||||
|
||||
@@ -10,8 +10,6 @@ public final class TesrLifecycle {
|
||||
|
||||
public static void reset() {
|
||||
TesrBatchRenderer.INSTANCE.clearRetained();
|
||||
TranslucentPeel.destroy();
|
||||
ImmediateDrawOrder.endPass();
|
||||
ModelPartBatcher.INSTANCE.clear();
|
||||
EntityTextureAtlas.INSTANCE.clear();
|
||||
DroppedItemInstancer.forgetItemDraws();
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.RenderLayer;
|
||||
import com.gtnewhorizons.angelica.glsm.DepthPeel;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMAttribStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDepthStencilAlpha;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMFramebuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMQueries;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMRasterizer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.StateSet;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.DepthBufferFormat;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TranslucencyMode;
|
||||
import net.coderbot.batchedentityrendering.impl.TransparencyType;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
|
||||
import net.coderbot.iris.rendertarget.IRenderTargetExt;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/// Depth peels the translucent geometry the block entity batchers have queued ([DepthPeel]), since batches group it by
|
||||
/// layer and material rather than by depth. A flush whose translucent geometry comes from one block entity in one
|
||||
/// batch that keeps submission order is not peeled.
|
||||
///
|
||||
/// Each of the first [#SLOTS_PER_PASS] peeled flushes of a pass keeps its own peel count, and later ones peel
|
||||
/// [#MAX_PEELS]. Occlusion queries, read back frames later without stalling, lower a count one peel at a time while
|
||||
/// its last peel draws nothing and reset it when the rest pass draws.
|
||||
public final class TranslucentPeel {
|
||||
|
||||
private static final int MAX_PEELS = 4;
|
||||
private static final int SLOTS_PER_PASS = 32;
|
||||
|
||||
private static int width;
|
||||
private static int height;
|
||||
private static int depthVersion = -1;
|
||||
private static DepthBufferFormat depthFormat;
|
||||
private static Target[] peels;
|
||||
private static Target sceneDepth;
|
||||
private static StateSet clearState;
|
||||
private static final Slot[] slots = new Slot[2 * SLOTS_PER_PASS];
|
||||
private static int passFlushes;
|
||||
private static boolean replay;
|
||||
private static Object firstSource;
|
||||
private static Object firstBatch;
|
||||
private static int firstBlockEntity;
|
||||
private static int blockEntity;
|
||||
private static boolean mixed;
|
||||
|
||||
private TranslucentPeel() {}
|
||||
|
||||
static boolean enabled() {
|
||||
return ClientProxy.options().performance.translucencyMode == TranslucencyMode.FANCY && Iris.enabled
|
||||
&& TesrBatchRenderer.deferredPipeline() == null;
|
||||
}
|
||||
|
||||
public static void beginPass() {
|
||||
passFlushes = 0;
|
||||
resetBatches();
|
||||
}
|
||||
|
||||
public static void beforeBlockEntity() {
|
||||
blockEntity++;
|
||||
}
|
||||
|
||||
/// `source` and `batch` identify one draw: an `AngelicaBufferSource` and a layer, or [RetainedTesrGroups] and a
|
||||
/// group.
|
||||
public static void queued(RenderLayer layer, Object source, Object batch) {
|
||||
if (mixed || layer.getTransparencyType() == TransparencyType.OPAQUE) return;
|
||||
if (firstBatch == null) {
|
||||
firstSource = source;
|
||||
firstBatch = batch;
|
||||
firstBlockEntity = blockEntity;
|
||||
} else if (batch != firstBatch || source != firstSource || blockEntity != firstBlockEntity) {
|
||||
mixed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void queuedUnordered(RenderLayer layer) {
|
||||
if (layer.getTransparencyType() != TransparencyType.OPAQUE) mixed = true;
|
||||
}
|
||||
|
||||
private static void resetBatches() {
|
||||
firstSource = null;
|
||||
firstBatch = null;
|
||||
mixed = false;
|
||||
}
|
||||
|
||||
public static void flush() {
|
||||
final ModelPartBatcher models = ModelPartBatcher.INSTANCE;
|
||||
final TesrBatchRenderer tesrs = TesrBatchRenderer.INSTANCE;
|
||||
BatchStateGuard.suspend();
|
||||
try {
|
||||
models.drawOpaque();
|
||||
tesrs.drawOpaque();
|
||||
} finally {
|
||||
BatchStateGuard.resume();
|
||||
}
|
||||
if (!enabled()) {
|
||||
if (peels != null) destroy();
|
||||
return;
|
||||
}
|
||||
models.queueShadows();
|
||||
final boolean peeling = mixed;
|
||||
resetBatches();
|
||||
if (!peeling) return;
|
||||
BatchStateGuard.suspend();
|
||||
try {
|
||||
final boolean modelsQueued = models.beginPeel();
|
||||
final boolean tesrsQueued = tesrs.beginPeel();
|
||||
if (modelsQueued || tesrsQueued) peel(modelsQueued, tesrsQueued);
|
||||
} finally {
|
||||
try {
|
||||
tesrs.endPeel();
|
||||
} finally {
|
||||
try {
|
||||
models.endPeel();
|
||||
} finally {
|
||||
BatchStateGuard.resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void draw(boolean models, boolean tesrs) {
|
||||
if (models) ModelPartBatcher.INSTANCE.drawPeeled(replay);
|
||||
if (tesrs) TesrBatchRenderer.INSTANCE.drawPeeled(replay);
|
||||
replay = true;
|
||||
}
|
||||
|
||||
private static void peel(boolean models, boolean tesrs) {
|
||||
replay = false;
|
||||
final int target = GLSMFramebuffer.getDrawFramebuffer();
|
||||
final int read = GLSMFramebuffer.getReadFramebuffer();
|
||||
if (!syncSize() || target != Minecraft.getMinecraft().getFramebuffer().framebufferObject && target != TranslucencyLayers.INSTANCE.openFramebuffer()) {
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, target);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, read);
|
||||
draw(models, tesrs);
|
||||
return;
|
||||
}
|
||||
final int unit = GLSMTextures.getActiveTextureUnit();
|
||||
final int previousPeelTexture = GLSMTextures.getTextures().getTextureUnitBindings(DepthPeel.TEXTURE_UNIT).getBinding();
|
||||
final int previousSceneTexture = GLSMTextures.getTextures().getTextureUnitBindings(DepthPeel.SCENE_TEXTURE_UNIT).getBinding();
|
||||
final Slot slot = slot(passFlushes++);
|
||||
final int count = slot != null ? slot.update() : MAX_PEELS;
|
||||
final boolean query = slot != null && slot.beginQueries(count);
|
||||
boolean completed = false;
|
||||
try {
|
||||
blitDepth(target, sceneDepth.framebuffer.getId());
|
||||
bindTexture(DepthPeel.SCENE_TEXTURE_UNIT, sceneDepth.depth);
|
||||
Target bound = sceneDepth;
|
||||
for (int i = 0; i < count; i++) {
|
||||
final Target current = peels[i % 2];
|
||||
clearDepth(current);
|
||||
current.framebuffer.bind();
|
||||
bindTexture(DepthPeel.TEXTURE_UNIT, bound.depth);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
DepthPeel.setPass(DepthPeel.Pass.DEPTH, i == 0);
|
||||
if (query) slot.begin(i);
|
||||
draw(models, tesrs);
|
||||
if (query) slot.end();
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, target);
|
||||
bindTexture(DepthPeel.TEXTURE_UNIT, current.depth);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
DepthPeel.setPass(DepthPeel.Pass.COLOR, false);
|
||||
draw(models, tesrs);
|
||||
bound = current;
|
||||
}
|
||||
DepthPeel.setPass(DepthPeel.Pass.REST, false);
|
||||
if (query) slot.begin(count);
|
||||
draw(models, tesrs);
|
||||
if (query) slot.end();
|
||||
if (DepthPeel.skippedApplicationDraws()) {
|
||||
DepthPeel.setPass(DepthPeel.Pass.APPLICATION, false);
|
||||
draw(models, tesrs);
|
||||
}
|
||||
completed = true;
|
||||
} finally {
|
||||
if (!completed && slot != null) slot.abandon();
|
||||
DepthPeel.setPass(DepthPeel.Pass.OFF, false);
|
||||
bindTexture(DepthPeel.TEXTURE_UNIT, previousPeelTexture);
|
||||
bindTexture(DepthPeel.SCENE_TEXTURE_UNIT, previousSceneTexture);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, target);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, read);
|
||||
}
|
||||
}
|
||||
|
||||
private static Slot slot(int flush) {
|
||||
if (flush >= SLOTS_PER_PASS) return null;
|
||||
final int index = (MinecraftForgeClient.getRenderPass() == 1 ? SLOTS_PER_PASS : 0) + flush;
|
||||
if (slots[index] == null) slots[index] = new Slot();
|
||||
return slots[index];
|
||||
}
|
||||
|
||||
private static void clearDepth(Target target) {
|
||||
if (clearState == null) clearState = StateSet.forMask(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_SCISSOR_BIT);
|
||||
final int saved = GLSMAttribStack.pushState(clearState);
|
||||
try {
|
||||
GLSMRasterizer.disableScissorTest();
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
GLSMDepthStencilAlpha.glClearDepth(0.0);
|
||||
target.framebuffer.bind();
|
||||
GLSMFramebuffer.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
||||
} finally {
|
||||
GLSMAttribStack.popStateTo(saved);
|
||||
}
|
||||
}
|
||||
|
||||
private static void blitDepth(int from, int to) {
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, from);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, to);
|
||||
GLSMFramebuffer.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL11.GL_DEPTH_BUFFER_BIT, GL11.GL_NEAREST);
|
||||
}
|
||||
|
||||
private static void bindTexture(int unit, int texture) {
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
private static boolean syncSize() {
|
||||
final Framebuffer main = Minecraft.getMinecraft().getFramebuffer();
|
||||
final IRenderTargetExt ext = (IRenderTargetExt) main;
|
||||
if (peels != null && main.framebufferWidth == width && main.framebufferHeight == height && ext.iris$getDepthBufferVersion() == depthVersion) return true;
|
||||
destroyTargets();
|
||||
width = main.framebufferWidth;
|
||||
height = main.framebufferHeight;
|
||||
depthVersion = ext.iris$getDepthBufferVersion();
|
||||
final int mainDepth = ext.iris$getDepthTextureId();
|
||||
if (width <= 0 || height <= 0 || mainDepth <= 0) return false;
|
||||
depthFormat = DepthBufferFormat.fromGlEnumOrDefault(TextureInfoCache.INSTANCE.getInfo(mainDepth).getInternalFormat());
|
||||
sceneDepth = new Target(depthFormat.getGlInternalFormat(), depthFormat.getGlType(), depthFormat.getGlFormat());
|
||||
peels = new Target[] { Target.float32(), Target.float32() };
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
destroyTargets();
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null) slots[i].delete();
|
||||
slots[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void destroyTargets() {
|
||||
if (peels != null) for (Target target : peels) target.destroy();
|
||||
if (sceneDepth != null) sceneDepth.destroy();
|
||||
peels = null;
|
||||
sceneDepth = null;
|
||||
}
|
||||
|
||||
private static final class Slot {
|
||||
private int count = MAX_PEELS;
|
||||
private final int[] queries = new int[MAX_PEELS + 1];
|
||||
private int issued = -1;
|
||||
private boolean querying;
|
||||
|
||||
int update() {
|
||||
if (issued < 0) return count;
|
||||
for (int i = 0; i <= issued; i++) {
|
||||
if (GLSMQueries.glGetQueryObjecti(queries[i], GL15.GL_QUERY_RESULT_AVAILABLE) == 0) return count;
|
||||
}
|
||||
int drawn = issued;
|
||||
for (int i = 0; i < issued; i++) {
|
||||
if (GLSMQueries.glGetQueryObjecti(queries[i], GL15.GL_QUERY_RESULT) == 0) {
|
||||
drawn = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (drawn == issued && GLSMQueries.glGetQueryObjecti(queries[issued], GL15.GL_QUERY_RESULT) != 0) {
|
||||
count = MAX_PEELS;
|
||||
} else if (drawn < count) {
|
||||
count = Math.max(1, count - 1);
|
||||
}
|
||||
issued = -1;
|
||||
return count;
|
||||
}
|
||||
|
||||
boolean beginQueries(int peels) {
|
||||
if (issued >= 0 || RENDER_BACKEND.isSDLGPU()) return false;
|
||||
if (queries[0] == 0) {
|
||||
try {
|
||||
for (int i = 0; i < queries.length; i++) queries[i] = GLSMQueries.glGenQueries();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
issued = peels;
|
||||
return true;
|
||||
}
|
||||
|
||||
void begin(int peel) {
|
||||
GLSMQueries.glBeginQuery(GL33.GL_ANY_SAMPLES_PASSED, queries[peel]);
|
||||
querying = true;
|
||||
}
|
||||
|
||||
void end() {
|
||||
querying = false;
|
||||
GLSMQueries.glEndQuery(GL33.GL_ANY_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
void abandon() {
|
||||
if (querying) end();
|
||||
issued = -1;
|
||||
}
|
||||
|
||||
void delete() {
|
||||
if (queries[0] == 0) return;
|
||||
for (int query : queries) GLSMQueries.glDeleteQueries(query);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Target {
|
||||
final int depth;
|
||||
final GlFramebuffer framebuffer = new GlFramebuffer();
|
||||
|
||||
Target(int internalFormat, int format, int type) {
|
||||
depth = texture(internalFormat, format, type);
|
||||
framebuffer.addDepthAttachment(depth);
|
||||
framebuffer.noDrawBuffers();
|
||||
RenderSystem.readBuffer(framebuffer.getId(), GL11.GL_NONE);
|
||||
}
|
||||
|
||||
static Target float32() {
|
||||
return new Target(GL30.GL_DEPTH_COMPONENT32F, GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT);
|
||||
}
|
||||
|
||||
private static int texture(int internalFormat, int format, int type) {
|
||||
final int previous = GLSMQueries.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int texture = GLSMTextures.glGenTextures();
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_COMPARE_MODE, GL11.GL_NONE);
|
||||
GLSMTextures.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, (ByteBuffer) null);
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, previous);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
framebuffer.destroy();
|
||||
GLSMTextures.glDeleteTextures(depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
-485
@@ -1,485 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.translucency;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMAttribStack;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMBlend;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDepthStencilAlpha;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDraws;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMFramebuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMPrograms;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMQueries;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMRasterizer;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMVertexInput;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.StateSet;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.BatchStateGuard;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ColorMaskStack;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.DepthBufferFormat;
|
||||
import com.gtnewhorizons.angelica.glsm.texture.TextureInfoCache;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import com.gtnewhorizons.angelica.render.PanoramaRenderer;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.framebuffer.GlFramebuffer;
|
||||
import net.coderbot.iris.pipeline.FixedFunctionWorldRenderingPipeline;
|
||||
import net.coderbot.iris.rendertarget.IRenderTargetExt;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.GlProgram;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderConstants;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/// Draws each [TranslucentLayer] into its own target, seeded with the main depth, and composites the drawn layers over
|
||||
/// the main framebuffer per pixel, farthest first. Layers hold premultiplied color with coverage alpha (GLSM layer
|
||||
/// blending), and the composite writes the nearest layer depth.
|
||||
///
|
||||
/// The terrain layer has a second sheet for fragments behind the block-entity layer, so a tile entity inside a
|
||||
/// block's own translucent model is covered only by the faces in front of it.
|
||||
///
|
||||
/// Glows (blended block-entity draws that write no depth) would sort at the opaque depth behind them, so
|
||||
/// [DepthEcho] records their depth separately, and it is merged into the block-entity layer before anything
|
||||
/// reads that depth.
|
||||
public final class TranslucencyLayers {
|
||||
|
||||
private static final int LAYERS = TranslucentLayer.values().length;
|
||||
private static final int FIRST_LAYER_UNIT = 1;
|
||||
private static final int TERRAIN_BEHIND_UNIT = FIRST_LAYER_UNIT + 2 * LAYERS;
|
||||
private static final int SPLIT_DEPTH_UNIT = TERRAIN_BEHIND_UNIT + 1;
|
||||
private static final int[] SINGLE_BUFFER = { 0 };
|
||||
private static final int[] SPLIT_BUFFERS = { 0, 1 };
|
||||
private static final int[] BEHIND_BUFFER = { 1 };
|
||||
|
||||
public static final TranslucencyLayers INSTANCE = new TranslucencyLayers(new MinecraftTarget());
|
||||
|
||||
interface MainTarget {
|
||||
int framebuffer();
|
||||
int depthTexture();
|
||||
int width();
|
||||
int height();
|
||||
int depthVersion();
|
||||
}
|
||||
|
||||
private final MainTarget main;
|
||||
private final Target[] layers = new Target[LAYERS];
|
||||
private Target depthSnapshot;
|
||||
private int width;
|
||||
private int height;
|
||||
private int depthVersion = -1;
|
||||
private DepthBufferFormat depthFormat;
|
||||
|
||||
private boolean decided;
|
||||
private boolean active;
|
||||
private int drawnMask;
|
||||
private TranslucentLayer open;
|
||||
private int savedDraw;
|
||||
private int savedRead;
|
||||
private boolean alphaMasked;
|
||||
|
||||
private boolean splitting;
|
||||
private boolean behindDrawn;
|
||||
|
||||
private Target glowDepth;
|
||||
private boolean replayingGlows;
|
||||
|
||||
private CompositeProgram program;
|
||||
private CompositeProgram behindProgram;
|
||||
private GlProgram<Object> glowMergeProgram;
|
||||
private int vao;
|
||||
private StateSet prepareState;
|
||||
private StateSet compositeState;
|
||||
private StateSet clearDepthState;
|
||||
private final Runnable compositePass = this::drawComposite;
|
||||
private final Runnable glowMergePass = this::drawGlowMerge;
|
||||
|
||||
TranslucencyLayers(MainTarget main) {
|
||||
this.main = main;
|
||||
}
|
||||
|
||||
/// Whether layering applies is decided on the first [#active] call, once Iris has prepared the frame's pipeline.
|
||||
public void beginFrame() {
|
||||
decided = false;
|
||||
resetFrame();
|
||||
}
|
||||
|
||||
void beginFrame(boolean active) {
|
||||
this.active = active;
|
||||
decided = true;
|
||||
resetFrame();
|
||||
}
|
||||
|
||||
private void resetFrame() {
|
||||
drawnMask = 0;
|
||||
behindDrawn = false;
|
||||
DepthEcho.takeEchoed();
|
||||
}
|
||||
|
||||
public boolean active() {
|
||||
if (!decided) {
|
||||
active = ClientProxy.options().performance.translucencyMode.composites() && Iris.enabled
|
||||
&& Iris.getPipelineManager().getPipelineNullable() instanceof FixedFunctionWorldRenderingPipeline;
|
||||
decided = true;
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
public boolean beginIfActive(TranslucentLayer layer) {
|
||||
if (!active()) return false;
|
||||
begin(layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void begin(TranslucentLayer layer) {
|
||||
if (open != null) throw new IllegalStateException("Translucency layer " + open + " is still open");
|
||||
BatchStateGuard.beforeChange();
|
||||
savedDraw = GLSMFramebuffer.getDrawFramebuffer();
|
||||
savedRead = GLSMFramebuffer.getReadFramebuffer();
|
||||
syncSize();
|
||||
if (layer == TranslucentLayer.TERRAIN) mergeGlowDepth();
|
||||
final Target target = layer(layer);
|
||||
final int bit = 1 << layer.ordinal();
|
||||
if ((drawnMask & bit) == 0) {
|
||||
drawnMask |= bit;
|
||||
prepare(target);
|
||||
if (layer == TranslucentLayer.BLOCK_ENTITIES) clearDepth(glowDepth());
|
||||
}
|
||||
target.framebuffer.bind();
|
||||
if (layer == TranslucentLayer.BLOCK_ENTITIES) DepthEcho.arm(glowDepth.framebuffer.getId(), target.framebuffer.getId());
|
||||
open = layer;
|
||||
GLSMBlend.setLayerBlending(true);
|
||||
final ColorMaskStack mask = GLSMBlend.getColorMask();
|
||||
alphaMasked = !mask.alpha;
|
||||
if (alphaMasked) GLSMBlend.glColorMask(mask.red, mask.green, mask.blue, true);
|
||||
}
|
||||
|
||||
public void end() {
|
||||
BatchStateGuard.beforeChange();
|
||||
DepthEcho.disarm();
|
||||
if (alphaMasked) {
|
||||
final ColorMaskStack mask = GLSMBlend.getColorMask();
|
||||
GLSMBlend.glColorMask(mask.red, mask.green, mask.blue, false);
|
||||
}
|
||||
GLSMBlend.setLayerBlending(false);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, savedDraw);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, savedRead);
|
||||
open = null;
|
||||
}
|
||||
|
||||
public boolean redirectsMainBind() {
|
||||
return open != null;
|
||||
}
|
||||
|
||||
public int openFramebuffer() {
|
||||
return open != null ? layers[open.ordinal()].framebuffer.getId() : 0;
|
||||
}
|
||||
|
||||
public void bindOpenLayer() {
|
||||
(replayingGlows ? glowDepth : layers[open.ordinal()]).framebuffer.bind();
|
||||
}
|
||||
|
||||
public boolean beginGlowReplay() {
|
||||
if (!DepthEcho.armed()) return false;
|
||||
BatchStateGuard.beforeChange();
|
||||
glowDepth.framebuffer.bind();
|
||||
replayingGlows = true;
|
||||
DepthEcho.beginReplay();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void endGlowReplay() {
|
||||
BatchStateGuard.beforeChange();
|
||||
DepthEcho.endReplay();
|
||||
replayingGlows = false;
|
||||
layers[open.ordinal()].framebuffer.bind();
|
||||
}
|
||||
|
||||
public void beginTerrainSplit(int program) {
|
||||
splitting = open == TranslucentLayer.TERRAIN && (drawnMask & (1 << TranslucentLayer.BLOCK_ENTITIES.ordinal())) != 0;
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(program, "u_SplitEnabled"), splitting ? 1 : 0);
|
||||
if (!splitting) return;
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(program, "u_SplitDepth"), SPLIT_DEPTH_UNIT);
|
||||
final Target terrain = layers[TranslucentLayer.TERRAIN.ordinal()];
|
||||
if (!behindDrawn) {
|
||||
behindDrawn = true;
|
||||
terrain.attachBehind(width, height);
|
||||
terrain.framebuffer.drawBuffers(BEHIND_BUFFER);
|
||||
clear(terrain);
|
||||
}
|
||||
final int unit = GLSMTextures.getActiveTextureUnit();
|
||||
bindTexture(SPLIT_DEPTH_UNIT, layers[TranslucentLayer.BLOCK_ENTITIES.ordinal()].depth);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
terrain.framebuffer.drawBuffers(SPLIT_BUFFERS);
|
||||
}
|
||||
|
||||
public void endTerrainSplit() {
|
||||
if (!splitting) return;
|
||||
splitting = false;
|
||||
layers[TranslucentLayer.TERRAIN.ordinal()].framebuffer.drawBuffers(SINGLE_BUFFER);
|
||||
final int unit = GLSMTextures.getActiveTextureUnit();
|
||||
bindTexture(SPLIT_DEPTH_UNIT, 0);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
}
|
||||
|
||||
public void composite() {
|
||||
if (drawnMask == 0) return;
|
||||
BatchStateGuard.beforeChange();
|
||||
syncSize();
|
||||
if (drawnMask == 0) return;
|
||||
try {
|
||||
mergeGlowDepth();
|
||||
fullscreenPass(compositePass);
|
||||
} finally {
|
||||
drawnMask = 0;
|
||||
behindDrawn = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void drawComposite() {
|
||||
final Target snapshot = depthSnapshot();
|
||||
blit(main.framebuffer(), snapshot.framebuffer.getId(), GL11.GL_DEPTH_BUFFER_BIT);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_FRAMEBUFFER, main.framebuffer());
|
||||
GLSMBlend.enableBlend();
|
||||
GLSMBlend.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ZERO, GL11.GL_ONE);
|
||||
GLSMDepthStencilAlpha.glDepthFunc(GL11.GL_ALWAYS);
|
||||
bindTexture(0, snapshot.depth);
|
||||
for (int i = 0; i < LAYERS; i++) {
|
||||
if ((drawnMask & (1 << i)) == 0) continue;
|
||||
bindTexture(FIRST_LAYER_UNIT + i, layers[i].color);
|
||||
bindTexture(FIRST_LAYER_UNIT + LAYERS + i, layers[i].depth);
|
||||
}
|
||||
if (behindDrawn) bindTexture(TERRAIN_BEHIND_UNIT, layers[TranslucentLayer.TERRAIN.ordinal()].behind);
|
||||
final CompositeProgram composite = behindDrawn ? behindProgram : program;
|
||||
GLSMPrograms.glUseProgram(composite.program.handle());
|
||||
GLSMPrograms.glUniform1i(composite.maskUniform, drawnMask);
|
||||
}
|
||||
|
||||
private void mergeGlowDepth() {
|
||||
if (!DepthEcho.takeEchoed() || (drawnMask & (1 << TranslucentLayer.BLOCK_ENTITIES.ordinal())) == 0) return;
|
||||
fullscreenPass(glowMergePass);
|
||||
}
|
||||
|
||||
private void drawGlowMerge() {
|
||||
layers[TranslucentLayer.BLOCK_ENTITIES.ordinal()].framebuffer.bind();
|
||||
GLSMBlend.disableBlend();
|
||||
GLSMBlend.glColorMask(false, false, false, false);
|
||||
GLSMDepthStencilAlpha.glDepthFunc(GL11.GL_LESS);
|
||||
bindTexture(0, glowDepth.depth);
|
||||
GLSMPrograms.glUseProgram(glowMergeProgram.handle());
|
||||
}
|
||||
|
||||
private void fullscreenPass(Runnable setup) {
|
||||
final int draw = GLSMFramebuffer.getDrawFramebuffer();
|
||||
final int read = GLSMFramebuffer.getReadFramebuffer();
|
||||
final int activeProgram = GLSMPrograms.getActiveProgram();
|
||||
final int activeVao = GLSMQueries.glGetInteger(GL30.GL_VERTEX_ARRAY_BINDING);
|
||||
if (program == null) initProgram();
|
||||
final int depth = GLSMAttribStack.pushState(compositeState);
|
||||
try {
|
||||
GLSMRasterizer.disableScissorTest();
|
||||
GLSMRasterizer.disableCull();
|
||||
GLSMDepthStencilAlpha.enableDepthTest();
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
setup.run();
|
||||
GLSMRasterizer.glViewport(0, 0, width, height);
|
||||
GLSMVertexInput.glBindVertexArray(vao);
|
||||
GLSMDraws.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
|
||||
} finally {
|
||||
GLSMVertexInput.glBindVertexArray(activeVao);
|
||||
GLSMPrograms.glUseProgram(activeProgram);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, draw);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, read);
|
||||
GLSMAttribStack.popStateTo(depth);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
destroyTargets();
|
||||
if (program != null) {
|
||||
program.program.delete();
|
||||
behindProgram.program.delete();
|
||||
glowMergeProgram.delete();
|
||||
GLSMVertexInput.glDeleteVertexArrays(vao);
|
||||
program = null;
|
||||
behindProgram = null;
|
||||
glowMergeProgram = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initProgram() {
|
||||
program = new CompositeProgram("angelica:translucency_composite", ShaderConstants.EMPTY);
|
||||
behindProgram = new CompositeProgram("angelica:translucency_composite_behind", ShaderConstants.builder().add("TERRAIN_BEHIND").build());
|
||||
glowMergeProgram = PanoramaRenderer.loadProgram("angelica:translucency_glow_depth", "angelica:panorama_blur", "angelica:translucency_glow_depth", ctx -> ctx);
|
||||
final int merge = glowMergeProgram.handle();
|
||||
GLSMPrograms.glUseProgram(merge);
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(merge, "u_GlowDepth"), 0);
|
||||
GLSMPrograms.glUseProgram(0);
|
||||
vao = GLSMVertexInput.glGenVertexArrays();
|
||||
compositeState = StateSet.forMask(GL11.GL_ALL_ATTRIB_BITS);
|
||||
}
|
||||
|
||||
private void prepare(Target target) {
|
||||
clear(target);
|
||||
blit(main.framebuffer(), target.framebuffer.getId(), depthFormat.isCombinedStencil() ? GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_STENCIL_BUFFER_BIT : GL11.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
private void clear(Target target) {
|
||||
if (prepareState == null) prepareState = StateSet.forMask(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_SCISSOR_BIT);
|
||||
final int depth = GLSMAttribStack.pushState(prepareState);
|
||||
try {
|
||||
GLSMRasterizer.disableScissorTest();
|
||||
GLSMBlend.glColorMask(true, true, true, true);
|
||||
target.framebuffer.bind();
|
||||
GLSMBlend.glClearColor(0f, 0f, 0f, 0f);
|
||||
GLSMFramebuffer.glClear(GL11.GL_COLOR_BUFFER_BIT);
|
||||
} finally {
|
||||
GLSMAttribStack.popStateTo(depth);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearDepth(Target target) {
|
||||
if (clearDepthState == null) clearDepthState = StateSet.forMask(GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_SCISSOR_BIT);
|
||||
final int depth = GLSMAttribStack.pushState(clearDepthState);
|
||||
try {
|
||||
GLSMRasterizer.disableScissorTest();
|
||||
GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
GLSMDepthStencilAlpha.glClearDepth(1.0);
|
||||
target.framebuffer.bind();
|
||||
GLSMFramebuffer.glClear(GL11.GL_DEPTH_BUFFER_BIT);
|
||||
} finally {
|
||||
GLSMAttribStack.popStateTo(depth);
|
||||
}
|
||||
}
|
||||
|
||||
private void blit(int from, int to, int mask) {
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, from);
|
||||
GLSMFramebuffer.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, to);
|
||||
GLSMFramebuffer.glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, mask, GL11.GL_NEAREST);
|
||||
}
|
||||
|
||||
private static void bindTexture(int unit, int texture) {
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
private void syncSize() {
|
||||
if (main.width() == width && main.height() == height && main.depthVersion() == depthVersion) return;
|
||||
destroyTargets();
|
||||
width = main.width();
|
||||
height = main.height();
|
||||
depthVersion = main.depthVersion();
|
||||
depthFormat = DepthBufferFormat.fromGlEnumOrDefault(TextureInfoCache.INSTANCE.getInfo(main.depthTexture()).getInternalFormat());
|
||||
}
|
||||
|
||||
private Target layer(TranslucentLayer layer) {
|
||||
final int i = layer.ordinal();
|
||||
if (layers[i] == null) layers[i] = new Target(width, height, depthFormat, true);
|
||||
return layers[i];
|
||||
}
|
||||
|
||||
private Target glowDepth() {
|
||||
if (glowDepth == null) glowDepth = new Target(width, height, depthFormat, false);
|
||||
return glowDepth;
|
||||
}
|
||||
|
||||
private Target depthSnapshot() {
|
||||
if (depthSnapshot == null) depthSnapshot = new Target(width, height, depthFormat, false);
|
||||
return depthSnapshot;
|
||||
}
|
||||
|
||||
private void destroyTargets() {
|
||||
for (int i = 0; i < LAYERS; i++) {
|
||||
if (layers[i] != null) layers[i].destroy();
|
||||
layers[i] = null;
|
||||
}
|
||||
if (depthSnapshot != null) depthSnapshot.destroy();
|
||||
depthSnapshot = null;
|
||||
if (glowDepth != null) glowDepth.destroy();
|
||||
glowDepth = null;
|
||||
DepthEcho.disarm();
|
||||
resetFrame();
|
||||
}
|
||||
|
||||
private static final class CompositeProgram {
|
||||
final GlProgram<Object> program;
|
||||
final int maskUniform;
|
||||
|
||||
CompositeProgram(String name, ShaderConstants constants) {
|
||||
program = PanoramaRenderer.loadProgram(name, "angelica:panorama_blur", "angelica:translucency_composite", constants, ctx -> ctx);
|
||||
final int handle = program.handle();
|
||||
GLSMPrograms.glUseProgram(handle);
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(handle, "u_Depth"), 0);
|
||||
for (int i = 0; i < LAYERS; i++) {
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(handle, "u_Layer" + i), FIRST_LAYER_UNIT + i);
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(handle, "u_LayerDepth" + i), FIRST_LAYER_UNIT + LAYERS + i);
|
||||
}
|
||||
GLSMPrograms.glUniform1i(GLSMPrograms.glGetUniformLocation(handle, "u_TerrainBehind"), TERRAIN_BEHIND_UNIT);
|
||||
maskUniform = GLSMPrograms.glGetUniformLocation(handle, "u_LayerMask");
|
||||
GLSMPrograms.glUseProgram(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Target {
|
||||
final int color;
|
||||
final int depth;
|
||||
final GlFramebuffer framebuffer;
|
||||
int behind;
|
||||
|
||||
Target(int width, int height, DepthBufferFormat depthFormat, boolean withColor) {
|
||||
depth = texture(width, height, depthFormat.getGlInternalFormat(), depthFormat.getGlType(), depthFormat.getGlFormat());
|
||||
framebuffer = new GlFramebuffer();
|
||||
framebuffer.addDepthAttachment(depth);
|
||||
if (withColor) {
|
||||
color = texture(width, height, GL11.GL_RGBA8, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
|
||||
framebuffer.addColorAttachment(0, color);
|
||||
framebuffer.drawBuffers(SINGLE_BUFFER);
|
||||
framebuffer.readBuffer(0);
|
||||
} else {
|
||||
color = 0;
|
||||
framebuffer.noDrawBuffers();
|
||||
RenderSystem.readBuffer(framebuffer.getId(), GL11.GL_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void attachBehind(int width, int height) {
|
||||
if (behind != 0) return;
|
||||
behind = texture(width, height, GL11.GL_RGBA8, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
|
||||
framebuffer.addColorAttachment(1, behind);
|
||||
}
|
||||
|
||||
private static int texture(int width, int height, int internalFormat, int format, int type) {
|
||||
final int previous = GLSMQueries.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
final int texture = GLSMTextures.glGenTextures();
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, texture);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
|
||||
GLSMTextures.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
|
||||
GLSMTextures.glTexImage2D(GL11.GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, (ByteBuffer) null);
|
||||
GLSMTextures.glBindTexture(GL11.GL_TEXTURE_2D, previous);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
framebuffer.destroy();
|
||||
if (color != 0) GLSMTextures.glDeleteTextures(color);
|
||||
if (behind != 0) GLSMTextures.glDeleteTextures(behind);
|
||||
GLSMTextures.glDeleteTextures(depth);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class MinecraftTarget implements MainTarget {
|
||||
private static Framebuffer fb() {
|
||||
return Minecraft.getMinecraft().getFramebuffer();
|
||||
}
|
||||
|
||||
@Override public int framebuffer() { return fb().framebufferObject; }
|
||||
@Override public int depthTexture() { return ((IRenderTargetExt) fb()).iris$getDepthTextureId(); }
|
||||
@Override public int width() { return fb().framebufferWidth; }
|
||||
@Override public int height() { return fb().framebufferHeight; }
|
||||
@Override public int depthVersion() { return ((IRenderTargetExt) fb()).iris$getDepthBufferVersion(); }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.rendering.translucency;
|
||||
|
||||
public enum TranslucentLayer {
|
||||
TERRAIN,
|
||||
BLOCK_ENTITIES,
|
||||
PARTICLES,
|
||||
WEATHER,
|
||||
CLOUDS
|
||||
}
|
||||
@@ -47,7 +47,6 @@ import me.jellysquid.mods.sodium.client.gui.options.named.MultiDrawMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.ParticleMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TexelSampling;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TextureFilterMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TranslucencyMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.AngelicaOptionsStorage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.CubicChunksOptionStorage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.storage.MinecraftOptionsStorage;
|
||||
@@ -404,23 +403,15 @@ public class SodiumGameOptionPages {
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build()
|
||||
)
|
||||
.add(OptionImpl.createBuilder(TranslucencyMode.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.translucency_mode.name"))
|
||||
.setTooltip(I18n.format("sodium.options.translucency_mode.tooltip"))
|
||||
.setControl(o -> new CyclingControl<>(o, TranslucencyMode.class))
|
||||
.setBinding((opts, value) -> opts.performance.translucencyMode = value, opts -> opts.performance.translucencyMode)
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.translucency_sorting.name"))
|
||||
.setTooltip(I18n.format("sodium.options.translucency_sorting.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.performance.translucencySorting = value, opts -> opts.performance.translucencySorting)
|
||||
.setImpact(OptionImpact.MEDIUM)
|
||||
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
|
||||
.build()
|
||||
)
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.block_entities_before_translucent_terrain.name"))
|
||||
.setTooltip(I18n.format("sodium.options.block_entities_before_translucent_terrain.tooltip"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> opts.performance.blockEntitiesBeforeTranslucentTerrain = value, opts -> opts.performance.blockEntitiesBeforeTranslucentTerrain)
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.build()
|
||||
)
|
||||
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
|
||||
.setName(I18n.format("sodium.options.use_entity_culling.name"))
|
||||
.setTooltip(I18n.format("sodium.options.use_entity_culling.tooltip"))
|
||||
|
||||
@@ -15,7 +15,6 @@ import me.jellysquid.mods.sodium.client.gui.options.named.MipmapGeneration;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.MultiDrawMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TexelSampling;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TextureFilterMode;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.named.TranslucencyMode;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
@@ -25,7 +24,6 @@ import org.embeddedt.embeddium.impl.render.chunk.occlusion.AsyncOcclusionMode;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -126,7 +124,7 @@ public class SodiumGameOptions {
|
||||
|
||||
if (Files.exists(path)) {
|
||||
try (FileReader reader = new FileReader(path.toFile())) {
|
||||
config = read(reader);
|
||||
config = GSON.fromJson(reader, SodiumGameOptions.class);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not parse config", e);
|
||||
} catch (JsonSyntaxException e) {
|
||||
@@ -144,6 +142,23 @@ public class SodiumGameOptions {
|
||||
|
||||
config.configPath = path;
|
||||
|
||||
if (config.advanced.streamingUploadStrategy == null) {
|
||||
config.advanced.streamingUploadStrategy = StreamingUploader.UploadStrategy.MAP_BUFFER_RANGE;
|
||||
}
|
||||
|
||||
if (config.quality.textureFilterMode == null) {
|
||||
config.quality.textureFilterMode = TextureFilterMode.RGSS_ANISOTROPIC;
|
||||
}
|
||||
|
||||
if (config.quality.texelSampling == null) {
|
||||
config.quality.texelSampling = TexelSampling.LINEAR;
|
||||
}
|
||||
config.quality.guiBlockSupersampling = Integer.highestOneBit(MathHelper.clamp_int(config.quality.guiBlockSupersampling, 1, 16));
|
||||
|
||||
if (config.quality.mipmapGeneration == null) {
|
||||
config.quality.mipmapGeneration = MipmapGeneration.MODERN_VANILLA;
|
||||
}
|
||||
|
||||
if (GLStateManager.capabilities != null) {
|
||||
if (!GLStateManager.capabilities.OpenGL32) {
|
||||
config.performance.cpuRenderAheadLimit = 0;
|
||||
@@ -164,43 +179,6 @@ public class SodiumGameOptions {
|
||||
return config;
|
||||
}
|
||||
|
||||
static SodiumGameOptions read(Reader reader) {
|
||||
final SodiumGameOptions config = GSON.fromJson(reader, SodiumGameOptions.class);
|
||||
config.normalize();
|
||||
return config;
|
||||
}
|
||||
|
||||
private void normalize() {
|
||||
if (this.advanced.streamingUploadStrategy == null) {
|
||||
this.advanced.streamingUploadStrategy = StreamingUploader.UploadStrategy.MAP_BUFFER_RANGE;
|
||||
}
|
||||
|
||||
if (this.quality.textureFilterMode == null) {
|
||||
this.quality.textureFilterMode = TextureFilterMode.RGSS_ANISOTROPIC;
|
||||
}
|
||||
|
||||
if (this.quality.texelSampling == null) {
|
||||
this.quality.texelSampling = TexelSampling.LINEAR;
|
||||
}
|
||||
this.quality.guiBlockSupersampling = Integer.highestOneBit(MathHelper.clamp_int(this.quality.guiBlockSupersampling, 1, 16));
|
||||
|
||||
if (this.quality.mipmapGeneration == null) {
|
||||
this.quality.mipmapGeneration = MipmapGeneration.MODERN_VANILLA;
|
||||
}
|
||||
|
||||
if (this.performance.translucencySorting != null) {
|
||||
this.performance.translucencyMode = this.performance.translucencySorting ? TranslucencyMode.FAST : TranslucencyMode.OFF;
|
||||
this.performance.translucencySorting = null;
|
||||
}
|
||||
if (this.performance.translucencyMode == null) {
|
||||
this.performance.translucencyMode = TranslucencyMode.FAST;
|
||||
}
|
||||
}
|
||||
|
||||
String toJson() {
|
||||
return GSON.toJson(this);
|
||||
}
|
||||
|
||||
private static boolean isLwjgl2() {
|
||||
return SodiumGameOptions.class.getClassLoader().getResource("org/lwjgl/Sys.class") != null;
|
||||
}
|
||||
@@ -218,7 +196,7 @@ public class SodiumGameOptions {
|
||||
throw new IOException("Not a directory: " + dir);
|
||||
}
|
||||
|
||||
Files.writeString(this.configPath, toJson());
|
||||
Files.writeString(this.configPath, GSON.toJson(this));
|
||||
if (Iris.enabled) {
|
||||
try {
|
||||
if (Iris.getIrisConfig() != null) {
|
||||
@@ -255,9 +233,7 @@ public class SodiumGameOptions {
|
||||
public boolean useFogOcclusion = true;
|
||||
public boolean useBlockFaceCulling = true;
|
||||
public boolean useCompactVertexFormat = true;
|
||||
public TranslucencyMode translucencyMode = TranslucencyMode.FAST;
|
||||
public Boolean translucencySorting;
|
||||
public boolean blockEntitiesBeforeTranslucentTerrain = true;
|
||||
public boolean translucencySorting = true;
|
||||
public boolean useRenderPassOptimization = true;
|
||||
public int cpuRenderAheadLimit = 3;
|
||||
}
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package me.jellysquid.mods.sodium.client.gui.options.named;
|
||||
|
||||
public enum TranslucencyMode implements NamedState {
|
||||
OFF("options.off"),
|
||||
FAST("options.graphics.fast"),
|
||||
FANCY("options.graphics.fancy");
|
||||
|
||||
private final String name;
|
||||
|
||||
TranslucencyMode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public boolean sorts() {
|
||||
return this != OFF;
|
||||
}
|
||||
|
||||
public boolean composites() {
|
||||
return this == FANCY;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import com.gtnewhorizons.angelica.glsm.GLSMMatrices;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.LightingSnapshot;
|
||||
import com.gtnewhorizons.angelica.glsm.StateSet;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TranslucentPeel;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
@@ -67,14 +66,12 @@ public class AngelicaBufferSource implements Groupable {
|
||||
}
|
||||
|
||||
public SegmentedBufferBuilder getBuffer(RenderLayer type, int blockEntityId) {
|
||||
TranslucentPeel.queued(type, this, type);
|
||||
renderOrderManager.begin(type);
|
||||
int affinity = affinities.getAndMoveToLast(type);
|
||||
if (affinity == -1) {
|
||||
if (affinities.size() < builders.length) {
|
||||
affinity = affinities.size();
|
||||
} else {
|
||||
TranslucentPeel.queuedUnordered(affinities.firstKey());
|
||||
affinity = affinities.removeFirstInt();
|
||||
}
|
||||
affinities.put(type, affinity);
|
||||
@@ -166,7 +163,16 @@ public class AngelicaBufferSource implements Groupable {
|
||||
public void endBatch(LayerDrawHook hook) {
|
||||
ensurePrepared();
|
||||
try {
|
||||
drawOrder(hook);
|
||||
int lastGlint = -1;
|
||||
for (int i = 0, n = order.size(); i < n; i++) {
|
||||
if (getTransparencyType(order.get(i)) == TransparencyType.DECAL) lastGlint = i;
|
||||
}
|
||||
for (int i = 0, n = order.size(); i < n; i++) {
|
||||
final RenderLayer layer = order.get(i);
|
||||
if (getTransparencyType(layer) != TransparencyType.AFTER_GLINT) drawLayer(layer, hook);
|
||||
if (i == lastGlint) drawAfterGlintLayers(hook);
|
||||
}
|
||||
if (lastGlint < 0) drawAfterGlintLayers(hook);
|
||||
} catch (Throwable t) {
|
||||
discardAfterFailure(t);
|
||||
throw t;
|
||||
@@ -175,29 +181,6 @@ public class AngelicaBufferSource implements Groupable {
|
||||
finish();
|
||||
}
|
||||
|
||||
public void drawPending(LayerDrawHook hook) {
|
||||
ensurePrepared();
|
||||
drawOrder(hook);
|
||||
}
|
||||
|
||||
public void openDrawState() {
|
||||
ensureDrawState();
|
||||
saveIrisState();
|
||||
}
|
||||
|
||||
private void drawOrder(LayerDrawHook hook) {
|
||||
int lastGlint = -1;
|
||||
for (int i = 0, n = order.size(); i < n; i++) {
|
||||
if (getTransparencyType(order.get(i)) == TransparencyType.DECAL) lastGlint = i;
|
||||
}
|
||||
for (int i = 0, n = order.size(); i < n; i++) {
|
||||
final RenderLayer layer = order.get(i);
|
||||
if (getTransparencyType(layer) != TransparencyType.AFTER_GLINT) drawLayer(layer, hook);
|
||||
if (i == lastGlint) drawAfterGlintLayers(hook);
|
||||
}
|
||||
if (lastGlint < 0) drawAfterGlintLayers(hook);
|
||||
}
|
||||
|
||||
private void drawAfterGlintLayers(LayerDrawHook hook) {
|
||||
for (int i = 0, n = order.size(); i < n; i++) {
|
||||
final RenderLayer layer = order.get(i);
|
||||
@@ -215,14 +198,6 @@ public class AngelicaBufferSource implements Groupable {
|
||||
finish();
|
||||
}
|
||||
|
||||
private void ensureDrawState() {
|
||||
if (drawStateDepth >= 0) return;
|
||||
drawStateDepth = GLSMAttribStack.pushState(StateSet.BATCH);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
if (passLighting != null) GLSMLighting.applyLighting(passLighting);
|
||||
drawDefaults.apply();
|
||||
}
|
||||
|
||||
private void restoreDrawState() {
|
||||
if (drawStateDepth >= 0) {
|
||||
drawDefaults.restore();
|
||||
@@ -252,7 +227,12 @@ public class AngelicaBufferSource implements Groupable {
|
||||
final boolean hasDynamic = segments != null && !segments.isEmpty();
|
||||
final boolean hasRetained = hook != null && hook.hasDraws(layer);
|
||||
if (!hasDynamic && !hasRetained) return;
|
||||
ensureDrawState();
|
||||
if (drawStateDepth < 0) {
|
||||
drawStateDepth = GLSMAttribStack.pushState(StateSet.BATCH);
|
||||
GLSMTextures.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
if (passLighting != null) GLSMLighting.applyLighting(passLighting);
|
||||
drawDefaults.apply();
|
||||
}
|
||||
saveIrisState();
|
||||
layer.startDrawing();
|
||||
Throwable failure = null;
|
||||
|
||||
@@ -41,6 +41,7 @@ class CoreTransformHelper {
|
||||
transformer.injectVariable("uniform vec4 iris_WeatherParams0;");
|
||||
transformer.injectVariable("uniform vec4 iris_WeatherParams1;");
|
||||
transformer.injectVariable("uniform vec4 iris_WeatherParams2;");
|
||||
transformer.injectVariable("uniform vec4 iris_WeatherParams3;");
|
||||
transformer.injectVariable("vec4 iris_Vertex;");
|
||||
transformer.injectVariable("vec4 iris_Color;");
|
||||
transformer.injectVariable("vec4 iris_MultiTexCoord0;");
|
||||
|
||||
@@ -44,6 +44,7 @@ public class IrisInternalUniforms {
|
||||
private static final Vector4f WEATHER_0 = new Vector4f();
|
||||
private static final Vector4f WEATHER_1 = new Vector4f();
|
||||
private static final Vector4f WEATHER_2 = new Vector4f();
|
||||
private static final Vector4f WEATHER_3 = new Vector4f();
|
||||
|
||||
public static void addWeatherUniforms(DynamicUniformHolder uniforms) {
|
||||
uniforms.uniform4f(PER_FRAME, "iris_WeatherParams0", () -> WEATHER_0.set(
|
||||
@@ -51,7 +52,9 @@ public class IrisInternalUniforms {
|
||||
uniforms.uniform4f(PER_FRAME, "iris_WeatherParams1", () -> WEATHER_1.set(
|
||||
WeatherParams.cameraFracX, WeatherParams.cameraFracZ, WeatherParams.partialTicks, WeatherParams.age));
|
||||
uniforms.uniform4f(PER_FRAME, "iris_WeatherParams2", () -> WEATHER_2.set(
|
||||
WeatherParams.rainScroll, WeatherParams.snowScroll, WeatherParams.rainStrength, 0.0f));
|
||||
WeatherParams.vanillaTick, WeatherParams.providerTick, WeatherParams.rainStrength, WeatherParams.providerAge));
|
||||
uniforms.uniform4f(PER_FRAME, "iris_WeatherParams3", () -> WEATHER_3.set(
|
||||
WeatherParams.providerInvRadius, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
public static void addFogUniforms(DynamicUniformHolder uniforms, FogMode fogMode) {
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class PerFrameUniformBlockHarvester {
|
||||
"gbufferModelView", "gbufferModelViewInverse", "gbufferPreviousModelView",
|
||||
"gbufferProjection", "gbufferProjectionInverse", "gbufferPreviousProjection",
|
||||
"fogColor", "iris_FogColor", "iris_FogStart", "iris_FogEnd", "iris_FogDensity",
|
||||
"iris_WeatherParams0", "iris_WeatherParams1", "iris_WeatherParams2");
|
||||
"iris_WeatherParams0", "iris_WeatherParams1", "iris_WeatherParams2", "iris_WeatherParams3");
|
||||
|
||||
/**
|
||||
* @param primary manifest whose entry order defines the block layout
|
||||
|
||||
@@ -57,7 +57,8 @@ sodium.options.use_particle_culling.name=Partikel-Culling
|
||||
sodium.options.use_particle_culling.tooltip=Zeigt nur Partikel innerhalb des Spielersichtfeldes an. Dies kann die Performance bemerkbar verbessern, wenn viele Partikel in der Nähe sind.
|
||||
sodium.options.animate_only_visible_textures.name=Nur sichtbare Texturen animieren
|
||||
sodium.options.animate_only_visible_textures.tooltip=Animiert nur Texturen, die auch im Sichtfeld des Spielers sind. Dies kann die Framerate mancher Hardware stark verbessern, besonders bei "schwereren" Ressourcenpaketen. Wenn du Probleme damit hast, dass Texturen nicht animiert werden, versuch, ob das hier auszuschalten hilft.
|
||||
sodium.options.translucency_mode.name=Durchsichtigkeits-Sortierung
|
||||
sodium.options.translucency_sorting.name=Durchsichtigkeits-Sortierung
|
||||
sodium.options.translucency_sorting.tooltip=Aktiviert die korrekte Sortierung durchsichtiger Blöcke von hinten nach vorne für bessered Rendern,insbesondere bei überlappenden durchsichtigen Blöcken. Dies kann die Rechenlast erhöhen.
|
||||
sodium.options.cpu_render_ahead_limit.name=CPU-Vorausrendern begrenzen
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=Die maximale Anzahl an Frames, die der CPU auf das Rendern des GPU warten darf. Sehr niedrige oder hohe Werte können die Bildrate destabilisieren.
|
||||
sodium.options.cpu_render_ahead_limit.value=%s Frame(s)
|
||||
|
||||
@@ -89,10 +89,8 @@ sodium.options.use_particle_culling.name=Particle Culling
|
||||
sodium.options.use_particle_culling.tooltip=If enabled, only particles which are determined to be visible will be rendered. This can provide a significant improvement to frame rates when many particles are nearby.
|
||||
sodium.options.animate_only_visible_textures.name=Animate Only Visible Textures
|
||||
sodium.options.animate_only_visible_textures.tooltip=If enabled, only animated textures determined to be visible will be updated. This can provide a significant boost to frame rates on some hardware, especially with heavier resource packs. If you experience issues with some textures not being animated, try disabling this option.
|
||||
sodium.options.translucency_mode.name=Translucency Sorting
|
||||
sodium.options.translucency_mode.tooltip=Fast sorts translucent terrain (water, stained glass, ice) and translucent tile entities back to front so overlapping layers draw correctly. Fancy also draws translucent terrain, translucent tile entities, particles, weather and clouds into separate layers that blend correctly over one another; it uses more video memory and GPU time and has no effect with a shader pack. Off is fastest but causes layering artifacts. Changing this reloads chunks.
|
||||
sodium.options.block_entities_before_translucent_terrain.name=Tile Entities Before Translucent Terrain
|
||||
sodium.options.block_entities_before_translucent_terrain.tooltip=If enabled, translucent tile entities are drawn before translucent terrain (water, stained glass, ice), so that the latter does not hide the former behind it. Tile Entities in front of terrain may hide the terrain, and glows in front of terrain may appear behind it. Always on with Fancy translucency sorting.
|
||||
sodium.options.translucency_sorting.name=Translucency Sorting
|
||||
sodium.options.translucency_sorting.tooltip=If enabled, translucent terrain (water, stained glass, ice) and translucent tile entities are sorted back to front so overlapping layers draw correctly. Disabling improves performance in scenes with lots of translucent blocks but causes layering artifacts. Changing this reloads chunks.
|
||||
sodium.options.cpu_render_ahead_limit.name=CPU Render-Ahead Limit
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=How many frames the CPU may run ahead of the GPU. Lower values cut input latency, higher values smooth out uneven frame times. Very low or high values may create frame rate instability. 0 disables it; the SDL-GPU backend ignores it and applies its own backpressure.
|
||||
sodium.options.cpu_render_ahead_limit.value=%s frame(s)
|
||||
|
||||
@@ -82,7 +82,8 @@ sodium.options.use_particle_culling.name=パーティクルカリング
|
||||
sodium.options.use_particle_culling.tooltip=有効にすると、見えると判断されたパーティクルのみが描画されるようになります。近くに多数のパーティクルがある場合にFPSが大幅に向上する可能性があります。
|
||||
sodium.options.animate_only_visible_textures.name=見えるアニメーションのみ描画
|
||||
sodium.options.animate_only_visible_textures.tooltip=有効にすると、表示可能と判断されたアニメーションのみが描画されます。特にリソースパックの負荷が高い場合、一部のハードウェアでFPSが大幅に向上する可能性があります。一部のアニメーションが動かないなどの問題が発生した場合は、この設定を無効にしてください。
|
||||
sodium.options.translucency_mode.name=半透明ブロックの整理
|
||||
sodium.options.translucency_sorting.name=半透明ブロックの整理
|
||||
sodium.options.translucency_sorting.tooltip=有効にすると、半透明ブロックは奥から手前へと正しく並べ替えられ、特に複数の半透明ブロックが重なっている場合の品質が向上しますが、代わりに負荷が上昇します。
|
||||
sodium.options.cpu_render_ahead_limit.name=CPUの先読み処理制限
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=CPUがGPUの描画完了まで待機できる最大フレーム数を設定します。極端に低い値、または高い値を設定すると、FPSが不安定になる可能性があります。
|
||||
sodium.options.cpu_render_ahead_limit.value=%s フレーム
|
||||
|
||||
@@ -89,7 +89,8 @@ sodium.options.use_particle_culling.name=Culling cząstek
|
||||
sodium.options.use_particle_culling.tooltip=Jeśli włączone, tylko cząstki, które uważane są za widoczne, będą renderowane. To może skutkować znaczną poprawą klatek na sekundę, gdy wiele cząstek znajduje się w polu widzenia.
|
||||
sodium.options.animate_only_visible_textures.name=Animuj tylko widoczne tekstury
|
||||
sodium.options.animate_only_visible_textures.tooltip=Jeśli włączone, tylko animowane tekstury, które uważane są za widoczne, będą aktualizowane. To może pomóc z wydajnością na niektórych systemach, szczególnie z cięższymi paczkami zasobów. Jeśli zauważyłeś, że niektóre tekstury nie są animowane, spróbuj wyłączyć tę opcję.
|
||||
sodium.options.translucency_mode.name=Sortowanie przezroczystości
|
||||
sodium.options.translucency_sorting.name=Sortowanie przezroczystości
|
||||
sodium.options.translucency_sorting.tooltip=Jeśli włączone, przezroczysty teren (woda, kolorowe szkło, lód) i przezroczyste byty-bloki będą sortowane od tyłu do przodu, aby nakładające się warstwy były poprawnie wyświetlone. Wyłączenie tej opcji zwiększa wdyajność w sytuacjach z dużą ilością przezroczystych bloków, ale powoduje artefakty. Zmienienie tej opcji przeładowuje chunki.
|
||||
sodium.options.cpu_render_ahead_limit.name=Limit renderowania klatek z wyprzedzeniem przez CPU
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=Określa maksymalną liczbę klatek na które CPU może czekać, aby zostały wyrenderowane przez GPU. Bardzo niskie lub wysokie wartości mogą powodować niestabilność klatek. 0 wyłącza tą opcję; Backend SDL-GPU ignoruje ją i stosuje własne rozwiązanie.
|
||||
sodium.options.cpu_render_ahead_limit.value=%s klat(ki/ek)
|
||||
|
||||
@@ -55,7 +55,8 @@ sodium.options.use_particle_culling.name=Отсечение Частиц
|
||||
sodium.options.use_particle_culling.tooltip=Если включено, будут отрисовываться только те частицы, которые определены как видимые. Это может значительно улучшить частоту кадров, когда рядом находится много частиц.
|
||||
sodium.options.animate_only_visible_textures.name=Анимировать Только Видимые Текстуры
|
||||
sodium.options.animate_only_visible_textures.tooltip=Если включено, будут обновляться только анимированные текстуры, определенные как видимые. Это может значительно увеличить частоту кадров на некотором оборудовании, особенно с более тяжелыми ресурс-паками. Если у вас возникают проблемы с некоторыми текстурами, которые не анимируются, попробуйте отключить эту опцию.
|
||||
sodium.options.translucency_mode.name=Сортировка Прозрачности
|
||||
sodium.options.translucency_sorting.name=Сортировка Прозрачности
|
||||
sodium.options.translucency_sorting.tooltip=Если включено, прозрачные блоки будут правильно отсортированы сзади вперед для обеспечения лучшей отрисовки, особенно когда в поле зрения находится несколько прозрачных блоков и они слоены. Это немного дорогостоящая операция.
|
||||
sodium.options.cpu_render_ahead_limit.name=Предел Предварительной Отрисовки CPU
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=Определяет максимальное количество кадров, которые CPU может ожидать завершения отрисовки на GPU. Очень низкие или высокие значения могут создать нестабильность частоты кадров.
|
||||
sodium.options.cpu_render_ahead_limit.value=%s кадр(ов)
|
||||
|
||||
@@ -73,7 +73,8 @@ sodium.options.use_particle_culling.name=Відсікання частинок
|
||||
sodium.options.use_particle_culling.tooltip=Якщо увімкнено, рендеритися будуть лише ті частинки, які є безпосередньо видимими. Це дозволяє суттєво підвищити частоту кадрів, коли поруч є велика кількість частинок.
|
||||
sodium.options.animate_only_visible_textures.name=Анімувати лише видимі текстури
|
||||
sodium.options.animate_only_visible_textures.tooltip=Якщо увімкнено, оновлюватимуться лише ті анімовані текстури, які є видимими для гравця. Це може суттєво підвищити частоту кадрів на деякому залізі, особливо з важкими ресурспаками. Якщо ви помітили, що деякі текстури перестали анімуватися, спробуйте вимкнути цю опцію.
|
||||
sodium.options.translucency_mode.name=Сортування напівпрозорості
|
||||
sodium.options.translucency_sorting.name=Сортування напівпрозорості
|
||||
sodium.options.translucency_sorting.tooltip=Якщо увімкнено, напівпрозорі блоки сортуватимуться у правильному порядку (від дальніх до ближніх) для коректнішого рендерингу. Це особливо важливо, коли кілька таких блоків накладаються один на одного шарами. Ця операція є досить ресурсомісткою.
|
||||
sodium.options.cpu_render_ahead_limit.name=Ліміт заздалегідь підготовлених кадрів CPU
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=Визначає, скільки кадрів процесор може підготувати наперед для відеокарти. Нижчі значення зменшують затримку введення, а вищі — згладжують нерівномірний час кадру. Занадто низькі або високі значення можуть викликати нестабільність частоти кадрів. Значення 0 вимикає цей параметр; бекенд SDL-GPU ігнорує його та застосовує власний механізм зворотного тиску.
|
||||
sodium.options.cpu_render_ahead_limit.value=%s кадр(ів)
|
||||
|
||||
@@ -59,7 +59,8 @@ sodium.options.use_particle_culling.name=使用粒子剔除
|
||||
sodium.options.use_particle_culling.tooltip=如果启用,则只会渲染可见的粒子。当附近有许多粒子时,可以显著提高帧率。
|
||||
sodium.options.animate_only_visible_textures.name=仅绘制可见动画纹理
|
||||
sodium.options.animate_only_visible_textures.tooltip=如果启用,则只会更新确定为可见的纹理动画。这可以显著提高某些硬件的帧率(FPS),尤其是对于大型的资源包。如果你遇到某些纹理失去动画的问题,请尝试禁用此选项。
|
||||
sodium.options.translucency_mode.name=半透明排序
|
||||
sodium.options.translucency_sorting.name=半透明排序
|
||||
sodium.options.translucency_sorting.tooltip=如果启用,半透明方块将从后向前正确排序,当多个分层的半透明方块在视野中时,可以提供更好的渲染效果。这个选项性能花销较大。
|
||||
sodium.options.cpu_render_ahead_limit.name=CPU 预渲染限制
|
||||
sodium.options.cpu_render_ahead_limit.tooltip=指定CPU可以在GPU上等待完成渲染的最大帧数。非常低或非常高的值都可能会导致帧率(FPS)不稳定。
|
||||
sodium.options.cpu_render_ahead_limit.value=%s 帧
|
||||
|
||||
@@ -54,13 +54,6 @@ out vec4 fragColor; // The output fragment for the color framebuffer
|
||||
#define fragColor gl_FragColor
|
||||
#endif
|
||||
|
||||
#if !defined(LEGACY) && defined(TRANSLUCENCY_SPLIT)
|
||||
// Fragments behind the block-entity layer's depth go to a second sheet (TranslucencyLayers).
|
||||
uniform bool u_SplitEnabled;
|
||||
uniform sampler2D u_SplitDepth;
|
||||
layout(location = 1) out vec4 fragBehind;
|
||||
#endif
|
||||
|
||||
vec2 snapToTexelCentre(vec2 uv, vec2 texelSize, vec2 texelsPerPixel) {
|
||||
vec2 centreCoords = uv / texelSize - 0.5;
|
||||
vec2 lowerCentre = floor(centreCoords);
|
||||
@@ -244,12 +237,4 @@ void main() {
|
||||
#else // No fog
|
||||
fragColor = diffuseColor;
|
||||
#endif
|
||||
|
||||
#if !defined(LEGACY) && defined(TRANSLUCENCY_SPLIT)
|
||||
fragBehind = vec4(0.0);
|
||||
if (u_SplitEnabled && gl_FragCoord.z > texelFetch(u_SplitDepth, ivec2(gl_FragCoord.xy), 0).r) {
|
||||
fragBehind = fragColor;
|
||||
fragColor = vec4(0.0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
// A sample is skipped only when all zero, so additive light with no coverage still counts. The TERRAIN_BEHIND sheet
|
||||
// sorts at the block-entity depth where the front sheet has terrain, inserted first so a tie keeps it behind.
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_Depth;
|
||||
uniform sampler2D u_Layer0;
|
||||
uniform sampler2D u_Layer1;
|
||||
uniform sampler2D u_Layer2;
|
||||
uniform sampler2D u_Layer3;
|
||||
uniform sampler2D u_Layer4;
|
||||
uniform sampler2D u_LayerDepth0;
|
||||
uniform sampler2D u_LayerDepth1;
|
||||
uniform sampler2D u_LayerDepth2;
|
||||
uniform sampler2D u_LayerDepth3;
|
||||
uniform sampler2D u_LayerDepth4;
|
||||
uniform int u_LayerMask;
|
||||
#ifdef TERRAIN_BEHIND
|
||||
uniform sampler2D u_TerrainBehind;
|
||||
#define SHEETS 6
|
||||
#else
|
||||
#define SHEETS 5
|
||||
#endif
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
vec4 colors[SHEETS];
|
||||
float depths[SHEETS];
|
||||
int count = 0;
|
||||
float mainDepth;
|
||||
|
||||
void insertSheet(vec4 color, float depth) {
|
||||
if (depth > mainDepth) return;
|
||||
int j = count++;
|
||||
colors[j] = color;
|
||||
depths[j] = depth;
|
||||
while (j > 0 && depths[j] > depths[j - 1]) {
|
||||
vec4 c = colors[j];
|
||||
colors[j] = colors[j - 1];
|
||||
colors[j - 1] = c;
|
||||
float d = depths[j];
|
||||
depths[j] = depths[j - 1];
|
||||
depths[j - 1] = d;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(int bit, sampler2D colorTexture, sampler2D depthTexture) {
|
||||
if ((u_LayerMask & bit) == 0) return;
|
||||
vec4 color = texture(colorTexture, v_TexCoord);
|
||||
if (color == vec4(0.0)) return;
|
||||
insertSheet(color, texture(depthTexture, v_TexCoord).r);
|
||||
}
|
||||
|
||||
#ifdef TERRAIN_BEHIND
|
||||
void insertTerrain() {
|
||||
vec4 behind = texture(u_TerrainBehind, v_TexCoord);
|
||||
vec4 front = texture(u_Layer0, v_TexCoord);
|
||||
if (behind != vec4(0.0)) {
|
||||
insertSheet(behind, front == vec4(0.0) ? texture(u_LayerDepth0, v_TexCoord).r : texture(u_LayerDepth1, v_TexCoord).r);
|
||||
}
|
||||
if (front != vec4(0.0)) insertSheet(front, texture(u_LayerDepth0, v_TexCoord).r);
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
mainDepth = texture(u_Depth, v_TexCoord).r;
|
||||
#ifdef TERRAIN_BEHIND
|
||||
insertTerrain();
|
||||
#else
|
||||
insert(1, u_Layer0, u_LayerDepth0);
|
||||
#endif
|
||||
insert(2, u_Layer1, u_LayerDepth1);
|
||||
insert(4, u_Layer2, u_LayerDepth2);
|
||||
insert(8, u_Layer3, u_LayerDepth3);
|
||||
insert(16, u_Layer4, u_LayerDepth4);
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
result = result * (1.0 - colors[i].a) + colors[i];
|
||||
}
|
||||
fragColor = result;
|
||||
gl_FragDepth = count > 0 ? depths[count - 1] : mainDepth;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 v_TexCoord;
|
||||
|
||||
uniform sampler2D u_GlowDepth;
|
||||
|
||||
void main() {
|
||||
gl_FragDepth = texture(u_GlowDepth, v_TexCoord).r;
|
||||
}
|
||||
@@ -50,7 +50,8 @@
|
||||
"sodium.options.use_particle_culling.tooltip": "启用后,将仅渲染可见的颗粒。当周围有许多颗粒时,这可以显著地提高帧率。",
|
||||
"sodium.options.animate_only_visible_textures.name": "仅渲染可见的动态材质",
|
||||
"sodium.options.animate_only_visible_textures.tooltip": "启用后,将只会更新可见的动画材质。 这可以显着提高某些低配电脑的帧率。 尤其是对于较大的资源包。因此如果你看到动态材质不生效,请尝试禁用此选项。",
|
||||
"sodium.options.translucency_mode.name": "透明度排序",
|
||||
"sodium.options.translucency_sorting.name": "透明度排序",
|
||||
"sodium.options.translucency_sorting.tooltip": "启用后,透明方块将被正确排序,从后向前渲染,以提供更好的渲染效果,特别是当你的视野中有多个重叠的透明方块时。此操作在性能上相对较昂贵。",
|
||||
"sodium.options.cpu_render_ahead_limit.name": "CPU提前渲染限制",
|
||||
"sodium.options.cpu_render_ahead_limit.tooltip": "指定CPU可以在GPU上等待完成渲染的最大帧数。很低或很高的值可能会导致帧速率不稳定。",
|
||||
"sodium.options.cpu_render_ahead_limit.value": "%s帧",
|
||||
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizons.angelica.experimental.surround.Surround;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMDepthStencilAlpha;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucentLayer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
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;
|
||||
|
||||
@Mixin(EntityRenderer.class)
|
||||
public class MixinEntityRenderer_TranslucencyLayers {
|
||||
|
||||
@Inject(method = "renderWorld(FJ)V", at = @At("HEAD"))
|
||||
private void angelica$beginTranslucencyLayers(float partialTicks, long finishTimeNano, CallbackInfo ci) {
|
||||
TranslucencyLayers.INSTANCE.beginFrame();
|
||||
}
|
||||
|
||||
@Inject(method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/client/ForgeHooksClient;dispatchRenderLast(Lnet/minecraft/client/renderer/RenderGlobal;F)V", remap = false))
|
||||
private void angelica$compositeTranslucencyLayers(float partialTicks, long finishTimeNano, CallbackInfo ci) {
|
||||
TranslucencyLayers.INSTANCE.composite();
|
||||
}
|
||||
|
||||
@Surround(id = "translucencyParticles", method = "renderWorld(FJ)V", expect = 2, at = {
|
||||
@At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;renderLitParticles(Lnet/minecraft/entity/Entity;F)V"),
|
||||
@At(value = "INVOKE", target = "Lnet/minecraft/client/particle/EffectRenderer;renderParticles(Lnet/minecraft/entity/Entity;F)V") })
|
||||
private void angelica$particlesLayer() {
|
||||
@Surround.Carry boolean layered = TranslucencyLayers.INSTANCE.beginIfActive(TranslucentLayer.PARTICLES);
|
||||
}
|
||||
|
||||
@Surround.Finally("translucencyParticles")
|
||||
private void angelica$particlesLayerEnd(@Surround.Carry boolean layered) {
|
||||
if (layered) TranslucencyLayers.INSTANCE.end();
|
||||
}
|
||||
|
||||
@Surround(id = "translucencyWeather", method = "renderWorld(FJ)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/EntityRenderer;renderRainSnow(F)V"))
|
||||
private void angelica$weatherLayer(@Surround.Local(argsOnly = true) float partialTicks) {
|
||||
final WorldClient world = Minecraft.getMinecraft().theWorld;
|
||||
@Surround.Carry boolean layered = (world.getRainStrength(partialTicks) > 0.0F || world.provider.getWeatherRenderer() != null)
|
||||
&& TranslucencyLayers.INSTANCE.beginIfActive(TranslucentLayer.WEATHER);
|
||||
// Rain writes no depth, which would leave the layer sorting at the opaque depth behind it.
|
||||
if (layered) GLSMDepthStencilAlpha.glDepthMask(true);
|
||||
}
|
||||
|
||||
@Surround.Finally("translucencyWeather")
|
||||
private void angelica$weatherLayerEnd(@Surround.Carry boolean layered) {
|
||||
if (layered) TranslucencyLayers.INSTANCE.end();
|
||||
}
|
||||
|
||||
@Surround(id = "translucencyClouds", method = "renderWorld(FJ)V", at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/client/renderer/EntityRenderer;renderCloudsCheck(Lnet/minecraft/client/renderer/RenderGlobal;F)V"))
|
||||
private void angelica$cloudsLayer() {
|
||||
@Surround.Carry boolean layered = Minecraft.getMinecraft().gameSettings.shouldRenderClouds() && TranslucencyLayers.INSTANCE.beginIfActive(TranslucentLayer.CLOUDS);
|
||||
}
|
||||
|
||||
@Surround.Finally("translucencyClouds")
|
||||
private void angelica$cloudsLayerEnd(@Surround.Carry boolean layered) {
|
||||
if (layered) TranslucencyLayers.INSTANCE.end();
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.rendering;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMRasterizer;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.shader.Framebuffer;
|
||||
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;
|
||||
|
||||
@Mixin(Framebuffer.class)
|
||||
public class MixinFramebuffer_TranslucencyLayers {
|
||||
|
||||
@Inject(method = "bindFramebuffer", at = @At("HEAD"), cancellable = true)
|
||||
private void angelica$bindOpenTranslucencyLayer(boolean viewport, CallbackInfo ci) {
|
||||
final Framebuffer framebuffer = (Framebuffer) (Object) this;
|
||||
if (!TranslucencyLayers.INSTANCE.redirectsMainBind() || framebuffer != Minecraft.getMinecraft().getFramebuffer()) return;
|
||||
TranslucencyLayers.INSTANCE.bindOpenLayer();
|
||||
if (viewport) GLSMRasterizer.glViewport(0, 0, framebuffer.framebufferWidth, framebuffer.framebufferHeight);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import net.minecraft.client.particle.EffectRenderer;
|
||||
import net.minecraft.client.particle.EntityFX;
|
||||
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;
|
||||
|
||||
@Mixin(EffectRenderer.class)
|
||||
public class MixinEffectRenderer_GlowDepthReplay {
|
||||
|
||||
@Inject(method = "addEffect", at = @At("HEAD"), cancellable = true)
|
||||
private void angelica$dropDuringGlowReplay(EntityFX effect, CallbackInfo ci) {
|
||||
if (DepthEcho.replaying()) ci.cancel();
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.tesr;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.DepthEcho;
|
||||
import net.minecraft.client.audio.ISound;
|
||||
import net.minecraft.client.audio.SoundHandler;
|
||||
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;
|
||||
|
||||
@Mixin(SoundHandler.class)
|
||||
public class MixinSoundHandler_GlowDepthReplay {
|
||||
|
||||
@Inject(method = "playSound", at = @At("HEAD"), cancellable = true)
|
||||
private void angelica$dropDuringGlowReplay(ISound sound, CallbackInfo ci) {
|
||||
if (DepthEcho.replaying()) ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "playDelayedSound", at = @At("HEAD"), cancellable = true)
|
||||
private void angelica$dropDelayedDuringGlowReplay(ISound sound, int delay, CallbackInfo ci) {
|
||||
if (DepthEcho.replaying()) ci.cancel();
|
||||
}
|
||||
}
|
||||
+17
-28
@@ -9,7 +9,6 @@ import com.gtnewhorizons.angelica.glsm.GLSMEnable;
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMTextures;
|
||||
import com.gtnewhorizons.angelica.glsm.profiling.Tracy;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt;
|
||||
import com.gtnewhorizons.angelica.proxy.ClientProxy;
|
||||
import com.gtnewhorizons.angelica.rendering.AngelicaRenderQueue;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.BlockRenderLayer;
|
||||
@@ -17,10 +16,9 @@ import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasSetup;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.ModelPartBatcher;
|
||||
import com.gtnewhorizons.angelica.rendering.tesr.TesrBatchRenderer;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucencyLayers;
|
||||
import com.gtnewhorizons.angelica.rendering.translucency.TranslucentLayer;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.layer.GbufferPrograms;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
@@ -36,7 +34,6 @@ import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraftforge.client.MinecraftForgeClient;
|
||||
import org.embeddedt.embeddium.impl.gl.device.RenderDevice;
|
||||
import org.embeddedt.embeddium.impl.render.terrain.SimpleWorldRenderer;
|
||||
import org.embeddedt.embeddium.impl.render.viewport.Viewport;
|
||||
@@ -66,6 +63,7 @@ import static org.joml.Math.lerp;
|
||||
*/
|
||||
@Mixin(value = RenderGlobal.class, priority = 900)
|
||||
public class MixinRenderGlobal implements IRenderGlobalExt {
|
||||
@Unique private static final long P_BLOCK_ENTITIES_RENDERED = Tracy.plotHandle("blockEntitiesRendered");
|
||||
@Unique private static final Tracy.ZoneId Z_MT_QUEUE = Tracy.zoneId("mtQueue", Tracy.COLOR_TERRAIN);
|
||||
|
||||
@Shadow public Minecraft mc;
|
||||
@@ -148,13 +146,10 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
|
||||
pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (pass == 0) {
|
||||
pipeline.setPhase(WorldRenderingPhase.TERRAIN_SOLID);
|
||||
} else if (pass == 1 && !ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
|
||||
iris$beginTranslucents(pipeline, Camera.INSTANCE);
|
||||
}
|
||||
}
|
||||
if (pass == 1) {
|
||||
celeritas$renderBlockEntitiesBeforeTranslucent(partialTicks);
|
||||
if (pipeline != null) {
|
||||
} else if (pass == 1) {
|
||||
if (!ShadowRenderingState.areShadowsCurrentlyBeingRendered()) {
|
||||
iris$beginTranslucents(pipeline, Camera.INSTANCE);
|
||||
}
|
||||
pipeline.setPhase(WorldRenderingPhase.TERRAIN_TRANSLUCENT);
|
||||
this.renderEngine.bindTexture(TextureMap.locationBlocksTexture);
|
||||
}
|
||||
@@ -192,13 +187,8 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
|
||||
this.celeritas$renderer.drawChunkLayer(BlockRenderLayer.CUTOUT_MIPPED, camX, camY, camZ);
|
||||
} else {
|
||||
mc.mcProfiler.endStartSection(shadow ? SECTION_SHADOW_TRANSLUCENT : SECTION_TRANSLUCENT);
|
||||
final boolean layered = (this.celeritas$renderer.hasVisibleLayer(BlockRenderLayer.TRANSLUCENT) || RenderChunkEvent.BUS.hasListeners()) && TranslucencyLayers.INSTANCE.beginIfActive(TranslucentLayer.TERRAIN);
|
||||
try {
|
||||
this.celeritas$renderer.drawChunkLayer(BlockRenderLayer.TRANSLUCENT, camX, camY, camZ);
|
||||
RenderChunkEvent.post();
|
||||
} finally {
|
||||
if (layered) TranslucencyLayers.INSTANCE.end();
|
||||
}
|
||||
this.celeritas$renderer.drawChunkLayer(BlockRenderLayer.TRANSLUCENT, camX, camY, camZ);
|
||||
RenderChunkEvent.post();
|
||||
}
|
||||
} finally {
|
||||
RenderDevice.exitManagedCode();
|
||||
@@ -286,18 +276,17 @@ public class MixinRenderGlobal implements IRenderGlobalExt {
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderHelper;enableStandardItemLighting()V", ordinal = 0))
|
||||
private void celeritas$enterBlockEntities() {}
|
||||
|
||||
@Unique
|
||||
private void celeritas$renderBlockEntitiesBeforeTranslucent(double partialTicks) {
|
||||
if (ShadowRenderingState.areShadowsCurrentlyBeingRendered()) return;
|
||||
if (!ClientProxy.options().performance.blockEntitiesBeforeTranslucentTerrain && !TranslucencyLayers.INSTANCE.active()) return;
|
||||
if (this.mc.entityRenderer.debugViewDirection != 0) return;
|
||||
this.celeritas$renderer.renderBlockEntitiesBeforeTranslucent((float) partialTicks);
|
||||
}
|
||||
|
||||
@Surround.Return("blockEntities")
|
||||
private void celeritas$renderTileEntities(@Surround.Local(argsOnly = true) float partialTicks) {
|
||||
if (MinecraftForgeClient.getRenderPass() == 1 && !this.celeritas$renderer.takeLatePassOne()) return;
|
||||
this.celeritas$renderer.renderBlockEntitiesInPhase(partialTicks);
|
||||
if (Iris.enabled) {
|
||||
GbufferPrograms.beginBlockEntities();
|
||||
GbufferPrograms.setBlockEntityDefaults();
|
||||
}
|
||||
final int blockEntitiesRendered = this.celeritas$renderer.renderBlockEntities(partialTicks);
|
||||
if (Tracy.ENABLED) Tracy.plotInt(P_BLOCK_ENTITIES_RENDERED, blockEntitiesRendered);
|
||||
if (Iris.enabled) {
|
||||
GbufferPrograms.endBlockEntities();
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyExpressionValue(method = "renderEntities", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/RenderGlobal;tileEntities:Ljava/util/List;", opcode = Opcodes.GETFIELD))
|
||||
|
||||
+4
-1
@@ -68,7 +68,10 @@ public abstract class MixinRenderBlocks implements ExtCeleritasRenderBlocks {
|
||||
private boolean renderingPlainCube;
|
||||
|
||||
@Surround(method = "renderBlockByRenderType", id = "plainCube",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderBlocks;renderStandardBlock(Lnet/minecraft/block/Block;III)Z"),
|
||||
at = {
|
||||
@At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderBlocks;renderStandardBlock(Lnet/minecraft/block/Block;III)Z"),
|
||||
// LOTR's coremod swaps the call for its natural-blocks wrapper, which ends in renderStandardBlock
|
||||
@At(value = "INVOKE", target = "Llotr/common/coremod/LOTRReplacedMethods$BlockRendering;renderStandardBlock(Lnet/minecraft/client/renderer/RenderBlocks;Lnet/minecraft/block/Block;III)Z", remap = false) },
|
||||
require = 1)
|
||||
private void angelica$enterPlainCube() {
|
||||
@Surround.Carry final boolean wasPlainCube = this.renderingPlainCube;
|
||||
|
||||
+11
-6
@@ -33,12 +33,17 @@ public abstract class MixinRenderBlockConnectedTexturesEthereal extends RenderBl
|
||||
block.setBlockBoundsBasedOnState(getFakeRender().blockAccess, x, y, z);
|
||||
getFakeRender().setRenderBoundsFromBlock(block);
|
||||
boolean render = getFakeRender().renderStandardBlock(block, x, y, z);
|
||||
newFakeRenderEthereal.setWorld(renderer.blockAccess);
|
||||
newFakeRenderEthereal.curBlock = getFakeRender().curBlock;
|
||||
newFakeRenderEthereal.curMeta = getFakeRender().curMeta;
|
||||
double h = 0.05D;
|
||||
newFakeRenderEthereal.setRenderBounds(h, h, h, 1.0D - h, 1.0D - h, 1.0D - h);
|
||||
render &= newFakeRenderEthereal.renderStandardBlock(block, x, y, z);
|
||||
try {
|
||||
newFakeRenderEthereal.setWorld(renderer.blockAccess);
|
||||
newFakeRenderEthereal.curBlock = getFakeRender().curBlock;
|
||||
newFakeRenderEthereal.curMeta = getFakeRender().curMeta;
|
||||
double h = 0.05D;
|
||||
newFakeRenderEthereal.setRenderBounds(h, h, h, 1.0D - h, 1.0D - h, 1.0D - h);
|
||||
render &= newFakeRenderEthereal.renderStandardBlock(block, x, y, z);
|
||||
} finally {
|
||||
getFakeRender().setWorld(null);
|
||||
newFakeRenderEthereal.setWorld(null);
|
||||
}
|
||||
return render;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.biomesoplenty;
|
||||
|
||||
import biomesoplenty.common.blocks.BlockBOPAppleLeaves;
|
||||
import jss.notfine.util.LeafRenderUtil;
|
||||
import net.minecraft.block.BlockLeavesBase;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(value = BlockBOPAppleLeaves.class)
|
||||
public abstract class MixinBlockBOPAppleLeaves extends BlockLeavesBase {
|
||||
|
||||
@Shadow(remap = false)
|
||||
private IIcon[][] textures;
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) {
|
||||
final int meta = world.getBlockMetadata(x, y, z);
|
||||
final int type = meta & 3;
|
||||
return textures[LeafRenderUtil.selectRenderMode(world, x, y, z, side) ? 1 : 0][type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @author NotFine
|
||||
* @reason Support new leaf rendering modes on Biomes O' Plenty leaves.
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) {
|
||||
return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side);
|
||||
}
|
||||
|
||||
private MixinBlockBOPAppleLeaves(Material material, boolean fancy) {
|
||||
super(material, fancy);
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.biomesoplenty;
|
||||
|
||||
import biomesoplenty.common.blocks.BlockBOPColorizedLeaves;
|
||||
import biomesoplenty.common.blocks.BlockBOPColorizedLeaves.ColourizedLeafCategory;
|
||||
import jss.notfine.util.LeafRenderUtil;
|
||||
import net.minecraft.block.BlockLeavesBase;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(value = BlockBOPColorizedLeaves.class)
|
||||
public abstract class MixinBlockBOPColorizedLeaves extends BlockLeavesBase {
|
||||
|
||||
@Shadow(remap = false)
|
||||
private IIcon[][] textures;
|
||||
@Shadow(remap = false)
|
||||
@Final
|
||||
private static String[] leaves;
|
||||
|
||||
@Shadow(remap = false)
|
||||
@Final
|
||||
private ColourizedLeafCategory category;
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) {
|
||||
final int meta = world.getBlockMetadata(x, y, z);
|
||||
int type = (meta & 3) + category.ordinal() * 4;
|
||||
if (type >= leaves.length) {
|
||||
type = 0;
|
||||
}
|
||||
return textures[LeafRenderUtil.selectRenderMode(world, x, y, z, side) ? 1 : 0][type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @author NotFine
|
||||
* @reason Support new leaf rendering modes on Biomes O' Plenty leaves.
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) {
|
||||
return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side);
|
||||
}
|
||||
|
||||
private MixinBlockBOPColorizedLeaves(Material material, boolean fancy) {
|
||||
super(material, fancy);
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.biomesoplenty;
|
||||
|
||||
import biomesoplenty.common.blocks.BlockBOPLeaves;
|
||||
import biomesoplenty.common.blocks.BlockBOPLeaves.LeafCategory;
|
||||
import jss.notfine.util.LeafRenderUtil;
|
||||
import net.minecraft.block.BlockLeavesBase;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(value = BlockBOPLeaves.class)
|
||||
public abstract class MixinBlockBOPLeaves extends BlockLeavesBase {
|
||||
|
||||
@Shadow(remap = false)
|
||||
private IIcon[][] textures;
|
||||
@Shadow(remap = false)
|
||||
@Final
|
||||
private static String[] leaves;
|
||||
|
||||
@Shadow(remap = false)
|
||||
@Final
|
||||
private LeafCategory category;
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) {
|
||||
final int meta = world.getBlockMetadata(x, y, z);
|
||||
int type = (meta & 3) + category.ordinal() * 4;
|
||||
if (type >= leaves.length) {
|
||||
type = 0;
|
||||
}
|
||||
return textures[LeafRenderUtil.selectRenderMode(world, x, y, z, side) ? 1 : 0][type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @author NotFine
|
||||
* @reason Support new leaf rendering modes on Biomes O' Plenty leaves.
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) {
|
||||
return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side);
|
||||
}
|
||||
|
||||
private MixinBlockBOPLeaves(Material material, boolean fancy) {
|
||||
super(material, fancy);
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.gtnewhorizons.angelica.mixins.late.notfine.leaves.biomesoplenty;
|
||||
|
||||
import biomesoplenty.common.blocks.BlockBOPPersimmonLeaves;
|
||||
import jss.notfine.util.LeafRenderUtil;
|
||||
import net.minecraft.block.BlockLeavesBase;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(value = BlockBOPPersimmonLeaves.class)
|
||||
public abstract class MixinBlockBOPPersimmonLeaves extends BlockLeavesBase {
|
||||
|
||||
@Shadow(remap = false)
|
||||
private IIcon[][] textures;
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(IBlockAccess world, int x, int y, int z, int side) {
|
||||
final int meta = world.getBlockMetadata(x, y, z);
|
||||
final int type = meta & 3;
|
||||
return textures[LeafRenderUtil.selectRenderMode(world, x, y, z, side) ? 1 : 0][type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @author NotFine
|
||||
* @reason Support new leaf rendering modes on Biomes O' Plenty leaves.
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) {
|
||||
return LeafRenderUtil.shouldSideBeRendered(world, x, y, z, side);
|
||||
}
|
||||
|
||||
private MixinBlockBOPPersimmonLeaves(Material material, boolean fancy) {
|
||||
super(material, fancy);
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 107 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user