Skip to content

Commit

Permalink
Merge pull request #221 from PepperCode1/pr/1.20.x/main/fixes
Browse files Browse the repository at this point in the history
Fix and Improve 0.5 Port
  • Loading branch information
comp500 committed Aug 5, 2023
2 parents 3dd1814 + 7a0e27e commit 78ef0ea
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 82 deletions.
107 changes: 71 additions & 36 deletions src/main/java/link/infra/indium/renderer/aocalc/AoCalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

package link.infra.indium.renderer.aocalc;

import static java.lang.Math.max;
import static link.infra.indium.renderer.helper.GeometryHelper.AXIS_ALIGNED_FLAG;
import static link.infra.indium.renderer.helper.GeometryHelper.CUBIC_FLAG;
import static link.infra.indium.renderer.helper.GeometryHelper.LIGHT_FACE_FLAG;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.getLightmap;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.unpackAO;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.unpackEM;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.unpackFO;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.getLightmap;
import static me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess.unpackOP;
import static net.minecraft.util.math.Direction.DOWN;
import static net.minecraft.util.math.Direction.EAST;
Expand All @@ -44,6 +44,7 @@
import link.infra.indium.renderer.mesh.QuadViewImpl;
import link.infra.indium.renderer.render.BlockRenderInfo;
import me.jellysquid.mods.sodium.client.model.light.data.LightDataAccess;
import net.minecraft.client.render.LightmapTextureManager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.MathHelper;
Expand Down Expand Up @@ -369,76 +370,93 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo
final int word0 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[0]);
final int light0 = getLightmap(word0);
final float ao0 = unpackAO(word0);
final boolean isClear0 = unpackOP(word0);
final boolean opaque0 = unpackOP(word0);
final boolean em0 = unpackEM(word0);

final int word1 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[1]);
final int light1 = getLightmap(word1);
final float ao1 = unpackAO(word1);
final boolean isClear1 = unpackOP(word1);
final boolean opaque1 = unpackOP(word1);
final boolean em1 = unpackEM(word1);

final int word2 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[2]);
final int light2 = getLightmap(word2);
final float ao2 = unpackAO(word2);
final boolean isClear2 = unpackOP(word2);
final boolean opaque2 = unpackOP(word2);
final boolean em2 = unpackEM(word2);

final int word3 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[3]);
final int light3 = getLightmap(word3);
final float ao3 = unpackAO(word3);
final boolean isClear3 = unpackOP(word3);
final boolean opaque3 = unpackOP(word3);
final boolean em3 = unpackEM(word3);

// c = corner - values at corners of face
int cLight0, cLight1, cLight2, cLight3;
float cAo0, cAo1, cAo2, cAo3;
boolean cEm0, cEm1, cEm2, cEm3;

// If neighbors on both sides of the corner are opaque, then apparently we use the light/shade
// from one of the sides adjacent to the corner. If either neighbor is clear (no light subtraction)
// then we use values from the outwardly diagonal corner. (outwardly = position is one more away from light face)
if (!isClear2 && !isClear0) {
if (opaque2 && opaque0) {
cAo0 = ao0;
cLight0 = light0;
cEm0 = em0;
} else {
final int word02 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[0], neighbors[2]);
cAo0 = unpackAO(word02);
cLight0 = getLightmap(word02);
cEm0 = unpackEM(word02);
}

if (!isClear3 && !isClear0) {
if (opaque3 && opaque0) {
cAo1 = ao0;
cLight1 = light0;
cEm1 = em0;
} else {
final int word03 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[0], neighbors[3]);
cAo1 = unpackAO(word03);
cLight1 = getLightmap(word03);
cEm1 = unpackEM(word03);
}

if (!isClear2 && !isClear1) {
if (opaque2 && opaque1) {
cAo2 = ao1;
cLight2 = light1;
cEm2 = em1;
} else {
final int word12 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[1], neighbors[2]);
cAo2 = unpackAO(word12);
cLight2 = getLightmap(word12);
cEm2 = unpackEM(word12);
}

if (!isClear3 && !isClear1) {
if (opaque3 && opaque1) {
cAo3 = ao1;
cLight3 = light1;
cEm3 = em1;
} else {
final int word13 = cache.get(lightPosX, lightPosY, lightPosZ, neighbors[1], neighbors[3]);
cAo3 = unpackAO(word13);
cLight3 = getLightmap(word13);
cEm3 = unpackEM(word13);
}

int centerWord = cache.get(lightPosX, lightPosY, lightPosZ);

// If on block face or neighbor isn't occluding, "center" will be neighbor brightness
// Doesn't use light pos because logic not based solely on this block's geometry
int lightCenter;
boolean emCenter;

if (isOnBlockFace || !unpackFO(centerWord)) {
lightCenter = getLightmap(centerWord);
if (isOnBlockFace && unpackFO(centerWord)) {
final int originWord = cache.get(x, y, z);
lightCenter = getLightmap(originWord);
emCenter = unpackEM(originWord);
} else {
lightCenter = getLightmap(cache.get(x, y, z));
lightCenter = getLightmap(centerWord);
emCenter = unpackEM(centerWord);
}

float aoCenter = unpackAO(centerWord);
Expand All @@ -449,34 +467,51 @@ private void computeFace(AoFaceData result, Direction lightFace, boolean isOnBlo
result.a2 = ((ao2 + ao1 + cAo2 + aoCenter) * 0.25F) * worldBrightness;
result.a3 = ((ao3 + ao1 + cAo3 + aoCenter) * 0.25F) * worldBrightness;

result.l0(meanBrightness(light3, light0, cLight1, lightCenter));
result.l1(meanBrightness(light2, light0, cLight0, lightCenter));
result.l2(meanBrightness(light2, light1, cLight2, lightCenter));
result.l3(meanBrightness(light3, light1, cLight3, lightCenter));
result.l0(calculateCornerBrightness(light3, light0, cLight1, lightCenter, em3, em0, cEm1, emCenter));
result.l1(calculateCornerBrightness(light2, light0, cLight0, lightCenter, em2, em0, cEm0, emCenter));
result.l2(calculateCornerBrightness(light2, light1, cLight2, lightCenter, em2, em1, cEm2, emCenter));
result.l3(calculateCornerBrightness(light3, light1, cLight3, lightCenter, em3, em1, cEm3, emCenter));
}

/**
* Vanilla code excluded missing light values from mean but was not isotropic.
* Still need to substitute or edges are too dark but consistently use the min
* value from all four samples.
*/
private static int meanBrightness(int a, int b, int c, int d) {
return a == 0 || b == 0 || c == 0 || d == 0 ? meanEdgeBrightness(a, b, c, d) : meanInnerBrightness(a, b, c, d);
}
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
if ((a == 0) || (b == 0) || (c == 0) || (d == 0)) {
// Find the minimum value between all corners
final int min = minNonZero(minNonZero(a, b), minNonZero(c, d));

// Normalize the corner values
a = Math.max(a, min);
b = Math.max(b, min);
c = Math.max(c, min);
d = Math.max(d, min);
}

private static int meanInnerBrightness(int a, int b, int c, int d) {
// bitwise divide by 4, clamp to expected (positive) range
return a + b + c + d >> 2 & 0xFF00FF;
}
// FIX: Apply the fullbright lightmap from emissive blocks at the very end so it cannot influence
// the minimum lightmap and produce incorrect results (for example, sculk sensors in a dark room)
if (aem) {
a = LightmapTextureManager.MAX_LIGHT_COORDINATE;
}
if (bem) {
b = LightmapTextureManager.MAX_LIGHT_COORDINATE;
}
if (cem) {
c = LightmapTextureManager.MAX_LIGHT_COORDINATE;
}
if (dem) {
d = LightmapTextureManager.MAX_LIGHT_COORDINATE;
}

private static int nonZeroMin(int a, int b) {
if (a == 0) return b;
if (b == 0) return a;
return Math.min(a, b);
return ((a + b + c + d) >> 2) & 0xFF00FF;
}

private static int meanEdgeBrightness(int a, int b, int c, int d) {
final int min = nonZeroMin(nonZeroMin(a, b), nonZeroMin(c, d));
return meanInnerBrightness(max(a, min), max(b, min), max(c, min), max(d, min));
private static int minNonZero(int a, int b) {
if (a == 0) {
return b;
} else if (b == 0) {
return a;
}

return Math.min(a, b);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@

import org.joml.Vector3f;

import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
import me.jellysquid.mods.sodium.client.util.DirectionUtil;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Direction.Axis;
import net.minecraft.util.math.Direction.AxisDirection;

import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.minecraft.util.math.MathHelper;

/**
* Static routines of general utility for renderer implementations.
Expand Down Expand Up @@ -197,6 +199,33 @@ public static Direction lightFace(QuadView quad) {
}
}

// Copied from ModelQuadUtil.findNormalFace to prevent unnecessary allocation
public static ModelQuadFacing normalFace(QuadView quad) {
final Vector3f normal = quad.faceNormal();

if (!normal.isFinite()) {
return ModelQuadFacing.UNASSIGNED;
}

float maxDot = 0;
Direction closestFace = null;

for (Direction face : DirectionUtil.ALL_DIRECTIONS) {
float dot = normal.dot(face.getUnitVector());

if (dot > maxDot) {
maxDot = dot;
closestFace = face;
}
}

if (closestFace != null && MathHelper.approximatelyEquals(maxDot, 1.0f)) {
return ModelQuadFacing.fromDirection(closestFace);
}

return ModelQuadFacing.UNASSIGNED;
}

/**
* Simple 4-way compare, doesn't handle NaN values.
*/
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/link/infra/indium/renderer/mesh/EncodingFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import link.infra.indium.renderer.helper.GeometryHelper;
import link.infra.indium.renderer.material.RenderMaterialImpl;
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
import net.minecraft.client.render.VertexFormat;
Expand Down Expand Up @@ -77,13 +78,17 @@ private EncodingFormat() { }
/** used for quick clearing of quad buffers. */
static final int[] EMPTY = new int[TOTAL_STRIDE];

private static final int DIRECTION_MASK = MathHelper.smallestEncompassingPowerOfTwo(ModelHelper.NULL_FACE_ID) - 1;
private static final int DIRECTION_MASK = MathHelper.smallestEncompassingPowerOfTwo(ModelHelper.NULL_FACE_ID + 1) - 1;
private static final int DIRECTION_BIT_COUNT = Integer.bitCount(DIRECTION_MASK);
private static final int FACING_MASK = MathHelper.smallestEncompassingPowerOfTwo(ModelQuadFacing.COUNT) - 1;
private static final int FACING_BIT_COUNT = Integer.bitCount(FACING_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 NORMALS_SHIFT = LIGHT_SHIFT + DIRECTION_BIT_COUNT;
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);
Expand Down Expand Up @@ -115,6 +120,14 @@ 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;
Expand Down
16 changes: 15 additions & 1 deletion src/main/java/link/infra/indium/renderer/mesh/QuadViewImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import link.infra.indium.renderer.helper.GeometryHelper;
import link.infra.indium.renderer.helper.NormalHelper;
import link.infra.indium.renderer.material.RenderMaterialImpl;
import me.jellysquid.mods.sodium.client.model.quad.properties.ModelQuadFacing;
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
import net.minecraft.util.math.Direction;

Expand All @@ -51,7 +52,7 @@
public class QuadViewImpl implements QuadView {
@Nullable
protected Direction nominalFace;
/** True when face normal, light face, or geometry flags may not match geometry. */
/** 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();

Expand Down Expand Up @@ -81,6 +82,9 @@ protected void computeGeometry() {
// depends on face normal
data[baseIndex + HEADER_BITS] = EncodingFormat.lightFace(data[baseIndex + HEADER_BITS], GeometryHelper.lightFace(this));

// depends on face normal
data[baseIndex + HEADER_BITS] = EncodingFormat.normalFace(data[baseIndex + HEADER_BITS], GeometryHelper.normalFace(this));

// depends on light face
data[baseIndex + HEADER_BITS] = EncodingFormat.geometryFlags(data[baseIndex + HEADER_BITS], GeometryHelper.computeShapeFlags(this));
}
Expand Down Expand Up @@ -172,6 +176,11 @@ 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;
}
Expand Down Expand Up @@ -220,6 +229,11 @@ public final Direction lightFace() {
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() {
Expand Down
Loading

0 comments on commit 78ef0ea

Please sign in to comment.