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 fc0f7f5f..87db9dbf 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/RenderLib.kt @@ -45,6 +45,7 @@ import kotlin.math.sin val NOISE: PerlinNoise = PerlinNoise.create(XoroshiroRandomSource(9001L), listOf(0, 1, 2, 3, 4)) val CAP_THETA: Float = 18f +val READABILITY_OFFSET: Float = 0.2f /** * Draw a sequence of linePoints spanning the given points. @@ -199,13 +200,14 @@ fun rotate(vec: Vec2, theta: Float): Vec2 { fun drawPatternFromPoints( mat: Matrix4f, points: List, + dupIndices: Set?, drawLast: Boolean, tail: Int, head: Int, flowIrregular: Float, animTime: Float? = null ) { - val zappyPts = makeZappy(points, 10f, 2.5f, 0.1f, flowIrregular) + val zappyPts = makeZappy(points, dupIndices, 10f, 2.5f, 0.1f, flowIrregular) val nodes = if (drawLast) { points } else { @@ -226,58 +228,99 @@ fun drawPatternFromPoints( } } -fun makeZappy(points: List, hops: Float, variance: Float, speed: Float, flowIrregular: Float) = - makeZappy(points, hops.toInt(), variance, speed, flowIrregular) +fun makeZappy(points: List, dupIndices: Set?, hops: Float, variance: Float, speed: Float, flowIrregular: Float) = + makeZappy(points, dupIndices, hops.toInt(), variance, speed, flowIrregular) /** * 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(points: List, hops: Int, variance: Float, speed: Float, flowIrregular: Float): List { +fun makeZappy(barePoints: List, dupIndices: Set?, hops: Int, variance: Float, speed: Float, flowIrregular: Float): List { // Nothing in, nothing out - if (points.isEmpty()) { + if (barePoints.isEmpty()) { return emptyList() } - 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]) - // For each segment in the original... - for ((i, pair) in points.zipWithNext().withIndex()) { - val (src, target) = pair - val delta = target.add(src.negated()) - // Take hop distance - val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops - // Compute how big the radius of variance should be - val maxVariance = hopDist * variance + fun zappify(points: List): 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]) + // For each segment in the original... + for ((i, pair) in points.zipWithNext().withIndex()) { + val (src, target) = pair + val delta = target.add(src.negated()) + // Take hop distance + val hopDist = Mth.sqrt(src.distanceToSqr(target)) / hops + // Compute how big the radius of variance should be + val maxVariance = hopDist * variance - for (j in 1..hops) { - val progress = j.toDouble() / (hops + 1) - // Add the next hop... - val pos = src.add(delta.scale(progress.toFloat())) - // 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, - 1337.0, - 0.0 - ) * TAU).toFloat() - val r = (NOISE.getValue( - 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. - zappyPts.add(pos.add(randomHop)) + for (j in 1..hops) { + val progress = j.toDouble() / (hops + 1) + // Add the next hop... + val pos = src.add(delta.scale(progress.toFloat())) + // 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, + 1337.0, + 0.0 + ) * TAU).toFloat() + val r = (NOISE.getValue( + 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. + zappyPts.add(pos.add(randomHop)) + } + // Finally, we hit the destination, add that too + zappyPts.add(target) } - // Finally, we hit the destination, add that too - zappyPts.add(target) + return zappyPts } - return zappyPts + val points = mutableListOf() + val daisyChain = mutableListOf() + return if (dupIndices != null) { + for ((i, pair) in barePoints.zipWithNext().withIndex()) { + val (head, tail) = pair + val tangent = tail.add(head.negated()).scale(READABILITY_OFFSET) + if (i != 0 && dupIndices.contains(i)) { + daisyChain.add(head.add(tangent)) + } else { + daisyChain.add(head) + } + if (i == barePoints.size - 2) { + daisyChain.add(tail) + points.addAll(zappify(daisyChain)) + } else if (dupIndices.contains(i + 1)) { + daisyChain.add(tail.add(tangent.negated())) + points.addAll(zappify(daisyChain)) + daisyChain.clear() + } + } + points + } else { + zappify(barePoints) + } +} + +fun findDupIndices(pts: Iterable): Set { + val dedup = HashMap() + val found = HashSet() + for ((i, pt) in pts.withIndex()) { + val ix = dedup[pt] + if (ix != null) { + found.add(i) + found.add(ix) + } else { + dedup.put(pt, i) + } + } + return found } /** 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 ef14b663..45d53851 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 @@ -73,7 +73,7 @@ public class BlockEntityAkashicBookshelfRenderer implements BlockEntityRenderer< lines2.set(j, new Vec2(-v.x, v.y)); } - var zappy = RenderLib.makeZappy(lines2, 10f, 0.5f, 0f, 0f); + var zappy = RenderLib.makeZappy(lines2, RenderLib.findDupIndices(pattern.positions()), 10f, 0.5f, 0f, 0f); 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 6667a0ae..f255d9df 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,7 +84,7 @@ public class BlockEntitySlateRenderer implements BlockEntityRenderer() + var dupIndices: Set? = null if (this.drawState is PatternDrawState.JustStarted) { val ds = this.drawState as PatternDrawState.JustStarted points.add(this.coordToPx(ds.start)) } else if (this.drawState is PatternDrawState.Drawing) { val ds = this.drawState as PatternDrawState.Drawing + dupIndices = findDupIndices(ds.wipPattern.positions()) for (pos in ds.wipPattern.positions()) { val pix = this.coordToPx(pos + ds.start) points.add(pix) @@ -370,7 +374,7 @@ class GuiSpellcasting constructor( } points.add(mousePos) - drawPatternFromPoints(mat, points, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.1f) + drawPatternFromPoints(mat, points, dupIndices, false, 0xff_64c8ff_u.toInt(), 0xff_fecbe6_u.toInt(), 0.1f) } 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 1cdb2c0c..0b0a5135 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 @@ -45,7 +45,7 @@ public class PatternTooltipComponent implements ClientTooltipComponent { var pair = RenderLib.getCenteredPattern(pattern, SIZE, SIZE, 8f); this.scale = pair.getFirst(); var dots = pair.getSecond(); - this.zappyPoints = RenderLib.makeZappy(dots, 10f, 0.8f, 0f, 0f); + this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10f, 0.8f, 0f, 0f); this.pathfinderDots = dots.stream().distinct().collect(Collectors.toList()); } 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 17ac032a..4091ad91 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 @@ -71,7 +71,7 @@ public class EntityWallScroll extends HangingEntity { var pair = RenderLib.getCenteredPattern(pattern, 128f / 3 * blockSize, 128f / 3 * blockSize, 16f / 3 * blockSize); var dots = pair.getSecond(); - this.zappyPoints = RenderLib.makeZappy(dots, 10f, 0.8f, 0f, 0f); + this.zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10f, 0.8f, 0f, 0f); } this.isAncient = NBTHelper.hasString(scroll, ItemScroll.TAG_OP_ID); 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 033fbf0d..a47f0944 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 @@ -108,7 +108,7 @@ public final class PatternDrawingUtil { for (var pat : patternEntries) { var localOrigin = HexUtils.coordToPx(pat.origin(), hexSize, realCom.negated()); var points = pat.pattern().toLines(hexSize, localOrigin); - pat.zappyPoints().addAll(RenderLib.makeZappy(points, 10f, 0.8f, 0f, 0f)); + pat.zappyPoints().addAll(RenderLib.makeZappy(points, RenderLib.findDupIndices(pat.pattern().positions()), 10f, 0.8f, 0f, 0f)); } var pathfinderDots = seenCoords.stream()