From 5956ad38d5bc0a1e281dc30c99a25f00e500edf6 Mon Sep 17 00:00:00 2001 From: ChuijkYahus <94828194+ChuijkYahus@users.noreply.github.com> Date: Mon, 21 Nov 2022 00:42:56 +0800 Subject: [PATCH 01/13] Update zh_cn.json --- .../assets/hexcasting/lang/zh_cn.json | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json index d437e9d9..34f8a459 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json +++ b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json @@ -336,12 +336,17 @@ "hexcasting.spell.hexcasting:zone_entity/not_player": "区域之馏化:非玩家", "hexcasting.spell.hexcasting:zone_entity/not_living": "区域之馏化:非生物", - "hexcasting.spell.hexcasting:duplicate": "双子之分解", - "hexcasting.spell.hexcasting:duplicate_n": "双子之策略", - "hexcasting.spell.hexcasting:over": "狄俄斯库里之策略", - "hexcasting.spell.hexcasting:stack_len": "群体之精思", "hexcasting.spell.hexcasting:swap": "弄臣之策略", + "hexcasting.spell.hexcasting:rotate": "轮换之策略", + "hexcasting.spell.hexcasting:rotate_reverse": "轮换之策略,第二型", + "hexcasting.spell.hexcasting:duplicate": "双子之分解", + "hexcasting.spell.hexcasting:over": "勘探者之策略", + "hexcasting.spell.hexcasting:tuck": "送葬者之策略", + "hexcasting.spell.hexcasting:2dup": "狄俄斯库里之策略", + "hexcasting.spell.hexcasting:duplicate_n": "双子之策略", + "hexcasting.spell.hexcasting:stack_len": "群体之精思", "hexcasting.spell.hexcasting:fisherman": "渔夫之策略", + "hexcasting.spell.hexcasting:fisherman/copy": "渔夫之策略,第二型", "hexcasting.spell.hexcasting:swizzle": "骗徒之策略", "hexcasting.spell.hexcasting:and_bit": "交叉之馏化", @@ -897,10 +902,15 @@ "hexcasting.page.stackmanip.pseudo-novice": "移除栈顶的 iota。", "hexcasting.page.stackmanip.duplicate": "复制栈顶的 iota。", "hexcasting.page.stackmanip.swap": "交换栈顶两个 iota 的位置。", - "hexcasting.page.stackmanip.rotate": "将栈顶往下第三元素拉至栈顶。[0, 1, 2] 变为 [1, 2, 0]。", "hexcasting.page.stackmanip.over": "将栈顶往下第二元素复制至栈顶。[0, 1] 变为 [0, 1, 0]。", + "hexcasting.page.stackmanip.rotate": "将栈顶往下第三元素拉至栈顶。[0, 1, 2] 变为 [1, 2, 0]。", + "hexcasting.page.stackmanip.rotate_reverse": "将栈顶元素沉至栈顶往下第三位处。[0, 1, 2] 变为 [2, 0, 1]。", + "hexcasting.page.stackmanip.over": "将栈底往上第二元素复制至栈顶。[0, 1] 变为 [0, 1, 0]。", + "hexcasting.page.stackmanip.tuck": "将栈底元素复制至栈顶往下第二元素下方。[0, 1] 变为 [1, 0, 1]。", + "hexcasting.page.stackmanip.2dup": "复制栈顶的两个 iota。[0, 1] 变为 [0, 1, 0, 1]。", "hexcasting.page.stackmanip.duplicate_n": "移除栈顶的数,然后将现在的栈顶元素复制该数次。(若所给数为 2,则栈顶会有两个同一元素。)", "hexcasting.page.stackmanip.fisherman": "提出下标为所给数的元素并将其置于栈顶。", + "hexcasting.page.stackmanip.fisherman/copy": "与$(action)渔夫之策略/$类似,但会复制 iota 而非将其提出。", "hexcasting.page.stackmanip.stack_len": "以数的形式压入栈中元素的个数。(例如,一个形如 [0, 1] 的栈会变为 [0, 1, 2]。)", "hexcasting.page.stackmanip.last_n_list": "移除$(italic)所给数/$个元素,然后压入一个由其组成的列表。", "hexcasting.page.stackmanip.splat": "移除栈顶的列表,然后依次压入其元素。", From 52726ba522b3ef3800767c0ef73c27ab1ce22309 Mon Sep 17 00:00:00 2001 From: ChuijkYahus <94828194+ChuijkYahus@users.noreply.github.com> Date: Mon, 21 Nov 2022 00:53:06 +0800 Subject: [PATCH 02/13] fix --- Common/src/main/resources/assets/hexcasting/lang/zh_cn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json index 34f8a459..ddfb5598 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json +++ b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json @@ -905,7 +905,7 @@ "hexcasting.page.stackmanip.over": "将栈顶往下第二元素复制至栈顶。[0, 1] 变为 [0, 1, 0]。", "hexcasting.page.stackmanip.rotate": "将栈顶往下第三元素拉至栈顶。[0, 1, 2] 变为 [1, 2, 0]。", "hexcasting.page.stackmanip.rotate_reverse": "将栈顶元素沉至栈顶往下第三位处。[0, 1, 2] 变为 [2, 0, 1]。", - "hexcasting.page.stackmanip.over": "将栈底往上第二元素复制至栈顶。[0, 1] 变为 [0, 1, 0]。", + "hexcasting.page.stackmanip.over": "将栈顶往下第二元素复制至栈顶。[0, 1] 变为 [0, 1, 0]。", "hexcasting.page.stackmanip.tuck": "将栈底元素复制至栈顶往下第二元素下方。[0, 1] 变为 [1, 0, 1]。", "hexcasting.page.stackmanip.2dup": "复制栈顶的两个 iota。[0, 1] 变为 [0, 1, 0, 1]。", "hexcasting.page.stackmanip.duplicate_n": "移除栈顶的数,然后将现在的栈顶元素复制该数次。(若所给数为 2,则栈顶会有两个同一元素。)", From c2edcd68c14d447e63b3e45107953850d71dcc5b Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 15:54:20 -0600 Subject: [PATCH 03/13] probably fix #286 again --- .../java/at/petrak/hexcasting/forge/ForgeHexInitializer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java index 0d841aae..f5e8e567 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/ForgeHexInitializer.java @@ -111,7 +111,7 @@ public class ForgeHexInitializer { // https://github.com/VazkiiMods/Botania/blob/1.18.x/Forge/src/main/java/vazkii/botania/forge/ForgeCommonInitializer.java private static void bind(ResourceKey> registry, - Consumer> source) { + Consumer> source) { getModEventBus().addListener((RegisterEvent event) -> { if (registry.equals(event.getRegistryKey())) { source.accept((t, rl) -> event.register(registry, rl, () -> t)); @@ -123,7 +123,7 @@ public class ForgeHexInitializer { var modBus = getModEventBus(); var evBus = MinecraftForge.EVENT_BUS; - modBus.register(ForgeHexClientInitializer.class); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> modBus.register(ForgeHexClientInitializer.class)); modBus.addListener((FMLCommonSetupEvent evt) -> evt.enqueueWork(() -> { From 3d56f0f8263faabdb0d0a8b1bb5d1929af991bd9 Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 16:09:06 -0600 Subject: [PATCH 04/13] close #303 --- .../at/petrak/hexcasting/api/item/IotaHolderItem.java | 8 +++++++- .../java/at/petrak/hexcasting/common/items/ItemSlate.java | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java index 62f2aade..11e9bf70 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/item/IotaHolderItem.java @@ -86,12 +86,18 @@ public interface IotaHolderItem { return HexIotaTypes.getColor(tag); } + /** + * Write {@code null} to indicate erasing + */ boolean canWrite(ItemStack stack, @Nullable Iota iota); + /** + * Write {@code null} to indicate erasing + */ void writeDatum(ItemStack stack, @Nullable Iota iota); static void appendHoverText(IotaHolderItem self, ItemStack stack, List components, - TooltipFlag flag) { + TooltipFlag flag) { var datumTag = self.readIotaTag(stack); if (datumTag != null) { var cmp = HexIotaTypes.getDisplay(datumTag); diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemSlate.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemSlate.java index c6faf57b..8d97a5da 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemSlate.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemSlate.java @@ -86,7 +86,10 @@ public class ItemSlate extends BlockItem implements IotaHolderItem { @Override public boolean canWrite(ItemStack stack, Iota datum) { - return datum instanceof PatternIota && !NBTHelper.hasCompound(stack, BlockEntitySlate.TAG_PATTERN); + var isWritten = NBTHelper.hasCompound(stack, "BlockEntityTag") + && stack.getTag().getCompound("BlockEntityTag").contains(BlockEntitySlate.TAG_PATTERN); + return (datum instanceof PatternIota && !isWritten) + || (datum == null && isWritten); } @Override From 9376632128ef2242cea78242c5dfea4f3bdca3ed Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 16:12:09 -0600 Subject: [PATCH 05/13] close #299 --- Common/src/main/resources/assets/hexcasting/lang/en_us.json | 2 +- .../thehexbook/en_us/entries/patterns/readwrite.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.json b/Common/src/main/resources/assets/hexcasting/lang/en_us.json index b6fe4005..16a6f428 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.json @@ -270,7 +270,7 @@ "hexcasting.spell.book.hexcasting:const/vec/x": "Vector Rfln. +X/-X", "hexcasting.spell.book.hexcasting:const/vec/y": "Vector Rfln. +Y/-Y", "hexcasting.spell.book.hexcasting:const/vec/z": "Vector Rfln. +Z/-Z", - "hexcasting.spell.book.hexcasting:write/entity": "Chronicler's Prfn.", + "hexcasting.spell.book.hexcasting:read/entity": "Chronicler's Prfn.", "hexcasting.spell.book.hexcasting:number": "Numerical Reflection", "hexcasting.spell.book.hexcasting:mask": "Bookkeeper's Gambit", diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json index 77178bec..c661d10d 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json @@ -36,7 +36,7 @@ "type": "hexcasting:pattern", "op_id": "hexcasting:write/entity", "anchor": "hexcasting:write/entity", - "input": "any, entity", + "input": "entity, any", "output": "", "text": "hexcasting.page.readwrite.write/entity" }, From e535938368c97ebf8082f9c4d59b95c3110e63ae Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 16:14:36 -0600 Subject: [PATCH 06/13] nerd emoji (close #300) --- Common/src/main/resources/assets/hexcasting/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.json b/Common/src/main/resources/assets/hexcasting/lang/en_us.json index 16a6f428..17329d06 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.json @@ -340,7 +340,7 @@ "hexcasting.spell.hexcasting:rotate": "Rotation Gambit", "hexcasting.spell.hexcasting:rotate_reverse": "Rotation Gambit II", "hexcasting.spell.hexcasting:duplicate": "Gemini Decomposition", - "hexcasting.spell.hexcasting:over": "Prospecter's Gambit", + "hexcasting.spell.hexcasting:over": "Prospector's Gambit", "hexcasting.spell.hexcasting:tuck": "Undertaker's Gambit", "hexcasting.spell.hexcasting:2dup": "Dioscuri Gambit", "hexcasting.spell.hexcasting:duplicate_n": "Gemini Gambit", From 6cdb34efbb16ba5a0a95e2e96ecb4f2d47274017 Mon Sep 17 00:00:00 2001 From: ChuijkYahus <94828194+ChuijkYahus@users.noreply.github.com> Date: Mon, 21 Nov 2022 07:45:52 +0800 Subject: [PATCH 07/13] Update zh_cn.json --- Common/src/main/resources/assets/hexcasting/lang/zh_cn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json index ddfb5598..acbe7e1f 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json +++ b/Common/src/main/resources/assets/hexcasting/lang/zh_cn.json @@ -270,7 +270,7 @@ "hexcasting.spell.book.hexcasting:const/vec/x": "向量之精思,+X/-X型", "hexcasting.spell.book.hexcasting:const/vec/y": "向量之精思,+Y/-Y型", "hexcasting.spell.book.hexcasting:const/vec/z": "向量之精思,+Z/-Z型", - "hexcasting.spell.book.hexcasting:write/entity": "编年史家之策略", + "hexcasting.spell.book.hexcasting:read/entity": "编年史家之纯化", "hexcasting.spell.book.hexcasting:number": "数字之精思", "hexcasting.spell.book.hexcasting:mask": "簿记员之策略", From 220ac8bcab6612d8415f7a82c0073e2c51f87dcf Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 19:59:00 -0600 Subject: [PATCH 08/13] re #280, upload things to the GPU in bigger chunks --- .../at/petrak/hexcasting/client/RenderLib.kt | 184 ++++++++++-------- 1 file changed, 107 insertions(+), 77 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 eabeb1aa..7e188e58 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -51,12 +51,12 @@ val CAP_THETA: Float = 18f * Please make sure to enable the right asinine shaders; see [GuiSpellcasting] */ fun drawLineSeq( - mat: Matrix4f, - points: List, - width: Float, - z: Float, - tail: Int, - head: Int, + mat: Matrix4f, + points: List, + width: Float, + z: Float, + tail: Int, + head: Int, ) { if (points.size <= 1) return @@ -86,15 +86,16 @@ fun drawLineSeq( val prev = p1.add(p0.negated()) val next = p2.add(p1.negated()) val angle = - Mth.atan2((prev.x * next.y - prev.y * next.x).toDouble(), (prev.x * next.x + prev.y * next.y).toDouble()) - .toFloat() + Mth.atan2((prev.x * next.y - prev.y * next.x).toDouble(), (prev.x * next.x + prev.y * next.y).toDouble()) + .toFloat() joinAngles[i - 1] = angle val clamp = Math.min(prev.length(), next.length()) / (width * 0.5f); joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp) } fun vertex(color: BlockPos, pos: Vec2) = - buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() + buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() + buf.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR) for ((i, pair) in points.zipWithNext().withIndex()) { val (p1, p2) = pair // https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163 @@ -104,22 +105,38 @@ fun drawLineSeq( val normal = Vec2(-tangent.y, tangent.x) fun color(time: Float): BlockPos = - BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) + BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) val color1 = color(i.toFloat() / n) val color2 = color((i + 1f) / n) val jlow = joinOffsets[i] val jhigh = joinOffsets[i + 1] - buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR) - vertex(color1, p1.add(tangent.scale(Math.max(0f, jlow))).add(normal)) + // 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 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, p1) - vertex(color1, p1.add(tangent.scale(Math.max(0f, -jlow))).add(normal.negated())) - vertex(color2, p2.add(tangent.scale(Math.max(0f, -jhigh)).negated()).add(normal.negated())) + vertex(color1, p1Down) + + vertex(color1, p1Up) + vertex(color1, p1Down) + vertex(color2, p2Up) + + vertex(color1, p1Up) + vertex(color2, p2Up) vertex(color2, p2) - vertex(color2, p2.add(tangent.scale(Math.max(0f, jhigh)).negated()).add(normal)) - tess.end() + + vertex(color1, p1Up) + vertex(color2, p2) + vertex(color2, p2Down) if (i > 0) { + // Draw the connector to the next line segment val sangle = joinAngles[i] val angle = Math.abs(sangle) val rnormal = normal.negated() @@ -127,22 +144,35 @@ fun drawLineSeq( if (joinSteps < 1) { continue } - buf.begin(VertexFormat.Mode.TRIANGLE_FAN, DefaultVertexFormat.POSITION_COLOR) - buf.vertex(mat, p1.x, p1.y, z).color(color1.x, color1.y, color1.z, a).endVertex() + if (sangle < 0) { - for (j in 0..joinSteps) { + var prevVert = Vec2(p1.x - rnormal.x, p1.y - rnormal.y) + for (j in 1..joinSteps) { val fan = rotate(rnormal, -sangle * (j.toFloat() / joinSteps)) - buf.vertex(mat, p1.x - fan.x, p1.y - fan.y, z).color(color1.x, color1.y, color1.z, a).endVertex() + val fanShift = Vec2(p1.x - fan.x, p1.y - fan.y) + + vertex(color1, p1) + vertex(color1, prevVert) + vertex(color1, fanShift) + prevVert = fanShift } } else { - for (j in joinSteps downTo 0) { + val startFan = rotate(normal, -sangle) + var prevVert = Vec2(p1.x - startFan.x, p1.y - startFan.y) + for (j in joinSteps - 1 downTo 0) { val fan = rotate(normal, -sangle * (j.toFloat() / joinSteps)) - buf.vertex(mat, p1.x - fan.x, p1.y - fan.y, z).color(color1.x, color1.y, color1.z, a).endVertex() + val fanShift = Vec2(p1.x - fan.x, p1.y - fan.y) + + vertex(color1, p1) + vertex(color1, prevVert) + vertex(color1, fanShift) + prevVert = fanShift } } - tess.end() } } + tess.end() + fun drawCaps(color: BlockPos, point: Vec2, prev: Vec2) { val tangent = point.add(prev.negated()).normalized().scale(0.5f * width) val normal = Vec2(-tangent.y, tangent.x) @@ -166,17 +196,17 @@ fun rotate(vec: Vec2, theta: Float): Vec2 { } /** - * * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it, - * * you have to do the conversion yourself.) - * */ + * Draw a hex pattern from the given list of non-zappy points (as in, do the *style* of drawing it, + * you have to do the conversion yourself.) + */ fun drawPatternFromPoints( - mat: Matrix4f, - points: List, - dupIndices: Set?, - drawLast: Boolean, - tail: Int, - head: Int, - flowIrregular: Float, + mat: Matrix4f, + points: List, + dupIndices: Set?, + drawLast: Boolean, + tail: Int, + head: Int, + flowIrregular: Float, ) { val zappyPts = makeZappy(points, dupIndices, 10f, 2.5f, 0.1f, flowIrregular) val nodes = if (drawLast) { @@ -188,26 +218,26 @@ fun drawPatternFromPoints( drawLineSeq(mat, zappyPts, 2f, 1f, screenCol(tail), screenCol(head)) for (node in nodes) { drawSpot( - mat, - node, - 2f, - dodge(FastColor.ARGB32.red(head)) / 255f, - dodge(FastColor.ARGB32.green(head)) / 255f, - dodge(FastColor.ARGB32.blue(head)) / 255f, - FastColor.ARGB32.alpha(head) / 255f + mat, + node, + 2f, + dodge(FastColor.ARGB32.red(head)) / 255f, + dodge(FastColor.ARGB32.green(head)) / 255f, + dodge(FastColor.ARGB32.blue(head)) / 255f, + FastColor.ARGB32.alpha(head) / 255f ); } } fun makeZappy( - points: List, - dupIndices: Set?, - hops: Float, - variance: Float, - speed: Float, - flowIrregular: Float + points: List, + dupIndices: Set?, + hops: Float, + variance: Float, + speed: Float, + flowIrregular: Float ) = - makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular, 0.2f) + makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular, 0.2f) /** * Split up a sequence of linePoints with a lightning effect @@ -215,8 +245,8 @@ fun makeZappy( * @param speed: rate at which the lightning effect should move/shake/etc */ fun makeZappy( - barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, - readabilityOffset: Float + barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, + readabilityOffset: Float ): List { // Nothing in, nothing out if (barePoints.isEmpty()) { @@ -245,14 +275,14 @@ fun makeZappy( // and zSeed (i.e. time elapsed) to perturb the shape gradually over time) val minorPerturb = NOISE.getValue(i.toDouble(), j.toDouble(), sin(zSeed)) * flowIrregular val theta = (3 * NOISE.getValue( - i.toDouble() + j.toDouble() / (hops + 1) + minorPerturb - zSeed, - 1337.0, - 0.0 + i.toDouble() + j.toDouble() / (hops + 1) + minorPerturb - zSeed, + 1337.0, + 0.0 ) * TAU).toFloat() val r = (NOISE.getValue( - i.toDouble() + j.toDouble() / (hops + 1) - zSeed, - 69420.0, - 0.0 + i.toDouble() + j.toDouble() / (hops + 1) - zSeed, + 69420.0, + 0.0 ) * maxVariance * scaleVariance(progress)).toFloat() val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta)) // Then record the new location. @@ -333,10 +363,10 @@ fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: F fun screenCol(n: Int): Int { return FastColor.ARGB32.color( - FastColor.ARGB32.alpha(n), - screen(FastColor.ARGB32.red(n)), - screen(FastColor.ARGB32.green(n)), - screen(FastColor.ARGB32.blue(n)), + FastColor.ARGB32.alpha(n), + screen(FastColor.ARGB32.red(n)), + screen(FastColor.ARGB32.green(n)), + screen(FastColor.ARGB32.blue(n)), ) } @@ -363,7 +393,7 @@ fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize } } val scale = - min(minSize, min(width / 3f / maxDx, height / 3f / maxDy)) + min(minSize, min(width / 3f / maxDx, height / 3f / maxDy)) val com2: Vec2 = pattern.getCenter(scale) val lines2: List = pattern.toLines(scale, com2.negated()) return scale to lines2 @@ -388,9 +418,9 @@ private var villager: Villager? by weakMapped(Villager::level) fun prepareVillagerForRendering(ingredient: VillagerIngredient, level: Level): Villager { val minLevel: Int = ingredient.minLevel() val profession: VillagerProfession = Registry.VILLAGER_PROFESSION.getOptional(ingredient.profession()) - .orElse(VillagerProfession.NONE) + .orElse(VillagerProfession.NONE) val biome: VillagerType = Registry.VILLAGER_TYPE.getOptional(ingredient.biome()) - .orElse(VillagerType.PLAINS) + .orElse(VillagerType.PLAINS) val instantiatedVillager = villager ?: run { val newVillager = Villager(EntityType.VILLAGER, level) @@ -399,18 +429,18 @@ fun prepareVillagerForRendering(ingredient: VillagerIngredient, level: Level): V } instantiatedVillager.villagerData = instantiatedVillager.villagerData - .setProfession(profession) - .setType(biome) - .setLevel(minLevel) + .setProfession(profession) + .setType(biome) + .setLevel(minLevel) return instantiatedVillager } @JvmOverloads fun renderEntity( - ms: PoseStack, entity: Entity, world: Level, x: Float, y: Float, rotation: Float, - renderScale: Float, offset: Float, - bufferTransformer: (MultiBufferSource) -> MultiBufferSource = { it -> it } + ms: PoseStack, entity: Entity, world: Level, x: Float, y: Float, rotation: Float, + renderScale: Float, offset: Float, + bufferTransformer: (MultiBufferSource) -> MultiBufferSource = { it -> it } ) { entity.level = world ms.pushPose() @@ -432,23 +462,23 @@ fun renderEntity( * Make sure you have the `PositionColorShader` set */ fun renderQuad( - ps: PoseStack, x: Float, y: Float, w: Float, h: Float, color: Int + ps: PoseStack, x: Float, y: Float, w: Float, h: Float, color: Int ) { val mat = ps.last().pose() val tess = Tesselator.getInstance() val buf = tess.builder buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR) buf.vertex(mat, x, y, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x, y + h, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x + w, y + h, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x + w, y, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() tess.end() } From f4bc78755127dd3f027cee13335255c887149777 Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 20:15:33 -0600 Subject: [PATCH 09/13] re #280, use indexing instead of iterator abstraction --- .../main/java/at/petrak/hexcasting/client/RenderLib.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 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 7e188e58..14f966dd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -79,7 +79,7 @@ fun drawLineSeq( val n = points.size val joinAngles = FloatArray(n) val joinOffsets = FloatArray(n) - for (i in 2..n - 1) { + for (i in 2 until n) { val p0 = points[i - 2]; val p1 = points[i - 1]; val p2 = points[i]; @@ -95,9 +95,11 @@ fun drawLineSeq( fun vertex(color: BlockPos, pos: Vec2) = buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() + buf.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR) - for ((i, pair) in points.zipWithNext().withIndex()) { - val (p1, p2) = pair + for (i in 0 until points.size - 1) { + val p1 = points[i] + val p2 = points[i + 1] // https://github.com/not-fl3/macroquad/blob/master/src/shapes.rs#L163 // GuiComponent::innerFill line 52 // fedor have useful variable names challenge (99% can't beat) From 2878dcb0c18bf5e0cd6b1f280fe4706efe2e51c5 Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 21:07:33 -0600 Subject: [PATCH 10/13] close #280 and reduce conformity --- Common/logs/latest.log | 0 .../at/petrak/hexcasting/client/RenderLib.kt | 40 ++++++++++--------- .../BlockEntityAkashicBookshelfRenderer.java | 5 ++- .../client/be/BlockEntitySlateRenderer.java | 5 ++- .../hexcasting/client/gui/GuiSpellcasting.kt | 10 +++-- .../client/gui/PatternTooltipComponent.java | 8 ++-- .../interop/utils/PatternDrawingUtil.java | 7 ++-- ...WhatRangeDoTheNoisesOutputAnywaysTest.java | 39 ++++++++++++++++++ 8 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 Common/logs/latest.log create mode 100644 Common/src/test/java/WhatRangeDoTheNoisesOutputAnywaysTest.java diff --git a/Common/logs/latest.log b/Common/logs/latest.log new file mode 100644 index 00000000..e69de29b 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 14f966dd..ad13727b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -31,19 +31,21 @@ import net.minecraft.world.entity.npc.VillagerProfession import net.minecraft.world.entity.npc.VillagerType import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level -import net.minecraft.world.level.levelgen.XoroshiroRandomSource -import net.minecraft.world.level.levelgen.synth.PerlinNoise +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource +import net.minecraft.world.level.levelgen.synth.SimplexNoise import net.minecraft.world.phys.Vec2 import kotlin.math.abs import kotlin.math.min import kotlin.math.sin -/** - * Source of perlin noise - */ -val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4)) +val NOISE: SimplexNoise = SimplexNoise(SingleThreadedRandomSource(9001L)) -val CAP_THETA: Float = 18f +// see the test; perlin noise seems to output almost exclusively between -0.5 and 0.5 +// i could probably impl this "properly" with some kind of exponent but it's faster and easier to divide +fun getNoise(x: Double, y: Double, z: Double): Double = + NOISE.getValue(x * 0.6, y * 0.6, z * 0.6) / 2.0 + +const val CAP_THETA: Float = 18f /** * Draw a sequence of linePoints spanning the given points. @@ -209,8 +211,9 @@ fun drawPatternFromPoints( tail: Int, head: Int, flowIrregular: Float, + seed: Double ) { - val zappyPts = makeZappy(points, dupIndices, 10f, 2.5f, 0.1f, flowIrregular) + val zappyPts = makeZappy(points, dupIndices, 10f, 2.5f, 0.1f, flowIrregular, seed) val nodes = if (drawLast) { points } else { @@ -237,9 +240,10 @@ fun makeZappy( hops: Float, variance: Float, speed: Float, - flowIrregular: Float + flowIrregular: Float, + seed: Double, ) = - makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular, 0.2f) + makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular, 0.2f, seed) /** * Split up a sequence of linePoints with a lightning effect @@ -248,7 +252,7 @@ fun makeZappy( */ fun makeZappy( barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, - readabilityOffset: Float + readabilityOffset: Float, seed: Double ): List { // Nothing in, nothing out if (barePoints.isEmpty()) { @@ -275,16 +279,16 @@ fun makeZappy( // as well as some random variance... // (We use i, j (segment #, subsegment #) as seeds for the Perlin noise, // and zSeed (i.e. time elapsed) to perturb the shape gradually over time) - val minorPerturb = NOISE.getValue(i.toDouble(), j.toDouble(), sin(zSeed)) * flowIrregular - val theta = (3 * NOISE.getValue( - i.toDouble() + j.toDouble() / (hops + 1) + minorPerturb - zSeed, + val minorPerturb = getNoise(i.toDouble(), j.toDouble(), sin(zSeed)) * flowIrregular + val theta = (3 * getNoise( + i + progress + minorPerturb - zSeed, 1337.0, - 0.0 + seed ) * TAU).toFloat() - val r = (NOISE.getValue( - i.toDouble() + j.toDouble() / (hops + 1) - zSeed, + val r = (getNoise( + i + progress - zSeed, 69420.0, - 0.0 + seed ) * maxVariance * scaleVariance(progress)).toFloat() val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta)) // Then record the new location. diff --git a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java index 45d53851..3bd51e6e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java @@ -22,7 +22,7 @@ public class BlockEntityAkashicBookshelfRenderer implements BlockEntityRenderer< @Override public void render(BlockEntityAkashicBookshelf tile, float pPartialTick, PoseStack ps, - MultiBufferSource buffer, int light, int overlay) { + MultiBufferSource buffer, int light, int overlay) { HexPattern pattern = tile.getPattern(); if (pattern == null) { return; @@ -73,7 +73,8 @@ public class BlockEntityAkashicBookshelfRenderer implements BlockEntityRenderer< lines2.set(j, new Vec2(-v.x, v.y)); } - var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10f, 0.5f, 0f, 0f); + var stupidHash = tile.getBlockPos().hashCode(); + var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10f, 0.5f, 0f, 0f, stupidHash); int outer = 0xff_d2c8c8; int inner = 0xc8_322b33; diff --git a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java index f255d9df..60df4c0d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java @@ -22,7 +22,7 @@ public class BlockEntitySlateRenderer implements BlockEntityRenderer { val (start, _, pat) = this.drawState as PatternDrawState.Drawing this.drawState = PatternDrawState.BetweenPatterns @@ -325,7 +326,8 @@ class GuiSpellcasting constructor( } RenderSystem.defaultBlendFunc() - for ((pat, origin, valid) in this.patterns) { + for ((idx, elts) in this.patterns.withIndex()) { + val (pat, origin, valid) = elts drawPatternFromPoints( mat, pat.toLines( @@ -336,7 +338,8 @@ class GuiSpellcasting constructor( true, valid.color or (0xC8 shl 24), valid.fadeColor or (0xC8 shl 24), - if (valid.success) 0.2f else 0.9f + if (valid.success) 0.2f else 0.9f, + idx.toDouble() ) } @@ -358,7 +361,8 @@ class GuiSpellcasting constructor( } points.add(mousePos) - drawPatternFromPoints(mat, points, dupIndices, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.1f) + // Use the size of the patterns as the seed so that way when this one is added the zappies don't jump + drawPatternFromPoints(mat, points, dupIndices, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.1f, this.patterns.size.toDouble()) } RenderSystem.enableDepthTest() diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java index 103dcf0e..23b4254f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/PatternTooltipComponent.java @@ -48,7 +48,7 @@ public class PatternTooltipComponent implements ClientTooltipComponent { var pair = RenderLib.getCenteredPattern(pattern, RENDER_SIZE, RENDER_SIZE, 8f); this.scale = pair.getFirst(); var dots = pair.getSecond(); - this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10f, 0.8f, 0f, 0f); + this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10f, 0.8f, 0f, 0f, 0.0); this.pathfinderDots = dots.stream().distinct().collect(Collectors.toList()); } @@ -79,7 +79,7 @@ public class PatternTooltipComponent implements ClientTooltipComponent { RenderSystem.setShader(GameRenderer::getPositionColorShader); RenderSystem.disableCull(); RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); ps.translate(width / 2f, height / 2f, 1); var mat = ps.last().pose(); @@ -87,9 +87,9 @@ public class PatternTooltipComponent implements ClientTooltipComponent { var innerLight = 0xc8_aba2a2; var innerDark = 0xc8_322b33; RenderLib.drawLineSeq(mat, this.zappyPoints, 5f, 0, - outer, outer); + outer, outer); RenderLib.drawLineSeq(mat, this.zappyPoints, 2f, 0, - innerDark, innerLight); + innerDark, innerLight); RenderLib.drawSpot(mat, this.zappyPoints.get(0), 2.5f, 1f, 0.1f, 0.15f, 0.6f); for (var dot : this.pathfinderDots) { diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java b/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java index ea0126ed..5f2c3266 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java @@ -19,7 +19,7 @@ import java.util.List; public final class PatternDrawingUtil { public static void drawPattern(PoseStack poseStack, int x, int y, List patterns, List dots, - boolean strokeOrder, long animTicks, int outer, int innerLight, int innerDark, int dotColor) { + boolean strokeOrder, long animTicks, int outer, int innerLight, int innerDark, int dotColor) { poseStack.pushPose(); poseStack.translate(x, y, 1); var mat = poseStack.last().pose(); @@ -103,12 +103,13 @@ public final class PatternDrawingUtil { var realCom = HexUtils.findCenter(seenRealPoints); // and NOW for real! - for (var pat : patternEntries) { + for (int i = 0; i < patternEntries.size(); i++) { + PatternEntry pat = patternEntries.get(i); var localOrigin = HexUtils.coordToPx(pat.origin(), hexSize, realCom.negated()); var points = pat.pattern().toLines(hexSize, localOrigin); pat.zappyPoints() .addAll(RenderLib.makeZappy(points, RenderLib.findDupIndices(pat.pattern().positions()), 10f, 0.8f, 0f, - 0f)); + 0f, i)); } var pathfinderDots = seenCoords.stream() diff --git a/Common/src/test/java/WhatRangeDoTheNoisesOutputAnywaysTest.java b/Common/src/test/java/WhatRangeDoTheNoisesOutputAnywaysTest.java new file mode 100644 index 00000000..827ca5c9 --- /dev/null +++ b/Common/src/test/java/WhatRangeDoTheNoisesOutputAnywaysTest.java @@ -0,0 +1,39 @@ +import net.minecraft.world.level.levelgen.SingleThreadedRandomSource; +import net.minecraft.world.level.levelgen.synth.PerlinNoise; +import net.minecraft.world.level.levelgen.synth.SimplexNoise; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class WhatRangeDoTheNoisesOutputAnywaysTest { + @Test + public void test() { + var perlin = PerlinNoise.create(new SingleThreadedRandomSource(12345), List.of(0, 1, 2, 3, 4)); + var simplex = new SimplexNoise(new SingleThreadedRandomSource(12345)); + + System.out.println("Perlin:"); + for (int i = 0; i < 20; i++) { + System.out.printf(" %f%n", perlin.getValue(i / 10.0, 69420.0, 1337.0)); + } + + System.out.println("Simplex:"); + for (int i = 0; i < 20; i++) { + System.out.printf(" %f%n", simplex.getValue(i / 10.0, 69420.0, 1337.0)); + } + } + + @Test + public void perlinBounds() { + var perlin = PerlinNoise.create(new SingleThreadedRandomSource(12345), List.of(0, 1, 2, 3, 4)); + var min = Double.POSITIVE_INFINITY; + var max = Double.NEGATIVE_INFINITY; + + for (int i = 0; i < 10000; i++) { + var it = perlin.getValue(i / 10.0, 12345.0, 7604.0); + min = Math.min(min, it); + max = Math.max(max, it); + } + + System.out.printf("Min: %f\nMax: %f\n", min, max); + } +} From ef176058ea1343982cf4abb826ea72f24bed582d Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 21:36:55 -0600 Subject: [PATCH 11/13] fix #309 --- .../at/petrak/hexcasting/api/PatternRegistry.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.java b/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.java index 8c817d52..28a6b33e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.java @@ -34,7 +34,7 @@ public class PatternRegistry { new ConcurrentHashMap<>(); public static void mapPattern(HexPattern pattern, ResourceLocation id, - Action action) throws RegisterPatternException { + Action action) throws RegisterPatternException { mapPattern(pattern, id, action, false); } @@ -42,7 +42,7 @@ public class PatternRegistry { * Associate a given angle signature with a SpellOperator. */ public static void mapPattern(HexPattern pattern, ResourceLocation id, Action action, - boolean isPerWorld) throws RegisterPatternException { + boolean isPerWorld) throws RegisterPatternException { if (actionLookup.containsKey(id)) { throw new RegisterPatternException("The operator with id `%s` was already registered to: %s", id, actionLookup.get(id)); @@ -83,7 +83,7 @@ public class PatternRegistry { * Internal use only. */ public static Pair matchPatternAndID(HexPattern pat, - ServerLevel overworld) throws MishapInvalidPattern { + ServerLevel overworld) throws MishapInvalidPattern { // Pipeline: // patterns are registered here every time the game boots // when we try to look @@ -232,13 +232,13 @@ public class PatternRegistry { /** * Maps angle sigs to resource locations and their preferred start dir so we can look them up in the main registry + * Save this on the world in case the random algorithm changes. */ public static class Save extends SavedData { private static final String TAG_OP_ID = "op_id"; private static final String TAG_START_DIR = "start_dir"; - // TODO: this is slightly weird that we save it *on* the world - // might it be better to recalculate it every time the world loads? + // Maps hex signatures to (op ids, canonical start dir) private Map> lookup; private boolean missingEntries; @@ -279,7 +279,7 @@ public class PatternRegistry { public CompoundTag save(CompoundTag tag) { this.lookup.forEach((sig, rhs) -> { var entry = new CompoundTag(); - entry.putString(TAG_OP_ID, sig.toString()); + entry.putString(TAG_OP_ID, rhs.getFirst().toString()); entry.putInt(TAG_START_DIR, rhs.getSecond().ordinal()); tag.put(sig, entry); }); From 9a276c70de87badebdaca78fd8d8334d3bdab1f7 Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Sun, 20 Nov 2022 22:38:35 -0600 Subject: [PATCH 12/13] clip the end of the pattern line in certain cases for visibility --- .../at/petrak/hexcasting/client/RenderLib.kt | 161 +++++++++--------- .../BlockEntityAkashicBookshelfRenderer.java | 3 +- .../client/be/BlockEntitySlateRenderer.java | 5 +- .../hexcasting/client/gui/GuiSpellcasting.kt | 13 +- .../client/gui/PatternTooltipComponent.java | 17 +- .../common/entities/EntityWallScroll.java | 10 +- .../patchouli/AbstractPatternComponent.java | 14 +- .../interop/utils/PatternDrawingUtil.java | 10 +- .../interop/emi/PatternRendererEMI.java | 5 +- .../forge/interop/jei/PatternDrawable.java | 7 +- 10 files changed, 140 insertions(+), 105 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 ad13727b..9fbbcc53 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -8,7 +8,6 @@ import at.petrak.hexcasting.api.utils.TAU import at.petrak.hexcasting.api.utils.getValue import at.petrak.hexcasting.api.utils.setValue import at.petrak.hexcasting.api.utils.weakMapped -import at.petrak.hexcasting.client.gui.GuiSpellcasting import at.petrak.hexcasting.common.recipe.ingredient.VillagerIngredient import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.DefaultVertexFormat @@ -36,6 +35,7 @@ import net.minecraft.world.level.levelgen.synth.SimplexNoise import net.minecraft.world.phys.Vec2 import kotlin.math.abs import kotlin.math.min +import kotlin.math.roundToInt import kotlin.math.sin val NOISE: SimplexNoise = SimplexNoise(SingleThreadedRandomSource(9001L)) @@ -43,9 +43,12 @@ val NOISE: SimplexNoise = SimplexNoise(SingleThreadedRandomSource(9001L)) // see the test; perlin noise seems to output almost exclusively between -0.5 and 0.5 // i could probably impl this "properly" with some kind of exponent but it's faster and easier to divide fun getNoise(x: Double, y: Double, z: Double): Double = - NOISE.getValue(x * 0.6, y * 0.6, z * 0.6) / 2.0 + NOISE.getValue(x * 0.6, y * 0.6, z * 0.6) / 2.0 -const val CAP_THETA: Float = 18f +// how many degrees are between each triangle on the smooth caps of the lines +const val CAP_THETA = 180f / 5f +const val DEFAULT_READABILITY_OFFSET = 0.2f +const val DEFAULT_LAST_SEGMENT_LEN_PROP = 0.8f /** * Draw a sequence of linePoints spanning the given points. @@ -53,12 +56,12 @@ const val CAP_THETA: Float = 18f * Please make sure to enable the right asinine shaders; see [GuiSpellcasting] */ fun drawLineSeq( - mat: Matrix4f, - points: List, - width: Float, - z: Float, - tail: Int, - head: Int, + mat: Matrix4f, + points: List, + width: Float, + z: Float, + tail: Int, + head: Int, ) { if (points.size <= 1) return @@ -88,15 +91,15 @@ fun drawLineSeq( val prev = p1.add(p0.negated()) val next = p2.add(p1.negated()) val angle = - Mth.atan2((prev.x * next.y - prev.y * next.x).toDouble(), (prev.x * next.x + prev.y * next.y).toDouble()) - .toFloat() + Mth.atan2((prev.x * next.y - prev.y * next.x).toDouble(), (prev.x * next.x + prev.y * next.y).toDouble()) + .toFloat() joinAngles[i - 1] = angle val clamp = Math.min(prev.length(), next.length()) / (width * 0.5f); joinOffsets[i - 1] = Mth.clamp(Mth.sin(angle) / (1 + Mth.cos(angle)), -clamp, clamp) } fun vertex(color: BlockPos, pos: Vec2) = - buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() + buf.vertex(mat, pos.x, pos.y, z).color(color.x, color.y, color.z, a).endVertex() buf.begin(VertexFormat.Mode.TRIANGLES, DefaultVertexFormat.POSITION_COLOR) for (i in 0 until points.size - 1) { @@ -109,7 +112,7 @@ fun drawLineSeq( val normal = Vec2(-tangent.y, tangent.x) fun color(time: Float): BlockPos = - BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) + BlockPos(Mth.lerp(time, r1, r2).toInt(), Mth.lerp(time, g1, g2).toInt(), Mth.lerp(time, b1, b2).toInt()) val color1 = color(i.toFloat() / n) val color2 = color((i + 1f) / n) @@ -204,16 +207,18 @@ fun rotate(vec: Vec2, theta: Float): Vec2 { * you have to do the conversion yourself.) */ fun drawPatternFromPoints( - mat: Matrix4f, - points: List, - dupIndices: Set?, - drawLast: Boolean, - tail: Int, - head: Int, - flowIrregular: Float, - seed: Double + mat: Matrix4f, + points: List, + dupIndices: Set?, + drawLast: Boolean, + tail: Int, + head: Int, + flowIrregular: Float, + readabilityOffset: Float, + lastSegmentLenProportion: Float, + seed: Double ) { - val zappyPts = makeZappy(points, dupIndices, 10f, 2.5f, 0.1f, flowIrregular, seed) + val zappyPts = makeZappy(points, dupIndices, 10, 2.5f, 0.1f, flowIrregular, readabilityOffset, lastSegmentLenProportion, seed) val nodes = if (drawLast) { points } else { @@ -223,46 +228,36 @@ fun drawPatternFromPoints( drawLineSeq(mat, zappyPts, 2f, 1f, screenCol(tail), screenCol(head)) for (node in nodes) { drawSpot( - mat, - node, - 2f, - dodge(FastColor.ARGB32.red(head)) / 255f, - dodge(FastColor.ARGB32.green(head)) / 255f, - dodge(FastColor.ARGB32.blue(head)) / 255f, - FastColor.ARGB32.alpha(head) / 255f + mat, + node, + 2f, + dodge(FastColor.ARGB32.red(head)) / 255f, + dodge(FastColor.ARGB32.green(head)) / 255f, + dodge(FastColor.ARGB32.blue(head)) / 255f, + FastColor.ARGB32.alpha(head) / 255f ); } } -fun makeZappy( - points: List, - dupIndices: Set?, - hops: Float, - variance: Float, - speed: Float, - flowIrregular: Float, - seed: Double, -) = - makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular, 0.2f, seed) - /** * Split up a sequence of linePoints with a lightning effect * @param hops: rough number of points to subdivide each segment into * @param speed: rate at which the lightning effect should move/shake/etc */ fun makeZappy( - barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, - readabilityOffset: Float, seed: Double + barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float, + readabilityOffset: Float, lastSegmentLenProportion: Float, seed: Double ): List { // Nothing in, nothing out if (barePoints.isEmpty()) { return emptyList() } - fun zappify(points: List): List { + fun zappify(points: List, truncateLast: Boolean): List { val scaleVariance = { it: Double -> 1.0.coerceAtMost(8 * (0.5 - abs(0.5 - it))) } val zSeed = ClientTickCounter.getTotal().toDouble() * speed // Create our output list of zap points - val zappyPts = mutableListOf(points[0]) + val zappyPts = ArrayList(points.size * hops) + zappyPts.add(points[0]) // For each segment in the original... for ((i, pair) in points.zipWithNext().withIndex()) { val (src, target) = pair @@ -272,7 +267,13 @@ fun makeZappy( // Compute how big the radius of variance should be val maxVariance = hopDist * variance - for (j in 1..hops) { + // for a list of length n, there will be n-1 pairs, + // and so the last index will be (n-1)-1 + val maxJ = if (truncateLast && i == points.size - 2) { + (lastSegmentLenProportion * hops.toFloat()).roundToInt() + } else hops + + for (j in 1..maxJ) { val progress = j.toDouble() / (hops + 1) // Add the next hop... val pos = src.add(delta.scale(progress.toFloat())) @@ -281,21 +282,25 @@ fun makeZappy( // and zSeed (i.e. time elapsed) to perturb the shape gradually over time) val minorPerturb = getNoise(i.toDouble(), j.toDouble(), sin(zSeed)) * flowIrregular val theta = (3 * getNoise( - i + progress + minorPerturb - zSeed, - 1337.0, - seed + i + progress + minorPerturb - zSeed, + 1337.0, + seed ) * TAU).toFloat() val r = (getNoise( - i + progress - zSeed, - 69420.0, - seed + i + progress - zSeed, + 69420.0, + seed ) * maxVariance * scaleVariance(progress)).toFloat() val randomHop = Vec2(r * Mth.cos(theta), r * Mth.sin(theta)) // Then record the new location. zappyPts.add(pos.add(randomHop)) + + if (j == hops) { + // Finally, we hit the destination, add that too + // but we might not hit the destination if we want to stop short + zappyPts.add(target) + } } - // Finally, we hit the destination, add that too - zappyPts.add(target) } return zappyPts } @@ -313,16 +318,16 @@ fun makeZappy( } if (i == barePoints.size - 2) { daisyChain.add(tail) - points.addAll(zappify(daisyChain)) + points.addAll(zappify(daisyChain, true)) } else if (dupIndices.contains(i + 1)) { daisyChain.add(tail.add(tangent.negated())) - points.addAll(zappify(daisyChain)) + points.addAll(zappify(daisyChain, false)) daisyChain.clear() } } points } else { - zappify(barePoints) + zappify(barePoints, true) } } @@ -369,10 +374,10 @@ fun drawSpot(mat: Matrix4f, point: Vec2, radius: Float, r: Float, g: Float, b: F fun screenCol(n: Int): Int { return FastColor.ARGB32.color( - FastColor.ARGB32.alpha(n), - screen(FastColor.ARGB32.red(n)), - screen(FastColor.ARGB32.green(n)), - screen(FastColor.ARGB32.blue(n)), + FastColor.ARGB32.alpha(n), + screen(FastColor.ARGB32.red(n)), + screen(FastColor.ARGB32.green(n)), + screen(FastColor.ARGB32.blue(n)), ) } @@ -399,7 +404,7 @@ fun getCenteredPattern(pattern: HexPattern, width: Float, height: Float, minSize } } val scale = - min(minSize, min(width / 3f / maxDx, height / 3f / maxDy)) + min(minSize, min(width / 3f / maxDx, height / 3f / maxDy)) val com2: Vec2 = pattern.getCenter(scale) val lines2: List = pattern.toLines(scale, com2.negated()) return scale to lines2 @@ -424,9 +429,9 @@ private var villager: Villager? by weakMapped(Villager::level) fun prepareVillagerForRendering(ingredient: VillagerIngredient, level: Level): Villager { val minLevel: Int = ingredient.minLevel() val profession: VillagerProfession = Registry.VILLAGER_PROFESSION.getOptional(ingredient.profession()) - .orElse(VillagerProfession.NONE) + .orElse(VillagerProfession.NONE) val biome: VillagerType = Registry.VILLAGER_TYPE.getOptional(ingredient.biome()) - .orElse(VillagerType.PLAINS) + .orElse(VillagerType.PLAINS) val instantiatedVillager = villager ?: run { val newVillager = Villager(EntityType.VILLAGER, level) @@ -435,18 +440,18 @@ fun prepareVillagerForRendering(ingredient: VillagerIngredient, level: Level): V } instantiatedVillager.villagerData = instantiatedVillager.villagerData - .setProfession(profession) - .setType(biome) - .setLevel(minLevel) + .setProfession(profession) + .setType(biome) + .setLevel(minLevel) return instantiatedVillager } @JvmOverloads fun renderEntity( - ms: PoseStack, entity: Entity, world: Level, x: Float, y: Float, rotation: Float, - renderScale: Float, offset: Float, - bufferTransformer: (MultiBufferSource) -> MultiBufferSource = { it -> it } + ms: PoseStack, entity: Entity, world: Level, x: Float, y: Float, rotation: Float, + renderScale: Float, offset: Float, + bufferTransformer: (MultiBufferSource) -> MultiBufferSource = { it -> it } ) { entity.level = world ms.pushPose() @@ -468,23 +473,23 @@ fun renderEntity( * Make sure you have the `PositionColorShader` set */ fun renderQuad( - ps: PoseStack, x: Float, y: Float, w: Float, h: Float, color: Int + ps: PoseStack, x: Float, y: Float, w: Float, h: Float, color: Int ) { val mat = ps.last().pose() val tess = Tesselator.getInstance() val buf = tess.builder buf.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR) buf.vertex(mat, x, y, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x, y + h, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x + w, y + h, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() buf.vertex(mat, x + w, y, 0f) - .color(color) - .endVertex() + .color(color) + .endVertex() tess.end() } diff --git a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java index 3bd51e6e..1f5c2fc9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntityAkashicBookshelfRenderer.java @@ -74,7 +74,8 @@ public class BlockEntityAkashicBookshelfRenderer implements BlockEntityRenderer< } var stupidHash = tile.getBlockPos().hashCode(); - var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10f, 0.5f, 0f, 0f, stupidHash); + var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10, 0.5f, 0f, 0f, 0f, + 1f, stupidHash); int outer = 0xff_d2c8c8; int inner = 0xc8_322b33; diff --git a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java index 60df4c0d..5713ed8d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java +++ b/Common/src/main/java/at/petrak/hexcasting/client/be/BlockEntitySlateRenderer.java @@ -84,8 +84,11 @@ public class BlockEntitySlateRenderer implements BlockEntityRenderer zappyPoints; @@ -45,10 +44,13 @@ public class PatternTooltipComponent implements ClientTooltipComponent { this.pattern = tt.pattern(); this.background = tt.background(); - var pair = RenderLib.getCenteredPattern(pattern, RENDER_SIZE, RENDER_SIZE, 8f); + var pair = RenderLib.getCenteredPattern(pattern, RENDER_SIZE, RENDER_SIZE, 16f); this.scale = pair.getFirst(); var dots = pair.getSecond(); - this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10f, 0.8f, 0f, 0f, 0.0); + this.zappyPoints = RenderLib.makeZappy( + dots, RenderLib.findDupIndices(pattern.positions()), + 10, 0.8f, 0f, 0f, RenderLib.DEFAULT_READABILITY_OFFSET, RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP, + 0.0); this.pathfinderDots = dots.stream().distinct().collect(Collectors.toList()); } @@ -86,9 +88,9 @@ public class PatternTooltipComponent implements ClientTooltipComponent { var outer = 0xff_d2c8c8; var innerLight = 0xc8_aba2a2; var innerDark = 0xc8_322b33; - RenderLib.drawLineSeq(mat, this.zappyPoints, 5f, 0, + RenderLib.drawLineSeq(mat, this.zappyPoints, 6f, 0, outer, outer); - RenderLib.drawLineSeq(mat, this.zappyPoints, 2f, 0, + RenderLib.drawLineSeq(mat, this.zappyPoints, 6f * 0.4f, 0, innerDark, innerLight); RenderLib.drawSpot(mat, this.zappyPoints.get(0), 2.5f, 1f, 0.1f, 0.15f, 0.6f); @@ -104,7 +106,8 @@ public class PatternTooltipComponent implements ClientTooltipComponent { RenderSystem.setShaderTexture(0, background); // x y blitoffset sw sh w h ... ? // parchment doesn't have this mapped - GuiComponent.blit(ps, 0, 0, blitOffset, 0f, 0f, (int) RENDER_SIZE, (int) RENDER_SIZE, (int) RENDER_SIZE, (int) RENDER_SIZE); + GuiComponent.blit(ps, 0, 0, blitOffset, 0f, 0f, (int) RENDER_SIZE, (int) RENDER_SIZE, (int) RENDER_SIZE, + (int) RENDER_SIZE); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java index 756147ec..f9b6ef14 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/entities/EntityWallScroll.java @@ -53,7 +53,7 @@ public class EntityWallScroll extends HangingEntity { } public EntityWallScroll(Level world, BlockPos pos, Direction dir, ItemStack scroll, boolean showStrokeOrder, - int blockSize) { + int blockSize) { super(HexEntities.WALL_SCROLL, world, pos); this.setDirection(dir); this.blockSize = blockSize; @@ -72,8 +72,10 @@ public class EntityWallScroll extends HangingEntity { var pair = RenderLib.getCenteredPattern(pattern, 128f / 3 * blockSize, 128f / 3 * blockSize, 16f / 3 * blockSize); var dots = pair.getSecond(); + var readOffset = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f; + var lastProp = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f; this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10, 0.4f, - 0f, 0f, this.getShowsStrokeOrder() ? 0.2f : 0f); + 0f, 0f, readOffset, lastProp, this.getId()); } this.isAncient = NBTHelper.hasString(scroll, ItemScroll.TAG_OP_ID); @@ -158,7 +160,7 @@ public class EntityWallScroll extends HangingEntity { } public void readSpawnData(BlockPos pos, Direction dir, ItemStack scrollItem, - boolean showsStrokeOrder, int blockSize) { + boolean showsStrokeOrder, int blockSize) { this.pos = pos; this.scroll = scrollItem; this.blockSize = blockSize; @@ -201,7 +203,7 @@ public class EntityWallScroll extends HangingEntity { @Override public void lerpTo(double pX, double pY, double pZ, float pYaw, float pPitch, int pPosRotationIncrements, - boolean pTeleport) { + boolean pTeleport) { BlockPos blockpos = this.pos.offset(pX - this.getX(), pY - this.getY(), pZ - this.getZ()); this.setPos(blockpos.getX(), blockpos.getY(), blockpos.getZ()); } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java index b27fb0a9..b8947478 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/AbstractPatternComponent.java @@ -2,6 +2,7 @@ package at.petrak.hexcasting.interop.patchouli; import at.petrak.hexcasting.api.spell.math.HexCoord; import at.petrak.hexcasting.api.spell.math.HexPattern; +import at.petrak.hexcasting.client.RenderLib; import at.petrak.hexcasting.interop.utils.PatternDrawingUtil; import at.petrak.hexcasting.interop.utils.PatternEntry; import com.mojang.blaze3d.vertex.PoseStack; @@ -22,7 +23,7 @@ abstract public class AbstractPatternComponent implements ICustomComponent { protected transient float hexSize; private transient List patterns; - private transient List pathfinderDots; + private transient List zappyPoints; /** * Pass -1, -1 to center it. @@ -39,17 +40,20 @@ abstract public class AbstractPatternComponent implements ICustomComponent { @Override public void render(PoseStack poseStack, IComponentRenderContext ctx, float partialTicks, int mouseX, int mouseY) { - PatternDrawingUtil.drawPattern(poseStack, this.x, this.y, this.patterns, this.pathfinderDots, - this.showStrokeOrder(), ctx.getTicksInBook(), + PatternDrawingUtil.drawPattern(poseStack, this.x, this.y, this.patterns, this.zappyPoints, + this.showStrokeOrder(), 0xff_d2c8c8, 0xc8_aba2a2, 0xc8_322b33, 0x80_d1cccc); } @Override public void onVariablesAvailable(UnaryOperator lookup) { - var data = PatternDrawingUtil.loadPatterns(this.getPatterns(lookup)); + var data = PatternDrawingUtil.loadPatterns( + this.getPatterns(lookup), + this.showStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f, + this.showStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f); this.hexSize = data.hexSize(); this.patterns = data.patterns(); - this.pathfinderDots = data.pathfinderDots(); + this.zappyPoints = data.pathfinderDots(); } protected static class RawPattern { diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java b/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java index 5f2c3266..e60c63a9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java +++ b/Common/src/main/java/at/petrak/hexcasting/interop/utils/PatternDrawingUtil.java @@ -19,7 +19,8 @@ import java.util.List; public final class PatternDrawingUtil { public static void drawPattern(PoseStack poseStack, int x, int y, List patterns, List dots, - boolean strokeOrder, long animTicks, int outer, int innerLight, int innerDark, int dotColor) { + boolean strokeOrder, int outer, int innerLight, int innerDark, + int dotColor) { poseStack.pushPose(); poseStack.translate(x, y, 1); var mat = poseStack.last().pose(); @@ -59,7 +60,8 @@ public final class PatternDrawingUtil { poseStack.popPose(); } - public static PatternRenderingData loadPatterns(List> patterns) { + public static PatternRenderingData loadPatterns(List> patterns, + float readabilityOffset, float lastLineLenProp) { var patternEntries = new ArrayList(patterns.size()); var fakeScale = 1; @@ -108,8 +110,8 @@ public final class PatternDrawingUtil { var localOrigin = HexUtils.coordToPx(pat.origin(), hexSize, realCom.negated()); var points = pat.pattern().toLines(hexSize, localOrigin); pat.zappyPoints() - .addAll(RenderLib.makeZappy(points, RenderLib.findDupIndices(pat.pattern().positions()), 10f, 0.8f, 0f, - 0f, i)); + .addAll(RenderLib.makeZappy(points, RenderLib.findDupIndices(pat.pattern().positions()), 10, 0.8f, 0f, + 0f, readabilityOffset, lastLineLenProp, i)); } var pathfinderDots = seenCoords.stream() diff --git a/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java b/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java index 71bb9489..4f38b39a 100644 --- a/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java +++ b/Fabric/src/main/java/at/petrak/hexcasting/fabric/interop/emi/PatternRendererEMI.java @@ -30,7 +30,8 @@ public class PatternRendererEMI implements EmiRenderable { public PatternRendererEMI(ResourceLocation pattern, int w, int h) { var entry = PatternRegistry.lookupPattern(pattern); this.strokeOrder = !entry.isPerWorld(); - var data = PatternDrawingUtil.loadPatterns(List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin()))); + var data = PatternDrawingUtil.loadPatterns(List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin())), 0f, + 1f); this.patterns = data.patterns(); this.pathfinderDots = data.pathfinderDots(); this.width = w; @@ -54,7 +55,7 @@ public class PatternRendererEMI implements EmiRenderable { poseStack.pushPose(); poseStack.translate(xOffset + x - 0.5f + width / 2f, yOffset + y + 1 + height / 2f, 0); poseStack.scale(width / 64f, height / 64f, 1f); - PatternDrawingUtil.drawPattern(poseStack, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, time, + PatternDrawingUtil.drawPattern(poseStack, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, 0xff_333030, 0xff_191818, 0xc8_0c0a0c, 0x80_666363); poseStack.popPose(); } diff --git a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java index 85a56d69..3acbde9c 100644 --- a/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java +++ b/Forge/src/main/java/at/petrak/hexcasting/forge/interop/jei/PatternDrawable.java @@ -26,7 +26,10 @@ public class PatternDrawable implements IDrawable { public PatternDrawable(ResourceLocation pattern, int w, int h) { var entry = PatternRegistry.lookupPattern(pattern); this.strokeOrder = !entry.isPerWorld(); - var data = PatternDrawingUtil.loadPatterns(List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin()))); + var data = PatternDrawingUtil.loadPatterns( + List.of(new Pair<>(entry.prototype(), HexCoord.getOrigin())), + 0f, + 1f); this.patterns = data.patterns(); this.pathfinderDots = data.pathfinderDots(); this.width = w; @@ -54,7 +57,7 @@ public class PatternDrawable implements IDrawable { poseStack.pushPose(); poseStack.translate(xOffset - 0.5f + width / 2f, yOffset + height / 2f, 0); poseStack.scale(width / 64f, height / 64f, 1f); - PatternDrawingUtil.drawPattern(poseStack, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, time, + PatternDrawingUtil.drawPattern(poseStack, 0, 0, this.patterns, this.pathfinderDots, this.strokeOrder, 0xff_333030, 0xff_191818, 0xc8_0c0a0c, 0x80_666363); poseStack.popPose(); } From a43ead40d65b6464d59e0bc3ee1ffe370c02607f Mon Sep 17 00:00:00 2001 From: "petrak@" Date: Mon, 21 Nov 2022 11:17:16 -0600 Subject: [PATCH 13/13] 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)); } } }