From a43ead40d65b6464d59e0bc3ee1ffe370c02607f Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Mon, 21 Nov 2022 11:17:16 -0600 Subject: [PATCH] wall scrolls don't look like they were drawn with tank treads anymore --- .../at/petrak/hexcasting/client/RenderLib.kt | 16 +- .../client/entity/WallScrollRenderer.java | 151 ++++++++++++------ 2 files changed, 111 insertions(+), 56 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt index 9fbbcc53..4bf5ae67 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -46,7 +46,7 @@ fun getNoise(x: Double, y: Double, z: Double): Double = NOISE.getValue(x * 0.6, y * 0.6, z * 0.6) / 2.0 // how many degrees are between each triangle on the smooth caps of the lines -const val CAP_THETA = 180f / 5f +const val CAP_THETA = 180f / 10f const val DEFAULT_READABILITY_OFFSET = 0.2f const val DEFAULT_LAST_SEGMENT_LEN_PROP = 0.8f @@ -121,24 +121,24 @@ fun drawLineSeq( // Draw the line segment as a hexagon, sort of // I can't imagine what the hell alwinfy is up to but this is implementing what TRIANGLE_FAN does // using normal triangles so we can send the entire segment to the buffer at once - val p1Up = p1.add(tangent.scale(Math.max(0f, jlow))).add(normal) - val p1Down = p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated()) + val p1Down = p1.add(tangent.scale(Math.max(0f, jlow))).add(normal) + val p1Up = p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated()) val p2Down = p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal) val p2Up = p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated()) - vertex(color1, p1Up) + vertex(color1, p1Down) vertex(color1, p1) - vertex(color1, p1Down) - vertex(color1, p1Up) + vertex(color1, p1Down) + vertex(color1, p1Up) vertex(color2, p2Up) - vertex(color1, p1Up) + vertex(color1, p1Down) vertex(color2, p2Up) vertex(color2, p2) - vertex(color1, p1Up) + vertex(color1, p1Down) vertex(color2, p2) vertex(color2, p2Down) diff --git a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java index 0b94567f..98e0b4ff 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/entity/WallScrollRenderer.java @@ -1,5 +1,6 @@ package at.petrak.hexcasting.client.entity; +import at.petrak.hexcasting.client.RenderLib; import at.petrak.hexcasting.common.entities.EntityWallScroll; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; @@ -38,7 +39,7 @@ public class WallScrollRenderer extends EntityRenderer { // I do as the PaintingRenderer guides @Override public void render(EntityWallScroll wallScroll, float yaw, float partialTicks, PoseStack ps, - MultiBufferSource bufSource, int packedLight) { + MultiBufferSource bufSource, int packedLight) { RenderSystem.setShader(GameRenderer::getPositionTexShader); @@ -157,8 +158,8 @@ public class WallScrollRenderer extends EntityRenderer { } private static void vertex(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, float x, float y, - float z, float u, - float v, float nx, float ny, float nz) { + float z, float u, + float v, float nx, float ny, float nz) { verts.vertex(mat, x, y, z) .color(0xffffffff) .uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) @@ -166,82 +167,136 @@ public class WallScrollRenderer extends EntityRenderer { .endVertex(); } - private static void vertexCol(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, int col, float x, - float y) { - verts.vertex(mat, -x, y, 0) + private static void vertexCol(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, int col, Vec2 pos) { + verts.vertex(mat, -pos.x, pos.y, 0) .color(col) .uv(0, 0).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(light) .normal(normal, 0, 0, 1) .endVertex(); } - private static void theCoolerDrawLineSeq(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, - List points, float width, int color + private static void theCoolerDrawLineSeq(Matrix4f mat, Matrix3f normalMat, int light, VertexConsumer verts, + List points, float width, int color ) { if (points.size() <= 1) { return; } - float prevXHi, prevYHi, prevXLo, prevYLo; - { - var p1 = points.get(0); - var p2 = points.get(1); - - var dx = p2.x - p1.x; - var dy = p2.y - p1.y; - var nx = -dy; - var ny = dx; - var tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f); - var tx = nx / tlen; - var ty = ny / tlen; - - prevXHi = p1.x - tx; - prevYHi = p1.y - ty; - prevXLo = p1.x + tx; - prevYLo = p1.y + ty; + // TODO: abstract some of this out with RenderLib to stop WET code + var joinAngles = new float[points.size()]; + var joinOffsets = new float[points.size()]; + for (int i = 2; i < points.size(); i++) { + var p0 = points.get(i - 2); + var p1 = points.get(i - 1); + var p2 = points.get(i); + var prev = p1.add(p0.negated()); + var next = p2.add(p1.negated()); + var angle = (float) Mth.atan2( + prev.x * next.y - prev.y * next.x, + prev.x * next.x + prev.y * next.y); + joinAngles[i - 1] = angle; + var clamp = Math.min(prev.length(), next.length()) / (width * 0.5f); + joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp); } for (var i = 0; i < points.size() - 1; i++) { var p1 = points.get(i); var p2 = points.get(i + 1); - var dx = p2.x - p1.x; - var dy = p2.y - p1.y; - var nx = -dy; - var ny = dx; - var tlen = Mth.sqrt(nx * nx + ny * ny) / (width * 0.5f); - var tx = nx / tlen; - var ty = ny / tlen; + var tangent = p2.add(p1.negated()).normalized().scale(width * 0.5f); + var normal = new Vec2(-tangent.y, tangent.x); - var xHi = p2.x - tx; - var yHi = p2.y - ty; - var xLo = p2.x + tx; - var yLo = p2.y + ty; - vertexCol(mat, normal, light, verts, color, prevXHi, prevYHi); - vertexCol(mat, normal, light, verts, color, prevXLo, prevYLo); - vertexCol(mat, normal, light, verts, color, xLo, yLo); - vertexCol(mat, normal, light, verts, color, xHi, yHi); + var jlow = joinOffsets[i]; + var jhigh = joinOffsets[i + 1]; - prevXHi = xHi; - prevYHi = yHi; - prevXLo = xLo; - prevYLo = yLo; + var p1Down = p1.add(tangent.scale(Math.max(0f, jlow))).add(normal); + var p1Up = p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated()); + var p2Down = p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal); + var p2Up = p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated()); + + // Draw the chamfer hexagon as two trapezoids + // the points are in different orders to keep clockwise + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, p2); + vertexCol(mat, normalMat, light, verts, color, p2Up); + vertexCol(mat, normalMat, light, verts, color, p1Up); + + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, p1Down); + vertexCol(mat, normalMat, light, verts, color, p2Down); + vertexCol(mat, normalMat, light, verts, color, p2); + + if (i > 0) { + var sangle = joinAngles[i]; + var angle = Math.abs(sangle); + var rnormal = normal.negated(); + var joinSteps = Mth.ceil(angle * 180 / (RenderLib.CAP_THETA * Mth.PI)); + if (joinSteps < 1) continue; + + if (sangle < 0) { + var prevVert = new Vec2(p1.x - rnormal.x, p1.y - rnormal.y); + for (var j = 1; j <= joinSteps; j++) { + var fan = RenderLib.rotate(rnormal, -sangle * ((float) j / joinSteps)); + var fanShift = new Vec2(p1.x - fan.x, p1.y - fan.y); + + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, fanShift); + vertexCol(mat, normalMat, light, verts, color, prevVert); + prevVert = fanShift; + } + } else { + var startFan = RenderLib.rotate(normal, -sangle); + var prevVert = new Vec2(p1.x - startFan.x, p1.y - startFan.y); + for (var j = joinSteps - 1; j >= 0; j--) { + var fan = RenderLib.rotate(normal, -sangle * ((float) j / joinSteps)); + var fanShift = new Vec2(p1.x - fan.x, p1.y - fan.y); + + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, p1); + vertexCol(mat, normalMat, light, verts, color, fanShift); + vertexCol(mat, normalMat, light, verts, color, prevVert); + prevVert = fanShift; + } + } + } + } + + for (var pair : new Vec2[][]{ + {points.get(0), points.get(1)}, + {points.get(points.size() - 1), points.get(points.size() - 2)} + }) { + var point = pair[0]; + var prev = pair[1]; + + var tangent = point.add(prev.negated()).normalized().scale(0.5f * width); + var normal = new Vec2(-tangent.y, tangent.x); + var joinSteps = Mth.ceil(180f / RenderLib.CAP_THETA); + for (int j = joinSteps; j > 0; j--) { + var fan0 = RenderLib.rotate(normal, -Mth.PI * ((float) j / joinSteps)); + var fan1 = RenderLib.rotate(normal, -Mth.PI * ((float) (j - 1) / joinSteps)); + + vertexCol(mat, normalMat, light, verts, color, point); + vertexCol(mat, normalMat, light, verts, color, point); + vertexCol(mat, normalMat, light, verts, color, point.add(fan1)); + vertexCol(mat, normalMat, light, verts, color, point.add(fan0)); + } } } private static void theCoolerDrawSpot(Matrix4f mat, Matrix3f normal, int light, VertexConsumer verts, - Vec2 point, float radius, int color) { + Vec2 point, float radius, int color) { var fracOfCircle = 6; for (int i = 0; i < fracOfCircle; i++) { // We do need rects, irritatingly // so we do fake triangles - vertexCol(mat, normal, light, verts, color, point.x, point.y); - vertexCol(mat, normal, light, verts, color, point.x, point.y); + vertexCol(mat, normal, light, verts, color, point); + vertexCol(mat, normal, light, verts, color, point); for (int j = 0; j <= 1; j++) { var theta = (i - j) / (float) fracOfCircle * Mth.TWO_PI; var rx = Mth.cos(theta) * radius + point.x; var ry = Mth.sin(theta) * radius + point.y; - vertexCol(mat, normal, light, verts, color, rx, ry); + vertexCol(mat, normal, light, verts, color, new Vec2(rx, ry)); } } }