mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-14 01:14:08 +00:00
Merge branch 'core-profile' into core-profile-dsa
This commit is contained in:
commit
580b72829d
19 files changed
+368
-37
No files matched your search
@@ -149,7 +149,7 @@ public class CompatShaderTransformer {
|
||||
|
||||
injectMatrixUniforms(transformer);
|
||||
|
||||
transformFog(transformer, isFragment);
|
||||
transformFog(transformer, isFragment, source);
|
||||
|
||||
// gl_FrontLightModelProduct.sceneColor → angelica_SceneColor uniform
|
||||
if (source.contains("gl_FrontLightModelProduct")) {
|
||||
@@ -158,6 +158,8 @@ public class CompatShaderTransformer {
|
||||
}
|
||||
|
||||
// gl_FrontColor (vertex) → gl_Color (fragment) varying chain
|
||||
// Vertex side is unconditional: fragment may read gl_Color without vertex writing gl_FrontColor.
|
||||
// Uses angelica_ prefix to avoid colliding with user-declared varyings (e.g. "v_Color").
|
||||
if (!isFragment) {
|
||||
transformer.injectVariable("out vec4 angelica_FrontColor;");
|
||||
transformer.rename("gl_FrontColor", "angelica_FrontColor");
|
||||
@@ -166,8 +168,10 @@ public class CompatShaderTransformer {
|
||||
// Vertex attributes — replaces removed FFP vertex inputs with explicit in declarations
|
||||
transformVertexAttributes(transformer, source);
|
||||
} else {
|
||||
transformer.injectVariable("in vec4 angelica_FrontColor;");
|
||||
transformer.rename("gl_Color", "angelica_FrontColor");
|
||||
if (source.contains("gl_Color")) {
|
||||
transformer.injectVariable("in vec4 angelica_FrontColor;");
|
||||
transformer.rename("gl_Color", "angelica_FrontColor");
|
||||
}
|
||||
}
|
||||
|
||||
// gl_TexCoord[N] varying array → per-index in/out declarations
|
||||
@@ -261,13 +265,16 @@ public class CompatShaderTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
private static void transformFog(Transformer transformer, boolean isFragment) {
|
||||
private static void transformFog(Transformer transformer, boolean isFragment, String source) {
|
||||
// Vertex side is unconditional: fragment may read gl_FogFragCoord without vertex writing it
|
||||
transformer.rename("gl_FogFragCoord", "angelica_FogFragCoord");
|
||||
if (!isFragment) {
|
||||
transformer.injectVariable("out float angelica_FogFragCoord;");
|
||||
transformer.prependMain("angelica_FogFragCoord = 0.0f;");
|
||||
transformer.prependMain("angelica_FogFragCoord = 0.0;");
|
||||
} else {
|
||||
transformer.injectVariable("in float angelica_FogFragCoord;");
|
||||
if (source.contains("gl_FogFragCoord")) {
|
||||
transformer.injectVariable("in float angelica_FogFragCoord;");
|
||||
}
|
||||
}
|
||||
|
||||
transformer.rename("gl_Fog", "angelica_Fog");
|
||||
@@ -279,7 +286,7 @@ public class CompatShaderTransformer {
|
||||
transformer.injectFunction(
|
||||
"angelica_FogParameters angelica_Fog = angelica_FogParameters("
|
||||
+ "angelica_FogColor, angelica_FogDensity, angelica_FogStart, angelica_FogEnd, "
|
||||
+ "1.0f / (angelica_FogEnd - angelica_FogStart));");
|
||||
+ "1.0 / (angelica_FogEnd - angelica_FogStart));");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -352,6 +359,63 @@ public class CompatShaderTransformer {
|
||||
return source;
|
||||
}
|
||||
|
||||
// Patterns for parsing fragment shader in declarations to generate passthrough vertex shaders
|
||||
private static final Pattern FRAG_IN_COLOR = Pattern.compile("\\bin\\s+vec4\\s+angelica_FrontColor\\b");
|
||||
private static final Pattern FRAG_IN_TEXCOORD = Pattern.compile("\\bin\\s+vec4\\s+angelica_TexCoord(\\d+)\\b");
|
||||
private static final Pattern FRAG_IN_FOGCOORD = Pattern.compile("\\bin\\s+float\\s+angelica_FogFragCoord\\b");
|
||||
|
||||
/**
|
||||
* Generate a passthrough vertex shader for a fragment-only program.
|
||||
*
|
||||
* @param fragmentSource the transformed fragment shader source
|
||||
* @return a complete vertex shader source string
|
||||
*/
|
||||
public static String generatePassthroughVertexShader(String fragmentSource) {
|
||||
final StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("#version 330 core\n\n");
|
||||
|
||||
// Always have position
|
||||
sb.append("layout(location = 0) in vec4 a_Position;\n");
|
||||
|
||||
// Matrix uniforms for position transform
|
||||
sb.append("uniform mat4 angelica_ModelViewMatrix;\n");
|
||||
sb.append("uniform mat4 angelica_ProjectionMatrix;\n");
|
||||
|
||||
final StringBuilder varyings = new StringBuilder();
|
||||
final StringBuilder assignments = new StringBuilder();
|
||||
if (FRAG_IN_COLOR.matcher(fragmentSource).find()) {
|
||||
sb.append("layout(location = 1) in vec4 a_Color;\n");
|
||||
varyings.append("out vec4 angelica_FrontColor;\n");
|
||||
assignments.append(" angelica_FrontColor = a_Color;\n");
|
||||
}
|
||||
|
||||
final Matcher texCoordMatcher = FRAG_IN_TEXCOORD.matcher(fragmentSource);
|
||||
final Set<Integer> texCoordIndices = new HashSet<>();
|
||||
while (texCoordMatcher.find()) {
|
||||
texCoordIndices.add(Integer.parseInt(texCoordMatcher.group(1)));
|
||||
}
|
||||
for (int i : texCoordIndices) {
|
||||
// PRIMARY_UV=2, SECONDARY_UV=3. Only indices 0 and 1 are supported; higher indices collide at location 3.
|
||||
final int location = i == 0 ? 2 : 3;
|
||||
sb.append("layout(location = ").append(location).append(") in vec4 a_TexCoord").append(i).append(";\n");
|
||||
varyings.append("out vec4 angelica_TexCoord").append(i).append(";\n");
|
||||
assignments.append(" angelica_TexCoord").append(i).append(" = a_TexCoord").append(i).append(";\n");
|
||||
}
|
||||
|
||||
if (FRAG_IN_FOGCOORD.matcher(fragmentSource).find()) {
|
||||
varyings.append("out float angelica_FogFragCoord;\n");
|
||||
assignments.append(" angelica_FogFragCoord = abs((angelica_ModelViewMatrix * a_Position).z);\n");
|
||||
}
|
||||
|
||||
sb.append(varyings);
|
||||
sb.append("\nvoid main() {\n");
|
||||
sb.append(" gl_Position = angelica_ProjectionMatrix * angelica_ModelViewMatrix * a_Position;\n");
|
||||
sb.append(assignments);
|
||||
sb.append("}\n");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Ensure #version is at least 330 core, strip 'compatibility' profile. */
|
||||
private static String fixupVersion(String source) {
|
||||
final Matcher m = VERSION_PATTERN.matcher(source);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.FogStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.LightModelState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.MaterialState;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
@@ -38,7 +39,9 @@ public class CompatUniformManager {
|
||||
static final int LOC_IRIS_LIGHTMAP_TEXTURE_MATRIX = 13;
|
||||
static final int LOC_ALPHA_TEST_REF = 14;
|
||||
static final int LOC_SCENE_COLOR = 15;
|
||||
static final int LOC_COUNT = 16;
|
||||
static final int LOC_CLIP_PLANES = 16;
|
||||
static final int LOC_CLIP_PLANES_ENABLED = 17;
|
||||
static final int LOC_COUNT = 18;
|
||||
|
||||
private static final String[] UNIFORM_NAMES = {
|
||||
"angelica_ModelViewMatrix",
|
||||
@@ -57,6 +60,8 @@ public class CompatUniformManager {
|
||||
"iris_LightmapTextureMatrix",
|
||||
"angelica_currentAlphaTest",
|
||||
"angelica_SceneColor",
|
||||
"angelica_ClipPlane[0]",
|
||||
"angelica_ClipPlanesEnabled",
|
||||
};
|
||||
|
||||
/** Per-program cached uniform locations. Maps program ID → int[LOC_COUNT]. */
|
||||
@@ -66,6 +71,7 @@ public class CompatUniformManager {
|
||||
private static final FloatBuffer mat4Buf = BufferUtils.createFloatBuffer(16);
|
||||
private static final FloatBuffer mat3Buf = BufferUtils.createFloatBuffer(9);
|
||||
private static final FloatBuffer vec4Buf = BufferUtils.createFloatBuffer(4);
|
||||
private static final FloatBuffer clipPlaneBuf = BufferUtils.createFloatBuffer(32); // 8 planes * vec4
|
||||
private static final Matrix3f normalMatrix = new Matrix3f();
|
||||
private static final Matrix4f scratchMatrix = new Matrix4f();
|
||||
|
||||
@@ -83,6 +89,7 @@ public class CompatUniformManager {
|
||||
private static int lastTexMatGen = -1;
|
||||
private static int lastFragmentGen = -1;
|
||||
private static int lastLightingGen = -1;
|
||||
private static int lastClipPlaneGen = -1;
|
||||
|
||||
private CompatUniformManager() {}
|
||||
|
||||
@@ -139,6 +146,15 @@ public class CompatUniformManager {
|
||||
uploadSceneColor(locs);
|
||||
}
|
||||
}
|
||||
|
||||
// Clip plane equations + enabled bool — uploaded when enable state or equations change
|
||||
if (locs[LOC_CLIP_PLANES] != -1 || locs[LOC_CLIP_PLANES_ENABLED] != -1) {
|
||||
final int cpGen = GLStateManager.clipPlaneGeneration;
|
||||
if (programChanged || cpGen != lastClipPlaneGen) {
|
||||
lastClipPlaneGen = cpGen;
|
||||
uploadClipPlanes(locs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void uploadMatrices(int[] locs, boolean mvChanged, boolean projChanged, boolean texMatChanged) {
|
||||
@@ -261,6 +277,21 @@ public class CompatUniformManager {
|
||||
GL20.glUniform4(locs[LOC_SCENE_COLOR], vec4Buf);
|
||||
}
|
||||
|
||||
private static void uploadClipPlanes(int[] locs) {
|
||||
if (locs[LOC_CLIP_PLANES_ENABLED] != -1) {
|
||||
GL20.glUniform1i(locs[LOC_CLIP_PLANES_ENABLED], GLStateManager.anyClipPlaneEnabled() ? 1 : 0);
|
||||
}
|
||||
if (locs[LOC_CLIP_PLANES] != -1) {
|
||||
final ClipPlaneState cps = GLStateManager.getClipPlaneState();
|
||||
clipPlaneBuf.clear();
|
||||
for (int i = 0; i < GLStateManager.MAX_CLIP_PLANES; i++) {
|
||||
cps.putEyePlane(i, clipPlaneBuf);
|
||||
}
|
||||
clipPlaneBuf.flip();
|
||||
GL20.glUniform4(locs[LOC_CLIP_PLANES], clipPlaneBuf);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onDeleteProgram(int program) {
|
||||
programLocations.remove(program);
|
||||
}
|
||||
|
||||
@@ -497,6 +497,12 @@ public class DisplayListManager {
|
||||
currentRecorder.recordMaterial(face, pname, params);
|
||||
}
|
||||
|
||||
public static void recordClipPlane(int plane, double a, double b, double c, double d) {
|
||||
if (currentRecorder == null) return;
|
||||
drawBarrier();
|
||||
currentRecorder.recordClipPlane(plane, a, b, c, d);
|
||||
}
|
||||
|
||||
public static void recordStencilFunc(int func, int ref, int mask) {
|
||||
if (currentRecorder == null) return;
|
||||
drawBarrier();
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.gtnewhorizons.angelica.glsm.stacks.PolygonStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.StencilStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.ViewPortStateStack;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClientArrayState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
@@ -52,6 +53,7 @@ import net.coderbot.iris.gbuffer_overrides.state.StateTracker;
|
||||
import net.coderbot.iris.gl.blending.AlphaTestStorage;
|
||||
import net.coderbot.iris.gl.blending.BlendModeStorage;
|
||||
import net.coderbot.iris.gl.blending.DepthColorStorage;
|
||||
import net.coderbot.iris.gl.program.ProgramUniforms;
|
||||
import net.coderbot.iris.samplers.IrisSamplers;
|
||||
import net.coderbot.iris.texture.pbr.PBRTextureManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -144,6 +146,7 @@ public class GLStateManager {
|
||||
public static int lightingGeneration;
|
||||
public static int fragmentGeneration; // fog + alpha ref
|
||||
public static int colorGeneration; // current vertex color
|
||||
public static int clipPlaneGeneration; // clip plane equation changes
|
||||
|
||||
// Deferred vertex attribute upload flags — set when state changes, flushed before draw
|
||||
private static boolean dirtyColorAttrib;
|
||||
@@ -366,6 +369,7 @@ public class GLStateManager {
|
||||
|
||||
// Clip plane states
|
||||
@Getter protected static final BooleanStateStack[] clipPlaneStates = new BooleanStateStack[MAX_CLIP_PLANES];
|
||||
@Getter protected static final ClipPlaneState clipPlaneState = new ClipPlaneState();
|
||||
|
||||
@Getter protected static final MatrixModeStack matrixMode = new MatrixModeStack();
|
||||
@Getter protected static final Matrix4fStack modelViewMatrix = new Matrix4fStack(MAX_MODELVIEW_STACK_DEPTH);
|
||||
@@ -581,6 +585,7 @@ public class GLStateManager {
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (cap >= GL11.GL_CLIP_PLANE0 && cap < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
clipPlaneStates[cap - GL11.GL_CLIP_PLANE0].enable();
|
||||
clipPlaneGeneration++;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -660,6 +665,7 @@ public class GLStateManager {
|
||||
// Handle clip planes dynamically (supports up to MAX_CLIP_PLANES)
|
||||
if (cap >= GL11.GL_CLIP_PLANE0 && cap < GL11.GL_CLIP_PLANE0 + MAX_CLIP_PLANES) {
|
||||
clipPlaneStates[cap - GL11.GL_CLIP_PLANE0].disable();
|
||||
clipPlaneGeneration++;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3833,6 +3839,8 @@ public class GLStateManager {
|
||||
if (caching) {
|
||||
activeProgram = 0; // Track that FFP was requested
|
||||
}
|
||||
// Deregister Iris ValueUpdateNotifier listeners so they don't fire
|
||||
ProgramUniforms.clearActiveUniforms();
|
||||
ffp.activate();
|
||||
return;
|
||||
}
|
||||
@@ -3847,6 +3855,8 @@ public class GLStateManager {
|
||||
if (caching) {
|
||||
activeProgram = program;
|
||||
}
|
||||
// Deregister Iris ValueUpdateNotifier listeners before switching programs.
|
||||
ProgramUniforms.clearActiveUniforms();
|
||||
if (AngelicaMod.lwjglDebug) {
|
||||
final String programName = GLDebug.getObjectLabel(KHRDebug.GL_PROGRAM, program);
|
||||
GLDebug.debugMessage("Activating Program - " + program + ":" + programName);
|
||||
@@ -4311,9 +4321,23 @@ public class GLStateManager {
|
||||
// Clip Plane Commands
|
||||
public static void glClipPlane(int plane, DoubleBuffer equation) {
|
||||
if (DisplayListManager.isRecording()) {
|
||||
throw new UnsupportedOperationException("glClipPlane in display lists not yet implemented - if you see this, please report!");
|
||||
final int pos = equation.position();
|
||||
DisplayListManager.recordClipPlane(plane, equation.get(pos), equation.get(pos + 1), equation.get(pos + 2), equation.get(pos + 3));
|
||||
return;
|
||||
}
|
||||
GL11.glClipPlane(plane, equation);
|
||||
final int index = plane - GL11.GL_CLIP_PLANE0;
|
||||
if (index < 0 || index >= MAX_CLIP_PLANES) return;
|
||||
final int pos = equation.position();
|
||||
clipPlaneState.setPlane(index, equation.get(pos), equation.get(pos + 1), equation.get(pos + 2), equation.get(pos + 3), modelViewMatrix);
|
||||
clipPlaneGeneration++;
|
||||
}
|
||||
|
||||
/** Returns true if any GL_CLIP_PLANE0..7 is currently enabled. */
|
||||
public static boolean anyClipPlaneEnabled() {
|
||||
for (int i = 0; i < MAX_CLIP_PLANES; i++) {
|
||||
if (clipPlaneStates[i].isEnabled()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear Commands
|
||||
@@ -4810,10 +4834,61 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void glLinkProgram(int program) {
|
||||
if (ShaderManager.getInstance().isEnabled()) {
|
||||
generateVertexShaderIfNeeded(program);
|
||||
}
|
||||
GL20.glLinkProgram(program);
|
||||
CompatUniformManager.onLinkProgram(program);
|
||||
}
|
||||
|
||||
private static final IntBuffer SHADER_BUF = BufferUtils.createIntBuffer(8);
|
||||
|
||||
/**
|
||||
* If a program has a fragment shader but no vertex shader, generate a passthrough
|
||||
* vertex shader from the fragment's in declarations and attach it.
|
||||
*/
|
||||
private static void generateVertexShaderIfNeeded(int program) {
|
||||
final int shaderCount = GL20.glGetProgrami(program, GL20.GL_ATTACHED_SHADERS);
|
||||
if (shaderCount == 0 || shaderCount > SHADER_BUF.capacity()) return;
|
||||
|
||||
SHADER_BUF.clear().limit(shaderCount);
|
||||
GL20.glGetAttachedShaders(program, null, SHADER_BUF);
|
||||
|
||||
int fragmentShader = 0;
|
||||
boolean hasVertex = false;
|
||||
for (int i = 0; i < shaderCount; i++) {
|
||||
final int shader = SHADER_BUF.get(i);
|
||||
final int type = GL20.glGetShaderi(shader, GL20.GL_SHADER_TYPE);
|
||||
if (type == GL20.GL_VERTEX_SHADER) {
|
||||
hasVertex = true;
|
||||
break;
|
||||
} else if (type == GL20.GL_FRAGMENT_SHADER) {
|
||||
fragmentShader = shader;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasVertex || fragmentShader == 0) return;
|
||||
|
||||
// Fragment-only program — generate a passthrough vertex shader
|
||||
final String fragSource = GL20.glGetShaderSource(fragmentShader, 65536);
|
||||
final String vertSource = CompatShaderTransformer.generatePassthroughVertexShader(fragSource);
|
||||
|
||||
final int vertShader = GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
|
||||
GL20.glShaderSource(vertShader, vertSource);
|
||||
GL20.glCompileShader(vertShader);
|
||||
|
||||
if (GL20.glGetShaderi(vertShader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
|
||||
final String log = GL20.glGetShaderInfoLog(vertShader, 8192);
|
||||
AngelicaTweaker.LOGGER.warn("CompatShaderTransformer: Generated passthrough vertex shader failed to compile:\n{}\nSource:\n{}", log, vertSource);
|
||||
GL20.glDeleteShader(vertShader);
|
||||
return;
|
||||
}
|
||||
|
||||
AngelicaTweaker.LOGGER.debug("CompatShaderTransformer: Generated passthrough vertex shader for fragment-only program {}", program);
|
||||
GL20.glAttachShader(program, vertShader);
|
||||
GL20.glDeleteShader(vertShader);
|
||||
}
|
||||
|
||||
public static void glDeleteProgram(int program) {
|
||||
CompatUniformManager.onDeleteProgram(program);
|
||||
GL20.glDeleteProgram(program);
|
||||
|
||||
@@ -37,10 +37,10 @@ public final class FragmentShaderGenerator {
|
||||
sb.append("in vec3 v_SpecularColor;\n");
|
||||
}
|
||||
if (key.textureEnabled()) {
|
||||
sb.append("in vec2 v_TexCoord0;\n");
|
||||
sb.append("in vec4 v_TexCoord0;\n");
|
||||
}
|
||||
if (key.lightmapEnabled()) {
|
||||
sb.append("in vec2 v_TexCoord1;\n");
|
||||
sb.append("in vec4 v_TexCoord1;\n");
|
||||
}
|
||||
if (key.fogMode() != FragmentKey.FOG_NONE) {
|
||||
sb.append("in float v_FogCoord;\n");
|
||||
@@ -70,10 +70,10 @@ public final class FragmentShaderGenerator {
|
||||
|
||||
private static void emitTextureSampling(StringBuilder sb, FragmentKey key) {
|
||||
if (key.textureEnabled()) {
|
||||
sb.append(" vec4 texColor = texture(u_Sampler0, v_TexCoord0);\n");
|
||||
sb.append(" vec4 texColor = texture(u_Sampler0, v_TexCoord0.st);\n");
|
||||
}
|
||||
if (key.lightmapEnabled()) {
|
||||
sb.append(" vec4 lightmapColor = texture(u_Sampler1, v_TexCoord1);\n");
|
||||
sb.append(" vec4 lightmapColor = texture(u_Sampler1, v_TexCoord1.st);\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ public class Program {
|
||||
public int locTexGenEyePlaneR = -1;
|
||||
public int locTexGenEyePlaneQ = -1;
|
||||
|
||||
// Clip planes
|
||||
public int locClipPlanes = -1;
|
||||
|
||||
// Fragment uniforms
|
||||
public int locSampler0 = -1;
|
||||
public int locSampler1 = -1;
|
||||
@@ -143,6 +146,9 @@ public class Program {
|
||||
locTexGenEyePlaneR = loc("u_TexGenEyePlaneR");
|
||||
locTexGenEyePlaneQ = loc("u_TexGenEyePlaneQ");
|
||||
|
||||
// Clip planes
|
||||
locClipPlanes = loc("u_ClipPlane[0]");
|
||||
|
||||
// Fragment
|
||||
locSampler0 = loc("u_Sampler0");
|
||||
locSampler1 = loc("u_Sampler1");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.FogState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.LightState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.MaterialState;
|
||||
@@ -30,6 +31,7 @@ public class Uniforms {
|
||||
private final FloatBuffer mat3Buf = memAllocFloat(9);
|
||||
private final FloatBuffer vec4Buf = memAllocFloat(4);
|
||||
private final FloatBuffer vec3Buf = memAllocFloat(3);
|
||||
private final FloatBuffer clipPlaneBuf = memAllocFloat(32); // 8 planes * vec4
|
||||
|
||||
// Derived matrices (computed on CPU)
|
||||
private final Matrix4f mvpMatrix = new Matrix4f();
|
||||
@@ -57,6 +59,7 @@ public class Uniforms {
|
||||
private float lastLightmapX = Float.NaN;
|
||||
private float lastLightmapY = Float.NaN;
|
||||
private int lastTexGenGen = -1;
|
||||
private int lastClipPlaneGen = -1;
|
||||
|
||||
/**
|
||||
* Upload all relevant uniforms to the given FFP program based on current GLSM state.
|
||||
@@ -128,6 +131,14 @@ public class Uniforms {
|
||||
}
|
||||
}
|
||||
|
||||
if (program.getVertexKey().clipPlanesEnabled()) {
|
||||
final int cpGen = GLStateManager.clipPlaneGeneration;
|
||||
if (programChanged || cpGen != lastClipPlaneGen) {
|
||||
uploadClipPlanes(program);
|
||||
lastClipPlaneGen = cpGen;
|
||||
}
|
||||
}
|
||||
|
||||
final int fragGen = GLStateManager.fragmentGeneration;
|
||||
if (programChanged || fragGen != lastFragmentGen) {
|
||||
uploadFragmentUniforms(program);
|
||||
@@ -368,6 +379,17 @@ public class Uniforms {
|
||||
GL20.glUniform4(loc, vec4Buf);
|
||||
}
|
||||
|
||||
private void uploadClipPlanes(Program program) {
|
||||
if (program.locClipPlanes == -1) return;
|
||||
final ClipPlaneState cps = GLStateManager.getClipPlaneState();
|
||||
clipPlaneBuf.clear();
|
||||
for (int i = 0; i < GLStateManager.MAX_CLIP_PLANES; i++) {
|
||||
cps.putEyePlane(i, clipPlaneBuf);
|
||||
}
|
||||
clipPlaneBuf.flip();
|
||||
GL20.glUniform4(program.locClipPlanes, clipPlaneBuf);
|
||||
}
|
||||
|
||||
private void uploadFragmentUniforms(Program program) {
|
||||
final FragmentKey fk = program.getFragmentKey();
|
||||
|
||||
@@ -442,5 +464,6 @@ public class Uniforms {
|
||||
memFree(mat3Buf);
|
||||
memFree(vec4Buf);
|
||||
memFree(vec3Buf);
|
||||
memFree(clipPlaneBuf);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,8 @@ public final class VertexKey {
|
||||
private static final int BIT_TEXGEN_T = 25;
|
||||
private static final int BIT_TEXGEN_R = 28;
|
||||
private static final int BIT_TEXGEN_Q = 31;
|
||||
// bits 31-33: texGenModeQ (3 bits)
|
||||
private static final int BIT_CLIP_PLANES = 34;
|
||||
|
||||
public static final int TG_NONE = 0;
|
||||
public static final int TG_OBJ_LINEAR = 1;
|
||||
@@ -88,6 +90,8 @@ public final class VertexKey {
|
||||
public int texGenModeQ() { return (int)((packed >> BIT_TEXGEN_Q) & 0x7); }
|
||||
/** Whether any texgen coordinate is enabled. */
|
||||
public boolean texGenEnabled() { return texGenModeS() != TG_NONE || texGenModeT() != TG_NONE || texGenModeR() != TG_NONE || texGenModeQ() != TG_NONE; }
|
||||
/** Whether any clip plane is enabled. */
|
||||
public boolean clipPlanesEnabled() { return bit(BIT_CLIP_PLANES); }
|
||||
|
||||
/** Whether vertex color replaces material ambient in this variant. */
|
||||
public boolean cmReplacesAmbient() { final int m = colorMaterialMode(); return m == CM_AMBIENT || m == CM_AMBIENT_AND_DIFFUSE; }
|
||||
@@ -214,6 +218,11 @@ public final class VertexKey {
|
||||
if (hasTexCoord) bits |= (1L << BIT_HAS_VERTEX_TEX);
|
||||
if (hasLightmap) bits |= (1L << BIT_HAS_VERTEX_LIGHTMAP);
|
||||
|
||||
// Clip planes
|
||||
if (GLStateManager.anyClipPlaneEnabled()) {
|
||||
bits |= (1L << BIT_CLIP_PLANES);
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -239,10 +248,10 @@ public final class VertexKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("FFPVertexKey[0x%09X: lit=%b l0=%b l1=%b cm=%b fog=%b tex=%b lm=%b col=%b nrm=%b vtex=%b vlm=%b tg=%d/%d/%d/%d]",
|
||||
return String.format("FFPVertexKey[0x%09X: lit=%b l0=%b l1=%b cm=%b fog=%b tex=%b lm=%b col=%b nrm=%b vtex=%b vlm=%b tg=%d/%d/%d/%d clip=%b]",
|
||||
packed, lightingEnabled(), light0Enabled(), light1Enabled(),
|
||||
colorMaterialEnabled(), fogEnabled(), textureEnabled(), lightmapEnabled(),
|
||||
hasVertexColor(), hasVertexNormal(), hasVertexTexCoord(), hasVertexLightmap(),
|
||||
texGenModeS(), texGenModeT(), texGenModeR(), texGenModeQ());
|
||||
texGenModeS(), texGenModeT(), texGenModeR(), texGenModeQ(), clipPlanesEnabled());
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,9 @@ public final class VertexShaderGenerator {
|
||||
if (key.fogEnabled()) {
|
||||
emitFogDistance(sb, key);
|
||||
}
|
||||
if (key.clipPlanesEnabled()) {
|
||||
emitClipDistances(sb);
|
||||
}
|
||||
sb.append("}\n");
|
||||
|
||||
return sb.toString();
|
||||
@@ -110,6 +113,10 @@ public final class VertexShaderGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
if (key.clipPlanesEnabled()) {
|
||||
sb.append("uniform vec4 u_ClipPlane[8];\n");
|
||||
}
|
||||
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
@@ -164,10 +171,10 @@ public final class VertexShaderGenerator {
|
||||
sb.append("out vec3 v_SpecularColor;\n");
|
||||
}
|
||||
if (key.textureEnabled() || key.hasVertexTexCoord() || key.texGenEnabled()) {
|
||||
sb.append("out vec2 v_TexCoord0;\n");
|
||||
sb.append("out vec4 v_TexCoord0;\n");
|
||||
}
|
||||
if (key.lightmapEnabled()) {
|
||||
sb.append("out vec2 v_TexCoord1;\n");
|
||||
sb.append("out vec4 v_TexCoord1;\n");
|
||||
}
|
||||
if (key.fogEnabled()) {
|
||||
sb.append("out float v_FogCoord;\n");
|
||||
@@ -180,8 +187,8 @@ public final class VertexShaderGenerator {
|
||||
sb.append(" vec4 pos4 = vec4(a_Position, 1.0);\n");
|
||||
sb.append(" gl_Position = u_MVPMatrix * pos4;\n");
|
||||
|
||||
// Eye position needed for lighting, fog, and EYE_LINEAR texgen
|
||||
if (key.lightingEnabled() || key.fogEnabled() || texGenNeedsEyePos(key)) {
|
||||
// Eye position needed for lighting, fog, EYE_LINEAR texgen, and clip planes
|
||||
if (key.lightingEnabled() || key.fogEnabled() || texGenNeedsEyePos(key) || key.clipPlanesEnabled()) {
|
||||
sb.append(" vec4 eyePos = u_ModelViewMatrix * pos4;\n");
|
||||
}
|
||||
sb.append('\n');
|
||||
@@ -320,23 +327,23 @@ public final class VertexShaderGenerator {
|
||||
sb.append(" // Texture coordinates\n");
|
||||
if (key.hasVertexTexCoord()) {
|
||||
if (key.textureMatrixEnabled()) {
|
||||
sb.append(" v_TexCoord0 = (u_TextureMatrix0 * vec4(a_TexCoord0, 0.0, 1.0)).st;\n");
|
||||
sb.append(" v_TexCoord0 = u_TextureMatrix0 * vec4(a_TexCoord0, 0.0, 1.0);\n");
|
||||
} else {
|
||||
sb.append(" v_TexCoord0 = a_TexCoord0;\n");
|
||||
sb.append(" v_TexCoord0 = vec4(a_TexCoord0, 0.0, 1.0);\n");
|
||||
}
|
||||
} else {
|
||||
if (key.textureMatrixEnabled()) {
|
||||
sb.append(" v_TexCoord0 = (u_TextureMatrix0 * u_CurrentTexCoord).st;\n");
|
||||
sb.append(" v_TexCoord0 = u_TextureMatrix0 * u_CurrentTexCoord;\n");
|
||||
} else {
|
||||
sb.append(" v_TexCoord0 = u_CurrentTexCoord.st;\n");
|
||||
sb.append(" v_TexCoord0 = u_CurrentTexCoord;\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key.lightmapEnabled()) {
|
||||
if (key.hasVertexLightmap()) {
|
||||
sb.append(" v_TexCoord1 = (u_LightmapTextureMatrix * vec4(a_TexCoord1, 0.0, 1.0)).st;\n");
|
||||
sb.append(" v_TexCoord1 = u_LightmapTextureMatrix * vec4(a_TexCoord1, 0.0, 1.0);\n");
|
||||
} else {
|
||||
sb.append(" v_TexCoord1 = (u_LightmapTextureMatrix * vec4(u_CurrentLightmapCoord, 0.0, 1.0)).st;\n");
|
||||
sb.append(" v_TexCoord1 = u_LightmapTextureMatrix * vec4(u_CurrentLightmapCoord, 0.0, 1.0);\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,7 +363,7 @@ public final class VertexShaderGenerator {
|
||||
emitTexGenComponent(sb, key.texGenModeQ(), "q", "Q", key);
|
||||
|
||||
// Always apply texture matrix when texgen is active (forced on in VertexKey)
|
||||
sb.append(" v_TexCoord0 = (u_TextureMatrix0 * texGenCoord).st;\n");
|
||||
sb.append(" v_TexCoord0 = u_TextureMatrix0 * texGenCoord;\n");
|
||||
}
|
||||
|
||||
private static void emitTexGenComponent(StringBuilder sb, int mode, String swizzle, String coordName, VertexKey key) {
|
||||
@@ -391,4 +398,11 @@ public final class VertexShaderGenerator {
|
||||
sb.append(" v_FogCoord = abs(eyePos.z);\n");
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitClipDistances(StringBuilder sb) {
|
||||
sb.append(" // Clip distances\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
sb.append(" gl_ClipDistance[").append(i).append("] = dot(u_ClipPlane[").append(i).append("], eyePos);\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,6 +554,16 @@ public final class CommandBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeClipPlane(int plane, double a, double b, double c, double d) {
|
||||
ensureCapacity(40);
|
||||
writeInt(GLCommand.CLIP_PLANE);
|
||||
writeInt(plane);
|
||||
writeDouble(a);
|
||||
writeDouble(b);
|
||||
writeDouble(c);
|
||||
writeDouble(d);
|
||||
}
|
||||
|
||||
// === Draw commands ===
|
||||
|
||||
public void writeDrawRange(int vboIndex) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
@@ -25,6 +26,8 @@ public final class CommandBufferExecutor {
|
||||
private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer(16);
|
||||
// Static reusable buffer for fog/light/material params
|
||||
private static final FloatBuffer PARAMS_BUFFER = BufferUtils.createFloatBuffer(4);
|
||||
// Static reusable buffer for clip plane equation
|
||||
private static final DoubleBuffer PARAMS_DOUBLE_BUFFER = BufferUtils.createDoubleBuffer(4);
|
||||
// Static reusable buffer for draw buffers
|
||||
private static final int MAX_DRAW_BUFFERS = 8;
|
||||
private static final IntBuffer DRAW_BUFFERS_BUFFER = BufferUtils.createIntBuffer(MAX_DRAW_BUFFERS);
|
||||
@@ -457,6 +460,19 @@ public final class CommandBufferExecutor {
|
||||
GLStateManager.glMaterial(face, pname, PARAMS_BUFFER);
|
||||
}
|
||||
|
||||
case GLCommand.CLIP_PLANE -> {
|
||||
final int plane = memGetInt(ptr);
|
||||
final double a = memGetDouble(ptr + 4);
|
||||
final double b = memGetDouble(ptr + 12);
|
||||
final double c = memGetDouble(ptr + 20);
|
||||
final double d = memGetDouble(ptr + 28);
|
||||
ptr += 36;
|
||||
PARAMS_DOUBLE_BUFFER.clear();
|
||||
PARAMS_DOUBLE_BUFFER.put(a).put(b).put(c).put(d);
|
||||
PARAMS_DOUBLE_BUFFER.flip();
|
||||
GLStateManager.glClipPlane(plane, PARAMS_DOUBLE_BUFFER);
|
||||
}
|
||||
|
||||
// === Draw commands ===
|
||||
case GLCommand.DRAW_RANGE -> {
|
||||
final int vboIndex = memGetInt(ptr);
|
||||
|
||||
@@ -143,6 +143,16 @@ public final class CommandBufferProcessor {
|
||||
out.writeMaterial(face, pname, fb);
|
||||
}
|
||||
|
||||
// Clip plane command (4 doubles)
|
||||
case GLCommand.CLIP_PLANE -> {
|
||||
final int plane = raw.readInt();
|
||||
final double a = raw.readDouble();
|
||||
final double b = raw.readDouble();
|
||||
final double c = raw.readDouble();
|
||||
final double d = raw.readDouble();
|
||||
out.writeClipPlane(plane, a, b, c, d);
|
||||
}
|
||||
|
||||
// Draw/call commands
|
||||
case GLCommand.DRAW_RANGE -> out.writeDrawRange(raw.readInt());
|
||||
case GLCommand.CALL_LIST -> out.writeCallList(raw.readInt());
|
||||
|
||||
@@ -292,6 +292,11 @@ public final class CommandRecorder {
|
||||
commandCount++;
|
||||
}
|
||||
|
||||
public void recordClipPlane(int plane, double a, double b, double c, double d) {
|
||||
buffer.writeClipPlane(plane, a, b, c, d);
|
||||
commandCount++;
|
||||
}
|
||||
|
||||
public void recordStencilFunc(int func, int ref, int mask) {
|
||||
buffer.writeStencilFunc(func, ref, mask);
|
||||
commandCount++;
|
||||
|
||||
@@ -89,6 +89,7 @@ public final class GLCommand {
|
||||
public static final int LIGHT = 91; // [cmd:4][light:4][pname:4][count:4][params:16f] = 32 bytes
|
||||
public static final int LIGHT_MODEL = 92; // [cmd:4][pname:4][count:4][params:16f] = 28 bytes
|
||||
public static final int MATERIAL = 93; // [cmd:4][face:4][pname:4][count:4][params:16f] = 32 bytes
|
||||
public static final int CLIP_PLANE = 94; // [cmd:4][plane:4][a:8d][b:8d][c:8d][d:8d] = 40 bytes
|
||||
|
||||
// === Draw commands ===
|
||||
public static final int DRAW_RANGE = 100; // [cmd:4][vboIndex:4] = 8 bytes
|
||||
@@ -179,6 +180,7 @@ public final class GLCommand {
|
||||
case LIGHT -> "LIGHT";
|
||||
case LIGHT_MODEL -> "LIGHT_MODEL";
|
||||
case MATERIAL -> "MATERIAL";
|
||||
case CLIP_PLANE -> "CLIP_PLANE";
|
||||
case DRAW_RANGE -> "DRAW_RANGE";
|
||||
case CALL_LIST -> "CALL_LIST";
|
||||
case DRAW_BUFFER -> "DRAW_BUFFER";
|
||||
@@ -254,6 +256,7 @@ public final class GLCommand {
|
||||
final int count = memGetInt(ptr + 12); // light/face at +4, pname at +8, count at +12
|
||||
yield 16 + count * 4;
|
||||
}
|
||||
case GLCommand.CLIP_PLANE -> 40; // cmd + plane + 4 doubles
|
||||
|
||||
default -> throw new IllegalStateException("Unknown command: " + cmd);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.gtnewhorizons.angelica.glsm.states;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Stores eye-space clip plane equations for core profile emulation.
|
||||
*/
|
||||
public class ClipPlaneState {
|
||||
private final float[][] eyePlanes = new float[GLStateManager.MAX_CLIP_PLANES][4];
|
||||
|
||||
private static final Vector4f tempPlane = new Vector4f();
|
||||
private static final Matrix4f tempInverse = new Matrix4f();
|
||||
|
||||
public void setPlane(int index, double a, double b, double c, double d, Matrix4f modelView) {
|
||||
final float[] dest = eyePlanes[index];
|
||||
modelView.invert(tempInverse);
|
||||
tempPlane.set((float) a, (float) b, (float) c, (float) d);
|
||||
tempInverse.transformTranspose(tempPlane);
|
||||
dest[0] = tempPlane.x;
|
||||
dest[1] = tempPlane.y;
|
||||
dest[2] = tempPlane.z;
|
||||
dest[3] = tempPlane.w;
|
||||
}
|
||||
|
||||
/** Writes the 4-component eye-space plane equation into {@code buf} at its current position. */
|
||||
public void putEyePlane(int index, FloatBuffer buf) {
|
||||
final float[] p = eyePlanes[index];
|
||||
buf.put(p[0]).put(p[1]).put(p[2]).put(p[3]);
|
||||
}
|
||||
}
|
||||
@@ -74,5 +74,21 @@ public class CommonTransformer {
|
||||
root.renameFunctionCall(GlslTransformUtils.TEXTURE_RENAMES);
|
||||
root.renameAndWrapShadow("shadow2D", "texture");
|
||||
root.renameAndWrapShadow("shadow2DLod", "textureLod");
|
||||
|
||||
if (parameters.patch == Patch.ATTRIBUTES && parameters.type == ShaderType.VERTEX) {
|
||||
root.injectVariable("uniform bool angelica_ClipPlanesEnabled;");
|
||||
root.injectVariable("uniform vec4 angelica_ClipPlane[8];");
|
||||
root.appendMain(
|
||||
"{ if (angelica_ClipPlanesEnabled) { vec4 _cp_ep = iris_ModelViewMatrix * iris_Vertex; "
|
||||
+ "gl_ClipDistance[0] = dot(angelica_ClipPlane[0], _cp_ep); "
|
||||
+ "gl_ClipDistance[1] = dot(angelica_ClipPlane[1], _cp_ep); "
|
||||
+ "gl_ClipDistance[2] = dot(angelica_ClipPlane[2], _cp_ep); "
|
||||
+ "gl_ClipDistance[3] = dot(angelica_ClipPlane[3], _cp_ep); "
|
||||
+ "gl_ClipDistance[4] = dot(angelica_ClipPlane[4], _cp_ep); "
|
||||
+ "gl_ClipDistance[5] = dot(angelica_ClipPlane[5], _cp_ep); "
|
||||
+ "gl_ClipDistance[6] = dot(angelica_ClipPlane[6], _cp_ep); "
|
||||
+ "gl_ClipDistance[7] = dot(angelica_ClipPlane[7], _cp_ep); } }"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class ExternallyManagedUniforms {
|
||||
addMat4(uniformHolder, "iris_ModelViewMatrix");
|
||||
addMat4(uniformHolder, "iris_ProjectionMatrix");
|
||||
addMat4(uniformHolder, "u_ModelViewProjectionMatrix");
|
||||
addMat4(uniformHolder, "iris_NormalMatrix");
|
||||
addMat3(uniformHolder, "iris_NormalMatrix");
|
||||
uniformHolder.externallyManagedUniform("heavyFog", UniformType.BOOL);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ public class ExternallyManagedUniforms {
|
||||
uniformHolder.externallyManagedUniform("u_TextureScale", UniformType.VEC2);
|
||||
}
|
||||
|
||||
private static void addMat3(UniformHolder uniformHolder, String name) {
|
||||
uniformHolder.externallyManagedUniform(name, UniformType.MAT3);
|
||||
}
|
||||
|
||||
private static void addMat4(UniformHolder uniformHolder, String name) {
|
||||
uniformHolder.externallyManagedUniform(name, UniformType.MAT4);
|
||||
}
|
||||
|
||||
+12
-7
@@ -51,7 +51,7 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
throw new RuntimeException("Failed to obtain ContextAttribs version setters", e);
|
||||
}
|
||||
|
||||
LWJGLException cur_exception = null;
|
||||
Exception cur_exception = null;
|
||||
for (int major = 4; major >= 3; --major) {
|
||||
final int maxMinor = (major == 4) ? 6 : 3;
|
||||
final int minMinor = (major == 3) ? 3 : 0;
|
||||
@@ -59,21 +59,26 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
try {
|
||||
setMajor.invokeExact(attribs, major);
|
||||
setMinor.invokeExact(attribs, minor);
|
||||
Display.create(format, attribs);
|
||||
return;
|
||||
} catch (LWJGLException e) {
|
||||
cur_exception = e;
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Failed to set ContextAttribs version", t);
|
||||
}
|
||||
try {
|
||||
Display.create(format, attribs);
|
||||
return;
|
||||
} catch (LWJGLException | RuntimeException e) {
|
||||
cur_exception = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
angelica$reportContextFailure(cur_exception);
|
||||
throw cur_exception;
|
||||
if (cur_exception instanceof LWJGLException lwjgl) {
|
||||
throw lwjgl;
|
||||
}
|
||||
throw new LWJGLException("Failed to create OpenGL core profile context", cur_exception);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static void angelica$reportContextFailure(LWJGLException e) {
|
||||
private static void angelica$reportContextFailure(Exception e) {
|
||||
System.err.println("[Angelica] FATAL: Failed to create OpenGL core profile context.");
|
||||
System.err.println("[Angelica] Error: " + e.getMessage());
|
||||
try {
|
||||
|
||||
@@ -244,7 +244,7 @@ class CompatShaderTransformerTest {
|
||||
""";
|
||||
|
||||
String result = CompatShaderTransformer.transform(src, false);
|
||||
assertTrue(result.contains("vec4 angelica_FrontColor"), "gl_FrontColor should become a local vec4");
|
||||
assertTrue(result.contains("vec4 angelica_FrontColor"), "gl_FrontColor should become angelica_FrontColor out varying");
|
||||
assertFalse(result.contains("gl_FrontColor"), "gl_FrontColor should not remain");
|
||||
}
|
||||
|
||||
@@ -494,7 +494,7 @@ class CompatShaderTransformerTest {
|
||||
|
||||
// Fragment shader: gl_Color → angelica_FrontColor (in varying)
|
||||
assertTrue(fragResult.contains("angelica_FrontColor"), "fragment gl_Color → angelica_FrontColor");
|
||||
assertFalse(fragResult.contains("angelica_Color"), "fragment should NOT have angelica_Color");
|
||||
assertFalse(fragResult.contains("gl_Color"), "fragment should NOT have gl_Color");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in new issue
Block a user