diff --git a/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java b/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java index 3ce0927b4..3ed227033 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java +++ b/src/main/java/com/jozufozu/flywheel/backend/engine/uniform/FrameUniforms.java @@ -7,11 +7,12 @@ import com.jozufozu.flywheel.api.event.RenderContext; import com.jozufozu.flywheel.api.visualization.VisualizationManager; import com.jozufozu.flywheel.lib.math.MatrixMath; +import net.minecraft.client.Minecraft; import net.minecraft.core.Vec3i; import net.minecraft.world.phys.Vec3; public class FrameUniforms implements UniformProvider { - public static final int SIZE = 220; + public static final int SIZE = 232; private RenderContext context; @@ -51,10 +52,17 @@ public class FrameUniforms implements UniformProvider { writeVec3(ptr + 176, lookVector.x, lookVector.y, lookVector.z); writeVec2(ptr + 192, camera.getXRot(), camera.getYRot()); + var window = Minecraft.getInstance() + .getWindow(); - MemoryUtil.memPutInt(ptr + 200, getConstantAmbientLightFlag(context)); + writeVec2(ptr + 200, window.getWidth(), window.getHeight()); - writeTime(ptr + 204); + // default line width: net.minecraft.client.renderer.RenderStateShard.LineStateShard + MemoryUtil.memPutFloat(ptr + 208, Math.max(2.5F, (float) window.getWidth() / 1920.0F * 2.5F)); + + MemoryUtil.memPutInt(ptr + 212, getConstantAmbientLightFlag(context)); + + writeTime(ptr + 216); } private void writeTime(long ptr) { diff --git a/src/main/java/com/jozufozu/flywheel/lib/material/StandardMaterialShaders.java b/src/main/java/com/jozufozu/flywheel/lib/material/StandardMaterialShaders.java index 84baf4275..7937f7a87 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/material/StandardMaterialShaders.java +++ b/src/main/java/com/jozufozu/flywheel/lib/material/StandardMaterialShaders.java @@ -10,6 +10,8 @@ public final class StandardMaterialShaders { Flywheel.rl("material/default.vert"), Flywheel.rl("material/default.frag"))); + public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag"))); + private StandardMaterialShaders() { } diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java index e48d27bdb..957608290 100644 --- a/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/AbstractEntityVisual.java @@ -35,6 +35,7 @@ public abstract class AbstractEntityVisual extends AbstractVis protected final EntityVisibilityTester visibilityTester; protected final ShadowComponent shadow; protected final FireComponent fire; + protected final BoundingBoxComponent boundingBox; public AbstractEntityVisual(VisualizationContext ctx, T entity) { super(ctx, entity.level()); @@ -42,6 +43,7 @@ public abstract class AbstractEntityVisual extends AbstractVis visibilityTester = new EntityVisibilityTester(entity, ctx.renderOrigin(), 1.5f); shadow = new ShadowComponent(ctx, entity); fire = new FireComponent(ctx, entity); + boundingBox = new BoundingBoxComponent(ctx, entity); } @Override @@ -96,5 +98,6 @@ public abstract class AbstractEntityVisual extends AbstractVis protected void _delete() { shadow.delete(); fire.delete(); + boundingBox.delete(); } } diff --git a/src/main/java/com/jozufozu/flywheel/lib/visual/BoundingBoxComponent.java b/src/main/java/com/jozufozu/flywheel/lib/visual/BoundingBoxComponent.java new file mode 100644 index 000000000..d64b0b78c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/lib/visual/BoundingBoxComponent.java @@ -0,0 +1,170 @@ +package com.jozufozu.flywheel.lib.visual; + +import org.joml.Vector4f; +import org.joml.Vector4fc; + +import com.jozufozu.flywheel.api.material.Material; +import com.jozufozu.flywheel.api.model.Model; +import com.jozufozu.flywheel.api.vertex.MutableVertexList; +import com.jozufozu.flywheel.api.visual.VisualFrameContext; +import com.jozufozu.flywheel.api.visualization.VisualizationContext; +import com.jozufozu.flywheel.lib.instance.InstanceTypes; +import com.jozufozu.flywheel.lib.instance.TransformedInstance; +import com.jozufozu.flywheel.lib.material.SimpleMaterial; +import com.jozufozu.flywheel.lib.material.StandardMaterialShaders; +import com.jozufozu.flywheel.lib.math.MoreMath; +import com.jozufozu.flywheel.lib.model.QuadMesh; +import com.jozufozu.flywheel.lib.model.SingleMeshModel; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; + +public class BoundingBoxComponent { + private static final Material MATERIAL = SimpleMaterial.builder() + .shaders(StandardMaterialShaders.WIREFRAME) + .backfaceCulling(false) + .build(); + private static final Model MODEL = new SingleMeshModel(BoundingBoxMesh.INSTANCE, MATERIAL); + + private final VisualizationContext context; + private final Entity entity; + + private boolean showEyeBox; + + private final InstanceRecycler recycler; + + public BoundingBoxComponent(VisualizationContext context, Entity entity) { + this.context = context; + this.entity = entity; + this.showEyeBox = entity instanceof LivingEntity; + + this.recycler = new InstanceRecycler<>(this::createInstance); + } + + private TransformedInstance createInstance() { + TransformedInstance instance = context.instancerProvider() + .instancer(InstanceTypes.TRANSFORMED, MODEL) + .createInstance(); + instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK)); + instance.setChanged(); + return instance; + } + + public void showEyeBox(boolean renderEyeBox) { + this.showEyeBox = renderEyeBox; + } + + public void beginFrame(VisualFrameContext context) { + recycler.resetCount(); + + var shouldRenderHitBoxes = Minecraft.getInstance() + .getEntityRenderDispatcher() + .shouldRenderHitBoxes(); + if (shouldRenderHitBoxes && !entity.isInvisible() && !Minecraft.getInstance() + .showOnlyReducedInfo()) { + double entityX = Mth.lerp(context.partialTick(), entity.xOld, entity.getX()); + double entityY = Mth.lerp(context.partialTick(), entity.yOld, entity.getY()); + double entityZ = Mth.lerp(context.partialTick(), entity.zOld, entity.getZ()); + + var bbWidth = entity.getBbWidth(); + var bbHeight = entity.getBbHeight(); + var bbWidthHalf = bbWidth * 0.5; + recycler.get() + .loadIdentity() + .translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf) + .scale(bbWidth, bbHeight, bbWidth) + .setChanged(); + + // TODO: multipart entities and view vectors + + if (showEyeBox) { + recycler.get() + .loadIdentity() + .translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf) + .scale(bbWidth, 0.02f, bbWidth) + .setColor(255, 0, 0) + .setChanged(); + } + } + + recycler.discardExtra(); + } + + public void delete() { + recycler.delete(); + } + + private static class BoundingBoxMesh implements QuadMesh { + private static final BoundingBoxMesh INSTANCE = new BoundingBoxMesh(); + private static final Vector4fc BOUNDING_SPHERE = new Vector4f(0.5f, 0.5f, 0.5f, MoreMath.SQRT_3_OVER_2); + + private BoundingBoxMesh() { + } + + @Override + public int vertexCount() { + return 24; + } + + @Override + public void write(MutableVertexList vertexList) { + // very cursed, maybe we should use vanilla ModelParts instead? + writeVertex(vertexList, 0, 0, 0, 0, 0, 0); + writeVertex(vertexList, 1, 1, 0, 0, 1, 0); + writeVertex(vertexList, 2, 1, 1, 0, 1, 1); + writeVertex(vertexList, 3, 0, 1, 0, 0, 1); + + writeVertex(vertexList, 4, 0, 0, 1, 0, 0); + writeVertex(vertexList, 5, 0, 0, 0, 1, 0); + writeVertex(vertexList, 6, 0, 1, 0, 1, 1); + writeVertex(vertexList, 7, 0, 1, 1, 0, 1); + + writeVertex(vertexList, 8, 0, 1, 0, 0, 0); + writeVertex(vertexList, 9, 1, 1, 0, 1, 0); + writeVertex(vertexList, 10, 1, 1, 1, 1, 1); + writeVertex(vertexList, 11, 0, 1, 1, 0, 1); + + writeVertex(vertexList, 12, 1, 0, 1, 0, 0); + writeVertex(vertexList, 13, 0, 0, 1, 1, 0); + writeVertex(vertexList, 14, 0, 1, 1, 1, 1); + writeVertex(vertexList, 15, 1, 1, 1, 0, 1); + + writeVertex(vertexList, 16, 1, 0, 0, 0, 0); + writeVertex(vertexList, 17, 1, 0, 1, 1, 0); + writeVertex(vertexList, 18, 1, 1, 1, 1, 1); + writeVertex(vertexList, 19, 1, 1, 0, 0, 1); + + writeVertex(vertexList, 20, 0, 0, 0, 0, 0); + writeVertex(vertexList, 21, 1, 0, 0, 1, 0); + writeVertex(vertexList, 22, 1, 0, 1, 1, 1); + writeVertex(vertexList, 23, 0, 0, 1, 0, 1); + } + + @Override + public Vector4fc boundingSphere() { + return BOUNDING_SPHERE; + } + + @Override + public void delete() { + } + + private static void writeVertex(MutableVertexList vertexList, int i, float x, float y, float z, float u, float v) { + vertexList.x(i, x); + vertexList.y(i, y); + vertexList.z(i, z); + vertexList.r(i, 1); + vertexList.g(i, 1); + vertexList.b(i, 1); + vertexList.u(i, u); + vertexList.v(i, v); + vertexList.light(i, LightTexture.FULL_BRIGHT); + vertexList.normalX(i, 0); + vertexList.normalY(i, 1); + vertexList.normalZ(i, 0); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java index 2b19898f8..2fb19d7e5 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/MinecartVisual.java @@ -111,6 +111,7 @@ public class MinecartVisual extends AbstractEntityVi public void beginFrame(VisualFrameContext context) { shadow.beginFrame(context); fire.beginFrame(context); + boundingBox.beginFrame(context); if (!isVisible(context.frustum())) { return; diff --git a/src/main/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl b/src/main/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl index a5cc4dce0..84a2a09f0 100644 --- a/src/main/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl +++ b/src/main/resources/assets/flywheel/flywheel/internal/uniforms/frame.glsl @@ -15,6 +15,10 @@ layout(std140) uniform _FlwFrameUniforms { vec4 flw_cameraPos; vec4 flw_cameraLook; vec2 flw_cameraRot; + + vec2 flw_viewportSize; + float flw_defaultLineWidth; + uint flw_constantAmbientLight; uint flw_ticks; diff --git a/src/main/resources/assets/flywheel/flywheel/material/wireframe.frag b/src/main/resources/assets/flywheel/flywheel/material/wireframe.frag new file mode 100644 index 000000000..8b2088d42 --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/material/wireframe.frag @@ -0,0 +1,10 @@ +void flw_materialFragment() { + float closestEdge = min(flw_vertexTexCoord.s, min(flw_vertexTexCoord.t, min(1. - flw_vertexTexCoord.s, 1. - flw_vertexTexCoord.t))); + + // multiply by fwidth to get the width of the edge in screen space + if (flw_defaultLineWidth * fwidth(closestEdge) < closestEdge) { + discard; + } + + flw_fragColor = flw_vertexColor; +} diff --git a/src/main/resources/assets/flywheel/flywheel/material/wireframe.vert b/src/main/resources/assets/flywheel/flywheel/material/wireframe.vert new file mode 100644 index 000000000..5d92e7ffb --- /dev/null +++ b/src/main/resources/assets/flywheel/flywheel/material/wireframe.vert @@ -0,0 +1,2 @@ +void flw_materialVertex() { +}