mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1991dc58ec | ||
|
|
ae19236e1a | ||
|
|
7ad368c937 | ||
|
|
5c86c87bcf | ||
|
|
99ba7fa775 | ||
|
|
5ae4ab8c5c | ||
|
|
ddd68e023f | ||
|
|
f78cfdd5fb | ||
|
|
183bcfbf41 | ||
|
|
502f30c0f9 | ||
|
|
ceff04adba | ||
|
|
b4dfdb8cc5 | ||
|
|
3064818477 | ||
|
|
27524e6a89 | ||
|
|
5d5e910fc0 | ||
|
|
f325fd7fc3 | ||
|
|
ec278d3d7a | ||
|
|
eef3d2f50a | ||
|
|
3da597ab18 | ||
|
|
0e79380618 | ||
|
|
b639d5c646 | ||
|
|
0d209d426d | ||
|
|
bf24084033 | ||
|
|
9267ecc735 | ||
|
|
dcc8d8deed | ||
|
|
5dc4f1fab8 | ||
|
|
d3cea1bfe4 | ||
|
|
5db2b248d7 | ||
|
|
21ab526284 | ||
|
|
4c8ea679ef | ||
|
|
2317379df2 | ||
|
|
24dae49c7f | ||
|
|
865de3cbab |
No files matched your search
@@ -50,6 +50,7 @@ Targets GL 3.3+ core profile
|
||||
* CodeChicken[Core](https://github.com/GTNewHorizons/CodeChickenCore/releases)/[Lib](https://github.com/GTNewHorizons/CodeChickenLib/releases) <1.2.0 - Threading issues, use 1.3.0+
|
||||
* Neodymium - Untested, but unlikely to be compatible. (Chunk Meshing is definitely incompatible, other features might work depending on config)
|
||||
* SmoothFont - Equivalent functionality added
|
||||
* ClientFixer - Use a resource pack like [GTNH-FTI-Standard-Font](https://github.com/Eldrinn-Elantey/GTNH-FTI-Standard-Font)
|
||||
|
||||
# Credits
|
||||
* ShadersMod
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import xyz.wagyourtail.jvmdg.gradle.flags.DowngradeFlags
|
||||
import xyz.wagyourtail.jvmdg.gradle.task.DowngradeJar
|
||||
import xyz.wagyourtail.jvmdg.gradle.task.files.DowngradeFiles
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhconvention")
|
||||
}
|
||||
|
||||
tasks.withType<DowngradeJar>().configureEach { logLevel.set("FATAL") }
|
||||
tasks.withType<DowngradeFiles>().configureEach { logLevel.set("FATAL") }
|
||||
|
||||
minecraft {
|
||||
extraRunJvmArguments.add("-Dangelica.enableTestBlocks=true")
|
||||
extraRunJvmArguments.add("-Dangelica.dumpClass=true")
|
||||
|
||||
+3
-3
@@ -66,9 +66,9 @@ configurations.all {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.7.14:dev")
|
||||
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.7.158:dev")
|
||||
|
||||
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.0.7") { transitive = false }
|
||||
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.1.0") { transitive = false }
|
||||
// runtimeOnlyNonPublishable("com.github.GTNewHorizons:lwjgl3ify:3.0.99")
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.42") { transitive = false }
|
||||
@@ -76,7 +76,7 @@ dependencies {
|
||||
|
||||
// Iris Shaders
|
||||
compileOnly('org.jetbrains:annotations:26.0.2')
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.10.0:dev")
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.11.4:dev")
|
||||
|
||||
shadowImplementation(project(":glsm")) { transitive = false }
|
||||
shadowImplementation(project(":lwjgl3-backend")) { transitive = false }
|
||||
|
||||
@@ -124,6 +124,7 @@ tasks.withType<DowngradeFiles>().configureEach {
|
||||
downgradeTo.set(JavaVersion.VERSION_1_8)
|
||||
multiReleaseOriginal.set(false)
|
||||
multiReleaseVersions.set(emptySet())
|
||||
logLevel.set("FATAL")
|
||||
}
|
||||
|
||||
val downgradeDepsForTest by tasks.registering(DowngradeFiles::class) {
|
||||
@@ -139,6 +140,7 @@ val downgradeMainClasses by tasks.registering(DowngradeFiles::class) {
|
||||
val downgradeTestClasses by tasks.registering(DowngradeFiles::class) {
|
||||
inputCollection = sourceSets["test"].output.classesDirs
|
||||
classpath = sourceSets["test"].compileClasspath
|
||||
sourceSets["test"].output.classesDirs.files.forEach { outputs.dir(temporaryDir.resolve(it.name)) }
|
||||
dependsOn(tasks.named("testClasses"))
|
||||
}
|
||||
|
||||
@@ -174,6 +176,19 @@ tasks.test {
|
||||
jvmArgs("-Djava.library.path=${extractNatives.get().property("destinationFolder").let { (it as DirectoryProperty).asFile.get().path }}")
|
||||
}
|
||||
|
||||
val verifyTestsRan by tasks.registering {
|
||||
val resultsDir = layout.buildDirectory.dir("test-results/test")
|
||||
dependsOn(tasks.test)
|
||||
doLast {
|
||||
val dir = resultsDir.get().asFile
|
||||
val xmls = dir.listFiles { f -> f.name.startsWith("TEST-") && f.name.endsWith(".xml") } ?: emptyArray()
|
||||
check(xmls.isNotEmpty()) {
|
||||
":glsm:test produced no TEST-*.xml in $dir - test task likely went NO-SOURCE"
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.check { dependsOn(verifyTestsRan) }
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.backend.RenderBackend;
|
||||
import org.taumc.glsl.ShaderParser;
|
||||
import org.taumc.glsl.Transformer;
|
||||
|
||||
@@ -114,13 +113,17 @@ public class CompatShaderTransformer {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean needsTransformation(String source) {
|
||||
// Shaders already at 330+ core don't need compat transformation
|
||||
public static boolean isCoreShader(String source) {
|
||||
final Matcher vm = VERSION_PATTERN.matcher(source);
|
||||
if (vm.find()) {
|
||||
final int version = Integer.parseInt(vm.group(1));
|
||||
if (version >= 330 && "core".equals(vm.group(2))) return false;
|
||||
return version >= 330 && "core".equals(vm.group(2));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean needsTransformation(String source) {
|
||||
if (isCoreShader(source)) return false;
|
||||
|
||||
return NEEDS_TRANSFORM_PATTERN.matcher(source).find();
|
||||
}
|
||||
|
||||
@@ -7,15 +7,16 @@ import com.gtnewhorizons.angelica.glsm.states.LightModelState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.LightState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.MaterialState;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/**
|
||||
* Per-program compat uniform location cache and upload manager.
|
||||
*
|
||||
@@ -102,8 +103,15 @@ public class CompatUniformManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Per-program cached uniform locations. Maps program ID → int[LOC_COUNT]. */
|
||||
private static final Int2ObjectOpenHashMap<int[]> programLocations = new Int2ObjectOpenHashMap<>();
|
||||
/** Per-program cached uniform locations + last-uploaded generations. Maps program ID -> state. */
|
||||
private static final Int2ObjectOpenHashMap<ProgramUniforms> programUniforms = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
private static final class ProgramUniforms {
|
||||
final int[] locs;
|
||||
int lastMvGen = -1, lastMvLinearGen = -1, lastProjGen = -1, lastTexMatGen = -1;
|
||||
int lastFragmentGen = -1, lastLightingGen = -1, lastClipPlaneGen = -1;
|
||||
ProgramUniforms(int[] locs) { this.locs = locs; }
|
||||
}
|
||||
|
||||
// Reusable NIO buffers for upload
|
||||
private static final FloatBuffer mat4Buf = BufferUtils.createFloatBuffer(16);
|
||||
@@ -112,6 +120,7 @@ public class CompatUniformManager {
|
||||
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();
|
||||
private static final Vector3f scratchCol = new Vector3f();
|
||||
|
||||
private static final float LIGHTMAP_SCALE = 1.0f / 256.0f;
|
||||
private static final FloatBuffer lightmapMatrixBuf;
|
||||
@@ -121,17 +130,18 @@ public class CompatUniformManager {
|
||||
new Matrix4f().scale(LIGHTMAP_SCALE).translate(8.0f, 8.0f, 8.0f).get(lightmapMatrixBuf);
|
||||
}
|
||||
|
||||
// Dirty tracking: skip uploads when state hasn't changed and program is the same
|
||||
private static int lastProgram = -1;
|
||||
private static int lastMvGen = -1;
|
||||
private static int lastProjGen = -1;
|
||||
private static int lastTexMatGen = -1;
|
||||
private static int lastFragmentGen = -1;
|
||||
private static int lastLightingGen = -1;
|
||||
private static int lastClipPlaneGen = -1;
|
||||
|
||||
private CompatUniformManager() {}
|
||||
|
||||
/**
|
||||
* Normalize each column of a 3x3 matrix in place. Used to strip the residual 1/scale that
|
||||
* inverse-transpose introduces.
|
||||
*/
|
||||
private static void normalizeColumnsInPlace(Matrix3f m) {
|
||||
m.setColumn(0, m.getColumn(0, scratchCol).normalize());
|
||||
m.setColumn(1, m.getColumn(1, scratchCol).normalize());
|
||||
m.setColumn(2, m.getColumn(2, scratchCol).normalize());
|
||||
}
|
||||
|
||||
public static void onLinkProgram(int program) {
|
||||
int[] locs = new int[LOC_COUNT];
|
||||
boolean hasAny = false;
|
||||
@@ -142,45 +152,49 @@ public class CompatUniformManager {
|
||||
}
|
||||
|
||||
if (hasAny) {
|
||||
programLocations.put(program, locs);
|
||||
programUniforms.put(program, new ProgramUniforms(locs));
|
||||
GLStateManager.LOGGER.debug("CompatUniformManager: program {} has compat uniforms", program);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onUseProgram(int program) {
|
||||
if (program == 0) return;
|
||||
/**
|
||||
* Uploads the emulated uniforms.
|
||||
*
|
||||
* @return Whether the program needs emulation (FFP or Iris Program)
|
||||
*/
|
||||
public static boolean refreshCompatUniforms(int program) {
|
||||
final ProgramUniforms pu = programUniforms.get(program);
|
||||
if (pu == null) return false;
|
||||
final int[] locs = pu.locs;
|
||||
|
||||
int[] locs = programLocations.get(program);
|
||||
if (locs == null) return;
|
||||
|
||||
final boolean programChanged = program != lastProgram;
|
||||
lastProgram = program;
|
||||
|
||||
// Matrix uniforms — skip if generation unchanged and same program
|
||||
// Matrix uniforms — skip if this program's storage already holds the current generation
|
||||
final int mvGen = GLStateManager.mvGeneration;
|
||||
final int mvLinearGen = GLStateManager.mvLinearGeneration;
|
||||
final int projGen = GLStateManager.projGeneration;
|
||||
final int texMatGen = GLStateManager.texMatrixGeneration;
|
||||
final boolean mvChanged = programChanged || mvGen != lastMvGen;
|
||||
final boolean projChanged = programChanged || projGen != lastProjGen;
|
||||
final boolean texMatChanged = programChanged || texMatGen != lastTexMatGen;
|
||||
final boolean mvChanged = mvGen != pu.lastMvGen;
|
||||
final boolean mvLinearChanged = mvLinearGen != pu.lastMvLinearGen;
|
||||
final boolean projChanged = projGen != pu.lastProjGen;
|
||||
final boolean texMatChanged = texMatGen != pu.lastTexMatGen;
|
||||
if (mvChanged || projChanged || texMatChanged) {
|
||||
uploadMatrices(locs, mvChanged, projChanged, texMatChanged);
|
||||
lastMvGen = mvGen;
|
||||
lastProjGen = projGen;
|
||||
lastTexMatGen = texMatGen;
|
||||
uploadMatrices(locs, mvChanged, mvLinearChanged, projChanged, texMatChanged);
|
||||
pu.lastMvGen = mvGen;
|
||||
pu.lastMvLinearGen = mvLinearGen;
|
||||
pu.lastProjGen = projGen;
|
||||
pu.lastTexMatGen = texMatGen;
|
||||
}
|
||||
|
||||
// Fragment-category uniforms (fog, alpha) — skip if generation unchanged
|
||||
final int fragGen = GLStateManager.fragmentGeneration;
|
||||
if (programChanged || fragGen != lastFragmentGen) {
|
||||
lastFragmentGen = fragGen;
|
||||
if (fragGen != pu.lastFragmentGen) {
|
||||
pu.lastFragmentGen = fragGen;
|
||||
uploadFragmentUniforms(locs);
|
||||
}
|
||||
|
||||
// Lighting-derived uniforms (scene color, light sources, material)
|
||||
final int litGen = GLStateManager.lightingGeneration;
|
||||
if (programChanged || litGen != lastLightingGen) {
|
||||
lastLightingGen = litGen;
|
||||
if (litGen != pu.lastLightingGen) {
|
||||
pu.lastLightingGen = litGen;
|
||||
if (locs[LOC_SCENE_COLOR] != -1) uploadSceneColor(locs);
|
||||
uploadLightSources(locs);
|
||||
uploadMaterial(locs);
|
||||
@@ -189,14 +203,16 @@ public class CompatUniformManager {
|
||||
// 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;
|
||||
if (cpGen != pu.lastClipPlaneGen) {
|
||||
pu.lastClipPlaneGen = cpGen;
|
||||
uploadClipPlanes(locs);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void uploadMatrices(int[] locs, boolean mvChanged, boolean projChanged, boolean texMatChanged) {
|
||||
private static void uploadMatrices(int[] locs, boolean mvChanged, boolean mvLinearChanged, boolean projChanged, boolean texMatChanged) {
|
||||
final Matrix4f mv = GLStateManager.getModelViewMatrix();
|
||||
final Matrix4f proj = GLStateManager.getProjectionMatrix();
|
||||
|
||||
@@ -218,15 +234,20 @@ public class CompatUniformManager {
|
||||
scratchMatrix.get(mat4Buf);
|
||||
RENDER_BACKEND.uniformMatrix4(locs[LOC_MODELVIEW_INVERSE], false, mat4Buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (mvLinearChanged) {
|
||||
// Normal Matrix (inverse-transpose of upper-left 3x3 of ModelView)
|
||||
if (locs[LOC_NORMAL] != -1 || locs[LOC_IRIS_NORMAL] != -1) {
|
||||
mv.normal(normalMatrix);
|
||||
normalMatrix.get(mat3Buf);
|
||||
if (locs[LOC_NORMAL] != -1) {
|
||||
normalMatrix.get(mat3Buf);
|
||||
RENDER_BACKEND.uniformMatrix3(locs[LOC_NORMAL], false, mat3Buf);
|
||||
}
|
||||
// Column-normalized to unit magnitude
|
||||
if (locs[LOC_IRIS_NORMAL] != -1) {
|
||||
normalizeColumnsInPlace(normalMatrix);
|
||||
normalMatrix.get(mat3Buf);
|
||||
RENDER_BACKEND.uniformMatrix3(locs[LOC_IRIS_NORMAL], false, mat3Buf);
|
||||
}
|
||||
}
|
||||
@@ -398,14 +419,15 @@ public class CompatUniformManager {
|
||||
}
|
||||
|
||||
public static void onDeleteProgram(int program) {
|
||||
programLocations.remove(program);
|
||||
programUniforms.remove(program);
|
||||
}
|
||||
|
||||
public static boolean hasProgram(int program) {
|
||||
return programLocations.containsKey(program);
|
||||
return programUniforms.containsKey(program);
|
||||
}
|
||||
|
||||
public static int[] getLocations(int program) {
|
||||
return programLocations.get(program);
|
||||
final ProgramUniforms pu = programUniforms.get(program);
|
||||
return pu == null ? null : pu.locs;
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ public class FeedbackManager {
|
||||
final int byteCount = count * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) first * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) first * stride + posOffset, readbackBuf);
|
||||
|
||||
emitAllPrimitives(mode, count, i -> i, stride);
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class FeedbackManager {
|
||||
final int byteCount = vertexCount * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) minIdx * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) minIdx * stride + posOffset, readbackBuf);
|
||||
|
||||
final int base = minIdx;
|
||||
emitAllPrimitives(mode, indexCount, i -> ImmediateModeRecorder.readIndex(indexBuf, type, 0, i) - base, stride);
|
||||
@@ -251,7 +251,23 @@ public class FeedbackManager {
|
||||
final int byteCount = vertexCount * stride;
|
||||
ensureReadbackCapacity(byteCount);
|
||||
readbackBuf.clear().limit(byteCount);
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, (long) minIdx * stride + posOffset, readbackBuf);
|
||||
readPositionBuffer((long) minIdx * stride + posOffset, readbackBuf);
|
||||
}
|
||||
|
||||
private static void readPositionBuffer(long offset, ByteBuffer destination) {
|
||||
final int positionVbo = VertexAttribState.get(0).vboId;
|
||||
final int previousVbo = GLStateManager.getBoundVBO();
|
||||
|
||||
if (positionVbo != 0 && positionVbo != previousVbo) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, positionVbo);
|
||||
}
|
||||
try {
|
||||
RENDER_BACKEND.getBufferSubData(GL15.GL_ARRAY_BUFFER, offset, destination);
|
||||
} finally {
|
||||
if (positionVbo != 0 && positionVbo != previousVbo) {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, previousVbo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitVertex(int vertexIndex, int stride) {
|
||||
|
||||
@@ -144,7 +144,8 @@ public class GLStateManager {
|
||||
|
||||
// Generation counters for FFP uniform dirty tracking. Bumped when the corresponding GLSM state changes.
|
||||
// Per-matrix-mode generation counters — avoids re-uploading all matrices when only one mode changed
|
||||
public static int mvGeneration; // modelview matrix changes
|
||||
public static int mvGeneration; // modelview matrix changes (any: translation, rotation, scale)
|
||||
public static int mvLinearGeneration;
|
||||
public static int projGeneration; // projection matrix changes
|
||||
public static int texMatrixGeneration; // texture matrix changes
|
||||
public static int lightingGeneration;
|
||||
@@ -163,28 +164,50 @@ public class GLStateManager {
|
||||
fragmentGeneration++;
|
||||
}
|
||||
|
||||
@Getter private static float shaderColorR = 1.0f;
|
||||
@Getter private static float shaderColorG = 1.0f;
|
||||
@Getter private static float shaderColorB = 1.0f;
|
||||
@Getter private static float shaderColorA = 1.0f;
|
||||
|
||||
public static void setShaderColor(float r, float g, float b, float a) {
|
||||
if (r == shaderColorR && g == shaderColorG && b == shaderColorB && a == shaderColorA) return;
|
||||
shaderColorR = r; shaderColorG = g; shaderColorB = b; shaderColorA = a;
|
||||
if (GLSMHooks.SHADER_COLOR_CHANGE.hasListeners()) {
|
||||
GLSMHooks.shaderColorChangeEvent.red = r;
|
||||
GLSMHooks.shaderColorChangeEvent.green = g;
|
||||
GLSMHooks.shaderColorChangeEvent.blue = b;
|
||||
GLSMHooks.shaderColorChangeEvent.alpha = a;
|
||||
GLSMHooks.SHADER_COLOR_CHANGE.post(GLSMHooks.shaderColorChangeEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// Deferred vertex attribute upload flags — set when state changes, flushed before draw
|
||||
private static boolean dirtyColorAttrib;
|
||||
private static boolean dirtyColorAttrib = true;
|
||||
private static boolean dirtyNormalAttrib;
|
||||
private static boolean dirtyTexCoordAttrib;
|
||||
private static boolean dirtyLightmapAttrib;
|
||||
private static boolean dirtyLightmapAttrib = true;
|
||||
|
||||
/** Flush deferred vertex attribute uploads. Called before draw to ensure default attrib values are current. */
|
||||
public static void flushDeferredVertexAttribs() {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.COLOR.getAttributeLocation(), color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
dirtyColorAttrib = false;
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.SECONDARY_UV.getAttributeLocation(), GLSMConfig.lastBrightnessX, GLSMConfig.lastBrightnessY, 0.0f, 1.0f);
|
||||
dirtyLightmapAttrib = false;
|
||||
if (dirtyNormalAttrib) {
|
||||
// vertexFlags bits mark attribs the VBO already supplies; FFP supplies the rest via u_Current* uniforms.
|
||||
// Skip the backend vertexAttrib call in either case.
|
||||
public static void flushDeferredVertexAttribs(int vertexFlags) {
|
||||
if (dirtyColorAttrib && (vertexFlags & VertexFlags.COLOR_BIT) == 0) {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.COLOR.getAttributeLocation(), color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
|
||||
dirtyColorAttrib = false;
|
||||
}
|
||||
if (dirtyNormalAttrib && (vertexFlags & VertexFlags.NORMAL_BIT) == 0) {
|
||||
final var n = ShaderManager.getCurrentNormal();
|
||||
RENDER_BACKEND.vertexAttrib3f(Usage.NORMAL.getAttributeLocation(), n.x, n.y, n.z);
|
||||
dirtyNormalAttrib = false;
|
||||
}
|
||||
if (dirtyTexCoordAttrib) {
|
||||
if (dirtyTexCoordAttrib && (vertexFlags & VertexFlags.TEXTURE_BIT) == 0) {
|
||||
final var tc = ShaderManager.getCurrentTexCoord();
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.PRIMARY_UV.getAttributeLocation(), tc.x, tc.y, tc.z, tc.w);
|
||||
dirtyTexCoordAttrib = false;
|
||||
}
|
||||
if (dirtyLightmapAttrib) {
|
||||
RENDER_BACKEND.vertexAttrib4f(Usage.SECONDARY_UV.getAttributeLocation(), GLSMConfig.lastBrightnessX, GLSMConfig.lastBrightnessY, 0.0f, 1.0f);
|
||||
dirtyLightmapAttrib = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Highest texture unit index that has ever had a non-zero binding; limits onDeleteTexture scan range
|
||||
@@ -280,6 +303,7 @@ public class GLStateManager {
|
||||
|
||||
// Saved generation counters at push time — used to detect whether state actually changed during push/pop scope
|
||||
private static final int[] savedMvGen = new int[MAX_ATTRIB_STACK_DEPTH];
|
||||
private static final int[] savedMvLinearGen = new int[MAX_ATTRIB_STACK_DEPTH];
|
||||
private static final int[] savedProjGen = new int[MAX_ATTRIB_STACK_DEPTH];
|
||||
private static final int[] savedTexMatGen = new int[MAX_ATTRIB_STACK_DEPTH];
|
||||
private static final int[] savedLightingGen = new int[MAX_ATTRIB_STACK_DEPTH];
|
||||
@@ -1977,7 +2001,14 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** Shrink texture to 1x1 to free GPU memory, unbind from all units, but keep the name valid. */
|
||||
/**
|
||||
* Defer deleting textures until it has been reclaimed.
|
||||
* Why you might ask? In compat profile if you bind a texture that doesn't exist, ie a deleted texture,
|
||||
* mesa will silently create it for you, in core this is an error. Why would you be binding a deleted texture?
|
||||
* Damned if I know, but vanilla and mods do it... they create one, delete it, and then bind it....
|
||||
*
|
||||
* So... we shrink the texture to 1x1 to free GPU memory, unbind from all units, but keep the name valid.
|
||||
* */
|
||||
private static void deferDeleteTexture(int id) {
|
||||
if (id == 0) return;
|
||||
|
||||
@@ -2848,6 +2879,22 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
colorMaterial.enable();
|
||||
bakeCurrentColorIntoTrackedMaterial();
|
||||
}
|
||||
|
||||
public static void disableColorMaterial() {
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordDisable(GL11.GL_COLOR_MATERIAL);
|
||||
if (mode == RecordMode.COMPILE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
bakeCurrentColorIntoTrackedMaterial();
|
||||
colorMaterial.disable();
|
||||
}
|
||||
|
||||
private static void bakeCurrentColorIntoTrackedMaterial() {
|
||||
final float r = getColor().getRed();
|
||||
final float g = getColor().getGreen();
|
||||
final float b = getColor().getBlue();
|
||||
@@ -2878,17 +2925,6 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void disableColorMaterial() {
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
DisplayListManager.recordDisable(GL11.GL_COLOR_MATERIAL);
|
||||
if (mode == RecordMode.COMPILE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
colorMaterial.disable();
|
||||
}
|
||||
|
||||
public static void disableLighting() {
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
@@ -3019,16 +3055,19 @@ public class GLStateManager {
|
||||
}
|
||||
// Update cached state (FFP shader reads from cache)
|
||||
if (isCachingEnabled()) {
|
||||
boolean changed = true;
|
||||
boolean changed = false;
|
||||
switch (pname) {
|
||||
case GL11.GL_FOG_DENSITY -> { fogState.setDensity(param); fragmentGeneration++; }
|
||||
case GL11.GL_FOG_START -> { fogState.setStart(param); fragmentGeneration++; }
|
||||
case GL11.GL_FOG_END -> { fogState.setEnd(param); fragmentGeneration++; }
|
||||
case GL11.GL_FOG_MODE -> { fogState.setFogMode((int) param); fragmentGeneration++; }
|
||||
default -> changed = false;
|
||||
case GL11.GL_FOG_DENSITY -> { if (BYPASS_CACHE || fogState.getDensity() != param) { fogState.setDensity(param); changed = true; } }
|
||||
case GL11.GL_FOG_START -> { if (BYPASS_CACHE || fogState.getStart() != param) { fogState.setStart(param); changed = true; } }
|
||||
case GL11.GL_FOG_END -> { if (BYPASS_CACHE || fogState.getEnd() != param) { fogState.setEnd(param); changed = true; } }
|
||||
case GL11.GL_FOG_MODE -> { if (BYPASS_CACHE || fogState.getFogMode() != (int) param) { fogState.setFogMode((int) param); changed = true; } }
|
||||
default -> {}
|
||||
}
|
||||
if (changed && GLSMHooks.FOG_STATE_CHANGE.hasListeners()) {
|
||||
GLSMHooks.FOG_STATE_CHANGE.post(GLSMHooks.fogStateChangeEvent);
|
||||
if (changed) {
|
||||
fragmentGeneration++;
|
||||
if (GLSMHooks.FOG_STATE_CHANGE.hasListeners()) {
|
||||
GLSMHooks.FOG_STATE_CHANGE.post(GLSMHooks.fogStateChangeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3042,7 +3081,7 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
// Update cached state (FFP shader reads from cache)
|
||||
if (isCachingEnabled() && pname == GL11.GL_FOG_MODE) {
|
||||
if (isCachingEnabled() && pname == GL11.GL_FOG_MODE && (BYPASS_CACHE || fogState.getFogMode() != param)) {
|
||||
fogState.setFogMode(param);
|
||||
fragmentGeneration++;
|
||||
if (GLSMHooks.FOG_STATE_CHANGE.hasListeners()) {
|
||||
@@ -3193,6 +3232,7 @@ public class GLStateManager {
|
||||
|
||||
// Snapshot generation counters so we can detect actual changes at pop time
|
||||
savedMvGen[attribDepth] = mvGeneration;
|
||||
savedMvLinearGen[attribDepth] = mvLinearGeneration;
|
||||
savedProjGen[attribDepth] = projGeneration;
|
||||
savedTexMatGen[attribDepth] = texMatrixGeneration;
|
||||
savedLightingGen[attribDepth] = lightingGeneration;
|
||||
@@ -3301,13 +3341,23 @@ public class GLStateManager {
|
||||
if ((mask & GL11.GL_TEXTURE_BIT) != 0 && fragmentGeneration != savedFragmentGen[depth]) fragmentGeneration++; // texenv state
|
||||
if ((mask & GL11.GL_TRANSFORM_BIT) != 0) {
|
||||
if (mvGeneration != savedMvGen[depth]) mvGeneration++;
|
||||
if (mvLinearGeneration != savedMvLinearGen[depth]) mvLinearGeneration++;
|
||||
if (projGeneration != savedProjGen[depth]) projGeneration++;
|
||||
if (texMatrixGeneration != savedTexMatGen[depth]) texMatrixGeneration++;
|
||||
}
|
||||
if ((mask & GL11.GL_CURRENT_BIT) != 0) {
|
||||
if (colorGeneration != savedColorGen[depth]) colorGeneration++;
|
||||
if (ShaderManager.getNormalGeneration() != savedNormalGen[depth]) ShaderManager.bumpNormalGeneration();
|
||||
if (ShaderManager.getTexCoordGeneration() != savedTexCoordGen[depth]) ShaderManager.bumpTexCoordGeneration();
|
||||
if (colorGeneration != savedColorGen[depth]) {
|
||||
colorGeneration++;
|
||||
dirtyColorAttrib = true;
|
||||
}
|
||||
if (ShaderManager.getNormalGeneration() != savedNormalGen[depth]) {
|
||||
ShaderManager.bumpNormalGeneration();
|
||||
dirtyNormalAttrib = true;
|
||||
}
|
||||
if (ShaderManager.getTexCoordGeneration() != savedTexCoordGen[depth]) {
|
||||
ShaderManager.bumpTexCoordGeneration();
|
||||
dirtyTexCoordAttrib = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3418,8 +3468,15 @@ public class GLStateManager {
|
||||
|
||||
/** Bump the generation counter for the currently active matrix mode. */
|
||||
private static void bumpMatrixGeneration() {
|
||||
bumpMatrixGeneration(true);
|
||||
}
|
||||
|
||||
private static void bumpMatrixGeneration(boolean linearChanged) {
|
||||
switch (matrixMode.getMode()) {
|
||||
case GL11.GL_MODELVIEW -> mvGeneration++;
|
||||
case GL11.GL_MODELVIEW -> {
|
||||
mvGeneration++;
|
||||
if (linearChanged) mvLinearGeneration++;
|
||||
}
|
||||
case GL11.GL_PROJECTION -> projGeneration++;
|
||||
case GL11.GL_TEXTURE -> texMatrixGeneration++;
|
||||
}
|
||||
@@ -3446,7 +3503,7 @@ public class GLStateManager {
|
||||
}
|
||||
if (isCachingEnabled()) {
|
||||
getMatrixStack().translate(x, y, z);
|
||||
bumpMatrixGeneration();
|
||||
bumpMatrixGeneration(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3457,7 +3514,7 @@ public class GLStateManager {
|
||||
}
|
||||
if (isCachingEnabled()) {
|
||||
getMatrixStack().translate((float) x, (float) y, (float) z);
|
||||
bumpMatrixGeneration();
|
||||
bumpMatrixGeneration(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3928,64 +3985,72 @@ public class GLStateManager {
|
||||
public static void glSamplerParameteri(int sampler, int pname, int param) { RENDER_BACKEND.samplerParameteri(sampler, pname, param); }
|
||||
public static void glSamplerParameterf(int sampler, int pname, float param) { RENDER_BACKEND.samplerParameterf(sampler, pname, param); }
|
||||
|
||||
private static void glMaterialFront(int pname, FloatBuffer params) {
|
||||
switch (pname) {
|
||||
private static boolean glMaterialFront(int pname, FloatBuffer params) {
|
||||
return switch (pname) {
|
||||
case GL11.GL_AMBIENT -> frontMaterial.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> frontMaterial.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> frontMaterial.setSpecular(params);
|
||||
case GL11.GL_EMISSION -> frontMaterial.setEmission(params);
|
||||
case GL11.GL_SHININESS -> frontMaterial.setShininess(params);
|
||||
case GL11.GL_AMBIENT_AND_DIFFUSE -> {
|
||||
frontMaterial.setAmbient(params);
|
||||
frontMaterial.setDiffuse(params);
|
||||
final boolean a = frontMaterial.setAmbient(params);
|
||||
final boolean d = frontMaterial.setDiffuse(params);
|
||||
yield a || d;
|
||||
}
|
||||
case GL11.GL_COLOR_INDEXES -> frontMaterial.setColorIndexes(params);
|
||||
}
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static void glMaterialBack(int pname, FloatBuffer params) {
|
||||
switch (pname) {
|
||||
private static boolean glMaterialBack(int pname, FloatBuffer params) {
|
||||
return switch (pname) {
|
||||
case GL11.GL_AMBIENT -> backMaterial.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> backMaterial.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> backMaterial.setSpecular(params);
|
||||
case GL11.GL_EMISSION -> backMaterial.setEmission(params);
|
||||
case GL11.GL_SHININESS -> backMaterial.setShininess(params);
|
||||
case GL11.GL_AMBIENT_AND_DIFFUSE -> {
|
||||
backMaterial.setAmbient(params);
|
||||
backMaterial.setDiffuse(params);
|
||||
final boolean a = backMaterial.setAmbient(params);
|
||||
final boolean d = backMaterial.setDiffuse(params);
|
||||
yield a || d;
|
||||
}
|
||||
case GL11.GL_COLOR_INDEXES -> backMaterial.setColorIndexes(params);
|
||||
}
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static void glMaterialFront(int pname, IntBuffer params) {
|
||||
switch (pname) {
|
||||
private static boolean glMaterialFront(int pname, IntBuffer params) {
|
||||
return switch (pname) {
|
||||
case GL11.GL_AMBIENT -> frontMaterial.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> frontMaterial.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> frontMaterial.setSpecular(params);
|
||||
case GL11.GL_EMISSION -> frontMaterial.setEmission(params);
|
||||
case GL11.GL_SHININESS -> frontMaterial.setShininess(params);
|
||||
case GL11.GL_AMBIENT_AND_DIFFUSE -> {
|
||||
frontMaterial.setAmbient(params);
|
||||
frontMaterial.setDiffuse(params);
|
||||
final boolean a = frontMaterial.setAmbient(params);
|
||||
final boolean d = frontMaterial.setDiffuse(params);
|
||||
yield a || d;
|
||||
}
|
||||
case GL11.GL_COLOR_INDEXES -> frontMaterial.setColorIndexes(params);
|
||||
}
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static void glMaterialBack(int pname, IntBuffer params) {
|
||||
switch (pname) {
|
||||
private static boolean glMaterialBack(int pname, IntBuffer params) {
|
||||
return switch (pname) {
|
||||
case GL11.GL_AMBIENT -> backMaterial.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> backMaterial.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> backMaterial.setSpecular(params);
|
||||
case GL11.GL_EMISSION -> backMaterial.setEmission(params);
|
||||
case GL11.GL_SHININESS -> backMaterial.setShininess(params);
|
||||
case GL11.GL_AMBIENT_AND_DIFFUSE -> {
|
||||
backMaterial.setAmbient(params);
|
||||
backMaterial.setDiffuse(params);
|
||||
final boolean a = backMaterial.setAmbient(params);
|
||||
final boolean d = backMaterial.setDiffuse(params);
|
||||
yield a || d;
|
||||
}
|
||||
case GL11.GL_COLOR_INDEXES -> backMaterial.setColorIndexes(params);
|
||||
}
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
public static void glMaterial(int face, int pname, FloatBuffer params) {
|
||||
@@ -3996,17 +4061,19 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean changed = false;
|
||||
if (face == GL11.GL_FRONT) {
|
||||
glMaterialFront(pname, params);
|
||||
changed = glMaterialFront(pname, params);
|
||||
} else if (face == GL11.GL_BACK) {
|
||||
glMaterialBack(pname, params);
|
||||
changed = glMaterialBack(pname, params);
|
||||
} else if (face == GL11.GL_FRONT_AND_BACK) {
|
||||
glMaterialFront(pname, params);
|
||||
glMaterialBack(pname, params);
|
||||
final boolean f = glMaterialFront(pname, params);
|
||||
final boolean b = glMaterialBack(pname, params);
|
||||
changed = f || b;
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported face value for glMaterial: " + face);
|
||||
}
|
||||
lightingGeneration++;
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glMaterial(int face, int pname, IntBuffer params) {
|
||||
@@ -4025,17 +4092,19 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean changed = false;
|
||||
if (face == GL11.GL_FRONT) {
|
||||
glMaterialFront(pname, params);
|
||||
changed = glMaterialFront(pname, params);
|
||||
} else if (face == GL11.GL_BACK) {
|
||||
glMaterialBack(pname, params);
|
||||
changed = glMaterialBack(pname, params);
|
||||
} else if (face == GL11.GL_FRONT_AND_BACK) {
|
||||
glMaterialFront(pname, params);
|
||||
glMaterialBack(pname, params);
|
||||
final boolean f = glMaterialFront(pname, params);
|
||||
final boolean b = glMaterialBack(pname, params);
|
||||
changed = f || b;
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported face value for glMaterial: " + face);
|
||||
}
|
||||
lightingGeneration++;
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glMaterialf(int face, int pname, float val) {
|
||||
@@ -4051,17 +4120,19 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
if (face == GL11.GL_FRONT) {
|
||||
frontMaterial.setShininess(val);
|
||||
changed = frontMaterial.setShininess(val);
|
||||
} else if (face == GL11.GL_BACK) {
|
||||
backMaterial.setShininess(val);
|
||||
changed = backMaterial.setShininess(val);
|
||||
} else if (face == GL11.GL_FRONT_AND_BACK) {
|
||||
frontMaterial.setShininess(val);
|
||||
backMaterial.setShininess(val);
|
||||
final boolean f = frontMaterial.setShininess(val);
|
||||
final boolean b = backMaterial.setShininess(val);
|
||||
changed = f || b;
|
||||
} else {
|
||||
throw new RuntimeException("Unsupported face value for glMaterial: " + face);
|
||||
}
|
||||
lightingGeneration++;
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glMateriali(int face, int pname, int val) {
|
||||
@@ -4079,7 +4150,7 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
final LightStateStack lightState = lightDataStates[light - GL11.GL_LIGHT0];
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_AMBIENT -> lightState.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> lightState.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> lightState.setSpecular(params);
|
||||
@@ -4090,9 +4161,9 @@ public class GLStateManager {
|
||||
case GL11.GL_CONSTANT_ATTENUATION -> lightState.setConstantAttenuation(params);
|
||||
case GL11.GL_LINEAR_ATTENUATION -> lightState.setLinearAttenuation(params);
|
||||
case GL11.GL_QUADRATIC_ATTENUATION -> lightState.setQuadraticAttenuation(params);
|
||||
default -> {}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLight(int light, int pname, IntBuffer params) {
|
||||
@@ -4112,7 +4183,7 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
final LightStateStack lightState = lightDataStates[light - GL11.GL_LIGHT0];
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_AMBIENT -> lightState.setAmbient(params);
|
||||
case GL11.GL_DIFFUSE -> lightState.setDiffuse(params);
|
||||
case GL11.GL_SPECULAR -> lightState.setSpecular(params);
|
||||
@@ -4123,9 +4194,9 @@ public class GLStateManager {
|
||||
case GL11.GL_CONSTANT_ATTENUATION -> lightState.setConstantAttenuation(params);
|
||||
case GL11.GL_LINEAR_ATTENUATION -> lightState.setLinearAttenuation(params);
|
||||
case GL11.GL_QUADRATIC_ATTENUATION -> lightState.setQuadraticAttenuation(params);
|
||||
default -> {}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLightf(int light, int pname, float param) {
|
||||
@@ -4137,15 +4208,15 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
final LightStateStack lightState = lightDataStates[light - GL11.GL_LIGHT0];
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_SPOT_EXPONENT -> lightState.setSpotExponent(param);
|
||||
case GL11.GL_SPOT_CUTOFF -> lightState.setSpotCutoff(param);
|
||||
case GL11.GL_CONSTANT_ATTENUATION -> lightState.setConstantAttenuation(param);
|
||||
case GL11.GL_LINEAR_ATTENUATION -> lightState.setLinearAttenuation(param);
|
||||
case GL11.GL_QUADRATIC_ATTENUATION -> lightState.setQuadraticAttenuation(param);
|
||||
default -> {}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLighti(int light, int pname, int param) {
|
||||
@@ -4157,16 +4228,15 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
final LightStateStack lightState = lightDataStates[light - GL11.GL_LIGHT0];
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_SPOT_EXPONENT -> lightState.setSpotExponent(param);
|
||||
case GL11.GL_SPOT_CUTOFF -> lightState.setSpotCutoff(param);
|
||||
case GL11.GL_CONSTANT_ATTENUATION -> lightState.setConstantAttenuation(param);
|
||||
case GL11.GL_LINEAR_ATTENUATION -> lightState.setLinearAttenuation(param);
|
||||
case GL11.GL_QUADRATIC_ATTENUATION -> lightState.setQuadraticAttenuation(param);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLightModel(int pname, FloatBuffer params) {
|
||||
@@ -4177,14 +4247,13 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_LIGHT_MODEL_AMBIENT -> lightModel.setAmbient(params);
|
||||
case GL11.GL_LIGHT_MODEL_LOCAL_VIEWER -> lightModel.setLocalViewer(params);
|
||||
case GL11.GL_LIGHT_MODEL_TWO_SIDE -> lightModel.setTwoSide(params);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLightModel(int pname, IntBuffer params) {
|
||||
@@ -4203,15 +4272,14 @@ public class GLStateManager {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_LIGHT_MODEL_AMBIENT -> lightModel.setAmbient(params);
|
||||
case GL12.GL_LIGHT_MODEL_COLOR_CONTROL -> lightModel.setColorControl(params);
|
||||
case GL11.GL_LIGHT_MODEL_LOCAL_VIEWER -> lightModel.setLocalViewer(params);
|
||||
case GL11.GL_LIGHT_MODEL_TWO_SIDE -> lightModel.setTwoSide(params);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
|
||||
public static void glLightModelf(int pname, float param) {
|
||||
@@ -4224,13 +4292,12 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
if (isCachingEnabled()) {
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL11.GL_LIGHT_MODEL_LOCAL_VIEWER -> lightModel.setLocalViewer(param);
|
||||
case GL11.GL_LIGHT_MODEL_TWO_SIDE -> lightModel.setTwoSide(param);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4244,14 +4311,13 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
if (isCachingEnabled()) {
|
||||
switch (pname) {
|
||||
final boolean changed = switch (pname) {
|
||||
case GL12.GL_LIGHT_MODEL_COLOR_CONTROL -> lightModel.setColorControl(param);
|
||||
case GL11.GL_LIGHT_MODEL_LOCAL_VIEWER -> lightModel.setLocalViewer(param);
|
||||
case GL11.GL_LIGHT_MODEL_TWO_SIDE -> lightModel.setTwoSide(param);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
lightingGeneration++;
|
||||
default -> false;
|
||||
};
|
||||
if (changed) lightingGeneration++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4326,7 +4392,6 @@ public class GLStateManager {
|
||||
GLDebug.debugMessage("Activating Program - " + program + ":" + programName);
|
||||
}
|
||||
RENDER_BACKEND.useProgram(program);
|
||||
CompatUniformManager.onUseProgram(program);
|
||||
if (GLSMHooks.PROGRAM_CHANGE.hasListeners()) {
|
||||
GLSMHooks.programChangeEvent.previousProgram = prev;
|
||||
GLSMHooks.programChangeEvent.newProgram = program;
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Abstract rendering backend.
|
||||
@@ -25,6 +27,14 @@ public abstract class RenderBackend {
|
||||
/** Higher priority backends are preferred. */
|
||||
public int getPriority() { return 0; }
|
||||
|
||||
public boolean supportsFileDrop() { return false; }
|
||||
|
||||
public void startFileDrop() {}
|
||||
|
||||
public void stopFileDrop() {}
|
||||
|
||||
public List<String> pollDroppedFiles() { return Collections.emptyList(); }
|
||||
|
||||
public abstract int getMinGLSLVersion();
|
||||
|
||||
public abstract void flush();
|
||||
|
||||
@@ -26,6 +26,16 @@ public class Program {
|
||||
@Getter private final VertexKey vertexKey;
|
||||
@Getter private final FragmentKey fragmentKey;
|
||||
|
||||
// Per-program uniform dirty-tracking
|
||||
static final class UploadState {
|
||||
int mvGen = -1, mvLinearGen = -1, projGen = -1, texMatGen = -1;
|
||||
int lightingGen = -1, fragmentGen = -1, colorGen = -1, normalGen = -1, texCoordGen = -1;
|
||||
int texGenGen = -1, clipPlaneGen = -1;
|
||||
float lightmapX = Float.NaN, lightmapY = Float.NaN, lineWidth = Float.NaN;
|
||||
int viewportWidth = -1, viewportHeight = -1;
|
||||
}
|
||||
final UploadState uploadState = new UploadState();
|
||||
|
||||
// Uniform locations (-1 = not present in this variant)
|
||||
// Matrices
|
||||
public int locModelViewMatrix = -1;
|
||||
|
||||
@@ -22,7 +22,7 @@ import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACK
|
||||
/**
|
||||
* FFP shader manager
|
||||
*/
|
||||
public class ShaderManager {
|
||||
public final class ShaderManager {
|
||||
|
||||
private static final class Holder {
|
||||
|
||||
@@ -36,6 +36,7 @@ public class ShaderManager {
|
||||
@Getter
|
||||
private boolean active = false;
|
||||
private Program currentProgram = null;
|
||||
private int lastBoundProgramId = -1;
|
||||
private long currentVertexKeyPacked = Long.MIN_VALUE;
|
||||
private final long[] currentFKScratch = new long[FragmentKey.MAX_UNITS];
|
||||
private final long[] currentFKPacked = new long[FragmentKey.MAX_UNITS];
|
||||
@@ -87,35 +88,34 @@ public class ShaderManager {
|
||||
|
||||
public void activate() {
|
||||
active = true;
|
||||
updateVariant(true, true, true, true);
|
||||
uploadUniforms();
|
||||
lastBoundProgramId = GLStateManager.getActiveProgram();
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
active = false;
|
||||
currentProgram = null;
|
||||
lastBoundProgramId = -1;
|
||||
currentVertexKeyPacked = Long.MIN_VALUE;
|
||||
currentFKLen = 0;
|
||||
}
|
||||
|
||||
public void preDraw(boolean hasColor, boolean hasNormal, boolean hasTexCoord, boolean hasLightmap) {
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
final DeferredBlendHandler bh = GLSMHooks.blendHandler;
|
||||
if (bh != null) bh.flushDeferredBlend();
|
||||
|
||||
if (!active) {
|
||||
if (enabled) {
|
||||
final int currentProgramId = GLStateManager.getActiveProgram();
|
||||
if (currentProgramId != 0) {
|
||||
CompatUniformManager.onUseProgram(currentProgramId);
|
||||
return;
|
||||
}
|
||||
active = true;
|
||||
} else {
|
||||
return;
|
||||
// Handle FFP & Iris uniforms
|
||||
final int currentProgramId = GLStateManager.getActiveProgram();
|
||||
if (currentProgramId != 0) {
|
||||
if (!CompatUniformManager.refreshCompatUniforms(currentProgramId)) {
|
||||
return; // Don't emulate FFP on non-iris core shaders
|
||||
}
|
||||
}
|
||||
|
||||
GLStateManager.flushDeferredVertexAttribs(currentVertexFlags);
|
||||
|
||||
if (!active) return;
|
||||
|
||||
|
||||
final int fkLen = FragmentKey.packFromState(currentFKScratch);
|
||||
final int fragMask = FragmentKey.unitMaskFromPacked(currentFKScratch, fkLen);
|
||||
final long vkPacked = VertexKey.packFromState(hasColor, hasNormal, hasTexCoord, hasLightmap, fragMask);
|
||||
@@ -141,19 +141,16 @@ public class ShaderManager {
|
||||
preDraw(currentVertexFlags);
|
||||
}
|
||||
|
||||
private void updateVariant(boolean hasColor, boolean hasNormal, boolean hasTexCoord, boolean hasLightmap) {
|
||||
final int fkLen = FragmentKey.packFromState(currentFKScratch);
|
||||
final int fragMask = FragmentKey.unitMaskFromPacked(currentFKScratch, fkLen);
|
||||
final long vkPacked = VertexKey.packFromState(hasColor, hasNormal, hasTexCoord, hasLightmap, fragMask);
|
||||
commitVariant(vkPacked, fkLen);
|
||||
}
|
||||
|
||||
private void commitVariant(long vkPacked, int fkLen) {
|
||||
currentVertexKeyPacked = vkPacked;
|
||||
System.arraycopy(currentFKScratch, 0, currentFKPacked, 0, fkLen);
|
||||
currentFKLen = fkLen;
|
||||
currentProgram = cache.getOrCreate(vkPacked, currentFKPacked, currentFKLen);
|
||||
RENDER_BACKEND.useProgram(currentProgram.getProgramId());
|
||||
final int programId = currentProgram.getProgramId();
|
||||
if (programId != lastBoundProgramId) {
|
||||
RENDER_BACKEND.useProgram(programId);
|
||||
lastBoundProgramId = programId;
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadUniforms() {
|
||||
|
||||
@@ -46,116 +46,99 @@ public class Uniforms {
|
||||
private static final double LN2 = java.lang.Math.log(2.0);
|
||||
private static final double SQRT_LN2 = java.lang.Math.sqrt(LN2);
|
||||
|
||||
// Dirty tracking: last-uploaded generation per category + program ID.
|
||||
// Program change forces full re-upload since uniform locations differ.
|
||||
private int lastProgramId = -1;
|
||||
private int lastMvGen = -1;
|
||||
private int lastProjGen = -1;
|
||||
private int lastTexMatGen = -1;
|
||||
private int lastLightingGen = -1;
|
||||
private int lastFragmentGen = -1;
|
||||
private int lastColorGen = -1;
|
||||
private int lastNormalGen = -1;
|
||||
private int lastTexCoordGen = -1;
|
||||
private float lastLightmapX = Float.NaN;
|
||||
private float lastLightmapY = Float.NaN;
|
||||
private int lastTexGenGen = -1;
|
||||
private int lastClipPlaneGen = -1;
|
||||
private float lastLineWidth = Float.NaN;
|
||||
private int lastViewportWidth = -1;
|
||||
private int lastViewportHeight = -1;
|
||||
|
||||
/**
|
||||
* Upload all relevant uniforms to the given FFP program based on current GLSM state.
|
||||
* Uses generation counters to skip categories that haven't changed since last upload.
|
||||
*/
|
||||
public void upload(Program program) {
|
||||
final boolean programChanged = program.getProgramId() != lastProgramId;
|
||||
lastProgramId = program.getProgramId();
|
||||
final Program.UploadState st = program.uploadState;
|
||||
|
||||
final int mvGen = GLStateManager.mvGeneration;
|
||||
final int mvLinearGen = GLStateManager.mvLinearGeneration;
|
||||
final int projGen = GLStateManager.projGeneration;
|
||||
final int texMatGen = GLStateManager.texMatrixGeneration;
|
||||
final boolean mvChanged = programChanged || mvGen != lastMvGen;
|
||||
final boolean projChanged = programChanged || projGen != lastProjGen;
|
||||
final boolean texMatChanged = programChanged || texMatGen != lastTexMatGen;
|
||||
final boolean mvChanged = mvGen != st.mvGen;
|
||||
final boolean mvLinearChanged = mvLinearGen != st.mvLinearGen;
|
||||
final boolean projChanged = projGen != st.projGen;
|
||||
final boolean texMatChanged = texMatGen != st.texMatGen;
|
||||
if (mvChanged || projChanged || texMatChanged) {
|
||||
uploadMatrices(program, mvChanged, projChanged, texMatChanged);
|
||||
lastMvGen = mvGen;
|
||||
lastProjGen = projGen;
|
||||
lastTexMatGen = texMatGen;
|
||||
uploadMatrices(program, mvChanged, mvLinearChanged, projChanged, texMatChanged);
|
||||
st.mvGen = mvGen;
|
||||
st.mvLinearGen = mvLinearGen;
|
||||
st.projGen = projGen;
|
||||
st.texMatGen = texMatGen;
|
||||
}
|
||||
|
||||
if (program.getVertexKey().lightingEnabled()) {
|
||||
final int litGen = GLStateManager.lightingGeneration;
|
||||
if (programChanged || litGen != lastLightingGen) {
|
||||
if (litGen != st.lightingGen) {
|
||||
uploadLighting(program);
|
||||
lastLightingGen = litGen;
|
||||
st.lightingGen = litGen;
|
||||
}
|
||||
}
|
||||
|
||||
// Current color/normal/texcoord — skip if generation unchanged
|
||||
if (!program.getVertexKey().hasVertexColor()) {
|
||||
final int colorGen = GLStateManager.colorGeneration;
|
||||
if (programChanged || colorGen != lastColorGen) {
|
||||
if (colorGen != st.colorGen) {
|
||||
uploadCurrentColor(program);
|
||||
lastColorGen = colorGen;
|
||||
st.colorGen = colorGen;
|
||||
}
|
||||
}
|
||||
|
||||
if (!program.getVertexKey().hasVertexNormal() && program.getVertexKey().lightingEnabled()) {
|
||||
final int normalGen = ShaderManager.getNormalGeneration();
|
||||
if (programChanged || normalGen != lastNormalGen) {
|
||||
if (normalGen != st.normalGen) {
|
||||
uploadCurrentNormal(program);
|
||||
lastNormalGen = normalGen;
|
||||
st.normalGen = normalGen;
|
||||
}
|
||||
}
|
||||
|
||||
if (program.getVertexKey().anyUnitTexCoordEnabled()) {
|
||||
final int texGen = ShaderManager.getTexCoordGeneration();
|
||||
if (programChanged || texGen != lastTexCoordGen) {
|
||||
if (texGen != st.texCoordGen) {
|
||||
uploadCurrentTexCoords(program);
|
||||
lastTexCoordGen = texGen;
|
||||
st.texCoordGen = texGen;
|
||||
}
|
||||
}
|
||||
|
||||
if (program.getVertexKey().lightmapEnabled() && !program.getVertexKey().hasVertexLightmap()) {
|
||||
if (programChanged || GLSMConfig.lastBrightnessX != lastLightmapX || GLSMConfig.lastBrightnessY != lastLightmapY) {
|
||||
if (GLSMConfig.lastBrightnessX != st.lightmapX || GLSMConfig.lastBrightnessY != st.lightmapY) {
|
||||
uploadCurrentLightmapCoord(program);
|
||||
lastLightmapX = GLSMConfig.lastBrightnessX;
|
||||
lastLightmapY = GLSMConfig.lastBrightnessY;
|
||||
st.lightmapX = GLSMConfig.lastBrightnessX;
|
||||
st.lightmapY = GLSMConfig.lastBrightnessY;
|
||||
}
|
||||
}
|
||||
|
||||
if (program.getVertexKey().texGenEnabled()) {
|
||||
final int tgGen = GLStateManager.texGenGeneration;
|
||||
if (programChanged || tgGen != lastTexGenGen) {
|
||||
if (tgGen != st.texGenGen) {
|
||||
uploadTexGen(program);
|
||||
lastTexGenGen = tgGen;
|
||||
st.texGenGen = tgGen;
|
||||
}
|
||||
}
|
||||
|
||||
if (program.getVertexKey().clipPlanesEnabled()) {
|
||||
final int cpGen = GLStateManager.clipPlaneGeneration;
|
||||
if (programChanged || cpGen != lastClipPlaneGen) {
|
||||
if (cpGen != st.clipPlaneGen) {
|
||||
uploadClipPlanes(program);
|
||||
lastClipPlaneGen = cpGen;
|
||||
st.clipPlaneGen = cpGen;
|
||||
}
|
||||
}
|
||||
|
||||
final int fragGen = GLStateManager.fragmentGeneration;
|
||||
if (programChanged || fragGen != lastFragmentGen) {
|
||||
if (fragGen != st.fragmentGen) {
|
||||
uploadFragmentUniforms(program);
|
||||
lastFragmentGen = fragGen;
|
||||
st.fragmentGen = fragGen;
|
||||
}
|
||||
|
||||
// Wide line emulation uniforms
|
||||
if (program.locLineWidth != -1 && program.locViewportSize != -1) {
|
||||
uploadWideLineUniforms(program, programChanged);
|
||||
uploadWideLineUniforms(program);
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadMatrices(Program program, boolean mvChanged, boolean projChanged, boolean texMatChanged) {
|
||||
private void uploadMatrices(Program program, boolean mvChanged, boolean mvLinearChanged, boolean projChanged, boolean texMatChanged) {
|
||||
final Matrix4f mv = GLStateManager.getModelViewMatrix();
|
||||
final Matrix4f proj = GLStateManager.getProjectionMatrix();
|
||||
|
||||
@@ -165,7 +148,9 @@ public class Uniforms {
|
||||
mv.get(mat4Buf);
|
||||
RENDER_BACKEND.uniformMatrix4(program.locModelViewMatrix, false, mat4Buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (mvLinearChanged) {
|
||||
// Normal matrix = inverse transpose of upper-left 3x3 of ModelView
|
||||
if (program.locNormalMatrix != -1 || program.locNormalScale != -1) {
|
||||
mv.normal(normalMatrix);
|
||||
@@ -314,12 +299,13 @@ public class Uniforms {
|
||||
if (program.locCurrentColor == -1) return;
|
||||
// Upload the current color from GLSM
|
||||
final var color = GLStateManager.getColor();
|
||||
tempVec4.set(
|
||||
Math.clamp(0f, 1f, color.getRed()),
|
||||
Math.clamp(0f, 1f, color.getGreen()),
|
||||
Math.clamp(0f, 1f, color.getBlue()),
|
||||
Math.clamp(0f, 1f, color.getAlpha()));
|
||||
vec4Buf.clear();
|
||||
vec4Buf.put(Math.clamp(0f, 1f, color.getRed()));
|
||||
vec4Buf.put(Math.clamp(0f, 1f, color.getGreen()));
|
||||
vec4Buf.put(Math.clamp(0f, 1f, color.getBlue()));
|
||||
vec4Buf.put(Math.clamp(0f, 1f, color.getAlpha()));
|
||||
vec4Buf.flip();
|
||||
tempVec4.get(vec4Buf);
|
||||
RENDER_BACKEND.uniform4(program.locCurrentColor, vec4Buf);
|
||||
}
|
||||
|
||||
@@ -342,10 +328,7 @@ public class Uniforms {
|
||||
// Upload current normal from FFPShaderManager's tracked normal
|
||||
final var normal = ShaderManager.getCurrentNormal();
|
||||
vec3Buf.clear();
|
||||
vec3Buf.put(normal.x);
|
||||
vec3Buf.put(normal.y);
|
||||
vec3Buf.put(normal.z);
|
||||
vec3Buf.flip();
|
||||
normal.get(vec3Buf);
|
||||
RENDER_BACKEND.uniform3(program.locCurrentNormal, vec3Buf);
|
||||
}
|
||||
|
||||
@@ -381,10 +364,7 @@ public class Uniforms {
|
||||
private void uploadPlane(int loc, float[] plane) {
|
||||
if (loc == -1) return;
|
||||
vec4Buf.clear();
|
||||
vec4Buf.put(plane[0]);
|
||||
vec4Buf.put(plane[1]);
|
||||
vec4Buf.put(plane[2]);
|
||||
vec4Buf.put(plane[3]);
|
||||
vec4Buf.put(plane, 0, 4);
|
||||
vec4Buf.flip();
|
||||
RENDER_BACKEND.uniform4(loc, vec4Buf);
|
||||
}
|
||||
@@ -470,29 +450,26 @@ public class Uniforms {
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadWideLineUniforms(Program program, boolean programChanged) {
|
||||
private void uploadWideLineUniforms(Program program) {
|
||||
final Program.UploadState st = program.uploadState;
|
||||
final float lineWidth = GLStateManager.getLineState().getWidth();
|
||||
if (programChanged || lineWidth != lastLineWidth) {
|
||||
if (lineWidth != st.lineWidth) {
|
||||
RENDER_BACKEND.uniform1f(program.locLineWidth, lineWidth);
|
||||
lastLineWidth = lineWidth;
|
||||
st.lineWidth = lineWidth;
|
||||
}
|
||||
final int vw = GLStateManager.getViewportState().width;
|
||||
final int vh = GLStateManager.getViewportState().height;
|
||||
if (programChanged || vw != lastViewportWidth || vh != lastViewportHeight) {
|
||||
if (vw != st.viewportWidth || vh != st.viewportHeight) {
|
||||
RENDER_BACKEND.uniform2f(program.locViewportSize, vw, vh);
|
||||
lastViewportWidth = vw;
|
||||
lastViewportHeight = vh;
|
||||
st.viewportWidth = vw;
|
||||
st.viewportHeight = vh;
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadVec4(int loc, Vector4f v) {
|
||||
if (loc == -1) return;
|
||||
vec4Buf.clear();
|
||||
vec4Buf.put(v.x);
|
||||
vec4Buf.put(v.y);
|
||||
vec4Buf.put(v.z);
|
||||
vec4Buf.put(v.w);
|
||||
vec4Buf.flip();
|
||||
v.get(vec4Buf);
|
||||
RENDER_BACKEND.uniform4(loc, vec4Buf);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class GLSMHooks {
|
||||
public static final EventBus<FogStateChangeEvent> FOG_STATE_CHANGE = EventBus.create(FogStateChangeEvent.class);
|
||||
public static final EventBus<LightmapCoordsEvent> LIGHTMAP_COORDS = EventBus.create(LightmapCoordsEvent.class);
|
||||
public static final EventBus<AlphaStateChangeEvent> ALPHA_STATE_CHANGE = EventBus.create(AlphaStateChangeEvent.class);
|
||||
public static final EventBus<ShaderColorChangeEvent> SHADER_COLOR_CHANGE = EventBus.create(ShaderColorChangeEvent.class);
|
||||
|
||||
// Reusable event instances
|
||||
public static final TextureBindEvent textureBindEvent = new TextureBindEvent();
|
||||
@@ -28,6 +29,7 @@ public final class GLSMHooks {
|
||||
public static final FogStateChangeEvent fogStateChangeEvent = new FogStateChangeEvent();
|
||||
public static final LightmapCoordsEvent lightmapCoordsEvent = new LightmapCoordsEvent();
|
||||
public static final AlphaStateChangeEvent alphaStateChangeEvent = new AlphaStateChangeEvent();
|
||||
public static final ShaderColorChangeEvent shaderColorChangeEvent = new ShaderColorChangeEvent();
|
||||
|
||||
private GLSMHooks() {}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.gtnewhorizons.angelica.glsm.hooks.events;
|
||||
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class ShaderColorChangeEvent extends MutableEvent {
|
||||
public float red;
|
||||
public float green;
|
||||
public float blue;
|
||||
public float alpha;
|
||||
}
|
||||
@@ -35,11 +35,30 @@ public final class EcosystemNarrowRules {
|
||||
"com.fiskmods.lightsabers.asm.transformers"
|
||||
)),
|
||||
|
||||
new NarrowRule("FiskHeroes", "com.fiskmods.heroes.asm", List.of(
|
||||
"com.fiskmods.heroes.asm.SHLoadingPlugin",
|
||||
"com.fiskmods.heroes.asm.transformers"
|
||||
)),
|
||||
|
||||
new NarrowRule("Ears", "com.unascribed.ears", List.of(
|
||||
"com.unascribed.ears.asm",
|
||||
"com.unascribed.ears.common.agent"
|
||||
)),
|
||||
|
||||
new NarrowRule("FoamFix", "pl.asie.foamfix", List.of(
|
||||
"pl.asie.foamfix.bugfixmod",
|
||||
"pl.asie.foamfix.coremod",
|
||||
"pl.asie.foamfix.forkage",
|
||||
"pl.asie.foamfix.ghostbuster",
|
||||
"pl.asie.foamfix.FoamFixMod",
|
||||
"pl.asie.foamfix.HackyMessageFactoryWrapper",
|
||||
"pl.asie.foamfix.LaunchWrapperRuntimeFix",
|
||||
"pl.asie.foamfix.ProxyClient",
|
||||
"pl.asie.foamfix.ProxyCommon",
|
||||
"pl.asie.foamfix.repack.com.unascribed.ears.asm",
|
||||
"pl.asie.foamfix.repack.com.unascribed.ears.common.agent"
|
||||
)),
|
||||
|
||||
new NarrowRule("Alfheim", "alfheim.common.core.asm.hook", List.of(
|
||||
"alfheim.common.core.asm.hook.AlfheimFieldHookHandler",
|
||||
"alfheim.common.core.asm.hook.AlfheimHPHooks",
|
||||
|
||||
@@ -27,65 +27,75 @@ public class LightModelState implements ISettableState<LightModelState> {
|
||||
twoSide = 0.0F;
|
||||
}
|
||||
|
||||
public void setAmbient(FloatBuffer newBuffer) {
|
||||
public boolean setAmbient(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAmbient(IntBuffer newBuffer) {
|
||||
public boolean setAmbient(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setColorControl(int val) {
|
||||
public boolean setColorControl(int val) {
|
||||
if (GLStateManager.shouldBypassCache() || this.colorControl != val) {
|
||||
this.colorControl = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setColorControl(IntBuffer newBuffer) {
|
||||
setColorControl(newBuffer.get());
|
||||
public boolean setColorControl(IntBuffer newBuffer) {
|
||||
return setColorControl(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setLocalViewer(float val) {
|
||||
public boolean setLocalViewer(float val) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(this.localViewer, val) != 0) {
|
||||
this.localViewer = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setLocalViewer(FloatBuffer newBuffer) {
|
||||
setLocalViewer(newBuffer.get());
|
||||
public boolean setLocalViewer(FloatBuffer newBuffer) {
|
||||
return setLocalViewer(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setLocalViewer(IntBuffer newBuffer) {
|
||||
setLocalViewer((float) newBuffer.get());
|
||||
public boolean setLocalViewer(IntBuffer newBuffer) {
|
||||
return setLocalViewer((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setLocalViewer(int val) {
|
||||
setLocalViewer((float) val);
|
||||
public boolean setLocalViewer(int val) {
|
||||
return setLocalViewer((float) val);
|
||||
}
|
||||
|
||||
public void setTwoSide(float val) {
|
||||
public boolean setTwoSide(float val) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(this.twoSide, val) != 0) {
|
||||
this.twoSide = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setTwoSide(FloatBuffer newBuffer) {
|
||||
setTwoSide(newBuffer.get());
|
||||
public boolean setTwoSide(FloatBuffer newBuffer) {
|
||||
return setTwoSide(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setTwoSide(IntBuffer newBuffer) {
|
||||
setTwoSide((float) newBuffer.get());
|
||||
public boolean setTwoSide(IntBuffer newBuffer) {
|
||||
return setTwoSide((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setTwoSide(int val) {
|
||||
setTwoSide((float) val);
|
||||
public boolean setTwoSide(int val) {
|
||||
return setTwoSide((float) val);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,6 +17,7 @@ public class LightState implements ISettableState<LightState> {
|
||||
|
||||
private static final Vector4i vector4i = new Vector4i();
|
||||
private static final Vector4f vector4f = new Vector4f();
|
||||
private static final Vector3f vector3f = new Vector3f();
|
||||
private static final Vector3i vector3i = new Vector3i();
|
||||
private static final Matrix3f matrix3f = new Matrix3f();
|
||||
|
||||
@@ -27,6 +28,10 @@ public class LightState implements ISettableState<LightState> {
|
||||
public final Vector4f specular;
|
||||
public final Vector4f position;
|
||||
public final Vector3f spotDirection;
|
||||
private final Vector4f rawPosition;
|
||||
private int posMvGeneration = -1;
|
||||
private final Vector3f rawSpotDirection;
|
||||
private int spotDirLinearGeneration = -1;
|
||||
public float spotExponent;
|
||||
public float spotCutoff;
|
||||
public float spotCosCutoff;
|
||||
@@ -66,178 +71,221 @@ public class LightState implements ISettableState<LightState> {
|
||||
this.linearAttenuation = linearAttenuation;
|
||||
this.quadraticAttenuation = quadraticAttenuation;
|
||||
|
||||
this.rawPosition = new Vector4f(position);
|
||||
this.position = position;
|
||||
this.position.mul(GLStateManager.getModelViewMatrix());
|
||||
this.posMvGeneration = GLStateManager.mvGeneration;
|
||||
|
||||
this.rawSpotDirection = new Vector3f(spotDirection);
|
||||
this.spotDirection = spotDirection;
|
||||
GLStateManager.getModelViewMatrix().get3x3(matrix3f);
|
||||
this.spotDirection.mul(matrix3f);
|
||||
this.spotDirLinearGeneration = GLStateManager.mvLinearGeneration;
|
||||
}
|
||||
|
||||
public void setAmbient(FloatBuffer newBuffer) {
|
||||
public boolean setAmbient(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAmbient(IntBuffer newBuffer) {
|
||||
public boolean setAmbient(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setDiffuse(FloatBuffer newBuffer) {
|
||||
public boolean setDiffuse(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.diffuse.equals(vector4f)) {
|
||||
this.diffuse.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setDiffuse(IntBuffer newBuffer) {
|
||||
public boolean setDiffuse(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.diffuse.equals(vector4f)) {
|
||||
this.diffuse.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpecular(FloatBuffer newBuffer) {
|
||||
public boolean setSpecular(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.specular.equals(vector4f)) {
|
||||
this.specular.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpecular(IntBuffer newBuffer) {
|
||||
public boolean setSpecular(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.specular.equals(vector4f)) {
|
||||
this.specular.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setPosition(FloatBuffer newBuffer) {
|
||||
// We are bypassing cache everytime for position, because the necessary components to enable tracking the cache
|
||||
// are big and probably more than just bypassing. We would need to track the modelview matrix it was transformed
|
||||
// with and the untransformed coordinates in addition to the final transformation.
|
||||
this.position.set(newBuffer);
|
||||
this.position.mul(GLStateManager.getModelViewMatrix());
|
||||
public boolean setPosition(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
return applyPosition(vector4f);
|
||||
}
|
||||
|
||||
public void setPosition(IntBuffer newBuffer) {
|
||||
public boolean setPosition(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
this.position.set((float) vector4i.x, (float) vector4i.y, (float) vector4i.z, (float) vector4i.w);
|
||||
this.position.mul(GLStateManager.getModelViewMatrix());
|
||||
vector4f.set((float) vector4i.x, (float) vector4i.y, (float) vector4i.z, (float) vector4i.w);
|
||||
return applyPosition(vector4f);
|
||||
}
|
||||
|
||||
public void setSpotDirection(FloatBuffer newBuffer) {
|
||||
// We are bypassing cache everytime for spot direction, because the necessary components to enable tracking the cache
|
||||
// are big and probably more than just bypassing. We would need to track the modelview matrix it was transformed
|
||||
// with and the untransformed coordinates in addition to the final transformation.
|
||||
GLStateManager.getModelViewMatrix().get3x3(matrix3f);
|
||||
this.spotDirection.set(newBuffer);
|
||||
this.spotDirection.mul(matrix3f);
|
||||
private boolean applyPosition(Vector4f raw) {
|
||||
final int mvGen = GLStateManager.mvGeneration;
|
||||
if (GLStateManager.shouldBypassCache() || this.posMvGeneration != mvGen || !this.rawPosition.equals(raw)) {
|
||||
this.rawPosition.set(raw);
|
||||
this.posMvGeneration = mvGen;
|
||||
this.position.set(raw);
|
||||
this.position.mul(GLStateManager.getModelViewMatrix());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpotDirection(IntBuffer newBuffer) {
|
||||
public boolean setSpotDirection(FloatBuffer newBuffer) {
|
||||
vector3f.set(newBuffer);
|
||||
return applySpotDirection(vector3f);
|
||||
}
|
||||
|
||||
public boolean setSpotDirection(IntBuffer newBuffer) {
|
||||
vector3i.set(newBuffer);
|
||||
GLStateManager.getModelViewMatrix().get3x3(matrix3f);
|
||||
this.spotDirection.set((float) vector3i.x, (float) vector3i.y, (float) vector3i.z);
|
||||
this.spotDirection.mul(matrix3f);
|
||||
vector3f.set((float) vector3i.x, (float) vector3i.y, (float) vector3i.z);
|
||||
return applySpotDirection(vector3f);
|
||||
}
|
||||
|
||||
public void setSpotExponent(FloatBuffer newBuffer) {
|
||||
setSpotExponent(newBuffer.get());
|
||||
private boolean applySpotDirection(Vector3f raw) {
|
||||
final int mvLinearGen = GLStateManager.mvLinearGeneration;
|
||||
if (GLStateManager.shouldBypassCache() || this.spotDirLinearGeneration != mvLinearGen || !this.rawSpotDirection.equals(raw)) {
|
||||
this.rawSpotDirection.set(raw);
|
||||
this.spotDirLinearGeneration = mvLinearGen;
|
||||
GLStateManager.getModelViewMatrix().get3x3(matrix3f);
|
||||
this.spotDirection.set(raw);
|
||||
this.spotDirection.mul(matrix3f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpotExponent(IntBuffer newBuffer) {
|
||||
setSpotExponent((float) newBuffer.get());
|
||||
public boolean setSpotExponent(FloatBuffer newBuffer) {
|
||||
return setSpotExponent(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setSpotExponent(int i) {
|
||||
setSpotExponent((float) i);
|
||||
public boolean setSpotExponent(IntBuffer newBuffer) {
|
||||
return setSpotExponent((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setSpotExponent(float f) {
|
||||
public boolean setSpotExponent(int i) {
|
||||
return setSpotExponent((float) i);
|
||||
}
|
||||
|
||||
public boolean setSpotExponent(float f) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(f, this.spotExponent) != 0) {
|
||||
this.spotExponent = f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpotCutoff(FloatBuffer newBuffer) {
|
||||
setSpotCutoff(newBuffer.get());
|
||||
public boolean setSpotCutoff(FloatBuffer newBuffer) {
|
||||
return setSpotCutoff(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setSpotCutoff(IntBuffer newBuffer) {
|
||||
setSpotCutoff((float) newBuffer.get());
|
||||
public boolean setSpotCutoff(IntBuffer newBuffer) {
|
||||
return setSpotCutoff((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setSpotCutoff(int i) {
|
||||
setSpotCutoff((float) i);
|
||||
public boolean setSpotCutoff(int i) {
|
||||
return setSpotCutoff((float) i);
|
||||
}
|
||||
|
||||
public void setSpotCutoff(float f) {
|
||||
public boolean setSpotCutoff(float f) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(f, this.spotCutoff) != 0) {
|
||||
this.spotCutoff = f;
|
||||
this.spotCosCutoff = (float) Math.cos(Math.toRadians(f));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setConstantAttenuation(FloatBuffer newBuffer) {
|
||||
setConstantAttenuation(newBuffer.get());
|
||||
public boolean setConstantAttenuation(FloatBuffer newBuffer) {
|
||||
return setConstantAttenuation(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setConstantAttenuation(IntBuffer newBuffer) {
|
||||
setConstantAttenuation((float) newBuffer.get());
|
||||
public boolean setConstantAttenuation(IntBuffer newBuffer) {
|
||||
return setConstantAttenuation((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setConstantAttenuation(int i) {
|
||||
setConstantAttenuation((float) i);
|
||||
public boolean setConstantAttenuation(int i) {
|
||||
return setConstantAttenuation((float) i);
|
||||
}
|
||||
|
||||
public void setConstantAttenuation(float f) {
|
||||
public boolean setConstantAttenuation(float f) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(f, this.constantAttenuation) != 0) {
|
||||
this.constantAttenuation = f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setLinearAttenuation(FloatBuffer newBuffer) {
|
||||
setLinearAttenuation(newBuffer.get());
|
||||
public boolean setLinearAttenuation(FloatBuffer newBuffer) {
|
||||
return setLinearAttenuation(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setLinearAttenuation(IntBuffer newBuffer) {
|
||||
setLinearAttenuation((float) newBuffer.get());
|
||||
public boolean setLinearAttenuation(IntBuffer newBuffer) {
|
||||
return setLinearAttenuation((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setLinearAttenuation(int i) {
|
||||
setLinearAttenuation((float) i);
|
||||
public boolean setLinearAttenuation(int i) {
|
||||
return setLinearAttenuation((float) i);
|
||||
}
|
||||
|
||||
public void setLinearAttenuation(float f) {
|
||||
public boolean setLinearAttenuation(float f) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(f, this.linearAttenuation) != 0) {
|
||||
this.linearAttenuation = f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setQuadraticAttenuation(FloatBuffer newBuffer) {
|
||||
setQuadraticAttenuation(newBuffer.get());
|
||||
public boolean setQuadraticAttenuation(FloatBuffer newBuffer) {
|
||||
return setQuadraticAttenuation(newBuffer.get());
|
||||
}
|
||||
|
||||
public void setQuadraticAttenuation(IntBuffer newBuffer) {
|
||||
setQuadraticAttenuation((float) newBuffer.get());
|
||||
public boolean setQuadraticAttenuation(IntBuffer newBuffer) {
|
||||
return setQuadraticAttenuation((float) newBuffer.get());
|
||||
}
|
||||
|
||||
public void setQuadraticAttenuation(int i) {
|
||||
setQuadraticAttenuation((float) i);
|
||||
public boolean setQuadraticAttenuation(int i) {
|
||||
return setQuadraticAttenuation((float) i);
|
||||
}
|
||||
|
||||
public void setQuadraticAttenuation(float f) {
|
||||
public boolean setQuadraticAttenuation(float f) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(f, this.quadraticAttenuation) != 0) {
|
||||
this.quadraticAttenuation = f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -246,7 +294,11 @@ public class LightState implements ISettableState<LightState> {
|
||||
this.diffuse.set(state.diffuse);
|
||||
this.specular.set(state.specular);
|
||||
this.position.set(state.position);
|
||||
this.rawPosition.set(state.rawPosition);
|
||||
this.posMvGeneration = state.posMvGeneration;
|
||||
this.spotDirection.set(state.spotDirection);
|
||||
this.rawSpotDirection.set(state.rawSpotDirection);
|
||||
this.spotDirLinearGeneration = state.spotDirLinearGeneration;
|
||||
this.spotExponent = state.spotExponent;
|
||||
this.spotCutoff = state.spotCutoff;
|
||||
this.spotCosCutoff = state.spotCosCutoff;
|
||||
|
||||
@@ -37,82 +37,100 @@ public class MaterialState implements ISettableState<MaterialState> {
|
||||
colorIndexes = new Vector3f(0.0F, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
public void setAmbient(FloatBuffer newBuffer) {
|
||||
public boolean setAmbient(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setAmbient(IntBuffer newBuffer) {
|
||||
public boolean setAmbient(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.ambient.equals(vector4f)) {
|
||||
this.ambient.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setDiffuse(FloatBuffer newBuffer) {
|
||||
public boolean setDiffuse(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.diffuse.equals(vector4f)) {
|
||||
this.diffuse.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setDiffuse(IntBuffer newBuffer) {
|
||||
public boolean setDiffuse(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.diffuse.equals(vector4f)) {
|
||||
this.diffuse.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpecular(FloatBuffer newBuffer) {
|
||||
public boolean setSpecular(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.specular.equals(vector4f)) {
|
||||
this.specular.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setSpecular(IntBuffer newBuffer) {
|
||||
public boolean setSpecular(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.specular.equals(vector4f)) {
|
||||
this.specular.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setEmission(FloatBuffer newBuffer) {
|
||||
public boolean setEmission(FloatBuffer newBuffer) {
|
||||
vector4f.set(newBuffer);
|
||||
if (GLStateManager.shouldBypassCache() || !this.emission.equals(vector4f)) {
|
||||
this.emission.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setEmission(IntBuffer newBuffer) {
|
||||
public boolean setEmission(IntBuffer newBuffer) {
|
||||
vector4i.set(newBuffer);
|
||||
vector4f.set(i2f(vector4i.x), i2f(vector4i.y), i2f(vector4i.z), i2f(vector4i.w));
|
||||
if (GLStateManager.shouldBypassCache() || !this.emission.equals(vector4f)) {
|
||||
this.emission.set(vector4f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setShininess(float val) {
|
||||
public boolean setShininess(float val) {
|
||||
if (GLStateManager.shouldBypassCache() || Float.compare(this.shininess, val) != 0) {
|
||||
this.shininess = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// On the buffer versions of shininess, we need to call `get(0)` explicitly specifying the index
|
||||
// otherwise calling `get()` advances the buffer position, and some mods may re-use the same buffer
|
||||
// in subsequent calls, resulting in a BufferUnderflowException.
|
||||
public void setShininess(FloatBuffer newBuffer) { setShininess(newBuffer.get(0)); }
|
||||
public boolean setShininess(FloatBuffer newBuffer) { return setShininess(newBuffer.get(0)); }
|
||||
|
||||
public void setShininess(IntBuffer newBuffer) { setShininess((float) newBuffer.get(0)); }
|
||||
public boolean setShininess(IntBuffer newBuffer) { return setShininess((float) newBuffer.get(0)); }
|
||||
|
||||
public void setShininess(int val) { setShininess((float) val);}
|
||||
public boolean setShininess(int val) { return setShininess((float) val);}
|
||||
|
||||
public void setColorIndexes(FloatBuffer newBuffer) {
|
||||
public boolean setColorIndexes(FloatBuffer newBuffer) {
|
||||
// You are reading this correctly, nvidia drivers flip the y and z values in
|
||||
// glMaterial specifically for GL_COLOR_INDEXES. Other drivers do not do this.
|
||||
// This probably breaks things but who knows, GLSM is setup to track to what the
|
||||
@@ -125,15 +143,19 @@ public class MaterialState implements ISettableState<MaterialState> {
|
||||
|
||||
if (GLStateManager.shouldBypassCache() || !this.colorIndexes.equals(vector3f)) {
|
||||
this.colorIndexes.set(vector3f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setColorIndexes(IntBuffer newBuffer) {
|
||||
public boolean setColorIndexes(IntBuffer newBuffer) {
|
||||
vector3i.set(newBuffer.get(0), newBuffer.get(2), newBuffer.get(1));
|
||||
vector3f.set((float) vector3i.x, (float) vector3i.y, (float) vector3i.z);
|
||||
if (GLStateManager.shouldBypassCache() || !this.colorIndexes.equals(vector3f)) {
|
||||
this.colorIndexes.set(vector3f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -68,7 +68,7 @@ class CompatUniformManagerTest {
|
||||
|
||||
// Use program and upload — should not error
|
||||
GL20.glUseProgram(program);
|
||||
CompatUniformManager.onUseProgram(program);
|
||||
CompatUniformManager.refreshCompatUniforms(program);
|
||||
|
||||
// Verify no GL errors
|
||||
assertEquals(0, org.lwjgl.opengl.GL11.glGetError(), "GL error after uniform upload");
|
||||
@@ -146,7 +146,7 @@ class CompatUniformManagerTest {
|
||||
|
||||
// Use program and upload — should not error
|
||||
GL20.glUseProgram(program);
|
||||
CompatUniformManager.onUseProgram(program);
|
||||
CompatUniformManager.refreshCompatUniforms(program);
|
||||
|
||||
assertEquals(0, org.lwjgl.opengl.GL11.glGetError(), "GL error after fog uniform upload");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import org.junit.jupiter.api.extension.AfterAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.DisplayMode;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
|
||||
/**
|
||||
* 3.3 core-profile context extension
|
||||
*/
|
||||
public class GLSMCoreExtension implements BeforeAllCallback, AfterAllCallback {
|
||||
private boolean ownsDisplay = false;
|
||||
|
||||
@Override
|
||||
public void beforeAll(ExtensionContext context) throws LWJGLException {
|
||||
if (Display.isCreated()) return;
|
||||
Display.setDisplayModeAndFullscreen(new DisplayMode(800, 600));
|
||||
Display.setResizable(false);
|
||||
Display.setFullscreen(false);
|
||||
Display.create(
|
||||
new PixelFormat().withDepthBits(24).withStencilBits(8),
|
||||
new ContextAttribs(3, 3).withProfileCore(true).withForwardCompatible(true));
|
||||
ownsDisplay = true;
|
||||
GLStateManager.initialize(GLSMInitConfig.builder().displaySize(800, 600).build());
|
||||
GLStateManager.setRunningSplash(false);
|
||||
GLStateManager.markSplashComplete();
|
||||
GLStateManager.BYPASS_CACHE = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAll(ExtensionContext context) {
|
||||
if (ownsDisplay && Display.isCreated()) Display.destroy();
|
||||
ownsDisplay = false;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
|
||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.Display;
|
||||
@@ -19,7 +21,19 @@ import java.lang.reflect.Field;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;
|
||||
|
||||
public class GLSMExtension implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback, ExtensionContext.Store.CloseableResource {
|
||||
public class GLSMExtension implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback, ExecutionCondition, ExtensionContext.Store.CloseableResource {
|
||||
|
||||
// Compat profile is not available on OSX
|
||||
private static final boolean IS_MAC = System.getProperty("os.name", "").toLowerCase().contains("mac");
|
||||
private static final boolean FORCE_RUN = Boolean.getBoolean("angelica.glsm.test.forceRun");
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
if (IS_MAC && !FORCE_RUN) {
|
||||
return ConditionEvaluationResult.disabled("Skipped on macOS: needs GL3+ compat profile");
|
||||
}
|
||||
return ConditionEvaluationResult.enabled("OS supports GL3+ compat profile");
|
||||
}
|
||||
|
||||
private static final Unsafe theUnsafe;
|
||||
static {
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.joml.Vector4f;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ExtendWith(GLSMCoreExtension.class)
|
||||
public class GLSM_DirtyTracking_UnitTest {
|
||||
|
||||
static final FloatBuffer f4b = ByteBuffer.allocateDirect(4 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
static final FloatBuffer f3b = ByteBuffer.allocateDirect(3 << 2).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
|
||||
@BeforeEach
|
||||
void pushTrackedState() {
|
||||
GLStateManager.glPushAttrib(GL11.GL_LIGHTING_BIT | GL11.GL_FOG_BIT | GL11.GL_CURRENT_BIT);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void popTrackedState() {
|
||||
GLStateManager.glPopAttrib();
|
||||
}
|
||||
|
||||
@Test
|
||||
void materialBumpsOnlyOnChange() {
|
||||
newf4b(0.1F, 0.2F, 0.3F, 0.4F);
|
||||
GLStateManager.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, f4b);
|
||||
final int gen = GLStateManager.lightingGeneration;
|
||||
|
||||
newf4b(0.1F, 0.2F, 0.3F, 0.4F);
|
||||
GLStateManager.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, f4b);
|
||||
assertEquals(gen, GLStateManager.lightingGeneration, "identical material must not bump lightingGeneration");
|
||||
|
||||
newf4b(0.9F, 0.2F, 0.3F, 0.4F);
|
||||
GLStateManager.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, f4b);
|
||||
assertEquals(gen + 1, GLStateManager.lightingGeneration, "changed material must bump lightingGeneration once");
|
||||
}
|
||||
|
||||
@Test
|
||||
void lightModelBumpsOnlyOnChange() {
|
||||
newf4b(0.5F, 0.5F, 0.5F, 1.0F);
|
||||
GLStateManager.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, f4b);
|
||||
final int gen = GLStateManager.lightingGeneration;
|
||||
|
||||
newf4b(0.5F, 0.5F, 0.5F, 1.0F);
|
||||
GLStateManager.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, f4b);
|
||||
assertEquals(gen, GLStateManager.lightingGeneration, "identical light model ambient must not bump");
|
||||
}
|
||||
|
||||
@Test
|
||||
void lightColorBumpsOnlyOnChange() {
|
||||
newf4b(0.25F, 0.5F, 0.75F, 1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, f4b);
|
||||
final int gen = GLStateManager.lightingGeneration;
|
||||
|
||||
newf4b(0.25F, 0.5F, 0.75F, 1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, f4b);
|
||||
assertEquals(gen, GLStateManager.lightingGeneration, "identical light diffuse must not bump");
|
||||
}
|
||||
|
||||
@Test
|
||||
void lightPositionDirtySkipsUnderSameModelview() {
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glLoadIdentity();
|
||||
GLStateManager.glTranslatef(1.0F, 2.0F, 3.0F);
|
||||
|
||||
newf4b(0.1F, 0.2F, 0.3F, 1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, f4b);
|
||||
final int gen = GLStateManager.lightingGeneration;
|
||||
|
||||
newf4b(0.1F, 0.2F, 0.3F, 1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, f4b);
|
||||
assertEquals(gen, GLStateManager.lightingGeneration, "same position under same modelview must not bump");
|
||||
|
||||
GLStateManager.glTranslatef(5.0F, 0.0F, 0.0F);
|
||||
newf4b(0.1F, 0.2F, 0.3F, 1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, f4b);
|
||||
assertEquals(gen + 1, GLStateManager.lightingGeneration, "same raw position under changed modelview must bump");
|
||||
|
||||
GLStateManager.glPopMatrix();
|
||||
}
|
||||
|
||||
@Test
|
||||
void translationDoesNotBumpLinearGeneration() {
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
|
||||
final int mv = GLStateManager.mvGeneration;
|
||||
final int lin = GLStateManager.mvLinearGeneration;
|
||||
|
||||
GLStateManager.glTranslatef(1.0F, 2.0F, 3.0F);
|
||||
assertEquals(mv + 1, GLStateManager.mvGeneration, "translate must bump mvGeneration");
|
||||
assertEquals(lin, GLStateManager.mvLinearGeneration, "translate must NOT bump mvLinearGeneration");
|
||||
|
||||
GLStateManager.glRotatef(30.0F, 0.0F, 1.0F, 0.0F);
|
||||
assertEquals(mv + 2, GLStateManager.mvGeneration, "rotate must bump mvGeneration");
|
||||
assertEquals(lin + 1, GLStateManager.mvLinearGeneration, "rotate must bump mvLinearGeneration");
|
||||
|
||||
GLStateManager.glScalef(2.0F, 2.0F, 2.0F);
|
||||
assertEquals(lin + 2, GLStateManager.mvLinearGeneration, "scale must bump mvLinearGeneration");
|
||||
|
||||
GLStateManager.glPopMatrix();
|
||||
}
|
||||
|
||||
@Test
|
||||
void fogBumpsOnlyOnChange() {
|
||||
GLStateManager.glFogf(GL11.GL_FOG_DENSITY, 0.5F);
|
||||
final int gen = GLStateManager.fragmentGeneration;
|
||||
|
||||
GLStateManager.glFogf(GL11.GL_FOG_DENSITY, 0.5F);
|
||||
assertEquals(gen, GLStateManager.fragmentGeneration, "identical fog density must not bump fragmentGeneration");
|
||||
|
||||
GLStateManager.glFogf(GL11.GL_FOG_DENSITY, 0.7F);
|
||||
assertEquals(gen + 1, GLStateManager.fragmentGeneration, "changed fog density must bump fragmentGeneration");
|
||||
}
|
||||
|
||||
@Test
|
||||
void spotDirectionDirtySkipsUnderTranslationOnly() {
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glLoadIdentity();
|
||||
|
||||
newf3b(0.0F, 0.0F, -1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_SPOT_DIRECTION, f3b);
|
||||
final int gen = GLStateManager.lightingGeneration;
|
||||
|
||||
GLStateManager.glTranslatef(5.0F, 0.0F, 0.0F);
|
||||
newf3b(0.0F, 0.0F, -1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_SPOT_DIRECTION, f3b);
|
||||
assertEquals(gen, GLStateManager.lightingGeneration, "spot direction under translation-only must not bump");
|
||||
|
||||
GLStateManager.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
|
||||
newf3b(0.0F, 0.0F, -1.0F);
|
||||
GLStateManager.glLight(GL11.GL_LIGHT0, GL11.GL_SPOT_DIRECTION, f3b);
|
||||
assertEquals(gen + 1, GLStateManager.lightingGeneration, "same raw spot direction under changed 3x3 must bump");
|
||||
|
||||
GLStateManager.glPopMatrix();
|
||||
}
|
||||
|
||||
@Test
|
||||
void colorMaterialFreezesLastColorOnDisable() {
|
||||
GLStateManager.glColorMaterial(GL11.GL_FRONT_AND_BACK, GL11.GL_AMBIENT_AND_DIFFUSE);
|
||||
GLStateManager.glColor4f(1.0F, 0.0F, 0.0F, 1.0F); // enable-time color
|
||||
GLStateManager.enableColorMaterial();
|
||||
GLStateManager.glColor4f(0.0F, 0.0F, 1.0F, 1.0F); // last color while enabled
|
||||
GLStateManager.disableColorMaterial();
|
||||
|
||||
final Vector4f diffuse = GLStateManager.getFrontMaterial().diffuse;
|
||||
assertEquals(0.0F, diffuse.x, "diffuse must freeze at last color (blue), not enable-time red");
|
||||
assertEquals(0.0F, diffuse.y, "green channel must be 0");
|
||||
assertEquals(1.0F, diffuse.z, "blue channel must be 1");
|
||||
}
|
||||
|
||||
static void newf4b(float x, float y, float z, float w) {
|
||||
f4b.clear();
|
||||
f4b.put(x).put(y).put(z).put(w);
|
||||
f4b.flip();
|
||||
}
|
||||
|
||||
static void newf3b(float x, float y, float z) {
|
||||
f3b.clear();
|
||||
f3b.put(x).put(y).put(z);
|
||||
f3b.flip();
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -45,9 +45,9 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testNonGenericUploadCachesWithoutRoundtrip() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertFalse(info.needsInternalFormatResolve());
|
||||
@@ -63,9 +63,9 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testGenericCompressedPreservesAsPassedInternalFormat() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertEquals(GL13.GL_COMPRESSED_RGBA, info.getInternalFormat());
|
||||
@@ -80,15 +80,15 @@ public class GLSM_TextureInfoCache_UnitTest {
|
||||
void testRepeatedQueryAfterResolveUsesCache() {
|
||||
int texId = GL11.glGenTextures();
|
||||
try {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, texId);
|
||||
ByteBuffer pixels = BufferUtils.createByteBuffer(64 * 64 * 4);
|
||||
GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
GLStateManager.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL13.GL_COMPRESSED_RGBA, 64, 64, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
TextureInfo info = TextureInfoCache.INSTANCE.getInfo(texId);
|
||||
assertTrue(info.needsInternalFormatResolve());
|
||||
int first = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
int first = GLStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
assertFalse(info.needsInternalFormatResolve());
|
||||
int second = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
int second = GLStateManager.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_INTERNAL_FORMAT);
|
||||
assertEquals(first, second);
|
||||
} finally {
|
||||
GL11.glDeleteTextures(texId);
|
||||
|
||||
@@ -21,6 +21,8 @@ class SharedDrawableVaoTest {
|
||||
private static final String VERT_330 = "#version 330 core\nvoid main() { gl_Position = vec4(0.0); }\n";
|
||||
private static final String FRAG_330 = "#version 330 core\nout vec4 o;\nvoid main() { o = vec4(0.0); }\n";
|
||||
|
||||
private static boolean ownsDisplay = false;
|
||||
|
||||
@BeforeAll
|
||||
static void createContext() throws LWJGLException {
|
||||
assumeTrue(!Display.isCreated(), "inherited Display -- skipping to avoid profile drift");
|
||||
@@ -31,11 +33,13 @@ class SharedDrawableVaoTest {
|
||||
new PixelFormat().withDepthBits(24).withStencilBits(8),
|
||||
new ContextAttribs(4, 1).withProfileCore(true).withForwardCompatible(true));
|
||||
GL30.glBindVertexArray(GL30.glGenVertexArrays());
|
||||
ownsDisplay = true;
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void destroyContext() {
|
||||
if (Display.isCreated()) Display.destroy();
|
||||
if (ownsDisplay && Display.isCreated()) Display.destroy();
|
||||
ownsDisplay = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+6
-6
@@ -28,7 +28,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
@Test
|
||||
void testGlColor4fSetsVertexAttrib() {
|
||||
GLStateManager.glColor4f(0.5f, 0.25f, 0.75f, 0.8f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
float[] color = getVertexAttrib4f(COLOR_ATTRIB);
|
||||
assertEquals(0.5f, color[0], EPSILON, "color.r");
|
||||
@@ -40,7 +40,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
@Test
|
||||
void testGlNormal3fSetsVertexAttrib() {
|
||||
GLStateManager.glNormal3f(0.0f, 1.0f, 0.0f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
float[] normal = getVertexAttrib4f(NORMAL_ATTRIB);
|
||||
assertEquals(0.0f, normal[0], EPSILON, "normal.x");
|
||||
@@ -51,7 +51,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
@Test
|
||||
void testSetLightmapTextureCoordsOnUnit1SetsVertexAttrib() {
|
||||
GLStateManager.setLightmapTextureCoords(GL13.GL_TEXTURE1, 240.0f, 128.0f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
float[] lm = getVertexAttrib4f(SECONDARY_UV_ATTRIB);
|
||||
assertEquals(240.0f, lm[0], EPSILON, "lightmap.s");
|
||||
@@ -64,7 +64,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
void testGlTexCoord2fSetsVertexAttrib() {
|
||||
// glTexCoord2f outside recording → sets default vertex attrib 2 (PRIMARY_UV)
|
||||
GLStateManager.glTexCoord2f(0.5f, 0.75f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
float[] uv = getVertexAttrib4f(PRIMARY_UV_ATTRIB);
|
||||
assertEquals(0.5f, uv[0], EPSILON, "texcoord.s");
|
||||
@@ -77,7 +77,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
// Second call is a cache hit — changeColor not called.
|
||||
// Vertex attrib should still hold the correct value from the first call.
|
||||
GLStateManager.glColor4f(0.3f, 0.6f, 0.9f, 1.0f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
float[] color = getVertexAttrib4f(COLOR_ATTRIB);
|
||||
assertEquals(0.3f, color[0], EPSILON, "color.r after dedup");
|
||||
@@ -89,7 +89,7 @@ class VertexAttribDefaultBridgeTest {
|
||||
@Test
|
||||
void testCompileMode_DoesNotSetVertexAttrib() {
|
||||
GLStateManager.glColor4f(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
GLStateManager.flushDeferredVertexAttribs();
|
||||
GLStateManager.flushDeferredVertexAttribs(0);
|
||||
|
||||
int listId = GLStateManager.glGenLists(1);
|
||||
GLStateManager.glNewList(listId, org.lwjgl.opengl.GL11.GL_COMPILE);
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.gtnewhorizons.angelica.glsm.ffp;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLSMCoreExtension;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@ExtendWith(GLSMCoreExtension.class)
|
||||
class ProgramUniformTrackingTest {
|
||||
|
||||
private static Program buildProgram(boolean hasColor) {
|
||||
final VertexKey vk = VertexKey.fromState(hasColor, false, false, false, 0);
|
||||
final FragmentKey fk = FragmentKey.fromState();
|
||||
return Program.create(vk, fk, VertexShaderGenerator.generate(vk), FragmentShaderGenerator.generate(fk), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void matrixTrackingIsPerProgram() {
|
||||
final Uniforms uniforms = new Uniforms();
|
||||
final Program a = buildProgram(true);
|
||||
final Program b = buildProgram(false);
|
||||
assertNotEquals(a.getProgramId(), b.getProgramId(), "distinct vertex keys must yield distinct programs");
|
||||
try {
|
||||
GLStateManager.glMatrixMode(GL11.GL_MODELVIEW);
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glLoadIdentity();
|
||||
|
||||
GLStateManager.glTranslatef(1.0F, 2.0F, 3.0F);
|
||||
final int genA = GLStateManager.mvGeneration;
|
||||
GL20.glUseProgram(a.getProgramId());
|
||||
uniforms.upload(a);
|
||||
assertEquals(genA, a.uploadState.mvGen, "A records the mv generation it uploaded");
|
||||
|
||||
GLStateManager.glTranslatef(4.0F, 0.0F, 0.0F);
|
||||
final int genB = GLStateManager.mvGeneration;
|
||||
assertNotEquals(genA, genB);
|
||||
GL20.glUseProgram(b.getProgramId());
|
||||
uniforms.upload(b);
|
||||
assertEquals(genB, b.uploadState.mvGen, "B records the new mv generation");
|
||||
assertEquals(genA, a.uploadState.mvGen, "A is unchanged -- tracking is per-program, not global");
|
||||
|
||||
// Return to A with the modelview still at genB: A is stale -> re-uploads and catches up.
|
||||
GL20.glUseProgram(a.getProgramId());
|
||||
uniforms.upload(a);
|
||||
assertEquals(genB, a.uploadState.mvGen, "A re-uploads on return and catches up to genB");
|
||||
|
||||
// Re-upload A with no change: gate (mvGeneration == A.mvGen) is satisfied -> skip.
|
||||
uniforms.upload(a);
|
||||
assertEquals(genB, a.uploadState.mvGen, "A already current -> skipped");
|
||||
|
||||
GLStateManager.glPopMatrix();
|
||||
} finally {
|
||||
GL20.glUseProgram(0);
|
||||
a.destroy();
|
||||
b.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
-1
@@ -23,6 +23,9 @@ import org.lwjgl.opengl.GL44C;
|
||||
import org.lwjgl.opengl.GL45C;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.opengl.GLDebugMessageCallback;
|
||||
import org.lwjgl.sdl.SDL_DropEvent;
|
||||
import org.lwjgl.sdl.SDL_EventFilter;
|
||||
import org.lwjgl.sdl.SDLEvents;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -31,6 +34,10 @@ import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* LWJGL3 GL implementation of {@link RenderBackend}.
|
||||
@@ -43,6 +50,10 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
private GLDebugMessageCallback debugCallback;
|
||||
private boolean debugOutputActive;
|
||||
|
||||
private SDL_EventFilter dropEventFilter;
|
||||
private final ConcurrentLinkedQueue<String> droppedFiles = new ConcurrentLinkedQueue<>();
|
||||
private volatile boolean watchingDrops;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
caps = GL.getCapabilities();
|
||||
@@ -50,7 +61,49 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
// no-op
|
||||
stopFileDrop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFileDrop() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startFileDrop() {
|
||||
if (watchingDrops) return;
|
||||
dropEventFilter = SDL_EventFilter.create((userData, eventPtr) -> {
|
||||
if (SDL_DropEvent.ntype(eventPtr) == SDLEvents.SDL_EVENT_DROP_FILE) {
|
||||
final String path = SDL_DropEvent.ndataString(eventPtr);
|
||||
if (path != null && !path.isEmpty()) {
|
||||
droppedFiles.add(path);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
SDLEvents.SDL_AddEventWatch(dropEventFilter, 0L);
|
||||
watchingDrops = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopFileDrop() {
|
||||
if (!watchingDrops) return;
|
||||
SDLEvents.SDL_RemoveEventWatch(dropEventFilter, 0L);
|
||||
dropEventFilter.free();
|
||||
dropEventFilter = null;
|
||||
droppedFiles.clear();
|
||||
watchingDrops = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> pollDroppedFiles() {
|
||||
if (droppedFiles.isEmpty()) return Collections.emptyList();
|
||||
final List<String> out = new ArrayList<>();
|
||||
String p;
|
||||
while ((p = droppedFiles.poll()) != null) {
|
||||
out.add(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhsettingsconvention") version ("2.0.24")
|
||||
id("com.gtnewhorizons.gtnhsettingsconvention") version ("2.0.25")
|
||||
}
|
||||
|
||||
include("glsm")
|
||||
|
||||
@@ -560,6 +560,9 @@ public class BatchingFontRenderer {
|
||||
boolean curWave = false;
|
||||
boolean curDinnerbone = false;
|
||||
boolean curGradient = false;
|
||||
boolean curShadow = false;
|
||||
boolean curShadowCustomColor = false;
|
||||
int curShadowColorOverride = 0;
|
||||
int gradientStartRgb = 0, gradientEndRgb = 0;
|
||||
int gradientCharIndex = 0, gradientTotalChars = 0;
|
||||
float gradientStep = 0f;
|
||||
@@ -651,6 +654,19 @@ public class BatchingFontRenderer {
|
||||
curWave = !curWave;
|
||||
} else if (fmtCode == 'v' && AngelicaConfig.enableDinnerboneText) {
|
||||
curDinnerbone = !curDinnerbone;
|
||||
} else if (fmtCode == 'u' && AngelicaConfig.enableDropShadow) {
|
||||
int customRgb = (charIdx + SECTION_X_LENGTH < stringEnd)
|
||||
? ColorCodeUtils.parseSectionXAt(string, charIdx + 1)
|
||||
: -1;
|
||||
if (customRgb != -1) {
|
||||
curShadow = true;
|
||||
curShadowCustomColor = true;
|
||||
curShadowColorOverride = customRgb;
|
||||
charIdx += SECTION_X_LENGTH;
|
||||
} else {
|
||||
curShadow = !curShadow;
|
||||
if (!curShadow) curShadowCustomColor = false;
|
||||
}
|
||||
} else if (fmtCode == 'g' && AngelicaConfig.enableGradients && charIdx + GRADIENT_PAYLOAD < stringEnd) {
|
||||
int color1 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1);
|
||||
int color2 = ColorCodeUtils.parseSectionXAt(string, charIdx + 1 + SECTION_X_LENGTH);
|
||||
@@ -674,6 +690,8 @@ public class BatchingFontRenderer {
|
||||
curWave = false;
|
||||
curDinnerbone = false;
|
||||
curGradient = false;
|
||||
curShadow = false;
|
||||
curShadowCustomColor = false;
|
||||
curColor = color;
|
||||
curShadowColor = shadowColor;
|
||||
}
|
||||
@@ -682,6 +700,8 @@ public class BatchingFontRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == ColorCodeUtils.ESCAPED_AMPERSAND) { chr = '&'; }
|
||||
|
||||
if (FontConfig.enableCustomFont && FontConfig.enableGlyphReplacements) {
|
||||
final char replacement = GlyphReplacements.getReplacementGlyph(chr);
|
||||
if (replacement != 0) {
|
||||
@@ -747,13 +767,17 @@ public class BatchingFontRenderer {
|
||||
renderY += (float) Math.sin(visibleCharIndex * WAVE_FREQUENCY + time) * AngelicaConfig.waveAmplitude;
|
||||
}
|
||||
|
||||
if (enableShadow) {
|
||||
final boolean drawShadow = enableShadow || curShadow;
|
||||
if (drawShadow) {
|
||||
final int effectiveShadowColor = curShadowCustomColor
|
||||
? ((curColor & 0xFF000000) | (curShadowColorOverride & 0x00FFFFFF))
|
||||
: curShadowColor;
|
||||
for (int n = 1; n <= shadowCopies; n++) {
|
||||
final float shadowOffsetPart = shadowOffset * ((float) n / shadowCopies);
|
||||
pushTexRect(curX + shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
pushTexRect(curX + shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, effectiveShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
|
||||
if (curBold) {
|
||||
pushTexRect(curX + 2.0f * shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
pushTexRect(curX + 2.0f * shadowOffsetPart, renderY + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, effectiveShadowColor, uStart, vStart, uSz, vSz, curDinnerbone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -775,7 +799,7 @@ public class BatchingFontRenderer {
|
||||
both: 4(1 + 2 * shadowCopies + boldCopies)
|
||||
*/
|
||||
int charCount = 1;
|
||||
if (enableShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
|
||||
if (drawShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
|
||||
if (curBold) { charCount += boldCopies; }
|
||||
final int vtxCount = 4 * charCount;
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
|
||||
@@ -822,6 +846,7 @@ public class BatchingFontRenderer {
|
||||
}
|
||||
|
||||
public float getCharWidthFine(char chr) {
|
||||
if (chr == ColorCodeUtils.ESCAPED_AMPERSAND) { chr = '&'; }
|
||||
if (chr == FORMATTING_CHAR) { return -1; }
|
||||
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class ColorCodeUtils {
|
||||
private ColorCodeUtils() {}
|
||||
|
||||
public static final char FORMATTING_CHAR = '§';
|
||||
public static final char ESCAPED_AMPERSAND = '';
|
||||
|
||||
public static final int SECTION_X_PAYLOAD = 12;
|
||||
public static final int SECTION_X_LENGTH = 14;
|
||||
@@ -25,7 +26,7 @@ public final class ColorCodeUtils {
|
||||
public static final int GRADIENT_LENGTH = 30;
|
||||
|
||||
/** Valid single {@code &} codes. {@code g} is excluded; {@code &g} only converts as part of a gradient. */
|
||||
public static final String VALID_SINGLE_CODES = "0123456789abcdefklmnorqzv";
|
||||
public static final String VALID_SINGLE_CODES = "0123456789abcdefklmnorqzvu";
|
||||
|
||||
private static final String[] SECTION_PREFIX = new String[128];
|
||||
static {
|
||||
@@ -87,6 +88,14 @@ public final class ColorCodeUtils {
|
||||
StringBuilder sb = null;
|
||||
int last = 0;
|
||||
while (idx != -1 && idx + 1 < len) {
|
||||
if (idx > 0 && text.charAt(idx - 1) == '\\') {
|
||||
if (sb == null) sb = new StringBuilder(len + 16);
|
||||
sb.append(text, last, idx - 1);
|
||||
sb.append(ESCAPED_AMPERSAND);
|
||||
last = idx + 1;
|
||||
idx = text.indexOf('&', last);
|
||||
continue;
|
||||
}
|
||||
if (text.charAt(idx + 1) == '#' && idx + 7 < len) {
|
||||
boolean validHex = true;
|
||||
for (int i = 2; i <= 7; i++) {
|
||||
|
||||
@@ -132,6 +132,10 @@ public class AngelicaConfig {
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableDinnerboneText;
|
||||
|
||||
@Config.Comment("Enable per-segment drop shadow toggle (&u) and colored shadow (&u&#RRGGBB)")
|
||||
@Config.DefaultBoolean(true)
|
||||
public static boolean enableDropShadow;
|
||||
|
||||
@Config.Comment("Wave text amplitude (how far characters bounce)")
|
||||
@Config.DefaultFloat(2.0f)
|
||||
@Config.RangeFloat(min = 1.0f, max = 8.0f)
|
||||
@@ -306,6 +310,16 @@ public class AngelicaConfig {
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public boolean narrowEars;
|
||||
|
||||
@Config.Comment("Narrow Fisk's Superheroes transformer exclusions to allow GL redirection")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public boolean narrowFiskHeroes;
|
||||
|
||||
@Config.Comment("Narrow FoamFix transformer exclusions to allow GL redirection in its repackaged Ears")
|
||||
@Config.DefaultBoolean(true)
|
||||
@Config.RequiresMcRestart
|
||||
public boolean narrowFoamFix;
|
||||
}
|
||||
|
||||
@Config.Comment("Renders chunks before neighbors are ready. Improves loading at render distance edges, useful for low render distance servers.")
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizons.angelica.event;
|
||||
|
||||
import net.minecraftforge.eventbus.api.bus.EventBus;
|
||||
import net.minecraftforge.eventbus.api.event.MutableEvent;
|
||||
|
||||
public final class ChunkBiomeDataChangedEvent extends MutableEvent {
|
||||
|
||||
public static final EventBus<ChunkBiomeDataChangedEvent> BUS = EventBus.create(ChunkBiomeDataChangedEvent.class);
|
||||
|
||||
private static final ChunkBiomeDataChangedEvent INSTANCE = new ChunkBiomeDataChangedEvent();
|
||||
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
|
||||
public static void post(int chunkX, int chunkZ) {
|
||||
if (!BUS.hasListeners()) return;
|
||||
INSTANCE.chunkX = chunkX;
|
||||
INSTANCE.chunkZ = chunkZ;
|
||||
BUS.post(INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.gtnewhorizons.angelica.event;
|
||||
|
||||
import net.minecraftforge.eventbus.api.bus.CancellableEventBus;
|
||||
import net.minecraftforge.eventbus.api.event.RecordEvent;
|
||||
import net.minecraftforge.eventbus.api.event.characteristic.Cancellable;
|
||||
|
||||
/**
|
||||
* Posted from {@link net.coderbot.iris.pipeline.HandRenderer}'s {@code canRender}
|
||||
* <p>
|
||||
* Cancel the event to prevent the hand from rendering.
|
||||
*/
|
||||
public record RenderHandEvent() implements RecordEvent, Cancellable {
|
||||
|
||||
public static final CancellableEventBus<RenderHandEvent> BUS = CancellableEventBus.create(RenderHandEvent.class);
|
||||
|
||||
private static final RenderHandEvent INSTANCE = new RenderHandEvent();
|
||||
|
||||
/**
|
||||
* @return true if a listener cancelled the event, meaning the hand should NOT render.
|
||||
*/
|
||||
public static boolean post() {
|
||||
if (!BUS.hasListeners()) return false;
|
||||
return BUS.post(INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class IrisGLSMBridge {
|
||||
private static Runnable fogStartListener = null;
|
||||
private static Runnable fogEndListener = null;
|
||||
private static Runnable fogDensityListener = null;
|
||||
private static Runnable colorModulatorListener = null;
|
||||
|
||||
static {
|
||||
StateUpdateNotifiers.alphaFuncNotifier = listener -> alphaFuncListener = listener;
|
||||
@@ -35,6 +36,7 @@ public class IrisGLSMBridge {
|
||||
StateUpdateNotifiers.fogStartNotifier = listener -> fogStartListener = listener;
|
||||
StateUpdateNotifiers.fogEndNotifier = listener -> fogEndListener = listener;
|
||||
StateUpdateNotifiers.fogDensityNotifier = listener -> fogDensityListener = listener;
|
||||
StateUpdateNotifiers.colorModulatorNotifier = listener -> colorModulatorListener = listener;
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
@@ -108,6 +110,10 @@ public class IrisGLSMBridge {
|
||||
}
|
||||
});
|
||||
|
||||
GLSMHooks.SHADER_COLOR_CHANGE.addListener(event -> {
|
||||
if (Iris.enabled && colorModulatorListener != null) colorModulatorListener.run();
|
||||
});
|
||||
|
||||
GLSMHooks.FOG_STATE_CHANGE.addListener(event -> {
|
||||
if (Iris.enabled) {
|
||||
if (fogModeListener != null) fogModeListener.run();
|
||||
@@ -157,17 +163,17 @@ public class IrisGLSMBridge {
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (event.postBind) return;
|
||||
|
||||
|
||||
final WorldRenderingPipeline pipeline = Iris.getPipelineManager().getPipelineNullable();
|
||||
if (!(pipeline instanceof DeferredWorldRenderingPipeline drp)) return;
|
||||
if (!drp.shouldOverrideShaders()) return;
|
||||
if (drp.getActivePassProgramId() == -1) return;
|
||||
|
||||
|
||||
if (DepthColorStorage.isOwnedProgram(event.newProgram)) {
|
||||
DepthColorStorage.unlockDepthColor();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
GLSMHooks.PROGRAM_CHANGE.addListener(event -> {
|
||||
if (!Iris.enabled) return;
|
||||
if (!event.postBind) return;
|
||||
|
||||
@@ -53,8 +53,15 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
Launch.classLoader.addTransformerExclusion("com.gtnewhorizons.angelica.loading");
|
||||
Launch.classLoader.addTransformerExclusion("com.gtnewhorizons.angelica.glsm.GLStateManager");
|
||||
|
||||
if (Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE) {
|
||||
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
|
||||
if (rfbLoaded) {
|
||||
addLwjgl3ifyExclusions();
|
||||
} else {
|
||||
// Fucking java 8 and non RFB
|
||||
try {
|
||||
Class.forName("com.gtnewhorizon.gtnhlib.core.GTNHLibCore", true, Launch.classLoader);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -84,7 +91,6 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
// packages to avoid interfering with mixin delegation on game classes. AngelicaLateTweaker removes this registration once
|
||||
// mixins are setup.
|
||||
if (FMLLaunchHandler.side().isClient()) {
|
||||
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
|
||||
if (!rfbLoaded) {
|
||||
final String transformer = "com.gtnewhorizons.angelica.loading.fml.transformers.EarlyRedirectorTransformer";
|
||||
FMLRelaunchLog.finer("Registering transformer %s", transformer);
|
||||
@@ -180,6 +186,8 @@ public final class AngelicaClientTweaker implements IFMLLoadingPlugin, IEarlyMix
|
||||
narrowTransformerConfig("AdvancedLightsabers", AngelicaConfig.transformerCompat.narrowAdvancedLightsabers);
|
||||
narrowTransformerConfig("Alfheim", AngelicaConfig.transformerCompat.narrowAlfheim);
|
||||
narrowTransformerConfig("Ears", AngelicaConfig.transformerCompat.narrowEars);
|
||||
narrowTransformerConfig("FiskHeroes", AngelicaConfig.transformerCompat.narrowFiskHeroes);
|
||||
narrowTransformerConfig("FoamFix", AngelicaConfig.transformerCompat.narrowFoamFix);
|
||||
|
||||
tweaks.add("com.gtnewhorizons.angelica.loading.fml.tweakers.IncompatibleModsDisablerTweaker");
|
||||
if (AngelicaConfig.enableHudCaching) {
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ public class CeleritasBlockTransformer implements IClassTransformer {
|
||||
public CeleritasBlockTransformer() {
|
||||
this.inner = new CeleritasBlockTransform(AngelicaClientTweaker.isObfEnv());
|
||||
this.exclusions = inner.getTransformerExclusions();
|
||||
this.inner.setCeleritasSetting();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-2
@@ -52,12 +52,20 @@ public class RFBAngelicaRedirector implements RfbClassTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
public boolean transformClassIfNeeded(@NotNull ExtensibleClassLoader classLoader,
|
||||
@NotNull RfbClassTransformer.Context context, @Nullable Manifest manifest,
|
||||
@NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
final boolean changed = inner.transformClassNode(className, classNode.getNode());
|
||||
if (changed) {
|
||||
classNode.computeMaxs();
|
||||
AngelicaClassDump.dumpRFBClass(className, classNode, this);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
transformClassIfNeeded(classLoader, context, manifest, className, classNode);
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -59,12 +59,20 @@ public class RFBCeleritasBlockTransformer implements RfbClassTransformer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
public boolean transformClassIfNeeded(@NotNull ExtensibleClassLoader classLoader,
|
||||
@NotNull RfbClassTransformer.Context context, @Nullable Manifest manifest,
|
||||
@NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
final boolean changed = inner.transformClassNode(className, classNode.getNode());
|
||||
if (changed) {
|
||||
classNode.computeMaxs();
|
||||
AngelicaClassDump.dumpRFBClass(className, classNode, this);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
transformClassIfNeeded(classLoader, context, manifest, className, classNode);
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -49,11 +49,19 @@ public class RFBIsbrhTessellatorAbuseTransformer implements RfbClassTransformer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
public boolean transformClassIfNeeded(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
if (inner.transformClassNode(classNode.getNode(), this.isObf)) {
|
||||
final boolean changed = inner.transformClassNode(classNode.getNode(), this.isObf);
|
||||
if (changed) {
|
||||
classNode.computeMaxs();
|
||||
AngelicaClassDump.dumpRFBClass(className, classNode, this);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
|
||||
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
|
||||
transformClassIfNeeded(classLoader, context, manifest, className, classNode);
|
||||
}
|
||||
}
|
||||
+30
-34
@@ -31,16 +31,21 @@ public final class CeleritasBlockTransform implements Opcodes {
|
||||
private static final Logger LOGGER = LogManager.getLogger("CeleritasBlockTransformer");
|
||||
private static final String BlockClass = "net/minecraft/block/Block";
|
||||
private static final String ThreadedBlockData = "com/gtnewhorizons/angelica/client/rendering/ThreadedBlockData";
|
||||
/** All classes under <tt>net.minecraft.block.Block*</tt> are Block subclasses save for these. */
|
||||
private static final String[] VanillaBlockExclusions = {
|
||||
"net/minecraft/block/IGrowable",
|
||||
"net/minecraft/block/ITileEntityProvider",
|
||||
"net/minecraft/block/BlockEventData",
|
||||
"net/minecraft/block/BlockSourceImpl",
|
||||
"net/minecraft/block/material/"
|
||||
};
|
||||
|
||||
private final Map<String, String> fieldNameToRedirect = new HashMap<>();
|
||||
private final Set<String> blockSubclasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private final Set<String> moddedBlockSubclasses = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
// Block subclass owners we shouldn't redirect because they shadow some fields we want to redirect
|
||||
private final Set<String> blockSubclassExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private final ClassConstantPoolParser cstPoolParser;
|
||||
|
||||
private final MethodHandle celeritasEnabledGetter;
|
||||
private boolean isCeleritasEnabled;
|
||||
|
||||
public CeleritasBlockTransform(boolean isObf) {
|
||||
final List<Pair<String, String>> mappings = ImmutableList.of(
|
||||
Pair.of("minX", "field_149759_B"),
|
||||
@@ -56,37 +61,30 @@ public final class CeleritasBlockTransform implements Opcodes {
|
||||
}
|
||||
|
||||
this.cstPoolParser = new ClassConstantPoolParser(this.fieldNameToRedirect.keySet().toArray(new String[0]));
|
||||
}
|
||||
|
||||
blockSubclasses.add(BlockClass);
|
||||
|
||||
try {
|
||||
// Needed because the config is loaded in LaunchClassLoader, but we need to access it in the parent system loader.
|
||||
final Class<?> angelicaConfig = Class.forName("com.gtnewhorizons.angelica.config.AngelicaConfig", true, Launch.classLoader);
|
||||
celeritasEnabledGetter = MethodHandles.lookup().findStaticGetter(angelicaConfig, "enableCeleritas", boolean.class);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
private boolean isVanillaBlockSubclass(String className) {
|
||||
if (!className.startsWith(BlockClass)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCeleritasSetting() {
|
||||
isCeleritasEnabled = true;
|
||||
}
|
||||
|
||||
private boolean isCeleritasEnabled() {
|
||||
if (isCeleritasEnabled) return true;
|
||||
try {
|
||||
return (boolean) celeritasEnabledGetter.invokeExact();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException(e);
|
||||
for (String exclusion : VanillaBlockExclusions) {
|
||||
if (className.startsWith(exclusion)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method needs to be called for every class, including the ones we don't want to transform
|
||||
private boolean isBlockSubclass(String className) {
|
||||
return isVanillaBlockSubclass(className) || moddedBlockSubclasses.contains(className);
|
||||
}
|
||||
|
||||
// This method needs to be called for every class, including the ones we don't want to transform.
|
||||
// Vanilla blocks are recognized by name; only modded subclasses need tracking, and FML's
|
||||
// EventSubscriptionTransformer guarantees a modded class's superclass loads first.
|
||||
public void trackBlockSubclasses(String className, String superClassName) {
|
||||
// It works because the deepest subclasses are always transformed first due to
|
||||
// ForgeEventTransformer recursive superclass loading
|
||||
if (blockSubclasses.contains(superClassName)) {
|
||||
blockSubclasses.add(className);
|
||||
if (!isVanillaBlockSubclass(className) && isBlockSubclass(superClassName)) {
|
||||
moddedBlockSubclasses.add(className);
|
||||
|
||||
if (blockSubclassExclusions.contains(superClassName)) {
|
||||
LOGGER.info("Class {} extends a class with shadowed block bounds fields and will be skipped from redirecting", className);
|
||||
@@ -110,9 +108,6 @@ public final class CeleritasBlockTransform implements Opcodes {
|
||||
|
||||
/** @return Was the class changed? */
|
||||
public boolean transformClassNode(String transformedName, ClassNode cn) {
|
||||
if (!isCeleritasEnabled()) {
|
||||
return false;
|
||||
}
|
||||
boolean changed = false;
|
||||
if (BlockClass.equals(cn.name)) {
|
||||
changed = cn.fields.removeIf(field -> fieldNameToRedirect.containsKey(field.name));
|
||||
@@ -124,7 +119,8 @@ public final class CeleritasBlockTransform implements Opcodes {
|
||||
}
|
||||
|
||||
private void trackBlockShadowingFields(ClassNode cn) {
|
||||
if (blockSubclasses.contains(cn.name)) {
|
||||
// Only modded subclasses can shadow; vanilla declares these fields solely in Block.
|
||||
if (moddedBlockSubclasses.contains(cn.name)) {
|
||||
for (FieldNode field : cn.fields) {
|
||||
if (fieldNameToRedirect.containsKey(field.name)) {
|
||||
LOGGER.info("Class '{}' shadows one or more block bounds fields, these accesses won't be redirected!", cn.name);
|
||||
@@ -141,7 +137,7 @@ public final class CeleritasBlockTransform implements Opcodes {
|
||||
for (AbstractInsnNode node = mn.instructions.getFirst(); node != null; node = node.getNext()) {
|
||||
if ((node.getOpcode() == GETFIELD || node.getOpcode() == PUTFIELD) && node instanceof FieldInsnNode fNode) {
|
||||
String newFieldName = fieldNameToRedirect.get(fNode.name);
|
||||
if (newFieldName != null && blockSubclasses.contains(fNode.owner) && !blockSubclassExclusions.contains(fNode.owner)) {
|
||||
if (newFieldName != null && isBlockSubclass(fNode.owner) && !blockSubclassExclusions.contains(fNode.owner)) {
|
||||
if (LOG_SPAM) {
|
||||
LOGGER.info("Redirecting Block.{} in {} to thread-safe wrapper", fNode.name, transformedName);
|
||||
}
|
||||
|
||||
@@ -329,6 +329,15 @@ public enum Mixins implements IMixins {
|
||||
)
|
||||
),
|
||||
|
||||
IRIS_SHADERS_CHISEL_BEACON(new MixinBuilder("Iris Chisel Beacon Beam")
|
||||
.setPhase(Phase.LATE)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris)
|
||||
.addRequiredMod(TargetedMod.CHISEL)
|
||||
.addClientMixins(
|
||||
"chisel.MixinRenderCarvableBeacon"
|
||||
)
|
||||
),
|
||||
|
||||
ANGELICA_TEXTURE(new MixinBuilder()
|
||||
.setPhase(Phase.EARLY)
|
||||
.setApplyIf(() -> AngelicaConfig.enableIris || AngelicaConfig.enableCeleritas)
|
||||
|
||||
@@ -10,6 +10,7 @@ public enum TargetedMod implements ITargetMod {
|
||||
ARCHAICFIX("org.embeddedt.archaicfix.ArchaicCore", "archaicfix"),
|
||||
BACKHAND("xonin.backhand.coremod.BackhandLoadingPlugin", "backhand"),
|
||||
CAMPFIRE_BACKPORT(null, "campfirebackport"),
|
||||
CHISEL(null, "chisel"),
|
||||
COFHCORE( "cofh.asm.LoadingPlugin", "CoFHCore"),
|
||||
DYNAMIC_SURROUNDINGS_MIST("org.blockartistry.mod.DynSurround.mixinplugin.DynamicSurroundingsEarlyMixins", "dsurround"),
|
||||
DYNAMIC_SURROUNDINGS_ORIGINAL("org.blockartistry.mod.DynSurround.asm.TransformLoader", "dsurround"),
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
final class CloudEdges {
|
||||
private static final int CELL_EMPTY_THRESHOLD = 10;
|
||||
|
||||
final int width, height;
|
||||
private final int wMask, hMask;
|
||||
private final boolean whPow2;
|
||||
private final long[] opaqueBits;
|
||||
final int opaqueCount;
|
||||
|
||||
CloudEdges(int width, int height, ByteBuffer rgba) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.wMask = width - 1;
|
||||
this.hMask = height - 1;
|
||||
this.whPow2 = (width & wMask) == 0 && (height & hMask) == 0;
|
||||
final int total = width * height;
|
||||
final long[] bits = new long[(total + 63) >>> 6];
|
||||
int op = 0;
|
||||
for (int i = 0; i < total; i++) {
|
||||
if ((rgba.get(i * 4 + 3) & 0xFF) >= CELL_EMPTY_THRESHOLD) {
|
||||
bits[i >>> 6] |= 1L << (i & 63);
|
||||
op++;
|
||||
}
|
||||
}
|
||||
this.opaqueBits = bits;
|
||||
this.opaqueCount = op;
|
||||
}
|
||||
|
||||
boolean cellOpaque(int x, int z) {
|
||||
final int xw, zh;
|
||||
if (whPow2) {
|
||||
xw = x & wMask;
|
||||
zh = z & hMask;
|
||||
} else {
|
||||
xw = Math.floorMod(x, width);
|
||||
zh = Math.floorMod(z, height);
|
||||
}
|
||||
final int idx = xw + zh * width;
|
||||
return ((opaqueBits[idx >>> 6] >>> (idx & 63)) & 1L) != 0L;
|
||||
}
|
||||
|
||||
long readOpaqueRowBits(int x0, int z) {
|
||||
final int zMod, x0Mod;
|
||||
if (whPow2) {
|
||||
zMod = z & hMask;
|
||||
x0Mod = x0 & wMask;
|
||||
} else {
|
||||
zMod = Math.floorMod(z, height);
|
||||
x0Mod = Math.floorMod(x0, width);
|
||||
}
|
||||
if (x0Mod + 10 <= width) {
|
||||
return readContigBits(opaqueBits, (long) zMod * width + x0Mod, 10);
|
||||
}
|
||||
final int colsBeforeWrap = width - x0Mod;
|
||||
final long firstPart = readContigBits(opaqueBits, (long) zMod * width + x0Mod, colsBeforeWrap);
|
||||
final long secondPart = readContigBits(opaqueBits, (long) zMod * width, 10 - colsBeforeWrap);
|
||||
return firstPart | (secondPart << colsBeforeWrap);
|
||||
}
|
||||
|
||||
private static long readContigBits(long[] bits, long startBitIdx, int count) {
|
||||
final int wordIdx = (int) (startBitIdx >>> 6);
|
||||
final int bitOff = (int) (startBitIdx & 63);
|
||||
final long mask = count == 64 ? -1L : (1L << count) - 1L;
|
||||
final long w0 = bits[wordIdx];
|
||||
if (bitOff + count <= 64) {
|
||||
return (w0 >>> bitOff) & mask;
|
||||
}
|
||||
final long w1 = bits[wordIdx + 1];
|
||||
return ((w0 >>> bitOff) | (w1 << (64 - bitOff))) & mask;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,78 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderBindingContext;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat4v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformInt;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformMatrix4f;
|
||||
|
||||
final class CloudUniforms {
|
||||
static final float ALPHA = 0.8f;
|
||||
|
||||
final GlUniformMatrix4f mvp;
|
||||
final GlUniformFloat4v colorMult;
|
||||
final GlUniformFloat4v fogParams;
|
||||
final GlUniformFloat4v fogColor;
|
||||
final GlUniformInt fogEnabled;
|
||||
final GlUniformInt tex;
|
||||
|
||||
private int lastFogEnabled = -1;
|
||||
private float lastFogR = Float.NaN, lastFogG = Float.NaN, lastFogB = Float.NaN;
|
||||
private float lastColorR = Float.NaN, lastColorG = Float.NaN, lastColorB = Float.NaN;
|
||||
private float lastFogParamX = Float.NaN, lastFogParamY = Float.NaN;
|
||||
private final float[] uploadBuf = new float[4];
|
||||
|
||||
CloudUniforms(ShaderBindingContext ctx) {
|
||||
mvp = ctx.bindUniform("u_MVPMatrix", GlUniformMatrix4f::new);
|
||||
colorMult = ctx.bindUniform("u_ColorMult", GlUniformFloat4v::new);
|
||||
fogParams = ctx.bindUniform("u_FogParams", GlUniformFloat4v::new);
|
||||
fogColor = ctx.bindUniform("u_FogColor", GlUniformFloat4v::new);
|
||||
fogEnabled = ctx.bindUniform("u_FogEnabled", GlUniformInt::new);
|
||||
tex = ctx.bindUniform("u_Tex", GlUniformInt::new);
|
||||
}
|
||||
|
||||
void setFogEnabled(boolean enabled) {
|
||||
final int val = enabled ? 1 : 0;
|
||||
if (val != lastFogEnabled) {
|
||||
lastFogEnabled = val;
|
||||
fogEnabled.setInt(val);
|
||||
}
|
||||
}
|
||||
|
||||
void setFogColor(float r, float g, float b) {
|
||||
if (r != lastFogR || g != lastFogG || b != lastFogB) {
|
||||
lastFogR = r;
|
||||
lastFogG = g;
|
||||
lastFogB = b;
|
||||
uploadBuf[0] = r;
|
||||
uploadBuf[1] = g;
|
||||
uploadBuf[2] = b;
|
||||
uploadBuf[3] = 1.0f;
|
||||
fogColor.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void setFogParams(float x, float y) {
|
||||
if (x != lastFogParamX || y != lastFogParamY) {
|
||||
lastFogParamX = x;
|
||||
lastFogParamY = y;
|
||||
uploadBuf[0] = x;
|
||||
uploadBuf[1] = y;
|
||||
uploadBuf[2] = 0f;
|
||||
uploadBuf[3] = 0f;
|
||||
fogParams.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
|
||||
void setColorMult(float r, float g, float b) {
|
||||
if (r != lastColorR || g != lastColorG || b != lastColorB) {
|
||||
lastColorR = r;
|
||||
lastColorG = g;
|
||||
lastColorB = b;
|
||||
uploadBuf[0] = r;
|
||||
uploadBuf[1] = g;
|
||||
uploadBuf[2] = b;
|
||||
uploadBuf[3] = ALPHA;
|
||||
colorMult.set(uploadBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,10 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.resources.FallbackResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
@@ -50,8 +54,23 @@ public class EmissiveTextureAutoloader {
|
||||
loc.getResourceDomain(),
|
||||
"textures/blocks/" + loc.getResourcePath() + ".png"
|
||||
);
|
||||
|
||||
final IResourceManager resMan = Minecraft.getMinecraft().getResourceManager();
|
||||
if (resMan instanceof SimpleReloadableResourceManager simple) {
|
||||
FallbackResourceManager fallback = simple.domainResourceManagers.get(full.getResourceDomain());
|
||||
if (fallback != null) {
|
||||
for (IResourcePack rp : fallback.resourcePacks) {
|
||||
if (rp != null && rp.resourceExists(full)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
try {
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(full);
|
||||
resMan.getResource(full);
|
||||
return true;
|
||||
} catch (Exception ignored) {
|
||||
return false;
|
||||
|
||||
@@ -1,28 +1,45 @@
|
||||
package com.gtnewhorizons.angelica.render;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.IVertexArrayObject;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vao.VertexBufferType;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.client.rendering.GlUniformFloat2v;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.GlProgram;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.GlShader;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderConstants;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.ShaderType;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat3v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformFloat4v;
|
||||
import org.embeddedt.embeddium.impl.gl.shader.uniform.GlUniformMatrix4f;
|
||||
import org.embeddedt.embeddium.impl.render.shader.ShaderLoader;
|
||||
import org.joml.Matrix4f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public final class SelectionBoxRenderer {
|
||||
|
||||
private static GlProgram<SelectionBoxUniforms> program;
|
||||
private static int emptyVao;
|
||||
private static IVertexArrayObject vao;
|
||||
private static final Matrix4f mvpMatrix = new Matrix4f();
|
||||
private static final float[] colorBuf = new float[4];
|
||||
|
||||
private static final int VERT_COUNT = 24;
|
||||
private static final float[] UNIT_EDGES = {
|
||||
0,0,0, 1,0,0, 1,0,0, 1,0,1,
|
||||
1,0,1, 0,0,1, 0,0,1, 0,0,0,
|
||||
0,1,0, 1,1,0, 1,1,0, 1,1,1,
|
||||
1,1,1, 0,1,1, 0,1,1, 0,1,0,
|
||||
0,0,0, 0,1,0, 1,0,0, 1,1,0,
|
||||
1,0,1, 1,1,1, 0,0,1, 0,1,1
|
||||
};
|
||||
|
||||
private SelectionBoxRenderer() {}
|
||||
|
||||
public static void init() {
|
||||
@@ -40,8 +57,6 @@ public final class SelectionBoxRenderer {
|
||||
|
||||
program = builder.link(ctx -> new SelectionBoxUniforms(
|
||||
ctx.bindUniform("u_MVP", GlUniformMatrix4f::new),
|
||||
ctx.bindUniform("u_Min", GlUniformFloat3v::new),
|
||||
ctx.bindUniform("u_Max", GlUniformFloat3v::new),
|
||||
ctx.bindUniform("u_Color", GlUniformFloat4v::new),
|
||||
needsGS ? ctx.bindUniform("u_ViewportSize", GlUniformFloat2v::new) : null,
|
||||
needsGS ? ctx.bindUniform("u_LineWidth", GlUniformFloat::new) : null));
|
||||
@@ -50,20 +65,34 @@ public final class SelectionBoxRenderer {
|
||||
fs.destroy();
|
||||
if (gs != null) gs.destroy();
|
||||
|
||||
emptyVao = GLStateManager.glGenVertexArrays();
|
||||
final ByteBuffer buf = BufferUtils.createByteBuffer(UNIT_EDGES.length * Float.BYTES);
|
||||
buf.asFloatBuffer().put(UNIT_EDGES);
|
||||
vao = VertexBufferType.IMMUTABLE.allocate(DefaultVertexFormat.POSITION, GL11.GL_LINES, buf, VERT_COUNT);
|
||||
}
|
||||
|
||||
public static void draw(AxisAlignedBB aabb, int color) {
|
||||
if (program == null) return;
|
||||
if (program == null || vao == null) return;
|
||||
|
||||
final float minX = (float) aabb.minX, minY = (float) aabb.minY, minZ = (float) aabb.minZ;
|
||||
final float extX = (float) (aabb.maxX - aabb.minX);
|
||||
final float extY = (float) (aabb.maxY - aabb.minY);
|
||||
final float extZ = (float) (aabb.maxZ - aabb.minZ);
|
||||
|
||||
if (AngelicaConfig.enableIris && IrisApi.getInstance().isShaderPackInUse()) {
|
||||
drawThroughShader(minX, minY, minZ, extX, extY, extZ, color);
|
||||
} else {
|
||||
drawFast(minX, minY, minZ, extX, extY, extZ, color);
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawFast(float minX, float minY, float minZ, float extX, float extY, float extZ, int color) {
|
||||
final SelectionBoxUniforms uniforms = program.getInterface();
|
||||
|
||||
program.bind();
|
||||
|
||||
GLStateManager.getProjectionMatrix().mul(GLStateManager.getModelViewMatrix(), mvpMatrix);
|
||||
mvpMatrix.translate(minX, minY, minZ).scale(extX, extY, extZ);
|
||||
uniforms.mvp.set(mvpMatrix);
|
||||
uniforms.min.set((float) aabb.minX, (float) aabb.minY, (float) aabb.minZ);
|
||||
uniforms.max.set((float) aabb.maxX, (float) aabb.maxY, (float) aabb.maxZ);
|
||||
|
||||
if (color != -1) {
|
||||
colorBuf[0] = ((color >> 16) & 0xFF) / 255.0f;
|
||||
@@ -84,25 +113,42 @@ public final class SelectionBoxRenderer {
|
||||
uniforms.lineWidth.setFloat(GLStateManager.getLineState().getWidth());
|
||||
}
|
||||
|
||||
GLStateManager.glBindVertexArray(emptyVao);
|
||||
GLStateManager.glDrawArrays(GL11.GL_LINES, 0, 24);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
vao.render();
|
||||
|
||||
program.unbind();
|
||||
}
|
||||
|
||||
private static void drawThroughShader(float minX, float minY, float minZ, float extX, float extY, float extZ, int color) {
|
||||
GLStateManager.glPushMatrix();
|
||||
GLStateManager.glTranslatef(minX, minY, minZ);
|
||||
GLStateManager.glScalef(extX, extY, extZ);
|
||||
|
||||
final Color4 prev = GLStateManager.getColor();
|
||||
final boolean overrideColor = color != -1;
|
||||
if (overrideColor) {
|
||||
GLStateManager.glColor4f(((color >> 16) & 0xFF) / 255.0f, ((color >> 8) & 0xFF) / 255.0f, (color & 0xFF) / 255.0f, 1.0f);
|
||||
}
|
||||
|
||||
vao.render();
|
||||
|
||||
if (overrideColor) {
|
||||
GLStateManager.glColor4f(prev.getRed(), prev.getGreen(), prev.getBlue(), prev.getAlpha());
|
||||
}
|
||||
GLStateManager.glPopMatrix();
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
if (program != null) {
|
||||
program.destroy();
|
||||
program = null;
|
||||
}
|
||||
if (emptyVao != 0) {
|
||||
GLStateManager.glDeleteVertexArrays(emptyVao);
|
||||
emptyVao = 0;
|
||||
if (vao != null) {
|
||||
vao.delete();
|
||||
vao = null;
|
||||
}
|
||||
}
|
||||
|
||||
private record SelectionBoxUniforms(GlUniformMatrix4f mvp, GlUniformFloat3v min, GlUniformFloat3v max, GlUniformFloat4v color, GlUniformFloat2v viewportSize, GlUniformFloat lineWidth) {
|
||||
private record SelectionBoxUniforms(GlUniformMatrix4f mvp, GlUniformFloat4v color, GlUniformFloat2v viewportSize, GlUniformFloat lineWidth) {
|
||||
|
||||
}
|
||||
}
|
||||
+14
@@ -14,6 +14,7 @@ import com.gtnewhorizons.angelica.rendering.celeritas.light.VanillaDiffuseProvid
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.WorldSlice;
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.vertices.ExtendedDataHelper;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
@@ -184,6 +185,8 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
animatedSprites.add(sprite);
|
||||
}
|
||||
|
||||
final boolean isFluid = blockRenderContext.renderType == ExtendedDataHelper.FLUID_RENDER_TYPE;
|
||||
|
||||
// If block used vanilla AO, then we can safely compute our own lighting data and ignore what vanilla
|
||||
// computed. We suppress vanilla emitting the brightness/color in MixinRenderBlocks.
|
||||
// Otherwise, we need to use the block's lightmap values as they are as the ISBRH may have
|
||||
@@ -213,6 +216,17 @@ public class AngelicaChunkBuildContext extends ChunkBuildContext {
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
vertices[vIdx].trueNormal = trueNormal;
|
||||
}
|
||||
|
||||
if (useAoCalculation && isFluid) {
|
||||
quadView.setup(trueNormal, blockX, blockY, blockZ);
|
||||
final ModelQuadFacing lightFace = quadView.getLightFace();
|
||||
final LightPipeline pipeline = blockAllowsSmoothLighting ? smoothLightPipeline : flatLightPipeline;
|
||||
final ModelQuadFacing cullFace = quadView.getCullFace();
|
||||
pipeline.calculate(quadView, worldX, worldY, worldZ, quadLightData, cullFace, lightFace, shouldApplyDiffuse, true);
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
vertices[vIdx].light = quadLightData.lm[vIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply dynamic lights after AO calculation so they're not overwritten
|
||||
|
||||
+4
-1
@@ -15,6 +15,7 @@ import net.coderbot.iris.block_rendering.BlockRenderingSettings;
|
||||
import net.coderbot.iris.block_rendering.NbtConditionalIdMap;
|
||||
import net.coderbot.iris.vertices.ExtendedDataHelper;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockDoublePlant;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
@@ -268,13 +269,15 @@ public abstract class AngelicaChunkBuilderMeshingTask extends ChunkBuilderTask<C
|
||||
if (contextEncoder != null) {
|
||||
final byte lightValue = (byte) block.getLightValue();
|
||||
if (isFluid) {
|
||||
contextEncoder.prepareToRenderFluid(blockRenderContext, block, lightValue);
|
||||
contextEncoder.prepareToRenderFluid(blockRenderContext, block, metadata, lightValue);
|
||||
} else {
|
||||
int effectiveMeta = metadata;
|
||||
if (BlockRenderingSettings.INSTANCE.hasSnowyEntries()
|
||||
&& BlockRenderingSettings.INSTANCE.getSnowyBlocks().contains(block)
|
||||
&& RenderBlocksUtils.isSnowCovered(renderBlocks.blockAccess, x, y, z)) {
|
||||
effectiveMeta |= BlockMaterialMapping.SNOWY_META_BIT;
|
||||
} else if (block instanceof BlockDoublePlant doublePlant && BlockDoublePlant.func_149887_c(metadata)) {
|
||||
effectiveMeta = 0x8 | (doublePlant.func_149885_e(renderBlocks.blockAccess, x, y, z) & 7);
|
||||
}
|
||||
contextEncoder.prepareToRenderBlock(blockRenderContext, block, effectiveMeta,
|
||||
ExtendedDataHelper.BLOCK_RENDER_TYPE, lightValue);
|
||||
|
||||
+2
@@ -21,6 +21,8 @@ public class AngelicaRenderPassConfiguration {
|
||||
private record AngelicaPipelineState(int pass, boolean disableAlphaTest) implements TerrainRenderPass.PipelineState {
|
||||
@Override
|
||||
public void setup() {
|
||||
GLStateManager.glDepthMask(true);
|
||||
|
||||
if (pass == 0) {
|
||||
GLStateManager.glAlphaFunc(GL11.GL_GREATER, 0.1F);
|
||||
}
|
||||
|
||||
+29
@@ -7,6 +7,8 @@ import com.gtnewhorizons.angelica.rendering.celeritas.api.IrisShaderProviderHold
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskProvider;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.threading.ChunkTaskRegistry;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.world.cloned.ClonedChunkSectionCache;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
@@ -40,6 +42,7 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
|
||||
private final WorldClient world;
|
||||
private final ClonedChunkSectionCache sectionCache;
|
||||
private final ChunkTaskProvider taskProvider;
|
||||
private final LongOpenHashSet biomeRebuildColumns = new LongOpenHashSet();
|
||||
|
||||
public AngelicaRenderSectionManager(RenderPassConfiguration<?> configuration, WorldClient world, int renderDistance, CommandList commandList, int minSection, int maxSection, int requestedThreads, ChunkTaskProvider taskProvider) {
|
||||
super(configuration, () -> new AngelicaChunkBuildContext(configuration, world), AngelicaChunkRenderer::new, renderDistance, commandList, minSection, maxSection, requestedThreads, true /* hasShadowPass = true for Iris */);
|
||||
@@ -144,9 +147,35 @@ public class AngelicaRenderSectionManager extends RenderSectionManager {
|
||||
this.sectionCache.invalidate(section.getChunkX(), section.getChunkY(), section.getChunkZ());
|
||||
}
|
||||
|
||||
public void onBiomesChanged(int chunkX, int chunkZ) {
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
this.biomeRebuildColumns.add(PositionUtil.packChunk(chunkX + dx, chunkZ + dz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void flushBiomeRebuilds() {
|
||||
if (this.biomeRebuildColumns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final int sectionCountY = this.world.getHeight() >> 4;
|
||||
for (final LongIterator it = this.biomeRebuildColumns.iterator(); it.hasNext(); ) {
|
||||
final long column = it.nextLong();
|
||||
final int cx = PositionUtil.unpackChunkX(column);
|
||||
final int cz = PositionUtil.unpackChunkZ(column);
|
||||
for (int cy = 0; cy < sectionCountY; cy++) {
|
||||
this.sectionCache.invalidate(cx, cy, cz);
|
||||
this.scheduleRebuild(cx, cy, cz, false);
|
||||
}
|
||||
}
|
||||
this.biomeRebuildColumns.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChunks(boolean updateImmediately) {
|
||||
this.sectionCache.cleanup();
|
||||
this.flushBiomeRebuilds();
|
||||
super.updateChunks(updateImmediately);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.event.ChunkBiomeDataChangedEvent;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.loading.AngelicaClientTweaker;
|
||||
import org.embeddedt.embeddium.impl.gl.device.GLRenderDevice;
|
||||
@@ -12,8 +13,16 @@ public class CeleritasSetup {
|
||||
public static void ensureInitialized() {
|
||||
if (!initialized && AngelicaConfig.enableCeleritas) {
|
||||
GLRenderDevice.VANILLA_STATE_RESETTER = () -> GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
ChunkBiomeDataChangedEvent.BUS.addListener(CeleritasSetup::onChunkBiomeDataChanged);
|
||||
AngelicaClientTweaker.LOGGER.debug("Celeritas init");
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void onChunkBiomeDataChanged(ChunkBiomeDataChangedEvent event) {
|
||||
final CeleritasWorldRenderer renderer = CeleritasWorldRenderer.getInstanceOrNull();
|
||||
if (renderer != null && renderer.isActive()) {
|
||||
renderer.getRenderSectionManager().onBiomesChanged(event.chunkX, event.chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-1
@@ -74,6 +74,10 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static CeleritasWorldRenderer getInstanceOrNull() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public AngelicaRenderSectionManager getRenderSectionManager() {
|
||||
return this.renderSectionManager;
|
||||
}
|
||||
@@ -118,7 +122,16 @@ public class CeleritasWorldRenderer extends SimpleWorldRenderer<WorldClient, Ang
|
||||
protected ChunkRenderMatrices createChunkRenderMatrices() {
|
||||
final boolean shadowPass = renderSectionManager.isInShadowPass();
|
||||
final Matrix4f projection = shadowPass ? ShadowRenderer.PROJECTION : RenderingState.INSTANCE.getProjectionMatrix();
|
||||
final Matrix4f modelView = shadowPass ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix();
|
||||
Matrix4f modelView = shadowPass ? ShadowRenderer.MODELVIEW : RenderingState.INSTANCE.getModelViewMatrix();
|
||||
if (!shadowPass) {
|
||||
// Minecraft's setupCameraTransform bakes translate(0, -eyeHeight, 0) into the modelview.
|
||||
// Chunk rendering passes eye position to drawChunkLayer so vertices arrive at
|
||||
// the shader as (vert_world - eye).
|
||||
final Entity view = mc.renderViewEntity;
|
||||
if (view != null) {
|
||||
modelView = new Matrix4f(modelView).translate(0f, view.getEyeHeight(), 0f);
|
||||
}
|
||||
}
|
||||
return new ChunkRenderMatrices(projection, modelView);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ public interface ContextAwareChunkVertexEncoder extends ChunkVertexEncoder {
|
||||
|
||||
void prepareToRenderBlock(BlockRenderContext ctx, Block block, int metadata, short renderType, byte lightValue);
|
||||
|
||||
void prepareToRenderFluid(BlockRenderContext ctx, Block block, byte lightValue);
|
||||
void prepareToRenderFluid(BlockRenderContext ctx, Block block, int metadata, byte lightValue);
|
||||
|
||||
void finishRenderingBlock();
|
||||
}
|
||||
+42
-3
@@ -12,6 +12,8 @@ import net.coderbot.iris.vertices.ExtendedDataHelper;
|
||||
import net.coderbot.iris.vertices.NormalHelper;
|
||||
import net.coderbot.iris.vertices.NormI8;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockDynamicLiquid;
|
||||
import net.minecraft.block.BlockStaticLiquid;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.terrain.material.Material;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.vertex.format.ChunkVertexEncoder;
|
||||
import org.joml.Vector3f;
|
||||
@@ -26,6 +28,11 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
private static final int NORMAL_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("iris_Normal").getPointer();
|
||||
private static final int MC_ENTITY_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("mc_Entity").getPointer();
|
||||
private static final int MID_BLOCK_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("at_midBlock").getPointer();
|
||||
private static final int A_TEXCOORD_OFFSET = IrisExtendedChunkVertexType.VERTEX_FORMAT.getAttribute("a_TexCoord").getPointer();
|
||||
|
||||
// One unit of UV-space shift toward the quad centroid. Stops bilinear /
|
||||
// mipmap sampling from bleeding pixels from neighboring atlas cells.
|
||||
private static final float TEX_CENTROID_BIAS = 1.0f / 32768.0f;
|
||||
|
||||
private final ChunkVertexEncoder baseEncoder = IrisExtendedChunkVertexType.BASE_TYPE.createEncoder();
|
||||
private final CeleritasQuadView quad = new CeleritasQuadView();
|
||||
@@ -54,14 +61,38 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareToRenderFluid(BlockRenderContext ctx, Block block, byte lightValue) {
|
||||
public void prepareToRenderFluid(BlockRenderContext ctx, Block block, int metadata, byte lightValue) {
|
||||
this.context = ctx;
|
||||
Int2IntMap metaMap = blockMetaMatches != null ? blockMetaMatches.get(block) : null;
|
||||
ctx.blockId = (short) (metaMap != null ? metaMap.get(0) : -1);
|
||||
ctx.blockId = (short) resolveFluidBlockId(block, metadata);
|
||||
ctx.renderType = ExtendedDataHelper.FLUID_RENDER_TYPE;
|
||||
ctx.lightValue = lightValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and prevent material flickering
|
||||
*/
|
||||
private int resolveFluidBlockId(Block block, int metadata) {
|
||||
if (blockMetaMatches == null) return -1;
|
||||
|
||||
int id = lookupFluidMeta(block, metadata);
|
||||
if (id == -1) {
|
||||
final Block counterpart = liquidCounterpart(block);
|
||||
if (counterpart != null) id = lookupFluidMeta(counterpart, metadata);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private int lookupFluidMeta(Block block, int metadata) {
|
||||
final Int2IntMap metaMap = blockMetaMatches.get(block);
|
||||
return metaMap != null ? metaMap.get(metadata) : -1;
|
||||
}
|
||||
|
||||
private static Block liquidCounterpart(Block block) {
|
||||
if (block instanceof BlockStaticLiquid) return Block.getBlockById(Block.getIdFromBlock(block) - 1);
|
||||
if (block instanceof BlockDynamicLiquid) return Block.getBlockById(Block.getIdFromBlock(block) + 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishRenderingBlock() {
|
||||
if (context != null) {
|
||||
@@ -98,6 +129,14 @@ public class IrisExtendedChunkVertexEncoder implements ContextAwareChunkVertexEn
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 2, midUV);
|
||||
memPutInt(ptr + MID_TEX_OFFSET - STRIDE * 3, midUV);
|
||||
|
||||
for (int vIdx = 0; vIdx < 4; vIdx++) {
|
||||
final long uvBase = ptr - (long) (3 - vIdx) * STRIDE + A_TEXCOORD_OFFSET;
|
||||
final float vU = memGetFloat(uvBase);
|
||||
final float vV = memGetFloat(uvBase + 4L);
|
||||
memPutFloat(uvBase, vU + (vU < midU ? TEX_CENTROID_BIAS : -TEX_CENTROID_BIAS));
|
||||
memPutFloat(uvBase + 4L, vV + (vV < midV ? TEX_CENTROID_BIAS : -TEX_CENTROID_BIAS));
|
||||
}
|
||||
|
||||
quad.setup(ptr, STRIDE);
|
||||
NormalHelper.computeFaceNormal(normal, quad);
|
||||
final int packedNormal = NormI8.pack(normal);
|
||||
|
||||
+27
-26
@@ -1,6 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.rendering.celeritas.world.cloned;
|
||||
|
||||
import com.falsepattern.endlessids.mixin.helpers.ChunkBiomeHook;
|
||||
import com.gtnewhorizons.angelica.api.BlockLightProvider;
|
||||
import com.gtnewhorizons.angelica.api.SectionLightData;
|
||||
import com.gtnewhorizons.angelica.compat.ExtendedBlockStorageExt;
|
||||
@@ -20,6 +19,7 @@ import net.minecraft.world.ChunkPosition;
|
||||
import net.minecraft.world.EnumSkyBlock;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
import net.minecraft.world.biome.WorldChunkManager;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
@@ -62,50 +62,51 @@ public class ClonedChunkSection {
|
||||
this.pos = pos;
|
||||
this.data = new ExtendedBlockStorageExt(chunk, section);
|
||||
|
||||
final int bArrLength;
|
||||
if (ModStatus.isEIDBiomeLoaded) {
|
||||
bArrLength = ((ChunkBiomeHook) chunk).getBiomeShortArray().length;
|
||||
} else {
|
||||
bArrLength = chunk.getBiomeArray().length;
|
||||
}
|
||||
this.biomeData = new BiomeGenBase[bArrLength];
|
||||
this.biomeData = new BiomeGenBase[16 * 16];
|
||||
|
||||
copyBlockEntities(chunk, pos);
|
||||
|
||||
// Fill biome data
|
||||
for (int z = pos.getMinZ(); z <= pos.getMaxZ(); z++) {
|
||||
for (int x = pos.getMinX(); x <= pos.getMaxX(); x++) {
|
||||
this.biomeData[(x & 15) | ((z & 15) << 4)] = world.getBiomeGenForCoords(x, z);
|
||||
}
|
||||
}
|
||||
fillBiomeData(chunk);
|
||||
|
||||
this.sectionLightData = BlockLightProvider.getInstance().prepareSectionData(chunk, pos.y);
|
||||
}
|
||||
|
||||
private void fillBiomeData(Chunk chunk) {
|
||||
final WorldChunkManager wcm = world.getWorldChunkManager();
|
||||
for (int lz = 0; lz < 16; lz++) {
|
||||
for (int lx = 0; lx < 16; lx++) {
|
||||
this.biomeData[lx | (lz << 4)] = chunk.getBiomeGenForWorldCoords(lx, lz, wcm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void copyBlockEntities(Chunk chunk, ChunkSectionPos pos) {
|
||||
this.tileEntities.clear();
|
||||
|
||||
final ConcurrentTileEntityMap map = ((IChunkTileEntityMapHolder) chunk).angelica$getConcurrentTEMap();
|
||||
|
||||
map.withReadLock(() -> {
|
||||
map.readLock();
|
||||
try {
|
||||
final Object2ObjectOpenHashMap<ChunkPosition, TileEntity> delegate = map.getDelegate();
|
||||
|
||||
if (delegate.isEmpty()) return;
|
||||
if (!delegate.isEmpty()) {
|
||||
final int minY = pos.getMinY();
|
||||
final int maxY = pos.getMaxY();
|
||||
|
||||
final int minY = pos.getMinY();
|
||||
final int maxY = pos.getMaxY();
|
||||
for (Object2ObjectMap.Entry<ChunkPosition, TileEntity> entry : Object2ObjectMaps.fastIterable(delegate)) {
|
||||
final ChunkPosition tePos = entry.getKey();
|
||||
if (tePos.chunkPosY < minY || tePos.chunkPosY > maxY) continue;
|
||||
|
||||
for (Object2ObjectMap.Entry<ChunkPosition, TileEntity> entry : Object2ObjectMaps.fastIterable(delegate)) {
|
||||
final ChunkPosition tePos = entry.getKey();
|
||||
if (tePos.chunkPosY < minY || tePos.chunkPosY > maxY) continue;
|
||||
|
||||
final TileEntity te = entry.getValue();
|
||||
if (te != null && !te.isInvalid()) {
|
||||
this.tileEntities.put(ChunkSectionPos.packLocal(tePos.chunkPosX & 15, tePos.chunkPosY & 15, tePos.chunkPosZ & 15), te);
|
||||
final TileEntity te = entry.getValue();
|
||||
if (te != null && !te.isInvalid()) {
|
||||
this.tileEntities.put(ChunkSectionPos.packLocal(tePos.chunkPosX & 15, tePos.chunkPosY & 15, tePos.chunkPosZ & 15), te);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
map.readUnlock();
|
||||
}
|
||||
|
||||
this.tileEntities.trim();
|
||||
}
|
||||
|
||||
+11
-6
@@ -21,7 +21,13 @@ public class ClonedChunkSectionCache {
|
||||
|
||||
public synchronized void cleanup() {
|
||||
this.time = getMonotonicTimeSource();
|
||||
this.byPosition.values().removeIf(entry -> this.time > (entry.getLastUsedTimestamp() + MAX_CACHE_DURATION));
|
||||
while (!this.byPosition.isEmpty()) {
|
||||
final ClonedChunkSection oldest = this.byPosition.get(this.byPosition.firstLongKey());
|
||||
if (this.time <= oldest.getLastUsedTimestamp() + MAX_CACHE_DURATION) {
|
||||
break;
|
||||
}
|
||||
this.byPosition.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ClonedChunkSection acquire(int x, int y, int z) {
|
||||
@@ -32,18 +38,17 @@ public class ClonedChunkSectionCache {
|
||||
while (this.byPosition.size() >= MAX_CACHE_SIZE) {
|
||||
this.byPosition.removeFirst();
|
||||
}
|
||||
section = this.createSection(x, y, z);
|
||||
section = this.createSection(key, x, y, z);
|
||||
}
|
||||
|
||||
section.setLastUsedTimestamp(this.time);
|
||||
return section;
|
||||
}
|
||||
|
||||
private ClonedChunkSection createSection(int x, int y, int z) {
|
||||
private ClonedChunkSection createSection(long key, int x, int y, int z) {
|
||||
final ClonedChunkSection section = new ClonedChunkSection(this, this.world);
|
||||
final ChunkSectionPos pos = ChunkSectionPos.from(x, y, z);
|
||||
section.init(pos);
|
||||
this.byPosition.putAndMoveToLast(pos.asLong(), section);
|
||||
section.init(ChunkSectionPos.from(x, y, z));
|
||||
this.byPosition.putAndMoveToLast(key, section);
|
||||
return section;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ public class ConcurrentTileEntityMap implements Map<ChunkPosition, TileEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
public void readLock() {
|
||||
lock.readLock().lock();
|
||||
}
|
||||
|
||||
public void readUnlock() {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
|
||||
public void withWriteLock(Runnable action) {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
|
||||
@@ -20,11 +20,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
// 1 2 3
|
||||
// c: coordinate (x,y,z) 0-2
|
||||
private static final int[][][] NEIGHBOR_OFFSET = new int[][][] {
|
||||
(
|
||||
fixedBottomFaceUV
|
||||
? makeNeighborOffset(EAST_FACE, SOUTH_FACE, WEST_FACE, NORTH_FACE) // BOTTOM_FACE fixedBottomFaceUV
|
||||
: makeNeighborOffset(WEST_FACE, SOUTH_FACE, EAST_FACE, NORTH_FACE) // BOTTOM_FACE not fixed
|
||||
),
|
||||
makeNeighborOffset(EAST_FACE, SOUTH_FACE, WEST_FACE, NORTH_FACE), // BOTTOM_FACE
|
||||
makeNeighborOffset(WEST_FACE, SOUTH_FACE, EAST_FACE, NORTH_FACE), // TOP_FACE
|
||||
makeNeighborOffset(EAST_FACE, BOTTOM_FACE, WEST_FACE, TOP_FACE), // NORTH_FACE
|
||||
makeNeighborOffset(WEST_FACE, BOTTOM_FACE, EAST_FACE, TOP_FACE), // SOUTH_FACE
|
||||
@@ -48,6 +44,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
private int textureFace;
|
||||
private int textureFaceOrig;
|
||||
private int rotateUV;
|
||||
private boolean flipBottom;
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
@@ -60,6 +57,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
offsetsComputed = false;
|
||||
haveOffsets = false;
|
||||
dx = dy = dz = 0;
|
||||
flipBottom = !fixedBottomFaceUV;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -104,7 +102,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
|
||||
@Override
|
||||
public int[] getOffset(int blockFace, int relativeDirection) {
|
||||
return NEIGHBOR_OFFSET[blockFace][rotateUV(relativeDirection)];
|
||||
return NEIGHBOR_OFFSET[flipBottom && blockFace == 0 ? 1 : blockFace][rotateUV(relativeDirection)];
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,6 +145,11 @@ final class BlockOrientation extends RenderBlockState {
|
||||
return haveOffsets;
|
||||
}
|
||||
|
||||
|
||||
public void setFlipBottom(){
|
||||
flipBottom = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldConnectByBlock(Block neighbor, int neighborX, int neighborY, int neighborZ) {
|
||||
return block == neighbor
|
||||
@@ -172,6 +175,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
copy.textureFace = textureFace;
|
||||
copy.textureFaceOrig = textureFaceOrig;
|
||||
copy.rotateUV = rotateUV;
|
||||
copy.flipBottom = flipBottom;
|
||||
|
||||
copy.blockAccess = blockAccess;
|
||||
copy.block = block;
|
||||
@@ -204,6 +208,7 @@ final class BlockOrientation extends RenderBlockState {
|
||||
rotateUV = 0;
|
||||
textureFace = blockFaceToTextureFace(blockFace);
|
||||
metadataBits = (1 << metadata) | (1 << altMetadata);
|
||||
flipBottom = !fixedBottomFaceUV;
|
||||
}
|
||||
|
||||
void setBlockMetadata(Block block, int metadata, int face) {
|
||||
|
||||
@@ -53,6 +53,9 @@ public final class CompactCtmQuadProcessor {
|
||||
}
|
||||
|
||||
public boolean processFace(RenderBlocks rb, RenderBlockState renderBlockState, IIcon origIcon) {
|
||||
if(renderBlockState instanceof BlockOrientation blockOrientation){
|
||||
blockOrientation.setFlipBottom();
|
||||
}
|
||||
int neighborBits = override.getNeighborBits(renderBlockState, origIcon);
|
||||
|
||||
int ctmIndex = TileOverride.neighborMap[neighborBits & 0xFF];
|
||||
|
||||
@@ -289,9 +289,6 @@ public abstract class TileOverride implements Comparable<TileOverride> {
|
||||
if (token.isEmpty()) {
|
||||
// nothing
|
||||
} else if (token.contains("/")) {
|
||||
if (!token.endsWith(".png")) {
|
||||
token += ".png";
|
||||
}
|
||||
ResourceLocation resource = TexturePackAPI.parseResourceLocation(properties.getResource(), token);
|
||||
if (resource != null) {
|
||||
list.add(resource.toString());
|
||||
|
||||
@@ -540,56 +540,63 @@ public class SodiumGameOptionPages {
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("RGB Colors")
|
||||
.setTooltip("Enable hex colors via &#RRGGBB syntax")
|
||||
.setName(I18n.format("options.angelica.texteffects.rgb_colors"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.rgb_colors.tooltip", "\\&#RRGGBB"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableRGBColors = value,
|
||||
opts -> AngelicaConfig.enableRGBColors)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Gradients")
|
||||
.setTooltip("Smooth color transitions via &g&#start&#end")
|
||||
.setName(I18n.format("options.angelica.texteffects.gradients"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.gradients.tooltip") + " \\&g\\&#start\\&#end")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableGradients = value,
|
||||
opts -> AngelicaConfig.enableGradients)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Rainbow")
|
||||
.setTooltip("Cycling rainbow colors via &q")
|
||||
.setName(I18n.format("options.angelica.texteffects.rainbow"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.rainbow.tooltip") + " \\&q")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableRainbow = value,
|
||||
opts -> AngelicaConfig.enableRainbow)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Wave Text")
|
||||
.setTooltip("Animated bouncing text via &z")
|
||||
.setName(I18n.format("options.angelica.texteffects.wave_text"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.wave_text.tooltip") + " \\&z")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableWaveText = value,
|
||||
opts -> AngelicaConfig.enableWaveText)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(int.class, angelicaOpts)
|
||||
.setName("Wave Amplitude")
|
||||
.setTooltip("How far wave text bounces (default 2.0)")
|
||||
.setName(I18n.format("options.angelica.texteffects.wave_amplitude"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.wave_amplitude.tooltip"))
|
||||
.setControl(option -> new SliderControl(option, 10, 80, 5, v -> (v / 10) + "." + (v % 10)))
|
||||
.setBinding((opts, value) -> AngelicaConfig.waveAmplitude = value / 10f, opts -> Math.round(AngelicaConfig.waveAmplitude * 10f))
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Dinnerbone Text")
|
||||
.setTooltip("Flipped upside down text via &v")
|
||||
.setName(I18n.format("options.angelica.texteffects.dinnerbone_text"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.dinnerbone_text.tooltip") + " \\&v")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableDinnerboneText = value,
|
||||
opts -> AngelicaConfig.enableDinnerboneText)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName("Ampersand Conversion")
|
||||
.setTooltip("Convert & prefix codes to formatting codes at render time")
|
||||
.setName(I18n.format("options.angelica.texteffects.drop_shadow"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.drop_shadow.tooltip", "\\&u") + " \\&u\\&#RRGGBB")
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableDropShadow = value,
|
||||
opts -> AngelicaConfig.enableDropShadow)
|
||||
.build())
|
||||
.add(OptionImpl.createBuilder(boolean.class, angelicaOpts)
|
||||
.setName(I18n.format("options.angelica.texteffects.ampersand_conversion"))
|
||||
.setTooltip(I18n.format("options.angelica.texteffects.ampersand_conversion.tooltip", "\\&"))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding((opts, value) -> AngelicaConfig.enableAmpersandConversion = value,
|
||||
opts -> AngelicaConfig.enableAmpersandConversion)
|
||||
.build())
|
||||
.build());
|
||||
|
||||
return new OptionPage("Text Effects", ImmutableList.copyOf(groups));
|
||||
return new OptionPage(I18n.format("sodium.options.pages.text"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,7 +72,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipError;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
public class Iris {
|
||||
@@ -458,6 +457,33 @@ public class Iris {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles shader debug mode. When enabled, patched shader sources are dumped to disk (see
|
||||
* {@link net.coderbot.iris.pipeline.PatchedShaderPrinter}) and logging is more verbose.
|
||||
*/
|
||||
public static void setDebug(boolean enable) {
|
||||
try {
|
||||
irisConfig.setDebugEnabled(enable);
|
||||
irisConfig.save();
|
||||
reload();
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to " + (enable ? "enable" : "disable") + " debug mode", e);
|
||||
}
|
||||
logger.info("Debug functionality is " + (enable ? "enabled, logging will be more verbose!" : "disabled."));
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles whether unrecognized shader packs may load, exposing the {@code ALLOWS_UNKNOWN_SHADERS} macro.
|
||||
*/
|
||||
public static void setAllowUnknownShaders(boolean allow) {
|
||||
try {
|
||||
irisConfig.setUnknown(allow);
|
||||
reload();
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to " + (allow ? "allow" : "disallow") + " unknown shaders", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadShaderpack() {
|
||||
if (irisConfig == null) {
|
||||
if (!initialized) {
|
||||
@@ -678,8 +704,7 @@ public class Iris {
|
||||
try (Stream<Path> stream = Files.walk(root)) {
|
||||
return stream.filter(Files::isDirectory).anyMatch(path -> path.endsWith("shaders"));
|
||||
}
|
||||
} catch (ZipError zipError) {
|
||||
// Java 8 seems to throw a ZipError instead of a subclass of IOException
|
||||
} catch (ZipException e) {
|
||||
Iris.logger.warn("The ZIP at " + pack + " is corrupt");
|
||||
} catch (IOException ignored) {
|
||||
// ignored, not a valid shader pack.
|
||||
|
||||
@@ -14,6 +14,7 @@ import net.coderbot.iris.shaderpack.materialmap.BlockRenderType;
|
||||
import net.coderbot.iris.shaderpack.materialmap.FlatteningMap;
|
||||
import net.coderbot.iris.shaderpack.materialmap.NamespacedId;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockDoublePlant;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
@@ -25,9 +26,11 @@ public class BlockMaterialMapping {
|
||||
|
||||
public record BlockIdMaps(Reference2ObjectMap<Block, Int2IntMap> blockMetaMap, NbtConditionalIdMap<Block> tileEntityMap) {}
|
||||
|
||||
/** Meta-key bit OR'd in at runtime when a snowy-tagged block has snow above it. */
|
||||
// Meta-key bits OR'd in at runtime
|
||||
public static final int SNOWY_META_BIT = 0x10;
|
||||
|
||||
public static final int DOUBLE_PLANT_TOP_BIT = 0x8;
|
||||
|
||||
/**
|
||||
* Creates the standard block meta ID map, the TileEntity NBT-conditional map, and registers
|
||||
* snowy blocks on {@link BlockRenderingSettings}.
|
||||
@@ -129,6 +132,7 @@ public class BlockMaterialMapping {
|
||||
final Map<String, String> stateProps = entry.stateProperties();
|
||||
final String snowy = stateProps.get("snowy");
|
||||
final int snowyBit = "true".equals(snowy) ? SNOWY_META_BIT : 0;
|
||||
final boolean wantsDoublePlantTop = "upper".equals(stateProps.get("half"));
|
||||
|
||||
// Vanilla modern names go through FlatteningMap; legacy-section packs and modded blocks
|
||||
// resolve directly from the registry.
|
||||
@@ -145,12 +149,16 @@ public class BlockMaterialMapping {
|
||||
}
|
||||
final Block block = resolveBlockOrNull(target.id());
|
||||
if (block == null) continue;
|
||||
applyMetas(block, target.metas(), idMap, intId, snowyBit);
|
||||
int extraBits = snowyBit;
|
||||
if (wantsDoublePlantTop && block instanceof BlockDoublePlant) {
|
||||
extraBits |= DOUBLE_PLANT_TOP_BIT;
|
||||
}
|
||||
applyMetas(block, target.metas(), idMap, intId, extraBits);
|
||||
if (snowy != null) snowyBlocks.add(block);
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyMetas(Block block, Set<Integer> metas, Reference2ObjectMap<Block, Int2IntMap> idMap, int intId, int snowyBit) {
|
||||
private static void applyMetas(Block block, Set<Integer> metas, Reference2ObjectMap<Block, Int2IntMap> idMap, int intId, int extraBits) {
|
||||
Int2IntMap metaMap = idMap.get(block);
|
||||
if (metaMap == null) {
|
||||
metaMap = new Int2IntOpenHashMap();
|
||||
@@ -159,9 +167,9 @@ public class BlockMaterialMapping {
|
||||
}
|
||||
|
||||
if (metas.isEmpty()) {
|
||||
for (int meta = 0; meta < 16; meta++) metaMap.putIfAbsent(meta | snowyBit, intId);
|
||||
for (int meta = 0; meta < 16; meta++) metaMap.putIfAbsent(meta | extraBits, intId);
|
||||
} else {
|
||||
for (int meta : metas) metaMap.putIfAbsent(meta | snowyBit, intId);
|
||||
for (int meta : metas) metaMap.putIfAbsent(meta | extraBits, intId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ public class IrisConfig {
|
||||
*/
|
||||
private boolean enableDebugOptions;
|
||||
|
||||
private boolean allowUnknownShaders;
|
||||
|
||||
private final Path propertiesPath;
|
||||
|
||||
public IrisConfig(Path propertiesPath) {
|
||||
@@ -45,6 +47,7 @@ public class IrisConfig {
|
||||
enableShaders = true;
|
||||
disableUpdateMessage = false;
|
||||
enableDebugOptions = false;
|
||||
allowUnknownShaders = false;
|
||||
this.propertiesPath = propertiesPath;
|
||||
}
|
||||
|
||||
@@ -113,6 +116,25 @@ public class IrisConfig {
|
||||
return enableDebugOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether debug features are enabled.
|
||||
*/
|
||||
public void setDebugEnabled(boolean enabled) {
|
||||
this.enableDebugOptions = enabled;
|
||||
}
|
||||
|
||||
public boolean shouldAllowUnknownShaders() {
|
||||
return allowUnknownShaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether unrecognized shader packs may load.
|
||||
*/
|
||||
public void setUnknown(boolean allow) throws IOException {
|
||||
this.allowUnknownShaders = allow;
|
||||
save();
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the config file and then populates the string, int, and boolean entries with the parsed entries
|
||||
*
|
||||
@@ -132,6 +154,7 @@ public class IrisConfig {
|
||||
shaderPackName = properties.getProperty("shaderPack");
|
||||
enableShaders = !"false".equals(properties.getProperty("enableShaders"));
|
||||
enableDebugOptions = "true".equals(properties.getProperty("enableDebugOptions"));
|
||||
allowUnknownShaders = "true".equals(properties.getProperty("allowUnknownShaders"));
|
||||
disableUpdateMessage = "true".equals(properties.getProperty("disableUpdateMessage"));
|
||||
// TODO: GUI
|
||||
try {
|
||||
@@ -159,6 +182,7 @@ public class IrisConfig {
|
||||
properties.setProperty("shaderPack", getShaderPackName().orElse(""));
|
||||
properties.setProperty("enableShaders", enableShaders ? "true" : "false");
|
||||
properties.setProperty("enableDebugOptions", enableDebugOptions ? "true" : "false");
|
||||
properties.setProperty("allowUnknownShaders", allowUnknownShaders ? "true" : "false");
|
||||
properties.setProperty("disableUpdateMessage", disableUpdateMessage ? "true" : "false");
|
||||
properties.setProperty("maxShadowRenderDistance", String.valueOf(IrisVideoSettings.shadowDistance));
|
||||
// NB: This uses ISO-8859-1 with unicode escapes as the encoding
|
||||
|
||||
@@ -18,6 +18,7 @@ public enum RenderCondition {
|
||||
HAND_TRANSLUCENT,
|
||||
RAIN_SNOW,
|
||||
WORLD_BORDER,
|
||||
LIGHTNING,
|
||||
SHADOW_TRANSLUCENT,
|
||||
// NB: Must be last due to implementation details of DeferredWorldRenderingPipeline
|
||||
SHADOW
|
||||
|
||||
@@ -3,5 +3,6 @@ package net.coderbot.iris.gbuffer_overrides.matching;
|
||||
public enum SpecialCondition {
|
||||
ENTITY_EYES,
|
||||
BEACON_BEAM,
|
||||
GLINT
|
||||
GLINT,
|
||||
LIGHTNING
|
||||
}
|
||||
@@ -2,16 +2,16 @@ package net.coderbot.iris.gl.buffer;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import lombok.Getter;
|
||||
import org.embeddedt.embeddium.impl.gl.debug.GLDebug;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public class ShaderStorageBuffer {
|
||||
protected final int index;
|
||||
protected final ShaderStorageInfo info;
|
||||
protected int id;
|
||||
@Getter protected int id;
|
||||
|
||||
public ShaderStorageBuffer(int index, ShaderStorageInfo info) {
|
||||
this.id = RenderSystem.createBuffers();
|
||||
@@ -45,16 +45,13 @@ public class ShaderStorageBuffer {
|
||||
GLStateManager.glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, newId);
|
||||
|
||||
// Calculation time
|
||||
int newWidth = (int) (width * info.scaleX());
|
||||
int newHeight = (int) (height * info.scaleY());
|
||||
int finalSize = (newHeight * newWidth) * info.size();
|
||||
long newWidth = (long) (width * info.scaleX());
|
||||
long newHeight = (long) (height * info.scaleY());
|
||||
long finalSize = (newHeight * newWidth) * info.size();
|
||||
RenderSystem.bufferStorage(GL43.GL_SHADER_STORAGE_BUFFER, finalSize, 0);
|
||||
RenderSystem.clearBufferSubData(GL43.GL_SHADER_STORAGE_BUFFER, GL30.GL_R8, 0, finalSize, GL11.GL_RED, GL11.GL_BYTE, new int[]{0});
|
||||
RenderSystem.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, index, newId);
|
||||
id = newId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.coderbot.iris.gl.buffer;
|
||||
|
||||
public record ShaderStorageInfo(int size, boolean relative, float scaleX, float scaleY) {
|
||||
public record ShaderStorageInfo(long size, boolean relative, float scaleX, float scaleY) {
|
||||
}
|
||||
@@ -4,15 +4,18 @@ import lombok.Getter;
|
||||
import net.coderbot.iris.gl.GlResource;
|
||||
import net.coderbot.iris.gl.blending.DepthColorStorage;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public final class Program extends GlResource {
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramUniforms uniforms;
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramSamplers samplers;
|
||||
|
||||
|
||||
@Getter
|
||||
private final ProgramImages images;
|
||||
|
||||
@@ -25,15 +28,16 @@ public final class Program extends GlResource {
|
||||
|
||||
DepthColorStorage.registerOwnedProgram(program);
|
||||
}
|
||||
|
||||
|
||||
public void use() {
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
GLStateManager.glUseProgram(getGlId());
|
||||
|
||||
|
||||
uniforms.update();
|
||||
samplers.update();
|
||||
images.update();
|
||||
}
|
||||
|
||||
|
||||
public static void unbind() {
|
||||
ProgramUniforms.clearActiveUniforms();
|
||||
ProgramSamplers.clearActiveSamplers();
|
||||
@@ -45,7 +49,7 @@ public final class Program extends GlResource {
|
||||
DepthColorStorage.unregisterOwnedProgram(getGlId());
|
||||
GLStateManager.glDeleteProgram(getGlId());
|
||||
}
|
||||
|
||||
|
||||
public int getProgramId() {
|
||||
return getGlId();
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.Tags;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.compat.dh.DHCompat;
|
||||
import net.coderbot.iris.parsing.BiomeCategories;
|
||||
import net.coderbot.iris.pipeline.HandRenderer;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPhase;
|
||||
import net.coderbot.iris.shaderpack.IrisLimits;
|
||||
import net.coderbot.iris.shaderpack.StringPair;
|
||||
import net.coderbot.iris.texture.format.TextureFormat;
|
||||
import net.coderbot.iris.texture.format.TextureFormatLoader;
|
||||
@@ -81,12 +83,19 @@ public class StandardMacros {
|
||||
define(standardDefines, "IS_ANGELICA");
|
||||
if (AngelicaConfig.defineIsIris) {
|
||||
define(standardDefines, "IS_IRIS");
|
||||
define(standardDefines, "IRIS_VERSION", "10803");
|
||||
define(standardDefines, "IRIS_HAS_TRANSLUCENCY_SORTING");
|
||||
define(standardDefines, "MAX_COLOR_BUFFERS", String.valueOf(IrisLimits.MAX_COLOR_BUFFERS));
|
||||
}
|
||||
|
||||
if (DHCompat.hasRenderingEnabled()) {
|
||||
define(standardDefines, "DISTANT_HORIZONS");
|
||||
}
|
||||
|
||||
if (Iris.getIrisConfig().shouldAllowUnknownShaders()) {
|
||||
define(standardDefines, "ALLOWS_UNKNOWN_SHADERS");
|
||||
}
|
||||
|
||||
define(standardDefines, "DH_BLOCK_UNKNOWN", String.valueOf(0));
|
||||
define(standardDefines, "DH_BLOCK_LEAVES", String.valueOf(1));
|
||||
define(standardDefines, "DH_BLOCK_STONE", String.valueOf(2));
|
||||
|
||||
@@ -11,6 +11,7 @@ public class StateUpdateNotifiers {
|
||||
public static ValueUpdateNotifier alphaFuncNotifier;
|
||||
public static ValueUpdateNotifier alphaTestNotifier;
|
||||
public static ValueUpdateNotifier blendFuncNotifier;
|
||||
public static ValueUpdateNotifier colorModulatorNotifier;
|
||||
public static ValueUpdateNotifier bindTextureNotifier;
|
||||
public static ValueUpdateNotifier normalTextureChangeNotifier;
|
||||
public static ValueUpdateNotifier specularTextureChangeNotifier;
|
||||
|
||||
@@ -4,10 +4,13 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import cpw.mods.fml.client.config.GuiUtils;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
* Class serving as abstraction and
|
||||
@@ -111,6 +114,32 @@ public final class GuiUtil {
|
||||
font.drawStringWithShadow(text, x + 4, y + 4, 0xFFFFFF);
|
||||
}
|
||||
|
||||
public static void drawScrollingText(FontRenderer font, String text, int centerX, int minX, int maxX, int minY, int maxY, int color) {
|
||||
final int textWidth = font.getStringWidth(text);
|
||||
final int boxWidth = maxX - minX;
|
||||
final int textY = ((minY + maxY) - font.FONT_HEIGHT) / 2 + 1;
|
||||
|
||||
if (textWidth > boxWidth) {
|
||||
final int overflow = textWidth - boxWidth;
|
||||
final double time = System.currentTimeMillis() / 1000.0;
|
||||
final double period = Math.max(overflow * 0.5, 3.0);
|
||||
final double t = (Math.sin((Math.PI / 2.0) * Math.cos((Math.PI * 2.0) * time / period)) / 2.0) + 0.5;
|
||||
final int scroll = (int) (t * overflow);
|
||||
|
||||
final Minecraft mc = client();
|
||||
final int scale = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight).getScaleFactor();
|
||||
GLStateManager.glEnable(GL11.GL_SCISSOR_TEST);
|
||||
GLStateManager.glScissor(minX * scale, mc.displayHeight - (maxY * scale), boxWidth * scale, (maxY - minY) * scale);
|
||||
font.drawStringWithShadow(text, minX - scroll, textY, color);
|
||||
GLStateManager.glDisable(GL11.GL_SCISSOR_TEST);
|
||||
} else {
|
||||
int textX = centerX - (textWidth / 2);
|
||||
textX = Math.min(textX, maxX - textWidth);
|
||||
textX = Math.max(textX, minX);
|
||||
font.drawStringWithShadow(text, textX, textY, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorten a text to a specific length, adding an ellipsis (...)
|
||||
* to the end if shortened.
|
||||
@@ -140,13 +169,25 @@ public final class GuiUtil {
|
||||
* @return the translated text if found, otherwise the default provided
|
||||
*/
|
||||
public static String translateOrDefault(String defaultText, String translationDesc, Object ... format) {
|
||||
final String translated = I18n.format(translationDesc, format);
|
||||
final String translated = format.length == 0
|
||||
? translateLenient(translationDesc)
|
||||
: I18n.format(translationDesc, format);
|
||||
if(!translated.equals(translationDesc)) {
|
||||
return translated;
|
||||
}
|
||||
return defaultText;
|
||||
}
|
||||
|
||||
private static final String FORMAT_ERROR_PREFIX = "Format error: ";
|
||||
|
||||
/**
|
||||
* Nasty dirty hack, but it works.
|
||||
*/
|
||||
public static String translateLenient(String key) {
|
||||
final String translated = I18n.format(key);
|
||||
return translated.startsWith(FORMAT_ERROR_PREFIX) ? translated.substring(FORMAT_ERROR_PREFIX.length()) : translated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the {@code UI_BUTTON_CLICK} sound event as a
|
||||
* master sound effect.
|
||||
@@ -155,7 +196,7 @@ public final class GuiUtil {
|
||||
* or other action.
|
||||
*/
|
||||
public static void playButtonClickSound() {
|
||||
// client().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1));
|
||||
client().getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,9 @@ public class IrisElementRow {
|
||||
private final int spacing;
|
||||
private int x;
|
||||
private int y;
|
||||
private int width;
|
||||
|
||||
@Getter
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public IrisElementRow(int spacing) {
|
||||
|
||||
@@ -19,7 +19,7 @@ public abstract class IrisGuiSlot extends GuiSlot {
|
||||
super(mc, width, height, top, bottom, slotHeight);
|
||||
// Set Center Vertically to false
|
||||
this.field_148163_i = false;
|
||||
|
||||
this.headerPadding = 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -37,11 +37,15 @@ public abstract class IrisGuiSlot extends GuiSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawSelectionBox(int x, int y, int mouseX, int mouseY) {
|
||||
final int oldPadding = this.headerPadding;
|
||||
this.headerPadding = 2;
|
||||
super.drawSelectionBox(x, y, mouseX, mouseY);
|
||||
this.headerPadding = oldPadding;
|
||||
public int func_148124_c/*getSlotIndexFromScreenCoords*/(int x, int y) {
|
||||
final int left = this.left + this.width / 2 - this.getListWidth() / 2 + hitLeftInset() + hitXShift();
|
||||
final int right = this.left + this.width / 2 + this.getListWidth() / 2 - hitRightInset() + hitXShift();
|
||||
final int relativeY = y - this.top + (int) this.amountScrolled - hitYOffset();
|
||||
final int index = relativeY / this.slotHeight;
|
||||
if (y <= this.top || y >= this.bottom) {
|
||||
return -1;
|
||||
}
|
||||
return x < this.getScrollBarX() && x >= left && x <= right && index >= 0 && relativeY >= 0 && index < this.getSize() ? index : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,6 +57,23 @@ public abstract class IrisGuiSlot extends GuiSlot {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int hitYOffset() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
protected int hitRightInset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int hitLeftInset() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int hitXShift() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if (!this.func_148125_i/*enabled*/()) {
|
||||
return false;
|
||||
@@ -60,15 +81,15 @@ public abstract class IrisGuiSlot extends GuiSlot {
|
||||
final int size = this.getSize();
|
||||
final int scrollBarX = this.getScrollBarX();
|
||||
final int rightEdge = scrollBarX + 6;
|
||||
final int elementLeft = this.width / 2 - this.getListWidth() / 2;
|
||||
final int elementRight = this.width / 2 + this.getListWidth() / 2;
|
||||
final int relativeY = mouseY - this.top - this.headerPadding + (int) this.amountScrolled - 4;
|
||||
final int elementLeft = this.width / 2 - this.getListWidth() / 2 + hitLeftInset() + hitXShift();
|
||||
final int elementRight = this.width / 2 + this.getListWidth() / 2 - hitRightInset() + hitXShift();
|
||||
final int relativeY = mouseY - this.top + (int) this.amountScrolled - hitYOffset();
|
||||
boolean handled = false;
|
||||
final boolean leftMouseDown = Mouse.isButtonDown(0);
|
||||
final boolean rightMouseDown = Mouse.isButtonDown(1);
|
||||
|
||||
if (mouseX <= this.left || mouseX >= this.right || mouseY <= this.top || mouseY >= this.bottom) {
|
||||
return handled;
|
||||
return false;
|
||||
}
|
||||
if (leftMouseDown && mouseX >= scrollBarX && mouseX <= rightEdge) {
|
||||
scrolling = true;
|
||||
|
||||
@@ -25,7 +25,7 @@ public class ShaderPackOptionList extends IrisGuiSlot {
|
||||
private final List<BaseEntry> entries = new ArrayList<>();
|
||||
|
||||
public ShaderPackOptionList(ShaderPackScreen screen, NavigationController navigation, ShaderPack pack, Minecraft client, int width, int height, int top, int bottom, int left, int right) {
|
||||
super(client, width, height, top, bottom, 20);
|
||||
super(client, width, height, top, bottom, 24);
|
||||
this.navigation = navigation;
|
||||
this.screen = screen;
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ShaderPackOptionList extends IrisGuiSlot {
|
||||
}
|
||||
}
|
||||
|
||||
if (row.size() > 0) {
|
||||
if (!row.isEmpty()) {
|
||||
while (row.size() < columns) {
|
||||
row.add(AbstractElementWidget.EMPTY);
|
||||
}
|
||||
@@ -93,7 +93,12 @@ public class ShaderPackOptionList extends IrisGuiSlot {
|
||||
}
|
||||
@Override
|
||||
public boolean mouseReleased( int mouseX, int mouseY, int button) {
|
||||
final int relativeY = mouseY - this.top - this.headerPadding + (int) this.amountScrolled - 4;
|
||||
this.scrolling = false;
|
||||
if (mouseY <= this.top || mouseY >= this.bottom) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int relativeY = mouseY - this.top + (int) this.amountScrolled - hitYOffset();
|
||||
final int index = relativeY / this.slotHeight;
|
||||
|
||||
if (index < 0 || index >= this.entries.size())
|
||||
@@ -113,11 +118,31 @@ public class ShaderPackOptionList extends IrisGuiSlot {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hitYOffset() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hitRightInset() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hitLeftInset() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int hitXShift() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawSlot(int index, int x, int y, int i1, Tessellator tessellator, int mouseX, int mouseY) {
|
||||
final BaseEntry entry = this.entries.get(index);
|
||||
final boolean isMouseOver = this.func_148124_c/*getSlotIndexFromScreenCoords*/(mouseX, mouseY) == index;
|
||||
entry.drawEntry(screen, index, x - 2, y + 4, this.getListWidth(), this.slotHeight, tessellator, mouseX, mouseY, isMouseOver);
|
||||
entry.drawEntry(screen, index, x, y - 2, this.getListWidth(), this.slotHeight, tessellator, mouseX, mouseY, isMouseOver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,13 +4,23 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gui.element.shaderselection.BaseEntry;
|
||||
import net.coderbot.iris.gui.element.shaderselection.DownloadEntry;
|
||||
import net.coderbot.iris.gui.element.shaderselection.LabelEntry;
|
||||
import net.coderbot.iris.gui.element.shaderselection.ShaderPackEntry;
|
||||
import net.coderbot.iris.gui.element.shaderselection.TopButtonRowEntry;
|
||||
import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.StandardWatchEventKinds;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.nio.file.WatchKey;
|
||||
import java.nio.file.WatchService;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -31,15 +41,70 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
|
||||
private final List<BaseEntry> entries = new ArrayList<>();
|
||||
|
||||
private final WatchService watcher;
|
||||
private final WatchKey key;
|
||||
private boolean keyValid;
|
||||
|
||||
public ShaderPackSelectionList(ShaderPackScreen screen, Minecraft client, int width, int height, int top, int bottom, int left, int right) {
|
||||
super(client, width, height, top, bottom, 20);
|
||||
|
||||
this.screen = screen;
|
||||
this.topButtonRow = new TopButtonRowEntry(this, Iris.getIrisConfig().areShadersEnabled());
|
||||
|
||||
WatchService watcher1;
|
||||
WatchKey key1;
|
||||
try {
|
||||
watcher1 = FileSystems.getDefault().newWatchService();
|
||||
key1 = Iris.getShaderpacksDirectory().register(watcher1,
|
||||
StandardWatchEventKinds.ENTRY_CREATE,
|
||||
StandardWatchEventKinds.ENTRY_MODIFY,
|
||||
StandardWatchEventKinds.ENTRY_DELETE);
|
||||
keyValid = true;
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Couldn't register shaderpacks directory file watcher!", e);
|
||||
watcher1 = null;
|
||||
key1 = null;
|
||||
keyValid = false;
|
||||
}
|
||||
this.watcher = watcher1;
|
||||
this.key = key1;
|
||||
|
||||
refresh();
|
||||
}
|
||||
|
||||
// Poll for new shaderpacks
|
||||
public void poll() {
|
||||
if (!keyValid) {
|
||||
return;
|
||||
}
|
||||
boolean changed = false;
|
||||
for (WatchEvent<?> event : key.pollEvents()) {
|
||||
if (event.kind() == StandardWatchEventKinds.OVERFLOW) {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
refresh();
|
||||
}
|
||||
keyValid = key.reset();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (key != null) {
|
||||
key.cancel();
|
||||
}
|
||||
if (watcher != null) {
|
||||
watcher.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
poll();
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
this.entries.clear();
|
||||
|
||||
@@ -68,8 +133,13 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
|
||||
this.entries.add(topButtonRow);
|
||||
|
||||
// Download something man
|
||||
if (names.isEmpty()) {
|
||||
this.entries.add(new DownloadEntry(this, "Download Shaders", "https://modrinth.com/shaders"));
|
||||
}
|
||||
|
||||
// Only allow the enable/disable shaders button if the user has added a shader pack. Otherwise, the button will be disabled.
|
||||
topButtonRow.allowEnableShadersButton = names.size() > 0;
|
||||
topButtonRow.allowEnableShadersButton = !names.isEmpty();
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -78,6 +148,11 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
addPackEntry(index, name);
|
||||
}
|
||||
|
||||
// Try not to gaslight users in case they swap back and forth from lwjgl2 and lwjgl3
|
||||
final String footerKey = BackendManager.RENDER_BACKEND.supportsFileDrop()
|
||||
? "pack.iris.list.label"
|
||||
: "pack.iris.list.label.lwjgl2";
|
||||
addLabelEntries(EnumChatFormatting.GRAY.toString() + EnumChatFormatting.ITALIC + I18n.format(footerKey));
|
||||
}
|
||||
|
||||
public void addPackEntry(int index, String name) {
|
||||
@@ -128,6 +203,8 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
return true;
|
||||
} else if( entry instanceof TopButtonRowEntry topButtonRowEntry) {
|
||||
return topButtonRowEntry.mouseClicked(mouseX, mouseY, 0);
|
||||
} else if (entry instanceof DownloadEntry downloadEntry) {
|
||||
return downloadEntry.click(this.screen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -152,7 +229,7 @@ public class ShaderPackSelectionList extends IrisGuiSlot {
|
||||
protected void drawSlot(int index, int x, int y, int i1, Tessellator tessellator, int mouseX, int mouseY) {
|
||||
final BaseEntry entry = this.entries.get(index);
|
||||
final boolean isMouseOver = this.func_148124_c/*getSlotIndexFromScreenCoords*/(mouseX, mouseY) == index;
|
||||
entry.drawEntry(screen, index, x - 2, y + 4, this.getListWidth(), tessellator, mouseX, mouseY, isMouseOver);
|
||||
entry.drawEntry(screen, index, x, y + 4, this.getListWidth(), tessellator, mouseX, mouseY, isMouseOver);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class ElementRowEntry extends BaseEntry {
|
||||
|
||||
private int cachedWidth;
|
||||
private int cachedPosX;
|
||||
private float cachedSingleWidth;
|
||||
|
||||
public ElementRowEntry(NavigationController navigation, List<AbstractElementWidget<?>> widgets) {
|
||||
super(navigation);
|
||||
@@ -32,25 +33,43 @@ public class ElementRowEntry extends BaseEntry {
|
||||
|
||||
// Width of a single widget
|
||||
final float singleWidgetWidth = (float) totalWidthWithoutMargins / widgets.size();
|
||||
this.cachedSingleWidth = singleWidgetWidth;
|
||||
|
||||
for (int i = 0; i < widgets.size(); i++) {
|
||||
final AbstractElementWidget<?> widget = widgets.get(i);
|
||||
final boolean widgetHovered = isMouseOver && (getHoveredWidget(mouseX) == i);
|
||||
widget.drawScreen(x + (int) ((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, slotHeight + 2, mouseX, mouseY, 0, widgetHovered);
|
||||
widget.drawScreen(x + (int) ((singleWidgetWidth + 2) * i), y, (int) singleWidgetWidth, slotHeight - 2, mouseX, mouseY, 0, widgetHovered);
|
||||
|
||||
screen.setElementHoveredStatus(widget, widgetHovered);
|
||||
}
|
||||
}
|
||||
|
||||
public int getHoveredWidget(int mouseX) {
|
||||
final float positionAcrossWidget = ((float) MathHelper.clamp_int(mouseX - cachedPosX, 0, cachedWidth)) / cachedWidth;
|
||||
|
||||
final float CONTENT_ANCHOR_OFFSET = 2f;
|
||||
final float rel = (mouseX - cachedPosX) + CONTENT_ANCHOR_OFFSET;
|
||||
final float clamped = Math.clamp(rel, 0f, cachedWidth);
|
||||
final float positionAcrossWidget = clamped / cachedWidth;
|
||||
|
||||
return MathHelper.clamp_int((int) Math.floor(widgets.size() * positionAcrossWidget), 0, widgets.size() - 1);
|
||||
}
|
||||
|
||||
private int widgetAt(int mouseX) {
|
||||
final int i = getHoveredWidget(mouseX);
|
||||
final int widgetX = this.cachedPosX + (int) ((this.cachedSingleWidth + 2) * i);
|
||||
if (mouseX < widgetX || mouseX >= widgetX + (int) this.cachedSingleWidth) {
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(int mouseX, int mouseY, int button) {
|
||||
return this.widgets.get(getHoveredWidget(mouseX)).mouseClicked(mouseX, mouseY, button);
|
||||
final int i = widgetAt(mouseX);
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
return this.widgets.get(i).mouseClicked(mouseX, mouseY, button);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import net.coderbot.iris.gui.element.IrisElementRow;
|
||||
import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
@@ -60,13 +61,12 @@ public class HeaderEntry extends BaseEntry {
|
||||
|
||||
@Override
|
||||
public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int slotWidth, int slotHeight, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) {
|
||||
// Draw dividing line
|
||||
// fill(x - 3, (y + slotHeight) - 2, x + slotWidth, (y + slotHeight) - 1, 0x66BEBEBE);
|
||||
Gui.drawRect(x - 3, (y + slotHeight) - 3, x + slotWidth, (y + slotHeight) - 2, 0x66BEBEBE);
|
||||
final int tickDelta = 0;
|
||||
final FontRenderer font = Minecraft.getMinecraft().fontRenderer;
|
||||
|
||||
// Draw header text
|
||||
this.screen.drawCenteredString(font, text, x + (int) (slotWidth * 0.5), y + 5, 0xFFFFFF);
|
||||
GuiUtil.drawScrollingText(font, text, x + (int) (slotWidth * 0.5), x + 5,
|
||||
((x + slotWidth) - 10) - this.utilityButtons.getWidth(), y + 5, y + 15, 0xFFFFFF);
|
||||
|
||||
GuiUtil.bindIrisWidgetsTexture();
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package net.coderbot.iris.gui.element.shaderselection;
|
||||
|
||||
import net.coderbot.iris.gui.GuiUtil;
|
||||
import net.coderbot.iris.gui.element.ShaderPackSelectionList;
|
||||
import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
|
||||
/**
|
||||
* Show a download button when no shaderpacks exist in the shaderpacks folder.
|
||||
*/
|
||||
public class DownloadEntry extends BaseEntry {
|
||||
private final String label;
|
||||
private final String url;
|
||||
|
||||
public DownloadEntry(ShaderPackSelectionList list, String label, String url) {
|
||||
super(list);
|
||||
this.label = label;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public boolean click(ShaderPackScreen screen) {
|
||||
GuiUtil.playButtonClickSound();
|
||||
screen.openLinkConfirm(url);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) {
|
||||
GuiUtil.bindIrisWidgetsTexture();
|
||||
GuiUtil.drawButton(x - 2, y - 5, listWidth, 18, isMouseOver, false);
|
||||
screen.drawCenteredString(label, (x + listWidth / 2) - 2, y, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,6 @@ public class LabelEntry extends BaseEntry {
|
||||
|
||||
@Override
|
||||
public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) {
|
||||
screen.drawCenteredString(label, x, y, 0xFFFFFF);
|
||||
screen.drawCenteredString(label, (x + listWidth / 2) - 2, y, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.gui.element.shaderselection;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.coderbot.iris.gui.GuiUtil;
|
||||
import net.coderbot.iris.gui.element.ShaderPackSelectionList;
|
||||
import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
@@ -37,6 +38,8 @@ public class ShaderPackEntry extends BaseEntry {
|
||||
}
|
||||
|
||||
if(isMouseOver) {
|
||||
GuiUtil.bindIrisWidgetsTexture();
|
||||
GuiUtil.drawButton(x - 2, y - 6, listWidth, 20, true, false);
|
||||
name = EnumChatFormatting.BOLD + name;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,10 @@ public class TopButtonRowEntry extends BaseEntry {
|
||||
private static final String NONE_PRESENT_LABEL = I18n.format("options.iris.shaders.nonePresent"); //.withStyle(ChatFormatting.GRAY);
|
||||
private static final String SHADERS_DISABLED_LABEL = I18n.format("options.iris.shaders.disabled");
|
||||
private static final String SHADERS_ENABLED_LABEL = I18n.format("options.iris.shaders.enabled");
|
||||
private static final int REFRESH_BUTTON_WIDTH = 18;
|
||||
|
||||
private final ShaderPackSelectionList shaderPackSelectionList;
|
||||
private final IrisElementRow buttons = new IrisElementRow();
|
||||
private final EnableShadersButtonElement enableDisableButton;
|
||||
private final IrisElementRow.Element refreshPacksButton;
|
||||
|
||||
public boolean allowEnableShadersButton = true;
|
||||
public boolean shadersEnabled;
|
||||
@@ -38,15 +36,7 @@ public class TopButtonRowEntry extends BaseEntry {
|
||||
|
||||
return false;
|
||||
});
|
||||
this.refreshPacksButton = new IrisElementRow.IconButtonElement(
|
||||
GuiUtil.Icon.REFRESH,
|
||||
button -> {
|
||||
this.shaderPackSelectionList.refresh();
|
||||
|
||||
GuiUtil.playButtonClickSound();
|
||||
return true;
|
||||
});
|
||||
this.buttons.add(this.enableDisableButton, 0).add(this.refreshPacksButton, REFRESH_BUTTON_WIDTH);
|
||||
this.buttons.add(this.enableDisableButton, 0);
|
||||
}
|
||||
|
||||
public void setShadersEnabled(boolean shadersEnabled) {
|
||||
@@ -57,7 +47,7 @@ public class TopButtonRowEntry extends BaseEntry {
|
||||
|
||||
@Override
|
||||
public void drawEntry(ShaderPackScreen screen, int index, int x, int y, int listWidth, Tessellator tessellator, int mouseX, int mouseY, boolean isMouseOver) {
|
||||
this.buttons.setWidth(this.enableDisableButton, (listWidth - 1) - REFRESH_BUTTON_WIDTH);
|
||||
this.buttons.setWidth(this.enableDisableButton, listWidth);
|
||||
this.enableDisableButton.centerX = x + (int)(listWidth * 0.5);
|
||||
|
||||
this.buttons.drawScreen(x - 2, y - 3, 18, mouseX, mouseY, 0, isMouseOver);
|
||||
|
||||
@@ -90,9 +90,9 @@ public abstract class BaseOptionElementWidget<T extends OptionMenuElement> exten
|
||||
FontRenderer font = Minecraft.getMinecraft().fontRenderer;
|
||||
|
||||
// Draw the label
|
||||
font.drawStringWithShadow(this.trimmedLabel, x + 6, y + 7, 0xFFFFFF);
|
||||
font.drawStringWithShadow(this.trimmedLabel, x + 6, y + 7, this.isValueModified() ? 0xFFC94A : 0xFFFFFF);
|
||||
// Draw the value label
|
||||
font.drawStringWithShadow(this.valueLabel, (x + (width - 2)) - (int)(this.valueSectionWidth * 0.5) - (int)(font.getStringWidth(this.valueLabel) * 0.5), y + 7, 0xFFFFFF);
|
||||
font.drawStringWithShadow(this.valueLabel, (x + (width - 2)) - (int)(this.valueSectionWidth * 0.5) - (int)(font.getStringWidth(this.valueLabel) * 0.5), y + 7, getValueColor());
|
||||
}
|
||||
|
||||
protected final void renderOptionWithValue(int x, int y, int width, int height, boolean hovered) {
|
||||
@@ -119,17 +119,15 @@ public abstract class BaseOptionElementWidget<T extends OptionMenuElement> exten
|
||||
}
|
||||
|
||||
protected final String createTrimmedLabel() {
|
||||
String label = GuiUtil.shortenText(Minecraft.getMinecraft().fontRenderer, this.label, this.maxLabelWidth);
|
||||
|
||||
if (this.isValueModified()) {
|
||||
label = label + " (*)"; //.withStyle(style -> style.withColor(TextColor.fromRgb(0xffc94a)));
|
||||
}
|
||||
|
||||
return label;
|
||||
return GuiUtil.shortenText(Minecraft.getMinecraft().fontRenderer, this.label, this.maxLabelWidth);
|
||||
}
|
||||
|
||||
protected abstract String createValueLabel();
|
||||
|
||||
protected int getValueColor() {
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
|
||||
public abstract boolean applyNextValue();
|
||||
|
||||
public abstract boolean applyPreviousValue();
|
||||
@@ -147,7 +145,13 @@ public abstract class BaseOptionElementWidget<T extends OptionMenuElement> exten
|
||||
|
||||
@Override
|
||||
public Optional<String> getCommentBody() {
|
||||
return Optional.ofNullable(getCommentKey()).map(I18n::format);
|
||||
final String key = getCommentKey();
|
||||
if (key == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
final String translated = GuiUtil.translateLenient(key);
|
||||
// Don't show comment boxes without a translation, otherwise you get something like option.{commentname}.comment
|
||||
return translated.equals(key) ? Optional.empty() : Optional.of(translated);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,6 +70,14 @@ public class BooleanElementWidget extends BaseOptionElementWidget<OptionMenuBool
|
||||
return this.value ? TEXT_TRUE : TEXT_FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getValueColor() {
|
||||
if (this.value == this.defaultValue) {
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
return this.value ? 0x55FF55 : 0xFF5555;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommentKey() {
|
||||
return "option." + this.option.getName() + ".comment";
|
||||
|
||||
@@ -6,13 +6,10 @@ import net.coderbot.iris.gui.screen.ShaderPackScreen;
|
||||
import net.coderbot.iris.shaderpack.option.menu.OptionMenuLinkElement;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class LinkElementWidget extends CommentedElementWidget<OptionMenuLinkElement> {
|
||||
private static final String ARROW = new String(">");
|
||||
|
||||
private final String targetScreenId;
|
||||
private final String label;
|
||||
|
||||
@@ -39,7 +36,7 @@ public class LinkElementWidget extends CommentedElementWidget<OptionMenuLinkElem
|
||||
|
||||
final FontRenderer font = Minecraft.getMinecraft().fontRenderer;
|
||||
|
||||
final int maxLabelWidth = width - 9;
|
||||
final int maxLabelWidth = width - 6;
|
||||
|
||||
if (font.getStringWidth(this.label) > maxLabelWidth) {
|
||||
this.isLabelTrimmed = true;
|
||||
@@ -51,8 +48,7 @@ public class LinkElementWidget extends CommentedElementWidget<OptionMenuLinkElem
|
||||
|
||||
int labelWidth = font.getStringWidth(this.trimmedLabel);
|
||||
|
||||
font.drawStringWithShadow(this.trimmedLabel, x + (int)(width * 0.5) - (int)(labelWidth * 0.5) - (int)(0.5 * Math.max(labelWidth - (width - 18), 0)), y + 7, 0xFFFFFF);
|
||||
font.drawString(ARROW, (x + width) - 9, y + 7, 0xFFFFFF);
|
||||
font.drawStringWithShadow(this.trimmedLabel, x + (int)(width * 0.5) - (int)(labelWidth * 0.5), y + 7, 0xFFFFFF);
|
||||
|
||||
if (hovered && this.isLabelTrimmed) {
|
||||
// To prevent other elements from being drawn on top of the tooltip
|
||||
@@ -79,7 +75,7 @@ public class LinkElementWidget extends CommentedElementWidget<OptionMenuLinkElem
|
||||
@Override
|
||||
public Optional<String> getCommentBody() {
|
||||
final String translation = "screen." + this.targetScreenId + ".comment";
|
||||
final String translated = I18n.format(translation);
|
||||
return Optional.ofNullable(!translated.equals(translation) ? I18n.format(translation) : null);
|
||||
final String translated = GuiUtil.translateLenient(translation);
|
||||
return Optional.ofNullable(!translated.equals(translation) ? translated : null);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.coderbot.iris.gui.element.widget;
|
||||
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.coderbot.iris.gui.GuiUtil;
|
||||
import net.coderbot.iris.gui.NavigationController;
|
||||
import net.coderbot.iris.gui.element.ShaderPackOptionList;
|
||||
@@ -64,7 +65,7 @@ public final class OptionMenuConstructor {
|
||||
|
||||
static {
|
||||
registerScreen(OptionMenuMainElementScreen.class, screen ->
|
||||
new ElementWidgetScreenData(Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : ""), false));
|
||||
new ElementWidgetScreenData(EnumChatFormatting.BOLD + Iris.getCurrentPackName() + (Iris.isFallback() ? " (fallback)" : ""), false));
|
||||
|
||||
registerScreen(OptionMenuSubElementScreen.class, screen ->
|
||||
new ElementWidgetScreenData(GuiUtil.translateOrDefault(new String(screen.screenId), "screen." + screen.screenId), true));
|
||||
|
||||
@@ -59,6 +59,11 @@ public class ProfileElementWidget extends BaseOptionElementWidget<OptionMenuProf
|
||||
return this.profileLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getValueColor() {
|
||||
return PROFILE_CUSTOM.equals(this.profileLabel) ? 0xFFFF55 : 0xFFFFFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getCommentTitle() {
|
||||
return Optional.of(PROFILE_LABEL);
|
||||
|
||||
@@ -108,7 +108,7 @@ public class SliderElementWidget extends StringElementWidget {
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(double mx, double my, int button) {
|
||||
if (button == 0) {
|
||||
if (button == 0 && this.mouseDown) {
|
||||
this.onReleased();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -60,6 +60,11 @@ public class StringElementWidget extends BaseOptionElementWidget<OptionMenuStrin
|
||||
return GuiUtil.translateOrDefault(getValue(), "value." + this.option.getName() + "." + getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getValueColor() {
|
||||
return 0x6688FF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommentKey() {
|
||||
return "option." + this.option.getName() + ".comment";
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.coderbot.iris.gui.screen;
|
||||
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gui.GuiUtil;
|
||||
import net.coderbot.iris.gui.NavigationController;
|
||||
@@ -16,8 +17,12 @@ import net.coderbot.iris.shaderpack.ShaderPack;
|
||||
import net.irisshaders.iris.api.v0.IrisApi;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiConfirmOpenLink;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiYesNo;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
import net.minecraft.util.Util;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
@@ -25,12 +30,19 @@ import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -41,8 +53,8 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
*/
|
||||
public static final Set<Runnable> TOP_LAYER_RENDER_QUEUE = new HashSet<>();
|
||||
|
||||
private static final String SELECT_TITLE = I18n.format("pack.iris.select.title");
|
||||
private static final String CONFIGURE_TITLE = I18n.format("pack.iris.configure.title");
|
||||
private static final String SELECT_TITLE = EnumChatFormatting.GRAY.toString() + EnumChatFormatting.ITALIC + I18n.format("pack.iris.select.title");
|
||||
private static final String CONFIGURE_TITLE = EnumChatFormatting.GRAY.toString() + EnumChatFormatting.ITALIC + I18n.format("pack.iris.configure.title");
|
||||
private static final int COMMENT_PANEL_WIDTH = 314;
|
||||
|
||||
private final GuiScreen parent;
|
||||
@@ -72,7 +84,6 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
|
||||
private boolean guiHidden = false;
|
||||
private boolean dirty = false;
|
||||
private float guiButtonHoverTimer = 0.0f;
|
||||
|
||||
public ShaderPackScreen(GuiScreen parent) {
|
||||
this.title = I18n.format("options.iris.shaderPackSelection.title");
|
||||
@@ -102,6 +113,8 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
this.initGui();
|
||||
}
|
||||
|
||||
handleDroppedFiles();
|
||||
|
||||
if (this.mc.theWorld == null) {
|
||||
super.drawDefaultBackground();
|
||||
} else if (!this.guiHidden) {
|
||||
@@ -122,11 +135,7 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
hoveredElementCommentTimer = 0;
|
||||
}
|
||||
|
||||
final float previousHoverTimer = this.guiButtonHoverTimer;
|
||||
super.drawScreen(mouseX, mouseY, delta);
|
||||
if (previousHoverTimer == this.guiButtonHoverTimer) {
|
||||
this.guiButtonHoverTimer = 0.0f;
|
||||
}
|
||||
|
||||
if (!this.guiHidden) {
|
||||
drawCenteredString(this.fontRendererObj, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF);
|
||||
@@ -143,12 +152,9 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
|
||||
// Draw the comment panel
|
||||
if (this.isDisplayingComment()) {
|
||||
// Determine panel height and position
|
||||
final int panelHeight = Math.max(50, 18 + (this.hoveredElementCommentBody.size() * 10));
|
||||
int x = mouseX + 5;
|
||||
if (x + 314 >= (this.width - 4)) x = this.width - (318);
|
||||
int y = mouseY + 8;
|
||||
if (y + panelHeight >= (this.height - 4)) y = this.height - (panelHeight + 4);
|
||||
final int x = (int) (0.5 * this.width) - 157;
|
||||
final int y = this.height - (panelHeight + 4);
|
||||
// Draw panel
|
||||
GuiUtil.drawPanel(x, y, COMMENT_PANEL_WIDTH, panelHeight);
|
||||
// Draw text
|
||||
@@ -181,10 +187,21 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
|
||||
BackendManager.RENDER_BACKEND.startFileDrop();
|
||||
|
||||
final int bottomCenter = this.width / 2 - 50;
|
||||
final int topCenter = this.width / 2 - 76;
|
||||
final boolean inWorld = this.mc.theWorld != null;
|
||||
|
||||
if (this.shaderPackList != null) {
|
||||
try {
|
||||
this.shaderPackList.close();
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Failed to close previous shaderpack selection watcher!", e);
|
||||
}
|
||||
}
|
||||
|
||||
this.shaderPackList = new ShaderPackSelectionList(this, this.mc, this.width, this.height, 32, this.height - 58, 0, this.width);
|
||||
|
||||
if (Iris.getCurrentPack().isPresent() && this.navigation != null) {
|
||||
@@ -339,12 +356,30 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
public void refreshScreenSwitchButton() {
|
||||
if (this.screenSwitchButton != null) {
|
||||
this.screenSwitchButton.displayString = optionMenuOpen ? I18n.format("options.iris.shaderPackList") : I18n.format("options.iris.shaderPackSettings");
|
||||
this.screenSwitchButton.enabled = optionMenuOpen || shaderPackList.getTopButtonRow().shadersEnabled;
|
||||
// Disable the settings switch when shaders are off or the selected pack exposes no options
|
||||
this.screenSwitchButton.enabled = optionMenuOpen || (shaderPackList.getTopButtonRow().shadersEnabled
|
||||
&& Iris.getCurrentPack().map(p -> !p.getMenuContainer().mainScreen.elements.isEmpty()).orElse(true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) {
|
||||
if (GuiScreen.isCtrlKeyDown() && keyCode == Keyboard.KEY_D) {
|
||||
this.mc.displayGuiScreen(new GuiYesNo((result, id) -> {
|
||||
Iris.setDebug(result);
|
||||
this.mc.displayGuiScreen(this);
|
||||
}, "Shader debug mode toggle",
|
||||
"Debug mode helps investigate problems and shows shader errors. Would you like to enable it?", 0));
|
||||
return;
|
||||
}
|
||||
if (GuiScreen.isCtrlKeyDown() && keyCode == Keyboard.KEY_G) {
|
||||
this.mc.displayGuiScreen(new GuiYesNo((result, id) -> {
|
||||
Iris.setAllowUnknownShaders(result);
|
||||
this.mc.displayGuiScreen(this);
|
||||
}, "Unknown shader toggle",
|
||||
"This allows unknown shaders to load in.", 0));
|
||||
return;
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
if (this.guiHidden) {
|
||||
this.guiHidden = false;
|
||||
@@ -359,6 +394,21 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_F1 && this.mc.theWorld != null) {
|
||||
this.guiHidden = !this.guiHidden;
|
||||
this.initGui();
|
||||
return;
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_TAB) {
|
||||
final boolean canOpenOptions = shaderPackList.getTopButtonRow().shadersEnabled
|
||||
&& Iris.getCurrentPack().map(p -> !p.getMenuContainer().mainScreen.elements.isEmpty()).orElse(false);
|
||||
if (this.optionMenuOpen || canOpenOptions) {
|
||||
this.optionMenuOpen = !this.optionMenuOpen;
|
||||
this.applyChanges();
|
||||
this.initGui();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
@@ -367,6 +417,84 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
this.notificationDialogTimer = 100;
|
||||
}
|
||||
|
||||
private void handleDroppedFiles() {
|
||||
final List<String> dropped = BackendManager.RENDER_BACKEND.pollDroppedFiles();
|
||||
if (dropped.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
final List<Path> paths = dropped.stream().map(Paths::get).collect(Collectors.toList());
|
||||
if (this.optionMenuOpen) {
|
||||
onOptionMenuFilesDrop(paths);
|
||||
} else {
|
||||
onPackListFilesDrop(paths);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPackListFilesDrop(List<Path> paths) {
|
||||
final List<Path> packs = paths.stream().filter(Iris::isValidShaderpack).toList();
|
||||
|
||||
for (Path pack : packs) {
|
||||
final String fileName = pack.getFileName().toString();
|
||||
try {
|
||||
Iris.getShaderpacksDirectoryManager().copyPackIntoDirectory(fileName, pack);
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.copyErrorAlreadyExists", fileName));
|
||||
this.shaderPackList.refresh();
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
Iris.logger.warn("Error copying dragged shader pack", e);
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.copyError", fileName));
|
||||
this.shaderPackList.refresh();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// After copying, refresh the list so the new packs show up
|
||||
this.shaderPackList.refresh();
|
||||
|
||||
if (packs.isEmpty()) {
|
||||
if (paths.size() == 1) {
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.failedAddSingle", paths.getFirst().getFileName().toString()));
|
||||
} else {
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.failedAdd"));
|
||||
}
|
||||
} else if (packs.size() == 1) {
|
||||
final String packName = packs.getFirst().getFileName().toString();
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.addedPack", packName));
|
||||
// Select the freshly-added pack, since the user probably wants to use it
|
||||
this.shaderPackList.select(packName);
|
||||
} else {
|
||||
displayNotification(I18n.format("options.iris.shaderPackSelection.addedPacks", packs.size()));
|
||||
}
|
||||
}
|
||||
|
||||
public void onOptionMenuFilesDrop(List<Path> paths) {
|
||||
// Only one settings file should be imported at a time
|
||||
if (paths.size() != 1) {
|
||||
displayNotification(I18n.format("options.iris.shaderPackOptions.tooManyFiles"));
|
||||
return;
|
||||
}
|
||||
importPackOptions(paths.getFirst());
|
||||
}
|
||||
|
||||
public void importPackOptions(Path settingFile) {
|
||||
try (InputStream in = Files.newInputStream(settingFile)) {
|
||||
final Properties properties = new Properties();
|
||||
properties.load(in);
|
||||
|
||||
Iris.queueShaderPackOptionsFromProperties(properties);
|
||||
|
||||
displayNotification(I18n.format("options.iris.shaderPackOptions.importedSettings", settingFile.getFileName().toString()));
|
||||
|
||||
if (this.navigation != null) {
|
||||
this.navigation.refresh();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Iris.logger.error("Error importing shader settings file \"" + settingFile + "\"", e);
|
||||
displayNotification(I18n.format("options.iris.shaderPackOptions.failedImport", settingFile.getFileName().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public void onClose() {
|
||||
if (!dropChanges) {
|
||||
applyChanges();
|
||||
@@ -377,6 +505,19 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
this.mc.displayGuiScreen(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
BackendManager.RENDER_BACKEND.stopFileDrop();
|
||||
|
||||
if (this.shaderPackList != null) {
|
||||
try {
|
||||
this.shaderPackList.close();
|
||||
} catch (IOException e) {
|
||||
Iris.logger.error("Failed to safely close shaderpack selection!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dropChangesAndClose() {
|
||||
dropChanges = true;
|
||||
onClose();
|
||||
@@ -419,8 +560,29 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
CompletableFuture.runAsync(() -> openUri(Iris.getShaderpacksDirectoryManager().getDirectoryUri()));
|
||||
}
|
||||
|
||||
public void openLinkConfirm(String url) {
|
||||
this.mc.displayGuiScreen(new GuiConfirmOpenLink((result, id) -> {
|
||||
if (result) {
|
||||
try {
|
||||
openUri(new URI(url));
|
||||
} catch (URISyntaxException e) {
|
||||
Iris.logger.error("Invalid shader download URL: " + url, e);
|
||||
}
|
||||
}
|
||||
this.mc.displayGuiScreen(this);
|
||||
}, url, 0, true) {
|
||||
@Override
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
for (int i = 0; i < this.buttonList.size(); i++) {
|
||||
this.buttonList.get(i).xPosition = this.width / 2 - 155 + i * 105;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void openUri(URI uri) {
|
||||
switch (net.minecraft.util.Util.getOSType()) {
|
||||
switch (Util.getOSType()) {
|
||||
case OSX -> {
|
||||
try {
|
||||
Runtime.getRuntime().exec(new String[] { "/usr/bin/open", uri.toString() });
|
||||
@@ -452,7 +614,7 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
|
||||
try {
|
||||
final Class<?> aClass = Class.forName("java.awt.Desktop");
|
||||
final Object getDesktop = aClass.getMethod("getDesktop").invoke((Object) null);
|
||||
final Object getDesktop = aClass.getMethod("getDesktop").invoke(null);
|
||||
aClass.getMethod("browse", URI.class).invoke(getDesktop, uri);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -475,17 +637,17 @@ public class ShaderPackScreen extends GuiScreen implements HudHideable {
|
||||
this.hoveredElementCommentTitle = ((CommentedElementWidget<?>) widget).getCommentTitle();
|
||||
|
||||
Optional<String> commentBody = ((CommentedElementWidget<?>) widget).getCommentBody();
|
||||
if (!commentBody.isPresent()) {
|
||||
if (commentBody.isEmpty()) {
|
||||
this.hoveredElementCommentBody.clear();
|
||||
} else {
|
||||
String rawCommentBody = commentBody.get();
|
||||
|
||||
// Strip any trailing "."s
|
||||
// Strip any trailing periods
|
||||
if (rawCommentBody.endsWith(".")) {
|
||||
rawCommentBody = rawCommentBody.substring(0, rawCommentBody.length() - 1);
|
||||
}
|
||||
// Split comment body into lines by separator ". "
|
||||
List<String> splitByPeriods = Arrays.stream(rawCommentBody.split("\\. [ ]*")).map(String::new).collect(Collectors.toList());
|
||||
List<String> splitByPeriods = Arrays.stream(rawCommentBody.split("\\. +")).toList();
|
||||
// Line wrap
|
||||
this.hoveredElementCommentBody = new ArrayList<>();
|
||||
for (String text : splitByPeriods) {
|
||||
|
||||
@@ -90,6 +90,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -394,6 +395,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
null, null, ProgramId.Weather,
|
||||
// world border uses textured_lit even though it has no lightmap :/
|
||||
null, ProgramId.TexturedLit, ProgramId.TexturedLit,
|
||||
ProgramId.Lightning, ProgramId.Lightning, ProgramId.Lightning,
|
||||
ProgramId.ShadowWater, ProgramId.ShadowWater, ProgramId.ShadowWater,
|
||||
ProgramId.Shadow, ProgramId.Shadow, ProgramId.Shadow
|
||||
};
|
||||
@@ -517,7 +519,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
if (hasSetup) {
|
||||
ComputeProgram.unbind();
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
// Terrain pipeline sampler/image factory setup follows.
|
||||
@@ -723,6 +725,8 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
return RenderCondition.ENTITY_EYES;
|
||||
} else if (special == SpecialCondition.GLINT) {
|
||||
return RenderCondition.GLINT;
|
||||
} else if (special == SpecialCondition.LIGHTNING) {
|
||||
return RenderCondition.LIGHTNING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,11 +775,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
public boolean shouldOverrideShaders() {
|
||||
return isRenderingWorld && !isRenderingFullScreenPass && !isPostChain && isMainBound;
|
||||
}
|
||||
|
||||
|
||||
public Pass getActivePassProgram() {
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public int getActivePassProgramId() {
|
||||
if (current == null) return -1;
|
||||
final Program p = current.getProgram();
|
||||
@@ -793,10 +797,10 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
if (!isRenderingWorld || isRenderingFullScreenPass || isPostChain || !isMainBound) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final RenderCondition condition = getCondition(getPhase());
|
||||
final Pass matched = table.match(condition, inputs);
|
||||
|
||||
|
||||
beginPass(matched);
|
||||
}
|
||||
|
||||
@@ -1332,7 +1336,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
}
|
||||
if (ranSetup) {
|
||||
ComputeProgram.unbind();
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1593,6 +1597,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
|
||||
this.customUniforms.update();
|
||||
|
||||
// Make sure SSBO is bound
|
||||
if (ssboHolder != null) {
|
||||
ssboHolder.setupBuffers();
|
||||
}
|
||||
|
||||
// Get ready for world rendering
|
||||
prepareRenderTargets();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.coderbot.iris.pipeline;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.InteractionHand;
|
||||
import com.gtnewhorizons.angelica.event.RenderHandEvent;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.BlockRenderLayer;
|
||||
@@ -78,7 +79,8 @@ public class HandRenderer {
|
||||
!camera.isSleeping() &&
|
||||
!mc.gameSettings.hideGUI &&
|
||||
!GameModeUtil.isSpectator() &&
|
||||
!mc.playerController.enableEverythingIsScrewedUpMode();
|
||||
!mc.playerController.enableEverythingIsScrewedUpMode() &&
|
||||
!RenderHandEvent.post();
|
||||
}
|
||||
|
||||
public boolean isHandTranslucent(InteractionHand hand) {
|
||||
|
||||
@@ -34,7 +34,7 @@ class AttributeTransformer {
|
||||
transformer.injectVariable("layout(location = 4) in vec3 iris_Normal;");
|
||||
|
||||
transformer.rename("gl_Vertex", "iris_Vertex");
|
||||
transformer.rename("gl_Color", "iris_Color");
|
||||
transformer.replaceExpression("gl_Color", "(iris_Color * iris_ColorModulator)");
|
||||
transformer.rename("gl_Normal", "iris_Normal");
|
||||
|
||||
// ftransform() = gl_ModelViewProjectionMatrix * gl_Vertex
|
||||
|
||||
@@ -34,6 +34,7 @@ class CeleritasTransformer {
|
||||
transformer.injectFunction(
|
||||
"void _celeritas_init() { " +
|
||||
"_vert_init(); " +
|
||||
"_vert_color = _vert_color * iris_ColorModulator; " +
|
||||
"iris_LightTexCoord = vec4(vec2(_vert_tex_light_coord), 0.0, 1.0); }");
|
||||
transformer.prependMain("_celeritas_init();");
|
||||
transformShared(transformer, parameters);
|
||||
@@ -60,6 +61,7 @@ class CeleritasTransformer {
|
||||
}
|
||||
|
||||
private static void transformShared(Transformer transformer, Parameters parameters) {
|
||||
transformer.replaceExpression("gl_TextureMatrix[0]", "mat4(1.0)");
|
||||
CoreTransformHelper.injectMatrixUniforms(transformer);
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,10 @@ public class CommonTransformer {
|
||||
}
|
||||
|
||||
if (parameters.type == ShaderType.VERTEX) {
|
||||
root.injectVariable("uniform vec4 iris_ColorModulator;");
|
||||
root.injectVariable("out vec4 iris_FrontColor;");
|
||||
root.rename("gl_FrontColor", "iris_FrontColor");
|
||||
root.prependMain("iris_FrontColor = vec4(1.0);");
|
||||
root.prependMain("iris_FrontColor = iris_ColorModulator;");
|
||||
} else if (parameters.type == ShaderType.FRAGMENT) {
|
||||
root.injectVariable("in vec4 iris_FrontColor;");
|
||||
root.rename("gl_Color", "iris_FrontColor");
|
||||
|
||||
@@ -94,7 +94,7 @@ public class DHGenericTransformer {
|
||||
+ " float skyLight = (float(uSkyLight) + 0.5) / 16.0;"
|
||||
+ " _vert_tex_light_coord = vec2(blockLight, skyLight);"
|
||||
+ " dhMaterialId = aMaterial;"
|
||||
+ " _vert_color = iris_color;"
|
||||
+ " _vert_color = iris_color * iris_ColorModulator;"
|
||||
+ " }"
|
||||
);
|
||||
transformer.prependMain("_vert_init();");
|
||||
|
||||
@@ -86,7 +86,7 @@ public class DHTerrainTransformer {
|
||||
+ " _vert_normal = irisNormals[int(irisExtra.y)];"
|
||||
+ " dhMaterialId = int(irisExtra.x);"
|
||||
+ " _vert_tex_light_coord = vec2((float(lights / 16u) + 0.5) / 16.0, (mod(float(lights), 16.0) + 0.5) / 16.0);"
|
||||
+ " _vert_color = iris_color;"
|
||||
+ " _vert_color = iris_color * iris_ColorModulator;"
|
||||
+ " }"
|
||||
);
|
||||
transformer.prependMain("_vert_init();");
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -263,7 +264,7 @@ public class CompositeRenderer {
|
||||
}
|
||||
|
||||
if (ranCompute) {
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
}
|
||||
|
||||
Program.unbind();
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL42;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -229,7 +230,7 @@ public class FinalPassRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT);
|
||||
RenderSystem.memoryBarrier(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL42.GL_TEXTURE_FETCH_BARRIER_BIT | GL43.GL_SHADER_STORAGE_BARRIER_BIT);
|
||||
|
||||
if (!finalPass.mipmappedBuffers.isEmpty()) {
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
|
||||
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user