1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-02 22:53:15 +00:00

Fix quad order when rendering turtles upside down

- Reverse quads in our model transformer and when rendering as a block
   entity.
 - Correctly recompute normals when the quads have been inverted.

Closes #1283
This commit is contained in:
Jonathan Coates
2023-06-18 19:30:25 +01:00
parent 36b9f4ec55
commit 953372b1b7
4 changed files with 172 additions and 81 deletions

View File

@@ -4,84 +4,32 @@
package dan200.computercraft.client.model;
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexFormatElement;
import com.mojang.math.Transformation;
import dan200.computercraft.client.model.turtle.ModelTransformer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link BakedModel} which applies a transformation matrix to its underlying quads.
*
* @see ModelTransformer
*/
public class TransformedBakedModel extends CustomBakedModel {
private static final int STRIDE = DefaultVertexFormat.BLOCK.getIntegerSize();
private static final int POS_OFFSET = findOffset(DefaultVertexFormat.BLOCK, DefaultVertexFormat.ELEMENT_POSITION);
private final Matrix4f transformation;
private @Nullable TransformedQuads cache;
private final ModelTransformer transformation;
public TransformedBakedModel(BakedModel model, Transformation transformation) {
super(model);
this.transformation = transformation.getMatrix();
this.transformation = new ModelTransformer(transformation);
}
@Override
public List<BakedQuad> getQuads(@Nullable BlockState blockState, @Nullable Direction face, RandomSource rand) {
var cache = this.cache;
var quads = wrapped.getQuads(blockState, face, rand);
if (quads.isEmpty()) return List.of();
// We do some basic caching here to avoid recomputing every frame. Most turtle models don't have culled faces,
// so it's not worth being smarter here.
if (cache != null && quads.equals(cache.original())) return cache.transformed();
List<BakedQuad> transformed = new ArrayList<>(quads.size());
for (var quad : quads) transformed.add(transformQuad(quad));
this.cache = new TransformedQuads(quads, transformed);
return transformed;
}
private BakedQuad transformQuad(BakedQuad quad) {
var vertexData = quad.getVertices().clone();
for (var i = 0; i < 4; i++) {
// Apply the matrix to our position
var start = STRIDE * i + POS_OFFSET;
var x = Float.intBitsToFloat(vertexData[start]);
var y = Float.intBitsToFloat(vertexData[start + 1]);
var z = Float.intBitsToFloat(vertexData[start + 2]);
// Transform the position
var pos = new Vector4f(x, y, z, 1);
transformation.transformProject(pos);
vertexData[start] = Float.floatToRawIntBits(pos.x());
vertexData[start + 1] = Float.floatToRawIntBits(pos.y());
vertexData[start + 2] = Float.floatToRawIntBits(pos.z());
}
return new BakedQuad(vertexData, quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade());
}
private record TransformedQuads(List<BakedQuad> original, List<BakedQuad> transformed) {
}
private static int findOffset(VertexFormat format, VertexFormatElement element) {
var offset = 0;
for (var other : format.getElements()) {
if (other == element) return offset / Integer.BYTES;
offset += element.getByteSize();
}
throw new IllegalArgumentException("Cannot find " + element + " in " + format);
return transformation.transform(wrapped.getQuads(blockState, face, rand));
}
}