mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Lines aren't too bad
- Add LineModelBuilder and use that instead of the manual mesh creation in HitboxComponent. - Clone mojang's line shader, adapted as a flywheel material. - Do not scale the view. - Set flw_vertexPos by multiplying by the inverse view projection. - Remove centerline material. - Use #define make padded vec3 uniforms available as actual vec3s. - Add flw_viewProjectionInverse to uniforms. - Minecarts actually delete the stuff from SimpleEntityVisual.
This commit is contained in:
parent
d5732bd788
commit
40a50642f3
12 changed files with 371 additions and 227 deletions
|
@ -1,5 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.engine.uniform;
|
package com.jozufozu.flywheel.backend.engine.uniform;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
@ -7,16 +8,19 @@ import com.jozufozu.flywheel.api.event.RenderContext;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
|
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
|
||||||
import com.jozufozu.flywheel.lib.math.MatrixMath;
|
import com.jozufozu.flywheel.lib.math.MatrixMath;
|
||||||
|
|
||||||
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class FrameUniforms implements UniformProvider {
|
public class FrameUniforms implements UniformProvider {
|
||||||
public static final int SIZE = 232;
|
public static final int SIZE = 304;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private RenderContext context;
|
private RenderContext context;
|
||||||
|
|
||||||
private final Matrix4f viewProjection = new Matrix4f();
|
private final Matrix4f viewProjection = new Matrix4f();
|
||||||
|
private final Matrix4f viewProjectionInverse = new Matrix4f();
|
||||||
|
|
||||||
public int byteSize() {
|
public int byteSize() {
|
||||||
return SIZE;
|
return SIZE;
|
||||||
|
@ -28,6 +32,10 @@ public class FrameUniforms implements UniformProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(long ptr) {
|
public void write(long ptr) {
|
||||||
|
if (context == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
|
Vec3i renderOrigin = VisualizationManager.getOrThrow(context.level())
|
||||||
.getRenderOrigin();
|
.getRenderOrigin();
|
||||||
var camera = context.camera();
|
var camera = context.camera();
|
||||||
|
@ -45,27 +53,43 @@ public class FrameUniforms implements UniformProvider {
|
||||||
Uniforms.frustumCapture = false;
|
Uniforms.frustumCapture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MatrixMath.writeUnsafe(viewProjection, ptr + 96);
|
ptr += 96;
|
||||||
writeVec3(ptr + 160, camX, camY, camZ);
|
|
||||||
|
|
||||||
var lookVector = camera.getLookVector();
|
ptr = writeMatrices(ptr);
|
||||||
writeVec3(ptr + 176, lookVector.x, lookVector.y, lookVector.z);
|
|
||||||
|
ptr = writeCamera(ptr, camX, camY, camZ, camera);
|
||||||
|
|
||||||
writeVec2(ptr + 192, camera.getXRot(), camera.getYRot());
|
|
||||||
var window = Minecraft.getInstance()
|
var window = Minecraft.getInstance()
|
||||||
.getWindow();
|
.getWindow();
|
||||||
|
ptr = writeVec2(ptr, window.getWidth(), window.getHeight());
|
||||||
writeVec2(ptr + 200, window.getWidth(), window.getHeight());
|
|
||||||
|
|
||||||
// default line width: net.minecraft.client.renderer.RenderStateShard.LineStateShard
|
// 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.memPutFloat(ptr, Math.max(2.5F, (float) window.getWidth() / 1920.0F * 2.5F));
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
MemoryUtil.memPutInt(ptr + 212, getConstantAmbientLightFlag(context));
|
MemoryUtil.memPutInt(ptr, getConstantAmbientLightFlag(context));
|
||||||
|
ptr += 4;
|
||||||
|
|
||||||
writeTime(ptr + 216);
|
writeTime(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeTime(long ptr) {
|
private long writeMatrices(long ptr) {
|
||||||
|
MatrixMath.writeUnsafe(viewProjection, ptr);
|
||||||
|
MatrixMath.writeUnsafe(viewProjection.invert(viewProjectionInverse), ptr + 64);
|
||||||
|
return ptr + 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long writeCamera(long ptr, float camX, float camY, float camZ, Camera camera) {
|
||||||
|
ptr = writeVec3(ptr, camX, camY, camZ);
|
||||||
|
|
||||||
|
var lookVector = camera.getLookVector();
|
||||||
|
ptr = writeVec3(ptr, lookVector.x, lookVector.y, lookVector.z);
|
||||||
|
|
||||||
|
ptr = writeVec2(ptr, camera.getXRot(), camera.getYRot());
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long writeTime(long ptr) {
|
||||||
int ticks = context.renderer()
|
int ticks = context.renderer()
|
||||||
.getTicks();
|
.getTicks();
|
||||||
float partialTick = context.partialTick();
|
float partialTick = context.partialTick();
|
||||||
|
@ -76,18 +100,21 @@ public class FrameUniforms implements UniformProvider {
|
||||||
MemoryUtil.memPutFloat(ptr + 4, partialTick);
|
MemoryUtil.memPutFloat(ptr + 4, partialTick);
|
||||||
MemoryUtil.memPutFloat(ptr + 8, renderTicks);
|
MemoryUtil.memPutFloat(ptr + 8, renderTicks);
|
||||||
MemoryUtil.memPutFloat(ptr + 12, renderSeconds);
|
MemoryUtil.memPutFloat(ptr + 12, renderSeconds);
|
||||||
|
return ptr + 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeVec3(long ptr, float camX, float camY, float camZ) {
|
private static long writeVec3(long ptr, float camX, float camY, float camZ) {
|
||||||
MemoryUtil.memPutFloat(ptr, camX);
|
MemoryUtil.memPutFloat(ptr, camX);
|
||||||
MemoryUtil.memPutFloat(ptr + 4, camY);
|
MemoryUtil.memPutFloat(ptr + 4, camY);
|
||||||
MemoryUtil.memPutFloat(ptr + 8, camZ);
|
MemoryUtil.memPutFloat(ptr + 8, camZ);
|
||||||
MemoryUtil.memPutFloat(ptr + 12, 0f); // empty component of vec4 because we don't trust std140
|
MemoryUtil.memPutFloat(ptr + 12, 0f); // empty component of vec4 because we don't trust std140
|
||||||
|
return ptr + 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeVec2(long ptr, float camX, float camY) {
|
private static long writeVec2(long ptr, float camX, float camY) {
|
||||||
MemoryUtil.memPutFloat(ptr, camX);
|
MemoryUtil.memPutFloat(ptr, camX);
|
||||||
MemoryUtil.memPutFloat(ptr + 4, camY);
|
MemoryUtil.memPutFloat(ptr + 4, camY);
|
||||||
|
return ptr + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getConstantAmbientLightFlag(RenderContext context) {
|
private static int getConstantAmbientLightFlag(RenderContext context) {
|
||||||
|
|
|
@ -12,7 +12,7 @@ public final class StandardMaterialShaders {
|
||||||
|
|
||||||
public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag")));
|
public static final MaterialShaders WIREFRAME = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/wireframe.vert"), Flywheel.rl("material/wireframe.frag")));
|
||||||
|
|
||||||
public static final MaterialShaders CENTERLINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/centerline.vert"), Flywheel.rl("material/centerline.frag")));
|
public static final MaterialShaders LINE = MaterialShaders.REGISTRY.registerAndGet(new SimpleMaterialShaders(Flywheel.rl("material/lines.vert"), Flywheel.rl("material/lines.frag")));
|
||||||
|
|
||||||
private StandardMaterialShaders() {
|
private StandardMaterialShaders() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
package com.jozufozu.flywheel.lib.model;
|
||||||
|
|
||||||
|
import org.joml.Vector4f;
|
||||||
|
import org.joml.Vector4fc;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.model.IndexSequence;
|
||||||
|
import com.jozufozu.flywheel.api.model.Mesh;
|
||||||
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.MutableVertexList;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.VertexView;
|
||||||
|
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
|
||||||
|
import com.jozufozu.flywheel.lib.material.StandardMaterialShaders;
|
||||||
|
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||||
|
import com.jozufozu.flywheel.lib.vertex.FullVertexView;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
|
public class LineModelBuilder {
|
||||||
|
public static final Material MATERIAL = SimpleMaterial.builder()
|
||||||
|
.shaders(StandardMaterialShaders.LINE)
|
||||||
|
.backfaceCulling(false)
|
||||||
|
.diffuse(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private final VertexView vertices;
|
||||||
|
private MemoryBlock block;
|
||||||
|
private int vertexCount = 0;
|
||||||
|
|
||||||
|
private LineModelBuilder(int segmentCount) {
|
||||||
|
this.vertices = new FullVertexView();
|
||||||
|
this.block = MemoryBlock.malloc(segmentCount * 4 * FullVertexView.STRIDE);
|
||||||
|
vertices.ptr(block.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LineModelBuilder withCapacity(int segmentCount) {
|
||||||
|
return new LineModelBuilder(segmentCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LineModelBuilder line(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||||
|
ensureCapacity(vertexCount + 4);
|
||||||
|
|
||||||
|
// We'll use the normal to figure out the orientation of the line in the vertex shader.
|
||||||
|
float dx = x2 - x1;
|
||||||
|
float dy = y2 - y1;
|
||||||
|
float dz = z2 - z1;
|
||||||
|
float length = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
float normalX = dx / length;
|
||||||
|
float normalY = dy / length;
|
||||||
|
float normalZ = dz / length;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
vertices.x(vertexCount + i, x1);
|
||||||
|
vertices.y(vertexCount + i, y1);
|
||||||
|
vertices.z(vertexCount + i, z1);
|
||||||
|
|
||||||
|
vertices.x(vertexCount + 2 + i, x2);
|
||||||
|
vertices.y(vertexCount + 2 + i, y2);
|
||||||
|
vertices.z(vertexCount + 2 + i, z2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
vertices.r(vertexCount + i, 1);
|
||||||
|
vertices.g(vertexCount + i, 1);
|
||||||
|
vertices.b(vertexCount + i, 1);
|
||||||
|
vertices.a(vertexCount + i, 1);
|
||||||
|
vertices.u(vertexCount + i, 0);
|
||||||
|
vertices.v(vertexCount + i, 0);
|
||||||
|
vertices.light(vertexCount + i, LightTexture.FULL_BRIGHT);
|
||||||
|
vertices.normalX(vertexCount + i, normalX);
|
||||||
|
vertices.normalY(vertexCount + i, normalY);
|
||||||
|
vertices.normalZ(vertexCount + i, normalZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertexCount += 4;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Model build() {
|
||||||
|
vertices.vertexCount(vertexCount);
|
||||||
|
|
||||||
|
var boundingSphere = ModelUtil.computeBoundingSphere(vertices);
|
||||||
|
boundingSphere.w += 0.1f; // make the bounding sphere a little bigger to account for line width
|
||||||
|
|
||||||
|
var mesh = new LineMesh(vertexCount, vertices, block, boundingSphere);
|
||||||
|
|
||||||
|
return new SingleMeshModel(mesh, MATERIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureCapacity(int vertexCount) {
|
||||||
|
if (vertexCount * FullVertexView.STRIDE > block.size()) {
|
||||||
|
this.block = block.realloc(vertexCount * FullVertexView.STRIDE);
|
||||||
|
vertices.ptr(block.ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LineMesh implements Mesh {
|
||||||
|
public static final IndexSequence INDEX_SEQUENCE = (ptr, count) -> {
|
||||||
|
int numVertices = 4 * (count / 6);
|
||||||
|
int baseVertex = 0;
|
||||||
|
while (baseVertex < numVertices) {
|
||||||
|
// triangle a
|
||||||
|
MemoryUtil.memPutInt(ptr, baseVertex);
|
||||||
|
MemoryUtil.memPutInt(ptr + 4, baseVertex + 1);
|
||||||
|
MemoryUtil.memPutInt(ptr + 8, baseVertex + 2);
|
||||||
|
// triangle b
|
||||||
|
MemoryUtil.memPutInt(ptr + 12, baseVertex + 3);
|
||||||
|
MemoryUtil.memPutInt(ptr + 16, baseVertex + 2);
|
||||||
|
MemoryUtil.memPutInt(ptr + 20, baseVertex + 1);
|
||||||
|
|
||||||
|
baseVertex += 4;
|
||||||
|
ptr += 24;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final int vertexCount;
|
||||||
|
private final VertexView vertexView;
|
||||||
|
private final MemoryBlock data;
|
||||||
|
private final Vector4f boundingSphere;
|
||||||
|
|
||||||
|
public LineMesh(int vertexCount, VertexView vertexView, MemoryBlock data, Vector4f boundingSphere) {
|
||||||
|
this.vertexCount = vertexCount;
|
||||||
|
this.vertexView = vertexView;
|
||||||
|
this.data = data;
|
||||||
|
this.boundingSphere = boundingSphere;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int vertexCount() {
|
||||||
|
return vertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(MutableVertexList vertexList) {
|
||||||
|
vertexView.writeAll(vertexList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IndexSequence indexSequence() {
|
||||||
|
return INDEX_SEQUENCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int indexCount() {
|
||||||
|
return vertexCount / 2 * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4fc boundingSphere() {
|
||||||
|
return boundingSphere;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
data.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,195 +0,0 @@
|
||||||
package com.jozufozu.flywheel.lib.visual.components;
|
|
||||||
|
|
||||||
import org.joml.Quaternionf;
|
|
||||||
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 com.jozufozu.flywheel.lib.visual.EntityComponent;
|
|
||||||
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
|
|
||||||
|
|
||||||
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 implements EntityComponent {
|
|
||||||
private static final Material WIREFRAME = SimpleMaterial.builder()
|
|
||||||
.shaders(StandardMaterialShaders.WIREFRAME)
|
|
||||||
.backfaceCulling(false)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private static final Material CENTERLINE = SimpleMaterial.builder()
|
|
||||||
.shaders(StandardMaterialShaders.CENTERLINE)
|
|
||||||
.backfaceCulling(false)
|
|
||||||
.build();
|
|
||||||
private static final Model BOX = new SingleMeshModel(BoundingBoxMesh.INSTANCE, WIREFRAME);
|
|
||||||
|
|
||||||
// Should we try a single quad oriented to face the camera instead?
|
|
||||||
private static final Model LINE = new SingleMeshModel(BoundingBoxMesh.INSTANCE, CENTERLINE);
|
|
||||||
|
|
||||||
private final VisualizationContext context;
|
|
||||||
private final Entity entity;
|
|
||||||
|
|
||||||
private boolean showEyeBox;
|
|
||||||
|
|
||||||
private final SmartRecycler<Model, TransformedInstance> recycler;
|
|
||||||
|
|
||||||
public BoundingBoxComponent(VisualizationContext context, Entity entity) {
|
|
||||||
this.context = context;
|
|
||||||
this.entity = entity;
|
|
||||||
this.showEyeBox = entity instanceof LivingEntity;
|
|
||||||
|
|
||||||
this.recycler = new SmartRecycler<>(this::createInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransformedInstance createInstance(Model model) {
|
|
||||||
TransformedInstance instance = context.instancerProvider()
|
|
||||||
.instancer(InstanceTypes.TRANSFORMED, model)
|
|
||||||
.createInstance();
|
|
||||||
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
|
|
||||||
instance.setChanged();
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoundingBoxComponent showEyeBox(boolean renderEyeBox) {
|
|
||||||
this.showEyeBox = renderEyeBox;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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(BOX)
|
|
||||||
.loadIdentity()
|
|
||||||
.translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf)
|
|
||||||
.scale(bbWidth, bbHeight, bbWidth)
|
|
||||||
.setChanged();
|
|
||||||
|
|
||||||
// TODO: multipart entities, but forge seems to have an
|
|
||||||
// injection for them so we'll need platform specific code.
|
|
||||||
|
|
||||||
if (showEyeBox) {
|
|
||||||
recycler.get(BOX)
|
|
||||||
.loadIdentity()
|
|
||||||
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
|
|
||||||
.scale(bbWidth, 0.02f, bbWidth)
|
|
||||||
.setColor(255, 0, 0)
|
|
||||||
.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewVector = entity.getViewVector(context.partialTick());
|
|
||||||
|
|
||||||
recycler.get(LINE)
|
|
||||||
.loadIdentity()
|
|
||||||
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
|
|
||||||
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
|
|
||||||
.scale(0.02f, 2f, 0.02f)
|
|
||||||
.setColor(0, 0, 255)
|
|
||||||
.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
recycler.discardExtra();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,134 @@
|
||||||
|
package com.jozufozu.flywheel.lib.visual.components;
|
||||||
|
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.api.model.Model;
|
||||||
|
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.model.LineModelBuilder;
|
||||||
|
import com.jozufozu.flywheel.lib.model.ModelHolder;
|
||||||
|
import com.jozufozu.flywheel.lib.visual.EntityComponent;
|
||||||
|
import com.jozufozu.flywheel.lib.visual.SmartRecycler;
|
||||||
|
|
||||||
|
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 HitboxComponent implements EntityComponent {
|
||||||
|
// 010------110
|
||||||
|
// /| /|
|
||||||
|
// / | / |
|
||||||
|
// 011------111 |
|
||||||
|
// | | | |
|
||||||
|
// | 000----|-100
|
||||||
|
// | / | /
|
||||||
|
// |/ |/
|
||||||
|
// 001------101
|
||||||
|
private static final ModelHolder BOX = new ModelHolder(() -> LineModelBuilder.withCapacity(12)
|
||||||
|
// Starting from 0, 0, 0
|
||||||
|
.line(0, 0, 0, 0, 0, 1)
|
||||||
|
.line(0, 0, 0, 0, 1, 0)
|
||||||
|
.line(0, 0, 0, 1, 0, 0)
|
||||||
|
// Starting from 0, 1, 1
|
||||||
|
.line(0, 1, 1, 0, 1, 0)
|
||||||
|
.line(0, 1, 1, 0, 0, 1)
|
||||||
|
.line(0, 1, 1, 1, 1, 1)
|
||||||
|
// Starting from 1, 0, 1
|
||||||
|
.line(1, 0, 1, 1, 0, 0)
|
||||||
|
.line(1, 0, 1, 1, 1, 1)
|
||||||
|
.line(1, 0, 1, 0, 0, 1)
|
||||||
|
// Starting from 1, 1, 0
|
||||||
|
.line(1, 1, 0, 1, 1, 1)
|
||||||
|
.line(1, 1, 0, 1, 0, 0)
|
||||||
|
.line(1, 1, 0, 0, 1, 0)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
private static final ModelHolder LINE = new ModelHolder(() -> LineModelBuilder.withCapacity(1)
|
||||||
|
.line(0, 0, 0, 0, 2, 0)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
private final VisualizationContext context;
|
||||||
|
private final Entity entity;
|
||||||
|
|
||||||
|
private boolean showEyeBox;
|
||||||
|
|
||||||
|
private final SmartRecycler<Model, TransformedInstance> recycler;
|
||||||
|
|
||||||
|
public HitboxComponent(VisualizationContext context, Entity entity) {
|
||||||
|
this.context = context;
|
||||||
|
this.entity = entity;
|
||||||
|
this.showEyeBox = entity instanceof LivingEntity;
|
||||||
|
|
||||||
|
this.recycler = new SmartRecycler<>(this::createInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TransformedInstance createInstance(Model model) {
|
||||||
|
TransformedInstance instance = context.instancerProvider()
|
||||||
|
.instancer(InstanceTypes.TRANSFORMED, model)
|
||||||
|
.createInstance();
|
||||||
|
instance.setBlockLight(LightTexture.block(LightTexture.FULL_BLOCK));
|
||||||
|
instance.setChanged();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HitboxComponent showEyeBox(boolean renderEyeBox) {
|
||||||
|
this.showEyeBox = renderEyeBox;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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(BOX.get())
|
||||||
|
.loadIdentity()
|
||||||
|
.translate(entityX - bbWidthHalf, entityY, entityZ - bbWidthHalf)
|
||||||
|
.scale(bbWidth, bbHeight, bbWidth)
|
||||||
|
.setChanged();
|
||||||
|
|
||||||
|
// TODO: multipart entities, but forge seems to have an
|
||||||
|
// injection for them so we'll need platform specific code.
|
||||||
|
|
||||||
|
if (showEyeBox) {
|
||||||
|
recycler.get(BOX.get())
|
||||||
|
.loadIdentity()
|
||||||
|
.translate(entityX - bbWidthHalf, entityY + entity.getEyeHeight() - 0.01, entityZ - bbWidthHalf)
|
||||||
|
.scale(bbWidth, 0.02f, bbWidth)
|
||||||
|
.setColor(255, 0, 0)
|
||||||
|
.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
var viewVector = entity.getViewVector(context.partialTick());
|
||||||
|
|
||||||
|
recycler.get(LINE.get())
|
||||||
|
.loadIdentity()
|
||||||
|
.translate(entityX, entityY + entity.getEyeHeight(), entityZ)
|
||||||
|
.rotate(new Quaternionf().rotateTo(0, 1, 0, (float) viewVector.x, (float) viewVector.y, (float) viewVector.z))
|
||||||
|
.setColor(0, 0, 255)
|
||||||
|
.setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
recycler.discardExtra();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete() {
|
||||||
|
recycler.delete();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,8 +15,8 @@ import com.jozufozu.flywheel.lib.model.Models;
|
||||||
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
|
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
|
||||||
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
|
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
|
||||||
import com.jozufozu.flywheel.lib.visual.SimpleEntityVisual;
|
import com.jozufozu.flywheel.lib.visual.SimpleEntityVisual;
|
||||||
import com.jozufozu.flywheel.lib.visual.components.BoundingBoxComponent;
|
|
||||||
import com.jozufozu.flywheel.lib.visual.components.FireComponent;
|
import com.jozufozu.flywheel.lib.visual.components.FireComponent;
|
||||||
|
import com.jozufozu.flywheel.lib.visual.components.HitboxComponent;
|
||||||
import com.jozufozu.flywheel.lib.visual.components.ShadowComponent;
|
import com.jozufozu.flywheel.lib.visual.components.ShadowComponent;
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
|
@ -63,7 +63,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
public void init(float partialTick) {
|
public void init(float partialTick) {
|
||||||
addComponent(new ShadowComponent(visualizationContext, entity).radius(0.7f));
|
addComponent(new ShadowComponent(visualizationContext, entity).radius(0.7f));
|
||||||
addComponent(new FireComponent(visualizationContext, entity));
|
addComponent(new FireComponent(visualizationContext, entity));
|
||||||
addComponent(new BoundingBoxComponent(visualizationContext, entity));
|
addComponent(new HitboxComponent(visualizationContext, entity));
|
||||||
|
|
||||||
body = createBodyInstance();
|
body = createBodyInstance();
|
||||||
blockState = entity.getDisplayBlockState();
|
blockState = entity.getDisplayBlockState();
|
||||||
|
@ -210,6 +210,7 @@ public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void _delete() {
|
protected void _delete() {
|
||||||
|
super._delete();
|
||||||
body.delete();
|
body.delete();
|
||||||
if (contents != null) {
|
if (contents != null) {
|
||||||
contents.delete();
|
contents.delete();
|
||||||
|
|
|
@ -9,6 +9,7 @@ void _flw_main(in FlwInstance instance) {
|
||||||
|
|
||||||
flw_vertexNormal = normalize(flw_vertexNormal);
|
flw_vertexNormal = normalize(flw_vertexNormal);
|
||||||
|
|
||||||
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos.xyz, flw_fogShape);
|
flw_distance = fogDistance(flw_vertexPos.xyz, flw_cameraPos, flw_fogShape);
|
||||||
|
|
||||||
gl_Position = flw_viewProjection * flw_vertexPos;
|
gl_Position = flw_viewProjection * flw_vertexPos;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,12 @@ struct FrustumPlanes {
|
||||||
|
|
||||||
layout(std140) uniform _FlwFrameUniforms {
|
layout(std140) uniform _FlwFrameUniforms {
|
||||||
FrustumPlanes flw_frustumPlanes;
|
FrustumPlanes flw_frustumPlanes;
|
||||||
|
|
||||||
mat4 flw_viewProjection;
|
mat4 flw_viewProjection;
|
||||||
vec4 flw_cameraPos;
|
mat4 flw_viewProjectionInverse;
|
||||||
vec4 flw_cameraLook;
|
|
||||||
|
vec4 _flw_cameraPos;
|
||||||
|
vec4 _flw_cameraLook;
|
||||||
vec2 flw_cameraRot;
|
vec2 flw_cameraRot;
|
||||||
|
|
||||||
vec2 flw_viewportSize;
|
vec2 flw_viewportSize;
|
||||||
|
@ -27,3 +30,6 @@ layout(std140) uniform _FlwFrameUniforms {
|
||||||
float flw_renderTicks;
|
float flw_renderTicks;
|
||||||
float flw_renderSeconds;
|
float flw_renderSeconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define flw_cameraPos _flw_cameraPos.xyz
|
||||||
|
#define flw_cameraLook _flw_cameraLook.xyz
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
void flw_materialFragment() {
|
|
||||||
float toCenter = abs(flw_vertexTexCoord.s - 0.5);
|
|
||||||
|
|
||||||
// multiply by fwidth to get the width of the edge in screen space
|
|
||||||
if (flw_defaultLineWidth * fwidth(toCenter) < toCenter) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
flw_fragColor = flw_vertexColor;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
void flw_materialVertex() {
|
|
||||||
}
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
void flw_materialFragment() {
|
||||||
|
flw_fragColor = flw_vertexColor;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
void flw_materialVertex() {
|
||||||
|
vec4 linePosStart = flw_viewProjection * flw_vertexPos;
|
||||||
|
vec4 linePosEnd = flw_viewProjection * (flw_vertexPos + vec4(flw_vertexNormal, 0.));
|
||||||
|
|
||||||
|
vec3 ndc1 = linePosStart.xyz / linePosStart.w;
|
||||||
|
vec3 ndc2 = linePosEnd.xyz / linePosEnd.w;
|
||||||
|
|
||||||
|
vec2 lineScreenDirection = normalize((ndc2.xy - ndc1.xy) * flw_viewportSize);
|
||||||
|
vec2 lineOffset = vec2(-lineScreenDirection.y, lineScreenDirection.x) * flw_defaultLineWidth / flw_viewportSize;
|
||||||
|
|
||||||
|
if (lineOffset.x < 0.0) {
|
||||||
|
lineOffset *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gl_VertexID % 2 == 0) {
|
||||||
|
flw_vertexPos = flw_viewProjectionInverse * vec4((ndc1 + vec3(lineOffset, 0.)) * linePosStart.w, linePosStart.w);
|
||||||
|
} else {
|
||||||
|
flw_vertexPos = flw_viewProjectionInverse * vec4((ndc1 - vec3(lineOffset, 0.)) * linePosStart.w, linePosStart.w);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue