Skip to content

Commit d274295

Browse files
committed
Implement neoforge outline rendering
1 parent fec1003 commit d274295

7 files changed

Lines changed: 296 additions & 46 deletions

File tree

common/src/main/java/dev/ryanhcode/sable/mixin/block_decal_render/LevelRendererMixin.java

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,20 @@
22

33
import com.llamalad7.mixinextras.sugar.Local;
44
import com.mojang.blaze3d.vertex.PoseStack;
5-
import com.mojang.blaze3d.vertex.VertexConsumer;
65
import dev.ryanhcode.sable.Sable;
76
import dev.ryanhcode.sable.companion.math.Pose3dc;
87
import dev.ryanhcode.sable.sublevel.ClientSubLevel;
98
import net.minecraft.client.Camera;
109
import net.minecraft.client.DeltaTracker;
11-
import net.minecraft.client.Minecraft;
1210
import net.minecraft.client.multiplayer.ClientLevel;
1311
import net.minecraft.client.renderer.GameRenderer;
1412
import net.minecraft.client.renderer.LevelRenderer;
1513
import net.minecraft.client.renderer.LightTexture;
1614
import net.minecraft.core.BlockPos;
17-
import net.minecraft.world.entity.Entity;
18-
import net.minecraft.world.level.block.state.BlockState;
1915
import net.minecraft.world.phys.Vec3;
20-
import net.minecraft.world.phys.shapes.CollisionContext;
21-
import net.minecraft.world.phys.shapes.VoxelShape;
2216
import org.jetbrains.annotations.Nullable;
2317
import org.joml.Matrix4f;
2418
import org.joml.Quaternionf;
25-
import org.joml.Vector3d;
2619
import org.spongepowered.asm.mixin.Mixin;
2720
import org.spongepowered.asm.mixin.Shadow;
2821
import org.spongepowered.asm.mixin.Unique;
@@ -33,51 +26,18 @@
3326
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
3427

3528
/**
36-
* Changes the distance block damage is rendered from, transforms block damage rendering for sublevels, and renders block hover outlines for sublevels.
29+
* Changes the distance block damage is rendered from, and transforms block damage rendering for sublevels.
3730
*/
3831
@Mixin(LevelRenderer.class)
3932
public abstract class LevelRendererMixin {
33+
4034
// Storage vectors to avoid repeated allocation
41-
private final @Unique Vector3d sable$localTranslationStorage = new Vector3d();
42-
private final @Unique Vector3d sable$globalTranslationStorage = new Vector3d();
4335
private final @Unique Quaternionf sable$orientationStorage = new Quaternionf();
4436

4537
@Shadow
4638
@Nullable
4739
private ClientLevel level;
4840

49-
@Shadow
50-
protected static void renderShape(final PoseStack arg, final VertexConsumer arg2, final VoxelShape arg3, final double d, final double e, final double f, final float g, final float h, final float i, final float j) {
51-
}
52-
53-
@Inject(method = "renderHitOutline", at = @At("HEAD"), cancellable = true)
54-
private void sable$preRenderHitOutline(final PoseStack ps, final VertexConsumer pConsumer, final Entity pEntity, final double pCamX, final double pCamY, final double pCamZ, final BlockPos blockPos, final BlockState blockState, final CallbackInfo ci) {
55-
final ClientSubLevel subLevel = (ClientSubLevel) Sable.HELPER.getContaining(this.level, blockPos);
56-
57-
if (subLevel == null) {
58-
return;
59-
}
60-
61-
ps.pushPose();
62-
63-
final Pose3dc pose = subLevel.renderPose();
64-
65-
final Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
66-
67-
final Vector3d globalTranslation = pose.position().sub(cameraPos.x, cameraPos.y, cameraPos.z, this.sable$globalTranslationStorage);
68-
final Vector3d localTranslation = this.sable$localTranslationStorage.set(blockPos.getX(), blockPos.getY(), blockPos.getZ()).sub(pose.rotationPoint());
69-
70-
// apply transforms
71-
ps.translate(globalTranslation.x, globalTranslation.y, globalTranslation.z);
72-
ps.mulPose(this.sable$orientationStorage.set(pose.orientation()));
73-
ps.translate(localTranslation.x, localTranslation.y, localTranslation.z);
74-
75-
renderShape(ps, pConsumer, blockState.getShape(this.level, blockPos, CollisionContext.of(pEntity)), 0, 0, 0, 0.0F, 0.0F, 0.0F, 0.4F);
76-
77-
ps.popPose();
78-
ci.cancel();
79-
}
80-
8141
@Inject(method = "renderLevel", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;last()Lcom/mojang/blaze3d/vertex/PoseStack$Pose;", shift = At.Shift.BEFORE))
8242
private void sable$preRenderBlockDamage(final DeltaTracker deltaTracker, final boolean bl, final Camera camera, final GameRenderer gameRenderer, final LightTexture lightTexture, final Matrix4f matrix4f, final Matrix4f matrix4f2, final CallbackInfo ci, @Local(ordinal = 0) final PoseStack ps, @Local(ordinal = 0) final BlockPos pos) {
8343

common/src/main/java/dev/ryanhcode/sable/mixin/entity/entity_sublevel_collision/CameraMixin.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ public class CameraMixin {
3232

3333
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
3434
private void sable$setPosition(final Camera instance,
35-
final double d,
36-
final double e,
37-
final double f,
35+
final double x,
36+
final double y,
37+
final double z,
3838
final Operation<Void> original,
3939
@Local(argsOnly = true) final Entity entity,
4040
@Local(argsOnly = true) final float partialTicks) {
@@ -58,7 +58,7 @@ public class CameraMixin {
5858
return;
5959
}
6060

61-
original.call(instance, d, e, f);
61+
original.call(instance, x, y, z);
6262

6363
}
6464

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package dev.ryanhcode.sable.mixinhelpers.block_outline_render;
2+
3+
import dev.ryanhcode.sable.companion.math.Pose3dc;
4+
import net.minecraft.client.Camera;
5+
import net.minecraft.core.BlockPos;
6+
import net.minecraft.world.entity.Entity;
7+
import net.minecraft.world.level.material.FogType;
8+
import net.minecraft.world.phys.Vec3;
9+
import org.jetbrains.annotations.ApiStatus;
10+
import org.jetbrains.annotations.NotNull;
11+
import org.joml.Quaterniond;
12+
import org.joml.Quaternionf;
13+
import org.joml.Vector3f;
14+
15+
@ApiStatus.Internal
16+
public class SubLevelCamera extends Camera {
17+
18+
private Camera renderCamera;
19+
private final Quaterniond inverseOrientation = new Quaterniond();
20+
private final Quaternionf inverseOrientationf = new Quaternionf();
21+
private final Vector3f rotationYXZ = new Vector3f();
22+
23+
private final BlockPos.MutableBlockPos blockPosition = new BlockPos.MutableBlockPos();
24+
private Vec3 pos = Vec3.ZERO;
25+
26+
public void transform(final Camera renderCamera, final Pose3dc pose) {
27+
this.renderCamera = renderCamera;
28+
29+
final Vec3 pos = pose.transformPositionInverse(renderCamera.getPosition());
30+
31+
final Quaternionf rotation = this.rotation();
32+
renderCamera.rotation().mul(this.inverseOrientationf.set(pose.orientation().invert(this.inverseOrientation)), rotation);
33+
34+
this.blockPosition.set(pos.x, pos.y, pos.z);
35+
this.pos = pos;
36+
37+
rotation.getEulerAnglesYXZ(this.rotationYXZ);
38+
39+
this.getLookVector().set(0.0F, 0.0F, -1.0F).rotate(rotation);
40+
this.getUpVector().set(0.0F, 1.0F, 0.0F).rotate(rotation);
41+
this.getLeftVector().set(-1.0F, 0.0F, 0.0F).rotate(rotation);
42+
}
43+
44+
public void clear() {
45+
this.renderCamera = null;
46+
this.pos = Vec3.ZERO;
47+
}
48+
49+
@Override
50+
public @NotNull Vec3 getPosition() {
51+
return this.pos;
52+
}
53+
54+
@Override
55+
public @NotNull BlockPos getBlockPosition() {
56+
return this.blockPosition;
57+
}
58+
59+
@Override
60+
public float getXRot() {
61+
return (float) (180.0 / Math.PI * -this.rotationYXZ.x);
62+
}
63+
64+
@Override
65+
public float getYRot() {
66+
return (float) (180.0 / Math.PI * -this.rotationYXZ.y + 180.0);
67+
}
68+
69+
@Override
70+
public @NotNull Entity getEntity() {
71+
return this.renderCamera.getEntity();
72+
}
73+
74+
@Override
75+
public boolean isInitialized() {
76+
return this.renderCamera.isInitialized();
77+
}
78+
79+
@Override
80+
public boolean isDetached() {
81+
return this.renderCamera.isDetached();
82+
}
83+
84+
@Override
85+
public @NotNull NearPlane getNearPlane() {
86+
return this.renderCamera.getNearPlane();
87+
}
88+
89+
@Override
90+
public @NotNull FogType getFluidInCamera() {
91+
return this.renderCamera.getFluidInCamera();
92+
}
93+
94+
@Override
95+
public void reset() {
96+
this.renderCamera.reset();
97+
}
98+
99+
@Override
100+
public float getPartialTickTime() {
101+
return this.renderCamera.getPartialTickTime();
102+
}
103+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package dev.ryanhcode.sable.fabric.mixin.block_outline_render;
2+
3+
import com.mojang.blaze3d.vertex.PoseStack;
4+
import com.mojang.blaze3d.vertex.VertexConsumer;
5+
import dev.ryanhcode.sable.Sable;
6+
import dev.ryanhcode.sable.companion.math.Pose3dc;
7+
import dev.ryanhcode.sable.sublevel.ClientSubLevel;
8+
import net.minecraft.client.Minecraft;
9+
import net.minecraft.client.multiplayer.ClientLevel;
10+
import net.minecraft.client.renderer.LevelRenderer;
11+
import net.minecraft.core.BlockPos;
12+
import net.minecraft.world.entity.Entity;
13+
import net.minecraft.world.level.block.state.BlockState;
14+
import net.minecraft.world.phys.Vec3;
15+
import net.minecraft.world.phys.shapes.CollisionContext;
16+
import net.minecraft.world.phys.shapes.VoxelShape;
17+
import org.jetbrains.annotations.Nullable;
18+
import org.joml.Quaternionf;
19+
import org.joml.Vector3d;
20+
import org.spongepowered.asm.mixin.Mixin;
21+
import org.spongepowered.asm.mixin.Shadow;
22+
import org.spongepowered.asm.mixin.Unique;
23+
import org.spongepowered.asm.mixin.injection.At;
24+
import org.spongepowered.asm.mixin.injection.Inject;
25+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
26+
27+
/**
28+
* Transforms block hover outlines for sublevels.
29+
*/
30+
@Mixin(LevelRenderer.class)
31+
public abstract class LevelRendererMixin {
32+
// Storage vectors to avoid repeated allocation
33+
private final @Unique Vector3d sable$localTranslationStorage = new Vector3d();
34+
private final @Unique Vector3d sable$globalTranslationStorage = new Vector3d();
35+
private final @Unique Quaternionf sable$orientationStorage = new Quaternionf();
36+
37+
@Shadow
38+
@Nullable
39+
private ClientLevel level;
40+
41+
@Shadow
42+
protected static void renderShape(final PoseStack arg, final VertexConsumer arg2, final VoxelShape arg3, final double d, final double e, final double f, final float g, final float h, final float i, final float j) {
43+
}
44+
45+
@Inject(method = "renderHitOutline", at = @At("HEAD"), cancellable = true)
46+
private void sable$preRenderHitOutline(final PoseStack ps, final VertexConsumer pConsumer, final Entity pEntity, final double pCamX, final double pCamY, final double pCamZ, final BlockPos blockPos, final BlockState blockState, final CallbackInfo ci) {
47+
final ClientSubLevel subLevel = (ClientSubLevel) Sable.HELPER.getContaining(this.level, blockPos);
48+
49+
if (subLevel == null) {
50+
return;
51+
}
52+
53+
ps.pushPose();
54+
55+
final Pose3dc pose = subLevel.renderPose();
56+
57+
final Vec3 cameraPos = Minecraft.getInstance().gameRenderer.getMainCamera().getPosition();
58+
59+
final Vector3d globalTranslation = pose.position().sub(cameraPos.x, cameraPos.y, cameraPos.z, this.sable$globalTranslationStorage);
60+
final Vector3d localTranslation = this.sable$localTranslationStorage.set(blockPos.getX(), blockPos.getY(), blockPos.getZ()).sub(pose.rotationPoint());
61+
62+
// apply transforms
63+
ps.translate(globalTranslation.x, globalTranslation.y, globalTranslation.z);
64+
ps.mulPose(this.sable$orientationStorage.set(pose.orientation()));
65+
ps.translate(localTranslation.x, localTranslation.y, localTranslation.z);
66+
67+
renderShape(ps, pConsumer, blockState.getShape(this.level, blockPos, CollisionContext.of(pEntity)), 0, 0, 0, 0.0F, 0.0F, 0.0F, 0.4F);
68+
69+
ps.popPose();
70+
ci.cancel();
71+
}
72+
}

fabric/src/main/resources/sable-fabric.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"minVersion": "0.8",
66
"plugin": "dev.ryanhcode.sable.plugin.SableMixinPlugin",
77
"client": [
8+
"block_outline_render.LevelRendererMixin",
89
"camera_rotation.CameraMixin",
910
"compatibility.sodiumextras.EmbyToolsMixin",
1011
"dynamic_directional_shading.SectionCompilerMixin",

0 commit comments

Comments
 (0)