diff --git a/.github/workflows/build-commit.yml b/.github/workflows/build-commit.yml
index 80f3152c9d..7ac5e33f8a 100644
--- a/.github/workflows/build-commit.yml
+++ b/.github/workflows/build-commit.yml
@@ -35,7 +35,9 @@ jobs:
run: ./gradlew build
- name: Upload artifacts
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v4
with:
name: sodium-artifacts-${{ steps.ref.outputs.branch }}
- path: build/libs/*.jar
\ No newline at end of file
+ path: |
+ neoforge/build/libs/*.jar
+ fabric/build/libs/*.jar
diff --git a/.gitignore b/.gitignore
index 01ca5bc812..69cd50978c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,7 +23,7 @@ bin/
# fabric
run/
-
+neoforge/runs
# macOS
.DS_Store
diff --git a/README.md b/README.md
index ee4676b337..4d5c52fb8a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
-# Sodium (for Fabric)
+# Sodium
Sodium is a powerful rendering engine and optimization mod for the Minecraft client which improves frame rates and reduces
micro-stutter, while fixing many graphical issues in Minecraft.
diff --git a/build.gradle.kts b/build.gradle.kts
index 6c4f79e62d..0fe9eeaf56 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,145 +1,75 @@
-object Constants {
- // https://fabricmc.net/develop/
- const val MINECRAFT_VERSION: String = "1.21"
- const val FABRIC_LOADER_VERSION: String = "0.16.0"
- const val FABRIC_API_VERSION: String = "0.100.7+1.21"
-
- // https://semver.org/
- const val MOD_VERSION: String = "0.6.0"
-}
-
plugins {
- // Unlike most projects, we choose to pin the specific version of Loom.
- // This prevents a lot of issues where the build script can fail randomly because the Fabric Maven server
- // is not reachable for some reason, and it makes builds much more reproducible. Observation also shows that it
- // really helps to improve startup times on slow connections.
- id("fabric-loom") version "1.7.2"
+ id("java")
+ id("fabric-loom") version ("1.7.3") apply (false)
}
-base {
- archivesName = "sodium-fabric"
+val MINECRAFT_VERSION by extra { "1.21" }
+val NEOFORGE_VERSION by extra { "21.0.147" }
+val FABRIC_LOADER_VERSION by extra { "0.16.0" }
+val FABRIC_API_VERSION by extra { "0.100.4+1.21" }
- group = "net.caffeinemc.mods"
- version = createVersionString()
-}
+// This value can be set to null to disable Parchment.
+val PARCHMENT_VERSION by extra { "2024.07.28" }
-loom {
- mixin {
- defaultRefmapName = "sodium.refmap.json"
- }
+// https://semver.org/
+val MOD_VERSION by extra { "0.6.0" }
- accessWidenerPath = file("src/main/resources/sodium.accesswidener")
+allprojects {
+ apply(plugin = "java")
+ apply(plugin = "maven-publish")
}
-java {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
+tasks.withType {
+ options.encoding = "UTF-8"
}
-sourceSets {
- val main = getByName("main")
- val api = create("api")
- val desktop = create("desktop")
+subprojects {
+ apply(plugin = "maven-publish")
- api.apply {
- java {
- compileClasspath += main.compileClasspath
- }
- }
+ java.toolchain.languageVersion = JavaLanguageVersion.of(21)
- desktop.apply {
- java {
- srcDir("src/desktop/java")
- }
- }
- main.apply {
- java {
- compileClasspath += api.output
- runtimeClasspath += api.output
- }
- }
-}
+ fun createVersionString(): String {
+ val builder = StringBuilder()
-dependencies {
- minecraft(group = "com.mojang", name = "minecraft", version = Constants.MINECRAFT_VERSION)
- mappings(loom.officialMojangMappings())
- modImplementation(group = "net.fabricmc", name = "fabric-loader", version = Constants.FABRIC_LOADER_VERSION)
- include(implementation(group = "com.lodborg", name = "interval-tree", version = "1.0.0"))
-
- fun addEmbeddedFabricModule(name: String) {
- val module = fabricApi.module(name, Constants.FABRIC_API_VERSION)
- modImplementation(module)
- include(module)
- }
-
- // Fabric API modules
- addEmbeddedFabricModule("fabric-api-base")
- addEmbeddedFabricModule("fabric-block-view-api-v2")
- addEmbeddedFabricModule("fabric-renderer-api-v1")
- addEmbeddedFabricModule("fabric-rendering-data-attachment-v1")
- addEmbeddedFabricModule("fabric-rendering-fluids-v1")
- addEmbeddedFabricModule("fabric-resource-loader-v0")
-}
+ val isReleaseBuild = project.hasProperty("build.release")
+ val buildId = System.getenv("GITHUB_RUN_NUMBER")
-tasks {
- getByName("compileDesktopJava") {
- sourceCompatibility = JavaVersion.VERSION_1_8.toString()
- targetCompatibility = JavaVersion.VERSION_1_8.toString()
- }
-
- jar {
- from("${rootProject.projectDir}/LICENSE.md")
+ if (isReleaseBuild) {
+ builder.append(MOD_VERSION)
+ } else {
+ builder.append(MOD_VERSION.substringBefore('-'))
+ builder.append("-snapshot")
+ }
- val api = sourceSets.getByName("api")
- from(api.output.classesDirs)
- from(api.output.resourcesDir)
+ builder.append("+mc").append(MINECRAFT_VERSION)
- val desktop = sourceSets.getByName("desktop")
- from(desktop.output.classesDirs)
- from(desktop.output.resourcesDir)
+ if (!isReleaseBuild) {
+ if (buildId != null) {
+ builder.append("-build.${buildId}")
+ } else {
+ builder.append("-local")
+ }
+ }
- manifest.attributes["Main-Class"] = "net.caffeinemc.mods.sodium.desktop.LaunchWarn"
+ return builder.toString()
}
- processResources {
- inputs.property("version", project.version)
-
- filesMatching("fabric.mod.json") {
- expand(mapOf("version" to project.version))
+ tasks.processResources {
+ filesMatching("META-INF/neoforge.mods.toml") {
+ expand(mapOf("version" to createVersionString()))
}
}
-}
-
-// ensure that the encoding is set to UTF-8, no matter what the system default is
-// this fixes some edge cases with special characters not displaying correctly
-// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
-tasks.withType {
- options.encoding = "UTF-8"
-}
-
-fun createVersionString(): String {
- val builder = StringBuilder()
- val isReleaseBuild = project.hasProperty("build.release")
- val buildId = System.getenv("GITHUB_RUN_NUMBER")
+ version = createVersionString()
+ group = "net.caffeinemc.mods"
- if (isReleaseBuild) {
- builder.append(Constants.MOD_VERSION)
- } else {
- builder.append(Constants.MOD_VERSION.substringBefore('-'))
- builder.append("-snapshot")
+ tasks.withType {
+ options.encoding = "UTF-8"
+ options.release.set(21)
}
- builder.append("+mc").append(Constants.MINECRAFT_VERSION)
-
- if (!isReleaseBuild) {
- if (buildId != null) {
- builder.append("-build.${buildId}")
- } else {
- builder.append("-local")
- }
+ tasks.withType().configureEach {
+ enabled = false
}
-
- return builder.toString()
}
diff --git a/common/build.gradle.kts b/common/build.gradle.kts
new file mode 100644
index 0000000000..f840ba1291
--- /dev/null
+++ b/common/build.gradle.kts
@@ -0,0 +1,119 @@
+plugins {
+ id("java")
+ id("idea")
+ id("fabric-loom") version ("1.7.3")
+}
+
+repositories {
+ maven("https://maven.parchmentmc.org/")
+}
+
+val MINECRAFT_VERSION: String by rootProject.extra
+val PARCHMENT_VERSION: String? by rootProject.extra
+val FABRIC_LOADER_VERSION: String by rootProject.extra
+val FABRIC_API_VERSION: String by rootProject.extra
+
+dependencies {
+ minecraft(group = "com.mojang", name = "minecraft", version = MINECRAFT_VERSION)
+ mappings(loom.layered() {
+ officialMojangMappings()
+ if (PARCHMENT_VERSION != null) {
+ parchment("org.parchmentmc.data:parchment-${MINECRAFT_VERSION}:${PARCHMENT_VERSION}@zip")
+ }
+ })
+ compileOnly("io.github.llamalad7:mixinextras-common:0.3.5")
+ annotationProcessor("io.github.llamalad7:mixinextras-common:0.3.5")
+ compileOnly("net.fabricmc:sponge-mixin:0.13.2+mixin.0.8.5")
+
+ fun addDependentFabricModule(name: String) {
+ val module = fabricApi.module(name, FABRIC_API_VERSION)
+ modCompileOnly(module)
+ }
+
+ addDependentFabricModule("fabric-api-base")
+ addDependentFabricModule("fabric-block-view-api-v2")
+ addDependentFabricModule("fabric-renderer-api-v1")
+ addDependentFabricModule("fabric-rendering-data-attachment-v1")
+
+ modCompileOnly("net.fabricmc.fabric-api:fabric-renderer-api-v1:3.2.9+1172e897d7")
+ implementation(group = "com.lodborg", name = "interval-tree", version = "1.0.0")
+}
+
+sourceSets {
+ val main = getByName("main")
+ val api = create("api")
+ val workarounds = create("workarounds")
+ val desktop = create("desktop")
+
+ api.apply {
+ java {
+ compileClasspath += main.compileClasspath
+ }
+ }
+
+ workarounds.apply {
+ java {
+ compileClasspath += main.compileClasspath
+ }
+ }
+
+ desktop.apply {
+ java {
+ srcDir("src/desktop/java")
+ }
+ }
+
+ main.apply {
+ java {
+ compileClasspath += api.output
+ compileClasspath += workarounds.output
+ runtimeClasspath += api.output
+ }
+ }
+}
+
+loom {
+ mixin {
+ defaultRefmapName = "sodium.refmap.json"
+ }
+
+ accessWidenerPath = file("src/main/resources/sodium.accesswidener")
+
+ mods {
+ val main by creating { // to match the default mod generated for Forge
+ sourceSet("api")
+ sourceSet("desktop")
+ sourceSet("main")
+ }
+ }
+}
+
+tasks {
+ getByName("compileDesktopJava") {
+ sourceCompatibility = JavaVersion.VERSION_1_8.toString()
+ targetCompatibility = JavaVersion.VERSION_1_8.toString()
+ }
+
+ jar {
+ from(rootDir.resolve("LICENSE.md"))
+
+ val api = sourceSets.getByName("api")
+ from(api.output.classesDirs)
+ from(api.output.resourcesDir)
+
+ val workarounds = sourceSets.getByName("workarounds")
+ from(workarounds.output.classesDirs)
+ from(workarounds.output.resourcesDir)
+
+ val desktop = sourceSets.getByName("desktop")
+ from(desktop.output.classesDirs)
+ from(desktop.output.resourcesDir)
+
+ manifest.attributes["Main-Class"] = "net.caffeinemc.mods.sodium.desktop.LaunchWarn"
+ }
+}
+
+// This trick hides common tasks in the IDEA list.
+tasks.configureEach {
+ group = null
+}
\ No newline at end of file
diff --git a/src/.gitignore b/common/src/.gitignore
similarity index 100%
rename from src/.gitignore
rename to common/src/.gitignore
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/internal/DependencyInjection.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/internal/package-info.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/internal/package-info.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/internal/package-info.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/internal/package-info.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java
similarity index 87%
rename from src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java
index 29dbb8afdc..12df8a23b8 100644
--- a/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java
+++ b/common/src/api/java/net/caffeinemc/mods/sodium/api/math/MatrixHelper.java
@@ -17,17 +17,26 @@
public class MatrixHelper {
/**
* @param mat The transformation matrix to apply to the normal
+ * @param skipNormalization Whether normalizing the vector is unnecessary
* @param x The X-coordinate of the normal vector
* @param y The Y-coordinate of the normal vector
* @param z The Z-coordinate of the normal vector
* @return The transformed normal vector (in packed format)
*/
- public static int transformNormal(Matrix3f mat, float x, float y, float z) {
+ public static int transformNormal(Matrix3f mat, boolean skipNormalization, float x, float y, float z) {
// The transformed normal vector
float nxt = transformNormalX(mat, x, y, z);
float nyt = transformNormalY(mat, x, y, z);
float nzt = transformNormalZ(mat, x, y, z);
+ if (!skipNormalization) {
+ float scalar = Math.invsqrt(Math.fma(nxt, nxt, Math.fma(nyt, nyt, nzt * nzt)));
+
+ nxt *= scalar;
+ nyt *= scalar;
+ nzt *= scalar;
+ }
+
return NormI8.pack(nxt, nyt, nzt);
}
@@ -36,13 +45,13 @@ public static int transformNormal(Matrix3f mat, float x, float y, float z) {
* @param norm The normal vector to transform (in packed format)
* @return The transformed normal vector (in packed format)
*/
- public static int transformNormal(Matrix3f mat, int norm) {
+ public static int transformNormal(Matrix3f mat, boolean skipNormalization, int norm) {
// The unpacked normal vector
float x = NormI8.unpackX(norm);
float y = NormI8.unpackY(norm);
float z = NormI8.unpackZ(norm);
- return transformNormal(mat, x, y, z);
+ return transformNormal(mat, skipNormalization, x, y, z);
}
/**
@@ -129,6 +138,15 @@ public static void rotateZYX(PoseStack.Pose matrices, float angleZ, float angleY
.rotateZYX(angleZ, angleY, angleX);
}
+ /**
+ * Returns the transformed normal vector for a given unit vector (direction). This is significantly faster
+ * than transforming the vector directly (i.e. with {@link Matrix3f#transform(Vector3f)}), as it can simply
+ * extract the values from the provided matrix (rather than transforming the vertices.)
+ *
+ * @param matrix The transformation matrix
+ * @param direction The unit vector (direction) to use
+ * @return A transformed normal in packed format
+ */
/**
* Returns the transformed normal vector for a given unit vector (direction). This is significantly faster
* than transforming the vector directly (i.e. with {@link Matrix3f#transform(Vector3f)}), as it can simply
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/memory/MemoryIntrinsics.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/memory/MemoryIntrinsics.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/memory/MemoryIntrinsics.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/memory/MemoryIntrinsics.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorABGR.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorABGR.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/util/ColorABGR.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorABGR.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java
similarity index 93%
rename from src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java
index d4a48cac2a..f93880555e 100644
--- a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java
+++ b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorARGB.java
@@ -72,6 +72,13 @@ public static int unpackBlue(int color) {
return color >> BLUE_COMPONENT_OFFSET & COMPONENT_MASK;
}
+ /**
+ * Re-packs the ARGB color into an ABGR color with the specified alpha component.
+ */
+ public static int toABGR(int color, float alpha) {
+ return Integer.reverseBytes(color << 8 | ColorU8.normalizedFloatToByte(alpha));
+ }
+
/**
* Re-packs the ARGB color into a aBGR color with the specified alpha component.
*/
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java
similarity index 83%
rename from src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java
index a81f00ccc6..a2cd74e5de 100644
--- a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java
+++ b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorMixer.java
@@ -59,4 +59,19 @@ public static int mul(int a, int b) {
// Pack the components
return (c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24);
}
+
+ /**
+ * Multiplies the 32-bit colors with one component
+ */
+ public static int mulSingle(int a, byte b) {
+ // Take each 8-bit component pair, multiply them together to create intermediate 16-bit integers,
+ // and then shift the high half of each 16-bit integer into 8-bit integers.
+ int c0 = (((a) & 0xFF) * b) >> 8;
+ int c1 = (((a >> 8) & 0xFF) * b) >> 8;
+ int c2 = (((a >> 16) & 0xFF) * b) >> 8;
+ int c3 = (((a >> 24) & 0xFF) * b) >> 8;
+
+ // Pack the components
+ return (c0 << 0) | (c1 << 8) | (c2 << 16) | (c3 << 24);
+ }
}
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorU8.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorU8.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/util/ColorU8.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/util/ColorU8.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java
similarity index 96%
rename from src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java
index 7dc0b68c34..a84597d247 100644
--- a/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java
+++ b/common/src/api/java/net/caffeinemc/mods/sodium/api/util/NormI8.java
@@ -1,6 +1,7 @@
package net.caffeinemc.mods.sodium.api.util;
import net.minecraft.util.Mth;
+import org.joml.Vector3f;
import org.joml.Vector3fc;
/**
@@ -114,4 +115,8 @@ public static boolean isOpposite(int normA, int normB) {
return normAX == -normBX && normAY == -normBY && normAZ == -normBZ;
}
+
+ public static Vector3f unpack(int i, Vector3f output) {
+ return output.set(unpackX(i), unpackY(i), unpackZ(i));
+ }
}
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/CommonVertexAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/ColorAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/ColorAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/ColorAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/ColorAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/LightAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/LightAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/LightAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/LightAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/NormalAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/NormalAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/NormalAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/NormalAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/OverlayAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/OverlayAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/OverlayAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/OverlayAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/PositionAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/PositionAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/PositionAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/PositionAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/TextureAttribute.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/TextureAttribute.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/TextureAttribute.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/attributes/common/TextureAttribute.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/buffer/VertexBufferWriter.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatDescription.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatDescription.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatDescription.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatDescription.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/VertexFormatRegistry.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ColorVertex.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/GlyphVertex.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/LineVertex.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ModelVertex.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/format/common/ParticleVertex.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializer.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializer.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializer.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializer.java
diff --git a/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java b/common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java
similarity index 100%
rename from src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java
rename to common/src/api/java/net/caffeinemc/mods/sodium/api/vertex/serializer/VertexSerializerRegistry.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/LaunchWarn.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/LaunchWarn.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/LaunchWarn.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/LaunchWarn.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/BrowseUrlHandler.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/BrowseUrlHandler.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/BrowseUrlHandler.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/BrowseUrlHandler.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/CrossPlatformImpl.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/CrossPlatformImpl.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/CrossPlatformImpl.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/CrossPlatformImpl.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/GNOMEImpl.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/GNOMEImpl.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/GNOMEImpl.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/GNOMEImpl.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/KDEImpl.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/KDEImpl.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/KDEImpl.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/KDEImpl.java
diff --git a/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl.java b/common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl.java
similarity index 100%
rename from src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl.java
rename to common/src/desktop/java/net/caffeinemc/mods/sodium/desktop/utils/browse/XDGImpl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java
similarity index 68%
rename from src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java
index 54f735464d..9dba7b3641 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/SodiumClientMod.java
@@ -3,44 +3,25 @@
import net.caffeinemc.mods.sodium.client.data.fingerprint.FingerprintMeasure;
import net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint;
import net.caffeinemc.mods.sodium.client.gui.SodiumGameOptions;
-import net.caffeinemc.mods.sodium.client.gui.console.Console;
-import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel;
-import net.caffeinemc.mods.sodium.client.render.frapi.SpriteFinderCache;
-import net.caffeinemc.mods.sodium.client.util.FlawlessFrames;
-import net.fabricmc.api.ClientModInitializer;
-import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.ModContainer;
+import net.caffeinemc.mods.sodium.client.console.Console;
+import net.caffeinemc.mods.sodium.client.console.message.MessageLevel;
import net.minecraft.network.chat.Component;
-import net.minecraft.server.packs.PackType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
-public class SodiumClientMod implements ClientModInitializer {
+public class SodiumClientMod {
private static SodiumGameOptions CONFIG;
- private static Logger LOGGER;
+ private static final Logger LOGGER = LoggerFactory.getLogger("Sodium");
private static String MOD_VERSION;
- @Override
- public void onInitializeClient() {
- ModContainer mod = FabricLoader.getInstance()
- .getModContainer("sodium")
- .orElseThrow(NullPointerException::new);
+ public static void onInitialization(String version) {
+ MOD_VERSION = version;
- MOD_VERSION = mod.getMetadata()
- .getVersion()
- .getFriendlyString();
-
- LOGGER = LoggerFactory.getLogger("Sodium");
CONFIG = loadConfig();
- FlawlessFrames.onClientInitialization();
-
- ResourceManagerHelper.get(PackType.CLIENT_RESOURCES).registerReloadListener(SpriteFinderCache.ReloadListener.INSTANCE);
-
try {
updateFingerprint();
} catch (Throwable t) {
@@ -71,7 +52,7 @@ private static SodiumGameOptions loadConfig() {
LOGGER.error("Failed to load configuration file", e);
LOGGER.error("Using default configuration file in read-only mode");
- Console.instance().logMessage(MessageLevel.SEVERE, Component.translatable("sodium.console.config_not_loaded"), 12.5);
+ Console.instance().logMessage(MessageLevel.SEVERE, "sodium.console.config_not_loaded", true, 12.5);
var config = SodiumGameOptions.defaults();
config.setReadOnly();
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/checks/ResourcePackScanner.java
similarity index 89%
rename from src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/checks/ResourcePackScanner.java
index 9ac0265407..56e0512812 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/ResourcePackScanner.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/checks/ResourcePackScanner.java
@@ -1,7 +1,7 @@
-package net.caffeinemc.mods.sodium.client.compatibility.checks;
+package net.caffeinemc.mods.sodium.client.checks;
-import net.caffeinemc.mods.sodium.client.gui.console.Console;
-import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel;
+import net.caffeinemc.mods.sodium.client.console.Console;
+import net.caffeinemc.mods.sodium.client.console.message.MessageLevel;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
@@ -76,27 +76,27 @@ private static void printToasts(Collection resourcePacks) {
boolean shown = false;
if (!incompatibleResourcePacks.isEmpty()) {
- showConsoleMessage(Component.translatable("sodium.console.core_shaders_error"), MessageLevel.SEVERE);
+ showConsoleMessage("sodium.console.core_shaders_error", true, MessageLevel.SEVERE);
for (var entry : incompatibleResourcePacks) {
- showConsoleMessage(Component.literal(getResourcePackName(entry.resourcePack)), MessageLevel.SEVERE);
+ showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.SEVERE);
}
shown = true;
}
if (!likelyIncompatibleResourcePacks.isEmpty()) {
- showConsoleMessage(Component.translatable("sodium.console.core_shaders_warn"), MessageLevel.WARN);
+ showConsoleMessage("sodium.console.core_shaders_warn", true, MessageLevel.WARN);
for (var entry : likelyIncompatibleResourcePacks) {
- showConsoleMessage(Component.literal(getResourcePackName(entry.resourcePack)), MessageLevel.WARN);
+ showConsoleMessage(getResourcePackName(entry.resourcePack), false, MessageLevel.WARN);
}
shown = true;
}
if (shown) {
- showConsoleMessage(Component.translatable("sodium.console.core_shaders_info"), MessageLevel.INFO);
+ showConsoleMessage("sodium.console.core_shaders_info", true, MessageLevel.INFO);
}
}
@@ -209,8 +209,8 @@ private static List determineIgnoredShaders(PackResources resourcePack)
return ignoredShaders;
}
- private static void showConsoleMessage(MutableComponent message, MessageLevel messageLevel) {
- Console.instance().logMessage(messageLevel, message, 12.5);
+ private static void showConsoleMessage(String message, boolean translatable, MessageLevel messageLevel) {
+ Console.instance().logMessage(messageLevel, message, translatable, 12.5);
}
private record ScannedResourcePack(PackResources resourcePack,
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/checks/SodiumResourcePackMetadata.java
similarity index 94%
rename from src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/checks/SodiumResourcePackMetadata.java
index 213b93e7ac..44898479b0 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/compatibility/checks/SodiumResourcePackMetadata.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/checks/SodiumResourcePackMetadata.java
@@ -1,4 +1,4 @@
-package net.caffeinemc.mods.sodium.client.compatibility.checks;
+package net.caffeinemc.mods.sodium.client.checks;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java
similarity index 83%
rename from src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java
index 09c945a453..8c72dad127 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/config/MixinConfig.java
@@ -1,10 +1,7 @@
package net.caffeinemc.mods.sodium.client.data.config;
+import net.caffeinemc.mods.sodium.client.services.Services;
import net.caffeinemc.mods.sodium.mixin.MixinOption;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.ModContainer;
-import net.fabricmc.loader.api.metadata.CustomValue;
-import net.fabricmc.loader.api.metadata.ModMetadata;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -17,14 +14,14 @@
* Documentation of these options...
*/
@SuppressWarnings("CanBeFinal")
-public class MixinConfig {
- private static final Logger LOGGER = LogManager.getLogger("SodiumConfig");
+public abstract class MixinConfig {
+ protected static final Logger LOGGER = LogManager.getLogger("SodiumConfig");
- private static final String JSON_KEY_SODIUM_OPTIONS = "sodium:options";
+ protected static final String JSON_KEY_SODIUM_OPTIONS = "sodium:options";
private final Map options = new HashMap<>();
- private MixinConfig() {
+ protected MixinConfig() {
// Defines the default rules which can be configured by the user or other mods.
// You must manually add a rule for any new mixins not covered by an existing package rule.
this.addMixinRule("core", true); // TODO: Don't actually allow the user to disable this
@@ -55,6 +52,8 @@ private MixinConfig() {
this.addMixinRule("features.render.entity.cull", true);
this.addMixinRule("features.render.entity.shadow", true);
+ this.addMixinRule("features.render.frapi", true);
+
this.addMixinRule("features.render.gui", true);
this.addMixinRule("features.render.gui.font", true);
this.addMixinRule("features.render.gui.outlines", true);
@@ -129,47 +128,23 @@ private void readProperties(Properties props) {
}
}
- private void applyModOverrides() {
- for (ModContainer container : FabricLoader.getInstance().getAllMods()) {
- ModMetadata meta = container.getMetadata();
-
- if (meta.containsCustomValue(JSON_KEY_SODIUM_OPTIONS)) {
- CustomValue overrides = meta.getCustomValue(JSON_KEY_SODIUM_OPTIONS);
-
- if (overrides.getType() != CustomValue.CvType.OBJECT) {
- LOGGER.warn("Mod '{}' contains invalid Sodium option overrides, ignoring", meta.getId());
- continue;
- }
+ public abstract void applyModOverrides();
- for (Map.Entry entry : overrides.getAsObject()) {
- this.applyModOverride(meta, entry.getKey(), entry.getValue());
- }
- }
- }
- }
-
- private void applyModOverride(ModMetadata meta, String name, CustomValue value) {
+ protected void applyModOverride(String modId, String name, boolean enabled) {
MixinOption option = this.options.get(name);
if (option == null) {
- LOGGER.warn("Mod '{}' attempted to override option '{}', which doesn't exist, ignoring", meta.getId(), name);
- return;
- }
-
- if (value.getType() != CustomValue.CvType.BOOLEAN) {
- LOGGER.warn("Mod '{}' attempted to override option '{}' with an invalid value, ignoring", meta.getId(), name);
+ LOGGER.warn("Mod '{}' attempted to override option '{}', which doesn't exist, ignoring", modId, name);
return;
}
- boolean enabled = value.getAsBoolean();
-
// disabling the option takes precedence over enabling
if (!enabled && option.isEnabled()) {
option.clearModsDefiningValue();
}
if (!enabled || option.isEnabled() || option.getDefiningMods().isEmpty()) {
- option.addModOverride(enabled, meta.getId());
+ option.addModOverride(enabled, modId);
}
}
@@ -218,7 +193,7 @@ public static MixinConfig load(File file) {
LOGGER.warn("Could not write default configuration file", e);
}
- MixinConfig config = new MixinConfig();
+ MixinConfig config = MixinConfig.create();
config.applyModOverrides();
return config;
@@ -232,13 +207,17 @@ public static MixinConfig load(File file) {
throw new RuntimeException("Could not load config file", e);
}
- MixinConfig config = new MixinConfig();
+ MixinConfig config = MixinConfig.create();
config.readProperties(props);
config.applyModOverrides();
return config;
}
+ private static MixinConfig create() {
+ return Services.load(MixinConfig.class);
+ }
+
private static void writeDefaultConfig(File file) throws IOException {
File dir = file.getParentFile();
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java
similarity index 93%
rename from src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java
index 97650eb2ea..f1e06db7ab 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/FingerprintMeasure.java
@@ -1,6 +1,6 @@
package net.caffeinemc.mods.sodium.client.data.fingerprint;
-import net.fabricmc.loader.api.FabricLoader;
+import net.caffeinemc.mods.sodium.client.services.PlatformInfoAccess;
import net.minecraft.client.Minecraft;
import org.apache.commons.codec.binary.Hex;
import org.jetbrains.annotations.NotNull;
@@ -17,7 +17,7 @@ public record FingerprintMeasure(@NotNull String uuid, @NotNull String path) {
public static @Nullable FingerprintMeasure create() {
var uuid = Minecraft.getInstance().getUser().getProfileId();
- var path = FabricLoader.getInstance().getGameDir();
+ var path = PlatformInfoAccess.getInstance().getGameDirectory();
if (uuid == null || path == null) {
return null;
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java
similarity index 92%
rename from src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java
index eda5bc8c61..10a2a8b0f5 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/data/fingerprint/HashedFingerprint.java
@@ -2,8 +2,8 @@
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
+import net.caffeinemc.mods.sodium.client.services.PlatformInfoAccess;
import net.caffeinemc.mods.sodium.client.util.FileUtil;
-import net.fabricmc.loader.api.FabricLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -68,8 +68,7 @@ public static void writeToDisk(@NotNull HashedFingerprint data) {
}
private static Path getFilePath() {
- return FabricLoader.getInstance()
- .getConfigDir()
+ return PlatformInfoAccess.getInstance().getConfigDirectory()
.resolve("sodium-fingerprint.json");
}
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/GlObject.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferArena.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/GlBufferSegment.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingBufferCopyCommand.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/PendingUpload.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/FallbackStagingBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/MappedStagingBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/arena/staging/StagingBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/array/GlVertexArray.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttribute.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeBinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java
similarity index 61%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java
index b828826112..91d42c1662 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexAttributeFormat.java
@@ -7,15 +7,7 @@
*/
public record GlVertexAttributeFormat(int typeId, int size) {
public static final GlVertexAttributeFormat FLOAT = new GlVertexAttributeFormat(GL33C.GL_FLOAT, 4);
-
- public static final GlVertexAttributeFormat BYTE = new GlVertexAttributeFormat(GL33C.GL_BYTE, 1);
- public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_BYTE, 1);
-
- public static final GlVertexAttributeFormat SHORT = new GlVertexAttributeFormat(GL33C.GL_SHORT, 2);
public static final GlVertexAttributeFormat UNSIGNED_SHORT = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_SHORT, 2);
-
- public static final GlVertexAttributeFormat INT = new GlVertexAttributeFormat(GL33C.GL_INT, 4);
+ public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_BYTE, 1);
public static final GlVertexAttributeFormat UNSIGNED_INT = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_INT, 4);
-
- public static final GlVertexAttributeFormat UNSIGNED_2_10_10_10_REV = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_INT_2_10_10_10_REV, 4);
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/attribute/GlVertexFormat.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapFlags.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferMapping.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferStorageFlags.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferTarget.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlBufferUsage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlImmutableBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/GlMutableBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/IndexedVertexData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/IndexedVertexData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/IndexedVertexData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/buffer/IndexedVertexData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/CommandList.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/DrawCommandList.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/GLRenderDevice.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/MultiDrawBatch.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/device/RenderDevice.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/BufferStorageFunctions.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/functions/DeviceFunctions.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlProgram.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/GlShader.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderConstants.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderLoader.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderParser.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/ShaderWorkarounds.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniform.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformBlock.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat3v.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformFloat4v.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformInt.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/shader/uniform/GlUniformMatrix4f.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/state/GlStateTracker.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/sync/GlFence.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlAbstractTessellation.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlIndexType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlPrimitiveType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlTessellation.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/GlVertexArrayTessellation.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/tessellation/TessellationBinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBit.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/EnumBitField.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gl/util/VertexRange.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptionPages.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java
similarity index 97%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java
index be31339ab5..8f6d383ad8 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumGameOptions.java
@@ -5,9 +5,9 @@
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import net.caffeinemc.mods.sodium.client.gui.options.TextProvider;
+import net.caffeinemc.mods.sodium.client.services.PlatformInfoAccess;
import net.caffeinemc.mods.sodium.client.util.FileUtil;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior;
-import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.GraphicsStatus;
import net.minecraft.network.chat.Component;
import java.io.FileReader;
@@ -123,8 +123,7 @@ public static SodiumGameOptions loadFromDisk() {
}
private static Path getConfigPath() {
- return FabricLoader.getInstance()
- .getConfigDir()
+ return PlatformInfoAccess.getInstance().getConfigDirectory()
.resolve(DEFAULT_FILE_NAME);
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java
similarity index 97%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java
index 411068dad7..c980a298d8 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/SodiumOptionsGUI.java
@@ -2,8 +2,8 @@
import net.caffeinemc.mods.sodium.client.SodiumClientMod;
import net.caffeinemc.mods.sodium.client.data.fingerprint.HashedFingerprint;
-import net.caffeinemc.mods.sodium.client.gui.console.Console;
-import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel;
+import net.caffeinemc.mods.sodium.client.console.Console;
+import net.caffeinemc.mods.sodium.client.console.message.MessageLevel;
import net.caffeinemc.mods.sodium.client.gui.options.*;
import net.caffeinemc.mods.sodium.client.gui.options.control.Control;
import net.caffeinemc.mods.sodium.client.gui.options.control.ControlElement;
@@ -12,8 +12,8 @@
import net.caffeinemc.mods.sodium.client.gui.prompt.ScreenPromptable;
import net.caffeinemc.mods.sodium.client.gui.screen.ConfigCorruptedScreen;
import net.caffeinemc.mods.sodium.client.gui.widgets.FlatButtonWidget;
+import net.caffeinemc.mods.sodium.client.services.PlatformInfoAccess;
import net.caffeinemc.mods.sodium.client.util.Dim2i;
-import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
@@ -70,7 +70,7 @@ private SodiumOptionsGUI(Screen prevScreen) {
private void checkPromptTimers() {
// Never show the prompt in developer workspaces.
- if (FabricLoader.getInstance().isDevelopmentEnvironment()) {
+ if (PlatformInfoAccess.getInstance().isDevelopmentEnvironment()) {
return;
}
@@ -357,7 +357,7 @@ private void applyChanges() {
if (flags.contains(OptionFlag.REQUIRES_GAME_RESTART)) {
Console.instance().logMessage(MessageLevel.WARN,
- Component.translatable("sodium.console.game_restart"), 10.0);
+ "sodium.console.game_restart", true, 10.0);
}
for (OptionStorage> storage : dirtyStorages) {
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java
similarity index 85%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java
index 5d4eb7a2c6..83300a4651 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleHooks.java
@@ -1,5 +1,6 @@
package net.caffeinemc.mods.sodium.client.gui.console;
+import net.caffeinemc.mods.sodium.client.console.Console;
import net.minecraft.client.gui.GuiGraphics;
public class ConsoleHooks {
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java
similarity index 95%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java
index 831e758c9c..87c554e977 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/console/ConsoleRenderer.java
@@ -1,7 +1,8 @@
package net.caffeinemc.mods.sodium.client.gui.console;
-import net.caffeinemc.mods.sodium.client.gui.console.message.Message;
-import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel;
+import net.caffeinemc.mods.sodium.client.console.Console;
+import net.caffeinemc.mods.sodium.client.console.message.Message;
+import net.caffeinemc.mods.sodium.client.console.message.MessageLevel;
import net.caffeinemc.mods.sodium.api.util.ColorARGB;
import net.caffeinemc.mods.sodium.api.util.ColorU8;
import net.minecraft.client.Minecraft;
@@ -173,7 +174,7 @@ private static int weightAlpha(double scale) {
private record ActiveMessage(MessageLevel level, Component text, double duration, double timestamp) {
public static ActiveMessage create(Message message, double timestamp) {
- var text = message.text()
+ var text = (message.translated() ? Component.translatable(message.text()) : Component.literal(message.text()))
.copy()
.withStyle((style) -> style.withFont(Minecraft.UNIFORM_FONT));
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/Option.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionFlag.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionGroup.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpact.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionImpl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/OptionPage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/TextProvider.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/GenericBinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/OptionBinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/binding/compat/VanillaBooleanOptionBinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/Control.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlElement.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/ControlValueFormatter.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/CyclingControl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/SliderControl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/control/TickBoxControl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/MinecraftOptionsStorage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/OptionStorage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/options/storage/SodiumOptionsStorage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPrompt.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/prompt/ScreenPromptable.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java
similarity index 92%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java
index e6c7b0e9db..6f868e41b5 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/screen/ConfigCorruptedScreen.java
@@ -1,8 +1,8 @@
package net.caffeinemc.mods.sodium.client.gui.screen;
import net.caffeinemc.mods.sodium.client.SodiumClientMod;
-import net.caffeinemc.mods.sodium.client.gui.console.Console;
-import net.caffeinemc.mods.sodium.client.gui.console.message.MessageLevel;
+import net.caffeinemc.mods.sodium.client.console.Console;
+import net.caffeinemc.mods.sodium.client.console.message.MessageLevel;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
@@ -54,7 +54,7 @@ protected void init() {
int buttonY = this.height - SCREEN_PADDING - BUTTON_HEIGHT;
this.addRenderableWidget(Button.builder(Component.literal("Continue"), (btn) -> {
- Console.instance().logMessage(MessageLevel.INFO, Component.translatable("sodium.console.config_file_was_reset"), 3.0);
+ Console.instance().logMessage(MessageLevel.INFO, "sodium.console.config_file_was_reset", true, 3.0);
SodiumClientMod.restoreDefaultOptions();
Minecraft.getInstance().setScreen(this.nextScreen.apply(this.prevScreen));
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/AbstractWidget.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/gui/widgets/FlatButtonWidget.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProvider.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/ColorProviderRegistry.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java
similarity index 65%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java
index 99bc40ba7d..0f716c23f6 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/DefaultColorProviders.java
@@ -2,11 +2,9 @@
import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView;
import net.caffeinemc.mods.sodium.client.model.quad.blender.BlendedColorProvider;
-import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorSource;
import net.caffeinemc.mods.sodium.client.world.LevelSlice;
-import net.caffeinemc.mods.sodium.api.util.ColorARGB;
-import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
import net.minecraft.client.color.block.BlockColor;
+import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
@@ -17,9 +15,7 @@ public static ColorProvider adapt(BlockColor color) {
return new VanillaAdapter(color);
}
- public static ColorProvider adapt(FluidRenderHandler handler) {
- return new FabricFluidAdapter(handler);
- }
+ private static final ThreadLocal blockPosHolder = ThreadLocal.withInitial(BlockPos.MutableBlockPos::new);
public static class GrassColorProvider extends BlendedColorProvider {
public static final ColorProvider BLOCKS = new GrassColorProvider<>();
@@ -30,7 +26,7 @@ private GrassColorProvider() {
@Override
protected int getColor(LevelSlice slice, int x, int y, int z) {
- return slice.getColor(BiomeColorSource.GRASS, x, y, z);
+ return BiomeColors.getAverageGrassColor(slice, blockPosHolder.get().set(x, y, z));
}
}
@@ -43,7 +39,7 @@ private FoliageColorProvider() {
@Override
protected int getColor(LevelSlice slice, int x, int y, int z) {
- return slice.getColor(BiomeColorSource.FOLIAGE, x, y, z);
+ return BiomeColors.getAverageFoliageColor(slice, blockPosHolder.get().set(x, y, z));
}
}
@@ -57,7 +53,7 @@ private WaterColorProvider() {
@Override
protected int getColor(LevelSlice slice, int x, int y, int z) {
- return slice.getColor(BiomeColorSource.WATER, x, y, z);
+ return BiomeColors.getAverageWaterColor(slice, blockPosHolder.get().set(x, y, z));
}
}
@@ -70,20 +66,7 @@ private VanillaAdapter(BlockColor color) {
@Override
public void getColors(LevelSlice slice, BlockPos pos, BlockState state, ModelQuadView quad, int[] output) {
- Arrays.fill(output, ColorARGB.toABGR(this.color.getColor(state, slice, pos, quad.getColorIndex())));
- }
- }
-
- private static class FabricFluidAdapter implements ColorProvider {
- private final FluidRenderHandler handler;
-
- public FabricFluidAdapter(FluidRenderHandler handler) {
- this.handler = handler;
- }
-
- @Override
- public void getColors(LevelSlice slice, BlockPos pos, FluidState state, ModelQuadView quad, int[] output) {
- Arrays.fill(output, this.handler.getFluidColor(slice, pos, state));
+ Arrays.fill(output, this.color.getColor(state, slice, pos, quad.getColorIndex()));
}
}
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/BlockColorsExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/color/interop/ItemColorsExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightMode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java
similarity index 86%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java
index d6affb784d..29eb8f57f1 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipeline.java
@@ -18,6 +18,7 @@ public interface LightPipeline {
* @param cullFace The cull face of the quad
* @param lightFace The light face of the quad
* @param shade True if the block is shaded by ambient occlusion
+ * @param isFluid True if the block is being drawn by the fluid renderer
*/
- void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade);
+ void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade, boolean isFluid);
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/LightPipelineProvider.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/ArrayLightDataCache.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/HashLightDataCache.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java
similarity index 92%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java
index c4c4bc143a..0ded5bc8c9 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/LightDataAccess.java
@@ -1,5 +1,6 @@
package net.caffeinemc.mods.sodium.client.model.light.data;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.BlockPos;
@@ -68,7 +69,7 @@ protected int compute(int x, int y, int z) {
boolean fo = state.isSolidRender(level, pos);
boolean fc = state.isCollisionShapeFullBlock(level, pos);
- int lu = state.getLightEmission();
+ int lu = PlatformBlockAccess.getInstance().getLightEmission(state, level, pos);
// OPTIMIZE: Do not calculate light data if the block is full and opaque and does not emit light.
int bl;
@@ -77,8 +78,14 @@ protected int compute(int x, int y, int z) {
bl = 0;
sl = 0;
} else {
- bl = level.getBrightness(LightLayer.BLOCK, pos);
- sl = level.getBrightness(LightLayer.SKY, pos);
+ if (em) {
+ bl = level.getBrightness(LightLayer.BLOCK, pos);
+ sl = level.getBrightness(LightLayer.SKY, pos);
+ } else {
+ int light = LevelRenderer.getLightColor(level, state, pos);
+ bl = LightTexture.block(light);
+ sl = LightTexture.sky(light);
+ }
}
// FIX: Do not apply AO from blocks that emit light
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/QuadLightData.java
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/SingleBlockLightDataCache.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/SingleBlockLightDataCache.java
new file mode 100644
index 0000000000..267f95a683
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/data/SingleBlockLightDataCache.java
@@ -0,0 +1,60 @@
+package net.caffeinemc.mods.sodium.client.model.light.data;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.BlockAndTintGetter;
+
+import java.util.Arrays;
+
+/**
+ * Adaptation of {@link ArrayLightDataCache} that stores data for
+ * only one block and its neighbors.
+ */
+public class SingleBlockLightDataCache extends LightDataAccess {
+ // Radius of 2 is required: block models may create geometry in up to a 3x3x3 region, which requires light to be
+ // queried from neighbours of any block in this region
+ private static final int NEIGHBOR_BLOCK_RADIUS = 2;
+ private static final int BLOCK_LENGTH = 1 + (NEIGHBOR_BLOCK_RADIUS * 2);
+
+ private final int[] light;
+
+ private int xOffset, yOffset, zOffset;
+
+ public SingleBlockLightDataCache() {
+ this.light = new int[BLOCK_LENGTH * BLOCK_LENGTH * BLOCK_LENGTH];
+ }
+
+ public void reset(BlockPos origin, BlockAndTintGetter blockView) {
+ this.xOffset = origin.getX() - NEIGHBOR_BLOCK_RADIUS;
+ this.yOffset = origin.getY() - NEIGHBOR_BLOCK_RADIUS;
+ this.zOffset = origin.getZ() - NEIGHBOR_BLOCK_RADIUS;
+
+ Arrays.fill(this.light, 0);
+
+ this.level = blockView;
+ }
+
+ public void release() {
+ this.level = null;
+ }
+
+ private int index(int x, int y, int z) {
+ int x2 = x - this.xOffset;
+ int y2 = y - this.yOffset;
+ int z2 = z - this.zOffset;
+
+ return (z2 * BLOCK_LENGTH * BLOCK_LENGTH) + (y2 * BLOCK_LENGTH) + x2;
+ }
+
+ @Override
+ public int get(int x, int y, int z) {
+ int l = this.index(x, y, z);
+
+ int word = this.light[l];
+
+ if (word != 0) {
+ return word;
+ }
+
+ return this.light[l] = this.compute(x, y, z);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java
similarity index 88%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java
index 83dbca2d98..de2fd59918 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/flat/FlatLightPipeline.java
@@ -5,6 +5,7 @@
import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData;
import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView;
import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.BlockPos;
@@ -30,25 +31,27 @@ public FlatLightPipeline(LightDataAccess lightCache) {
}
@Override
- public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade) {
+ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade, boolean isFluid) {
int lightmap;
// To match vanilla behavior, use the cull face if it exists/is available
if (cullFace != null) {
lightmap = getOffsetLightmap(pos, cullFace);
+ Arrays.fill(out.br, this.lightCache.getLevel().getShade(lightFace, shade));
} else {
int flags = quad.getFlags();
// If the face is aligned, use the light data above it
// To match vanilla behavior, also treat the face as aligned if it is parallel and the block state is a full cube
if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && unpackFC(this.lightCache.get(pos)))) {
lightmap = getOffsetLightmap(pos, lightFace);
+ Arrays.fill(out.br, this.lightCache.getLevel().getShade(lightFace, shade));
} else {
lightmap = getEmissiveLightmap(this.lightCache.get(pos));
+ Arrays.fill(out.br, PlatformBlockAccess.getInstance().getAccurateBlockShade(quad, this.lightCache.getLevel(), shade));
}
}
Arrays.fill(out.lm, lightmap);
- Arrays.fill(out.br, this.lightCache.getLevel().getShade(lightFace, shade));
}
/**
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoCompletionFlags.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java
similarity index 85%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java
index 13a3129882..2fca84b4d6 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoFaceData.java
@@ -155,6 +155,33 @@ public void initLightData(LightDataAccess cache, BlockPos pos, Direction directi
this.flags |= AoCompletionFlags.HAS_LIGHT_DATA;
}
+ static AoFaceData weightedMean(AoFaceData in0, float w0, AoFaceData in1, float w1, AoFaceData out) {
+ out.ao[0] = in0.ao[0] * w0 + in1.ao[0] * w1;
+ out.ao[1] = in0.ao[1] * w0 + in1.ao[1] * w1;
+ out.ao[2] = in0.ao[2] * w0 + in1.ao[2] * w1;
+ out.ao[3] = in0.ao[3] * w0 + in1.ao[3] * w1;
+
+ if (!in0.hasUnpackedLightData()) in0.unpackLightData();
+ if (!in1.hasUnpackedLightData()) in1.unpackLightData();
+
+ out.bl[0] = (int) (in0.bl[0] * w0 + in1.bl[0] * w1);
+ out.bl[1] = (int) (in0.bl[1] * w0 + in1.bl[1] * w1);
+ out.bl[2] = (int) (in0.bl[2] * w0 + in1.bl[2] * w1);
+ out.bl[3] = (int) (in0.bl[3] * w0 + in1.bl[3] * w1);
+
+ out.sl[0] = (int) (in0.sl[0] * w0 + in1.sl[0] * w1);
+ out.sl[1] = (int) (in0.sl[1] * w0 + in1.sl[1] * w1);
+ out.sl[2] = (int) (in0.sl[2] * w0 + in1.sl[2] * w1);
+ out.sl[3] = (int) (in0.sl[3] * w0 + in1.sl[3] * w1);
+
+ out.lm[0] = packLight(out.sl[0], out.bl[0]);
+ out.lm[1] = packLight(out.sl[1], out.bl[1]);
+ out.lm[2] = packLight(out.sl[2], out.bl[2]);
+ out.lm[3] = packLight(out.sl[3], out.bl[3]);
+
+ return out;
+ }
+
public void unpackLightData() {
int[] lm = this.lm;
@@ -203,6 +230,10 @@ private static float unpackBlockLight(int i) {
return i & 0xFF;
}
+ private static int packLight(float sl, float bl) {
+ return (((int) sl & 0xFF) << 16) | ((int) bl & 0xFF);
+ }
+
private static int calculateCornerBrightness(int a, int b, int c, int d, boolean aem, boolean bem, boolean cem, boolean dem) {
// FIX: Normalize corner vectors correctly to the minimum non-zero value between each one to prevent
// strange issues
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java
similarity index 88%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java
index 61b83f37d6..0b473eab32 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/AoNeighborInfo.java
@@ -1,18 +1,18 @@
package net.caffeinemc.mods.sodium.client.model.light.smooth;
import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
/**
* The neighbor information for each face of a block, used when performing smooth lighting in order to calculate
* the occlusion of each corner.
*/
-@SuppressWarnings("UnnecessaryLocalVariable")
enum AoNeighborInfo {
DOWN(new Direction[] { Direction.WEST, Direction.EAST, Direction.NORTH, Direction.SOUTH }, 0.5F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = z;
- final float v = 1.0f - x;
+ final float u = Mth.clamp(z, 0.0f, 1.0f);
+ final float v = Mth.clamp(1.0f - x, 0.0f, 1.0f);
out[0] = v * u;
out[1] = v * (1.0f - u);
@@ -35,14 +35,14 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return y;
+ return Mth.clamp(y, 0.0F, 1.0F);
}
},
UP(new Direction[] { Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH }, 1.0F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = z;
- final float v = x;
+ final float u = Mth.clamp(z, 0.0f, 1.0f);
+ final float v = Mth.clamp(x, 0.0f, 1.0f);
out[0] = v * u;
out[1] = v * (1.0f - u);
@@ -65,14 +65,14 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return 1.0f - y;
+ return 1.0f - Mth.clamp(y, 0.0F, 1.0F);
}
},
NORTH(new Direction[] { Direction.UP, Direction.DOWN, Direction.EAST, Direction.WEST }, 0.8F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = 1.0f - x;
- final float v = y;
+ final float u = Mth.clamp(1.0f - x, 0.0f, 1.0f);
+ final float v = Mth.clamp(y, 0.0f, 1.0f);
out[0] = v * u;
out[1] = v * (1.0f - u);
@@ -95,14 +95,14 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return z;
+ return Mth.clamp(z, 0.0F, 1.0F);
}
},
SOUTH(new Direction[] { Direction.WEST, Direction.EAST, Direction.DOWN, Direction.UP }, 0.8F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = y;
- final float v = 1.0f - x;
+ final float u = Mth.clamp(y, 0.0f, 1.0f);
+ final float v = Mth.clamp(1.0f - x, 0.0f, 1.0f);
out[0] = u * v;
out[1] = (1.0f - u) * v;
@@ -125,14 +125,14 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return 1.0f - z;
+ return 1.0f - Mth.clamp(z, 0.0F, 1.0F);
}
},
WEST(new Direction[] { Direction.UP, Direction.DOWN, Direction.NORTH, Direction.SOUTH }, 0.6F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = z;
- final float v = y;
+ final float u = Mth.clamp(z, 0.0f, 1.0f);
+ final float v = Mth.clamp(y, 0.0f, 1.0f);
out[0] = v * u;
out[1] = v * (1.0f - u);
@@ -155,14 +155,14 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return x;
+ return Mth.clamp(x, 0.0F, 1.0F);
}
},
EAST(new Direction[] { Direction.DOWN, Direction.UP, Direction.NORTH, Direction.SOUTH }, 0.6F) {
@Override
public void calculateCornerWeights(float x, float y, float z, float[] out) {
- final float u = z;
- final float v = 1.0f - y;
+ final float u = Mth.clamp(z, 0.0f, 1.0f);
+ final float v = Mth.clamp(1.0f - y, 0.0f, 1.0f);
out[0] = v * u;
out[1] = v * (1.0f - u);
@@ -185,7 +185,7 @@ public void mapCorners(int[] lm0, float[] ao0, int[] lm1, float[] ao1) {
@Override
public float getDepth(float x, float y, float z) {
- return 1.0f - x;
+ return 1.0f - Mth.clamp(x, 0.0F, 1.0F);
}
};
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java
similarity index 66%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java
index f27230914f..27ddb76f01 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/light/smooth/SmoothLightPipeline.java
@@ -1,5 +1,6 @@
package net.caffeinemc.mods.sodium.client.model.light.smooth;
+import net.caffeinemc.mods.sodium.api.util.NormI8;
import net.caffeinemc.mods.sodium.client.model.light.LightPipeline;
import net.caffeinemc.mods.sodium.client.model.light.data.LightDataAccess;
import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData;
@@ -8,6 +9,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
+import org.joml.Vector3f;
/**
* A light pipeline which produces smooth interpolated lighting and ambient occlusion for model quads. This
@@ -64,7 +66,7 @@ public SmoothLightPipeline(LightDataAccess cache) {
}
@Override
- public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade) {
+ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direction cullFace, Direction lightFace, boolean shade, boolean isFluid) {
this.updateCachedData(pos.asLong());
int flags = quad.getFlags();
@@ -77,17 +79,17 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc
// To match vanilla behavior, also treat the face as aligned if it is parallel and the block state is a full cube
if ((flags & ModelQuadFlags.IS_ALIGNED) != 0 || ((flags & ModelQuadFlags.IS_PARALLEL) != 0 && LightDataAccess.unpackFC(this.lightCache.get(pos)))) {
if ((flags & ModelQuadFlags.IS_PARTIAL) == 0) {
- this.applyAlignedFullFace(neighborInfo, pos, lightFace, out);
+ this.applyAlignedFullFace(neighborInfo, pos, lightFace, out, shade);
} else {
- this.applyAlignedPartialFace(neighborInfo, quad, pos, lightFace, out);
+ this.applyAlignedPartialFace(neighborInfo, quad, pos, lightFace, out, shade);
}
} else if ((flags & ModelQuadFlags.IS_PARALLEL) != 0) {
- this.applyParallelFace(neighborInfo, quad, pos, lightFace, out);
+ this.applyParallelFace(neighborInfo, quad, pos, lightFace, out, shade);
+ } else if (isFluid) {
+ this.applyNonParallelFace(neighborInfo, quad, pos, lightFace, out, shade);
} else {
- this.applyNonParallelFace(neighborInfo, quad, pos, lightFace, out);
+ this.applyIrregularFace(pos, quad, out, shade);
}
-
- this.applySidedBrightness(out, lightFace, shade);
}
/**
@@ -96,8 +98,8 @@ public void calculate(ModelQuadView quad, BlockPos pos, QuadLightData out, Direc
* have two contributing sides.
* Flags: IS_ALIGNED, !IS_PARTIAL
*/
- private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Direction dir, QuadLightData out) {
- AoFaceData faceData = this.getCachedFaceData(pos, dir, true);
+ private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Direction dir, QuadLightData out, boolean shade) {
+ AoFaceData faceData = this.getCachedFaceData(pos, dir, true, shade);
neighborInfo.mapCorners(faceData.lm, faceData.ao, out.lm, out.br);
}
@@ -105,7 +107,7 @@ private void applyAlignedFullFace(AoNeighborInfo neighborInfo, BlockPos pos, Dir
* Calculates the light data for a grid-aligned quad that does not cover the entire block volume's face.
* Flags: IS_ALIGNED, IS_PARTIAL
*/
- private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) {
+ private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out, boolean shade) {
for (int i = 0; i < 4; i++) {
// Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting
float cx = clamp(quad.getX(i));
@@ -114,18 +116,18 @@ private void applyAlignedPartialFace(AoNeighborInfo neighborInfo, ModelQuadView
float[] weights = this.weights;
neighborInfo.calculateCornerWeights(cx, cy, cz, weights);
- this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true);
+ this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true, shade);
}
}
/**
* This method is the same as {@link #applyNonParallelFace(AoNeighborInfo, ModelQuadView, BlockPos, Direction,
- * QuadLightData)} but with the check for a depth of approximately 0 removed. If the quad is parallel but not
+ * QuadLightData, boolean)} but with the check for a depth of approximately 0 removed. If the quad is parallel but not
* aligned, all of its vertices will have the same depth and this depth must be approximately greater than 0,
* meaning the check for 0 will always return false.
* Flags: !IS_ALIGNED, IS_PARALLEL
*/
- private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) {
+ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out, boolean shade) {
for (int i = 0; i < 4; i++) {
// Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting
float cx = clamp(quad.getX(i));
@@ -140,11 +142,11 @@ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad,
// If the quad is approximately grid-aligned (not inset) to the other side of the block, avoid unnecessary
// computation by treating it is as aligned
if (Mth.equal(depth, 1.0F)) {
- this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false);
+ this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false, shade);
} else {
// Blend the occlusion factor between the blocks directly beside this face and the blocks above it
// based on how inset the face is. This fixes a few issues with blocks such as farmland and paths.
- this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out);
+ this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out, shade);
}
}
}
@@ -152,7 +154,7 @@ private void applyParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad,
/**
* Flags: !IS_ALIGNED, !IS_PARALLEL
*/
- private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out) {
+ private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView quad, BlockPos pos, Direction dir, QuadLightData out, boolean shade) {
for (int i = 0; i < 4; i++) {
// Clamp the vertex positions to the block's boundaries to prevent weird errors in lighting
float cx = clamp(quad.getX(i));
@@ -166,19 +168,19 @@ private void applyNonParallelFace(AoNeighborInfo neighborInfo, ModelQuadView qua
// If the quad is approximately grid-aligned (not inset), avoid unnecessary computation by treating it is as aligned
if (Mth.equal(depth, 0.0F)) {
- this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true);
+ this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, true, shade);
} else if (Mth.equal(depth, 1.0F)) {
- this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false);
+ this.applyAlignedPartialFaceVertex(pos, dir, weights, i, out, false, shade);
} else {
// Blend the occlusion factor between the blocks directly beside this face and the blocks above it
// based on how inset the face is. This fixes a few issues with blocks such as farmland and paths.
- this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out);
+ this.applyInsetPartialFaceVertex(pos, dir, depth, 1.0f - depth, weights, i, out, shade);
}
}
}
- private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[] w, int i, QuadLightData out, boolean offset) {
- AoFaceData faceData = this.getCachedFaceData(pos, dir, offset);
+ private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[] w, int i, QuadLightData out, boolean offset, boolean shade) {
+ AoFaceData faceData = this.getCachedFaceData(pos, dir, offset, shade);
if (!faceData.hasUnpackedLightData()) {
faceData.unpackLightData();
@@ -192,14 +194,14 @@ private void applyAlignedPartialFaceVertex(BlockPos pos, Direction dir, float[]
out.lm[i] = getLightMapCoord(sl, bl);
}
- private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, float n2d, float[] w, int i, QuadLightData out) {
- AoFaceData n1 = this.getCachedFaceData(pos, dir, false);
+ private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d, float n2d, float[] w, int i, QuadLightData out, boolean shade) {
+ AoFaceData n1 = this.getCachedFaceData(pos, dir, false, shade);
if (!n1.hasUnpackedLightData()) {
n1.unpackLightData();
}
- AoFaceData n2 = this.getCachedFaceData(pos, dir, true);
+ AoFaceData n2 = this.getCachedFaceData(pos, dir, true, shade);
if (!n2.hasUnpackedLightData()) {
n2.unpackLightData();
@@ -214,23 +216,119 @@ private void applyInsetPartialFaceVertex(BlockPos pos, Direction dir, float n1d,
out.lm[i] = getLightMapCoord(sl, bl);
}
- private void applySidedBrightness(QuadLightData out, Direction face, boolean shade) {
+ /** used exclusively in irregular face to avoid new heap allocations each call. */
+ private final Vector3f vertexNormal = new Vector3f();
+ private final AoFaceData tmpFace = new AoFaceData();
+
+ private AoFaceData gatherInsetFace(ModelQuadView quad, BlockPos blockPos, int vertexIndex, Direction lightFace, boolean shade) {
+ final float w1 = AoNeighborInfo.get(lightFace).getDepth(quad.getX(vertexIndex), quad.getY(vertexIndex), quad.getZ(vertexIndex));
+
+ if (Mth.equal(w1, 0)) {
+ return getCachedFaceData(blockPos, lightFace, true, shade);
+ } else if (Mth.equal(w1, 1)) {
+ return getCachedFaceData(blockPos, lightFace, false, shade);
+ } else {
+ tmpFace.reset();
+ final float w0 = 1 - w1;
+ return AoFaceData.weightedMean(getCachedFaceData(blockPos, lightFace, true, shade), w0, getCachedFaceData(blockPos, lightFace, false, shade), w1, tmpFace);
+ }
+ }
+
+ /**
+ * Calculates the light data for a quad that does not follow any grid and is not parallel to it's light face.
+ * Flags: !IS_ALIGNED, !IS_PARTIAL, !IS_FULL
+ */
+ private void applyIrregularFace(BlockPos blockPos, ModelQuadView quad, QuadLightData out, boolean shade) {
+ final float[] w = this.weights;
+ final float[] aoResult = out.br;
+ final int[] lightResult = out.lm;
+
+ for (int i = 0; i < 4; i++) {
+ // TODO: Avoid this if the accurate normal is the face normal
+ Vector3f normal = NormI8.unpack(quad.getAccurateNormal(i), vertexNormal);
+ float ao = 0, sky = 0, block = 0, maxAo = 0;
+ float maxSky = 0, maxBlock = 0;
+
+ final float x = normal.x();
+
+ if (!Mth.equal(0f, x)) {
+ final Direction face = x > 0 ? Direction.EAST : Direction.WEST;
+ final AoFaceData fd = gatherInsetFace(quad, blockPos, i, face, shade);
+ AoNeighborInfo.get(face).calculateCornerWeights(quad.getX(i), quad.getY(i), quad.getZ(i), w);
+ final float n = x * x;
+ final float a = fd.getBlendedShade(w);
+ final float s = fd.getBlendedSkyLight(w);
+ final float b = fd.getBlendedBlockLight(w);
+ ao += n * a;
+ sky += n * s;
+ block += n * b;
+ maxAo = a;
+ maxSky = s;
+ maxBlock = b;
+ }
+
+ final float y = normal.y();
+
+ if (!Mth.equal(0f, y)) {
+ final Direction face = y > 0 ? Direction.UP : Direction.DOWN;
+ final AoFaceData fd = gatherInsetFace(quad, blockPos, i, face, shade);
+ AoNeighborInfo.get(face).calculateCornerWeights(quad.getX(i), quad.getY(i), quad.getZ(i), w);
+ final float n = y * y;
+ final float a = fd.getBlendedShade(w);
+ final float s = fd.getBlendedSkyLight(w);
+ final float b = fd.getBlendedBlockLight(w);
+ ao += n * a;
+ sky += n * s;
+ block += n * b;
+ maxAo = Math.max(maxAo, a);
+ maxSky = Math.max(maxSky, s);
+ maxBlock = Math.max(maxBlock, b);
+ }
+
+ final float z = normal.z();
+
+ if (!Mth.equal(0f, z)) {
+ final Direction face = z > 0 ? Direction.SOUTH : Direction.NORTH;
+ final AoFaceData fd = gatherInsetFace(quad, blockPos, i, face, shade);
+ AoNeighborInfo.get(face).calculateCornerWeights(quad.getX(i), quad.getY(i), quad.getZ(i), w);
+ final float n = z * z;
+ final float a = fd.getBlendedShade(w);
+ final float s = fd.getBlendedSkyLight(w);
+ final float b = fd.getBlendedBlockLight(w);
+ ao += n * a;
+ sky += n * s;
+ block += n * b;
+ maxAo = Math.max(maxAo, a);
+ maxSky = Math.max(maxSky, s);
+ maxBlock = Math.max(maxBlock, b);
+ }
+
+ aoResult[i] = (ao + maxAo) * 0.5f;
+ lightResult[i] = (((int) ((sky + maxSky) * 0.5f) & 0xF0) << 16) | ((int) ((block + maxBlock) * 0.5f) & 0xF0);
+ }
+ }
+
+ private void applySidedBrightness(AoFaceData out, Direction face, boolean shade) {
float brightness = this.lightCache.getLevel().getShade(face, shade);
- float[] br = out.br;
+ float[] ao = out.ao;
- for (int i = 0; i < br.length; i++) {
- br[i] *= brightness;
+ for (int i = 0; i < ao.length; i++) {
+ ao[i] *= brightness;
}
}
/**
* Returns the cached data for a given facing or calculates it if it hasn't been cached.
*/
- private AoFaceData getCachedFaceData(BlockPos pos, Direction face, boolean offset) {
+ private AoFaceData getCachedFaceData(BlockPos pos, Direction face, boolean offset, boolean shade) {
AoFaceData data = this.cachedFaceData[offset ? face.ordinal() : face.ordinal() + 6];
if (!data.hasLightData()) {
data.initLightData(this.lightCache, pos, face, offset);
+
+ this.applySidedBrightness(data, face, shade);
+
+ data.unpackLightData();
}
return data;
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java
similarity index 91%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java
index b95ee43fa2..8acff21468 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/BakedQuadView.java
@@ -5,7 +5,7 @@
public interface BakedQuadView extends ModelQuadView {
ModelQuadFacing getNormalFace();
- int getNormal();
+ int getFaceNormal();
boolean hasShade();
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java
similarity index 84%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java
index 3b19d98698..d5f650313d 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuad.java
@@ -16,6 +16,7 @@ public class ModelQuad implements ModelQuadViewMutable {
private Direction direction;
private int colorIdx;
+ private int faceNormal;
@Override
public void setX(int idx, float x) {
@@ -52,6 +53,16 @@ public void setLight(int idx, int light) {
this.data[ModelQuadUtil.vertexOffset(idx) + ModelQuadUtil.LIGHT_INDEX] = light;
}
+ @Override
+ public void setNormal(int idx, int normal) {
+ this.data[ModelQuadUtil.vertexOffset(idx) + ModelQuadUtil.NORMAL_INDEX] = normal;
+ }
+
+ @Override
+ public void setFaceNormal(int normal) {
+ this.faceNormal = normal;
+ }
+
@Override
public void setFlags(int flags) {
this.flags = flags;
@@ -107,6 +118,21 @@ public float getTexV(int idx) {
return Float.intBitsToFloat(this.data[ModelQuadUtil.vertexOffset(idx) + ModelQuadUtil.TEXTURE_INDEX + 1]);
}
+ @Override
+ public int getVertexNormal(int idx) {
+ return this.data[ModelQuadUtil.vertexOffset(idx) + ModelQuadUtil.NORMAL_INDEX];
+ }
+
+ @Override
+ public int getFaceNormal() {
+ return faceNormal;
+ }
+
+ @Override
+ public int getLight(int idx) {
+ return this.data[ModelQuadUtil.vertexOffset(idx) + ModelQuadUtil.LIGHT_INDEX];
+ }
+
@Override
public int getFlags() {
return this.flags;
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java
similarity index 81%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java
index fb0a0ee88b..08369fb0af 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadView.java
@@ -39,6 +39,21 @@ public interface ModelQuadView {
*/
float getTexV(int idx);
+ /**
+ * @return The packed normal set for the vertex at index {@param idx}.
+ */
+ int getVertexNormal(int idx);
+
+ /**
+ * @return The computed normal.
+ */
+ int getFaceNormal();
+
+ /**
+ * @return The packed light set for the vertex at index {@param idx}.
+ */
+ int getLight(int idx);
+
/**
* @return The integer bit flags containing the {@link ModelQuadFlags} for this quad
*/
@@ -101,4 +116,15 @@ default int calculateNormal() {
return NormI8.pack(normX, normY, normZ);
}
+
+ /**
+ * Returns the most accurate normal value for this vertex.
+ * @param i The vertex index.
+ * @return the per-vertex normal if it is set, otherwise the face normal.
+ */
+ default int getAccurateNormal(int i) {
+ int normal = getVertexNormal(i);
+
+ return normal == 0 ? getFaceNormal() : normal;
+ }
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java
similarity index 86%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java
index 13d0345481..30753db6ca 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/ModelQuadViewMutable.java
@@ -43,6 +43,16 @@ public interface ModelQuadViewMutable extends ModelQuadView {
*/
void setLight(int idx, int light);
+ /**
+ * Sets the normal vector of the vertex at index {@param idx} to the value {@param normal}
+ */
+ void setNormal(int idx, int normal);
+
+ /**
+ * Sets the normal vector of the face to the value {@param normal}
+ */
+ void setFaceNormal(int normal);
+
/**
* Sets the bit-flag field which contains the {@link ModelQuadFlags} for this quad
*/
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java
similarity index 98%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java
index e74314d643..38e58f9fdb 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/blender/BlendedColorProvider.java
@@ -66,7 +66,7 @@ private int getVertexColor(LevelSlice slice, BlockPos pos, ModelQuadView quad, i
x0 = z0;
}
- return ColorARGB.toABGR(x0);
+ return x0;
}
protected abstract int getColor(LevelSlice slice, int x, int y, int z);
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFacing.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java
similarity index 96%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java
index 6b46654731..856aed983c 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadFlags.java
@@ -20,6 +20,12 @@ public class ModelQuadFlags {
*/
public static final int IS_ALIGNED = 0b100;
+ /**
+ * Number of flags.
+ */
+ public static final int FLAG_BIT_COUNT = 3;
+
+
/**
* @return True if the bit-flag of {@link ModelQuadFlags} contains the given flag
*/
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java
similarity index 63%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java
index 21e5c6121f..19c7e61820 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadOrientation.java
@@ -1,5 +1,7 @@
package net.caffeinemc.mods.sodium.client.model.quad.properties;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+
/**
* Defines the orientation of vertices in a model quad. This information be used to re-orient the quad's vertices to a
* consistent order, eliminating a number of shading issues caused by anisotropy problems.
@@ -43,4 +45,27 @@ public static ModelQuadOrientation orientByBrightness(float[] brightnesses, int[
return FLIP;
}
}
+
+ /**
+ * Determines the orientation of the vertices in the quad.
+ */
+ public static ModelQuadOrientation orientByBrightness(float[] brightnesses, QuadView quad) {
+ // If one side of the quad is brighter, flip the sides
+ float br02 = brightnesses[0] + brightnesses[2];
+ float br13 = brightnesses[1] + brightnesses[3];
+ if (br02 > br13) {
+ return NORMAL;
+ } else if (br02 < br13) {
+ return FLIP;
+ }
+
+ // If one side of the quad is darker, flip the sides
+ int lm02 = quad.lightmap(0) + quad.lightmap(2);
+ int lm13 = quad.lightmap(1) + quad.lightmap(3);
+ if (lm02 <= lm13) {
+ return NORMAL;
+ } else {
+ return FLIP;
+ }
+ }
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/model/quad/properties/ModelQuadWinding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java
similarity index 92%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java
index 9d8fcfae23..b6ebe820f1 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/SodiumWorldRenderer.java
@@ -45,6 +45,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.SortedSet;
+import java.util.function.Consumer;
/**
* Provides an extension to vanilla's {@link LevelRenderer}.
@@ -405,6 +406,49 @@ private static void renderBlockEntity(PoseStack matrices,
matrices.popPose();
}
+ public void iterateVisibleBlockEntities(Consumer blockEntityConsumer) {
+ SortedRenderLists renderLists = this.renderSectionManager.getRenderLists();
+ Iterator renderListIterator = renderLists.iterator();
+
+ while (renderListIterator.hasNext()) {
+ var renderList = renderListIterator.next();
+
+ var renderRegion = renderList.getRegion();
+ var renderSectionIterator = renderList.sectionsWithEntitiesIterator();
+
+ if (renderSectionIterator == null) {
+ continue;
+ }
+
+ while (renderSectionIterator.hasNext()) {
+ var renderSectionId = renderSectionIterator.nextByteAsInt();
+ var renderSection = renderRegion.getSection(renderSectionId);
+
+ var blockEntities = renderSection.getCulledBlockEntities();
+
+ if (blockEntities == null) {
+ continue;
+ }
+
+ for (BlockEntity blockEntity : blockEntities) {
+ blockEntityConsumer.accept(blockEntity);
+ }
+ }
+ }
+
+ for (var renderSection : this.renderSectionManager.getSectionsWithGlobalEntities()) {
+ var blockEntities = renderSection.getGlobalBlockEntities();
+
+ if (blockEntities == null) {
+ continue;
+ }
+
+ for (BlockEntity blockEntity : blockEntities) {
+ blockEntityConsumer.accept(blockEntity);
+ }
+ }
+ }
+
// the volume of a section multiplied by the number of sections to be checked at most
private static final double MAX_ENTITY_CHECK_VOLUME = 16 * 16 * 16 * 15;
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderMatrices.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkRenderer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ChunkUpdateType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/DefaultChunkRenderer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/LocalSectionIndex.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/NonStoringBuilderPool.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSection.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionFlags.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/RenderSectionManager.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/ShaderChunkRenderer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/SharedQuadIndexBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/BuilderTaskOutput.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildBuffers.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildContext.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkBuildOutput.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/ChunkSortOutput.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/BakedChunkModelBuilder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkModelBuilder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java
similarity index 88%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java
index bdafe5bb4a..25ff13d50c 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/buffers/ChunkVertexConsumer.java
@@ -9,7 +9,8 @@
import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder;
import net.caffeinemc.mods.sodium.api.util.ColorABGR;
import net.caffeinemc.mods.sodium.api.util.ColorARGB;
-import net.caffeinemc.mods.sodium.client.render.frapi.SpriteFinderCache;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
+import net.caffeinemc.mods.sodium.client.services.PlatformTextureAccess;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.Direction;
import org.jetbrains.annotations.NotNull;
@@ -26,8 +27,6 @@ public class ChunkVertexConsumer implements VertexConsumer {
private final ChunkVertexEncoder.Vertex[] vertices = ChunkVertexEncoder.Vertex.uninitializedQuad();
private Material material;
- private boolean isColorFixed;
- private int fixedColor = 0xFFFFFFFF;
private int vertexIndex;
private int writtenAttributes;
private TranslucentGeometryCollector collector;
@@ -44,9 +43,9 @@ public void setData(Material material, TranslucentGeometryCollector collector) {
@Override
public @NotNull VertexConsumer addVertex(float x, float y, float z) {
ChunkVertexEncoder.Vertex vertex = this.vertices[this.vertexIndex];
- vertex.x = (float) x;
- vertex.y = (float) y;
- vertex.z = (float) z;
+ vertex.x = x;
+ vertex.y = y;
+ vertex.z = z;
this.writtenAttributes |= ATTRIBUTE_POSITION_BIT;
return potentiallyEndVertex();
}
@@ -54,10 +53,6 @@ public void setData(Material material, TranslucentGeometryCollector collector) {
// Writing color ignores alpha since alpha is used as a color multiplier by Sodium.
@Override
public @NotNull VertexConsumer setColor(int red, int green, int blue, int alpha) {
- if (this.isColorFixed) {
- throw new IllegalStateException();
- }
-
ChunkVertexEncoder.Vertex vertex = this.vertices[this.vertexIndex];
vertex.color = ColorABGR.pack(red, green, blue, 0xFF);
this.writtenAttributes |= ATTRIBUTE_COLOR_BIT;
@@ -66,10 +61,6 @@ public void setData(Material material, TranslucentGeometryCollector collector) {
@Override
public @NotNull VertexConsumer setColor(float red, float green, float blue, float alpha) {
- if (this.isColorFixed) {
- throw new IllegalStateException();
- }
-
ChunkVertexEncoder.Vertex vertex = this.vertices[this.vertexIndex];
vertex.color = ColorABGR.pack(red, green, blue, 1);
this.writtenAttributes |= ATTRIBUTE_COLOR_BIT;
@@ -78,10 +69,6 @@ public void setData(Material material, TranslucentGeometryCollector collector) {
@Override
public @NotNull VertexConsumer setColor(int argb) {
- if (this.isColorFixed) {
- throw new IllegalStateException();
- }
-
ChunkVertexEncoder.Vertex vertex = this.vertices[this.vertexIndex];
vertex.color = ColorARGB.toABGR(argb, 0xFF);
this.writtenAttributes |= ATTRIBUTE_COLOR_BIT;
@@ -131,12 +118,6 @@ public void setData(Material material, TranslucentGeometryCollector collector) {
}
public VertexConsumer potentiallyEndVertex() {
- if (this.isColorFixed) {
- ChunkVertexEncoder.Vertex vertex = this.vertices[this.vertexIndex];
- vertex.color = this.fixedColor;
- this.writtenAttributes |= ATTRIBUTE_COLOR_BIT;
- }
-
if (this.writtenAttributes != REQUIRED_ATTRIBUTES) {
return this;
}
@@ -163,7 +144,7 @@ public VertexConsumer potentiallyEndVertex() {
v += vertex.v;
}
- TextureAtlasSprite sprite = SpriteFinderCache.forBlockAtlas().find(u * 0.25f, v * 0.25f);
+ TextureAtlasSprite sprite = PlatformTextureAccess.getInstance().findInBlockAtlas(u * 0.25f, v * 0.25f);
if (sprite != null) {
this.modelBuilder.addSprite(sprite);
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkBuilder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJob.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobCollector.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobQueue.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobResult.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/executor/ChunkJobTyped.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java
similarity index 95%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java
index 432aae1259..294b2b96e4 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockOcclusionCache.java
@@ -2,6 +2,7 @@
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
import net.caffeinemc.mods.sodium.client.util.DirectionUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@@ -44,7 +45,7 @@ public boolean shouldDrawSide(BlockState selfState, BlockGetter view, BlockPos s
// Blocks can define special behavior to control whether faces are rendered.
// This is mostly used by transparent blocks (Leaves, Glass, etc.) to not render interior faces between blocks
// of the same type.
- if (selfState.skipRendering(otherState, facing)) {
+ if (selfState.skipRendering(otherState, facing) || PlatformBlockAccess.getInstance().shouldSkipRender(view, selfState, otherState, selfPos, otherPos, facing)) {
return false;
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java
similarity index 90%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java
index cdeb4b969d..c183c305e3 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderCache.java
@@ -3,6 +3,7 @@
import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
import net.caffeinemc.mods.sodium.client.model.light.data.ArrayLightDataCache;
+import net.caffeinemc.mods.sodium.client.services.PlatformLevelAccess;
import net.caffeinemc.mods.sodium.client.world.LevelSlice;
import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext;
import net.minecraft.client.Minecraft;
@@ -27,7 +28,7 @@ public BlockRenderCache(Minecraft minecraft, ClientLevel level) {
var colorRegistry = new ColorProviderRegistry(minecraft.getBlockColors());
this.blockRenderer = new BlockRenderer(colorRegistry, lightPipelineProvider);
- this.fluidRenderer = new FluidRenderer(colorRegistry, lightPipelineProvider);
+ this.fluidRenderer = PlatformLevelAccess.getInstance().createPlatformFluidRenderer(colorRegistry, lightPipelineProvider);
this.blockModels = minecraft.getModelManager().getBlockModelShaper();
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderContext.java
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java
new file mode 100644
index 0000000000..9d29915ec9
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/BlockRenderer.java
@@ -0,0 +1,186 @@
+package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline;
+
+import net.caffeinemc.mods.sodium.client.model.color.ColorProvider;
+import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
+import net.caffeinemc.mods.sodium.client.model.light.LightMode;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadOrientation;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.buffers.ChunkModelBuilder;
+import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials;
+import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material;
+import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector;
+import net.caffeinemc.mods.sodium.client.render.chunk.vertex.builder.ChunkMeshBufferBuilder;
+import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MutableQuadViewImpl;
+import net.caffeinemc.mods.sodium.client.render.frapi.render.AbstractBlockRenderContext;
+import net.caffeinemc.mods.sodium.client.services.PlatformModelAccess;
+import net.caffeinemc.mods.sodium.client.services.PlatformTextureAccess;
+import net.caffeinemc.mods.sodium.client.services.SodiumModelData;
+import net.caffeinemc.mods.sodium.client.world.LevelSlice;
+import net.caffeinemc.mods.sodium.api.util.ColorARGB;
+import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
+import net.fabricmc.fabric.api.util.TriState;
+import net.minecraft.client.renderer.ItemBlockRenderTypes;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.levelgen.SingleThreadedRandomSource;
+import net.minecraft.world.phys.Vec3;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector3f;
+
+public class BlockRenderer extends AbstractBlockRenderContext {
+ private final ColorProviderRegistry colorProviderRegistry;
+ private final int[] vertexColors = new int[4];
+ private final ChunkVertexEncoder.Vertex[] vertices = ChunkVertexEncoder.Vertex.uninitializedQuad();
+
+ private ChunkBuildBuffers buffers;
+
+ private final Vector3f posOffset = new Vector3f();
+ @Nullable
+ private ColorProvider colorProvider;
+ private TranslucentGeometryCollector collector;
+
+ public BlockRenderer(ColorProviderRegistry colorRegistry, LightPipelineProvider lighters) {
+ this.colorProviderRegistry = colorRegistry;
+ this.lighters = lighters;
+
+ this.random = new SingleThreadedRandomSource(42L);
+ }
+
+ public void prepare(ChunkBuildBuffers buffers, LevelSlice level, TranslucentGeometryCollector collector) {
+ this.buffers = buffers;
+ this.level = level;
+ this.collector = collector;
+ this.slice = level;
+ }
+
+ public void release() {
+ this.buffers = null;
+ this.level = null;
+ this.collector = null;
+ this.slice = null;
+ }
+
+ public void renderModel(BakedModel model, BlockState state, BlockPos pos, BlockPos origin) {
+ this.state = state;
+ this.pos = pos;
+
+ this.randomSeed = state.getSeed(pos);
+
+ this.posOffset.set(origin.getX(), origin.getY(), origin.getZ());
+ if (state.hasOffsetFunction()) {
+ Vec3 modelOffset = state.getOffset(this.level, pos);
+ this.posOffset.add((float) modelOffset.x, (float) modelOffset.y, (float) modelOffset.z);
+ }
+
+ this.colorProvider = this.colorProviderRegistry.getColorProvider(state.getBlock());
+
+ type = ItemBlockRenderTypes.getChunkRenderType(state);
+
+ this.prepareCulling(true);
+ this.prepareAoInfo(model.useAmbientOcclusion());
+
+ modelData = PlatformModelAccess.getInstance().getModelData(slice, model, state, pos, slice.getPlatformModelData(pos));
+
+ Iterable renderTypes = PlatformModelAccess.getInstance().getModelRenderTypes(level, model, state, pos, random, modelData);
+
+ for (RenderType type : renderTypes) {
+ this.type = type;
+ ((FabricBakedModel) model).emitBlockQuads(this.level, state, pos, this.randomSupplier, this);
+ }
+
+ type = null;
+ modelData = SodiumModelData.EMPTY;
+ }
+
+ /**
+ * Process quad, after quad transforms and the culling check have been applied.
+ */
+ @Override
+ protected void processQuad(MutableQuadViewImpl quad) {
+ final RenderMaterial mat = quad.material();
+ final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
+ final TriState aoMode = mat.ambientOcclusion();
+ final LightMode lightMode;
+ if (aoMode == TriState.DEFAULT) {
+ lightMode = this.defaultLightMode;
+ } else {
+ lightMode = this.useAmbientOcclusion && aoMode.get() ? LightMode.SMOOTH : LightMode.FLAT;
+ }
+ final boolean emissive = mat.emissive();
+
+ Material material;
+
+ final BlendMode blendMode = mat.blendMode();
+ if (blendMode == BlendMode.DEFAULT) {
+ material = DefaultMaterials.forRenderLayer(type);
+ } else {
+ material = DefaultMaterials.forRenderLayer(blendMode.blockRenderLayer == null ? type : blendMode.blockRenderLayer);
+ }
+
+ ChunkModelBuilder builder = this.buffers.get(material);
+
+ this.colorizeQuad(quad, colorIndex);
+ this.shadeQuad(quad, lightMode, emissive);
+ this.bufferQuad(quad, this.quadLightData.br, material, builder);
+ }
+
+ private void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
+ if (colorIndex != -1) {
+ ColorProvider colorProvider = this.colorProvider;
+
+ if (colorProvider != null) {
+ int[] vertexColors = this.vertexColors;
+ colorProvider.getColors(this.slice, this.pos, this.state, quad, vertexColors);
+
+ for (int i = 0; i < 4; i++) {
+ // Set alpha to 0xFF in case a quad transform inspects the color.
+ // We do not support per-vertex alpha, however, so this will get discarded at vertex encoding time.
+ quad.color(i, ColorHelper.multiplyColor(0xFF000000 | vertexColors[i], quad.color(i)));
+ }
+ }
+ }
+ }
+
+ private void bufferQuad(MutableQuadViewImpl quad, float[] brightnesses, Material material, ChunkModelBuilder modelBuilder) {
+ ModelQuadOrientation orientation = defaultLightMode == LightMode.FLAT ? ModelQuadOrientation.NORMAL : ModelQuadOrientation.orientByBrightness(brightnesses, quad);
+ ChunkVertexEncoder.Vertex[] vertices = this.vertices;
+ Vector3f offset = this.posOffset;
+
+ for (int dstIndex = 0; dstIndex < 4; dstIndex++) {
+ int srcIndex = orientation.getVertexIndex(dstIndex);
+
+ ChunkVertexEncoder.Vertex out = vertices[dstIndex];
+ out.x = quad.x(srcIndex) + offset.x;
+ out.y = quad.y(srcIndex) + offset.y;
+ out.z = quad.z(srcIndex) + offset.z;
+
+ // FRAPI uses ARGB color format; convert to ABGR.
+ // Due to our vertex format, the alpha from the quad color is ignored entirely.
+ out.color = ColorARGB.toABGR(quad.color(srcIndex), brightnesses[srcIndex]);
+
+ out.u = quad.u(srcIndex);
+ out.v = quad.v(srcIndex);
+
+ out.light = quad.lightmap(srcIndex);
+ }
+
+ ModelQuadFacing normalFace = quad.normalFace();
+
+ if (material == DefaultMaterials.TRANSLUCENT && collector != null) {
+ collector.appendQuad(quad.getFaceNormal(), vertices, normalFace);
+ }
+
+ ChunkMeshBufferBuilder vertexBuffer = modelBuilder.getVertexBuffer(normalFace);
+ vertexBuffer.push(vertices, material);
+
+ modelBuilder.addSprite(PlatformTextureAccess.getInstance().findInBlockAtlas(quad.getTexU(0), quad.getTexV(0)));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java
similarity index 91%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java
index 483eea8418..548461405e 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/DefaultFluidRenderer.java
@@ -2,6 +2,7 @@
import net.caffeinemc.mods.sodium.api.util.ColorABGR;
+import net.caffeinemc.mods.sodium.api.util.ColorARGB;
import net.caffeinemc.mods.sodium.api.util.NormI8;
import net.caffeinemc.mods.sodium.client.model.color.ColorProvider;
import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
@@ -20,10 +21,9 @@
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.Material;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector;
import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexEncoder;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
import net.caffeinemc.mods.sodium.client.util.DirectionUtil;
import net.caffeinemc.mods.sodium.client.world.LevelSlice;
-import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler;
-import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
@@ -98,7 +98,7 @@ private boolean isSideExposed(BlockAndTintGetter world, int x, int y, int z, Dir
return true;
}
- public void render(LevelSlice level, FluidState fluidState, BlockPos blockPos, BlockPos offset, TranslucentGeometryCollector collector, ChunkModelBuilder meshBuilder, Material material, FluidRenderHandler handler) {
+ public void render(LevelSlice level, FluidState fluidState, BlockPos blockPos, BlockPos offset, TranslucentGeometryCollector collector, ChunkModelBuilder meshBuilder, Material material, ColorProvider colorProvider, TextureAtlasSprite[] sprites) {
int posX = blockPos.getX();
int posY = blockPos.getY();
int posZ = blockPos.getZ();
@@ -119,10 +119,6 @@ public void render(LevelSlice level, FluidState fluidState, BlockPos blockPos, B
boolean isWater = fluidState.is(FluidTags.WATER);
- final ColorProvider colorProvider = this.getColorProvider(fluid, handler);
-
- TextureAtlasSprite[] sprites = handler.getFluidSprites(level, blockPos, fluidState);
-
float fluidHeight = this.fluidHeight(level, fluid, blockPos, Direction.UP);
float northWestHeight, southWestHeight, southEastHeight, northEastHeight;
if (fluidHeight >= 1.0f) {
@@ -234,7 +230,7 @@ && isAlignedEquals(southEastHeight, southWestHeight)
setVertex(quad, 3, 1.0F, northEastHeight, 0.0f, u4, v4);
}
- this.updateQuad(quad, level, blockPos, lighter, Direction.UP, 1.0F, colorProvider, fluidState);
+ this.updateQuad(quad, level, blockPos, lighter, Direction.UP, ModelQuadFacing.POS_Y, 1.0F, colorProvider, fluidState);
this.writeQuad(meshBuilder, collector, material, offset, quad, aligned ? ModelQuadFacing.POS_Y : ModelQuadFacing.UNASSIGNED, false);
if (fluidState.shouldRenderBackwardUpFace(level, this.scratchPos.set(posX, posY + 1, posZ))) {
@@ -257,7 +253,7 @@ && isAlignedEquals(southEastHeight, southWestHeight)
setVertex(quad, 2, 1.0F, yOffset, 0.0f, maxU, minV);
setVertex(quad, 3, 1.0F, yOffset, 1.0F, maxU, maxV);
- this.updateQuad(quad, level, blockPos, lighter, Direction.DOWN, 1.0F, colorProvider, fluidState);
+ this.updateQuad(quad, level, blockPos, lighter, Direction.DOWN, ModelQuadFacing.NEG_Y, 1.0F, colorProvider, fluidState);
this.writeQuad(meshBuilder, collector, material, offset, quad, ModelQuadFacing.NEG_Y, false);
}
@@ -330,11 +326,11 @@ && isAlignedEquals(southEastHeight, southWestHeight)
boolean isOverlay = false;
- if (sprites.length > 2) {
+ if (sprites.length > 2 && sprites[2] != null) {
BlockPos adjPos = this.scratchPos.set(adjX, adjY, adjZ);
BlockState adjBlock = level.getBlockState(adjPos);
- if (FluidRenderHandlerRegistry.INSTANCE.isBlockTransparent(adjBlock.getBlock())) {
+ if (PlatformBlockAccess.getInstance().shouldShowFluidOverlay(adjBlock, level, adjPos, fluidState)) {
sprite = sprites[2];
isOverlay = true;
}
@@ -357,7 +353,7 @@ && isAlignedEquals(southEastHeight, southWestHeight)
ModelQuadFacing facing = ModelQuadFacing.fromDirection(dir);
- this.updateQuad(quad, level, blockPos, lighter, dir, br, colorProvider, fluidState);
+ this.updateQuad(quad, level, blockPos, lighter, dir, facing, br, colorProvider, fluidState);
this.writeQuad(meshBuilder, collector, material, offset, quad, facing, false);
if (!isOverlay) {
@@ -372,38 +368,28 @@ private static boolean isAlignedEquals(float a, float b) {
return Math.abs(a - b) <= ALIGNED_EQUALS_EPSILON;
}
- private ColorProvider getColorProvider(Fluid fluid, FluidRenderHandler handler) {
- var override = this.colorProviderRegistry.getColorProvider(fluid);
+ private void updateQuad(ModelQuadViewMutable quad, LevelSlice level, BlockPos pos, LightPipeline lighter, Direction dir, ModelQuadFacing facing, float brightness,
+ ColorProvider colorProvider, FluidState fluidState) {
- if (override != null) {
- return override;
+ int normal;
+ if (facing.isAligned()) {
+ normal = facing.getPackedAlignedNormal();
+ } else {
+ normal = quad.calculateNormal();
}
- return DefaultColorProviders.adapt(handler);
- }
-
- private static FluidRenderHandler getFluidRenderHandler(FluidState fluidState) {
- FluidRenderHandler handler = FluidRenderHandlerRegistry.INSTANCE.get(fluidState.getType());
-
- // Match the vanilla FluidRenderer's behavior if the handler is null
- if (handler == null) {
- boolean isLava = fluidState.is(FluidTags.LAVA);
- handler = FluidRenderHandlerRegistry.INSTANCE.get(isLava ? Fluids.LAVA : Fluids.WATER);
- }
- return handler;
- }
+ quad.setFaceNormal(normal);
- private void updateQuad(ModelQuadView quad, LevelSlice level, BlockPos pos, LightPipeline lighter, Direction dir, float brightness,
- ColorProvider colorProvider, FluidState fluidState) {
QuadLightData light = this.quadLightData;
- lighter.calculate(quad, pos, light, null, dir, false);
+
+ lighter.calculate(quad, pos, light, null, dir, false, true);
colorProvider.getColors(level, pos, fluidState, quad, this.quadColors);
// multiply the per-vertex color against the combined brightness
// the combined brightness is the per-vertex brightness multiplied by the block's brightness
for (int i = 0; i < 4; i++) {
- this.quadColors[i] = ColorABGR.withAlpha(this.quadColors[i], light.br[i] * brightness);
+ this.quadColors[i] = ColorARGB.toABGR(this.quadColors[i], light.br[i] * brightness);
}
}
@@ -431,14 +417,18 @@ private void writeQuad(ChunkModelBuilder builder, TranslucentGeometryCollector c
if (material.isTranslucent() && collector != null) {
int normal;
+
if (facing.isAligned()) {
normal = facing.getPackedAlignedNormal();
} else {
- normal = quad.calculateNormal();
+ // This was updated earlier in updateQuad. There is no situation where the normal vector should have changed.
+ normal = quad.getFaceNormal();
}
+
if (flip) {
normal = NormI8.flipPacked(normal);
}
+
collector.appendQuad(normal, vertices, facing);
}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java
new file mode 100644
index 0000000000..5a9a16766d
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/pipeline/FluidRenderer.java
@@ -0,0 +1,14 @@
+package net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline;
+
+import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.ChunkBuildBuffers;
+import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector;
+import net.caffeinemc.mods.sodium.client.world.LevelSlice;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.FluidState;
+
+public abstract class FluidRenderer {
+ public abstract void render(LevelSlice level, BlockState blockState, FluidState fluidState, BlockPos blockPos, BlockPos offset, TranslucentGeometryCollector collector, ChunkBuildBuffers buffers);
+}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java
similarity index 91%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java
index 1070f0c462..4ab680ef8b 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderMeshingTask.java
@@ -9,15 +9,18 @@
import net.caffeinemc.mods.sodium.client.render.chunk.compile.executor.ChunkBuilder;
import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderCache;
import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderer;
import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionInfo;
import net.caffeinemc.mods.sodium.client.render.chunk.data.BuiltSectionMeshParts;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.DefaultTerrainRenderPasses;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
+import net.caffeinemc.mods.sodium.client.render.chunk.terrain.material.DefaultMaterials;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortType;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.TranslucentGeometryCollector;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.PresentTranslucentData;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.data.TranslucentData;
+import net.caffeinemc.mods.sodium.client.services.PlatformLevelAccess;
import net.caffeinemc.mods.sodium.client.util.task.CancellationToken;
import net.caffeinemc.mods.sodium.client.world.LevelSlice;
import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext;
@@ -77,11 +80,14 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke
BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(minX, minY, minZ);
BlockPos.MutableBlockPos modelOffset = new BlockPos.MutableBlockPos();
- TranslucentGeometryCollector collector = null;
+ TranslucentGeometryCollector collector;
if (SodiumClientMod.options().performance.getSortBehavior() != SortBehavior.OFF) {
collector = new TranslucentGeometryCollector(render.getPosition());
+ } else {
+ collector = null;
}
- BlockRenderContext context = new BlockRenderContext(slice, collector);
+ BlockRenderer blockRenderer = cache.getBlockRenderer();
+ blockRenderer.prepare(buffers, slice, collector);
try {
for (int y = minY; y < maxY; y++) {
@@ -102,13 +108,8 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke
if (blockState.getRenderShape() == RenderShape.MODEL) {
BakedModel model = cache.getBlockModels()
- .getBlockModel(blockState);
-
- long seed = blockState.getSeed(blockPos);
-
- context.update(blockPos, modelOffset, blockState, model, seed);
- cache.getBlockRenderer()
- .renderModel(context, buffers);
+ .getBlockModel(blockState);
+ blockRenderer.renderModel(model, blockState, blockPos, modelOffset);
}
FluidState fluidState = blockState.getFluidState();
@@ -143,6 +144,11 @@ public ChunkBuildOutput execute(ChunkBuildContext buildContext, CancellationToke
throw fillCrashInfo(CrashReport.forThrowable(ex, "Encountered exception while building chunk meshes"), slice, blockPos);
}
+ PlatformLevelAccess.INSTANCE.renderAdditionalRenderers(renderContext.getRenderers(), type -> buffers.get(DefaultMaterials.forRenderLayer(type)).asFallbackVertexConsumer(DefaultMaterials.forRenderLayer(type), collector),
+ slice);
+
+ blockRenderer.release();
+
SortType sortType = SortType.NONE;
if (collector != null) {
sortType = collector.finishRendering();
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderSortingTask.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/compile/tasks/ChunkBuilderTask.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionInfo.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/BuiltSectionMeshParts.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataStorage.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/data/SectionRenderDataUnsafe.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderList.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/ChunkRenderListIterable.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/SortedRenderLists.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/lists/VisibleChunkCollector.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkStatus.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTracker.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ChunkTrackerHolder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/map/ClientChunkEventListener.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirection.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/GraphDirectionSet.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/OcclusionCuller.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/occlusion/VisibilityEncoding.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegion.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/region/RenderRegionManager.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkFogMode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderBindingPoints.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderFogComponent.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderInterface.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderOptions.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ChunkShaderTextureSlot.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/shader/ShaderBindingContext.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/DefaultTerrainRenderPasses.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/TerrainRenderPass.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/DefaultMaterials.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/Material.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/AlphaCutoffParameter.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/terrain/material/parameters/MaterialParameters.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/AlignableNormal.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortBehavior.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/SortType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TQuad.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/TranslucentGeometryCollector.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPBuildFailureException.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPResult.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPSortState.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/BSPWorkspace.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerBinaryPartitionBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerFixedDoubleBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerFixedDoubleBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerFixedDoubleBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerFixedDoubleBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerMultiPartitionBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/InnerPartitionBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafDoubleBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafMultiBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/LeafSingleBSPNode.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/bsp_tree/Partition.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/AnyOrderData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/CombinedCameraPos.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicBSPData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicBSPData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicBSPData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicBSPData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicSorter.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicSorter.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicSorter.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicSorter.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicTopoData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicTopoData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicTopoData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/DynamicTopoData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/MixedDirectionData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/NoData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentSortData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentSortData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentSortData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentSortData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/PresentTranslucentData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SortData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SortData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SortData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SortData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/Sorter.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/Sorter.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/Sorter.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/Sorter.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/SplitDirectionData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticNormalRelativeData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticSorter.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticSorter.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticSorter.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticSorter.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/StaticTopoData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TopoGraphSorting.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/data/TranslucentData.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/CameraMovement.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/DirectTriggers.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GFNITriggers.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/GeometryPlanes.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/Group.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java
similarity index 97%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java
index 5c08e996ac..02878e1589 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalList.java
@@ -2,6 +2,7 @@
import java.util.Collection;
+import org.joml.Math;
import org.joml.Vector3dc;
import com.lodborg.intervaltree.DoubleInterval;
@@ -69,9 +70,9 @@ public AlignableNormal getNormal() {
}
private double normalDotDouble(Vector3dc v) {
- return Math.fma((double) this.normal.x, v.x(),
- Math.fma((double) this.normal.y, v.y(),
- (double) this.normal.z * v.z()));
+ return org.joml.Math.fma(this.normal.x, v.x(),
+ org.joml.Math.fma(this.normal.y, v.y(),
+ this.normal.z * v.z()));
}
void processMovement(SortTriggering ts, CameraMovement movement) {
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/NormalPlanes.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/translucent_sorting/trigger/SortTriggering.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/builder/ChunkMeshBufferBuilder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshAttribute.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkMeshFormats.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexEncoder.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/ChunkVertexType.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java
similarity index 70%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java
index 3a9918bef2..67dba7bdad 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/chunk/vertex/format/impl/CompactChunkVertex.java
@@ -12,8 +12,8 @@ public class CompactChunkVertex implements ChunkVertexType {
public static final int STRIDE = 20;
public static final GlVertexFormat VERTEX_FORMAT = GlVertexFormat.builder(ChunkMeshAttribute.class, STRIDE)
- .addElement(ChunkMeshAttribute.POSITION_HI, 0, GlVertexAttributeFormat.UNSIGNED_2_10_10_10_REV, 4, false, false)
- .addElement(ChunkMeshAttribute.POSITION_LO, 4, GlVertexAttributeFormat.UNSIGNED_2_10_10_10_REV, 4, false, false)
+ .addElement(ChunkMeshAttribute.POSITION_HI, 0, GlVertexAttributeFormat.UNSIGNED_INT, 1, false, true)
+ .addElement(ChunkMeshAttribute.POSITION_LO, 4, GlVertexAttributeFormat.UNSIGNED_INT, 1, false, true)
.addElement(ChunkMeshAttribute.COLOR, 8, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, true, false)
.addElement(ChunkMeshAttribute.TEXTURE, 12, GlVertexAttributeFormat.UNSIGNED_SHORT, 2, false, true)
.addElement(ChunkMeshAttribute.LIGHT_MATERIAL_INDEX, 16, GlVertexAttributeFormat.UNSIGNED_BYTE, 4, false, true)
@@ -22,8 +22,8 @@ public class CompactChunkVertex implements ChunkVertexType {
private static final int POSITION_MAX_VALUE = 1 << 20;
private static final int TEXTURE_MAX_VALUE = 1 << 15;
- private static final float MODEL_TRANSLATION = 8.0f;
- private static final float MODEL_SCALE = 32.0f;
+ private static final float MODEL_ORIGIN = 8.0f;
+ private static final float MODEL_RANGE = 32.0f;
@Override
public GlVertexFormat getVertexFormat() {
@@ -48,9 +48,9 @@ public ChunkVertexEncoder getEncoder() {
for (int i = 0; i < 4; i++) {
var vertex = vertices[i];
- int x = encodePosition(vertex.x);
- int y = encodePosition(vertex.y);
- int z = encodePosition(vertex.z);
+ int x = quantizePosition(vertex.x);
+ int y = quantizePosition(vertex.y);
+ int z = quantizePosition(vertex.z);
int u = encodeTexture(texCentroidU, vertex.u);
int v = encodeTexture(texCentroidV, vertex.v);
@@ -82,8 +82,12 @@ private static int packPositionLo(int x, int y, int z) {
((z & 0x3FF) << 20);
}
- private static int encodePosition(float position) {
- return Math.round((position + MODEL_TRANSLATION) * (POSITION_MAX_VALUE / MODEL_SCALE));
+ private static int quantizePosition(float position) {
+ return ((int) (normalizePosition(position) * POSITION_MAX_VALUE)) & 0xFFFFF;
+ }
+
+ private static float normalizePosition(float v) {
+ return (MODEL_ORIGIN + v) / MODEL_RANGE;
}
private static int packTexture(int u, int v) {
@@ -91,22 +95,16 @@ private static int packTexture(int u, int v) {
}
private static int encodeTexture(float center, float x) {
- // Normally, the UV coordinates are shrunk towards the center of the texture by a very small epsilon to avoid
- // texture bleeding between sprites in the atlas. When compressing to smaller integer formats, this creates a
- // problem, since the very small offsets can not be encoded without using a significant number of bits.
- //
- // Rather than encoding very small epsilons, we use a single bit to represent the sign of a constant bias
- // value, which is then applied in the shader code. The sign of the bias is determined by comparing the
- // coordinates to the center point of the texture region.
+ // Shrink the texture coordinates (towards the center of the mapped texture region) by the minimum
+ // addressable unit (after quantization.) Then, encode the sign of the bias that was used, and apply
+ // the inverse transformation on the GPU with a small epsilon.
//
- // By always shrinking the texture coordinates at least one unit, we also avoid needing to encode both x=0.0 and
- // x=1.0, which normally requires an extra bit to represent.
+ // This makes it possible to use much smaller epsilons for avoiding texture bleed, since the epsilon is no
+ // longer encoded into the vertex data (instead, we only store the sign.)
int bias = (x < center) ? 1 : -1;
int quantized = floorInt(x * TEXTURE_MAX_VALUE) + bias;
- // When packing the values into a 16-bit unsigned integer, the 15-bit quantized value is shifted to the left by
- // one, and the least-significant bit (which is now zero-filled) is used to store the sign of the bias.
- return ((quantized & 0x7FFF) << 1) | (bias >>> 31);
+ return (quantized & 0x7FFF) | (sign(bias) << 15);
}
private static int encodeLight(int light) {
@@ -122,6 +120,12 @@ private static int packLightAndData(int light, int material, int section) {
((section & 0xFF) << 24);
}
+ private static int sign(int x) {
+ // Shift the sign-bit to the least significant bit's position
+ // (0) if positive, (1) if negative
+ return (x >>> 31);
+ }
+
private static int floorInt(float x) {
return (int) Math.floor(x);
}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/SodiumRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/SodiumRenderer.java
new file mode 100644
index 0000000000..7b39a52063
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/SodiumRenderer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi;
+
+import net.caffeinemc.mods.sodium.client.render.frapi.material.MaterialFinderImpl;
+import net.caffeinemc.mods.sodium.client.render.frapi.material.RenderMaterialImpl;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MeshBuilderImpl;
+import net.fabricmc.fabric.api.renderer.v1.Renderer;
+import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
+import net.minecraft.resources.ResourceLocation;
+
+import java.util.HashMap;
+
+/**
+ * The Sodium renderer implementation.
+ */
+public class SodiumRenderer implements Renderer {
+ public static final SodiumRenderer INSTANCE = new SodiumRenderer();
+
+ public static final RenderMaterial STANDARD_MATERIAL = INSTANCE.materialFinder().find();
+
+ static {
+ INSTANCE.registerMaterial(RenderMaterial.MATERIAL_STANDARD, STANDARD_MATERIAL);
+ }
+
+ private final HashMap materialMap = new HashMap<>();
+
+ private SodiumRenderer() { }
+
+ @Override
+ public MeshBuilder meshBuilder() {
+ return new MeshBuilderImpl();
+ }
+
+ @Override
+ public MaterialFinder materialFinder() {
+ return new MaterialFinderImpl();
+ }
+
+ @Override
+ public RenderMaterial materialById(ResourceLocation id) {
+ return materialMap.get(id);
+ }
+
+ @Override
+ public boolean registerMaterial(ResourceLocation id, RenderMaterial material) {
+ if (materialMap.containsKey(id)) return false;
+
+ // cast to prevent acceptance of impostor implementations
+ materialMap.put(id, (RenderMaterialImpl) material);
+ return true;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/ColorHelper.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/ColorHelper.java
new file mode 100644
index 0000000000..9961263598
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/ColorHelper.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.helper;
+
+import java.nio.ByteOrder;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class ColorHelper {
+ private ColorHelper() { }
+
+ private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
+
+ /** Component-wise multiply. Components need to be in same order in both inputs! */
+ public static int multiplyColor(int color1, int color2) {
+ if (color1 == -1) {
+ return color2;
+ } else if (color2 == -1) {
+ return color1;
+ }
+
+ final int alpha = ((color1 >>> 24) & 0xFF) * ((color2 >>> 24) & 0xFF) / 0xFF;
+ final int red = ((color1 >>> 16) & 0xFF) * ((color2 >>> 16) & 0xFF) / 0xFF;
+ final int green = ((color1 >>> 8) & 0xFF) * ((color2 >>> 8) & 0xFF) / 0xFF;
+ final int blue = (color1 & 0xFF) * (color2 & 0xFF) / 0xFF;
+
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /** Multiplies three lowest components by shade. High byte (usually alpha) unchanged. */
+ public static int multiplyRGB(int color, float shade) {
+ final int alpha = ((color >>> 24) & 0xFF);
+ final int red = (int) (((color >>> 16) & 0xFF) * shade);
+ final int green = (int) (((color >>> 8) & 0xFF) * shade);
+ final int blue = (int) ((color & 0xFF) * shade);
+
+ return (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+
+ /**
+ * Component-wise max.
+ */
+ public static int maxBrightness(int b0, int b1) {
+ if (b0 == 0) return b1;
+ if (b1 == 0) return b0;
+
+ return Math.max(b0 & 0xFFFF, b1 & 0xFFFF) | Math.max(b0 & 0xFFFF0000, b1 & 0xFFFF0000);
+ }
+
+ /*
+ Renderer color format: ARGB (0xAARRGGBB)
+ Vanilla color format (little endian): ABGR (0xAABBGGRR)
+ Vanilla color format (big endian): RGBA (0xRRGGBBAA)
+
+ Why does the vanilla color format change based on endianness?
+ See VertexConsumer#quad. Quad data is loaded as integers into
+ a native byte order buffer. Color is read directly from bytes
+ 12, 13, 14 of each vertex. A different byte order will yield
+ different results.
+
+ The renderer always uses ARGB because the API color methods
+ always consume and return ARGB. Vanilla block and item colors
+ also use ARGB.
+ */
+
+ /**
+ * Converts from ARGB color to ABGR color if little endian or RGBA color if big endian.
+ */
+ public static int toVanillaColor(int color) {
+ if (color == -1) {
+ return -1;
+ }
+
+ if (BIG_ENDIAN) {
+ // ARGB to RGBA
+ return ((color & 0x00FFFFFF) << 8) | ((color & 0xFF000000) >>> 24);
+ } else {
+ // ARGB to ABGR
+ return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
+ }
+ }
+
+ /**
+ * Converts to ARGB color from ABGR color if little endian or RGBA color if big endian.
+ */
+ public static int fromVanillaColor(int color) {
+ if (color == -1) {
+ return -1;
+ }
+
+ if (BIG_ENDIAN) {
+ // RGBA to ARGB
+ return ((color & 0xFFFFFF00) >>> 8) | ((color & 0x000000FF) << 24);
+ } else {
+ // ABGR to ARGB
+ return (color & 0xFF00FF00) | ((color & 0x00FF0000) >>> 16) | ((color & 0x000000FF) << 16);
+ }
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/GeometryHelper.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/GeometryHelper.java
new file mode 100644
index 0000000000..da25fe4eda
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/GeometryHelper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.helper;
+
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
+import org.joml.Vector3f;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class GeometryHelper {
+ private GeometryHelper() { }
+
+ /**
+ * Returns true if quad is parallel to the given face.
+ * Does not validate quad winding order.
+ * Expects convex quads with all points co-planar.
+ */
+ public static boolean isQuadParallelToFace(Direction face, QuadView quad) {
+ int i = face.getAxis().ordinal();
+ final float val = quad.posByIndex(0, i);
+ return Mth.equal(val, quad.posByIndex(1, i)) && Mth.equal(val, quad.posByIndex(2, i)) && Mth.equal(val, quad.posByIndex(3, i));
+ }
+
+ /**
+ * Identifies the face to which the quad is most closely aligned.
+ * This mimics the value that {@link BakedQuad#getDirection()} returns, and is
+ * used in the vanilla renderer for all diffuse lighting.
+ *
+ *
Derived from the quad face normal and expects convex quads with all points co-planar.
+ */
+ public static Direction lightFace(QuadView quad) {
+ final Vector3f normal = quad.faceNormal();
+ return switch (GeometryHelper.longestAxis(normal)) {
+ case X -> normal.x() > 0 ? Direction.EAST : Direction.WEST;
+ case Y -> normal.y() > 0 ? Direction.UP : Direction.DOWN;
+ case Z -> normal.z() > 0 ? Direction.SOUTH : Direction.NORTH;
+ default ->
+ // handle WTF case
+ Direction.UP;
+ };
+ }
+
+ /**
+ * @see #longestAxis(float, float, float)
+ */
+ public static Direction.Axis longestAxis(Vector3f vec) {
+ return longestAxis(vec.x(), vec.y(), vec.z());
+ }
+
+ /**
+ * Identifies the largest (max absolute magnitude) component (X, Y, Z) in the given vector.
+ */
+ public static Direction.Axis longestAxis(float normalX, float normalY, float normalZ) {
+ Direction.Axis result = Direction.Axis.Y;
+ float longest = Math.abs(normalY);
+ float a = Math.abs(normalX);
+
+ if (a > longest) {
+ result = Direction.Axis.X;
+ longest = a;
+ }
+
+ return Math.abs(normalZ) > longest
+ ? Direction.Axis.Z : result;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/NormalHelper.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/NormalHelper.java
new file mode 100644
index 0000000000..f2fd5a5486
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/NormalHelper.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.helper;
+
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+import net.minecraft.core.Direction;
+import net.minecraft.core.Vec3i;
+import org.jetbrains.annotations.NotNull;
+import org.joml.Vector3f;
+
+/**
+ * Static routines of general utility for renderer implementations.
+ * Renderers are not required to use these helpers, but they were
+ * designed to be usable without the default renderer.
+ */
+public abstract class NormalHelper {
+ private NormalHelper() { }
+
+ /**
+ * Computes the face normal of the given quad and saves it in the provided non-null vector.
+ * If {@link QuadView#nominalFace()} is set will optimize by confirming quad is parallel to that
+ * face and, if so, use the standard normal for that face direction.
+ *
+ *
Will work with triangles also. Assumes counter-clockwise winding order, which is the norm.
+ * Expects convex quads with all points co-planar.
+ */
+ public static void computeFaceNormal(@NotNull Vector3f saveTo, QuadView q) {
+ final Direction nominalFace = q.nominalFace();
+
+ if (nominalFace != null && GeometryHelper.isQuadParallelToFace(nominalFace, q)) {
+ Vec3i vec = nominalFace.getNormal();
+ saveTo.set(vec.getX(), vec.getY(), vec.getZ());
+ return;
+ }
+
+ final float x0 = q.x(0);
+ final float y0 = q.y(0);
+ final float z0 = q.z(0);
+ final float x1 = q.x(1);
+ final float y1 = q.y(1);
+ final float z1 = q.z(1);
+ final float x2 = q.x(2);
+ final float y2 = q.y(2);
+ final float z2 = q.z(2);
+ final float x3 = q.x(3);
+ final float y3 = q.y(3);
+ final float z3 = q.z(3);
+
+ final float dx0 = x2 - x0;
+ final float dy0 = y2 - y0;
+ final float dz0 = z2 - z0;
+ final float dx1 = x3 - x1;
+ final float dy1 = y3 - y1;
+ final float dz1 = z3 - z1;
+
+ float normX = dy0 * dz1 - dz0 * dy1;
+ float normY = dz0 * dx1 - dx0 * dz1;
+ float normZ = dx0 * dy1 - dy0 * dx1;
+
+ float l = (float) Math.sqrt(normX * normX + normY * normY + normZ * normZ);
+
+ if (l != 0) {
+ normX /= l;
+ normY /= l;
+ normZ /= l;
+ }
+
+ saveTo.set(normX, normY, normZ);
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/TextureHelper.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/TextureHelper.java
new file mode 100644
index 0000000000..84e4e34327
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/helper/TextureHelper.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.helper;
+
+import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+
+/**
+ * Handles most texture-baking use cases for model loaders and model libraries
+ * via {@link #bakeSprite(MutableQuadView, TextureAtlasSprite, int)}. Also used by the API
+ * itself to implement automatic block-breaking models for enhanced models.
+ */
+public class TextureHelper {
+ private TextureHelper() { }
+
+ private static final float NORMALIZER = 1f / 16f;
+
+ /**
+ * Bakes textures in the provided vertex data, handling UV locking,
+ * rotation, interpolation, etc. Textures must not be already baked.
+ */
+ public static void bakeSprite(MutableQuadView quad, TextureAtlasSprite sprite, int bakeFlags) {
+ if (quad.nominalFace() != null && (MutableQuadView.BAKE_LOCK_UV & bakeFlags) != 0) {
+ // Assigns normalized UV coordinates based on vertex positions
+ applyModifier(quad, UVLOCKERS[quad.nominalFace().get3DDataValue()]);
+ } else if ((MutableQuadView.BAKE_NORMALIZED & bakeFlags) == 0) { // flag is NOT set, UVs are assumed to not be normalized yet as is the default, normalize through dividing by 16
+ // Scales from 0-16 to 0-1
+ applyModifier(quad, (q, i) -> q.uv(i, q.u(i) * NORMALIZER, q.v(i) * NORMALIZER));
+ }
+
+ final int rotation = bakeFlags & 3;
+
+ if (rotation != 0) {
+ // Rotates texture around the center of sprite.
+ // Assumes normalized coordinates.
+ applyModifier(quad, ROTATIONS[rotation]);
+ }
+
+ if ((MutableQuadView.BAKE_FLIP_U & bakeFlags) != 0) {
+ // Inverts U coordinates. Assumes normalized (0-1) values.
+ applyModifier(quad, (q, i) -> q.uv(i, 1 - q.u(i), q.v(i)));
+ }
+
+ if ((MutableQuadView.BAKE_FLIP_V & bakeFlags) != 0) {
+ // Inverts V coordinates. Assumes normalized (0-1) values.
+ applyModifier(quad, (q, i) -> q.uv(i, q.u(i), 1 - q.v(i)));
+ }
+
+ interpolate(quad, sprite);
+ }
+
+ /**
+ * Faster than sprite method. Sprite computes span and normalizes inputs each call,
+ * so we'd have to denormalize before we called, only to have the sprite renormalize immediately.
+ */
+ private static void interpolate(MutableQuadView q, TextureAtlasSprite sprite) {
+ final float uMin = sprite.getU0();
+ final float uSpan = sprite.getU1() - uMin;
+ final float vMin = sprite.getV0();
+ final float vSpan = sprite.getV1() - vMin;
+
+ for (int i = 0; i < 4; i++) {
+ q.uv(i, uMin + q.u(i) * uSpan, vMin + q.v(i) * vSpan);
+ }
+ }
+
+ @FunctionalInterface
+ private interface VertexModifier {
+ void apply(MutableQuadView quad, int vertexIndex);
+ }
+
+ private static void applyModifier(MutableQuadView quad, VertexModifier modifier) {
+ for (int i = 0; i < 4; i++) {
+ modifier.apply(quad, i);
+ }
+ }
+
+ private static final VertexModifier[] ROTATIONS = new VertexModifier[] {
+ null,
+ (q, i) -> q.uv(i, q.v(i), 1 - q.u(i)), //90
+ (q, i) -> q.uv(i, 1 - q.u(i), 1 - q.v(i)), //180
+ (q, i) -> q.uv(i, 1 - q.v(i), q.u(i)) // 270
+ };
+
+ private static final VertexModifier[] UVLOCKERS = new VertexModifier[6];
+
+ static {
+ UVLOCKERS[Direction.EAST.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.z(i), 1 - q.y(i));
+ UVLOCKERS[Direction.WEST.get3DDataValue()] = (q, i) -> q.uv(i, q.z(i), 1 - q.y(i));
+ UVLOCKERS[Direction.NORTH.get3DDataValue()] = (q, i) -> q.uv(i, 1 - q.x(i), 1 - q.y(i));
+ UVLOCKERS[Direction.SOUTH.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.y(i));
+ UVLOCKERS[Direction.DOWN.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), 1 - q.z(i));
+ UVLOCKERS[Direction.UP.get3DDataValue()] = (q, i) -> q.uv(i, q.x(i), q.z(i));
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialFinderImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialFinderImpl.java
new file mode 100644
index 0000000000..e5b204b32e
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialFinderImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.material;
+
+import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
+import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
+import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.util.TriState;
+
+import java.util.Objects;
+
+public class MaterialFinderImpl extends MaterialViewImpl implements MaterialFinder {
+ private static int defaultBits = 0;
+
+ static {
+ MaterialFinderImpl finder = new MaterialFinderImpl();
+ finder.ambientOcclusion(TriState.DEFAULT);
+ finder.glint(TriState.DEFAULT);
+ defaultBits = finder.bits;
+
+ if (!areBitsValid(defaultBits)) {
+ throw new AssertionError("Default MaterialFinder bits are not valid!");
+ }
+ }
+
+ public MaterialFinderImpl() {
+ super(defaultBits);
+ }
+
+ @Override
+ public MaterialFinder blendMode(BlendMode blendMode) {
+ Objects.requireNonNull(blendMode, "BlendMode may not be null");
+
+ bits = (bits & ~BLEND_MODE_MASK) | (blendMode.ordinal() << BLEND_MODE_BIT_OFFSET);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder disableColorIndex(boolean disable) {
+ bits = disable ? (bits | COLOR_DISABLE_FLAG) : (bits & ~COLOR_DISABLE_FLAG);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder emissive(boolean isEmissive) {
+ bits = isEmissive ? (bits | EMISSIVE_FLAG) : (bits & ~EMISSIVE_FLAG);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder disableDiffuse(boolean disable) {
+ bits = disable ? (bits | DIFFUSE_FLAG) : (bits & ~DIFFUSE_FLAG);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder ambientOcclusion(TriState mode) {
+ Objects.requireNonNull(mode, "ambient occlusion TriState may not be null");
+
+ bits = (bits & ~AO_MASK) | (mode.ordinal() << AO_BIT_OFFSET);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder glint(TriState mode) {
+ Objects.requireNonNull(mode, "glint TriState may not be null");
+
+ bits = (bits & ~GLINT_MASK) | (mode.ordinal() << GLINT_BIT_OFFSET);
+ return this;
+ }
+
+ @Override
+ public MaterialFinder copyFrom(MaterialView material) {
+ bits = ((MaterialViewImpl) material).bits;
+ return this;
+ }
+
+ @Override
+ public MaterialFinder clear() {
+ bits = defaultBits;
+ return this;
+ }
+
+ @Override
+ public RenderMaterial find() {
+ return RenderMaterialImpl.byIndex(bits);
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialViewImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialViewImpl.java
new file mode 100644
index 0000000000..2cb8a4a8f9
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/MaterialViewImpl.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.material;
+
+import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
+import net.fabricmc.fabric.api.renderer.v1.material.MaterialView;
+import net.fabricmc.fabric.api.util.TriState;
+import net.minecraft.util.Mth;
+
+/**
+ * Default implementation of the standard render materials.
+ * The underlying representation is simply an int with bit-wise
+ * packing of the various material properties. This offers
+ * easy/fast interning via int/object hashmap.
+ */
+public class MaterialViewImpl implements MaterialView {
+ private static final BlendMode[] BLEND_MODES = BlendMode.values();
+ private static final int BLEND_MODE_COUNT = BLEND_MODES.length;
+ private static final TriState[] TRI_STATES = TriState.values();
+ private static final int TRI_STATE_COUNT = TRI_STATES.length;
+
+ protected static final int BLEND_MODE_BIT_LENGTH = Mth.ceillog2(BLEND_MODE_COUNT);
+ protected static final int COLOR_DISABLE_BIT_LENGTH = 1;
+ protected static final int EMISSIVE_BIT_LENGTH = 1;
+ protected static final int DIFFUSE_BIT_LENGTH = 1;
+ protected static final int AO_BIT_LENGTH = Mth.ceillog2(TRI_STATE_COUNT);
+ protected static final int GLINT_BIT_LENGTH = Mth.ceillog2(TRI_STATE_COUNT);
+
+ protected static final int BLEND_MODE_BIT_OFFSET = 0;
+ protected static final int COLOR_DISABLE_BIT_OFFSET = BLEND_MODE_BIT_OFFSET + BLEND_MODE_BIT_LENGTH;
+ protected static final int EMISSIVE_BIT_OFFSET = COLOR_DISABLE_BIT_OFFSET + COLOR_DISABLE_BIT_LENGTH;
+ protected static final int DIFFUSE_BIT_OFFSET = EMISSIVE_BIT_OFFSET + EMISSIVE_BIT_LENGTH;
+ protected static final int AO_BIT_OFFSET = DIFFUSE_BIT_OFFSET + DIFFUSE_BIT_LENGTH;
+ protected static final int GLINT_BIT_OFFSET = AO_BIT_OFFSET + AO_BIT_LENGTH;
+ protected static final int TOTAL_BIT_LENGTH = GLINT_BIT_OFFSET + GLINT_BIT_LENGTH;
+
+ protected static final int BLEND_MODE_MASK = bitMask(BLEND_MODE_BIT_LENGTH, BLEND_MODE_BIT_OFFSET);
+ protected static final int COLOR_DISABLE_FLAG = bitMask(COLOR_DISABLE_BIT_LENGTH, COLOR_DISABLE_BIT_OFFSET);
+ protected static final int EMISSIVE_FLAG = bitMask(EMISSIVE_BIT_LENGTH, EMISSIVE_BIT_OFFSET);
+ protected static final int DIFFUSE_FLAG = bitMask(DIFFUSE_BIT_LENGTH, DIFFUSE_BIT_OFFSET);
+ protected static final int AO_MASK = bitMask(AO_BIT_LENGTH, AO_BIT_OFFSET);
+ protected static final int GLINT_MASK = bitMask(GLINT_BIT_LENGTH, GLINT_BIT_OFFSET);
+
+ protected static int bitMask(int bitLength, int bitOffset) {
+ return ((1 << bitLength) - 1) << bitOffset;
+ }
+
+ protected static boolean areBitsValid(int bits) {
+ int blendMode = (bits & BLEND_MODE_MASK) >>> BLEND_MODE_BIT_OFFSET;
+ int ao = (bits & AO_MASK) >>> AO_BIT_OFFSET;
+ int glint = (bits & GLINT_MASK) >>> GLINT_BIT_OFFSET;
+
+ return blendMode < BLEND_MODE_COUNT
+ && ao < TRI_STATE_COUNT
+ && glint < TRI_STATE_COUNT;
+ }
+
+ protected int bits;
+
+ protected MaterialViewImpl(int bits) {
+ this.bits = bits;
+ }
+
+ @Override
+ public BlendMode blendMode() {
+ return BLEND_MODES[(bits & BLEND_MODE_MASK) >>> BLEND_MODE_BIT_OFFSET];
+ }
+
+ @Override
+ public boolean disableColorIndex() {
+ return (bits & COLOR_DISABLE_FLAG) != 0;
+ }
+
+ @Override
+ public boolean emissive() {
+ return (bits & EMISSIVE_FLAG) != 0;
+ }
+
+ @Override
+ public boolean disableDiffuse() {
+ return (bits & DIFFUSE_FLAG) != 0;
+ }
+
+ @Override
+ public TriState ambientOcclusion() {
+ return TRI_STATES[(bits & AO_MASK) >>> AO_BIT_OFFSET];
+ }
+
+ @Override
+ public TriState glint() {
+ return TRI_STATES[(bits & GLINT_MASK) >>> GLINT_BIT_OFFSET];
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/RenderMaterialImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/RenderMaterialImpl.java
new file mode 100644
index 0000000000..760f8b4dac
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/material/RenderMaterialImpl.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.material;
+
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+
+public class RenderMaterialImpl extends MaterialViewImpl implements RenderMaterial {
+ public static final int VALUE_COUNT = 1 << TOTAL_BIT_LENGTH;
+ private static final RenderMaterialImpl[] BY_INDEX = new RenderMaterialImpl[VALUE_COUNT];
+
+ static {
+ for (int i = 0; i < VALUE_COUNT; i++) {
+ if (areBitsValid(i)) {
+ BY_INDEX[i] = new RenderMaterialImpl(i);
+ }
+ }
+ }
+
+ private RenderMaterialImpl(int bits) {
+ super(bits);
+ }
+
+ public int index() {
+ return bits;
+ }
+
+ public static RenderMaterialImpl byIndex(int index) {
+ return BY_INDEX[index];
+ }
+
+ public static RenderMaterialImpl setDisableDiffuse(RenderMaterialImpl material, boolean disable) {
+ if (material.disableDiffuse() != disable) {
+ return byIndex(disable ? (material.bits | DIFFUSE_FLAG) : (material.bits & ~DIFFUSE_FLAG));
+ }
+
+ return material;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/EncodingFormat.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/EncodingFormat.java
new file mode 100644
index 0000000000..583867ec87
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/EncodingFormat.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.mesh;
+
+import com.google.common.base.Preconditions;
+import com.mojang.blaze3d.vertex.DefaultVertexFormat;
+import com.mojang.blaze3d.vertex.VertexFormat;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags;
+import net.caffeinemc.mods.sodium.client.render.frapi.material.RenderMaterialImpl;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
+import net.minecraft.core.Direction;
+import net.minecraft.util.Mth;
+
+/**
+ * Holds all the array offsets and bit-wise encoders/decoders for
+ * packing/unpacking quad data in an array of integers.
+ * All of this is implementation-specific - that's why it isn't a "helper" class.
+ */
+public abstract class EncodingFormat {
+ private EncodingFormat() { }
+
+ static final int HEADER_BITS = 0;
+ static final int HEADER_FACE_NORMAL = 1;
+ static final int HEADER_COLOR_INDEX = 2;
+ static final int HEADER_TAG = 3;
+ public static final int HEADER_STRIDE = 4;
+
+ static final int VERTEX_X;
+ static final int VERTEX_Y;
+ static final int VERTEX_Z;
+ static final int VERTEX_COLOR;
+ static final int VERTEX_U;
+ static final int VERTEX_V;
+ static final int VERTEX_LIGHTMAP;
+ static final int VERTEX_NORMAL;
+ public static final int VERTEX_STRIDE;
+
+ public static final int QUAD_STRIDE;
+ public static final int QUAD_STRIDE_BYTES;
+ public static final int TOTAL_STRIDE;
+
+ static {
+ final VertexFormat format = DefaultVertexFormat.BLOCK;
+ VERTEX_X = HEADER_STRIDE + 0;
+ VERTEX_Y = HEADER_STRIDE + 1;
+ VERTEX_Z = HEADER_STRIDE + 2;
+ VERTEX_COLOR = HEADER_STRIDE + 3;
+ VERTEX_U = HEADER_STRIDE + 4;
+ VERTEX_V = VERTEX_U + 1;
+ VERTEX_LIGHTMAP = HEADER_STRIDE + 6;
+ VERTEX_NORMAL = HEADER_STRIDE + 7;
+ VERTEX_STRIDE = format.getVertexSize() / 4;
+ QUAD_STRIDE = VERTEX_STRIDE * 4;
+ QUAD_STRIDE_BYTES = QUAD_STRIDE * 4;
+ TOTAL_STRIDE = HEADER_STRIDE + QUAD_STRIDE;
+
+ Preconditions.checkState(VERTEX_STRIDE == QuadView.VANILLA_VERTEX_STRIDE, "Sodium FRAPI vertex stride (%s) mismatched with rendering API (%s)", VERTEX_STRIDE, QuadView.VANILLA_VERTEX_STRIDE);
+ Preconditions.checkState(QUAD_STRIDE == QuadView.VANILLA_QUAD_STRIDE, "Sodium FRAPI quad stride (%s) mismatched with rendering API (%s)", QUAD_STRIDE, QuadView.VANILLA_QUAD_STRIDE);
+ }
+
+ /** used for quick clearing of quad buffers. */
+ static final int[] EMPTY = new int[TOTAL_STRIDE];
+
+ private static final int DIRECTION_MASK = Mth.smallestEncompassingPowerOfTwo(ModelHelper.NULL_FACE_ID + 1) - 1;
+ private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK);
+ private static final int FACING_MASK = Mth.smallestEncompassingPowerOfTwo(ModelQuadFacing.COUNT) - 1;
+ private static final int FACING_BIT_COUNT = Integer.bitCount(FACING_MASK);
+ private static final int MATERIAL_MASK = Mth.smallestEncompassingPowerOfTwo(RenderMaterialImpl.VALUE_COUNT) - 1;
+ private static final int MATERIAL_BIT_COUNT = Integer.bitCount(MATERIAL_MASK);
+
+ private static final int CULL_SHIFT = 0;
+ private static final int CULL_INVERSE_MASK = ~(DIRECTION_MASK << CULL_SHIFT);
+ private static final int LIGHT_SHIFT = CULL_SHIFT + DIRECTION_BIT_COUNT;
+ private static final int LIGHT_INVERSE_MASK = ~(DIRECTION_MASK << LIGHT_SHIFT);
+ private static final int NORMAL_FACE_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT;
+ private static final int NORMAL_FACE_INVERSE_MASK = ~(FACING_MASK << NORMAL_FACE_SHIFT);
+ private static final int NORMALS_SHIFT = NORMAL_FACE_SHIFT + FACING_BIT_COUNT;
+ private static final int NORMALS_COUNT = 4;
+ private static final int NORMALS_MASK = (1 << NORMALS_COUNT) - 1;
+ private static final int NORMALS_INVERSE_MASK = ~(NORMALS_MASK << NORMALS_SHIFT);
+ private static final int GEOMETRY_SHIFT = NORMALS_SHIFT + NORMALS_COUNT;
+ private static final int GEOMETRY_MASK = (1 << ModelQuadFlags.FLAG_BIT_COUNT) - 1;
+ private static final int GEOMETRY_INVERSE_MASK = ~(GEOMETRY_MASK << GEOMETRY_SHIFT);
+ private static final int MATERIAL_SHIFT = GEOMETRY_SHIFT + ModelQuadFlags.FLAG_BIT_COUNT;
+ private static final int MATERIAL_INVERSE_MASK = ~(MATERIAL_MASK << MATERIAL_SHIFT);
+
+ static {
+ Preconditions.checkArgument(MATERIAL_SHIFT + MATERIAL_BIT_COUNT <= 32, "Sodium FRAPI header encoding bit count (%s) exceeds integer bit length)", TOTAL_STRIDE);
+ }
+
+ static Direction cullFace(int bits) {
+ return ModelHelper.faceFromIndex((bits >>> CULL_SHIFT) & DIRECTION_MASK);
+ }
+
+ static int cullFace(int bits, Direction face) {
+ return (bits & CULL_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << CULL_SHIFT);
+ }
+
+ static Direction lightFace(int bits) {
+ return ModelHelper.faceFromIndex((bits >>> LIGHT_SHIFT) & DIRECTION_MASK);
+ }
+
+ static int lightFace(int bits, Direction face) {
+ return (bits & LIGHT_INVERSE_MASK) | (ModelHelper.toFaceIndex(face) << LIGHT_SHIFT);
+ }
+
+ static ModelQuadFacing normalFace(int bits) {
+ return ModelQuadFacing.VALUES[(bits >>> NORMAL_FACE_SHIFT) & FACING_MASK];
+ }
+
+ static int normalFace(int bits, ModelQuadFacing face) {
+ return (bits & NORMAL_FACE_INVERSE_MASK) | (face.ordinal() << NORMAL_FACE_SHIFT);
+ }
+
+ /** indicate if vertex normal has been set - bits correspond to vertex ordinals. */
+ static int normalFlags(int bits) {
+ return (bits >>> NORMALS_SHIFT) & NORMALS_MASK;
+ }
+
+ static int normalFlags(int bits, int normalFlags) {
+ return (bits & NORMALS_INVERSE_MASK) | ((normalFlags & NORMALS_MASK) << NORMALS_SHIFT);
+ }
+
+ static int geometryFlags(int bits) {
+ return (bits >>> GEOMETRY_SHIFT) & GEOMETRY_MASK;
+ }
+
+ static int geometryFlags(int bits, int geometryFlags) {
+ return (bits & GEOMETRY_INVERSE_MASK) | ((geometryFlags & GEOMETRY_MASK) << GEOMETRY_SHIFT);
+ }
+
+ static RenderMaterialImpl material(int bits) {
+ return RenderMaterialImpl.byIndex((bits >>> MATERIAL_SHIFT) & MATERIAL_MASK);
+ }
+
+ static int material(int bits, RenderMaterialImpl material) {
+ return (bits & MATERIAL_INVERSE_MASK) | (material.index() << MATERIAL_SHIFT);
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshBuilderImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshBuilderImpl.java
new file mode 100644
index 0000000000..34e69c8b1f
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshBuilderImpl.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.mesh;
+
+import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
+import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
+
+/**
+ * Our implementation of {@link MeshBuilder}, used for static mesh creation and baking.
+ * Not much to it - mainly it just needs to grow the int[] array as quads are appended
+ * and maintain/provide a properly-configured {@link net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView} instance.
+ * All the encoding and other work is handled in the quad base classes.
+ * The one interesting bit is in {@link Maker#emitDirectly()}.
+ */
+public class MeshBuilderImpl implements MeshBuilder {
+ private int[] data = new int[256];
+ private int index = 0;
+ private int limit = data.length;
+ private final Maker maker = new Maker();
+
+ public MeshBuilderImpl() {
+ ensureCapacity(EncodingFormat.TOTAL_STRIDE);
+ maker.data = data;
+ maker.baseIndex = index;
+ maker.clear();
+ }
+
+ protected void ensureCapacity(int stride) {
+ if (stride > limit - index) {
+ limit *= 2;
+ final int[] bigger = new int[limit];
+ System.arraycopy(data, 0, bigger, 0, index);
+ data = bigger;
+ maker.data = data;
+ }
+ }
+
+ @Override
+ public QuadEmitter getEmitter() {
+ maker.clear();
+ return maker;
+ }
+
+ @Override
+ public Mesh build() {
+ final int[] packed = new int[index];
+ System.arraycopy(data, 0, packed, 0, index);
+ index = 0;
+ maker.baseIndex = index;
+ maker.clear();
+ return new MeshImpl(packed);
+ }
+
+ /**
+ * Our base classes are used differently so we define final
+ * encoding steps in subtypes. This will be a static mesh used
+ * at render time so we want to capture all geometry now and
+ * apply non-location-dependent lighting.
+ */
+ private class Maker extends MutableQuadViewImpl {
+ @Override
+ public void emitDirectly() {
+ computeGeometry();
+ index += EncodingFormat.TOTAL_STRIDE;
+ ensureCapacity(EncodingFormat.TOTAL_STRIDE);
+ baseIndex = index;
+ }
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshImpl.java
new file mode 100644
index 0000000000..60fa624c90
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MeshImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.mesh;
+
+import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+
+import java.util.function.Consumer;
+
+/**
+ * Implementation of {@link Mesh}.
+ * The way we encode meshes makes it very simple.
+ */
+public class MeshImpl implements Mesh {
+ /** Used to satisfy external calls to {@link #forEach(Consumer)}. */
+ private final ThreadLocal cursorPool = ThreadLocal.withInitial(QuadViewImpl::new);
+
+ final int[] data;
+
+ MeshImpl(int[] data) {
+ this.data = data;
+ }
+
+ @Override
+ public void forEach(Consumer consumer) {
+ forEach(consumer, cursorPool.get());
+ }
+
+ /**
+ * The renderer can call this with its own cursor
+ * to avoid the performance hit of a thread-local lookup.
+ * Also means renderer can hold final references to quad buffers.
+ */
+ void forEach(Consumer consumer, QuadViewImpl cursor) {
+ final int limit = data.length;
+ int index = 0;
+ cursor.data = this.data;
+
+ while (index < limit) {
+ cursor.baseIndex = index;
+ cursor.load();
+ consumer.accept(cursor);
+ index += EncodingFormat.TOTAL_STRIDE;
+ }
+ }
+
+ @Override
+ public void outputTo(QuadEmitter emitter) {
+ MutableQuadViewImpl e = (MutableQuadViewImpl) emitter;
+ final int[] data = this.data;
+ final int limit = data.length;
+ int index = 0;
+
+ while (index < limit) {
+ System.arraycopy(data, index, e.data, e.baseIndex, EncodingFormat.TOTAL_STRIDE);
+ e.load();
+ e.emitDirectly();
+ index += EncodingFormat.TOTAL_STRIDE;
+ }
+
+ e.clear();
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MutableQuadViewImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MutableQuadViewImpl.java
new file mode 100644
index 0000000000..3ab4bc208f
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/MutableQuadViewImpl.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.mesh;
+
+import net.caffeinemc.mods.sodium.api.util.NormI8;
+import net.caffeinemc.mods.sodium.client.model.quad.BakedQuadView;
+import net.caffeinemc.mods.sodium.client.render.frapi.SodiumRenderer;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.TextureHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.material.RenderMaterialImpl;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+import net.fabricmc.fabric.api.renderer.v1.model.SpriteFinder;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import org.jetbrains.annotations.Nullable;
+
+import static net.caffeinemc.mods.sodium.client.render.frapi.mesh.EncodingFormat.*;
+
+/**
+ * Almost-concrete implementation of a mutable quad. The only missing part is {@link #emitDirectly()},
+ * because that depends on where/how it is used. (Mesh encoding vs. render-time transformation).
+ *
+ *
In many cases an instance of this class is used as an "editor quad". The editor quad's
+ * {@link #emitDirectly()} method calls some other internal method that transforms the quad
+ * data and then buffers it. Transformations should be the same as they would be in a vanilla
+ * render - the editor is serving mainly as a way to access vertex data without magical
+ * numbers. It also allows for a consistent interface for those transformations.
+ */
+public abstract class MutableQuadViewImpl extends QuadViewImpl implements QuadEmitter {
+ @Nullable
+ private TextureAtlasSprite cachedSprite;
+
+ @Nullable
+ public TextureAtlasSprite cachedSprite() {
+ return cachedSprite;
+ }
+
+ public void cachedSprite(@Nullable TextureAtlasSprite sprite) {
+ cachedSprite = sprite;
+ }
+
+ public TextureAtlasSprite sprite(SpriteFinder finder) {
+ TextureAtlasSprite sprite = cachedSprite;
+
+ if (sprite == null) {
+ cachedSprite = sprite = finder.find(this);
+ }
+
+ return sprite;
+ }
+
+ public void clear() {
+ System.arraycopy(EMPTY, 0, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
+ isGeometryInvalid = true;
+ nominalFace = null;
+ normalFlags(0);
+ tag(0);
+ colorIndex(-1);
+ cullFace(null);
+ material(SodiumRenderer.STANDARD_MATERIAL);
+ cachedSprite(null);
+ }
+
+ @Override
+ public void load() {
+ super.load();
+ cachedSprite(null);
+ }
+
+ @Override
+ public MutableQuadViewImpl pos(int vertexIndex, float x, float y, float z) {
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
+ data[index] = Float.floatToRawIntBits(x);
+ data[index + 1] = Float.floatToRawIntBits(y);
+ data[index + 2] = Float.floatToRawIntBits(z);
+ isGeometryInvalid = true;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl color(int vertexIndex, int color) {
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR] = color;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl uv(int vertexIndex, float u, float v) {
+ final int i = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
+ data[i] = Float.floatToRawIntBits(u);
+ data[i + 1] = Float.floatToRawIntBits(v);
+ cachedSprite(null);
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl spriteBake(TextureAtlasSprite sprite, int bakeFlags) {
+ TextureHelper.bakeSprite(this, sprite, bakeFlags);
+ cachedSprite(sprite);
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl lightmap(int vertexIndex, int lightmap) {
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP] = lightmap;
+ return this;
+ }
+
+ protected void normalFlags(int flags) {
+ data[baseIndex + HEADER_BITS] = EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS], flags);
+ }
+
+ @Override
+ public MutableQuadViewImpl normal(int vertexIndex, float x, float y, float z) {
+ normalFlags(normalFlags() | (1 << vertexIndex));
+ data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL] = NormI8.pack(x, y, z);
+ return this;
+ }
+
+ /**
+ * Internal helper method. Copies face normals to vertex normals lacking one.
+ */
+ public final void populateMissingNormals() {
+ final int normalFlags = this.normalFlags();
+
+ if (normalFlags == 0b1111) return;
+
+ final int packedFaceNormal = packedFaceNormal();
+
+ for (int v = 0; v < 4; v++) {
+ if ((normalFlags & (1 << v)) == 0) {
+ data[baseIndex + v * VERTEX_STRIDE + VERTEX_NORMAL] = packedFaceNormal;
+ }
+ }
+
+ normalFlags(0b1111);
+ }
+
+ @Override
+ public final MutableQuadViewImpl cullFace(@Nullable Direction face) {
+ data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(data[baseIndex + HEADER_BITS], face);
+ nominalFace(face);
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl nominalFace(@Nullable Direction face) {
+ nominalFace = face;
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl material(RenderMaterial material) {
+ if (material == null) {
+ material = SodiumRenderer.STANDARD_MATERIAL;
+ }
+
+ data[baseIndex + HEADER_BITS] = EncodingFormat.material(data[baseIndex + HEADER_BITS], (RenderMaterialImpl) material);
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl colorIndex(int colorIndex) {
+ data[baseIndex + HEADER_COLOR_INDEX] = colorIndex;
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl tag(int tag) {
+ data[baseIndex + HEADER_TAG] = tag;
+ return this;
+ }
+
+ @Override
+ public MutableQuadViewImpl copyFrom(QuadView quad) {
+ final QuadViewImpl q = (QuadViewImpl) quad;
+ q.computeGeometry();
+
+ System.arraycopy(q.data, q.baseIndex, data, baseIndex, EncodingFormat.TOTAL_STRIDE);
+ faceNormal.set(q.faceNormal);
+ nominalFace = q.nominalFace;
+ isGeometryInvalid = false;
+
+ if (quad instanceof MutableQuadViewImpl mutableQuad) {
+ cachedSprite(mutableQuad.cachedSprite());
+ } else {
+ cachedSprite(null);
+ }
+
+ return this;
+ }
+
+ /**
+ * Does the same work as {@link #fromVanilla(int[], int)}, but does not mark the geometry as invalid
+ * and does not clear the cached sprite.
+ * Only use this if you are also setting the geometry and sprite.
+ */
+ private void fromVanillaInternal(int[] quadData, int startIndex) {
+ System.arraycopy(quadData, startIndex, data, baseIndex + HEADER_STRIDE, QuadView.VANILLA_QUAD_STRIDE);
+
+ int colorIndex = baseIndex + VERTEX_COLOR;
+
+ for (int i = 0; i < 4; i++) {
+ data[colorIndex] = ColorHelper.fromVanillaColor(data[colorIndex]);
+ colorIndex += VERTEX_STRIDE;
+ }
+ }
+
+ @Override
+ public final MutableQuadViewImpl fromVanilla(int[] quadData, int startIndex) {
+ fromVanillaInternal(quadData, startIndex);
+ isGeometryInvalid = true;
+ cachedSprite(null);
+ return this;
+ }
+
+ @Override
+ public final MutableQuadViewImpl fromVanilla(BakedQuad quad, RenderMaterial material, @Nullable Direction cullFace) {
+ fromVanillaInternal(quad.getVertices(), 0);
+ data[baseIndex + HEADER_BITS] = EncodingFormat.cullFace(0, cullFace);
+ nominalFace(quad.getDirection());
+ colorIndex(quad.getTintIndex());
+
+ // TODO: Is this the same as hasShade?
+ if (!((BakedQuadView) quad).hasShade()) {
+ material = RenderMaterialImpl.setDisableDiffuse((RenderMaterialImpl) material, true);
+ }
+
+ material(material);
+ tag(0);
+
+ // Copy geometry cached inside the quad
+ BakedQuadView bakedView = (BakedQuadView) quad;
+ NormI8.unpack(bakedView.getFaceNormal(), faceNormal);
+ data[baseIndex + HEADER_FACE_NORMAL] = bakedView.getFaceNormal();
+ int headerBits = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], bakedView.getLightFace());
+ headerBits = EncodingFormat.normalFace(headerBits, bakedView.getNormalFace());
+ data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(headerBits, bakedView.getFlags());
+ isGeometryInvalid = false;
+
+ cachedSprite(quad.getSprite());
+ return this;
+ }
+
+ /**
+ * Emit the quad without clearing the underlying data.
+ * Geometry is not guaranteed to be valid when called, but can be computed by calling {@link #computeGeometry()}.
+ */
+ public abstract void emitDirectly();
+
+ @Override
+ public final MutableQuadViewImpl emit() {
+ emitDirectly();
+ clear();
+ return this;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/QuadViewImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/QuadViewImpl.java
new file mode 100644
index 0000000000..fce995a97b
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/mesh/QuadViewImpl.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.mesh;
+
+
+import net.caffeinemc.mods.sodium.api.util.NormI8;
+import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFacing;
+import net.caffeinemc.mods.sodium.client.model.quad.properties.ModelQuadFlags;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.GeometryHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.NormalHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.material.RenderMaterialImpl;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.core.Direction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Vector2f;
+import org.joml.Vector3f;
+
+import static net.caffeinemc.mods.sodium.client.render.frapi.mesh.EncodingFormat.*;
+
+/**
+ * Base class for all quads / quad makers. Handles the ugly bits
+ * of maintaining and encoding the quad state.
+ */
+public class QuadViewImpl implements QuadView, ModelQuadView {
+ @Nullable
+ protected Direction nominalFace;
+ /** True when face normal, light face, normal face, or geometry flags may not match geometry. */
+ protected boolean isGeometryInvalid = true;
+ protected final Vector3f faceNormal = new Vector3f();
+
+ /** Size and where it comes from will vary in subtypes. But in all cases quad is fully encoded to array. */
+ protected int[] data;
+
+ /** Beginning of the quad. Also the header index. */
+ protected int baseIndex = 0;
+
+ /**
+ * Decodes necessary state from the backing data array.
+ * The encoded data must contain valid computed geometry.
+ */
+ public void load() {
+ isGeometryInvalid = false;
+ nominalFace = lightFace();
+ NormI8.unpack(packedFaceNormal(), faceNormal);
+ }
+
+ protected void computeGeometry() {
+ if (isGeometryInvalid) {
+ isGeometryInvalid = false;
+
+ NormalHelper.computeFaceNormal(faceNormal, this);
+ int packedFaceNormal = NormI8.pack(faceNormal);
+ data[baseIndex + HEADER_FACE_NORMAL] = packedFaceNormal;
+
+ // depends on face normal
+ Direction lightFace = GeometryHelper.lightFace(this);
+ data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], lightFace);
+
+ // depends on face normal
+ data[baseIndex + HEADER_BITS] = EncodingFormat.normalFace(data[baseIndex + HEADER_BITS], ModelQuadFacing.fromPackedNormal(packedFaceNormal));
+
+ // depends on light face
+ data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], ModelQuadFlags.getQuadFlags(this, lightFace));
+ }
+ }
+
+ /** gets flags used for lighting - lazily computed via {@link ModelQuadFlags#getQuadFlags}. */
+ public int geometryFlags() {
+ computeGeometry();
+ return EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS]);
+ }
+
+ public boolean hasShade() {
+ return !material().disableDiffuse();
+ }
+
+ @Override
+ public float x(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X]);
+ }
+
+ @Override
+ public float y(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Y]);
+ }
+
+ @Override
+ public float z(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_Z]);
+ }
+
+ @Override
+ public float posByIndex(int vertexIndex, int coordinateIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X + coordinateIndex]);
+ }
+
+ @Override
+ public Vector3f copyPos(int vertexIndex, @Nullable Vector3f target) {
+ if (target == null) {
+ target = new Vector3f();
+ }
+
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_X;
+ target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]), Float.intBitsToFloat(data[index + 2]));
+ return target;
+ }
+
+ @Override
+ public int color(int vertexIndex) {
+ return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_COLOR];
+ }
+
+ @Override
+ public float u(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U]);
+ }
+
+ @Override
+ public float v(int vertexIndex) {
+ return Float.intBitsToFloat(data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_V]);
+ }
+
+ @Override
+ public Vector2f copyUv(int vertexIndex, @Nullable Vector2f target) {
+ if (target == null) {
+ target = new Vector2f();
+ }
+
+ final int index = baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_U;
+ target.set(Float.intBitsToFloat(data[index]), Float.intBitsToFloat(data[index + 1]));
+ return target;
+ }
+
+ @Override
+ public int lightmap(int vertexIndex) {
+ return data[baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_LIGHTMAP];
+ }
+
+ public int normalFlags() {
+ return EncodingFormat.normalFlags(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ public boolean hasNormal(int vertexIndex) {
+ return (normalFlags() & (1 << vertexIndex)) != 0;
+ }
+
+ /** True if any vertex normal has been set. */
+ public boolean hasVertexNormals() {
+ return normalFlags() != 0;
+ }
+
+ /** True if all vertex normals have been set. */
+ public boolean hasAllVertexNormals() {
+ return (normalFlags() & 0b1111) == 0b1111;
+ }
+
+ protected final int normalIndex(int vertexIndex) {
+ return baseIndex + vertexIndex * VERTEX_STRIDE + VERTEX_NORMAL;
+ }
+
+ /**
+ * This method will only return a meaningful value if {@link #hasNormal} returns {@code true} for the same vertex index.
+ */
+ public int packedNormal(int vertexIndex) {
+ return data[normalIndex(vertexIndex)];
+ }
+
+ @Override
+ public float normalX(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormI8.unpackX(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ public float normalY(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormI8.unpackY(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ public float normalZ(int vertexIndex) {
+ return hasNormal(vertexIndex) ? NormI8.unpackZ(data[normalIndex(vertexIndex)]) : Float.NaN;
+ }
+
+ @Override
+ @Nullable
+ public Vector3f copyNormal(int vertexIndex, @Nullable Vector3f target) {
+ if (hasNormal(vertexIndex)) {
+ if (target == null) {
+ target = new Vector3f();
+ }
+
+ final int normal = data[normalIndex(vertexIndex)];
+ NormI8.unpack(normal, target);
+ return target;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ public final Direction cullFace() {
+ return EncodingFormat.cullFace(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ @NotNull
+ public final Direction lightFace() {
+ computeGeometry();
+ return EncodingFormat.lightFace(data[baseIndex + HEADER_BITS]);
+ }
+
+ public final ModelQuadFacing normalFace() {
+ computeGeometry();
+ return EncodingFormat.normalFace(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ @Nullable
+ public final Direction nominalFace() {
+ return nominalFace;
+ }
+
+ public final int packedFaceNormal() {
+ computeGeometry();
+ return data[baseIndex + HEADER_FACE_NORMAL];
+ }
+
+ @Override
+ public final Vector3f faceNormal() {
+ computeGeometry();
+ return faceNormal;
+ }
+
+ @Override
+ public final RenderMaterialImpl material() {
+ return EncodingFormat.material(data[baseIndex + HEADER_BITS]);
+ }
+
+ @Override
+ public final int colorIndex() {
+ return data[baseIndex + HEADER_COLOR_INDEX];
+ }
+
+ @Override
+ public final int tag() {
+ return data[baseIndex + HEADER_TAG];
+ }
+
+ @Override
+ public final void toVanilla(int[] target, int targetIndex) {
+ System.arraycopy(data, baseIndex + HEADER_STRIDE, target, targetIndex, QUAD_STRIDE);
+
+ // The color is the fourth integer in each vertex.
+ // EncodingFormat.VERTEX_COLOR is not used because it also
+ // contains the header size; vanilla quads do not have a header.
+ int colorIndex = targetIndex + 3;
+
+ for (int i = 0; i < 4; i++) {
+ target[colorIndex] = ColorHelper.toVanillaColor(target[colorIndex]);
+ colorIndex += QuadView.VANILLA_VERTEX_STRIDE;
+ }
+ }
+
+ // ModelQuadView method implementations below
+
+ @Override
+ public float getX(int idx) {
+ return x(idx);
+ }
+
+ @Override
+ public float getY(int idx) {
+ return y(idx);
+ }
+
+ @Override
+ public float getZ(int idx) {
+ return z(idx);
+ }
+
+ @Override
+ public int getColor(int idx) {
+ return ColorHelper.toVanillaColor(color(idx));
+ }
+
+ @Override
+ public float getTexU(int idx) {
+ return u(idx);
+ }
+
+ @Override
+ public float getTexV(int idx) {
+ return v(idx);
+ }
+
+ @Override
+ public int getVertexNormal(int idx) {
+ return data[normalIndex(idx)];
+ }
+
+ @Override
+ public int getFaceNormal() {
+ return packedFaceNormal();
+ }
+
+ @Override
+ public int getLight(int idx) {
+ return lightmap(idx);
+ }
+
+ @Override
+ public int getColorIndex() {
+ return material().disableColorIndex() ? -1 : colorIndex();
+ }
+
+ @Override
+ public TextureAtlasSprite getSprite() {
+ throw new UnsupportedOperationException("Not available for QuadViewImpl.");
+ }
+
+ @Override
+ public Direction getLightFace() {
+ return lightFace();
+ }
+
+ @Override
+ public int getFlags() {
+ return geometryFlags();
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractBlockRenderContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractBlockRenderContext.java
new file mode 100644
index 0000000000..66b5252db4
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractBlockRenderContext.java
@@ -0,0 +1,274 @@
+package net.caffeinemc.mods.sodium.client.render.frapi.render;
+
+import net.caffeinemc.mods.sodium.client.model.light.LightMode;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipeline;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.model.light.data.QuadLightData;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
+import net.caffeinemc.mods.sodium.client.render.frapi.SodiumRenderer;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.EncodingFormat;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MutableQuadViewImpl;
+import net.caffeinemc.mods.sodium.client.services.PlatformBlockAccess;
+import net.caffeinemc.mods.sodium.client.services.PlatformLevelAccess;
+import net.caffeinemc.mods.sodium.client.services.PlatformModelAccess;
+import net.caffeinemc.mods.sodium.client.services.SodiumModelData;
+import net.caffeinemc.mods.sodium.client.world.LevelSlice;
+import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
+import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
+import net.fabricmc.fabric.api.util.TriState;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.LightTexture;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.item.ItemDisplayContext;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.block.state.BlockState;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * Base class for the functions that can be shared between the terrain and non-terrain pipelines.
+ *
+ *
Make sure to set the {@link #lighters} in the subclass constructor.
+ */
+public abstract class AbstractBlockRenderContext extends AbstractRenderContext {
+ private static final RenderMaterial[] STANDARD_MATERIALS;
+ private static final RenderMaterial TRANSLUCENT_MATERIAL = SodiumRenderer.INSTANCE.materialFinder().blendMode(BlendMode.TRANSLUCENT).find();
+
+ static {
+ STANDARD_MATERIALS = new RenderMaterial[TriState.values().length];
+
+ TriState[] values = TriState.values();
+ for (int i = 0; i < values.length; i++) {
+ TriState state = values[i];
+ STANDARD_MATERIALS[i] = SodiumRenderer.INSTANCE.materialFinder().ambientOcclusion(state).find();
+ }
+ }
+ private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
+ {
+ data = new int[EncodingFormat.TOTAL_STRIDE];
+ clear();
+ }
+
+ @Override
+ public void emitDirectly() {
+ if (type == null) {
+ throw new IllegalStateException("No render type is set but an FRAPI object was asked to render!");
+ }
+ renderQuad(this);
+ }
+ };
+
+ @Deprecated
+ private final BakedModelConsumerImpl vanillaModelConsumer = new BakedModelConsumerImpl();
+
+ /**
+ * The world which the block is being rendered in.
+ */
+ protected BlockAndTintGetter level;
+ /**
+ * The level slice used for rendering
+ */
+ protected LevelSlice slice;
+ /**
+ * The state of the block being rendered.
+ */
+ protected BlockState state;
+ /**
+ * The position (in world space) of the block being rendered.
+ */
+ protected BlockPos pos;
+
+ /**
+ * The current render type being rendered.
+ */
+ protected RenderType type;
+
+ /**
+ * The current model's model data.
+ */
+ protected SodiumModelData modelData;
+
+ private final BlockOcclusionCache occlusionCache = new BlockOcclusionCache();
+ private boolean enableCulling = true;
+ // Cull cache (as it's checked per-quad instead of once per side like in vanilla)
+ private int cullCompletionFlags;
+ private int cullResultFlags;
+
+ protected RandomSource random;
+ protected long randomSeed;
+ protected final Supplier randomSupplier = () -> {
+ random.setSeed(randomSeed);
+ return random;
+ };
+
+ /**
+ * Must be set by the subclass constructor.
+ */
+ protected LightPipelineProvider lighters;
+ protected final QuadLightData quadLightData = new QuadLightData();
+ protected boolean useAmbientOcclusion;
+ // Default AO mode for model (can be overridden by material property)
+ protected LightMode defaultLightMode;
+
+ @Override
+ public QuadEmitter getEmitter() {
+ this.editorQuad.clear();
+ return this.editorQuad;
+ }
+
+ @Override
+ public boolean isFaceCulled(@Nullable Direction face) {
+ if (face == null || !this.enableCulling) {
+ return false;
+ }
+
+ final int mask = 1 << face.get3DDataValue();
+
+ if ((this.cullCompletionFlags & mask) == 0) {
+ this.cullCompletionFlags |= mask;
+
+ if (this.occlusionCache.shouldDrawSide(this.state, this.level, this.pos, face)) {
+ this.cullResultFlags |= mask;
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return (this.cullResultFlags & mask) == 0;
+ }
+ }
+
+ @Override
+ public ItemDisplayContext itemTransformationMode() {
+ throw new UnsupportedOperationException("itemTransformationMode can only be called on an item render context.");
+ }
+
+ @SuppressWarnings("removal")
+ @Deprecated
+ @Override
+ public BakedModelConsumer bakedModelConsumer() {
+ return this.vanillaModelConsumer;
+ }
+
+ /**
+ * Pipeline entrypoint - handles transform and culling checks.
+ */
+ private void renderQuad(MutableQuadViewImpl quad) {
+ if (!this.transform(quad)) {
+ return;
+ }
+
+ if (this.isFaceCulled(quad.cullFace())) {
+ return;
+ }
+
+ this.processQuad(quad);
+ }
+
+ /**
+ * Quad pipeline function - after transform and culling checks.
+ * Can also be used as entrypoint to skip some logic if the transform and culling checks have already been performed.
+ */
+ protected abstract void processQuad(MutableQuadViewImpl quad);
+
+ protected void prepareCulling(boolean enableCulling) {
+ this.enableCulling = enableCulling;
+ this.cullCompletionFlags = 0;
+ this.cullResultFlags = 0;
+ }
+
+ protected void prepareAoInfo(boolean modelAo) {
+ this.useAmbientOcclusion = Minecraft.useAmbientOcclusion();
+ // Ignore the incorrect IDEA warning here.
+ this.defaultLightMode = this.useAmbientOcclusion && modelAo && PlatformBlockAccess.getInstance().getLightEmission(state, level, pos) == 0 ? LightMode.SMOOTH : LightMode.FLAT;
+ }
+
+ // TODO: normal-based (enhanced) AO for smooth lighting pipeline
+ // TODO: normal-based diffuse for both lighting pipelines
+ protected void shadeQuad(MutableQuadViewImpl quad, LightMode lightMode, boolean emissive) {
+ LightPipeline lighter = this.lighters.getLighter(lightMode);
+ QuadLightData data = this.quadLightData;
+ lighter.calculate(quad, this.pos, data, quad.cullFace(), quad.lightFace(), quad.hasShade(), false);
+
+ if (emissive) {
+ for (int i = 0; i < 4; i++) {
+ quad.lightmap(i, LightTexture.FULL_BRIGHT);
+ }
+ } else {
+ int[] lightmaps = data.lm;
+
+ for (int i = 0; i < 4; i++) {
+ quad.lightmap(i, ColorHelper.maxBrightness(quad.lightmap(i), lightmaps[i]));
+ }
+ }
+ }
+
+ /* Handling of vanilla models - this is the hot path for non-modded models */
+ public void bufferDefaultModel(BakedModel model, @Nullable BlockState state) {
+ MutableQuadViewImpl editorQuad = this.editorQuad;
+
+
+ // If there is no transform, we can check the culling face once for all the quads,
+ // and we don't need to check for transforms per-quad.
+ boolean noTransform = !this.hasTransform();
+
+ for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
+ final Direction cullFace = ModelHelper.faceFromIndex(i);
+
+ RandomSource random = this.randomSupplier.get();
+ TriState ao = PlatformBlockAccess.getInstance().usesAmbientOcclusion(model, state, modelData, type, slice, pos);
+ if (noTransform) {
+ if (!this.isFaceCulled(cullFace)) {
+ final List quads = PlatformModelAccess.getInstance().getQuads(level, pos, model, state, cullFace, random, type, modelData);
+ final int count = quads.size();
+
+ for (int j = 0; j < count; j++) {
+ final BakedQuad q = quads.get(j);
+ editorQuad.fromVanilla(q, (type == RenderType.tripwire() || type == RenderType.translucent()) ? TRANSLUCENT_MATERIAL : STANDARD_MATERIALS[ao.ordinal()], cullFace);
+ // Call processQuad instead of emit for efficiency
+ // (avoid unnecessarily clearing data, trying to apply transforms, and performing cull check again)
+
+ this.processQuad(editorQuad);
+ }
+ }
+ } else {
+ final List quads = PlatformModelAccess.getInstance().getQuads(level, pos, model, state, cullFace, random, type, modelData);
+ final int count = quads.size();
+
+ for (int j = 0; j < count; j++) {
+ final BakedQuad q = quads.get(j);
+ editorQuad.fromVanilla(q, (type == RenderType.tripwire() || type == RenderType.translucent()) ? TRANSLUCENT_MATERIAL : STANDARD_MATERIALS[ao.ordinal()], cullFace);
+ // Call renderQuad instead of emit for efficiency
+ // (avoid unnecessarily clearing data)
+ this.renderQuad(editorQuad);
+ }
+ }
+ }
+
+ editorQuad.clear();
+ }
+
+ @SuppressWarnings("removal")
+ @Deprecated
+ private class BakedModelConsumerImpl implements BakedModelConsumer {
+ @Override
+ public void accept(BakedModel model) {
+ accept(model, AbstractBlockRenderContext.this.state);
+ }
+
+ @Override
+ public void accept(BakedModel model, @Nullable BlockState state) {
+ AbstractBlockRenderContext.this.bufferDefaultModel(model, state);
+ }
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractRenderContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractRenderContext.java
new file mode 100644
index 0000000000..6074c497cf
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/AbstractRenderContext.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.render;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
+import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
+import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
+
+import java.util.function.Consumer;
+
+public abstract class AbstractRenderContext implements RenderContext {
+ private static final QuadTransform NO_TRANSFORM = q -> true;
+
+ private QuadTransform activeTransform = NO_TRANSFORM;
+ private final ObjectArrayList transformStack = new ObjectArrayList<>();
+ private final QuadTransform stackTransform = q -> {
+ int i = transformStack.size() - 1;
+
+ while (i >= 0) {
+ if (!transformStack.get(i--).transform(q)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ @Deprecated
+ private final Consumer meshConsumer = mesh -> mesh.outputTo(getEmitter());
+
+ protected final boolean transform(MutableQuadView q) {
+ return activeTransform.transform(q);
+ }
+
+ @Override
+ public boolean hasTransform() {
+ return activeTransform != NO_TRANSFORM;
+ }
+
+ @Override
+ public void pushTransform(QuadTransform transform) {
+ if (transform == null) {
+ throw new NullPointerException("Renderer received null QuadTransform.");
+ }
+
+ transformStack.push(transform);
+
+ if (transformStack.size() == 1) {
+ activeTransform = transform;
+ } else if (transformStack.size() == 2) {
+ activeTransform = stackTransform;
+ }
+ }
+
+ @Override
+ public void popTransform() {
+ transformStack.pop();
+
+ if (transformStack.isEmpty()) {
+ activeTransform = NO_TRANSFORM;
+ } else if (transformStack.size() == 1) {
+ activeTransform = transformStack.get(0);
+ }
+ }
+
+ // Overridden to prevent allocating a lambda every time this method is called.
+ @Deprecated
+ @Override
+ public Consumer meshConsumer() {
+ return meshConsumer;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/ItemRenderContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/ItemRenderContext.java
new file mode 100644
index 0000000000..7b359df853
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/ItemRenderContext.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.render;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import com.mojang.math.MatrixUtil;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.EncodingFormat;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MutableQuadViewImpl;
+import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil;
+import net.caffeinemc.mods.sodium.mixin.features.render.frapi.ItemRendererAccessor;
+import net.caffeinemc.mods.sodium.client.services.PlatformTextureAccess;
+import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
+import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
+import net.fabricmc.fabric.api.util.TriState;
+import net.fabricmc.fabric.impl.renderer.VanillaModelEncoder;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.color.item.ItemColors;
+import net.minecraft.client.renderer.*;
+import net.minecraft.client.renderer.entity.ItemRenderer;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.Direction;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.item.BlockItem;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemDisplayContext;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.levelgen.SingleThreadedRandomSource;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+
+import java.util.function.Supplier;
+
+/**
+ * The render context used for item rendering.
+ */
+public class ItemRenderContext extends AbstractRenderContext {
+ /** Value vanilla uses for item rendering. The only sensible choice, of course. */
+ private static final long ITEM_RANDOM_SEED = 42L;
+
+ private final MutableQuadViewImpl editorQuad = new MutableQuadViewImpl() {
+ {
+ data = new int[EncodingFormat.TOTAL_STRIDE];
+ clear();
+ }
+
+ @Override
+ public void emitDirectly() {
+ renderQuad(this);
+ }
+ };
+
+ @Deprecated
+ private final BakedModelConsumerImpl vanillaModelConsumer = new BakedModelConsumerImpl();
+
+ private final ItemColors colorMap;
+ private final VanillaModelBufferer vanillaBufferer;
+
+ private final RandomSource random = new SingleThreadedRandomSource(ITEM_RANDOM_SEED);
+ private final Supplier randomSupplier = () -> {
+ random.setSeed(ITEM_RANDOM_SEED);
+ return random;
+ };
+
+ private ItemStack itemStack;
+ private ItemDisplayContext transformMode;
+ private PoseStack poseStack;
+ private Matrix4f matPosition;
+ private boolean trustedNormals;
+ private Matrix3f matNormal;
+ private MultiBufferSource bufferSource;
+ private int lightmap;
+ private int overlay;
+
+ private boolean isDefaultTranslucent;
+ private boolean isTranslucentDirect;
+ private boolean isDefaultGlint;
+ private boolean isGlintDynamicDisplay;
+
+ private PoseStack.Pose dynamicDisplayGlintEntry;
+ private VertexConsumer translucentVertexConsumer;
+ private VertexConsumer cutoutVertexConsumer;
+ private VertexConsumer translucentGlintVertexConsumer;
+ private VertexConsumer cutoutGlintVertexConsumer;
+ private VertexConsumer defaultVertexConsumer;
+
+ public ItemRenderContext(ItemColors colorMap, VanillaModelBufferer vanillaBufferer) {
+ this.colorMap = colorMap;
+ this.vanillaBufferer = vanillaBufferer;
+ }
+
+ @Override
+ public QuadEmitter getEmitter() {
+ editorQuad.clear();
+ return editorQuad;
+ }
+
+ @Override
+ public boolean isFaceCulled(@Nullable Direction face) {
+ throw new UnsupportedOperationException("isFaceCulled can only be called on a block render context.");
+ }
+
+ @Override
+ public ItemDisplayContext itemTransformationMode() {
+ return transformMode;
+ }
+
+ @SuppressWarnings("removal")
+ @Deprecated
+ @Override
+ public BakedModelConsumer bakedModelConsumer() {
+ return vanillaModelConsumer;
+ }
+
+ public void renderModel(ItemStack itemStack, ItemDisplayContext transformMode, boolean invert, PoseStack poseStack, MultiBufferSource bufferSource, int lightmap, int overlay, BakedModel model) {
+ this.itemStack = itemStack;
+ this.transformMode = transformMode;
+ this.poseStack = poseStack;
+ matPosition = poseStack.last().pose();
+ trustedNormals = poseStack.last().trustedNormals;
+ matNormal = poseStack.last().normal();
+ this.bufferSource = bufferSource;
+ this.lightmap = lightmap;
+ this.overlay = overlay;
+ computeOutputInfo();
+
+ ((FabricBakedModel) model).emitItemQuads(itemStack, randomSupplier, this);
+
+ this.itemStack = null;
+ this.poseStack = null;
+ this.bufferSource = null;
+
+ dynamicDisplayGlintEntry = null;
+ translucentVertexConsumer = null;
+ cutoutVertexConsumer = null;
+ translucentGlintVertexConsumer = null;
+ cutoutGlintVertexConsumer = null;
+ defaultVertexConsumer = null;
+ }
+
+ private void computeOutputInfo() {
+ isDefaultTranslucent = true;
+ isTranslucentDirect = true;
+
+ Item item = itemStack.getItem();
+
+ if (item instanceof BlockItem blockItem) {
+ BlockState state = blockItem.getBlock().defaultBlockState();
+ RenderType renderType = ItemBlockRenderTypes.getChunkRenderType(state);
+
+ if (renderType != RenderType.translucent()) {
+ isDefaultTranslucent = false;
+ }
+
+ if (transformMode != ItemDisplayContext.GUI && !transformMode.firstPerson()) {
+ isTranslucentDirect = false;
+ }
+ }
+
+ isDefaultGlint = itemStack.hasFoil();
+ isGlintDynamicDisplay = ItemRendererAccessor.sodium$hasAnimatedTexture(itemStack);
+
+ defaultVertexConsumer = getVertexConsumer(BlendMode.DEFAULT, TriState.DEFAULT);
+ }
+
+ private void renderQuad(MutableQuadViewImpl quad) {
+ if (!transform(quad)) {
+ return;
+ }
+
+ final RenderMaterial mat = quad.material();
+ final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
+ final boolean emissive = mat.emissive();
+ final VertexConsumer vertexConsumer = getVertexConsumer(mat.blendMode(), mat.glint());
+
+ colorizeQuad(quad, colorIndex);
+ shadeQuad(quad, emissive);
+ bufferQuad(quad, vertexConsumer);
+ }
+
+ private void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
+ if (colorIndex != -1) {
+ final int itemColor = colorMap.getColor(itemStack, colorIndex);
+
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyColor(itemColor, quad.color(i)));
+ }
+ }
+ }
+
+ private void shadeQuad(MutableQuadViewImpl quad, boolean emissive) {
+ if (emissive) {
+ for (int i = 0; i < 4; i++) {
+ quad.lightmap(i, LightTexture.FULL_BRIGHT);
+ }
+ } else {
+ final int lightmap = this.lightmap;
+
+ for (int i = 0; i < 4; i++) {
+ quad.lightmap(i, ColorHelper.maxBrightness(quad.lightmap(i), lightmap));
+ }
+ }
+ }
+
+ private void bufferQuad(MutableQuadViewImpl quad, VertexConsumer vertexConsumer) {
+ QuadEncoder.writeQuadVertices(quad, vertexConsumer, overlay, matPosition, trustedNormals, matNormal);
+ SpriteUtil.markSpriteActive(PlatformTextureAccess.getInstance().findInBlockAtlas(quad.getTexU(0), quad.getTexV(0)));
+ }
+
+ /**
+ * Caches custom blend mode / vertex consumers and mimics the logic
+ * in {@code RenderLayers.getEntityBlockLayer}. Layers other than
+ * translucent are mapped to cutout.
+ */
+ private VertexConsumer getVertexConsumer(BlendMode blendMode, TriState glintMode) {
+ boolean translucent;
+ boolean glint;
+
+ if (blendMode == BlendMode.DEFAULT) {
+ translucent = isDefaultTranslucent;
+ } else {
+ translucent = blendMode == BlendMode.TRANSLUCENT;
+ }
+
+ if (glintMode == TriState.DEFAULT) {
+ glint = isDefaultGlint;
+ } else {
+ glint = glintMode == TriState.TRUE;
+ }
+
+ if (translucent) {
+ if (glint) {
+ if (translucentGlintVertexConsumer == null) {
+ translucentGlintVertexConsumer = createTranslucentVertexConsumer(true);
+ }
+
+ return translucentGlintVertexConsumer;
+ } else {
+ if (translucentVertexConsumer == null) {
+ translucentVertexConsumer = createTranslucentVertexConsumer(false);
+ }
+
+ return translucentVertexConsumer;
+ }
+ } else {
+ if (glint) {
+ if (cutoutGlintVertexConsumer == null) {
+ cutoutGlintVertexConsumer = createCutoutVertexConsumer(true);
+ }
+
+ return cutoutGlintVertexConsumer;
+ } else {
+ if (cutoutVertexConsumer == null) {
+ cutoutVertexConsumer = createCutoutVertexConsumer(false);
+ }
+
+ return cutoutVertexConsumer;
+ }
+ }
+ }
+
+ private VertexConsumer createTranslucentVertexConsumer(boolean glint) {
+ if (glint && isGlintDynamicDisplay) {
+ return createDynamicDisplayGlintVertexConsumer(Minecraft.useShaderTransparency() && !isTranslucentDirect ? Sheets.translucentItemSheet() : Sheets.translucentCullBlockSheet());
+ }
+
+ if (isTranslucentDirect) {
+ return ItemRenderer.getFoilBufferDirect(bufferSource, Sheets.translucentCullBlockSheet(), true, glint);
+ } else if (Minecraft.useShaderTransparency()) {
+ return ItemRenderer.getFoilBuffer(bufferSource, Sheets.translucentItemSheet(), true, glint);
+ } else {
+ return ItemRenderer.getFoilBuffer(bufferSource, Sheets.translucentItemSheet(), true, glint);
+ }
+ }
+
+ private VertexConsumer createCutoutVertexConsumer(boolean glint) {
+ if (glint && isGlintDynamicDisplay) {
+ return createDynamicDisplayGlintVertexConsumer(Sheets.cutoutBlockSheet());
+ }
+
+ return ItemRenderer.getFoilBufferDirect(bufferSource, Sheets.cutoutBlockSheet(), true, glint);
+ }
+
+ private VertexConsumer createDynamicDisplayGlintVertexConsumer(RenderType type) {
+ if (dynamicDisplayGlintEntry == null) {
+ dynamicDisplayGlintEntry = poseStack.last().copy();
+
+ if (transformMode == ItemDisplayContext.GUI) {
+ MatrixUtil.mulComponentWise(dynamicDisplayGlintEntry.pose(), 0.5F);
+ } else if (transformMode.firstPerson()) {
+ MatrixUtil.mulComponentWise(dynamicDisplayGlintEntry.pose(), 0.75F);
+ }
+ }
+
+ return ItemRenderer.getCompassFoilBuffer(bufferSource, type, dynamicDisplayGlintEntry);
+ }
+
+ public void bufferDefaultModel(BakedModel model, @Nullable BlockState state) {
+ if (hasTransform() || vanillaBufferer == null) {
+ VanillaModelEncoder.emitItemQuads(model, state, randomSupplier, ItemRenderContext.this);
+ } else {
+ vanillaBufferer.accept(model, itemStack, lightmap, overlay, poseStack, defaultVertexConsumer);
+ }
+ }
+
+ @SuppressWarnings("removal")
+ @Deprecated
+ private class BakedModelConsumerImpl implements BakedModelConsumer {
+ @Override
+ public void accept(BakedModel model) {
+ accept(model, null);
+ }
+
+ @Override
+ public void accept(BakedModel model, @Nullable BlockState state) {
+ bufferDefaultModel(model, state);
+ }
+ }
+
+ /** used to accept a method reference from the ItemRenderer. */
+ @FunctionalInterface
+ public interface VanillaModelBufferer {
+ void accept(BakedModel model, ItemStack stack, int color, int overlay, PoseStack matrixStack, VertexConsumer buffer);
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/NonTerrainBlockRenderContext.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/NonTerrainBlockRenderContext.java
new file mode 100644
index 0000000000..ae8eab1bbf
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/NonTerrainBlockRenderContext.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.caffeinemc.mods.sodium.client.render.frapi.render;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import net.caffeinemc.mods.sodium.client.model.light.LightMode;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.model.light.data.SingleBlockLightDataCache;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MutableQuadViewImpl;
+import net.caffeinemc.mods.sodium.client.render.texture.SpriteUtil;
+import net.caffeinemc.mods.sodium.client.services.PlatformTextureAccess;
+import net.caffeinemc.mods.sodium.client.services.SodiumModelData;
+import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
+import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
+import net.fabricmc.fabric.api.util.TriState;
+import net.minecraft.client.color.block.BlockColors;
+import net.minecraft.client.renderer.ItemBlockRenderTypes;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.block.state.BlockState;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+
+public class NonTerrainBlockRenderContext extends AbstractBlockRenderContext {
+ private final BlockColors colorMap;
+ private final SingleBlockLightDataCache lightDataCache = new SingleBlockLightDataCache();
+
+ private VertexConsumer vertexConsumer;
+ private Matrix4f matPosition;
+ private boolean trustedNormals;
+ private Matrix3f matNormal;
+ private int overlay;
+
+ public NonTerrainBlockRenderContext(BlockColors colorMap) {
+ this.colorMap = colorMap;
+ this.lighters = new LightPipelineProvider(this.lightDataCache);
+ }
+
+ public void renderModel(BlockAndTintGetter blockView, BakedModel model, BlockState state, BlockPos pos, PoseStack poseStack, VertexConsumer buffer, boolean cull, RandomSource random, long seed, int overlay) {
+ this.level = blockView;
+ this.state = state;
+ this.pos = pos;
+
+ this.random = random;
+ this.randomSeed = seed;
+
+ this.vertexConsumer = buffer;
+ this.matPosition = poseStack.last().pose();
+ this.trustedNormals = poseStack.last().trustedNormals;
+ this.matNormal = poseStack.last().normal();
+ this.overlay = overlay;
+ this.type = ItemBlockRenderTypes.getChunkRenderType(state);
+ this.modelData = SodiumModelData.EMPTY;
+
+ this.lightDataCache.reset(pos, blockView);
+ this.prepareCulling(cull);
+ this.prepareAoInfo(model.useAmbientOcclusion());
+
+ ((FabricBakedModel) model).emitBlockQuads(blockView, state, pos, this.randomSupplier, this);
+
+ this.level = null;
+ this.type = null;
+ this.modelData = null;
+ this.lightDataCache.release();
+ this.random = null;
+ this.vertexConsumer = null;
+ }
+
+ @Override
+ protected void processQuad(MutableQuadViewImpl quad) {
+ final RenderMaterial mat = quad.material();
+ final int colorIndex = mat.disableColorIndex() ? -1 : quad.colorIndex();
+ final TriState aoMode = mat.ambientOcclusion();
+ final LightMode lightMode;
+ if (aoMode == TriState.DEFAULT) {
+ lightMode = this.defaultLightMode;
+ } else {
+ lightMode = this.useAmbientOcclusion && aoMode.get() ? LightMode.SMOOTH : LightMode.FLAT;
+ }
+ final boolean emissive = mat.emissive();
+
+ colorizeQuad(quad, colorIndex);
+ shadeQuad(quad, lightMode, emissive);
+ bufferQuad(quad);
+ }
+
+ private void colorizeQuad(MutableQuadViewImpl quad, int colorIndex) {
+ if (colorIndex != -1) {
+ final int blockColor = 0xFF000000 | this.colorMap.getColor(this.state, this.level, this.pos, colorIndex);
+
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyColor(blockColor, quad.color(i)));
+ }
+ }
+ }
+
+ @Override
+ protected void shadeQuad(MutableQuadViewImpl quad, LightMode lightMode, boolean emissive) {
+ super.shadeQuad(quad, lightMode, emissive);
+
+ float[] brightnesses = this.quadLightData.br;
+
+ for (int i = 0; i < 4; i++) {
+ quad.color(i, ColorHelper.multiplyRGB(quad.color(i), brightnesses[i]));
+ }
+ }
+
+ private void bufferQuad(MutableQuadViewImpl quad) {
+ QuadEncoder.writeQuadVertices(quad, vertexConsumer, overlay, matPosition, trustedNormals, matNormal);
+ SpriteUtil.markSpriteActive(PlatformTextureAccess.getInstance().findInBlockAtlas(quad.getTexU(0), quad.getTexV(0)));
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/QuadEncoder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/QuadEncoder.java
new file mode 100644
index 0000000000..b9fe658704
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/frapi/render/QuadEncoder.java
@@ -0,0 +1,140 @@
+package net.caffeinemc.mods.sodium.client.render.frapi.render;
+
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import net.caffeinemc.mods.sodium.client.render.frapi.mesh.MutableQuadViewImpl;
+import net.caffeinemc.mods.sodium.client.render.vertex.VertexConsumerUtils;
+import net.caffeinemc.mods.sodium.api.math.MatrixHelper;
+import net.caffeinemc.mods.sodium.api.util.ColorARGB;
+import net.caffeinemc.mods.sodium.api.util.NormI8;
+import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
+import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex;
+import org.joml.Math;
+import org.joml.Matrix3f;
+import org.joml.Matrix4f;
+import org.joml.Vector3f;
+import org.lwjgl.system.MemoryStack;
+
+public class QuadEncoder {
+ public static void writeQuadVertices(MutableQuadViewImpl quad, VertexConsumer vertexConsumer, int overlay, Matrix4f matPosition, boolean trustedNormals, Matrix3f matNormal) {
+ VertexBufferWriter writer = VertexConsumerUtils.convertOrLog(vertexConsumer);
+
+ if (writer != null) {
+ writeQuadVertices(quad, writer, overlay, matPosition, trustedNormals, matNormal);
+ } else {
+ writeQuadVerticesSlow(quad, vertexConsumer, overlay, matPosition, trustedNormals, matNormal);
+ }
+ }
+
+ public static void writeQuadVertices(MutableQuadViewImpl quad, VertexBufferWriter writer, int overlay, Matrix4f matPosition, boolean trustedNormals, Matrix3f matNormal) {
+ try (MemoryStack stack = MemoryStack.stackPush()) {
+ long buffer = stack.nmalloc(4 * ModelVertex.STRIDE);
+ long ptr = buffer;
+
+ final boolean useNormals = quad.hasVertexNormals();
+
+ // The packed transformed normal vector
+ int normal = 0;
+
+ if (useNormals) {
+ quad.populateMissingNormals();
+ } else {
+ normal = MatrixHelper.transformNormal(matNormal, trustedNormals, quad.packedFaceNormal());
+ }
+
+ for (int i = 0; i < 4; i++) {
+ // The position vector
+ float x = quad.x(i);
+ float y = quad.y(i);
+ float z = quad.z(i);
+
+ // The transformed position vector
+ float xt = MatrixHelper.transformPositionX(matPosition, x, y, z);
+ float yt = MatrixHelper.transformPositionY(matPosition, x, y, z);
+ float zt = MatrixHelper.transformPositionZ(matPosition, x, y, z);
+
+ if (useNormals) {
+ normal = MatrixHelper.transformNormal(matNormal, trustedNormals, quad.packedNormal(i));
+ }
+
+ ModelVertex.write(ptr, xt, yt, zt, ColorARGB.toABGR(quad.color(i)), quad.u(i), quad.v(i), overlay, quad.lightmap(i), normal);
+ ptr += ModelVertex.STRIDE;
+ }
+
+ writer.push(stack, buffer, 4, ModelVertex.FORMAT);
+ }
+ }
+
+ private static void writeQuadVerticesSlow(MutableQuadViewImpl quad, VertexConsumer vertexConsumer, int overlay, Matrix4f matPosition, boolean trustedNormals, Matrix3f matNormal) {
+ final boolean useNormals = quad.hasVertexNormals();
+
+ // The transformed normal vector
+ float nxt = 0;
+ float nyt = 0;
+ float nzt = 0;
+
+ if (useNormals) {
+ quad.populateMissingNormals();
+ } else {
+ Vector3f faceNormal = quad.faceNormal();
+
+ // The normal vector
+ float nx = faceNormal.x;
+ float ny = faceNormal.y;
+ float nz = faceNormal.z;
+
+ nxt = MatrixHelper.transformNormalX(matNormal, nx, ny, nz);
+ nyt = MatrixHelper.transformNormalY(matNormal, nx, ny, nz);
+ nzt = MatrixHelper.transformNormalZ(matNormal, nx, ny, nz);
+
+ if (!trustedNormals) {
+ float scalar = Math.invsqrt(Math.fma(nxt, nxt, Math.fma(nyt, nyt, nzt * nzt)));
+
+ nxt *= scalar;
+ nyt *= scalar;
+ nzt *= scalar;
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ // The position vector
+ float x = quad.x(i);
+ float y = quad.y(i);
+ float z = quad.z(i);
+
+ // The transformed position vector
+ float xt = MatrixHelper.transformPositionX(matPosition, x, y, z);
+ float yt = MatrixHelper.transformPositionY(matPosition, x, y, z);
+ float zt = MatrixHelper.transformPositionZ(matPosition, x, y, z);
+
+ vertexConsumer.addVertex(xt, yt, zt);
+
+ vertexConsumer.setColor(quad.color(i));
+ vertexConsumer.setUv(quad.u(i), quad.v(i));
+ vertexConsumer.setOverlay(overlay);
+ vertexConsumer.setLight(quad.lightmap(i));
+
+ if (useNormals) {
+ int packedNormal = quad.packedNormal(i);
+
+ // The normal vector
+ float nx = NormI8.unpackX(packedNormal);
+ float ny = NormI8.unpackY(packedNormal);
+ float nz = NormI8.unpackZ(packedNormal);
+
+ nxt = MatrixHelper.transformNormalX(matNormal, nx, ny, nz);
+ nyt = MatrixHelper.transformNormalY(matNormal, nx, ny, nz);
+ nzt = MatrixHelper.transformNormalZ(matNormal, nx, ny, nz);
+
+ if (!trustedNormals) {
+ float scalar = Math.invsqrt(Math.fma(nxt, nxt, Math.fma(nyt, nyt, nzt * nzt)));
+
+ nxt *= scalar;
+ nyt *= scalar;
+ nzt *= scalar;
+ }
+ }
+
+ vertexConsumer.setNormal(nxt, nyt, nzt);
+ }
+ }
+}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java
similarity index 95%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java
index ab9c3c8fec..cb92773cd7 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/CloudRenderer.java
@@ -201,7 +201,7 @@ public void render(Camera camera,
}
}
- MeshData meshData = bufferBuilder.build();
+ MeshData builtBuffer = bufferBuilder.buildOrThrow();
VertexBuffer vertexBuffer;
@@ -211,9 +211,7 @@ public void render(Camera camera,
vertexBuffer = new VertexBuffer(VertexBuffer.Usage.DYNAMIC);
}
- if (meshData != null) {
- uploadToVertexBuffer(vertexBuffer, meshData);
- }
+ uploadToVertexBuffer(vertexBuffer, builtBuffer);
Tesselator.getInstance().clear();
@@ -337,23 +335,15 @@ private static void emitCellGeometry2D(VertexBufferWriter writer, int faces, int
final long buffer = stack.nmalloc(4 * ColorVertex.STRIDE);
long ptr = buffer;
- int count = 0;
- // -Y
- if (CloudFaceSet.contains(faces, CloudFace.NEG_Y)) {
- int mixedColor = ColorMixer.mul(color, CloudFace.POS_Y.getColor());
+ int mixedColor = ColorMixer.mul(color, CloudFace.POS_Y.getColor());
- ptr = writeVertex(ptr, x + 12.0f, 0.0f, z + 12.0f, mixedColor);
- ptr = writeVertex(ptr, x + 0.0f, 0.0f, z + 12.0f, mixedColor);
- ptr = writeVertex(ptr, x + 0.0f, 0.0f, z + 0.0f, mixedColor);
- ptr = writeVertex(ptr, x + 12.0f, 0.0f, z + 0.0f, mixedColor);
-
- count += 4;
- }
+ ptr = writeVertex(ptr, x + 12.0f, 0.0f, z + 12.0f, mixedColor);
+ ptr = writeVertex(ptr, x + 0.0f, 0.0f, z + 12.0f, mixedColor);
+ ptr = writeVertex(ptr, x + 0.0f, 0.0f, z + 0.0f, mixedColor);
+ ptr = writeVertex(ptr, x + 12.0f, 0.0f, z + 0.0f, mixedColor);
- if (count > 0) {
- writer.push(stack, buffer, count, ColorVertex.FORMAT);
- }
+ writer.push(stack, buffer, 4, ColorVertex.FORMAT);
}
}
@@ -396,9 +386,9 @@ private static long writeVertex(long buffer, float x, float y, float z, int colo
return buffer + ColorVertex.STRIDE;
}
- private static void uploadToVertexBuffer(VertexBuffer vertexBuffer, MeshData meshData) {
+ private static void uploadToVertexBuffer(VertexBuffer vertexBuffer, MeshData builtBuffer) {
vertexBuffer.bind();
- vertexBuffer.upload(meshData);
+ vertexBuffer.upload(builtBuffer);
VertexBuffer.unbind();
}
@@ -623,11 +613,11 @@ private int getCellIndex(int x, int z) {
}
}
- private record CloudGeometry(VertexBuffer vertexBuffer, CloudGeometryParameters params) {
+ public record CloudGeometry(VertexBuffer vertexBuffer, CloudGeometryParameters params) {
}
- private record CloudGeometryParameters(int originX, int originZ, int radius, int orientation, CloudStatus renderMode) {
+ public record CloudGeometryParameters(int originX, int originZ, int radius, int orientation, CloudStatus renderMode) {
}
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java
similarity index 79%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java
index fe9a6204fa..539e8ad3a6 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/BakedModelEncoder.java
@@ -7,11 +7,20 @@
import net.caffeinemc.mods.sodium.api.util.ColorU8;
import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex;
+import net.caffeinemc.mods.sodium.client.render.frapi.helper.ColorHelper;
import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.lwjgl.system.MemoryStack;
public class BakedModelEncoder {
+ private static int mergeLighting(int stored, int calculated) {
+ if (stored == 0) return calculated;
+
+ int blockLight = Math.max(stored & 0xFFFF, calculated & 0xFFFF);
+ int skyLight = Math.max((stored >> 16) & 0xFFFF, (calculated >> 16) & 0xFFFF);
+ return blockLight | (skyLight << 16);
+ }
+
public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose matrices, ModelQuadView quad, int color, int light, int overlay) {
Matrix3f matNormal = matrices.normal();
Matrix4f matPosition = matrices.pose();
@@ -20,21 +29,23 @@ public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose m
long buffer = stack.nmalloc(4 * ModelVertex.STRIDE);
long ptr = buffer;
- // The packed transformed normal vector
- var normal = MatrixHelper.transformNormal(matNormal, matrices.trustedNormals, quad.getLightFace());
-
for (int i = 0; i < 4; i++) {
// The position vector
float x = quad.getX(i);
float y = quad.getY(i);
float z = quad.getZ(i);
+ int newLight = mergeLighting(quad.getLight(i), light);
+
+ // The packed transformed normal vector
+ int normal = MatrixHelper.transformNormal(matNormal, matrices.trustedNormals, quad.getAccurateNormal(i));
+
// The transformed position vector
float xt = MatrixHelper.transformPositionX(matPosition, x, y, z);
float yt = MatrixHelper.transformPositionY(matPosition, x, y, z);
float zt = MatrixHelper.transformPositionZ(matPosition, x, y, z);
- ModelVertex.write(ptr, xt, yt, zt, color, quad.getTexU(i), quad.getTexV(i), overlay, light, normal);
+ ModelVertex.write(ptr, xt, yt, zt, ColorHelper.multiplyColor(color, quad.getColor(i)), quad.getTexU(i), quad.getTexV(i), overlay, newLight, normal);
ptr += ModelVertex.STRIDE;
}
@@ -50,9 +61,6 @@ public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose m
long buffer = stack.nmalloc(4 * ModelVertex.STRIDE);
long ptr = buffer;
- // The packed transformed normal vector
- var normal = MatrixHelper.transformNormal(matNormal, matrices.trustedNormals, quad.getLightFace());
-
for (int i = 0; i < 4; i++) {
// The position vector
float x = quad.getX(i);
@@ -68,6 +76,8 @@ public static void writeQuadVertices(VertexBufferWriter writer, PoseStack.Pose m
float fG;
float fB;
+ var normal = MatrixHelper.transformNormal(matNormal, matrices.trustedNormals, quad.getAccurateNormal(i));
+
float brightness = brightnessTable[i];
if (colorize) {
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java
similarity index 70%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java
index 8dffd7ef4f..434d2dc7c6 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/EntityRenderer.java
@@ -4,9 +4,8 @@
import net.caffeinemc.mods.sodium.api.math.MatrixHelper;
import net.caffeinemc.mods.sodium.api.vertex.buffer.VertexBufferWriter;
import net.caffeinemc.mods.sodium.api.vertex.format.common.ModelVertex;
-import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.core.Direction;
-import org.apache.commons.lang3.ArrayUtils;
+import org.joml.Matrix3f;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
@@ -37,6 +36,7 @@ public class EntityRenderer {
VERTEX_X2_Y2_Z2 = 6,
VERTEX_X1_Y2_Z2 = 7;
+ private static final Matrix3f lastMatrix = new Matrix3f();
private static final long SCRATCH_BUFFER = MemoryUtil.nmemAlignedAlloc(64, NUM_CUBE_FACES * NUM_FACE_VERTICES * ModelVertex.STRIDE);
@@ -79,50 +79,15 @@ public class EntityRenderer {
}
}
- public static void render(PoseStack poseStack, VertexBufferWriter writer, ModelPart part, int light, int overlay, int color) {
- ModelPartData accessor = ModelPartData.from(part);
-
- if (!accessor.isVisible()) {
- return;
- }
-
- var cuboids = accessor.getCuboids();
- var children = accessor.getChildren();
-
- if (ArrayUtils.isEmpty(cuboids) && ArrayUtils.isEmpty(children)) {
- return;
- }
-
- poseStack.pushPose();
+ public static void renderCuboid(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid cuboid, int light, int overlay, int color) {
+ prepareNormalsIfChanged(matrices);
- part.translateAndRotate(poseStack);
+ prepareVertices(matrices, cuboid);
- if (!accessor.isHidden()) {
- renderCuboids(poseStack.last(), writer, cuboids, light, overlay, color);
- }
-
- renderChildren(poseStack, writer, light, overlay, color, children);
-
- poseStack.popPose();
- }
+ var vertexCount = emitQuads(cuboid, color, overlay, light);
- private static void renderChildren(PoseStack poseStack, VertexBufferWriter writer, int light, int overlay, int color, ModelPart[] children) {
- for (ModelPart part : children) {
- render(poseStack, writer, part, light, overlay, color);
- }
- }
-
- private static void renderCuboids(PoseStack.Pose matrices, VertexBufferWriter writer, ModelCuboid[] cuboids, int light, int overlay, int color) {
- prepareNormals(matrices);
-
- for (ModelCuboid cuboid : cuboids) {
- prepareVertices(matrices, cuboid);
-
- var vertexCount = emitQuads(cuboid, color, overlay, light);
-
- try (MemoryStack stack = MemoryStack.stackPush()) {
- writer.push(stack, SCRATCH_BUFFER, vertexCount, ModelVertex.FORMAT);
- }
+ try (MemoryStack stack = MemoryStack.stackPush()) {
+ writer.push(stack, SCRATCH_BUFFER, vertexCount, ModelVertex.FORMAT);
}
}
@@ -180,21 +145,25 @@ private static void prepareVertices(PoseStack.Pose matrices, ModelCuboid cuboid)
buildVertexTexCoord(VERTEX_TEXTURES[FACE_POS_X], cuboid.u0, cuboid.v1, cuboid.u1, cuboid.v2);
}
- private static void prepareNormals(PoseStack.Pose matrices) {
- CUBE_NORMALS[FACE_NEG_Y] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.DOWN);
- CUBE_NORMALS[FACE_POS_Y] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.UP);
- CUBE_NORMALS[FACE_NEG_Z] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.NORTH);
- CUBE_NORMALS[FACE_POS_Z] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.SOUTH);
- CUBE_NORMALS[FACE_POS_X] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.WEST);
- CUBE_NORMALS[FACE_NEG_X] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.EAST);
-
- // When mirroring is used, the normals for EAST and WEST are swapped.
- CUBE_NORMALS_MIRRORED[FACE_NEG_Y] = CUBE_NORMALS[FACE_NEG_Y];
- CUBE_NORMALS_MIRRORED[FACE_POS_Y] = CUBE_NORMALS[FACE_POS_Y];
- CUBE_NORMALS_MIRRORED[FACE_NEG_Z] = CUBE_NORMALS[FACE_NEG_Z];
- CUBE_NORMALS_MIRRORED[FACE_POS_Z] = CUBE_NORMALS[FACE_POS_Z];
- CUBE_NORMALS_MIRRORED[FACE_POS_X] = CUBE_NORMALS[FACE_NEG_X]; // mirrored
- CUBE_NORMALS_MIRRORED[FACE_NEG_X] = CUBE_NORMALS[FACE_POS_X]; // mirrored
+ public static void prepareNormalsIfChanged(PoseStack.Pose matrices) {
+ if (!matrices.normal().equals(lastMatrix)) {
+ lastMatrix.set(matrices.normal());
+
+ CUBE_NORMALS[FACE_NEG_Y] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.DOWN);
+ CUBE_NORMALS[FACE_POS_Y] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.UP);
+ CUBE_NORMALS[FACE_NEG_Z] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.NORTH);
+ CUBE_NORMALS[FACE_POS_Z] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.SOUTH);
+ CUBE_NORMALS[FACE_POS_X] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.WEST);
+ CUBE_NORMALS[FACE_NEG_X] = MatrixHelper.transformNormal(matrices.normal(), matrices.trustedNormals, Direction.EAST);
+
+ // When mirroring is used, the normals for EAST and WEST are swapped.
+ CUBE_NORMALS_MIRRORED[FACE_NEG_Y] = CUBE_NORMALS[FACE_NEG_Y];
+ CUBE_NORMALS_MIRRORED[FACE_POS_Y] = CUBE_NORMALS[FACE_POS_Y];
+ CUBE_NORMALS_MIRRORED[FACE_NEG_Z] = CUBE_NORMALS[FACE_NEG_Z];
+ CUBE_NORMALS_MIRRORED[FACE_POS_Z] = CUBE_NORMALS[FACE_POS_Z];
+ CUBE_NORMALS_MIRRORED[FACE_POS_X] = CUBE_NORMALS[FACE_NEG_X]; // mirrored
+ CUBE_NORMALS_MIRRORED[FACE_NEG_X] = CUBE_NORMALS[FACE_POS_X]; // mirrored
+ }
}
private static void buildVertexPosition(Vector3f vector, float x, float y, float z, Matrix4f matrix) {
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/immediate/model/ModelCuboid.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteContentsExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/texture/SpriteUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/util/DeferredRenderTask.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/util/RenderAsserts.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerTracker.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexConsumerUtils.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java
similarity index 97%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java
index 1709326113..1cea64380b 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatDescriptionImpl.java
@@ -32,7 +32,7 @@ private static boolean checkSimple(VertexFormat format) {
for (int elementIndex = 0; elementIndex < elementList.size(); elementIndex++) {
var element = elementList.get(elementIndex);
var commonType = CommonVertexAttribute.getCommonType(element);
- if (commonType == null || !attributeSet.add(commonType)) {
+ if ((commonType == null || !attributeSet.add(commonType))) {
return false;
}
}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/VertexFormatRegistryImpl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/BufferBuilderExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/BufferBuilderExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/BufferBuilderExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/buffer/BufferBuilderExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/VertexSerializerRegistryImpl.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/vertex/serializers/generated/VertexSerializerFactory.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/CameraTransform.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/Viewport.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/ViewportProvider.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/Frustum.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/render/viewport/frustum/SimpleFrustum.java
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformBlockAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformBlockAccess.java
new file mode 100644
index 0000000000..18aa1346cf
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformBlockAccess.java
@@ -0,0 +1,91 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.model.quad.ModelQuadView;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
+import net.fabricmc.fabric.api.util.TriState;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.BlockGetter;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.FluidState;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
+
+public interface PlatformBlockAccess {
+ PlatformBlockAccess INSTANCE = Services.load(PlatformBlockAccess.class);
+
+ static PlatformBlockAccess getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Gets the light emission of the current block.
+ * @param state The current block
+ * @param level The current level slice
+ * @param pos The block position
+ * @return The light emission of the current block (default 0)
+ */
+ int getLightEmission(BlockState state, BlockAndTintGetter level, BlockPos pos);
+
+ /**
+ * Checks if the block should stop drawing a specific side based on the adjacent block.
+ * @param level The level slice.
+ * @param selfState The block currently being drawn.
+ * @param otherState The adjacent block.
+ * @param selfPos The current block position.
+ * @param otherPos The other block position.
+ * @param facing The direction between the two blocks.
+ * @return If the block's face should be skipped.
+ */
+ boolean shouldSkipRender(BlockGetter level, BlockState selfState, BlockState otherState, BlockPos selfPos, BlockPos otherPos, Direction facing);
+
+ /**
+ * Returns if the fluid should render fluid overlays if a block is adjacent to it.
+ * @param block The block adjacent to the fluid being rendered
+ * @param level The level slice
+ * @param pos The position of the adjacent block
+ * @param fluidState The fluid
+ * @return True if the fluid should render an overlay.
+ */
+ boolean shouldShowFluidOverlay(BlockState block, BlockAndTintGetter level, BlockPos pos, FluidState fluidState);
+
+ /**
+ * Gets the specialized render data for this block entity.
+ * @param blockEntity The block entity to get the render data of.
+ * @return The specialized render data for this block entity. If the platform does not support it or there is no data, null.
+ */
+ @Nullable
+ Object getBlockEntityData(BlockEntity blockEntity);
+
+ /**
+ * @return If the platform can return block entity data
+ */
+ boolean platformHasBlockData();
+
+ /**
+ * Gets the block shade.
+ * @param quad The quad being rendered.
+ * @param level The level.
+ * @param shade If directional lighting should be added.
+ * @return the block shade
+ */
+ float getAccurateBlockShade(ModelQuadView quad, BlockAndTintGetter level, boolean shade);
+
+ /**
+ * If the block contains forced ambient occlusion.
+ * @param model The model being rendered
+ * @param state The current block
+ * @param data Any model data
+ * @param renderType The current render type being drawn
+ * @param level The level slice
+ * @param pos The current position
+ * @return If ambient occlusion is forced, or {@code DEFAULT}
+ */
+ TriState usesAmbientOcclusion(BakedModel model, BlockState state, SodiumModelData data, RenderType renderType, BlockAndTintGetter level, BlockPos pos);
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformInfoAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformInfoAccess.java
new file mode 100644
index 0000000000..9945809e94
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformInfoAccess.java
@@ -0,0 +1,46 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import java.nio.file.Path;
+
+public interface PlatformInfoAccess {
+ PlatformInfoAccess INSTANCE = Services.load(PlatformInfoAccess.class);
+
+ static PlatformInfoAccess getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Returns if the user is running in a development environment.
+ */
+ boolean isDevelopmentEnvironment();
+
+ /**
+ * Returns the current game directory the user is running in.
+ */
+ Path getGameDirectory();
+
+ /**
+ * Returns the current configuration directory for the platform.
+ */
+ Path getConfigDirectory();
+
+ /**
+ * Returns if the FREX Flawless Frames API has been requested by a mod.
+ */
+ boolean isFlawlessFramesActive();
+
+ /**
+ * Returns if the platform has a early loading screen.
+ */
+ boolean platformHasEarlyLoadingScreen();
+
+ /**
+ * Returns if the platform uses refmaps.
+ */
+ boolean platformUsesRefmap();
+
+ /**
+ * Returns if a mod is in the mods folder during loading.
+ */
+ boolean isModInLoadingList(String modId);
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformLevelAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformLevelAccess.java
new file mode 100644
index 0000000000..bcc2b66ddd
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformLevelAccess.java
@@ -0,0 +1,79 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.VertexConsumer;
+import net.caffeinemc.mods.sodium.client.model.color.ColorProviderRegistry;
+import net.caffeinemc.mods.sodium.client.model.light.LightPipelineProvider;
+import net.caffeinemc.mods.sodium.client.render.chunk.compile.pipeline.FluidRenderer;
+import net.caffeinemc.mods.sodium.client.world.LevelSlice;
+import net.minecraft.client.Camera;
+import net.minecraft.client.renderer.LevelRenderer;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.culling.Frustum;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.SectionPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.chunk.LevelChunk;
+import org.jetbrains.annotations.Nullable;
+import org.joml.Matrix4f;
+
+import java.util.List;
+import java.util.function.Function;
+
+public interface PlatformLevelAccess {
+ PlatformLevelAccess INSTANCE = Services.load(PlatformLevelAccess.class);
+
+ static PlatformLevelAccess getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Creates a new platform dependent fluid renderer.
+ * @param colorRegistry The current color registry.
+ * @param lightPipelineProvider The current {@code LightPipelineProvider}.
+ * @return A new fluid renderer.
+ */
+ FluidRenderer createPlatformFluidRenderer(ColorProviderRegistry colorRegistry, LightPipelineProvider lightPipelineProvider);
+
+ /**
+ * Should be run in the top of the Vanilla fluid renderer. If true, cancel the Vanilla render.
+ * @return if the vanilla rendering should be cancelled.
+ */
+ boolean tryRenderFluid();
+
+ /**
+ * Runs any events after drawing a chunk layer.
+ * @param renderLayer The current chunk layer that was drawn
+ * @param levelRenderer The level renderer
+ * @param modelMatrix The current modelview matrix
+ * @param projectionMatrix The current projection matrix
+ * @param ticks The current tick count
+ * @param mainCamera The current camera
+ * @param cullingFrustum The current frustum
+ */
+ void runChunkLayerEvents(RenderType renderLayer, LevelRenderer levelRenderer, Matrix4f modelMatrix, Matrix4f projectionMatrix, int ticks, Camera mainCamera, Frustum cullingFrustum);
+
+ /**
+ * Returns any NeoForge chunk renderers to run. This is not thread safe.
+ * @param level The current level
+ * @param origin The origin of the current chunk
+ * @return Any NeoForge chunk renderers to run
+ */
+ List> getExtraRenderers(Level level, BlockPos origin);
+
+ /**
+ * Runs any NeoForge chunk renderers.
+ * @param renderers The list of chunk renderers to run.
+ * @param typeToConsumer A consumer that converts render types to vertex consumers
+ * @param slice The current level slice
+ */
+ void renderAdditionalRenderers(List> renderers, Function typeToConsumer, LevelSlice slice);
+
+ /**
+ * Gets the current light manager for the chunk section.
+ * @param chunk The current chunk.
+ * @param pos The section within that chunk being drawn.
+ * @return The current light manager, or null
+ */
+ @Nullable Object getLightManager(LevelChunk chunk, SectionPos pos);
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformModelAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformModelAccess.java
new file mode 100644
index 0000000000..efca9b4d44
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformModelAccess.java
@@ -0,0 +1,77 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import net.caffeinemc.mods.sodium.client.world.LevelSlice;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.core.SectionPos;
+import net.minecraft.util.RandomSource;
+import net.minecraft.world.level.BlockAndTintGetter;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.state.BlockState;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.List;
+
+public interface PlatformModelAccess {
+ PlatformModelAccess INSTANCE = Services.load(PlatformModelAccess.class);
+
+ static PlatformModelAccess getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Returns all the render types used by this model.
+ * @param level The level slice.
+ * @param model The {@code BakedModel} currently being drawn.
+ * @param state The block state of the current block.
+ * @param pos The position of the block being rendered.
+ * @param random The random source used by the current block renderer.
+ * @param modelData The platform specific model data.
+ * @return A list of render types used by this model.
+ */
+ Iterable getModelRenderTypes(BlockAndTintGetter level, BakedModel model, BlockState state, BlockPos pos, RandomSource random, SodiumModelData modelData);
+
+ /**
+ * Returns a list of quads used by this model.
+ * @param level The level slice.
+ * @param pos The position of the block being rendered.
+ * @param model The {@code BakedModel} currently being drawn.
+ * @param state The block state of the current block.
+ * @param face The current face of the block being rendered, or null if rendering unassigned quads.
+ * @param random The random source used by the current block renderer.
+ * @param renderType The current render type being drawn.
+ * @param modelData The platform specific model data.
+ * @return The list of quads used by the model.
+ */
+ List getQuads(BlockAndTintGetter level, BlockPos pos, BakedModel model, BlockState state, Direction face, RandomSource random, RenderType renderType, SodiumModelData modelData);
+
+ /**
+ * Gets the container holding model data for this chunk. This operation is not thread safe.
+ * @param level The current vanilla Level.
+ * @param sectionPos The current chunk position.
+ * @return The model data container for this section
+ */
+ SodiumModelDataContainer getModelDataContainer(Level level, SectionPos sectionPos);
+
+ /**
+ * Gets the true model data from the block data in the container.
+ * @param slice The current world slice.
+ * @param model The current model.
+ * @param state The current block.
+ * @param pos The current block position.
+ * @param originalData The model data, as retrieved by {@code getModelDataContainer()}.
+ * @return The true model data, to render with.
+ */
+ SodiumModelData getModelData(LevelSlice slice, BakedModel model, BlockState state, BlockPos pos, SodiumModelData originalData);
+
+ /**
+ * Should not use. Use {@code SodiumModelData.EMPTY} instead.
+ * @return The empty model data for this platform.
+ */
+ @ApiStatus.Internal
+ SodiumModelData getEmptyModelData();
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformTextureAccess.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformTextureAccess.java
new file mode 100644
index 0000000000..b6f0444860
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/PlatformTextureAccess.java
@@ -0,0 +1,19 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+
+public interface PlatformTextureAccess {
+ PlatformTextureAccess INSTANCE = Services.load(PlatformTextureAccess.class);
+
+ static PlatformTextureAccess getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Finds the current sprite in the block atlas ({@code TextureAtlas.LOCATION_BLOCKS})
+ * @param texU The U coordinate of the texture.
+ * @param texV The V coordinate of the texture.
+ * @return The sprite in the location in the block atlas.
+ */
+ TextureAtlasSprite findInBlockAtlas(float texU, float texV);
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/Services.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/Services.java
new file mode 100644
index 0000000000..eaf6fb20e8
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/Services.java
@@ -0,0 +1,18 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import net.caffeinemc.mods.sodium.client.SodiumClientMod;
+
+import java.util.ServiceLoader;
+
+public class Services {
+ // This code is used to load a service for the current environment. Your implementation of the service must be defined
+ // manually by including a text file in META-INF/services named with the fully qualified class name of the service.
+ // Inside the file you should write the fully qualified class name of the implementation to load for the platform.
+ public static T load(Class clazz) {
+ final T loadedService = ServiceLoader.load(clazz)
+ .findFirst()
+ .orElseThrow(() -> new NullPointerException("Failed to load service for " + clazz.getName()));
+ SodiumClientMod.logger().debug("Loaded {} for service {}", loadedService, clazz);
+ return loadedService;
+ }
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelData.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelData.java
new file mode 100644
index 0000000000..2879d45872
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelData.java
@@ -0,0 +1,8 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+/**
+ * Template class for the platform's model data.
+ */
+public interface SodiumModelData {
+ SodiumModelData EMPTY = PlatformModelAccess.getInstance().getEmptyModelData();
+}
diff --git a/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelDataContainer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelDataContainer.java
new file mode 100644
index 0000000000..acd20d8f67
--- /dev/null
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/services/SodiumModelDataContainer.java
@@ -0,0 +1,27 @@
+package net.caffeinemc.mods.sodium.client.services;
+
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
+import net.minecraft.core.BlockPos;
+
+import java.util.Map;
+
+/**
+ * A container that holds the platform's model data.
+ */
+public class SodiumModelDataContainer {
+ private final Long2ObjectMap modelDataMap;
+ private final boolean isEmpty;
+
+ public SodiumModelDataContainer(Long2ObjectMap modelDataMap) {
+ this.modelDataMap = modelDataMap;
+ this.isEmpty = modelDataMap.isEmpty();
+ }
+
+ public SodiumModelData getModelData(BlockPos pos) {
+ return modelDataMap.getOrDefault(pos.asLong(), SodiumModelData.EMPTY);
+ }
+
+ public boolean isEmpty() {
+ return isEmpty;
+ }
+}
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/BitwiseMath.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/Dim2i.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/DirectionUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/FileUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/ListUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/MathUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/ModelQuadUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeBuffer.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/NativeImageHelper.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/TextureUtil.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/BitArray.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/DoubleBufferedQueue.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/ReadQueue.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/collections/WriteQueue.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/BoxBlur.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/ColorSRGB.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/color/FastCubicSampler.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteArrayIterator.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ByteIterator.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleByteArrayIterator.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/iterator/ReversibleObjectArrayIterator.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/AbstractSort.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/InsertionSort.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/MergeSort.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/RadixSort.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/sorting/VertexSorters.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/util/task/CancellationToken.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/world/BiomeSeedProvider.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/world/BitStorageExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/world/BitStorageExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/world/BitStorageExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/world/BitStorageExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelRendererExtension.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelRendererExtension.java
similarity index 100%
rename from src/main/java/net/caffeinemc/mods/sodium/client/world/LevelRendererExtension.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelRendererExtension.java
diff --git a/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java b/common/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java
similarity index 86%
rename from src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java
rename to common/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java
index 5dc82d4c8c..500c728de2 100644
--- a/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java
+++ b/common/src/main/java/net/caffeinemc/mods/sodium/client/world/LevelSlice.java
@@ -1,9 +1,11 @@
package net.caffeinemc.mods.sodium.client.world;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import net.caffeinemc.mods.sodium.client.services.PlatformLevelAccess;
+import net.caffeinemc.mods.sodium.client.services.PlatformModelAccess;
+import net.caffeinemc.mods.sodium.client.services.SodiumModelData;
+import net.caffeinemc.mods.sodium.client.services.SodiumModelDataContainer;
import net.caffeinemc.mods.sodium.client.world.biome.LevelColorCache;
-import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorSource;
-import net.caffeinemc.mods.sodium.client.world.biome.BiomeColorView;
import net.caffeinemc.mods.sodium.client.world.biome.LevelBiomeSlice;
import net.caffeinemc.mods.sodium.client.world.cloned.ChunkRenderContext;
import net.caffeinemc.mods.sodium.client.world.cloned.ClonedChunkSection;
@@ -34,6 +36,7 @@
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -46,7 +49,7 @@
*
*
Object pooling should be used to avoid huge allocations as this class contains many large arrays.
*/
-public final class LevelSlice implements BlockAndTintGetter, BiomeColorView, RenderAttachedBlockView {
+public final class LevelSlice implements BlockAndTintGetter, RenderAttachedBlockView {
private static final LightLayer[] LIGHT_TYPES = LightLayer.values();
// The number of blocks in a section.
@@ -82,6 +85,10 @@ public final class LevelSlice implements BlockAndTintGetter, BiomeColorView, Ren
// (Local Section -> Block States) table.
private final BlockState[][] blockArrays;
+ // (Local Section -> Light Manager) table.
+ @SuppressWarnings("MismatchedReadAndWriteOfArray")
+ private final Object[] auxLightManager;
+
// (Local Section -> Light Arrays) table.
private final @Nullable DataLayer[][] lightArrays;
@@ -91,6 +98,9 @@ public final class LevelSlice implements BlockAndTintGetter, BiomeColorView, Ren
// (Local Section -> Block Entity Render Data) table.
private final @Nullable Int2ReferenceMap