Bend limbs along a single axis with a Bézier spine

- core: Bezier (any degree, De Casteljau), LimbBend (cubic spine through
  the rigid upper/joint/lower shape, one ring per texture row spaced by
  arc length, rigid rings so pieces share vertices) and QuadSplitter
  (cuts faces at the rings, interpolating UVs).
- fabric: ModelPartMixin draws parts that have a bend with
  BentCubeRenderer, which deforms vanilla's own cubes. Overlays and armor
  use the limb's spine so they stay attached. Bends are reset every
  setupAnim because models are shared between entities.
- testmod: flap and squat animations, and a client gametest that
  screenshots each animation from the front and side
  (runClientGameTest). The tester runs with the full Fabric API because
  single modules don't bring their version-specific dependencies.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 19:43:57 +02:00
co-authored by claude
parent d5af8d65c2
commit 8bac5eef64
18 changed files with 881 additions and 23 deletions
+21 -7
View File
@@ -33,6 +33,13 @@ loom {
options.put("mark-corresponding-synthetics", "1") // Names lambdas, useful for mixins
}
runConfigs.all {
preferGradleTask = true
generateRunConfig = true
runDirectory = rootProject.file("run") // Shared by every version
jvmArguments.add("-Dmixin.debug.export=true")
}
runs {
// ./gradlew :<mc>:runTestmodClient launches the game with the tester mod loaded.
register("testmodClient") {
@@ -40,13 +47,15 @@ loom {
name = "Testmod Client"
source(testmod)
}
}
runConfigs.all {
preferGradleTask = true
generateRunConfig = true
runDirectory = rootProject.file("run") // Shared by every version
jvmArguments.add("-Dmixin.debug.export=true")
// ./gradlew :<mc>:runClientGameTest screenshots the test animations, then quits.
register("clientGameTest") {
client()
name = "Client Game Test"
source(testmod)
vmArg("-Dfabric.client.gametest")
runDir = "build/run/clientGameTest"
}
}
}
@@ -65,7 +74,12 @@ dependencies {
api(project(":core"))
include(project(":core"))
"modTestmodImplementation"(fabricApi.module("fabric-command-api-v2", sc.properties["deps.fabric_api"]))
for (module in listOf("fabric-command-api-v2", "fabric-client-gametest-api-v1")) {
"modTestmodImplementation"(fabricApi.module(module, sc.properties["deps.fabric_api"]))
}
// Single modules don't bring their Fabric API dependencies (which differ between versions),
// so the tester runs with all of Fabric API.
"modTestmodRuntimeOnly"("net.fabricmc.fabric-api:fabric-api:${sc.properties.get<String>("deps.fabric_api")}")
}
java {