From 86f862db9ea108e5f49fd669d801a59dcc5d6f35 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 15:23:03 -0500 Subject: [PATCH 01/25] Parse bedrock model to java object --- gradleScripts/dependenciesCommon.gradle | 1 + .../renderer/model/bedrock/BedrockModel.java | 195 ++++++++++++++++++ .../engine/util/ArrayUtils.java | 27 +++ .../engine/util/ConfigUtils.java | 22 ++ 4 files changed, 245 insertions(+) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java diff --git a/gradleScripts/dependenciesCommon.gradle b/gradleScripts/dependenciesCommon.gradle index e724193..f6515e0 100644 --- a/gradleScripts/dependenciesCommon.gradle +++ b/gradleScripts/dependenciesCommon.gradle @@ -11,5 +11,6 @@ dependencies { api "org.fusesource.jansi:jansi:${jansiVersion}" api "org.joml:joml:${jomlVersion}" api "com.electronwill.night-config:toml:${nightConfigVersion}" + api "com.electronwill.night-config:json:${nightConfigVersion}" api "com.github.zafarkhaja:java-semver:${jsemverVersion}" } \ No newline at end of file diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java new file mode 100644 index 0000000..8128401 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java @@ -0,0 +1,195 @@ +package com.terminalvelocitycabbage.engine.client.renderer.model.bedrock; + +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.ConfigFormat; +import com.electronwill.nightconfig.core.io.ConfigParser; +import com.electronwill.nightconfig.json.JsonFormat; +import com.github.zafarkhaja.semver.Version; +import com.terminalvelocitycabbage.engine.debug.Log; +import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; +import com.terminalvelocitycabbage.engine.util.ConfigUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BedrockModel { + + Version formatVersion; + BedrockGeometryDescription geometryDescription; + BedrockBone[] bones; + + private BedrockModel(Version formatVersion, BedrockGeometryDescription geometryDescription, BedrockBone[] bones) { + this.formatVersion = formatVersion; + this.geometryDescription = geometryDescription; + this.bones = bones; + } + + public void print() { + Log.info(formatVersion.toString()); + Log.info(geometryDescription.toString()); + for (BedrockBone bone : bones) { + Log.info(bone.toString()); + } + } + + private static class BedrockCube { + + float[] origin; + int[] size; + int[] uv; + + public BedrockCube(float[] origin, int[] size, int[] uv) { + this.origin = origin; + this.size = size; + this.uv = uv; + } + + @Override + public String toString() { + return "BedrockCube{" + + "origin=" + Arrays.toString(origin) + + ", size=" + Arrays.toString(size) + + ", uv=" + Arrays.toString(uv) + + '}'; + } + } + + private static class BedrockBone { + + String name; + String parent; + float[] pivot; + float[] rotation; + BedrockCube[] cubes; + + public BedrockBone(String name, String parent, float[] pivot, float[] rotation, BedrockCube[] cubes) { + this.name = name; + this.parent = parent; + this.pivot = pivot; + this.rotation = rotation; + this.cubes = cubes; + } + + @Override + public String toString() { + return "BedrockBone{" + + "name='" + name + '\'' + + ", parent='" + parent + '\'' + + ", pivot=" + Arrays.toString(pivot) + + ", rotation=" + Arrays.toString(rotation) + + ", cubes=" + Arrays.toString(cubes) + + '}'; + } + } + + private static class BedrockGeometryDescription { + + String identifier; + int textureWidth; + int textureHeight; + float visibleBoundsWidth; + float visibleBoundsHeight; + float[] visibleBoundsOffset; + + public BedrockGeometryDescription(String identifier, int textureWidth, int textureHeight, float visibleBoundsWidth, float visibleBoundsHeight, float[] visibleBoundsOffset) { + this.identifier = identifier; + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + this.visibleBoundsWidth = visibleBoundsWidth; + this.visibleBoundsHeight = visibleBoundsHeight; + this.visibleBoundsOffset = visibleBoundsOffset; + } + + @Override + public String toString() { + return "BedrockGeometryDescription{" + + "identifier='" + identifier + '\'' + + ", textureWidth=" + textureWidth + + ", textureHeight=" + textureHeight + + ", visibleBoundsWidth=" + visibleBoundsWidth + + ", visibleBoundsHeight=" + visibleBoundsHeight + + ", visibleBoundsOffset=" + Arrays.toString(visibleBoundsOffset) + + '}'; + } + } + + public static class Loader { + + static Version formatVersion; + static BedrockGeometryDescription geometryDescription; + static BedrockBone[] bones; + + public static BedrockModel loadModel(Resource modelResource) { + + String resourceString = modelResource.asString(); + + ConfigFormat jsonFormat = JsonFormat.fancyInstance(); + ConfigParser parser = jsonFormat.createParser(); + Config config = parser.parse(resourceString); + + formatVersion = Version.parse(config.get("format_version")); + + List subConfig = config.get("minecraft:geometry"); + Config geometryConfig = subConfig.get(0); + + geometryDescription = parseGeometryDescription(geometryConfig); + bones = parseBones(geometryConfig); + + return new BedrockModel(formatVersion, geometryDescription, bones); + } + + private static BedrockBone[] parseBones(Config config) { + + List boneConfigs = config.get("bones"); + List bones = new ArrayList<>(); + + boneConfigs.forEach(bone -> bones.add(parseBone(bone))); + + return bones.toArray(new BedrockBone[0]); + } + + private static BedrockBone parseBone(Config config) { + + String name = config.get("name"); + String parent = config.getOrElse("parent", "none"); + float[] pivot = ConfigUtils.numberListToFloatArray(config.get("pivot")); + float[] rotation = ConfigUtils.numberListToFloatArray(config.get("rotation")); + + return new BedrockBone(name, parent, pivot, rotation, parseCubes(config)); + } + + private static BedrockCube[] parseCubes(Config config) { + + List cubes = config.get("cubes"); + List cubesList = new ArrayList<>(); + + cubes.forEach(cube -> cubesList.add(parseCube(cube))); + + return cubesList.toArray(new BedrockCube[0]); + } + + private static BedrockCube parseCube(Config cube) { + + float[] origin = ConfigUtils.numberListToFloatArray(cube.get("origin")); + int[] size = ConfigUtils.numberListToIntArray(cube.get("size")); + int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); + + return new BedrockCube(origin, size, uv); + } + + private static BedrockGeometryDescription parseGeometryDescription(Config config) { + + String identifier = config.get("description.identifier"); + int textureWidth = config.getInt("description.texture_width"); + int textureHeight = config.getInt("description.texture_height"); + float visibleBoundsWidth = ((Number) config.get("description.visible_bounds_width")).floatValue(); + float visibleBoundsHeight = ((Number) config.get("description.visible_bounds_height")).floatValue(); + float[] visibleBoundsOffset = ConfigUtils.numberListToFloatArray(config.get("description.visible_bounds_offset")); + + return new BedrockGeometryDescription(identifier, textureWidth, textureHeight, visibleBoundsWidth, visibleBoundsHeight, visibleBoundsOffset); + } + + } + +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/ArrayUtils.java b/src/main/java/com/terminalvelocitycabbage/engine/util/ArrayUtils.java index 92fa79e..9cd09de 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/ArrayUtils.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/ArrayUtils.java @@ -30,4 +30,31 @@ public static float[] combineFloatArrays(List arrays) { return compiledData; } + /** + * @param list the float list to be converted to an array + * @return an array made of the same values as the list + */ + public static float[] floatArrayFromClassList(List list) { + float[] compiledData = new float[list.size()]; + int currentPosition = 0; + for (Float element : list) { + compiledData[currentPosition] = element; + currentPosition++; + } + return compiledData; + } + + /** + * @param list the float list to be converted to an array + * @return an array made of the same values as the list + */ + public static int[] intArrayFromClassList(List list) { + int[] compiledData = new int[list.size()]; + int currentPosition = 0; + for (Integer element : list) { + compiledData[currentPosition] = element; + currentPosition++; + } + return compiledData; + } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java b/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java new file mode 100644 index 0000000..febbb1c --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java @@ -0,0 +1,22 @@ +package com.terminalvelocitycabbage.engine.util; + +import java.util.ArrayList; +import java.util.List; + +public class ConfigUtils { + + public static float[] numberListToFloatArray(List list) { + if (list == null) return new float[0]; + List convertedList = new ArrayList<>(); + list.forEach(n -> convertedList.add(n.floatValue())); + return ArrayUtils.floatArrayFromClassList(convertedList); + } + + public static int[] numberListToIntArray(List list) { + if (list == null) return new int[0]; + List convertedList = new ArrayList<>(); + list.forEach(n -> convertedList.add(n.intValue())); + return ArrayUtils.intArrayFromClassList(convertedList); + } + +} From 04d47bbc18463791a7f0caa02edb81e942d8dcaf Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 18:37:35 -0500 Subject: [PATCH 02/25] Some utility constructors in tuples --- .../engine/client/renderer/RenderGraph.java | 2 +- .../engine/graph/Routine.java | 2 +- .../engine/mod/ModInfo.java | 2 +- .../engine/mod/ModLoader.java | 2 +- .../engine/registry/RegistryPair.java | 2 +- .../engine/util/touples/Decade.java | 31 --------- .../engine/util/touples/Ennead.java | 30 --------- .../engine/util/touples/Octet.java | 29 -------- .../engine/util/touples/Quintet.java | 26 ------- .../engine/util/touples/Septet.java | 28 -------- .../engine/util/touples/Sextet.java | 27 -------- .../engine/util/tuples/Decade.java | 67 +++++++++++++++++++ .../engine/util/tuples/Ennead.java | 62 +++++++++++++++++ .../engine/util/tuples/Octet.java | 57 ++++++++++++++++ .../engine/util/{touples => tuples}/Pair.java | 6 +- .../util/{touples => tuples}/Quartet.java | 14 +++- .../engine/util/tuples/Quintet.java | 42 ++++++++++++ .../engine/util/tuples/Septet.java | 52 ++++++++++++++ .../engine/util/tuples/Sextet.java | 47 +++++++++++++ .../util/{touples => tuples}/Triplet.java | 10 ++- .../engine/util/{touples => tuples}/Unit.java | 2 +- 21 files changed, 360 insertions(+), 180 deletions(-) delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Decade.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Ennead.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Octet.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quintet.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Septet.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/touples/Sextet.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Decade.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Ennead.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Octet.java rename src/main/java/com/terminalvelocitycabbage/engine/util/{touples => tuples}/Pair.java (73%) rename src/main/java/com/terminalvelocitycabbage/engine/util/{touples => tuples}/Quartet.java (54%) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quintet.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Septet.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Sextet.java rename src/main/java/com/terminalvelocitycabbage/engine/util/{touples => tuples}/Triplet.java (63%) rename src/main/java/com/terminalvelocitycabbage/engine/util/{touples => tuples}/Unit.java (84%) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/RenderGraph.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/RenderGraph.java index 375893e..9050dad 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/RenderGraph.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/RenderGraph.java @@ -10,7 +10,7 @@ import com.terminalvelocitycabbage.engine.registry.Identifier; import com.terminalvelocitycabbage.engine.util.ClassUtils; import com.terminalvelocitycabbage.engine.util.Toggle; -import com.terminalvelocitycabbage.engine.util.touples.Pair; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; import com.terminalvelocitycabbage.templates.events.RenderGraphStageExecutionEvent; import javax.management.ReflectionException; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/graph/Routine.java b/src/main/java/com/terminalvelocitycabbage/engine/graph/Routine.java index a22a0e1..dd93716 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/graph/Routine.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/graph/Routine.java @@ -11,7 +11,7 @@ import com.terminalvelocitycabbage.engine.util.EntrypointUtils; import com.terminalvelocitycabbage.engine.util.MutableInstant; import com.terminalvelocitycabbage.engine.util.Toggle; -import com.terminalvelocitycabbage.engine.util.touples.Quartet; +import com.terminalvelocitycabbage.engine.util.tuples.Quartet; import com.terminalvelocitycabbage.templates.events.RoutineSystemExecutionEvent; import java.util.HashMap; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/mod/ModInfo.java b/src/main/java/com/terminalvelocitycabbage/engine/mod/ModInfo.java index ffcc71f..460491c 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/mod/ModInfo.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/mod/ModInfo.java @@ -1,7 +1,7 @@ package com.terminalvelocitycabbage.engine.mod; import com.github.zafarkhaja.semver.Version; -import com.terminalvelocitycabbage.engine.util.touples.Pair; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java b/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java index 94d0d6a..7f9ecd2 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java @@ -11,7 +11,7 @@ import com.terminalvelocitycabbage.engine.registry.Registry; import com.terminalvelocitycabbage.engine.util.ClassUtils; import com.terminalvelocitycabbage.engine.util.Toggle; -import com.terminalvelocitycabbage.engine.util.touples.Pair; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; import javax.management.ReflectionException; import java.io.File; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/registry/RegistryPair.java b/src/main/java/com/terminalvelocitycabbage/engine/registry/RegistryPair.java index 73d5542..5fefd97 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/registry/RegistryPair.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/registry/RegistryPair.java @@ -1,6 +1,6 @@ package com.terminalvelocitycabbage.engine.registry; -import com.terminalvelocitycabbage.engine.util.touples.Pair; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; /** * Represents a result from a registration used for doing things with data as it's being registered diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Decade.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Decade.java deleted file mode 100644 index 6e71015..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Decade.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Decade extends Ennead { - - private final J value9; - - public Decade(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8, J value9) { - super(value0, value1, value2, value3, value4, value5, value6, value7, value8); - this.value9 = value9; - } - - public J getValue9() { - return value9; - } - - @Override - public String toString() { - return "Decade{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - "value5=" + getValue5() + - "value6=" + getValue6() + - "value7=" + getValue7() + - "value8=" + getValue8() + - "value9=" + getValue9() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Ennead.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Ennead.java deleted file mode 100644 index b15c518..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Ennead.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Ennead extends Octet { - - private final I value8; - - public Ennead(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8) { - super(value0, value1, value2, value3, value4, value5, value6, value7); - this.value8 = value8; - } - - public I getValue8() { - return value8; - } - - @Override - public String toString() { - return "Ennead{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - "value5=" + getValue5() + - "value6=" + getValue6() + - "value7=" + getValue7() + - "value8=" + getValue8() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Octet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Octet.java deleted file mode 100644 index b7413d7..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Octet.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Octet extends Septet { - - private final H value7; - - public Octet(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7) { - super(value0, value1, value2, value3, value4, value5, value6); - this.value7 = value7; - } - - public H getValue7() { - return value7; - } - - @Override - public String toString() { - return "Octet{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - "value5=" + getValue5() + - "value6=" + getValue6() + - "value7=" + getValue7() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quintet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quintet.java deleted file mode 100644 index e6bb75a..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quintet.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Quintet extends Quartet { - - private final E value4; - - public Quintet(A value0, B value1, C value2, D value3, E value4) { - super(value0, value1, value2, value3); - this.value4 = value4; - } - - public E getValue4() { - return value4; - } - - @Override - public String toString() { - return "Quintet{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Septet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Septet.java deleted file mode 100644 index 1b57801..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Septet.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Septet extends Sextet { - - private final G value6; - - public Septet(A value0, B value1, C value2, D value3, E value4, F value5, G value6) { - super(value0, value1, value2, value3, value4, value5); - this.value6 = value6; - } - - public G getValue6() { - return value6; - } - - @Override - public String toString() { - return "Septet{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - "value5=" + getValue5() + - "value6=" + getValue6() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Sextet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Sextet.java deleted file mode 100644 index e77217a..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Sextet.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.terminalvelocitycabbage.engine.util.touples; - -public class Sextet extends Quintet { - - private final F value5; - - public Sextet(A value0, B value1, C value2, D value3, E value4, F value5) { - super(value0, value1, value2, value3, value4); - this.value5 = value5; - } - - public F getValue5() { - return value5; - } - - @Override - public String toString() { - return "Sextet{" + - "value0=" + getValue0() + - "value1=" + getValue1() + - "value2=" + getValue2() + - "value3=" + getValue3() + - "value4=" + getValue4() + - "value5=" + getValue5() + - '}'; - } -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Decade.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Decade.java new file mode 100644 index 0000000..8083771 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Decade.java @@ -0,0 +1,67 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Decade extends Ennead { + + private final J value9; + + public Decade(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8, J value9) { + super(value0, value1, value2, value3, value4, value5, value6, value7, value8); + this.value9 = value9; + } + + public Decade(Unit tuple, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), value1, value2, value3, value4, value5, value6, value7, value8, value9); + } + + public Decade(Pair tuple, C value2, D value3, E value4, F value5, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5, value6, value7, value8, value9); + } + + public Decade(Triplet tuple, D value3, E value4, F value5, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5, value6, value7, value8, value9); + } + + public Decade(Quartet tuple, E value4, F value5, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5, value6, value7, value8, value9); + } + + public Decade(Quintet tuple, F value5, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6, value7, value8, value9); + } + + public Decade(Sextet tuple, G value6, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), value6, value7, value8, value9); + } + + public Decade(Septet tuple, H value7, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), value7, value8, value9); + } + + public Decade(Octet tuple, I value8, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), tuple.getValue7(), value8, value9); + } + + public Decade(Ennead tuple, J value9) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), tuple.getValue7(), tuple.getValue8(), value9); + } + + public J getValue9() { + return value9; + } + + @Override + public String toString() { + return "Decade{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + "value5=" + getValue5() + + "value6=" + getValue6() + + "value7=" + getValue7() + + "value8=" + getValue8() + + "value9=" + getValue9() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Ennead.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Ennead.java new file mode 100644 index 0000000..8d71e59 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Ennead.java @@ -0,0 +1,62 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Ennead extends Octet { + + private final I value8; + + public Ennead(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8) { + super(value0, value1, value2, value3, value4, value5, value6, value7); + this.value8 = value8; + } + + public Ennead(Unit tuple, B value1, C value2, D value3, E value4, F value5, G value6, H value7, I value8) { + this(tuple.getValue0(), value1, value2, value3, value4, value5, value6, value7, value8); + } + + public Ennead(Pair tuple, C value2, D value3, E value4, F value5, G value6, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5, value6, value7, value8); + } + + public Ennead(Triplet tuple, D value3, E value4, F value5, G value6, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5, value6, value7, value8); + } + + public Ennead(Quartet tuple, E value4, F value5, G value6, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5, value6, value7, value8); + } + + public Ennead(Quintet tuple, F value5, G value6, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6, value7, value8); + } + + public Ennead(Sextet tuple, G value6, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), value6, value7, value8); + } + + public Ennead(Septet tuple, H value7, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), value7, value8); + } + + public Ennead(Octet tuple, I value8) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), tuple.getValue7(), value8); + } + + public I getValue8() { + return value8; + } + + @Override + public String toString() { + return "Ennead{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + "value5=" + getValue5() + + "value6=" + getValue6() + + "value7=" + getValue7() + + "value8=" + getValue8() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Octet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Octet.java new file mode 100644 index 0000000..1ba97f9 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Octet.java @@ -0,0 +1,57 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Octet extends Septet { + + private final H value7; + + public Octet(A value0, B value1, C value2, D value3, E value4, F value5, G value6, H value7) { + super(value0, value1, value2, value3, value4, value5, value6); + this.value7 = value7; + } + + public Octet(Unit tuple, B value1, C value2, D value3, E value4, F value5, G value6, H value7) { + this(tuple.getValue0(), value1, value2, value3, value4, value5, value6, value7); + } + + public Octet(Pair tuple, C value2, D value3, E value4, F value5, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5, value6, value7); + } + + public Octet(Triplet tuple, D value3, E value4, F value5, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5, value6, value7); + } + + public Octet(Quartet tuple, E value4, F value5, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5, value6, value7); + } + + public Octet(Quintet tuple, F value5, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6, value7); + } + + public Octet(Sextet tuple, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), value6, value7); + } + + public Octet(Septet tuple, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), tuple.getValue6(), value7); + } + + public H getValue7() { + return value7; + } + + @Override + public String toString() { + return "Octet{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + "value5=" + getValue5() + + "value6=" + getValue6() + + "value7=" + getValue7() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Pair.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Pair.java similarity index 73% rename from src/main/java/com/terminalvelocitycabbage/engine/util/touples/Pair.java rename to src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Pair.java index 7ddbedb..10d088b 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Pair.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Pair.java @@ -1,4 +1,4 @@ -package com.terminalvelocitycabbage.engine.util.touples; +package com.terminalvelocitycabbage.engine.util.tuples; public class Pair extends Unit { @@ -9,6 +9,10 @@ public Pair(A value0, B value1) { this.value1 = value1; } + public Pair(Unit tuple, B value1) { + this(tuple.getValue0(), value1); + } + public B getValue1() { return value1; } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quartet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quartet.java similarity index 54% rename from src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quartet.java rename to src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quartet.java index de03f84..a83170b 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Quartet.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quartet.java @@ -1,4 +1,4 @@ -package com.terminalvelocitycabbage.engine.util.touples; +package com.terminalvelocitycabbage.engine.util.tuples; public class Quartet extends Triplet { @@ -9,6 +9,18 @@ public Quartet(A value0, B value1, C value2, D value3) { this.value3 = value3; } + public Quartet(Unit tuple, B value1, C value2, D value3) { + this(tuple.getValue0(), value1, value2, value3); + } + + public Quartet(Pair tuple, C value2, D value3) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3); + } + + public Quartet(Triplet tuple, D value3) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3); + } + public D getValue3() { return value3; } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quintet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quintet.java new file mode 100644 index 0000000..e4749ed --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Quintet.java @@ -0,0 +1,42 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Quintet extends Quartet { + + private final E value4; + + public Quintet(A value0, B value1, C value2, D value3, E value4) { + super(value0, value1, value2, value3); + this.value4 = value4; + } + + public Quintet(Unit tuple, B value1, C value2, D value3, E value4) { + this(tuple.getValue0(), value1, value2, value3, value4); + } + + public Quintet(Pair tuple, C value2, D value3, E value4) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4); + } + + public Quintet(Triplet tuple, D value3, E value4) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4); + } + + public Quintet(Quartet tuple, E value4) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4); + } + + public E getValue4() { + return value4; + } + + @Override + public String toString() { + return "Quintet{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Septet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Septet.java new file mode 100644 index 0000000..e94b434 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Septet.java @@ -0,0 +1,52 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Septet extends Sextet { + + private final G value6; + + public Septet(A value0, B value1, C value2, D value3, E value4, F value5, G value6) { + super(value0, value1, value2, value3, value4, value5); + this.value6 = value6; + } + + public Septet(Unit tuple, B value1, C value2, D value3, E value4, F value5, G value6) { + this(tuple.getValue0(), value1, value2, value3, value4, value5, value6); + } + + public Septet(Pair tuple, C value2, D value3, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5, value6); + } + + public Septet(Triplet tuple, D value3, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5, value6); + } + + public Septet(Quartet tuple, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5, value6); + } + + public Septet(Quintet tuple, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6); + } + + public Septet(Sextet tuple, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), value6); + } + + public G getValue6() { + return value6; + } + + @Override + public String toString() { + return "Septet{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + "value5=" + getValue5() + + "value6=" + getValue6() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Sextet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Sextet.java new file mode 100644 index 0000000..7a55e8d --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Sextet.java @@ -0,0 +1,47 @@ +package com.terminalvelocitycabbage.engine.util.tuples; + +public class Sextet extends Quintet { + + private final F value5; + + public Sextet(A value0, B value1, C value2, D value3, E value4, F value5) { + super(value0, value1, value2, value3, value4); + this.value5 = value5; + } + + public Sextet(Unit tuple, B value1, C value2, D value3, E value4, F value5) { + this(tuple.getValue0(), value1, value2, value3, value4, value5); + } + + public Sextet(Pair tuple, C value2, D value3, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5); + } + + public Sextet(Triplet tuple, D value3, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5); + } + + public Sextet(Quartet tuple, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5); + } + + public Sextet(Quintet tuple, F value5) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5); + } + + public F getValue5() { + return value5; + } + + @Override + public String toString() { + return "Sextet{" + + "value0=" + getValue0() + + "value1=" + getValue1() + + "value2=" + getValue2() + + "value3=" + getValue3() + + "value4=" + getValue4() + + "value5=" + getValue5() + + '}'; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Triplet.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Triplet.java similarity index 63% rename from src/main/java/com/terminalvelocitycabbage/engine/util/touples/Triplet.java rename to src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Triplet.java index b2fab96..c13b2ff 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Triplet.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Triplet.java @@ -1,4 +1,4 @@ -package com.terminalvelocitycabbage.engine.util.touples; +package com.terminalvelocitycabbage.engine.util.tuples; public class Triplet extends Pair { @@ -9,6 +9,14 @@ public Triplet(A value0, B value1, C value2) { this.value2 = value2; } + public Triplet(Unit tuple, B value1, C value2) { + this(tuple.getValue0(), value1, value2); + } + + public Triplet(Pair tuple, C value2) { + this(tuple.getValue0(), tuple.getValue1(), value2); + } + public C getValue2() { return value2; } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Unit.java b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Unit.java similarity index 84% rename from src/main/java/com/terminalvelocitycabbage/engine/util/touples/Unit.java rename to src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Unit.java index 5f87f95..ef28eed 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/touples/Unit.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/tuples/Unit.java @@ -1,4 +1,4 @@ -package com.terminalvelocitycabbage.engine.util.touples; +package com.terminalvelocitycabbage.engine.util.tuples; public class Unit { From aac598fb38477e6982a34a766688f4e354a52f1a Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 20:20:00 -0500 Subject: [PATCH 03/25] Add model loading (not working, but not erroring either) --- .../engine/client/renderer/model/Mesh.java | 37 ++ .../engine/client/renderer/model/Model.java | 79 ++++ .../engine/client/renderer/model/Vertex.java | 23 + .../renderer/model/bedrock/BedrockModel.java | 195 -------- .../model/bedrock/BedrockModelData.java | 426 ++++++++++++++++++ .../ecs/components/ModelComponent.java | 27 ++ 6 files changed, 592 insertions(+), 195 deletions(-) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java create mode 100644 src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelComponent.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java index f7a9995..808b968 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java @@ -35,6 +35,43 @@ public Mesh(VertexFormat format, Vertex[] vertices, int[] indices) { this.indices = indices; } + public static Mesh of(List meshes) { + + //Verify all meshes have the same vertex format before merging data + VertexFormat format1 = null; + //While we're at it track vertex and index counts for later use IF it makes it past this point + int vertexCount = 0; + int indicesCount = 0; + for (Mesh mesh : meshes) { + if (format1 == null) format1 = mesh.getFormat(); + if (format1 != mesh.getFormat()) { + Log.crash("Tried to construct a mesh with mismatched formats"); + } + vertexCount += mesh.getNumVertices(); + indicesCount += mesh.getNumIndices(); + } + + //Combine all vertex data and index data + Vertex[] vertices = new Vertex[vertexCount]; + int[] indices = new int[indicesCount]; + int meshIndex = 0; + int vertexIndex = 0; + int indexOffset = 0; + for (Mesh mesh : meshes) { + for (int index : mesh.indices) { + indices[meshIndex] = index + indexOffset; + meshIndex++; + } + for (Vertex vertex : mesh.vertices) { + vertices[vertexIndex] = vertex; + vertexIndex++; + } + indexOffset += vertexIndex; + } + + return new Mesh(format1, vertices, indices); + } + /** * Initializes this mesh to be rendered. Only needs to be called once */ diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java new file mode 100644 index 0000000..48a8fdf --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -0,0 +1,79 @@ +package com.terminalvelocitycabbage.engine.client.renderer.model; + +import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; + +import java.util.ArrayList; +import java.util.List; + +public class Model { + + VertexFormat format; + List parts; + + public Model(VertexFormat format, List parts) { + this.format = format; + this.parts = parts; + } + + public void render() { + for (Part part : parts) { + part.render(); + } + } + + public void cleanup() { + for (Part part : parts) { + part.cleanup(); + } + } + + public VertexFormat getFormat() { + return format; + } + + public static class Part { + + String name; + Part parent; + List children; + Mesh mesh; + + public Part(String name, Part parent, Mesh mesh) { + this.name = name; + this.parent = parent; + this.children = new ArrayList(); + this.mesh = mesh; + } + + public void render() { + mesh.render(); + for (Part child : children) { + child.render(); + } + } + + public void cleanup() { + mesh.cleanup(); + for (Part child : children) { + child.cleanup(); + } + } + + public void addChild(Part child) { + children.add(child); + } + + public Part getParent() { + return parent; + } + + public List getChildren() { + return children; + } + + public Mesh getMesh() { + return mesh; + } + } + +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java index 3c24df0..41b0694 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java @@ -2,6 +2,8 @@ import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexAttribute; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import org.joml.Vector2f; +import org.joml.Vector3f; import java.util.Arrays; @@ -26,6 +28,13 @@ public Vertex setXYZPosition(float x, float y, float z) { return this; } + /** + * @return This vertex with the updated position data + */ + public Vertex setXYZPosition(Vector3f xyzPosition) { + return setXYZPosition(xyzPosition.x, xyzPosition.y, xyzPosition.z); + } + /** * @return This vertex with the updated texture coordinate data */ @@ -36,6 +45,13 @@ public Vertex setUV(float u, float v) { return this; } + /** + * @return This vertex with the updated texture coordinate data + */ + public Vertex setUV(Vector2f uv) { + return setUV(uv.x, uv.y); + } + /** * @return This vertex with the updated normal data */ @@ -47,6 +63,13 @@ public Vertex setXYZNormal(float x, float y, float z) { return this; } + /** + * @return This vertex with the updated normal data + */ + public Vertex setXYZNormal(Vector3f xyzNormal) { + return setXYZNormal(xyzNormal.x, xyzNormal.y, xyzNormal.z); + } + /** * @return This vertex with the updated color data */ diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java deleted file mode 100644 index 8128401..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModel.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.terminalvelocitycabbage.engine.client.renderer.model.bedrock; - -import com.electronwill.nightconfig.core.Config; -import com.electronwill.nightconfig.core.ConfigFormat; -import com.electronwill.nightconfig.core.io.ConfigParser; -import com.electronwill.nightconfig.json.JsonFormat; -import com.github.zafarkhaja.semver.Version; -import com.terminalvelocitycabbage.engine.debug.Log; -import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; -import com.terminalvelocitycabbage.engine.util.ConfigUtils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class BedrockModel { - - Version formatVersion; - BedrockGeometryDescription geometryDescription; - BedrockBone[] bones; - - private BedrockModel(Version formatVersion, BedrockGeometryDescription geometryDescription, BedrockBone[] bones) { - this.formatVersion = formatVersion; - this.geometryDescription = geometryDescription; - this.bones = bones; - } - - public void print() { - Log.info(formatVersion.toString()); - Log.info(geometryDescription.toString()); - for (BedrockBone bone : bones) { - Log.info(bone.toString()); - } - } - - private static class BedrockCube { - - float[] origin; - int[] size; - int[] uv; - - public BedrockCube(float[] origin, int[] size, int[] uv) { - this.origin = origin; - this.size = size; - this.uv = uv; - } - - @Override - public String toString() { - return "BedrockCube{" + - "origin=" + Arrays.toString(origin) + - ", size=" + Arrays.toString(size) + - ", uv=" + Arrays.toString(uv) + - '}'; - } - } - - private static class BedrockBone { - - String name; - String parent; - float[] pivot; - float[] rotation; - BedrockCube[] cubes; - - public BedrockBone(String name, String parent, float[] pivot, float[] rotation, BedrockCube[] cubes) { - this.name = name; - this.parent = parent; - this.pivot = pivot; - this.rotation = rotation; - this.cubes = cubes; - } - - @Override - public String toString() { - return "BedrockBone{" + - "name='" + name + '\'' + - ", parent='" + parent + '\'' + - ", pivot=" + Arrays.toString(pivot) + - ", rotation=" + Arrays.toString(rotation) + - ", cubes=" + Arrays.toString(cubes) + - '}'; - } - } - - private static class BedrockGeometryDescription { - - String identifier; - int textureWidth; - int textureHeight; - float visibleBoundsWidth; - float visibleBoundsHeight; - float[] visibleBoundsOffset; - - public BedrockGeometryDescription(String identifier, int textureWidth, int textureHeight, float visibleBoundsWidth, float visibleBoundsHeight, float[] visibleBoundsOffset) { - this.identifier = identifier; - this.textureWidth = textureWidth; - this.textureHeight = textureHeight; - this.visibleBoundsWidth = visibleBoundsWidth; - this.visibleBoundsHeight = visibleBoundsHeight; - this.visibleBoundsOffset = visibleBoundsOffset; - } - - @Override - public String toString() { - return "BedrockGeometryDescription{" + - "identifier='" + identifier + '\'' + - ", textureWidth=" + textureWidth + - ", textureHeight=" + textureHeight + - ", visibleBoundsWidth=" + visibleBoundsWidth + - ", visibleBoundsHeight=" + visibleBoundsHeight + - ", visibleBoundsOffset=" + Arrays.toString(visibleBoundsOffset) + - '}'; - } - } - - public static class Loader { - - static Version formatVersion; - static BedrockGeometryDescription geometryDescription; - static BedrockBone[] bones; - - public static BedrockModel loadModel(Resource modelResource) { - - String resourceString = modelResource.asString(); - - ConfigFormat jsonFormat = JsonFormat.fancyInstance(); - ConfigParser parser = jsonFormat.createParser(); - Config config = parser.parse(resourceString); - - formatVersion = Version.parse(config.get("format_version")); - - List subConfig = config.get("minecraft:geometry"); - Config geometryConfig = subConfig.get(0); - - geometryDescription = parseGeometryDescription(geometryConfig); - bones = parseBones(geometryConfig); - - return new BedrockModel(formatVersion, geometryDescription, bones); - } - - private static BedrockBone[] parseBones(Config config) { - - List boneConfigs = config.get("bones"); - List bones = new ArrayList<>(); - - boneConfigs.forEach(bone -> bones.add(parseBone(bone))); - - return bones.toArray(new BedrockBone[0]); - } - - private static BedrockBone parseBone(Config config) { - - String name = config.get("name"); - String parent = config.getOrElse("parent", "none"); - float[] pivot = ConfigUtils.numberListToFloatArray(config.get("pivot")); - float[] rotation = ConfigUtils.numberListToFloatArray(config.get("rotation")); - - return new BedrockBone(name, parent, pivot, rotation, parseCubes(config)); - } - - private static BedrockCube[] parseCubes(Config config) { - - List cubes = config.get("cubes"); - List cubesList = new ArrayList<>(); - - cubes.forEach(cube -> cubesList.add(parseCube(cube))); - - return cubesList.toArray(new BedrockCube[0]); - } - - private static BedrockCube parseCube(Config cube) { - - float[] origin = ConfigUtils.numberListToFloatArray(cube.get("origin")); - int[] size = ConfigUtils.numberListToIntArray(cube.get("size")); - int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); - - return new BedrockCube(origin, size, uv); - } - - private static BedrockGeometryDescription parseGeometryDescription(Config config) { - - String identifier = config.get("description.identifier"); - int textureWidth = config.getInt("description.texture_width"); - int textureHeight = config.getInt("description.texture_height"); - float visibleBoundsWidth = ((Number) config.get("description.visible_bounds_width")).floatValue(); - float visibleBoundsHeight = ((Number) config.get("description.visible_bounds_height")).floatValue(); - float[] visibleBoundsOffset = ConfigUtils.numberListToFloatArray(config.get("description.visible_bounds_offset")); - - return new BedrockGeometryDescription(identifier, textureWidth, textureHeight, visibleBoundsWidth, visibleBoundsHeight, visibleBoundsOffset); - } - - } - -} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java new file mode 100644 index 0000000..bb08a5b --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -0,0 +1,426 @@ +package com.terminalvelocitycabbage.engine.client.renderer.model.bedrock; + +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.ConfigFormat; +import com.electronwill.nightconfig.core.io.ConfigParser; +import com.electronwill.nightconfig.json.JsonFormat; +import com.github.zafarkhaja.semver.Version; +import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexAttribute; +import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import com.terminalvelocitycabbage.engine.client.renderer.model.Mesh; +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; +import com.terminalvelocitycabbage.engine.client.renderer.model.Vertex; +import com.terminalvelocitycabbage.engine.debug.Log; +import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; +import com.terminalvelocitycabbage.engine.util.ConfigUtils; +import com.terminalvelocitycabbage.engine.util.tuples.Triplet; +import org.joml.Vector2f; +import org.joml.Vector3f; + +import java.util.*; + +public class BedrockModelData { + + public static final VertexFormat BEDROCK_VERTEX_FORMAT = VertexFormat + .builder() + .addElement(VertexAttribute.XYZ_POSITION) + .addElement(VertexAttribute.XYZ_NORMAL) + .addElement(VertexAttribute.UV) + .build(); + + Version formatVersion; + BedrockGeometryDescription geometryDescription; + BedrockBone[] bones; + + private BedrockModelData(Version formatVersion, BedrockGeometryDescription geometryDescription, BedrockBone[] bones) { + this.formatVersion = formatVersion; + this.geometryDescription = geometryDescription; + this.bones = bones; + } + + private static class StagedModelPart extends Triplet { + + public StagedModelPart(String value0, String value1, Mesh value2) { + super(value0, value1, value2); + } + + public String getName() { + return getValue0(); + } + + public String getParentName() { + return getValue1(); + } + + public Mesh getMesh() { + return getValue2(); + } + } + + private static class PartInfo extends Triplet> { + + public PartInfo(String value0, Mesh value1, List value2) { + super(value0, value1, value2); + } + + public String getParentName() { + return getValue0(); + } + + public Mesh getMesh() { + return getValue1(); + } + + public List getChildNames() { + return getValue2(); + } + } + + public Model toModel() { + + //The information needed to create a model part extracted from all bones + List partsStaging = new ArrayList<>(); + + //Loop through all bones to get staging data for a model part + for (BedrockBone bone : bones) { + List meshes = new ArrayList<>(); + for (BedrockCube cube : bone.cubes) { + //Convert cubes to meshes + meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); + } + partsStaging.add(new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); + } + + //Create a map of bones that can store children + //Name: Parent, Mesh, Children + Map boneMap = new HashMap<>(); + for (StagedModelPart triplet : partsStaging) { + boneMap.put(triplet.getValue0(), new PartInfo(triplet.getParentName(), triplet.getMesh(), new ArrayList<>())); + } + + //Map these parts to the bones map + List roots = new ArrayList<>(); + for (StagedModelPart part : partsStaging) { + if (part.getParentName().equals("none")) { + roots.add(part); + } else { + if (!boneMap.containsKey(part.getParentName())) Log.crash("Parent bone not found on tree, verify model integrity or report this to TVE developers: " + part.getParentName()); + } + //Add this part's name to the list of the parent's children + boneMap.get(part.getName()).getChildNames().add(part.getName()); + } + + //Construct this model from these bones into model parts + List parts = new ArrayList<>(); + for (StagedModelPart part : roots) { + parts.add(createPart(boneMap, part.getName(), part.getParentName(), part.getMesh())); + } + + Log.info("Loaded model " + geometryDescription.identifier); + + return new Model(BEDROCK_VERTEX_FORMAT, parts); + } + + private Model.Part createPart(Map boneMap, String partName, String parentName, Mesh mesh) { + PartInfo parentInfo = boneMap.get(parentName); + if (parentInfo == null) { + return new Model.Part(partName, null, mesh); + } + return new Model.Part(partName, createPart(boneMap, partName, parentInfo.getParentName(), parentInfo.getMesh()), mesh); + } + + public void print() { + Log.info(formatVersion.toString()); + Log.info(geometryDescription.toString()); + for (BedrockBone bone : bones) { + Log.info(bone.toString()); + } + } + + private static class BedrockCube { + + float[] origin; + int[] size; + int[] uv; + + public BedrockCube(float[] origin, int[] size, int[] uv) { + this.origin = origin; + this.size = size; + this.uv = uv; + } + + /** + * + * Positions are defined by an origin and a size, there will be 3 Vertexes at each position, only difference + * Will be the UV. + * + * Origin is always the smallest of the 3 components, so it will always be at the SWBottom corner, meaning that + * the position components of the other 7 vertexes will be either the same as the origin or more North East or Up + * + * X is E/W (E is +), Y is T/B (T is +), Z is N/S (S is +) + * + * "* <-- Origin: (U,V)" the * is the origin, since OpenGL does UV from TL to BR this should already be right + * + * Offsets from the origin are defined by the size array 123 + xyz, offsets shown below: + * | s2 | s0 | s2 | s0 | + * * 1_______2_______3 --- + * | |BR BL| + * | T | B | s2 + * | |TR TL| + * 4_______5_______6_______7_______8 --- + * | | | | | + * | E | N | W | S | s1 + * | | | | | + * 9------10------11------12------13 --- + * For UVs all except Bottom use top/bottom/left/right based on above + * only 13 UV positions matter, numbered above + * + * The UVs need to be divided by the texture size to get them from 0 to 1 + * + * Naming conventions for the variables in this method: + * A vertex will be named based on the cardinal directions plus up/down + * nsew for cardinal directions u for up and d for down. + * + * Vertex net will be the vertex to the North East Top corner of this cuboid + * + * @return A mesh represented from this cube + */ + public Mesh toMesh(int textureWidth, int textureHeight) { + + //Vertex positions + Vector3f netPos = new Vector3f(origin[0] + size[0], origin[1] + size[1], origin[2] + 0f); + Vector3f nebPos = new Vector3f(origin[0] + size[0], origin[1] + 0f, origin[2] + 0f); + Vector3f nwtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + 0f); + Vector3f nwbPos = new Vector3f(origin[0] + 0f, origin[1] + 0f, origin[2] + 0f); + Vector3f setPos = new Vector3f(origin[0] + size[0], origin[1] + size[1], origin[2] + size[2]); + Vector3f sebPos = new Vector3f(origin[0] + size[0], origin[1] + 0f, origin[2] + size[2]); + Vector3f swtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + size[2]); + Vector3f swbPos = new Vector3f(origin[0] + 0f, origin[1] + 0f, origin[2] + size[2]); + + //Face normals + Vector3f northNormal = new Vector3f(0, 0, -1); + Vector3f eastNormal = new Vector3f(1, 0, 0); + Vector3f southNormal = new Vector3f(0, 0, 1); + Vector3f westNormal = new Vector3f(-1, 0, 0); + Vector3f upNormal = new Vector3f(0, 1, 0); + Vector3f downNormal = new Vector3f(0, -1, 0); + + //UVs + Vector2f uv1 = new Vector2f(uv[0] + size[2], uv[0]).div(textureWidth, textureHeight); + Vector2f uv2 = new Vector2f(uv[0] + size[2] + size[0], uv[0]).div(textureWidth, textureHeight); + Vector2f uv3 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0]).div(textureWidth, textureHeight); + Vector2f uv4 = new Vector2f(uv[0], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv5 = new Vector2f(uv[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv6 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv7 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv8 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv9 = new Vector2f(uv[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv10 = new Vector2f(uv[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv11 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv12 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv13 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + + //North Face + Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv5); + Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv6); + Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv10); + Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv11); + Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv4); + Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv5); + Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv9); + Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv10); + Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv7); + Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv8); + Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv12); + Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv13); + Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv6); + Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(westNormal).setUV(uv7); + Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv11); + Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv12); + Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv1); + Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv2); + Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv5); + Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv6); + Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv7); + Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv6); + Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv3); + Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv2); + + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + // 12 13 14 15 + // 16 17 18 19 + // 20 21 22 23 + + Vertex[] vertices = new Vertex[]{ + northTL, northTR, northBL, northBR, + eastTL, eastTR, eastBL, eastBR, + southTL, southTR, southBL, southBR, + westTL, westTR, westBL, westBR, + topTL, topTR, topBL, topBR, + bottomTL, bottomTR, bottomBL, bottomBR + }; + + //All should wind in the TL BL BR, TL, BR, TR order each face + //Bottom should be in BR, TR, TL, BR, TL, BL + int[] indexes = new int[]{ + 0, 2, 3, 0, 3, 1, + 4, 6, 7, 4, 7, 5, + 8, 10, 11, 8, 11, 9, + 12, 14, 15, 12, 15, 13, + 16, 18, 19, 16, 19, 17, + 23, 21, 20, 23, 20, 22, + }; + + return new Mesh(BEDROCK_VERTEX_FORMAT, vertices, indexes); + } + + @Override + public String toString() { + return "BedrockCube{" + + "origin=" + Arrays.toString(origin) + + ", size=" + Arrays.toString(size) + + ", uv=" + Arrays.toString(uv) + + '}'; + } + } + + private static class BedrockBone { + + String name; + String parent; + float[] pivot; + float[] rotation; + BedrockCube[] cubes; + + public BedrockBone(String name, String parent, float[] pivot, float[] rotation, BedrockCube[] cubes) { + this.name = name; + this.parent = parent; + this.pivot = pivot; + this.rotation = rotation; + this.cubes = cubes; + } + + @Override + public String toString() { + return "BedrockBone{" + + "name='" + name + '\'' + + ", parent='" + parent + '\'' + + ", pivot=" + Arrays.toString(pivot) + + ", rotation=" + Arrays.toString(rotation) + + ", cubes=" + Arrays.toString(cubes) + + '}'; + } + } + + private static class BedrockGeometryDescription { + + String identifier; + int textureWidth; + int textureHeight; + float visibleBoundsWidth; + float visibleBoundsHeight; + float[] visibleBoundsOffset; + + public BedrockGeometryDescription(String identifier, int textureWidth, int textureHeight, float visibleBoundsWidth, float visibleBoundsHeight, float[] visibleBoundsOffset) { + this.identifier = identifier; + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + this.visibleBoundsWidth = visibleBoundsWidth; + this.visibleBoundsHeight = visibleBoundsHeight; + this.visibleBoundsOffset = visibleBoundsOffset; + } + + @Override + public String toString() { + return "BedrockGeometryDescription{" + + "identifier='" + identifier + '\'' + + ", textureWidth=" + textureWidth + + ", textureHeight=" + textureHeight + + ", visibleBoundsWidth=" + visibleBoundsWidth + + ", visibleBoundsHeight=" + visibleBoundsHeight + + ", visibleBoundsOffset=" + Arrays.toString(visibleBoundsOffset) + + '}'; + } + } + + public static class Loader { + + static Version formatVersion; + static BedrockGeometryDescription geometryDescription; + static BedrockBone[] bones; + + public static BedrockModelData loadModel(Resource modelResource) { + + String resourceString = modelResource.asString(); + + ConfigFormat jsonFormat = JsonFormat.fancyInstance(); + ConfigParser parser = jsonFormat.createParser(); + Config config = parser.parse(resourceString); + + formatVersion = Version.parse(config.get("format_version")); + + List subConfig = config.get("minecraft:geometry"); + Config geometryConfig = subConfig.get(0); + + geometryDescription = parseGeometryDescription(geometryConfig); + bones = parseBones(geometryConfig); + + return new BedrockModelData(formatVersion, geometryDescription, bones); + } + + private static BedrockBone[] parseBones(Config config) { + + List boneConfigs = config.get("bones"); + List bones = new ArrayList<>(); + + boneConfigs.forEach(bone -> bones.add(parseBone(bone))); + + return bones.toArray(new BedrockBone[0]); + } + + private static BedrockBone parseBone(Config config) { + + String name = config.get("name"); + String parent = config.getOrElse("parent", "none"); + float[] pivot = ConfigUtils.numberListToFloatArray(config.get("pivot")); + float[] rotation = ConfigUtils.numberListToFloatArray(config.get("rotation")); + + return new BedrockBone(name, parent, pivot, rotation, parseCubes(config)); + } + + private static BedrockCube[] parseCubes(Config config) { + + List cubes = config.get("cubes"); + List cubesList = new ArrayList<>(); + + cubes.forEach(cube -> cubesList.add(parseCube(cube))); + + return cubesList.toArray(new BedrockCube[0]); + } + + private static BedrockCube parseCube(Config cube) { + + float[] origin = ConfigUtils.numberListToFloatArray(cube.get("origin")); + int[] size = ConfigUtils.numberListToIntArray(cube.get("size")); + int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); + + return new BedrockCube(origin, size, uv); + } + + private static BedrockGeometryDescription parseGeometryDescription(Config config) { + + String identifier = config.get("description.identifier"); + int textureWidth = config.getInt("description.texture_width"); + int textureHeight = config.getInt("description.texture_height"); + float visibleBoundsWidth = ((Number) config.get("description.visible_bounds_width")).floatValue(); + float visibleBoundsHeight = ((Number) config.get("description.visible_bounds_height")).floatValue(); + float[] visibleBoundsOffset = ConfigUtils.numberListToFloatArray(config.get("description.visible_bounds_offset")); + + return new BedrockGeometryDescription(identifier, textureWidth, textureHeight, visibleBoundsWidth, visibleBoundsHeight, visibleBoundsOffset); + } + + } + +} diff --git a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelComponent.java b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelComponent.java new file mode 100644 index 0000000..c2fc683 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelComponent.java @@ -0,0 +1,27 @@ +package com.terminalvelocitycabbage.templates.ecs.components; + +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; +import com.terminalvelocitycabbage.engine.ecs.Component; + +public class ModelComponent implements Component { + + Model model; + + @Override + public void setDefaults() { + model = null; + } + + @Override + public void cleanup() { + model.cleanup(); + } + + public Model getModel() { + return model; + } + + public void setModel(Model model) { + this.model = model; + } +} From d5d14ee64d3fd03b044b7ed59862b9be4b532c5a Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 22:01:03 -0500 Subject: [PATCH 04/25] A lot closer to rendering correctly --- .../engine/client/renderer/model/Model.java | 5 ++ .../model/bedrock/BedrockModelData.java | 64 +++++++------------ .../engine/client/window/WindowThread.java | 2 + 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index 48a8fdf..6814a19 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,6 +1,7 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import com.terminalvelocitycabbage.engine.debug.Log; import java.util.ArrayList; import java.util.List; @@ -74,6 +75,10 @@ public List getChildren() { public Mesh getMesh() { return mesh; } + + public String getName() { + return name; + } } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index bb08a5b..51d8834 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -13,7 +13,7 @@ import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; -import com.terminalvelocitycabbage.engine.util.tuples.Triplet; +import com.terminalvelocitycabbage.engine.util.tuples.Quartet; import org.joml.Vector2f; import org.joml.Vector3f; @@ -38,10 +38,10 @@ private BedrockModelData(Version formatVersion, BedrockGeometryDescription geome this.bones = bones; } - private static class StagedModelPart extends Triplet { + private static class StagedModelPart extends Quartet> { - public StagedModelPart(String value0, String value1, Mesh value2) { - super(value0, value1, value2); + public StagedModelPart(String name, String parentName, Mesh mesh) { + super(name, parentName, mesh, new ArrayList<>()); } public String getName() { @@ -55,31 +55,16 @@ public String getParentName() { public Mesh getMesh() { return getValue2(); } - } - - private static class PartInfo extends Triplet> { - public PartInfo(String value0, Mesh value1, List value2) { - super(value0, value1, value2); - } - - public String getParentName() { - return getValue0(); - } - - public Mesh getMesh() { - return getValue1(); - } - - public List getChildNames() { - return getValue2(); + public List getChildren() { + return getValue3(); } } public Model toModel() { //The information needed to create a model part extracted from all bones - List partsStaging = new ArrayList<>(); + Map partsStaging = new HashMap<>(); //Loop through all bones to get staging data for a model part for (BedrockBone bone : bones) { @@ -88,32 +73,25 @@ public Model toModel() { //Convert cubes to meshes meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); } - partsStaging.add(new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); + partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); } - //Create a map of bones that can store children - //Name: Parent, Mesh, Children - Map boneMap = new HashMap<>(); - for (StagedModelPart triplet : partsStaging) { - boneMap.put(triplet.getValue0(), new PartInfo(triplet.getParentName(), triplet.getMesh(), new ArrayList<>())); - } - - //Map these parts to the bones map + //Assign children to all staged model parts List roots = new ArrayList<>(); - for (StagedModelPart part : partsStaging) { - if (part.getParentName().equals("none")) { - roots.add(part); + for (StagedModelPart part : partsStaging.values()) { + if (!part.getParentName().equals("none")) { + partsStaging.get(part.getParentName()).getChildren().add(part.getName()); } else { - if (!boneMap.containsKey(part.getParentName())) Log.crash("Parent bone not found on tree, verify model integrity or report this to TVE developers: " + part.getParentName()); + roots.add(part); } - //Add this part's name to the list of the parent's children - boneMap.get(part.getName()).getChildNames().add(part.getName()); } //Construct this model from these bones into model parts List parts = new ArrayList<>(); for (StagedModelPart part : roots) { - parts.add(createPart(boneMap, part.getName(), part.getParentName(), part.getMesh())); + var newPart = new Model.Part(part.getName(), null, part.getMesh()); + parts.add(newPart); + addChildren(partsStaging, newPart); } Log.info("Loaded model " + geometryDescription.identifier); @@ -121,12 +99,14 @@ public Model toModel() { return new Model(BEDROCK_VERTEX_FORMAT, parts); } - private Model.Part createPart(Map boneMap, String partName, String parentName, Mesh mesh) { - PartInfo parentInfo = boneMap.get(parentName); + private void addChildren(Map boneMap, Model.Part part) { + var childrenNames = boneMap.get(part.getName()).getChildren(); if (parentInfo == null) { - return new Model.Part(partName, null, mesh); + for (String childName : childrenNames) { + var childPart = new Model.Part(childName, part, boneMap.get(childName).getMesh()); + part.addChild(childPart); + addChildren(boneMap, childPart); } - return new Model.Part(partName, createPart(boneMap, partName, parentInfo.getParentName(), parentInfo.getMesh()), mesh); } public void print() { diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/window/WindowThread.java b/src/main/java/com/terminalvelocitycabbage/engine/client/window/WindowThread.java index 16bfe38..9ee75eb 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/window/WindowThread.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/window/WindowThread.java @@ -39,6 +39,8 @@ public void run() { glfwMakeContextCurrent(windowHandle); GL.createCapabilities(); + glEnable(GL_DEPTH_TEST); + //Turn on vsync //TODO swap this out for a window config apply() && Verify that bgfx may take care of this instead glfwSwapInterval(1); From 52a62b11a8fa954a0e34504c9b69743bc27bdd76 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 22:41:51 -0500 Subject: [PATCH 05/25] Flip normal U direction (wacky moment) --- .../engine/client/renderer/model/Model.java | 1 - .../model/bedrock/BedrockModelData.java | 75 +++++++++---------- .../components/TransformationComponent.java | 2 +- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index 6814a19..6eb25fc 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,7 +1,6 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; -import com.terminalvelocitycabbage.engine.debug.Log; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 51d8834..7cd1455 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -94,14 +94,11 @@ public Model toModel() { addChildren(partsStaging, newPart); } - Log.info("Loaded model " + geometryDescription.identifier); - return new Model(BEDROCK_VERTEX_FORMAT, parts); } private void addChildren(Map boneMap, Model.Part part) { var childrenNames = boneMap.get(part.getName()).getChildren(); - if (parentInfo == null) { for (String childName : childrenNames) { var childPart = new Model.Part(childName, part, boneMap.get(childName).getMesh()); part.addChild(childPart); @@ -186,45 +183,45 @@ public Mesh toMesh(int textureWidth, int textureHeight) { Vector3f downNormal = new Vector3f(0, -1, 0); //UVs - Vector2f uv1 = new Vector2f(uv[0] + size[2], uv[0]).div(textureWidth, textureHeight); - Vector2f uv2 = new Vector2f(uv[0] + size[2] + size[0], uv[0]).div(textureWidth, textureHeight); - Vector2f uv3 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0]).div(textureWidth, textureHeight); - Vector2f uv4 = new Vector2f(uv[0], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv5 = new Vector2f(uv[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv6 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv7 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv8 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv9 = new Vector2f(uv[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv10 = new Vector2f(uv[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv11 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv12 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv1 = new Vector2f(uv[0] + size[2], uv[0]).div(textureWidth, textureHeight); + Vector2f uv2 = new Vector2f(uv[0] + size[2] + size[0], uv[0]).div(textureWidth, textureHeight); + Vector2f uv3 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0]).div(textureWidth, textureHeight); + Vector2f uv4 = new Vector2f(uv[0] + 0f, uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv5 = new Vector2f(uv[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv6 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv7 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv8 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); + Vector2f uv9 = new Vector2f(uv[0] + 0f, uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv10 = new Vector2f(uv[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv11 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv12 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); Vector2f uv13 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); //North Face - Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv5); - Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv6); - Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv10); - Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv11); - Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv4); - Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv5); - Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv9); - Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv10); - Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv7); - Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv8); - Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv12); - Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv13); - Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv6); - Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(westNormal).setUV(uv7); - Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv11); - Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv12); - Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv1); - Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv2); - Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv5); - Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv6); - Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv7); - Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv6); - Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv3); - Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv2); + Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv6); + Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv5); + Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv11); + Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv10); + Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv5); + Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv4); + Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv10); + Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv9); + Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv8); + Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv7); + Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv13); + Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv12); + Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv7); + Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(westNormal).setUV(uv6); + Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv12); + Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv11); + Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv2); + Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv1); + Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv6); + Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv5); + Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv6); + Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv7); + Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv2); + Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv3); // 0 1 2 3 // 4 5 6 7 diff --git a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java index e794eed..ca57eca 100644 --- a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java +++ b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java @@ -38,7 +38,7 @@ public Quaternionf getRotation() { } public TransformationComponent rotate(float x, float y, float z) { - this.rotation.rotateYXZ((float) Math.toRadians(x), (float) Math.toRadians(y), (float) Math.toRadians(z)); + this.rotation.rotateXYZ((float) Math.toRadians(x), (float) Math.toRadians(y), (float) Math.toRadians(z)); dirty = true; return this; } From 4c917c880370da3d4bb5898a596862b440c6874d Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 13 Jul 2024 22:59:24 -0500 Subject: [PATCH 06/25] Fix bottom face uv spacing --- .../model/bedrock/BedrockModelData.java | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 7cd1455..4b226d4 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -143,12 +143,12 @@ public BedrockCube(float[] origin, int[] size, int[] uv) { * * 1_______2_______3 --- * | |BR BL| * | T | B | s2 - * | |TR TL| - * 4_______5_______6_______7_______8 --- + * | |TR TL|7 + * 4_______5_______6_______8_______9 --- * | | | | | * | E | N | W | S | s1 * | | | | | - * 9------10------11------12------13 --- + * 10-----11------12------13------14 --- * For UVs all except Bottom use top/bottom/left/right based on above * only 13 UV positions matter, numbered above * @@ -165,6 +165,7 @@ public BedrockCube(float[] origin, int[] size, int[] uv) { public Mesh toMesh(int textureWidth, int textureHeight) { //Vertex positions + //TODO start all at the origin, rotate them, then move them to their size to apply rotations to vertex positions Vector3f netPos = new Vector3f(origin[0] + size[0], origin[1] + size[1], origin[2] + 0f); Vector3f nebPos = new Vector3f(origin[0] + size[0], origin[1] + 0f, origin[2] + 0f); Vector3f nwtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + 0f); @@ -183,45 +184,46 @@ public Mesh toMesh(int textureWidth, int textureHeight) { Vector3f downNormal = new Vector3f(0, -1, 0); //UVs - Vector2f uv1 = new Vector2f(uv[0] + size[2], uv[0]).div(textureWidth, textureHeight); - Vector2f uv2 = new Vector2f(uv[0] + size[2] + size[0], uv[0]).div(textureWidth, textureHeight); - Vector2f uv3 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0]).div(textureWidth, textureHeight); - Vector2f uv4 = new Vector2f(uv[0] + 0f, uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv5 = new Vector2f(uv[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv6 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv7 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv8 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2]).div(textureWidth, textureHeight); - Vector2f uv9 = new Vector2f(uv[0] + 0f, uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv10 = new Vector2f(uv[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv11 = new Vector2f(uv[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv12 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); - Vector2f uv13 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[0] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv1 = new Vector2f(uv[0] + size[2], uv[1]).div(textureWidth, textureHeight); + Vector2f uv2 = new Vector2f(uv[0] + size[2] + size[0], uv[1]).div(textureWidth, textureHeight); + Vector2f uv3 = new Vector2f(uv[0] + size[2] + size[0] + size[0], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv4 = new Vector2f(uv[0], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv5 = new Vector2f(uv[0] + size[2], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv6 = new Vector2f(uv[0] + size[2] + size[0], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv7 = new Vector2f(uv[0] + size[2] + size[0] + size[0], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv8 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv9 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[1] + size[2]).div(textureWidth, textureHeight); + Vector2f uv10 = new Vector2f(uv[0], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv11 = new Vector2f(uv[0] + size[2], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv12 = new Vector2f(uv[0] + size[2] + size[0], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv13 = new Vector2f(uv[0] + size[2] + size[0] + size[2], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); + Vector2f uv14 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); //North Face Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv6); Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv5); - Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv11); - Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv10); + Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv12); + Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv11); Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv5); Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv4); - Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv10); - Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv9); - Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv8); - Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv7); - Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv13); - Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv12); - Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv7); + Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv11); + Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv10); + Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv9); + Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv8); + Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv14); + Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv13); + Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv8); Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(westNormal).setUV(uv6); - Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv12); - Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv11); + Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv13); + Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv12); Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv2); Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv1); Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv6); Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv5); - Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv6); - Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv7); - Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv2); - Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv3); + Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv7); + Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv6); + Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv3); + Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv2); // 0 1 2 3 // 4 5 6 7 From c4a41767695827a9021e1c948ebc11e5bbfefd51 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 14 Jul 2024 20:32:16 -0500 Subject: [PATCH 07/25] Add cube rotations to model loader (still pivot rotations todo) --- .../model/bedrock/BedrockModelData.java | 196 +++++++++++------- 1 file changed, 118 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 4b226d4..5c8c395 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -14,6 +14,7 @@ import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; import com.terminalvelocitycabbage.engine.util.tuples.Quartet; +import org.joml.Quaternionf; import org.joml.Vector2f; import org.joml.Vector3f; @@ -38,92 +39,20 @@ private BedrockModelData(Version formatVersion, BedrockGeometryDescription geome this.bones = bones; } - private static class StagedModelPart extends Quartet> { - - public StagedModelPart(String name, String parentName, Mesh mesh) { - super(name, parentName, mesh, new ArrayList<>()); - } - - public String getName() { - return getValue0(); - } - - public String getParentName() { - return getValue1(); - } - - public Mesh getMesh() { - return getValue2(); - } - - public List getChildren() { - return getValue3(); - } - } - - public Model toModel() { - - //The information needed to create a model part extracted from all bones - Map partsStaging = new HashMap<>(); - - //Loop through all bones to get staging data for a model part - for (BedrockBone bone : bones) { - List meshes = new ArrayList<>(); - for (BedrockCube cube : bone.cubes) { - //Convert cubes to meshes - meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); - } - partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); - } - - //Assign children to all staged model parts - List roots = new ArrayList<>(); - for (StagedModelPart part : partsStaging.values()) { - if (!part.getParentName().equals("none")) { - partsStaging.get(part.getParentName()).getChildren().add(part.getName()); - } else { - roots.add(part); - } - } - - //Construct this model from these bones into model parts - List parts = new ArrayList<>(); - for (StagedModelPart part : roots) { - var newPart = new Model.Part(part.getName(), null, part.getMesh()); - parts.add(newPart); - addChildren(partsStaging, newPart); - } - - return new Model(BEDROCK_VERTEX_FORMAT, parts); - } - - private void addChildren(Map boneMap, Model.Part part) { - var childrenNames = boneMap.get(part.getName()).getChildren(); - for (String childName : childrenNames) { - var childPart = new Model.Part(childName, part, boneMap.get(childName).getMesh()); - part.addChild(childPart); - addChildren(boneMap, childPart); - } - } - - public void print() { - Log.info(formatVersion.toString()); - Log.info(geometryDescription.toString()); - for (BedrockBone bone : bones) { - Log.info(bone.toString()); - } - } - private static class BedrockCube { float[] origin; int[] size; int[] uv; + float[] pivot; + float[] rotation; - public BedrockCube(float[] origin, int[] size, int[] uv) { + public BedrockCube(float[] origin, int[] size, int[] uv, float[] pivot, float[] rotation) { this.origin = origin; this.size = size; this.uv = uv; + this.pivot = pivot; + this.rotation = rotation; } /** @@ -175,6 +104,39 @@ public Mesh toMesh(int textureWidth, int textureHeight) { Vector3f swtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + size[2]); Vector3f swbPos = new Vector3f(origin[0] + 0f, origin[1] + 0f, origin[2] + size[2]); + if (rotation.length > 0 && pivot.length > 0) { + + Quaternionf q = new Quaternionf(); + q.rotateXYZ((float) Math.toRadians(rotation[0]), (float) Math.toRadians(rotation[1]), (float) Math.toRadians(rotation[2])); + + netPos.sub(pivot[0], pivot[1], pivot[2]); + nebPos.sub(pivot[0], pivot[1], pivot[2]); + nwtPos.sub(pivot[0], pivot[1], pivot[2]); + nwbPos.sub(pivot[0], pivot[1], pivot[2]); + setPos.sub(pivot[0], pivot[1], pivot[2]); + sebPos.sub(pivot[0], pivot[1], pivot[2]); + swtPos.sub(pivot[0], pivot[1], pivot[2]); + swbPos.sub(pivot[0], pivot[1], pivot[2]); + + netPos.rotate(q); + nebPos.rotate(q); + nwtPos.rotate(q); + nwbPos.rotate(q); + setPos.rotate(q); + sebPos.rotate(q); + swtPos.rotate(q); + swbPos.rotate(q); + + netPos.add(pivot[0], pivot[1], pivot[2]); + nebPos.add(pivot[0], pivot[1], pivot[2]); + nwtPos.add(pivot[0], pivot[1], pivot[2]); + nwbPos.add(pivot[0], pivot[1], pivot[2]); + setPos.add(pivot[0], pivot[1], pivot[2]); + sebPos.add(pivot[0], pivot[1], pivot[2]); + swtPos.add(pivot[0], pivot[1], pivot[2]); + swbPos.add(pivot[0], pivot[1], pivot[2]); + } + //Face normals Vector3f northNormal = new Vector3f(0, 0, -1); Vector3f eastNormal = new Vector3f(1, 0, 0); @@ -384,8 +346,10 @@ private static BedrockCube parseCube(Config cube) { float[] origin = ConfigUtils.numberListToFloatArray(cube.get("origin")); int[] size = ConfigUtils.numberListToIntArray(cube.get("size")); int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); + float[] pivot = ConfigUtils.numberListToFloatArray(cube.get("pivot")); + float[] rotation = ConfigUtils.numberListToFloatArray(cube.get("rotation")); - return new BedrockCube(origin, size, uv); + return new BedrockCube(origin, size, uv, pivot, rotation); } private static BedrockGeometryDescription parseGeometryDescription(Config config) { @@ -402,4 +366,80 @@ private static BedrockGeometryDescription parseGeometryDescription(Config config } + private static class StagedModelPart extends Quartet> { + + public StagedModelPart(String name, String parentName, Mesh mesh) { + super(name, parentName, mesh, new ArrayList<>()); + } + + public String getName() { + return getValue0(); + } + + public String getParentName() { + return getValue1(); + } + + public Mesh getMesh() { + return getValue2(); + } + + public List getChildren() { + return getValue3(); + } + } + + public Model toModel() { + + //The information needed to create a model part extracted from all bones + Map partsStaging = new HashMap<>(); + + //Loop through all bones to get staging data for a model part + for (BedrockBone bone : bones) { + List meshes = new ArrayList<>(); + for (BedrockCube cube : bone.cubes) { + //Convert cubes to meshes + meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); + } + partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); + } + + //Assign children to all staged model parts + List roots = new ArrayList<>(); + for (StagedModelPart part : partsStaging.values()) { + if (!part.getParentName().equals("none")) { + partsStaging.get(part.getParentName()).getChildren().add(part.getName()); + } else { + roots.add(part); + } + } + + //Construct this model from these bones into model parts + List parts = new ArrayList<>(); + for (StagedModelPart part : roots) { + var newPart = new Model.Part(part.getName(), null, part.getMesh()); + parts.add(newPart); + addChildren(partsStaging, newPart); + } + + return new Model(BEDROCK_VERTEX_FORMAT, parts); + } + + private void addChildren(Map boneMap, Model.Part part) { + var childrenNames = boneMap.get(part.getName()).getChildren(); + for (String childName : childrenNames) { + var childPart = new Model.Part(childName, part, boneMap.get(childName).getMesh()); + part.addChild(childPart); + addChildren(boneMap, childPart); + } + } + + public void print() { + Log.info(formatVersion.toString()); + Log.info(geometryDescription.toString()); + for (BedrockBone bone : bones) { + Log.info(bone.toString()); + } + } + } From b691d5d6e53c560d21e9c610173f6743a1852959 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 27 Jul 2024 10:55:42 -0500 Subject: [PATCH 08/25] Fix a few bugs with mesh loading and rendering Mainly to do with accommodating empty bones --- .../engine/client/renderer/model/Mesh.java | 8 +++++ .../engine/client/renderer/model/Model.java | 25 ++++++++++++-- .../model/bedrock/BedrockModelData.java | 33 ++++++++++++++----- .../components/TransformationComponent.java | 4 +++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java index 808b968..272da6d 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java @@ -76,6 +76,13 @@ public static Mesh of(List meshes) { * Initializes this mesh to be rendered. Only needs to be called once */ public void init() { + + //Just in case it makes it to this point (it shouldn't) + if (vertices.length == 0) { + Log.error("Tried to initialize an empty mesh."); + return; + } + try (MemoryStack stack = MemoryStack.stackPush()) { vboIdList = new ArrayList<>(); @@ -123,6 +130,7 @@ public void init() { * Renders this mesh */ public void render() { + if (vertices.length == 0) return; if (!isInitialized()) init(); glBindVertexArray(getVaoId()); glDrawElements(GL_TRIANGLES, getNumIndices(), GL_UNSIGNED_INT, 0); diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index 6eb25fc..a279f41 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,6 +1,10 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import com.terminalvelocitycabbage.engine.debug.Log; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; @@ -38,15 +42,32 @@ public static class Part { List children; Mesh mesh; - public Part(String name, Part parent, Mesh mesh) { + boolean dirty; + + Vector3f pivotPoint; + Vector3f origin; + Quaternionf rotation; + Vector3f scale; + + public Part(String name, Part parent, Mesh mesh, Vector3f pivotPoint, Quaternionf rotation) { this.name = name; this.parent = parent; this.children = new ArrayList(); this.mesh = mesh; + + this.dirty = true; + + this.pivotPoint = pivotPoint; + this.rotation = rotation; + } + + public void updateMeshTransforms(Matrix4f transformationMatrix) { + if (!dirty) return; + //Log.info(); } public void render() { - mesh.render(); + if (mesh != null) mesh.render(); for (Part child : children) { child.render(); } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 5c8c395..559f7bf 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -13,7 +13,7 @@ import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; -import com.terminalvelocitycabbage.engine.util.tuples.Quartet; +import com.terminalvelocitycabbage.engine.util.tuples.Sextet; import org.joml.Quaternionf; import org.joml.Vector2f; import org.joml.Vector3f; @@ -336,7 +336,7 @@ private static BedrockCube[] parseCubes(Config config) { List cubes = config.get("cubes"); List cubesList = new ArrayList<>(); - cubes.forEach(cube -> cubesList.add(parseCube(cube))); + if (cubes != null) cubes.forEach(cube -> cubesList.add(parseCube(cube))); return cubesList.toArray(new BedrockCube[0]); } @@ -366,10 +366,10 @@ private static BedrockGeometryDescription parseGeometryDescription(Config config } - private static class StagedModelPart extends Quartet> { + private static class StagedModelPart extends Sextet, float[], float[]> { - public StagedModelPart(String name, String parentName, Mesh mesh) { - super(name, parentName, mesh, new ArrayList<>()); + public StagedModelPart(String name, String parentName, Mesh mesh, float[] bonePivot, float[] boneRotation) { + super(name, parentName, mesh, new ArrayList<>(), bonePivot, boneRotation); } public String getName() { @@ -387,6 +387,14 @@ public Mesh getMesh() { public List getChildren() { return getValue3(); } + + public float[] getBonePivot() { + return getValue4(); + } + + public float[] getBoneRotation() { + return getValue5(); + } } public Model toModel() { @@ -401,7 +409,7 @@ public Model toModel() { //Convert cubes to meshes meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); } - partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes))); + partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes), bone.pivot, bone.rotation)); } //Assign children to all staged model parts @@ -417,7 +425,11 @@ public Model toModel() { //Construct this model from these bones into model parts List parts = new ArrayList<>(); for (StagedModelPart part : roots) { - var newPart = new Model.Part(part.getName(), null, part.getMesh()); + var partPivot = new Vector3f(); + var partRotation = new Quaternionf(); + if (part.getBonePivot().length > 0) partPivot.add(part.getBonePivot()[0], part.getBonePivot()[1], part.getBonePivot()[2]); + if (part.getBoneRotation().length > 0) partRotation.rotateXYZ(part.getBoneRotation()[0], part.getBoneRotation()[1], part.getBoneRotation()[2]); + var newPart = new Model.Part(part.getName(), null, part.getMesh(), partPivot, partRotation); parts.add(newPart); addChildren(partsStaging, newPart); } @@ -428,7 +440,12 @@ public Model toModel() { private void addChildren(Map boneMap, Model.Part part) { var childrenNames = boneMap.get(part.getName()).getChildren(); for (String childName : childrenNames) { - var childPart = new Model.Part(childName, part, boneMap.get(childName).getMesh()); + var stagedPart = boneMap.get(childName); + var partPivot = new Vector3f(); + var partRotation = new Quaternionf(); + if (stagedPart.getBonePivot().length > 0) partPivot.add(stagedPart.getBonePivot()[0], stagedPart.getBonePivot()[1], stagedPart.getBonePivot()[2]); + if (stagedPart.getBoneRotation().length > 0) partRotation.rotateXYZ(stagedPart.getBoneRotation()[0], stagedPart.getBoneRotation()[1], stagedPart.getBoneRotation()[2]); + var childPart = new Model.Part(childName, part, stagedPart.getMesh(), partPivot, partRotation); part.addChild(childPart); addChildren(boneMap, childPart); } diff --git a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java index ca57eca..030706f 100644 --- a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java +++ b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/TransformationComponent.java @@ -27,6 +27,10 @@ public Vector3f getPosition() { return position; } + public TransformationComponent setPosition(Vector3f position) { + return setPosition(position.x, position.y, position.z); + } + public TransformationComponent setPosition(float x, float y, float z) { this.position.set(x, y, z); dirty = true; From 3baf900d4e191d540cc1ecac08afea4f2c4e4cba Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 27 Jul 2024 10:55:56 -0500 Subject: [PATCH 09/25] Add back easing functions from TVE1 --- .../engine/util/Easing.java | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java b/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java new file mode 100644 index 0000000..317337d --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java @@ -0,0 +1,261 @@ +package com.terminalvelocitycabbage.engine.util; + +import static java.lang.Math.*; +import static org.joml.Math.sin; + +public class Easing { + + private static final float PI = 3.1415f; + private static final float C1 = 1.70158f; + private static final float C2 = C1 * 1.525f; + private static final float C3 = C1 + 1; + private static final float C4 = (2 * PI) / 3f; + private static final float C5 = (2 * PI) / 4.5f; + private static final float N1 = 7.5625f; + private static final float D1 = 2.75f; + + public enum Direction { + + IN("in"), + OUT("out"), + IN_OUT("in_out"); + + private final String name; + + Direction(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public enum Function { + + LINEAR("linear"), + SIN("sin"), + QUADRATIC("quadratic"), + CUBIC("cubic"), + QUARTIC("quartic"), + QUINTIC("quintic"), + EXPONENTIAL("exponential"), + CIRCULAR("circular"), + BACK("back"), + ELASTIC("elsatic"), + BOUNCE("bounce"); + + private final String name; + + Function(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public static float lerp(float start, float end, float progress, Direction direction, Function function) { + return (start + (end - start) * ease(direction, function, progress)); + } + + public static float ease(Direction direction, Function function, float progress) { + return switch (direction) { + case IN -> easeIn(function, progress); + case OUT -> easeOut(function, progress); + case IN_OUT -> easeInOut(function, progress); + }; + } + + public static float easeIn(Function function, float progress) { + return switch (function) { + case LINEAR -> easeInLinear(progress); + case SIN -> easeInSin(progress); + case QUADRATIC -> easeInQuad(progress); + case CUBIC -> easeInCubic(progress); + case QUARTIC -> easeInQuart(progress); + case QUINTIC -> easeInQuint(progress); + case EXPONENTIAL -> easeInExpo(progress); + case CIRCULAR -> easeInCirc(progress); + case BACK -> easeInBack(progress); + case ELASTIC -> easeInElastic(progress); + case BOUNCE -> easeInBounce(progress); + }; + } + + public static float easeOut(Function function, float progress) { + return switch (function) { + case LINEAR -> easeOutLinear(progress); + case SIN -> easeOutSin(progress); + case QUADRATIC -> easeOutQuad(progress); + case CUBIC -> easeOutCubic(progress); + case QUARTIC -> easeOutQuart(progress); + case QUINTIC -> easeOutQuint(progress); + case EXPONENTIAL -> easeOutExpo(progress); + case CIRCULAR -> easeOutCirc(progress); + case BACK -> easeOutBack(progress); + case ELASTIC -> easeOutElastic(progress); + case BOUNCE -> easeOutBounce(progress); + }; + } + + public static float easeInOut(Function function, float progress) { + return switch (function) { + case LINEAR -> easeInOutLinear(progress); + case SIN -> easeInOutSin(progress); + case QUADRATIC -> easeInOutQuad(progress); + case CUBIC -> easeInOutCubic(progress); + case QUARTIC -> easeInOutQuart(progress); + case QUINTIC -> easeInOutQuint(progress); + case EXPONENTIAL -> easeInOutExpo(progress); + case CIRCULAR -> easeInOutCirc(progress); + case BACK -> easeInOutBack(progress); + case ELASTIC -> easeInOutElastic(progress); + case BOUNCE -> easeInOutBounce(progress); + }; + } + + public static float easeInLinear(float progress) { + return progress; + } + + public static float easeOutLinear(float progress) { + return progress; + } + + public static float easeInOutLinear(float progress) { + return progress; + } + + public static float easeInSin(float progress) { + return (float) (1 - cos((progress * PI) / 2f)); + } + + public static float easeOutSin(float progress) { + return sin((progress * PI) / 2f); + } + + public static float easeInOutSin(float progress) { + return (float) ((-cos(PI * progress) - 1) / 2f); + } + + public static float easeInQuad(float progress) { + return progress * progress; + } + + public static float easeOutQuad(float progress) { + return 1 - ((1 - progress) * (1 - progress)); + } + + public static float easeInOutQuad(float progress) { + return progress < 0.5 ? 2 * progress * progress : 1 - (float)pow((-2 * progress) + 2, 2) / 2f; + } + + public static float easeInCubic(float progress) { + return progress * progress * progress; + } + + public static float easeOutCubic(float progress) { + return 1 - ((1 - progress) * (1 - progress) * (1 - progress)); + } + + public static float easeInOutCubic(float progress) { + return progress < 0.5 ? 4 * progress * progress * progress : 1 - (float)pow((-2 * progress) + 2, 3) / 2f; + } + + public static float easeInQuart(float progress) { + return progress * progress * progress * progress; + } + + public static float easeOutQuart(float progress) { + return 1 - (float)pow(1 - progress, 4); + } + + public static float easeInOutQuart(float progress) { + return progress < 0.5 ? 8 * progress * progress * progress * progress : 1 - (float)pow(-2 * progress + 2, 4) / 2f; + } + + public static float easeInQuint(float progress) { + return progress * progress * progress * progress * progress; + } + + public static float easeOutQuint(float progress) { + return 1 - (float)pow(1 - progress, 5); + } + + public static float easeInOutQuint(float progress) { + return progress < 0.5 ? 16 * progress * progress * progress * progress * progress : 1 - (float)pow(-2 * progress + 2, 5) / 2f; + } + + public static float easeInExpo(float progress) { + return progress == 0 ? 0 : (float)pow(2, 10 * progress - 10); + } + + public static float easeOutExpo(float progress) { + return progress == 1 ? 1 : 1 - (float)pow(2, -10 * progress); + } + + public static float easeInOutExpo(float progress) { + return progress == 0 ? 0 : progress == 1 ? 1 : progress < 0.5 ? (float)pow(2, 20 * progress - 10) / 2 : (2 - (float)pow(2, -20 * progress + 10)) / 2; + } + + public static float easeInCirc(float progress) { + return 1 - (float)sqrt(1 - pow(progress, 2)); + } + + public static float easeOutCirc(float progress) { + return (float)sqrt(1 - pow(progress - 1, 2)); + } + + public static float easeInOutCirc(float progress) { + return progress < 0.5 ? (float)(1 - sqrt(1 - pow(2 * progress, 2))) / 2 : (float)(sqrt(1 - pow(-2 * progress + 2, 2)) + 1) / 2; + } + + public static float easeInBack(float progress) { + return C3 * progress * progress * progress - C1 * progress * progress; + } + + public static float easeOutBack(float progress) { + return (float)(1 + C3 * pow(progress - 1, 3) + C1 * pow(progress - 1, 2)); + } + + public static float easeInOutBack(float progress) { + return progress < 0.5 ? (float)(pow(2 * progress, 2) * ((C2 + 1) * 2 * progress - C2)) / 2 : (float)(pow(2 * progress - 2, 2) * ((C2 + 1) * (progress * 2 - 2) + C2) + 2) / 2; + } + + public static float easeInElastic(float progress) { + return progress == 0 ? 0 : progress == 1 ? 1 : (float)-pow(2, 10 * progress - 10) * (float)sin((progress * 10 - 10.75) * C4); + } + + public static float easeOutElastic(float progress) { + return progress == 0 ? 0 : progress == 1 ? 1 : (float)pow(2, -10 * progress) * (float)sin((progress * 10 - 0.75) * C4) + 1; + } + + public static float easeInOutElastic(float progress) { + return progress == 0 ? 0 : progress == 1 ? 1 : progress < 0.5 + ? (float) -(pow(2, 20 * progress - 10) * sin((20 * progress - 11.125) * C5)) / 2 + : (float) (pow(2, -20 * progress + 10) * sin((20 * progress - 11.125) * C5)) / 2 + 1; + } + + public static float easeInBounce(float progress) { + return 1 - easeOutBounce(1 - progress); + } + + public static float easeOutBounce(float progress) { + if (progress < 1 / D1) { + return N1 * progress * progress; + } else if (progress < 2 / D1) { + return N1 * (progress -= 1.5 / D1) * progress + 0.75f; + } else if (progress < 2.5 / D1) { + return N1 * (progress -= 2.25 / D1) * progress + 0.9375f; + } else { + return N1 * (progress -= 2.625 / D1) * progress + 0.984375f; + } + } + + public static float easeInOutBounce(float progress) { + return progress < 0.5 ? (1 - easeOutBounce(1 - 2 * progress)) / 2 : (1 + easeOutBounce(2 * progress - 1)) / 2; + } + +} From 6355d2955a07ac83de208df8ae92b4c58e19e459 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sat, 27 Jul 2024 13:29:59 -0500 Subject: [PATCH 10/25] Add basic bedrock animation loader --- .../bedrock/BedrockAnimationData.java | 170 ++++++++++++++++++ .../engine/util/ConfigUtils.java | 7 + .../engine/util/Easing.java | 16 ++ 3 files changed, 193 insertions(+) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java new file mode 100644 index 0000000..a9d4081 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -0,0 +1,170 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation.bedrock; + +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.ConfigFormat; +import com.electronwill.nightconfig.core.io.ConfigParser; +import com.electronwill.nightconfig.json.JsonFormat; +import com.github.zafarkhaja.semver.Version; +import com.terminalvelocitycabbage.engine.debug.Log; +import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; +import com.terminalvelocitycabbage.engine.util.ConfigUtils; +import com.terminalvelocitycabbage.engine.util.Easing; +import com.terminalvelocitycabbage.engine.util.tuples.Triplet; +import org.joml.Vector3f; + +import java.util.*; + +public class BedrockAnimationData { + + Version formatVersion; + Map animations; + + public BedrockAnimationData(Version formatVersion, Map animations) { + this.formatVersion = formatVersion; + this.animations = animations; + } + + public void print() { + Log.info(formatVersion); + for (Map.Entry entry : animations.entrySet()) { + Log.info(entry.getKey() + " " + entry.getValue()); + } + } + + public record BedrockBoneTransformationData( + float percentStage, + Vector3f simpleTransform, + Easing.Function easing + ) { + + @Override + public String toString() { + return "BedrockBoneTransformationData{" + + "percentStage=" + percentStage + + ", simpleTransform=" + simpleTransform + + ", easing=" + easing + + '}'; + } + } + + public record AnimationData ( + boolean loop, + float animationLength, + float startDelay, + float loopDelay, + //Bone name, positions, rotations, scale + Map, + List, + List>> boneTransformationData + ) { + + @Override + public String toString() { + return "AnimationData{" + + "loop=" + loop + + ", animationLength=" + animationLength + + ", startDelay=" + startDelay + + ", loopDelay=" + loopDelay + + ", boneTransformationData=" + boneTransformationData + + '}'; + } + } + + public static class Loader { + + static Version formatVersion; + static Map animations = new HashMap<>(); + + public static BedrockAnimationData loadAnimations(Resource animationsResource) { + + String resourceString = animationsResource.asString(); + + ConfigFormat jsonFormat = JsonFormat.fancyInstance(); + ConfigParser parser = jsonFormat.createParser(); + Config config = parser.parse(resourceString); + + formatVersion = Version.parse(config.get("format_version")); + + Config animationsConfig = config.get("animations"); + animationsConfig.valueMap().forEach((key, value) -> parseAnimationConfig(key, (Config) value, animations)); + + return new BedrockAnimationData(formatVersion, animations); + } + + private static void parseAnimationConfig(String animationName, Config animation, Map animationData) { + + AnimationData data = new AnimationData( + animation.get("loop"), + Float.parseFloat(animation.get("animation_length").toString()), + Float.parseFloat(animation.get("start_delay").toString()), + Float.parseFloat(animation.get("loop_delay").toString()), + parseBedrockBoneData(animation.get("bones")) + ); + + animationData.put(animationName, data); + } + + //bone name, Position, Rotation, Scale + private static Map, + List, + List>> parseBedrockBoneData(Config bones) { + + Map, + List, + List>> boneTransformationData = new HashMap<>(); + + bones.valueMap().forEach((key, value) -> { + + var bonesConfig = (Config) value; + boneTransformationData.put( + key, + new Triplet<>( + parseTransformationData(bonesConfig.get("position")), + parseTransformationData(bonesConfig.get("rotation")), + parseTransformationData(bonesConfig.get("scale")) + ) + ); + }); + + return boneTransformationData; + } + + //TODO parse molang + private static List parseTransformationData(Config transformationConfig) { + + if (transformationConfig == null) return null; + + List transformationData = new ArrayList<>(); + + transformationConfig.valueMap().forEach((key, value) -> { + + //The default when it's not interpolated + if (value.toString().startsWith("[")) { + transformationData.add(new BedrockBoneTransformationData( + Float.parseFloat(key), + ConfigUtils.numberListToVector3f((List) value), + Easing.Function.LINEAR + )); + } else { + transformationData.add(new BedrockBoneTransformationData( + Float.parseFloat(key), + ConfigUtils.numberListToVector3f(((Config) value).get("post")), //TODO pre + switch (((Config) value).get("lerp_mode").toString()) { + case "linear" -> Easing.Function.LINEAR; + case "catmullrom" -> Easing.Function.CIRCULAR; + case "step" -> Easing.Function.STEP; + default -> Easing.Function.LINEAR; + } + )); + } + }); + + return transformationData; + } + + } + +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java b/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java index febbb1c..a62ff03 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java @@ -1,10 +1,17 @@ package com.terminalvelocitycabbage.engine.util; +import org.joml.Vector3f; + import java.util.ArrayList; import java.util.List; public class ConfigUtils { + public static Vector3f numberListToVector3f(List list) { + float[] numberArray = numberListToFloatArray(list); + return new Vector3f(numberArray[0], numberArray[1], numberArray[2]); + } + public static float[] numberListToFloatArray(List list) { if (list == null) return new float[0]; List convertedList = new ArrayList<>(); diff --git a/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java b/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java index 317337d..6efa4da 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java @@ -34,6 +34,7 @@ public String getName() { public enum Function { LINEAR("linear"), + STEP("step"), SIN("sin"), QUADRATIC("quadratic"), CUBIC("cubic"), @@ -71,6 +72,7 @@ public static float ease(Direction direction, Function function, float progress) public static float easeIn(Function function, float progress) { return switch (function) { case LINEAR -> easeInLinear(progress); + case STEP -> easeInStep(progress); case SIN -> easeInSin(progress); case QUADRATIC -> easeInQuad(progress); case CUBIC -> easeInCubic(progress); @@ -87,6 +89,7 @@ public static float easeIn(Function function, float progress) { public static float easeOut(Function function, float progress) { return switch (function) { case LINEAR -> easeOutLinear(progress); + case STEP -> easeOutStep(progress); case SIN -> easeOutSin(progress); case QUADRATIC -> easeOutQuad(progress); case CUBIC -> easeOutCubic(progress); @@ -103,6 +106,7 @@ public static float easeOut(Function function, float progress) { public static float easeInOut(Function function, float progress) { return switch (function) { case LINEAR -> easeInOutLinear(progress); + case STEP -> easeInOutStep(progress); case SIN -> easeInOutSin(progress); case QUADRATIC -> easeInOutQuad(progress); case CUBIC -> easeInOutCubic(progress); @@ -128,6 +132,18 @@ public static float easeInOutLinear(float progress) { return progress; } + public static float easeInStep(float progress) { + return progress > 0 ? 1f : 0f; + } + + public static float easeOutStep(float progress) { + return progress > 0 ? 0f : 1f; + } + + public static float easeInOutStep(float progress) { + return progress > 0.5 ? 1f : 0f; + } + public static float easeInSin(float progress) { return (float) (1 - cos((progress * PI) / 2f)); } From 9e7107c30477aa8a2752950fb363825160141f22 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 28 Jul 2024 11:16:25 -0500 Subject: [PATCH 11/25] Most of the animation class started, need to simplify a lot still --- .../client/renderer/animation/Animation.java | 89 +++++++++++++++++++ .../animation/AnimationTransformation.java | 9 ++ .../engine/client/renderer/model/Model.java | 11 +-- .../model/bedrock/BedrockModelData.java | 1 + 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java new file mode 100644 index 0000000..086feb5 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -0,0 +1,89 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; +import org.joml.Matrix4f; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Animation { + + long time; //The time that this animation has been playing + long startDelay; + long animationLength; + long loopDelay; + long loopLength; + + //Map of boneName, + private final Map, List>> transformations; + + public Animation(Map, List>> transformations, long time, long startDelay, long animationLength, long loopDelay) { + this.transformations = transformations; + this.time = time; + this.startDelay = startDelay; + this.animationLength = animationLength; + this.loopDelay = loopDelay; + this.loopLength = animationLength + loopDelay; + } + + public void updateTime(long deltaTime) { + time += deltaTime; + } + + //Percentage through keyframe, the target transformation + //TODO also return in this the previous transforms + public Pair getCurrentTransform(String boneName) { + + //Get the current position in the looping keyframe + long currentTime = time - startDelay; + currentTime %= loopLength; + + //Get the current keyframe based on this position + int currentFrameIndex = 0; + + Pair, List> startsTransformsList = transformations.get(boneName); + List transformationStarts = startsTransformsList.getValue0(); + List animationTransformations = startsTransformsList.getValue1(); + for (int i = 0; i < transformationStarts.size(); i++) { + if (currentTime >= transformationStarts.get(i)) { + currentFrameIndex = i; + } + } + + //Get current percentage through this keyframe + float startTime = transformationStarts.get(currentFrameIndex); + float nextStartTime; + if (startsTransformsList.getValue0().size() > currentFrameIndex + 1) { + nextStartTime = startsTransformsList.getValue0().get(currentFrameIndex + 1); + } else { //If this is the last keyframe + nextStartTime = loopLength - startsTransformsList.getValue0().get(currentFrameIndex); + } + float percentComplete = currentTime / (nextStartTime - startTime); + var targetTransformation = animationTransformations.get(currentFrameIndex); + + return new Pair<>(percentComplete, targetTransformation); + } + + public Map getCurrentTransformations(Model model) { + + //Get all the current target transformations + //TODO change this to a map with a triplet including the previous transforms + Map> relevantTransforms = new HashMap<>(); + for (String boneName : transformations.keySet()) { + relevantTransforms.put(boneName, getCurrentTransform(boneName)); + } + + //Interpolate these targets with the previous keyframes values and the progress between these two + Map transforms = new HashMap<>(); + Matrix4f transformationMatrix = new Matrix4f(); + for (Model.Part part : model.getParts()) { + //TODO interpolate current transforms by progress compared to previous transforms + //TODO get default transforms of model part and add current transforms + //TODO create matrix4f from this + } + + return transforms; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java new file mode 100644 index 0000000..002f83c --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java @@ -0,0 +1,9 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import org.joml.Vector3f; + +public record AnimationTransformation( + Vector3f position, + Vector3f rotation, + Vector3f scale +) { } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index a279f41..ddd8312 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,8 +1,6 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; -import com.terminalvelocitycabbage.engine.debug.Log; -import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -35,6 +33,10 @@ public VertexFormat getFormat() { return format; } + public List getParts() { + return parts; + } + public static class Part { String name; @@ -61,11 +63,6 @@ public Part(String name, Part parent, Mesh mesh, Vector3f pivotPoint, Quaternion this.rotation = rotation; } - public void updateMeshTransforms(Matrix4f transformationMatrix) { - if (!dirty) return; - //Log.info(); - } - public void render() { if (mesh != null) mesh.render(); for (Part child : children) { diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 559f7bf..2fdcafc 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -348,6 +348,7 @@ private static BedrockCube parseCube(Config cube) { int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); float[] pivot = ConfigUtils.numberListToFloatArray(cube.get("pivot")); float[] rotation = ConfigUtils.numberListToFloatArray(cube.get("rotation")); + //TODO inflate return new BedrockCube(origin, size, uv, pivot, rotation); } From 478d3a3492446073e377e4e1e84376a6ffcca386 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 28 Jul 2024 16:53:08 -0500 Subject: [PATCH 12/25] Simplify animation code a lot --- .../client/renderer/animation/Animation.java | 97 +++++++++---------- .../animation/AnimationTransformation.java | 5 + .../client/renderer/animation/Keyframe.java | 50 ++++++++++ 3 files changed, 103 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index 086feb5..11e5162 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -1,7 +1,5 @@ package com.terminalvelocitycabbage.engine.client.renderer.animation; -import com.terminalvelocitycabbage.engine.client.renderer.model.Model; -import com.terminalvelocitycabbage.engine.util.tuples.Pair; import org.joml.Matrix4f; import java.util.HashMap; @@ -11,79 +9,80 @@ public class Animation { long time; //The time that this animation has been playing + long currentTime; long startDelay; long animationLength; long loopDelay; long loopLength; - //Map of boneName, - private final Map, List>> transformations; + //Bone name, keyframe + private final Map> keyframes; - public Animation(Map, List>> transformations, long time, long startDelay, long animationLength, long loopDelay) { - this.transformations = transformations; + public Animation(long time, long startDelay, long animationLength, long loopDelay, Map> keyframes) { this.time = time; this.startDelay = startDelay; this.animationLength = animationLength; this.loopDelay = loopDelay; this.loopLength = animationLength + loopDelay; + this.keyframes = keyframes; } public void updateTime(long deltaTime) { - time += deltaTime; - } - - //Percentage through keyframe, the target transformation - //TODO also return in this the previous transforms - public Pair getCurrentTransform(String boneName) { + time += deltaTime; //Get the current position in the looping keyframe - long currentTime = time - startDelay; + currentTime = time - startDelay; currentTime %= loopLength; + } - //Get the current keyframe based on this position - int currentFrameIndex = 0; - - Pair, List> startsTransformsList = transformations.get(boneName); - List transformationStarts = startsTransformsList.getValue0(); - List animationTransformations = startsTransformsList.getValue1(); - for (int i = 0; i < transformationStarts.size(); i++) { - if (currentTime >= transformationStarts.get(i)) { - currentFrameIndex = i; - } - } + //Percentage through keyframe, the target transformation + public Keyframe getCurrentKeyframe(String boneName) { - //Get current percentage through this keyframe - float startTime = transformationStarts.get(currentFrameIndex); - float nextStartTime; - if (startsTransformsList.getValue0().size() > currentFrameIndex + 1) { - nextStartTime = startsTransformsList.getValue0().get(currentFrameIndex + 1); - } else { //If this is the last keyframe - nextStartTime = loopLength - startsTransformsList.getValue0().get(currentFrameIndex); + Keyframe currentKeyframe = keyframes.get(boneName).getFirst(); + for (Keyframe keyframe : keyframes.get(boneName)) { + if (currentTime > keyframe.startTime) currentKeyframe = keyframe; } - float percentComplete = currentTime / (nextStartTime - startTime); - var targetTransformation = animationTransformations.get(currentFrameIndex); - return new Pair<>(percentComplete, targetTransformation); + return currentKeyframe; } - public Map getCurrentTransformations(Model model) { + //Bone name, transformations + public Map getCurrentTransformations() { - //Get all the current target transformations - //TODO change this to a map with a triplet including the previous transforms - Map> relevantTransforms = new HashMap<>(); - for (String boneName : transformations.keySet()) { - relevantTransforms.put(boneName, getCurrentTransform(boneName)); + Map currentTransformations = new HashMap<>(); + Keyframe currentKeyframe; + float currentKeyframeProgress; + for (String boneName : keyframes.keySet()) { + currentKeyframe = getCurrentKeyframe(boneName); + currentKeyframeProgress = getCurrentKeyframeProgress(currentKeyframe); + currentTransformations.put(boneName, currentKeyframe.getTransformationMatrix(currentKeyframeProgress)); } - //Interpolate these targets with the previous keyframes values and the progress between these two - Map transforms = new HashMap<>(); - Matrix4f transformationMatrix = new Matrix4f(); - for (Model.Part part : model.getParts()) { - //TODO interpolate current transforms by progress compared to previous transforms - //TODO get default transforms of model part and add current transforms - //TODO create matrix4f from this - } + return currentTransformations; + } - return transforms; + /** + * Return the value from 0 to 1 that defines the progress between KS and KE for this animation + * + * AS = animation start + * KS = keyframe start time + * CT = currentTime + * KE = keyframe end time + * AS KS CT KE + * |-----------|----x--|-----------... + * + * to make the math easier we should just subtract everything by KS + * KS = KS - KS (0) + * CT = CT - KS + * KE = KE - AS + * + * percentage is just CT / KE so + * (CT - KS) / (KE - AS) = percentage + * + * @param keyframe The keyframe we want the progress of + * @return the progress from 0 to 1 of this keyframe + */ + public float getCurrentKeyframeProgress(Keyframe keyframe) { + return (currentTime - keyframe.startTime) / (keyframe.endTime - keyframe.startTime); } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java index 002f83c..04b210e 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java @@ -2,6 +2,11 @@ import org.joml.Vector3f; +/** + * @param position The target position for this endpoint of a keyframe + * @param rotation The target rotation for this endpoint of a keyframe + * @param scale The target scale for this endpoint of a keyframe + */ public record AnimationTransformation( Vector3f position, Vector3f rotation, diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java new file mode 100644 index 0000000..e74e270 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java @@ -0,0 +1,50 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import com.terminalvelocitycabbage.engine.util.Easing; +import org.joml.Matrix4f; + +/** + * Represents a portion of a transformation between two target transformations. + */ +public class Keyframe { + + Easing.Function easingFunction; + AnimationTransformation startTransformation; + AnimationTransformation endTransformation; + float startTime; + float endTime; + + Matrix4f transformationMatrix; + + public Keyframe(Easing.Function easingFunction, AnimationTransformation startTransformation, AnimationTransformation endTransformation, float startTime, float endTime) { + this.easingFunction = easingFunction; + this.startTransformation = startTransformation; + this.endTransformation = endTransformation; + this.startTime = startTime; + this.endTime = endTime; + transformationMatrix = new Matrix4f(); + } + + public Matrix4f getTransformationMatrix(float progress) { + + transformationMatrix.identity(); + + transformationMatrix.scale( + Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().x) - (startTransformation.scale().x)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().y) - (startTransformation.scale().y)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().z) - (startTransformation.scale().z)) + ); + transformationMatrix.rotateXYZ( + Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().x) - (startTransformation.rotation().x)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().y) - (startTransformation.rotation().y)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().z) - (startTransformation.rotation().z)) + ); + transformationMatrix.translate( + Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().x) - (startTransformation.position().x)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().y) - (startTransformation.position().y)), + Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().z) - (startTransformation.position().z)) + ); + return transformationMatrix; + } + +} From a33348c23c6f4d489f260d5dc08647c5e63b713c Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 28 Jul 2024 18:46:09 -0500 Subject: [PATCH 13/25] Make keyframes only store a single transformation component --- .../client/renderer/animation/Animation.java | 69 +++++++++++++++---- .../animation/AnimationTransformation.java | 14 ---- .../client/renderer/animation/Keyframe.java | 42 ++++------- 3 files changed, 69 insertions(+), 56 deletions(-) delete mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index 11e5162..7dd3a8e 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -1,11 +1,17 @@ package com.terminalvelocitycabbage.engine.client.renderer.animation; +import com.terminalvelocitycabbage.engine.util.Easing; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; import org.joml.Matrix4f; +import org.joml.Vector3f; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe.Component.*; + public class Animation { long time; //The time that this animation has been playing @@ -18,8 +24,10 @@ public class Animation { //Bone name, keyframe private final Map> keyframes; - public Animation(long time, long startDelay, long animationLength, long loopDelay, Map> keyframes) { - this.time = time; + Matrix4f transformationMatrix; + + public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes) { + this.time = 0; this.startDelay = startDelay; this.animationLength = animationLength; this.loopDelay = loopDelay; @@ -36,26 +44,27 @@ public void updateTime(long deltaTime) { } //Percentage through keyframe, the target transformation - public Keyframe getCurrentKeyframe(String boneName) { + public List getCurrentKeyframes(String boneName) { + + List currentKeyFrames = new ArrayList<>(); - Keyframe currentKeyframe = keyframes.get(boneName).getFirst(); for (Keyframe keyframe : keyframes.get(boneName)) { - if (currentTime > keyframe.startTime) currentKeyframe = keyframe; + if (currentTime > keyframe.startTime && currentTime < keyframe.endTime) currentKeyFrames.add(keyframe); } - return currentKeyframe; + return currentKeyFrames; } //Bone name, transformations public Map getCurrentTransformations() { Map currentTransformations = new HashMap<>(); - Keyframe currentKeyframe; - float currentKeyframeProgress; + List> progressKeyframes = new ArrayList<>(); for (String boneName : keyframes.keySet()) { - currentKeyframe = getCurrentKeyframe(boneName); - currentKeyframeProgress = getCurrentKeyframeProgress(currentKeyframe); - currentTransformations.put(boneName, currentKeyframe.getTransformationMatrix(currentKeyframeProgress)); + for (Keyframe keyframe : getCurrentKeyframes(boneName)) { + progressKeyframes.add(new Pair<>(getKeyframeProgress( keyframe), keyframe)); + } + currentTransformations.put(boneName, getTransformationMatrices(progressKeyframes)); } return currentTransformations; @@ -82,7 +91,43 @@ public Map getCurrentTransformations() { * @param keyframe The keyframe we want the progress of * @return the progress from 0 to 1 of this keyframe */ - public float getCurrentKeyframeProgress(Keyframe keyframe) { + public float getKeyframeProgress(Keyframe keyframe) { return (currentTime - keyframe.startTime) / (keyframe.endTime - keyframe.startTime); } + + public Matrix4f getTransformationMatrices(List> keyframes) { + + transformationMatrix.identity(); + + //combine all keyframe transformations into one + Vector3f position = new Vector3f(); + Vector3f rotation = new Vector3f(); + Vector3f scale = new Vector3f(); + + for (Pair entry : keyframes) { + float progress = entry.getValue0(); + Keyframe keyframe = entry.getValue1(); + switch (keyframe.component) { + case POSITION -> interpolateComponent(position, progress, keyframe, POSITION); + case ROTATION -> interpolateComponent(position, progress, keyframe, ROTATION); + case SCALE -> interpolateComponent(position, progress, keyframe, SCALE); + } + } + + //Transform the matrix + transformationMatrix.scale(scale); + transformationMatrix.rotateXYZ(rotation); + transformationMatrix.translate(position); + + return transformationMatrix; + } + + private void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe, Keyframe.Component component) { + //TODO set to start transformation if end is null or 0 instead of calculating all 9 components of below if there is no need for any of them + transformation.add( + Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.x() - keyframe.startTransformation.x()), + Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()), + Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()) + ); + } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java deleted file mode 100644 index 04b210e..0000000 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationTransformation.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.terminalvelocitycabbage.engine.client.renderer.animation; - -import org.joml.Vector3f; - -/** - * @param position The target position for this endpoint of a keyframe - * @param rotation The target rotation for this endpoint of a keyframe - * @param scale The target scale for this endpoint of a keyframe - */ -public record AnimationTransformation( - Vector3f position, - Vector3f rotation, - Vector3f scale -) { } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java index e74e270..e91f0f1 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java @@ -1,50 +1,32 @@ package com.terminalvelocitycabbage.engine.client.renderer.animation; import com.terminalvelocitycabbage.engine.util.Easing; -import org.joml.Matrix4f; +import org.joml.Vector3f; /** - * Represents a portion of a transformation between two target transformations. + * Represents a portion of a transformation between two target transformations of a single component. */ public class Keyframe { + Component component; + Vector3f startTransformation; + Vector3f endTransformation; Easing.Function easingFunction; - AnimationTransformation startTransformation; - AnimationTransformation endTransformation; float startTime; float endTime; - Matrix4f transformationMatrix; - - public Keyframe(Easing.Function easingFunction, AnimationTransformation startTransformation, AnimationTransformation endTransformation, float startTime, float endTime) { - this.easingFunction = easingFunction; + public Keyframe(Component component, Vector3f startTransformation, Vector3f endTransformation, Easing.Function easingFunction, float startTime, float endTime) { + this.component = component; this.startTransformation = startTransformation; this.endTransformation = endTransformation; + this.easingFunction = easingFunction; this.startTime = startTime; this.endTime = endTime; - transformationMatrix = new Matrix4f(); } - public Matrix4f getTransformationMatrix(float progress) { - - transformationMatrix.identity(); - - transformationMatrix.scale( - Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().x) - (startTransformation.scale().x)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().y) - (startTransformation.scale().y)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.scale().z) - (startTransformation.scale().z)) - ); - transformationMatrix.rotateXYZ( - Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().x) - (startTransformation.rotation().x)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().y) - (startTransformation.rotation().y)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.rotation().z) - (startTransformation.rotation().z)) - ); - transformationMatrix.translate( - Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().x) - (startTransformation.position().x)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().y) - (startTransformation.position().y)), - Easing.easeInOut(easingFunction, progress) * ((endTransformation.position().z) - (startTransformation.position().z)) - ); - return transformationMatrix; + public enum Component { + POSITION, + ROTATION, + SCALE } - } From 01151aed0229994dd14eaa08d4d68bbb28160b28 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 28 Jul 2024 21:57:42 -0500 Subject: [PATCH 14/25] Parse most animation file data into keyframes directly This is to make converting easier in the future --- .../client/renderer/animation/Keyframe.java | 36 ++++ .../bedrock/BedrockAnimationData.java | 167 +++++++++++------- 2 files changed, 140 insertions(+), 63 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java index e91f0f1..991d30d 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java @@ -24,6 +24,42 @@ public Keyframe(Component component, Vector3f startTransformation, Vector3f endT this.endTime = endTime; } + public Component getComponent() { + return component; + } + + public Vector3f getStartTransformation() { + return startTransformation; + } + + public Vector3f getEndTransformation() { + return endTransformation; + } + + public Easing.Function getEasingFunction() { + return easingFunction; + } + + public float getStartTime() { + return startTime; + } + + public float getEndTime() { + return endTime; + } + + @Override + public String toString() { + return "Keyframe{" + + "component=" + component + + ", startTransformation=" + startTransformation + + ", endTransformation=" + endTransformation + + ", easingFunction=" + easingFunction + + ", startTime=" + startTime + + ", endTime=" + endTime + + '}'; + } + public enum Component { POSITION, ROTATION, diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java index a9d4081..3347a4b 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -5,11 +5,11 @@ import com.electronwill.nightconfig.core.io.ConfigParser; import com.electronwill.nightconfig.json.JsonFormat; import com.github.zafarkhaja.semver.Version; +import com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe; import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; import com.terminalvelocitycabbage.engine.util.Easing; -import com.terminalvelocitycabbage.engine.util.tuples.Triplet; import org.joml.Vector3f; import java.util.*; @@ -31,21 +31,41 @@ public void print() { } } - public record BedrockBoneTransformationData( - float percentStage, - Vector3f simpleTransform, - Easing.Function easing - ) { - - @Override - public String toString() { - return "BedrockBoneTransformationData{" + - "percentStage=" + percentStage + - ", simpleTransform=" + simpleTransform + - ", easing=" + easing + - '}'; - } - } +// public List toAnimations() { +// +// List convertedAnimations = new ArrayList<>(); +// Map> keyframes; +// List keyframeList = new ArrayList<>(); +// for (Map.Entry entry : animations.entrySet()) { +// var name = entry.getKey(); +// var data = entry.getValue(); +// +// //Convert bedrock transformation data into keyframes +// keyframes = new HashMap<>(); +// keyframeList.clear(); +// +// for (Map.Entry> boneData : data.boneKeyframes.entrySet()) { +// keyframeList.add(new Keyframe( +// null, +// null, +// null, +// null +// )); +// } +// keyframes.put(name, keyframeList); +// +// Animation animation = new Animation( +// Math.round(data.startDelay * 1000f), +// Math.round(data.animationLength * 1000f), +// Math.round(data.loopDelay * 1000f), +// keyframes +// ); +// +// convertedAnimations.add(animation); +// } +// +// return convertedAnimations; +// } public record AnimationData ( boolean loop, @@ -53,10 +73,7 @@ public record AnimationData ( float startDelay, float loopDelay, //Bone name, positions, rotations, scale - Map, - List, - List>> boneTransformationData + Map> boneKeyframes ) { @Override @@ -66,7 +83,7 @@ public String toString() { ", animationLength=" + animationLength + ", startDelay=" + startDelay + ", loopDelay=" + loopDelay + - ", boneTransformationData=" + boneTransformationData + + ", boneKeyframes=" + boneKeyframes + '}'; } } @@ -80,6 +97,8 @@ public static BedrockAnimationData loadAnimations(Resource animationsResource) { String resourceString = animationsResource.asString(); + //Not sure where best to have this call, but it is needed to be called sometime before reading animations. + Config.setInsertionOrderPreserved(true); ConfigFormat jsonFormat = JsonFormat.fancyInstance(); ConfigParser parser = jsonFormat.createParser(); Config config = parser.parse(resourceString); @@ -94,75 +113,97 @@ public static BedrockAnimationData loadAnimations(Resource animationsResource) { private static void parseAnimationConfig(String animationName, Config animation, Map animationData) { + var animationLength = Float.parseFloat(animation.get("animation_length").toString()); AnimationData data = new AnimationData( animation.get("loop"), - Float.parseFloat(animation.get("animation_length").toString()), + animationLength, Float.parseFloat(animation.get("start_delay").toString()), Float.parseFloat(animation.get("loop_delay").toString()), - parseBedrockBoneData(animation.get("bones")) + parseBedrockBoneData(animation.get("bones"), animationLength) ); animationData.put(animationName, data); } //bone name, Position, Rotation, Scale - private static Map, - List, - List>> parseBedrockBoneData(Config bones) { + private static Map> parseBedrockBoneData(Config bones, float animationLength) { - Map, - List, - List>> boneTransformationData = new HashMap<>(); + Map> boneKeyframeMap = new HashMap<>(); bones.valueMap().forEach((key, value) -> { var bonesConfig = (Config) value; - boneTransformationData.put( - key, - new Triplet<>( - parseTransformationData(bonesConfig.get("position")), - parseTransformationData(bonesConfig.get("rotation")), - parseTransformationData(bonesConfig.get("scale")) - ) - ); + List keyframes = new ArrayList<>(); + + keyframes.addAll(parseTransformationData(Keyframe.Component.POSITION, bonesConfig.get("position"), animationLength)); + keyframes.addAll(parseTransformationData(Keyframe.Component.ROTATION, bonesConfig.get("rotation"), animationLength)); + keyframes.addAll(parseTransformationData(Keyframe.Component.SCALE, bonesConfig.get("scale"), animationLength)); + + boneKeyframeMap.put(key, keyframes); }); - return boneTransformationData; + return boneKeyframeMap; } //TODO parse molang - private static List parseTransformationData(Config transformationConfig) { - - if (transformationConfig == null) return null; - - List transformationData = new ArrayList<>(); - - transformationConfig.valueMap().forEach((key, value) -> { - - //The default when it's not interpolated - if (value.toString().startsWith("[")) { - transformationData.add(new BedrockBoneTransformationData( - Float.parseFloat(key), - ConfigUtils.numberListToVector3f((List) value), - Easing.Function.LINEAR - )); + private static List parseTransformationData(Keyframe.Component component, Config transformationConfig, float endTime) { + + if (transformationConfig == null) return Collections.emptyList(); + + List keyframes = new ArrayList<>(); + int iteration = 0; + for (Map.Entry entry : transformationConfig.valueMap().entrySet()) { + //Easier entry names + String endTimeSeconds = entry.getKey(); + Object keyframeConfigOrTransformation = entry.getValue(); + + //The previous keyframes final transformation to use used as this keyframe's start transformation + Vector3f previousKeyframeEndTransformation; + //The previous keyframes end time to be used as this keyframes start time + float previousKeyframeEndTime; + //If this is the first iteration we assume this is the first keyframe + if (iteration == 0) { + //Some default values for the first keyframe (this keyframe gets deleted at the end since it's just setup) + previousKeyframeEndTransformation = new Vector3f(); + previousKeyframeEndTime = 0f; } else { - transformationData.add(new BedrockBoneTransformationData( - Float.parseFloat(key), - ConfigUtils.numberListToVector3f(((Config) value).get("post")), //TODO pre - switch (((Config) value).get("lerp_mode").toString()) { - case "linear" -> Easing.Function.LINEAR; + //Get the previous keyframe and some info about it to use for this keyframe + var previousKeyframe = keyframes.get(iteration - 1); + previousKeyframeEndTransformation = previousKeyframe.getEndTransformation(); + previousKeyframeEndTime = previousKeyframe.getEndTime(); + } + var endTimeMillis = Float.parseFloat(endTimeSeconds) * 1000; + + //Create the keyframes + if (keyframeConfigOrTransformation.toString().startsWith("[")) { //linear is simplified out in bbmodel + keyframes.add(new Keyframe( + component, + previousKeyframeEndTransformation, + ConfigUtils.numberListToVector3f((List) keyframeConfigOrTransformation), + Easing.Function.LINEAR, + previousKeyframeEndTime, + endTimeMillis + )); + } else { //Usually Non-linear interpolation + keyframes.add(new Keyframe( + component, + previousKeyframeEndTransformation, + ConfigUtils.numberListToVector3f(((Config) keyframeConfigOrTransformation).get("post")), //TODO pre + switch (((Config) keyframeConfigOrTransformation).get("lerp_mode").toString()) { case "catmullrom" -> Easing.Function.CIRCULAR; case "step" -> Easing.Function.STEP; default -> Easing.Function.LINEAR; - } + }, + previousKeyframeEndTime, + endTimeMillis )); } - }); + iteration++; + } + //The first keyframe is really only to set the stage for the second keyframe to start in the right place + keyframes.removeFirst(); - return transformationData; + return keyframes; } } From d44c633033145bcb6eeee43f0cd039424cf715ec Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Sun, 28 Jul 2024 22:07:38 -0500 Subject: [PATCH 15/25] Probably bedrock animation data to animation converter --- .../bedrock/BedrockAnimationData.java | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java index 3347a4b..1cb5458 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -5,6 +5,7 @@ import com.electronwill.nightconfig.core.io.ConfigParser; import com.electronwill.nightconfig.json.JsonFormat; import com.github.zafarkhaja.semver.Version; +import com.terminalvelocitycabbage.engine.client.renderer.animation.Animation; import com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe; import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; @@ -17,6 +18,7 @@ public class BedrockAnimationData { Version formatVersion; + //Animation name, Animation data Map animations; public BedrockAnimationData(Version formatVersion, Map animations) { @@ -31,48 +33,44 @@ public void print() { } } -// public List toAnimations() { -// -// List convertedAnimations = new ArrayList<>(); -// Map> keyframes; -// List keyframeList = new ArrayList<>(); -// for (Map.Entry entry : animations.entrySet()) { -// var name = entry.getKey(); -// var data = entry.getValue(); -// -// //Convert bedrock transformation data into keyframes -// keyframes = new HashMap<>(); -// keyframeList.clear(); -// -// for (Map.Entry> boneData : data.boneKeyframes.entrySet()) { -// keyframeList.add(new Keyframe( -// null, -// null, -// null, -// null -// )); -// } -// keyframes.put(name, keyframeList); -// -// Animation animation = new Animation( -// Math.round(data.startDelay * 1000f), -// Math.round(data.animationLength * 1000f), -// Math.round(data.loopDelay * 1000f), -// keyframes -// ); -// -// convertedAnimations.add(animation); -// } -// -// return convertedAnimations; -// } + public Map toAnimations() { + + Map convertedAnimations = new HashMap<>(); + Map> keyframes; + for (Map.Entry entry : animations.entrySet()) { + var animationName = entry.getKey(); + var data = entry.getValue(); + + //Convert bedrock transformation data into keyframes + keyframes = new HashMap<>(); + + for (Map.Entry> boneData : data.boneKeyframes.entrySet()) { + + var boneName = boneData.getKey(); + var boneKeyframes = boneData.getValue(); + + keyframes.put(boneName, boneKeyframes); + } + + Animation animation = new Animation( + Math.round(data.startDelay * 1000f), + Math.round(data.animationLength * 1000f), + Math.round(data.loopDelay * 1000f), + keyframes + ); + + convertedAnimations.put(animationName, animation); + } + + return convertedAnimations; + } public record AnimationData ( boolean loop, float animationLength, float startDelay, float loopDelay, - //Bone name, positions, rotations, scale + //Bone name, keyframes Map> boneKeyframes ) { From 3907ca42c8a9a7667cca20a91d43505de92cdc42 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 29 Jul 2024 19:17:58 -0500 Subject: [PATCH 16/25] Generate bone indexes on models --- .../renderer/elements/VertexAttribute.java | 3 +- .../engine/client/renderer/model/Model.java | 7 +- .../engine/client/renderer/model/Vertex.java | 10 ++ .../model/bedrock/BedrockModelData.java | 108 +++++++----------- 4 files changed, 57 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexAttribute.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexAttribute.java index ee4fb2d..2013511 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexAttribute.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexAttribute.java @@ -6,7 +6,8 @@ public enum VertexAttribute { UV("uv", 2, false), XYZ_NORMAL("normal", 3, true), RGBA_COLOR("color_rgba", 4, false), - RGB_COLOR("color_rgb", 3, false); + RGB_COLOR("color_rgb", 3, false), + BONE_INDEX("bone_index", 1, false); private final String name; private final int components; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index ddd8312..ab23fe3 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -43,6 +43,7 @@ public static class Part { Part parent; List children; Mesh mesh; + int boneIndex; boolean dirty; @@ -51,16 +52,18 @@ public static class Part { Quaternionf rotation; Vector3f scale; - public Part(String name, Part parent, Mesh mesh, Vector3f pivotPoint, Quaternionf rotation) { + public Part(String name, Part parent, Mesh mesh, Vector3f pivotPoint, Quaternionf rotation, int boneIndex) { this.name = name; this.parent = parent; - this.children = new ArrayList(); + this.children = new ArrayList<>(); this.mesh = mesh; this.dirty = true; this.pivotPoint = pivotPoint; this.rotation = rotation; + + this.boneIndex = boneIndex; } public void render() { diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java index 41b0694..8f93317 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Vertex.java @@ -93,6 +93,16 @@ public Vertex setRGBAColor(float r, float g, float b, float a) { return this; } + /** + * @param index The Index of the bone that this vertex should be transformed from + * @return This vertex with updated index data + */ + public Vertex setBoneIndex(int index) { + var offset = format.getOffset(VertexAttribute.BONE_INDEX); + data[offset] = index; + return this; + } + /** * Gets sub-data from the vertex data by component * @param element The element for which the data is to be retrieved diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 2fdcafc..0ebcdeb 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -13,7 +13,6 @@ import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; -import com.terminalvelocitycabbage.engine.util.tuples.Sextet; import org.joml.Quaternionf; import org.joml.Vector2f; import org.joml.Vector3f; @@ -27,6 +26,7 @@ public class BedrockModelData { .addElement(VertexAttribute.XYZ_POSITION) .addElement(VertexAttribute.XYZ_NORMAL) .addElement(VertexAttribute.UV) + .addElement(VertexAttribute.BONE_INDEX) .build(); Version formatVersion; @@ -91,7 +91,7 @@ public BedrockCube(float[] origin, int[] size, int[] uv, float[] pivot, float[] * * @return A mesh represented from this cube */ - public Mesh toMesh(int textureWidth, int textureHeight) { + public Mesh toMesh(int textureWidth, int textureHeight, int boneIndex) { //Vertex positions //TODO start all at the origin, rotate them, then move them to their size to apply rotations to vertex positions @@ -162,30 +162,30 @@ public Mesh toMesh(int textureWidth, int textureHeight) { Vector2f uv14 = new Vector2f(uv[0] + size[2] + size[0] + size[2] + size[0], uv[1] + size[2] + size[1]).div(textureWidth, textureHeight); //North Face - Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv6); - Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv5); - Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv12); - Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv11); - Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv5); - Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv4); - Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv11); - Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv10); - Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv9); - Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv8); - Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv14); - Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv13); - Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv8); - Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(westNormal).setUV(uv6); - Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv13); - Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv12); - Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv2); - Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv1); - Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv6); - Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv5); - Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv7); - Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv6); - Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv3); - Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv2); + Vertex northTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(northNormal).setUV(uv6).setBoneIndex(boneIndex); + Vertex northTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(northNormal).setUV(uv5).setBoneIndex(boneIndex); + Vertex northBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(northNormal).setUV(uv12).setBoneIndex(boneIndex); + Vertex northBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(northNormal).setUV(uv11).setBoneIndex(boneIndex); + Vertex eastTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(eastNormal).setUV(uv5).setBoneIndex(boneIndex); + Vertex eastTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(eastNormal).setUV(uv4).setBoneIndex(boneIndex); + Vertex eastBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(eastNormal).setUV(uv11).setBoneIndex(boneIndex); + Vertex eastBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(eastNormal).setUV(uv10).setBoneIndex(boneIndex); + Vertex southTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(southNormal).setUV(uv9).setBoneIndex(boneIndex); + Vertex southTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(southNormal).setUV(uv8).setBoneIndex(boneIndex); + Vertex southBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(southNormal).setUV(uv14).setBoneIndex(boneIndex); + Vertex southBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(southNormal).setUV(uv13).setBoneIndex(boneIndex); + Vertex westTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(westNormal).setUV(uv8).setBoneIndex(boneIndex); + Vertex westTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(westNormal).setUV(uv6).setBoneIndex(boneIndex); + Vertex westBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(westNormal).setUV(uv13).setBoneIndex(boneIndex); + Vertex westBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(westNormal).setUV(uv12).setBoneIndex(boneIndex); + Vertex topTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swtPos).setXYZNormal(upNormal).setUV(uv2).setBoneIndex(boneIndex); + Vertex topTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(setPos).setXYZNormal(upNormal).setUV(uv1).setBoneIndex(boneIndex); + Vertex topBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwtPos).setXYZNormal(upNormal).setUV(uv6).setBoneIndex(boneIndex); + Vertex topBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(netPos).setXYZNormal(upNormal).setUV(uv5).setBoneIndex(boneIndex); + Vertex bottomTL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nebPos).setXYZNormal(downNormal).setUV(uv7).setBoneIndex(boneIndex); + Vertex bottomTR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(nwbPos).setXYZNormal(downNormal).setUV(uv6).setBoneIndex(boneIndex); + Vertex bottomBL = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(sebPos).setXYZNormal(downNormal).setUV(uv3).setBoneIndex(boneIndex); + Vertex bottomBR = new Vertex(BEDROCK_VERTEX_FORMAT).setXYZPosition(swbPos).setXYZNormal(downNormal).setUV(uv2).setBoneIndex(boneIndex); // 0 1 2 3 // 4 5 6 7 @@ -367,36 +367,7 @@ private static BedrockGeometryDescription parseGeometryDescription(Config config } - private static class StagedModelPart extends Sextet, float[], float[]> { - - public StagedModelPart(String name, String parentName, Mesh mesh, float[] bonePivot, float[] boneRotation) { - super(name, parentName, mesh, new ArrayList<>(), bonePivot, boneRotation); - } - - public String getName() { - return getValue0(); - } - - public String getParentName() { - return getValue1(); - } - - public Mesh getMesh() { - return getValue2(); - } - - public List getChildren() { - return getValue3(); - } - - public float[] getBonePivot() { - return getValue4(); - } - - public float[] getBoneRotation() { - return getValue5(); - } - } + private record StagedModelPart(String name, String parentName, List children, Mesh mesh, float[] bonePivot, float[] boneRotation, int boneIndex) { } public Model toModel() { @@ -404,20 +375,21 @@ public Model toModel() { Map partsStaging = new HashMap<>(); //Loop through all bones to get staging data for a model part - for (BedrockBone bone : bones) { + for (int i = 0; i < bones.length; i++) { + BedrockBone bone = bones[i]; List meshes = new ArrayList<>(); for (BedrockCube cube : bone.cubes) { //Convert cubes to meshes - meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight)); + meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight, i)); } - partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, Mesh.of(meshes), bone.pivot, bone.rotation)); + partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, new ArrayList<>(), Mesh.of(meshes), bone.pivot, bone.rotation, i)); } //Assign children to all staged model parts List roots = new ArrayList<>(); for (StagedModelPart part : partsStaging.values()) { - if (!part.getParentName().equals("none")) { - partsStaging.get(part.getParentName()).getChildren().add(part.getName()); + if (!part.parentName().equals("none")) { + partsStaging.get(part.parentName()).children().add(part.name()); } else { roots.add(part); } @@ -428,9 +400,9 @@ public Model toModel() { for (StagedModelPart part : roots) { var partPivot = new Vector3f(); var partRotation = new Quaternionf(); - if (part.getBonePivot().length > 0) partPivot.add(part.getBonePivot()[0], part.getBonePivot()[1], part.getBonePivot()[2]); - if (part.getBoneRotation().length > 0) partRotation.rotateXYZ(part.getBoneRotation()[0], part.getBoneRotation()[1], part.getBoneRotation()[2]); - var newPart = new Model.Part(part.getName(), null, part.getMesh(), partPivot, partRotation); + if (part.bonePivot().length > 0) partPivot.add(part.bonePivot()[0], part.bonePivot()[1], part.bonePivot()[2]); + if (part.boneRotation().length > 0) partRotation.rotateXYZ(part.boneRotation()[0], part.boneRotation()[1], part.boneRotation()[2]); + var newPart = new Model.Part(part.name(), null, part.mesh(), partPivot, partRotation, part.boneIndex()); parts.add(newPart); addChildren(partsStaging, newPart); } @@ -439,14 +411,14 @@ public Model toModel() { } private void addChildren(Map boneMap, Model.Part part) { - var childrenNames = boneMap.get(part.getName()).getChildren(); + var childrenNames = boneMap.get(part.getName()).children(); for (String childName : childrenNames) { var stagedPart = boneMap.get(childName); var partPivot = new Vector3f(); var partRotation = new Quaternionf(); - if (stagedPart.getBonePivot().length > 0) partPivot.add(stagedPart.getBonePivot()[0], stagedPart.getBonePivot()[1], stagedPart.getBonePivot()[2]); - if (stagedPart.getBoneRotation().length > 0) partRotation.rotateXYZ(stagedPart.getBoneRotation()[0], stagedPart.getBoneRotation()[1], stagedPart.getBoneRotation()[2]); - var childPart = new Model.Part(childName, part, stagedPart.getMesh(), partPivot, partRotation); + if (stagedPart.bonePivot().length > 0) partPivot.add(stagedPart.bonePivot()[0], stagedPart.bonePivot()[1], stagedPart.bonePivot()[2]); + if (stagedPart.boneRotation().length > 0) partRotation.rotateXYZ(stagedPart.boneRotation()[0], stagedPart.boneRotation()[1], stagedPart.boneRotation()[2]); + var childPart = new Model.Part(childName, part, stagedPart.mesh(), partPivot, partRotation, stagedPart.boneIndex()); part.addChild(childPart); addChildren(boneMap, childPart); } From 612053398f414c278c4e5a600e08f5655d50d219 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 29 Jul 2024 19:26:16 -0500 Subject: [PATCH 17/25] Generate and pass a bone index map to the model and animations --- .../engine/client/renderer/animation/Animation.java | 4 +++- .../renderer/animation/bedrock/BedrockAnimationData.java | 6 ++++-- .../engine/client/renderer/model/Model.java | 9 ++++++++- .../client/renderer/model/bedrock/BedrockModelData.java | 4 +++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index 7dd3a8e..d0fe1c5 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -23,16 +23,18 @@ public class Animation { //Bone name, keyframe private final Map> keyframes; + private final Map boneIndexMap; Matrix4f transformationMatrix; - public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes) { + public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes, Map boneIndexMap) { this.time = 0; this.startDelay = startDelay; this.animationLength = animationLength; this.loopDelay = loopDelay; this.loopLength = animationLength + loopDelay; this.keyframes = keyframes; + this.boneIndexMap = boneIndexMap; } public void updateTime(long deltaTime) { diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java index 1cb5458..a491855 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -7,6 +7,7 @@ import com.github.zafarkhaja.semver.Version; import com.terminalvelocitycabbage.engine.client.renderer.animation.Animation; import com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe; +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; import com.terminalvelocitycabbage.engine.util.ConfigUtils; @@ -33,7 +34,7 @@ public void print() { } } - public Map toAnimations() { + public Map toAnimations(Model model) { Map convertedAnimations = new HashMap<>(); Map> keyframes; @@ -56,7 +57,8 @@ public Map toAnimations() { Math.round(data.startDelay * 1000f), Math.round(data.animationLength * 1000f), Math.round(data.loopDelay * 1000f), - keyframes + keyframes, + model.getBoneIndexMap() ); convertedAnimations.put(animationName, animation); diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index ab23fe3..d979209 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -6,15 +6,18 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; public class Model { VertexFormat format; List parts; + Map boneIndexMap; - public Model(VertexFormat format, List parts) { + public Model(VertexFormat format, List parts, Map boneIndexMap) { this.format = format; this.parts = parts; + this.boneIndexMap = boneIndexMap; } public void render() { @@ -37,6 +40,10 @@ public List getParts() { return parts; } + public Map getBoneIndexMap() { + return boneIndexMap; + } + public static class Part { String name; diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 0ebcdeb..dcc6547 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -375,6 +375,7 @@ public Model toModel() { Map partsStaging = new HashMap<>(); //Loop through all bones to get staging data for a model part + Map boneIndexMap = new HashMap<>(); for (int i = 0; i < bones.length; i++) { BedrockBone bone = bones[i]; List meshes = new ArrayList<>(); @@ -383,6 +384,7 @@ public Model toModel() { meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight, i)); } partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, new ArrayList<>(), Mesh.of(meshes), bone.pivot, bone.rotation, i)); + boneIndexMap.put(bone.name, i); } //Assign children to all staged model parts @@ -407,7 +409,7 @@ public Model toModel() { addChildren(partsStaging, newPart); } - return new Model(BEDROCK_VERTEX_FORMAT, parts); + return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap); } private void addChildren(Map boneMap, Model.Part part) { From f739b05419232b5aaa3a36f95d47f651f26e79ca Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 29 Jul 2024 20:07:58 -0500 Subject: [PATCH 18/25] Convert to MemoryUtil in models to solve out of memory errors --- .../engine/client/renderer/model/Mesh.java | 60 +++++++++++-------- .../engine/client/renderer/model/Model.java | 17 +++++- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java index 272da6d..b92dc90 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java @@ -5,7 +5,7 @@ import com.terminalvelocitycabbage.engine.debug.Log; import com.terminalvelocitycabbage.engine.util.ArrayUtils; import org.lwjgl.opengl.GL30; -import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -83,46 +83,54 @@ public void init() { return; } - try (MemoryStack stack = MemoryStack.stackPush()) { - vboIdList = new ArrayList<>(); + vboIdList = new ArrayList<>(); - vaoId = glGenVertexArrays(); - glBindVertexArray(vaoId); + vaoId = glGenVertexArrays(); + glBindVertexArray(vaoId); - int vboId; + int vboId; - //Create attribute vbos and upload the data from the mesh - int attributeIndex = 0; - //Loop through all the attributes for the format of this mesh - for (VertexAttribute attribute : format.getAttributes()) { - //Create a vbo for this attribute data - vboId = glGenBuffers(); - vboIdList.add(vboId); - //Get the attribute data from this mesh - var attributeData = getDataOfType(attribute); - FloatBuffer attributeBuffer = stack.callocFloat(attributeData.length); + //Create attribute vbos and upload the data from the mesh + int attributeIndex = 0; + //Loop through all the attributes for the format of this mesh + for (VertexAttribute attribute : format.getAttributes()) { + //Create a vbo for this attribute data + vboId = glGenBuffers(); + vboIdList.add(vboId); + //Get the attribute data from this mesh + var attributeData = getDataOfType(attribute); + FloatBuffer attributeBuffer = MemoryUtil.memCallocFloat(attributeData.length); + try { attributeBuffer.put(0, attributeData); //Upload this data to OpenGL glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, attributeBuffer, GL_STATIC_DRAW); glEnableVertexAttribArray(attributeIndex); glVertexAttribPointer(attributeIndex, attribute.getNumComponents(), GL_FLOAT, attribute.isNormalized(), 0, 0); - attributeIndex++; + } finally { + MemoryUtil.memFree(attributeBuffer); } + attributeIndex++; + } - //Create the index buffers for mesh rendering - vboId = glGenBuffers(); - //Upload the data to the buffer and opengl - vboIdList.add(vboId); - IntBuffer indicesBuffer = stack.callocInt(indices.length); + //Create the index buffers for mesh rendering + vboId = glGenBuffers(); + //Upload the data to the buffer and opengl + vboIdList.add(vboId); + IntBuffer indicesBuffer = MemoryUtil.memAllocInt(indices.length); + try { indicesBuffer.put(0, indices); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW); - - //Bind all buffers - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + } finally { + MemoryUtil.memFree(indicesBuffer); } + + //Bind all buffers + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + //Mark this mesh as initialized, so we don't have to do this twice initialized = true; } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index d979209..63b809b 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -13,16 +13,29 @@ public class Model { VertexFormat format; List parts; Map boneIndexMap; + boolean compiledMesh; + Mesh mesh; + + public Model(VertexFormat format, List parts, Map boneIndexMap, Mesh mesh) { + this(format, parts, boneIndexMap); + this.mesh = mesh; + this.compiledMesh = true; + } public Model(VertexFormat format, List parts, Map boneIndexMap) { this.format = format; this.parts = parts; this.boneIndexMap = boneIndexMap; + this.compiledMesh = false; } public void render() { - for (Part part : parts) { - part.render(); + if (compiledMesh) { + mesh.render(); + } else { + for (Part part : parts) { + part.render(); + } } } From da178f6154266dfab091de30f042007a430b2e5a Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 29 Jul 2024 20:25:16 -0500 Subject: [PATCH 19/25] Fix a couple of bugs with meshes --- .../engine/client/renderer/elements/VertexFormat.java | 7 +++++++ .../engine/client/renderer/model/Mesh.java | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexFormat.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexFormat.java index 92363dc..55004d3 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexFormat.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/elements/VertexFormat.java @@ -71,6 +71,13 @@ public boolean hasComponent(VertexAttribute vertexAttribute) { return attributes.contains(vertexAttribute); } + @Override + public String toString() { + return "VertexFormat{" + + "attributes=" + attributes + + '}'; + } + /** * A required utility for building a vertex format, constructs all the strides and internal data for you */ diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java index b92dc90..dadf73d 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Mesh.java @@ -43,12 +43,14 @@ public static Mesh of(List meshes) { int vertexCount = 0; int indicesCount = 0; for (Mesh mesh : meshes) { - if (format1 == null) format1 = mesh.getFormat(); - if (format1 != mesh.getFormat()) { - Log.crash("Tried to construct a mesh with mismatched formats"); + if (format1 != null) { + if (format1 != mesh.getFormat()) { + Log.crash("Tried to construct a mesh with mismatched formats: " + format1 + ", " + mesh.getFormat()); + } } vertexCount += mesh.getNumVertices(); indicesCount += mesh.getNumIndices(); + format1 = mesh.getFormat(); } //Combine all vertex data and index data @@ -66,7 +68,7 @@ public static Mesh of(List meshes) { vertices[vertexIndex] = vertex; vertexIndex++; } - indexOffset += vertexIndex; + indexOffset += mesh.getNumVertices(); } return new Mesh(format1, vertices, indices); From d9cce03b8cd5cc691c8259e3884eb45a6a9d84dd Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Mon, 29 Jul 2024 20:25:34 -0500 Subject: [PATCH 20/25] Add option to bedrock loader to compile to single mesh --- .../renderer/model/bedrock/BedrockModelData.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index dcc6547..0cf166f 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -369,7 +369,7 @@ private static BedrockGeometryDescription parseGeometryDescription(Config config private record StagedModelPart(String name, String parentName, List children, Mesh mesh, float[] bonePivot, float[] boneRotation, int boneIndex) { } - public Model toModel() { + public Model toModel(boolean compileMesh) { //The information needed to create a model part extracted from all bones Map partsStaging = new HashMap<>(); @@ -409,7 +409,19 @@ public Model toModel() { addChildren(partsStaging, newPart); } - return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap); + if (compileMesh) { + List meshesToCompile = new ArrayList<>(); + partsStaging.values().forEach((stagedModelPart) -> { + if (stagedModelPart.mesh().getFormat() != null) { + meshesToCompile.add(stagedModelPart.mesh()); + } else { + Log.info("null format: " + stagedModelPart.name()); + } + }); + return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap, Mesh.of(meshesToCompile)); + } else { + return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap); + } } private void addChildren(Map boneMap, Model.Part part) { From 1eaf7ec7da5bd36834a8cd4e0121bc4351eac43a Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Tue, 30 Jul 2024 21:34:06 -0500 Subject: [PATCH 21/25] It runs but is not correct --- .../client/renderer/animation/Animation.java | 108 +++++++++++++----- .../animation/AnimationController.java | 46 ++++++++ .../bedrock/BedrockAnimationData.java | 9 +- .../client/renderer/shader/Uniform.java | 14 +++ .../ModelAnimationControllerComponent.java | 22 ++++ 5 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java create mode 100644 src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelAnimationControllerComponent.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index d0fe1c5..8008766 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -10,39 +10,94 @@ import java.util.List; import java.util.Map; -import static com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe.Component.*; - public class Animation { long time; //The time that this animation has been playing long currentTime; - long startDelay; - long animationLength; - long loopDelay; - long loopLength; + final long startDelay; + final long animationLength; + final long loopDelay; + final long loopLength; + + //Status + boolean isPlaying; + int playsRemaining; //-1 if indefinite + boolean startFromZero; //Bone name, keyframe private final Map> keyframes; - private final Map boneIndexMap; - Matrix4f transformationMatrix; + final Matrix4f transformationMatrix; - public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes, Map boneIndexMap) { + public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes) { this.time = 0; + this.currentTime = 0; this.startDelay = startDelay; this.animationLength = animationLength; this.loopDelay = loopDelay; this.loopLength = animationLength + loopDelay; + this.isPlaying = false; + this.playsRemaining = 0; + this.startFromZero = false; this.keyframes = keyframes; - this.boneIndexMap = boneIndexMap; + this.transformationMatrix = new Matrix4f(); } - public void updateTime(long deltaTime) { + public void update(long deltaTime) { - time += deltaTime; //Get the current position in the looping keyframe - currentTime = time - startDelay; - currentTime %= loopLength; + if (!isPlaying) { + + time = startFromZero ? 0 : time + deltaTime; + currentTime = time - startDelay; + + if (playsRemaining != -1 && currentTime > animationLength) { + playsRemaining = Math.max(playsRemaining - 1, 0); + } + + if (playsRemaining == 0) { + currentTime = animationLength + startDelay; + } else { + currentTime %= loopLength; + } + } + + startFromZero = false; + } + + public void play() { + play(true); + } + + public void play(boolean startOver) { + this.startFromZero = startOver; + isPlaying = true; + playsRemaining = 1; + } + + public void repeat(int timesToRepeat) { + isPlaying = true; + playsRemaining = timesToRepeat; + } + + public void loop() { + isPlaying = true; + playsRemaining = -1; + } + + public void pause() { + isPlaying = false; + } + + public void resume() { + isPlaying = true; + } + + public void stop() { + isPlaying = false; + playsRemaining = 0; + time = 0; + currentTime = 0; } //Percentage through keyframe, the target transformation @@ -58,10 +113,11 @@ public List getCurrentKeyframes(String boneName) { } //Bone name, transformations + Map currentTransformations = new HashMap<>(); + List> progressKeyframes = new ArrayList<>(); public Map getCurrentTransformations() { - - Map currentTransformations = new HashMap<>(); - List> progressKeyframes = new ArrayList<>(); + currentTransformations.clear(); + progressKeyframes.clear(); for (String boneName : keyframes.keySet()) { for (Keyframe keyframe : getCurrentKeyframes(boneName)) { progressKeyframes.add(new Pair<>(getKeyframeProgress( keyframe), keyframe)); @@ -110,9 +166,9 @@ public Matrix4f getTransformationMatrices(List> keyframes) float progress = entry.getValue0(); Keyframe keyframe = entry.getValue1(); switch (keyframe.component) { - case POSITION -> interpolateComponent(position, progress, keyframe, POSITION); - case ROTATION -> interpolateComponent(position, progress, keyframe, ROTATION); - case SCALE -> interpolateComponent(position, progress, keyframe, SCALE); + case POSITION -> interpolateComponent(position, progress, keyframe); + case ROTATION -> interpolateComponent(rotation, progress, keyframe); + case SCALE -> interpolateComponent(scale, progress, keyframe); } } @@ -124,12 +180,10 @@ public Matrix4f getTransformationMatrices(List> keyframes) return transformationMatrix; } - private void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe, Keyframe.Component component) { - //TODO set to start transformation if end is null or 0 instead of calculating all 9 components of below if there is no need for any of them - transformation.add( - Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.x() - keyframe.startTransformation.x()), - Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()), - Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()) - ); + private void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe) { + var xTransform = keyframe.endTransformation.x() == 0 ? keyframe.startTransformation.x() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.x() - keyframe.startTransformation.x()); + var yTransform = keyframe.endTransformation.y() == 0 ? keyframe.startTransformation.y() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()); + var zTransform = keyframe.endTransformation.z() == 0 ? keyframe.startTransformation.z() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.z() - keyframe.startTransformation.z()); + transformation.add(xTransform, yTransform, zTransform); } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java new file mode 100644 index 0000000..6f05ee8 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java @@ -0,0 +1,46 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import org.joml.Matrix4f; + +import java.util.HashMap; +import java.util.Map; + +public class AnimationController { + + //TODO replace string with identifier once animation registry exists + Map animations; + private final Map boneIndexMap; + Map boneTransformations; + + public AnimationController(Map animations, Map boneIndexMap) { + this.animations = animations; + this.boneIndexMap = boneIndexMap; + boneTransformations = new HashMap<>(); + boneIndexMap.values().forEach(boneIndex -> boneTransformations.put(boneIndex, new Matrix4f())); + } + + public void update(long deltaTime) { + animations.values().forEach(animation -> animation.update(deltaTime)); + } + + public Animation getAnimation(String animationName) { + return animations.get(animationName); + } + + public void stopAll() { + animations.values().forEach(Animation::stop); + } + + public Map getBoneTransformations() { + boneTransformations.values().forEach(Matrix4f::identity); + //Loop through all animations to get their contribution to the bone transformations + for (Animation animation : animations.values()) { + //Get this animation's transformation matrix and add it to the resultant transformation matrix to effectively combine these transformations + //TODO verify, likely a wrong assumption + animation.getCurrentTransformations().forEach( + (boneName, boneTransformation) -> boneTransformations.get(boneIndexMap.get(boneName)).add(boneTransformation) + ); + } + return boneTransformations; + } +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java index a491855..4356e94 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -6,6 +6,7 @@ import com.electronwill.nightconfig.json.JsonFormat; import com.github.zafarkhaja.semver.Version; import com.terminalvelocitycabbage.engine.client.renderer.animation.Animation; +import com.terminalvelocitycabbage.engine.client.renderer.animation.AnimationController; import com.terminalvelocitycabbage.engine.client.renderer.animation.Keyframe; import com.terminalvelocitycabbage.engine.client.renderer.model.Model; import com.terminalvelocitycabbage.engine.debug.Log; @@ -34,7 +35,7 @@ public void print() { } } - public Map toAnimations(Model model) { + public AnimationController toAnimationController(Model model) { Map convertedAnimations = new HashMap<>(); Map> keyframes; @@ -57,14 +58,14 @@ public Map toAnimations(Model model) { Math.round(data.startDelay * 1000f), Math.round(data.animationLength * 1000f), Math.round(data.loopDelay * 1000f), - keyframes, - model.getBoneIndexMap() + keyframes + ); convertedAnimations.put(animationName, animation); } - return convertedAnimations; + return new AnimationController(convertedAnimations, model.getBoneIndexMap()); } public record AnimationData ( diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/shader/Uniform.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/shader/Uniform.java index 1ddfe39..44f452f 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/shader/Uniform.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/shader/Uniform.java @@ -4,6 +4,8 @@ import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; +import java.util.Map; + import static org.lwjgl.opengl.GL20.*; public class Uniform { @@ -44,6 +46,18 @@ public void setUniform(Matrix4f matrix4f) { } } + public void setArrayUniform(Matrix4f matrix4f, int index) { + try (MemoryStack stack = MemoryStack.stackPush()) { + glUniformMatrix4fv(glGetUniformLocation(shaderProgramId, uniformName + "[" + index + "]"), false, matrix4f.get(stack.mallocFloat(16))); + } + } + + public void setUniforms(Map boneTransformations) { + for (Map.Entry entry : boneTransformations.entrySet()) { + setArrayUniform(entry.getValue(), entry.getKey()); + } + } + /** * @return the name of this uniform */ diff --git a/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelAnimationControllerComponent.java b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelAnimationControllerComponent.java new file mode 100644 index 0000000..dd86dd8 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/templates/ecs/components/ModelAnimationControllerComponent.java @@ -0,0 +1,22 @@ +package com.terminalvelocitycabbage.templates.ecs.components; + +import com.terminalvelocitycabbage.engine.client.renderer.animation.AnimationController; +import com.terminalvelocitycabbage.engine.ecs.Component; + +public class ModelAnimationControllerComponent implements Component { + + AnimationController animationController; + + @Override + public void setDefaults() { + animationController = null; + } + + public AnimationController getAnimationController() { + return animationController; + } + + public void setAnimationController(AnimationController animationController) { + this.animationController = animationController; + } +} From 25032c226e1e63dd488ebb165c20db306fe6f39f Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Wed, 31 Jul 2024 19:21:32 -0500 Subject: [PATCH 22/25] Fix a few issues with animation rendering --- .../client/renderer/animation/Animation.java | 30 ++++------- .../animation/AnimationController.java | 51 ++++++++++++++----- .../engine/client/renderer/model/Model.java | 4 ++ 3 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index 8008766..fbe86ab 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -2,7 +2,7 @@ import com.terminalvelocitycabbage.engine.util.Easing; import com.terminalvelocitycabbage.engine.util.tuples.Pair; -import org.joml.Matrix4f; +import com.terminalvelocitycabbage.engine.util.tuples.Triplet; import org.joml.Vector3f; import java.util.ArrayList; @@ -27,8 +27,6 @@ public class Animation { //Bone name, keyframe private final Map> keyframes; - final Matrix4f transformationMatrix; - public Animation(long startDelay, long animationLength, long loopDelay, Map> keyframes) { this.time = 0; this.currentTime = 0; @@ -40,7 +38,6 @@ public Animation(long startDelay, long animationLength, long loopDelay, Map getCurrentKeyframes(String boneName) { } //Bone name, transformations - Map currentTransformations = new HashMap<>(); + Map> currentTransformations = new HashMap<>(); List> progressKeyframes = new ArrayList<>(); - public Map getCurrentTransformations() { + public Map> getCurrentTransformations() { currentTransformations.clear(); progressKeyframes.clear(); for (String boneName : keyframes.keySet()) { for (Keyframe keyframe : getCurrentKeyframes(boneName)) { - progressKeyframes.add(new Pair<>(getKeyframeProgress( keyframe), keyframe)); + progressKeyframes.add(new Pair<>(getKeyframeProgress(keyframe), keyframe)); } - currentTransformations.put(boneName, getTransformationMatrices(progressKeyframes)); + currentTransformations.put(boneName, getCurrentTransforms(progressKeyframes)); } return currentTransformations; @@ -149,18 +146,16 @@ public Map getCurrentTransformations() { * @param keyframe The keyframe we want the progress of * @return the progress from 0 to 1 of this keyframe */ - public float getKeyframeProgress(Keyframe keyframe) { + float getKeyframeProgress(Keyframe keyframe) { return (currentTime - keyframe.startTime) / (keyframe.endTime - keyframe.startTime); } - public Matrix4f getTransformationMatrices(List> keyframes) { - - transformationMatrix.identity(); + Triplet getCurrentTransforms(List> keyframes) { //combine all keyframe transformations into one Vector3f position = new Vector3f(); Vector3f rotation = new Vector3f(); - Vector3f scale = new Vector3f(); + Vector3f scale = new Vector3f(1); for (Pair entry : keyframes) { float progress = entry.getValue0(); @@ -172,15 +167,10 @@ public Matrix4f getTransformationMatrices(List> keyframes) } } - //Transform the matrix - transformationMatrix.scale(scale); - transformationMatrix.rotateXYZ(rotation); - transformationMatrix.translate(position); - - return transformationMatrix; + return new Triplet<>(position, rotation, scale); } - private void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe) { + void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe) { var xTransform = keyframe.endTransformation.x() == 0 ? keyframe.startTransformation.x() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.x() - keyframe.startTransformation.x()); var yTransform = keyframe.endTransformation.y() == 0 ? keyframe.startTransformation.y() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.y() - keyframe.startTransformation.y()); var zTransform = keyframe.endTransformation.z() == 0 ? keyframe.startTransformation.z() : Easing.easeInOut(keyframe.easingFunction, progress) * (keyframe.endTransformation.z() - keyframe.startTransformation.z()); diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java index 6f05ee8..9fc34c1 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java @@ -1,6 +1,9 @@ package com.terminalvelocitycabbage.engine.client.renderer.animation; +import com.terminalvelocitycabbage.engine.util.tuples.Triplet; import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import java.util.HashMap; import java.util.Map; @@ -10,17 +13,48 @@ public class AnimationController { //TODO replace string with identifier once animation registry exists Map animations; private final Map boneIndexMap; - Map boneTransformations; + Map> boneTransformations; //Pos, Rot, Scale + Map boneTransformationMatrices; public AnimationController(Map animations, Map boneIndexMap) { this.animations = animations; this.boneIndexMap = boneIndexMap; boneTransformations = new HashMap<>(); - boneIndexMap.values().forEach(boneIndex -> boneTransformations.put(boneIndex, new Matrix4f())); + boneTransformationMatrices = new HashMap<>(); + boneIndexMap.values().forEach(boneIndex -> boneTransformations.put(boneIndex, new Triplet<>(new Vector3f(), new Vector3f(), new Vector3f(1)))); + boneIndexMap.values().forEach(boneIndex -> boneTransformationMatrices.put(boneIndex, new Matrix4f())); } public void update(long deltaTime) { - animations.values().forEach(animation -> animation.update(deltaTime)); + //Reset all transformations from last frame + boneTransformations.values().forEach(vector3fVector3fVector3fTriplet -> { + vector3fVector3fVector3fTriplet.getValue0().zero(); + vector3fVector3fVector3fTriplet.getValue1().zero(); + vector3fVector3fVector3fTriplet.getValue2().set(1); + }); + boneTransformationMatrices.values().forEach(Matrix4f::identity); + + //Loop through all animations update them and get their contribution to the bone transformations + for (Animation animation : animations.values()) { + animation.update(deltaTime); + //Get this animation's transformations add them together + animation.getCurrentTransformations().forEach( + (boneName, boneTransformation) -> { + boneTransformations.get(boneIndexMap.get(boneName)).getValue0().add(boneTransformation.getValue0()); + boneTransformations.get(boneIndexMap.get(boneName)).getValue1().add(boneTransformation.getValue1()); + boneTransformations.get(boneIndexMap.get(boneName)).getValue2().mul(boneTransformation.getValue2()); + } + ); + } + //Convert all of these updated and combined transformations into a single transformation matrix for each bone + for (int i = 0; i < boneTransformationMatrices.size(); i++) { + var boneTransformation = boneTransformations.get(i); + var eulerRotation = boneTransformation.getValue1(); + var rotation = new Quaternionf().rotateXYZ(eulerRotation.x, eulerRotation.y, eulerRotation.z); + boneTransformationMatrices.get(i) + .identity() + .translationRotateScale(boneTransformation.getValue0(), rotation, boneTransformation.getValue2()); + } } public Animation getAnimation(String animationName) { @@ -32,15 +66,6 @@ public void stopAll() { } public Map getBoneTransformations() { - boneTransformations.values().forEach(Matrix4f::identity); - //Loop through all animations to get their contribution to the bone transformations - for (Animation animation : animations.values()) { - //Get this animation's transformation matrix and add it to the resultant transformation matrix to effectively combine these transformations - //TODO verify, likely a wrong assumption - animation.getCurrentTransformations().forEach( - (boneName, boneTransformation) -> boneTransformations.get(boneIndexMap.get(boneName)).add(boneTransformation) - ); - } - return boneTransformations; + return boneTransformationMatrices; } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index 63b809b..a77bd34 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -53,6 +53,10 @@ public List getParts() { return parts; } + public Mesh getMesh() { + return mesh; + } + public Map getBoneIndexMap() { return boneIndexMap; } From 3652774f471c30d8f245418aeb18484e5bec8bbd Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Wed, 14 Aug 2024 20:34:34 -0500 Subject: [PATCH 23/25] A few animation fixes, still not perfect --- .../client/renderer/animation/Animation.java | 2 +- .../animation/AnimationController.java | 2 +- .../client/renderer/shader/Uniform.java | 21 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index fbe86ab..8bb9ad4 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -43,7 +43,7 @@ public Animation(long startDelay, long animationLength, long loopDelay, Map boneTransformations) { - for (Map.Entry entry : boneTransformations.entrySet()) { - setArrayUniform(entry.getValue(), entry.getKey()); + //TODO using memory stack here may result in an overflow of stack space, might need to change to not use this + try (MemoryStack stack = MemoryStack.stackPush()) { + int length = boneTransformations != null ? boneTransformations.size() : 0; + FloatBuffer fb = stack.mallocFloat(16 * length); + for (int i = 0; i < length; i++) { + boneTransformations.get(i).get(16 * i, fb); + } + glUniformMatrix4fv(uniformLocation, false, fb); } } From f0c0aa0fc1865af48edbc25284d05905bc934133 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Fri, 23 Aug 2024 16:19:54 -0500 Subject: [PATCH 24/25] Simplify bedrock loader (#9) * Simplify bedrock loader so much that it doesn't work * A few more simplifications + fix incorrect default transformations --- .../client/renderer/animation/Animation.java | 8 +- .../animation/AnimationController.java | 61 +++++++---- .../animation/TransformationSnapshot.java | 6 ++ .../bedrock/BedrockAnimationData.java | 4 +- .../engine/client/renderer/model/Model.java | 101 ++++++------------ .../model/bedrock/BedrockModelData.java | 90 ++++++---------- 6 files changed, 115 insertions(+), 155 deletions(-) create mode 100644 src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/TransformationSnapshot.java diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java index 8bb9ad4..28dcb61 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -110,9 +110,9 @@ public List getCurrentKeyframes(String boneName) { } //Bone name, transformations - Map> currentTransformations = new HashMap<>(); + Map currentTransformations = new HashMap<>(); List> progressKeyframes = new ArrayList<>(); - public Map> getCurrentTransformations() { + public Map getCurrentTransformations() { currentTransformations.clear(); progressKeyframes.clear(); for (String boneName : keyframes.keySet()) { @@ -150,7 +150,7 @@ float getKeyframeProgress(Keyframe keyframe) { return (currentTime - keyframe.startTime) / (keyframe.endTime - keyframe.startTime); } - Triplet getCurrentTransforms(List> keyframes) { + TransformationSnapshot getCurrentTransforms(List> keyframes) { //combine all keyframe transformations into one Vector3f position = new Vector3f(); @@ -167,7 +167,7 @@ Triplet getCurrentTransforms(List(position, rotation, scale); + return new TransformationSnapshot(position, rotation, scale); } void interpolateComponent(Vector3f transformation, float progress, Keyframe keyframe) { diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java index a2c5456..b4d5ea3 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java @@ -1,6 +1,6 @@ package com.terminalvelocitycabbage.engine.client.renderer.animation; -import com.terminalvelocitycabbage.engine.util.tuples.Triplet; +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -11,26 +11,31 @@ public class AnimationController { //TODO replace string with identifier once animation registry exists - Map animations; - private final Map boneIndexMap; - Map> boneTransformations; //Pos, Rot, Scale - Map boneTransformationMatrices; + private final Map animations; + private final Map bonesMap; + private final Map boneIndexMap; + private final Map boneTransformations; + private final Map boneTransformationMatrices; - public AnimationController(Map animations, Map boneIndexMap) { + public AnimationController(Map animations, Map bonesMap) { this.animations = animations; - this.boneIndexMap = boneIndexMap; + this.bonesMap = bonesMap; + boneIndexMap = new HashMap<>(); boneTransformations = new HashMap<>(); boneTransformationMatrices = new HashMap<>(); - boneIndexMap.values().forEach(boneIndex -> boneTransformations.put(boneIndex, new Triplet<>(new Vector3f(), new Vector3f(), new Vector3f(1)))); - boneIndexMap.values().forEach(boneIndex -> boneTransformationMatrices.put(boneIndex, new Matrix4f())); + bonesMap.values().forEach(bone -> { + boneIndexMap.put(bone.getBoneIndex(), bone); + boneTransformations.put(bone.getBoneIndex(), new TransformationSnapshot(new Vector3f(), new Vector3f(), new Vector3f(1))); + boneTransformationMatrices.put(bone.getBoneIndex(), new Matrix4f()); + }); } - public void update(long deltaTime) { + public void update(long deltaTime, Model model) { //Reset all transformations from last frame - boneTransformations.values().forEach(vector3fVector3fVector3fTriplet -> { - vector3fVector3fVector3fTriplet.getValue0().zero(); - vector3fVector3fVector3fTriplet.getValue1().zero(); - vector3fVector3fVector3fTriplet.getValue2().set(1); + boneTransformations.values().forEach(transformationSnapshot -> { + transformationSnapshot.position().zero(); + transformationSnapshot.rotation().zero(); + transformationSnapshot.scale().set(1); }); boneTransformationMatrices.values().forEach(Matrix4f::identity); @@ -40,20 +45,30 @@ public void update(long deltaTime) { //Get this animation's transformations add them together animation.getCurrentTransformations().forEach( (boneName, boneTransformation) -> { - boneTransformations.get(boneIndexMap.get(boneName)).getValue0().add(boneTransformation.getValue0()); - boneTransformations.get(boneIndexMap.get(boneName)).getValue1().add(boneTransformation.getValue1()); - boneTransformations.get(boneIndexMap.get(boneName)).getValue2().mul(boneTransformation.getValue2()); + var transformation = boneTransformations.get(bonesMap.get(boneName).getBoneIndex()); + transformation.position().add(boneTransformation.position()); + transformation.rotation().add(boneTransformation.rotation()); + transformation.scale().mul(boneTransformation.scale()); } ); } //Convert all of these updated and combined transformations into a single transformation matrix for each bone - for (int i = 0; i < boneTransformationMatrices.size(); i++) { - var boneTransformation = boneTransformations.get(i); - var eulerRotation = boneTransformation.getValue1(); - var rotation = new Quaternionf().rotateXYZ((float) Math.toRadians(eulerRotation.x), (float) Math.toRadians(eulerRotation.y), (float) Math.toRadians(eulerRotation.z)); - boneTransformationMatrices.get(i) + for (Map.Entry entry : boneIndexMap.entrySet()) { + + var index = entry.getKey(); + var bone = entry.getValue(); + + var boneTransformation = boneTransformations.get(index); + var eulerRotation = boneTransformation.rotation(); + var rotation = new Quaternionf().rotateXYZ( + (float) Math.toRadians(eulerRotation.x), + (float) Math.toRadians(eulerRotation.y), + (float) Math.toRadians(eulerRotation.z) + ); + boneTransformationMatrices.get(index) .identity() - .translationRotateScale(boneTransformation.getValue0(), rotation, boneTransformation.getValue2()); + .translationRotateScale(boneTransformation.position(), rotation, boneTransformation.scale()); + //.translate(bone.getOffset()); } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/TransformationSnapshot.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/TransformationSnapshot.java new file mode 100644 index 0000000..8c19250 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/TransformationSnapshot.java @@ -0,0 +1,6 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import org.joml.Vector3f; + +public record TransformationSnapshot(Vector3f position, Vector3f rotation, Vector3f scale) { +} diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java index 4356e94..5edc7b9 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -65,7 +65,7 @@ public AnimationController toAnimationController(Model model) { convertedAnimations.put(animationName, animation); } - return new AnimationController(convertedAnimations, model.getBoneIndexMap()); + return new AnimationController(convertedAnimations, model.getBones()); } public record AnimationData ( @@ -173,7 +173,7 @@ private static List parseTransformationData(Keyframe.Component compone previousKeyframeEndTransformation = previousKeyframe.getEndTransformation(); previousKeyframeEndTime = previousKeyframe.getEndTime(); } - var endTimeMillis = Float.parseFloat(endTimeSeconds) * 1000; + var endTimeMillis = Float.parseFloat(endTimeSeconds) * 1000f; //Create the keyframes if (keyframeConfigOrTransformation.toString().startsWith("[")) { //linear is simplified out in bbmodel diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index a77bd34..3688087 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,55 +1,42 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import com.terminalvelocitycabbage.engine.debug.Log; import org.joml.Quaternionf; import org.joml.Vector3f; -import java.util.ArrayList; -import java.util.List; import java.util.Map; public class Model { VertexFormat format; - List parts; - Map boneIndexMap; - boolean compiledMesh; + Map parts; Mesh mesh; - public Model(VertexFormat format, List parts, Map boneIndexMap, Mesh mesh) { - this(format, parts, boneIndexMap); - this.mesh = mesh; - this.compiledMesh = true; - } - - public Model(VertexFormat format, List parts, Map boneIndexMap) { + public Model(VertexFormat format, Map bones, Mesh mesh) { this.format = format; - this.parts = parts; - this.boneIndexMap = boneIndexMap; - this.compiledMesh = false; + this.parts = bones; + this.parts.values().forEach(bone -> bone.model = this); + this.mesh = mesh; } public void render() { - if (compiledMesh) { - mesh.render(); - } else { - for (Part part : parts) { - part.render(); - } - } + mesh.render(); } public void cleanup() { - for (Part part : parts) { - part.cleanup(); - } + mesh.cleanup(); } public VertexFormat getFormat() { return format; } - public List getParts() { + public Bone getBone(String partName) { + return parts.get(partName); + } + + public Map getBones() { return parts; } @@ -57,71 +44,53 @@ public Mesh getMesh() { return mesh; } - public Map getBoneIndexMap() { - return boneIndexMap; - } + public static class Bone { - public static class Part { + Model model; String name; - Part parent; - List children; - Mesh mesh; + String parentName; int boneIndex; boolean dirty; - Vector3f pivotPoint; - Vector3f origin; + Vector3f offset; Quaternionf rotation; Vector3f scale; - public Part(String name, Part parent, Mesh mesh, Vector3f pivotPoint, Quaternionf rotation, int boneIndex) { + public Bone(String name, String parentName, Vector3f pivotPoint, Quaternionf rotation, Vector3f scale, int boneIndex) { this.name = name; - this.parent = parent; - this.children = new ArrayList<>(); - this.mesh = mesh; + this.parentName = parentName; this.dirty = true; - this.pivotPoint = pivotPoint; + this.offset = pivotPoint; this.rotation = rotation; + this.scale = scale; this.boneIndex = boneIndex; } - public void render() { - if (mesh != null) mesh.render(); - for (Part child : children) { - child.render(); - } + public String getParentName() { + return parentName; } - public void cleanup() { - mesh.cleanup(); - for (Part child : children) { - child.cleanup(); - } - } - - public void addChild(Part child) { - children.add(child); - } - - public Part getParent() { - return parent; - } - - public List getChildren() { - return children; + public String getName() { + return name; } - public Mesh getMesh() { - return mesh; + //TODO cache this offset so we don't query every frame, do this on model instantiation + public Vector3f getOffset() { + Vector3f retOffset = new Vector3f(offset); + var parent = model.getBone(parentName); + if (parent != null) { + retOffset.add(parent.getOffset(), retOffset); + } + return retOffset; } - public String getName() { - return name; + public int getBoneIndex() { + return boneIndex; } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 0cf166f..9ef48b0 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -46,13 +46,15 @@ private static class BedrockCube { int[] uv; float[] pivot; float[] rotation; + float[] scale; - public BedrockCube(float[] origin, int[] size, int[] uv, float[] pivot, float[] rotation) { + public BedrockCube(float[] origin, int[] size, int[] uv, float[] pivot, float[] rotation, float[] scale) { this.origin = origin; this.size = size; this.uv = uv; this.pivot = pivot; this.rotation = rotation; + this.scale = scale; } /** @@ -233,13 +235,15 @@ private static class BedrockBone { String parent; float[] pivot; float[] rotation; + float[] scale; BedrockCube[] cubes; - public BedrockBone(String name, String parent, float[] pivot, float[] rotation, BedrockCube[] cubes) { + public BedrockBone(String name, String parent, float[] pivot, float[] rotation, float[] scale, BedrockCube[] cubes) { this.name = name; this.parent = parent; this.pivot = pivot; this.rotation = rotation; + this.scale = scale; this.cubes = cubes; } @@ -250,6 +254,7 @@ public String toString() { ", parent='" + parent + '\'' + ", pivot=" + Arrays.toString(pivot) + ", rotation=" + Arrays.toString(rotation) + + ", scale=" + Arrays.toString(scale) + ", cubes=" + Arrays.toString(cubes) + '}'; } @@ -327,8 +332,9 @@ private static BedrockBone parseBone(Config config) { String parent = config.getOrElse("parent", "none"); float[] pivot = ConfigUtils.numberListToFloatArray(config.get("pivot")); float[] rotation = ConfigUtils.numberListToFloatArray(config.get("rotation")); + float[] scale = ConfigUtils.numberListToFloatArray(config.get("scale")); - return new BedrockBone(name, parent, pivot, rotation, parseCubes(config)); + return new BedrockBone(name, parent, pivot, rotation, scale, parseCubes(config)); } private static BedrockCube[] parseCubes(Config config) { @@ -348,9 +354,10 @@ private static BedrockCube parseCube(Config cube) { int[] uv = ConfigUtils.numberListToIntArray(cube.get("uv")); float[] pivot = ConfigUtils.numberListToFloatArray(cube.get("pivot")); float[] rotation = ConfigUtils.numberListToFloatArray(cube.get("rotation")); - //TODO inflate + //TODO verify inflate + float[] scale = ConfigUtils.numberListToFloatArray(cube.get("inflate")); - return new BedrockCube(origin, size, uv, pivot, rotation); + return new BedrockCube(origin, size, uv, pivot, rotation, scale); } private static BedrockGeometryDescription parseGeometryDescription(Config config) { @@ -367,75 +374,38 @@ private static BedrockGeometryDescription parseGeometryDescription(Config config } - private record StagedModelPart(String name, String parentName, List children, Mesh mesh, float[] bonePivot, float[] boneRotation, int boneIndex) { } - - public Model toModel(boolean compileMesh) { + public Model toModel() { //The information needed to create a model part extracted from all bones - Map partsStaging = new HashMap<>(); + List meshesToCompile = new ArrayList<>(); + Map modelBones = new HashMap<>(); //Loop through all bones to get staging data for a model part - Map boneIndexMap = new HashMap<>(); for (int i = 0; i < bones.length; i++) { + //This iteration's bone BedrockBone bone = bones[i]; - List meshes = new ArrayList<>(); + + //Get all the meshes from these bones and add them to a list for later compilation for (BedrockCube cube : bone.cubes) { //Convert cubes to meshes - meshes.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight, i)); - } - partsStaging.put(bone.name, new StagedModelPart(bone.name, bone.parent, new ArrayList<>(), Mesh.of(meshes), bone.pivot, bone.rotation, i)); - boneIndexMap.put(bone.name, i); - } - - //Assign children to all staged model parts - List roots = new ArrayList<>(); - for (StagedModelPart part : partsStaging.values()) { - if (!part.parentName().equals("none")) { - partsStaging.get(part.parentName()).children().add(part.name()); - } else { - roots.add(part); + meshesToCompile.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight, i)); } - } - //Construct this model from these bones into model parts - List parts = new ArrayList<>(); - for (StagedModelPart part : roots) { + //Default Values var partPivot = new Vector3f(); var partRotation = new Quaternionf(); - if (part.bonePivot().length > 0) partPivot.add(part.bonePivot()[0], part.bonePivot()[1], part.bonePivot()[2]); - if (part.boneRotation().length > 0) partRotation.rotateXYZ(part.boneRotation()[0], part.boneRotation()[1], part.boneRotation()[2]); - var newPart = new Model.Part(part.name(), null, part.mesh(), partPivot, partRotation, part.boneIndex()); - parts.add(newPart); - addChildren(partsStaging, newPart); + var partScale = new Vector3f(1); + //Fill values if they exist + if (bone.pivot.length > 0) partPivot.set(bone.pivot[0], bone.pivot[1], bone.pivot[2]); + if (bone.rotation.length > 0) partRotation.rotateXYZ(bone.rotation[0], bone.rotation[1], bone.rotation[2]); + if (bone.scale.length > 0) partScale.set(bone.scale[0], bone.scale[1], bone.scale[2]); + //Create the part and add it to the list of parts + var newPart = new Model.Bone(bone.name, bone.parent, partPivot, partRotation, partScale, i); + modelBones.put(newPart.getName(), newPart); } - if (compileMesh) { - List meshesToCompile = new ArrayList<>(); - partsStaging.values().forEach((stagedModelPart) -> { - if (stagedModelPart.mesh().getFormat() != null) { - meshesToCompile.add(stagedModelPart.mesh()); - } else { - Log.info("null format: " + stagedModelPart.name()); - } - }); - return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap, Mesh.of(meshesToCompile)); - } else { - return new Model(BEDROCK_VERTEX_FORMAT, parts, boneIndexMap); - } - } - - private void addChildren(Map boneMap, Model.Part part) { - var childrenNames = boneMap.get(part.getName()).children(); - for (String childName : childrenNames) { - var stagedPart = boneMap.get(childName); - var partPivot = new Vector3f(); - var partRotation = new Quaternionf(); - if (stagedPart.bonePivot().length > 0) partPivot.add(stagedPart.bonePivot()[0], stagedPart.bonePivot()[1], stagedPart.bonePivot()[2]); - if (stagedPart.boneRotation().length > 0) partRotation.rotateXYZ(stagedPart.boneRotation()[0], stagedPart.boneRotation()[1], stagedPart.boneRotation()[2]); - var childPart = new Model.Part(childName, part, stagedPart.mesh(), partPivot, partRotation, stagedPart.boneIndex()); - part.addChild(childPart); - addChildren(boneMap, childPart); - } + //Create a model from all the parts and meshes + return new Model(BEDROCK_VERTEX_FORMAT, modelBones, Mesh.of(meshesToCompile)); } public void print() { From 8eeb6b7e725b26463eb0e4d7ebf87365db01f479 Mon Sep 17 00:00:00 2001 From: Brandon Davis Date: Wed, 4 Sep 2024 18:20:56 -0500 Subject: [PATCH 25/25] Some attempts at fixing animations --- .../animation/AnimationController.java | 4 ++- .../engine/client/renderer/model/Model.java | 11 +++---- .../model/bedrock/BedrockModelData.java | 33 ++++++++++++------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java index b4d5ea3..0cb8ddc 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java @@ -67,7 +67,9 @@ public void update(long deltaTime, Model model) { ); boneTransformationMatrices.get(index) .identity() - .translationRotateScale(boneTransformation.position(), rotation, boneTransformation.scale()); + .scale(boneTransformation.scale()) + .rotateAroundLocal(rotation, bone.getPivotPoint().x, bone.getPivotPoint().y, bone.getPivotPoint().z) + .translate(boneTransformation.position()); //.translate(bone.getOffset()); } } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java index 3688087..03a9f4d 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -1,7 +1,6 @@ package com.terminalvelocitycabbage.engine.client.renderer.model; import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; -import com.terminalvelocitycabbage.engine.debug.Log; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -54,7 +53,7 @@ public static class Bone { boolean dirty; - Vector3f offset; + Vector3f pivotPoint; Quaternionf rotation; Vector3f scale; @@ -64,7 +63,7 @@ public Bone(String name, String parentName, Vector3f pivotPoint, Quaternionf rot this.dirty = true; - this.offset = pivotPoint; + this.pivotPoint = pivotPoint; this.rotation = rotation; this.scale = scale; @@ -80,11 +79,11 @@ public String getName() { } //TODO cache this offset so we don't query every frame, do this on model instantiation - public Vector3f getOffset() { - Vector3f retOffset = new Vector3f(offset); + public Vector3f getPivotPoint() { + Vector3f retOffset = new Vector3f(pivotPoint); var parent = model.getBone(parentName); if (parent != null) { - retOffset.add(parent.getOffset(), retOffset); + retOffset.add(parent.getPivotPoint(), retOffset); } return retOffset; } diff --git a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java index 9ef48b0..e334aaa 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -95,17 +95,28 @@ public BedrockCube(float[] origin, int[] size, int[] uv, float[] pivot, float[] */ public Mesh toMesh(int textureWidth, int textureHeight, int boneIndex) { - //Vertex positions - //TODO start all at the origin, rotate them, then move them to their size to apply rotations to vertex positions - Vector3f netPos = new Vector3f(origin[0] + size[0], origin[1] + size[1], origin[2] + 0f); - Vector3f nebPos = new Vector3f(origin[0] + size[0], origin[1] + 0f, origin[2] + 0f); - Vector3f nwtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + 0f); - Vector3f nwbPos = new Vector3f(origin[0] + 0f, origin[1] + 0f, origin[2] + 0f); - Vector3f setPos = new Vector3f(origin[0] + size[0], origin[1] + size[1], origin[2] + size[2]); - Vector3f sebPos = new Vector3f(origin[0] + size[0], origin[1] + 0f, origin[2] + size[2]); - Vector3f swtPos = new Vector3f(origin[0] + 0f, origin[1] + size[1], origin[2] + size[2]); - Vector3f swbPos = new Vector3f(origin[0] + 0f, origin[1] + 0f, origin[2] + size[2]); - + //Initial cube sizes + //TODO inflate + Vector3f netPos = new Vector3f(size[0], size[1], 0f); + Vector3f nebPos = new Vector3f(size[0], 0f, 0f); + Vector3f nwtPos = new Vector3f(0f, size[1], 0f); + Vector3f nwbPos = new Vector3f(0f, 0f, 0f); + Vector3f setPos = new Vector3f(size[0], size[1], size[2]); + Vector3f sebPos = new Vector3f(size[0], 0f, size[2]); + Vector3f swtPos = new Vector3f(0f, size[1], size[2]); + Vector3f swbPos = new Vector3f(0f, 0f, size[2]); + + //Initial cube position + netPos.add(origin[0], origin[1], origin[2]); + nebPos.add(origin[0], origin[1], origin[2]); + nwtPos.add(origin[0], origin[1], origin[2]); + nwbPos.add(origin[0], origin[1], origin[2]); + setPos.add(origin[0], origin[1], origin[2]); + sebPos.add(origin[0], origin[1], origin[2]); + swtPos.add(origin[0], origin[1], origin[2]); + swbPos.add(origin[0], origin[1], origin[2]); + + //Initial Cube rotation if (rotation.length > 0 && pivot.length > 0) { Quaternionf q = new Quaternionf();