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/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/client/renderer/animation/Animation.java b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java new file mode 100644 index 0000000..28dcb61 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Animation.java @@ -0,0 +1,179 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import com.terminalvelocitycabbage.engine.util.Easing; +import com.terminalvelocitycabbage.engine.util.tuples.Pair; +import com.terminalvelocitycabbage.engine.util.tuples.Triplet; +import org.joml.Vector3f; + +import java.util.ArrayList; +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 currentTime; + 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<String, List<Keyframe>> keyframes; + + public Animation(long startDelay, long animationLength, long loopDelay, Map<String, List<Keyframe>> 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; + } + + public void update(long deltaTime) { + + //Get the current position in the looping keyframe + 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 + public List<Keyframe> getCurrentKeyframes(String boneName) { + + List<Keyframe> currentKeyFrames = new ArrayList<>(); + + for (Keyframe keyframe : keyframes.get(boneName)) { + if (currentTime > keyframe.startTime && currentTime < keyframe.endTime) currentKeyFrames.add(keyframe); + } + + return currentKeyFrames; + } + + //Bone name, transformations + Map<String, TransformationSnapshot> currentTransformations = new HashMap<>(); + List<Pair<Float, Keyframe>> progressKeyframes = new ArrayList<>(); + public Map<String, TransformationSnapshot> getCurrentTransformations() { + currentTransformations.clear(); + progressKeyframes.clear(); + for (String boneName : keyframes.keySet()) { + for (Keyframe keyframe : getCurrentKeyframes(boneName)) { + progressKeyframes.add(new Pair<>(getKeyframeProgress(keyframe), keyframe)); + } + currentTransformations.put(boneName, getCurrentTransforms(progressKeyframes)); + } + + return currentTransformations; + } + + /** + * 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 + */ + float getKeyframeProgress(Keyframe keyframe) { + return (currentTime - keyframe.startTime) / (keyframe.endTime - keyframe.startTime); + } + + TransformationSnapshot getCurrentTransforms(List<Pair<Float, Keyframe>> keyframes) { + + //combine all keyframe transformations into one + Vector3f position = new Vector3f(); + Vector3f rotation = new Vector3f(); + Vector3f scale = new Vector3f(1); + + for (Pair<Float, Keyframe> entry : keyframes) { + float progress = entry.getValue0(); + Keyframe keyframe = entry.getValue1(); + switch (keyframe.component) { + case POSITION -> interpolateComponent(position, progress, keyframe); + case ROTATION -> interpolateComponent(rotation, progress, keyframe); + case SCALE -> interpolateComponent(scale, progress, keyframe); + } + } + + return new TransformationSnapshot(position, rotation, scale); + } + + 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..0cb8ddc --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/AnimationController.java @@ -0,0 +1,88 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import com.terminalvelocitycabbage.engine.client.renderer.model.Model; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.util.HashMap; +import java.util.Map; + +public class AnimationController { + + //TODO replace string with identifier once animation registry exists + private final Map<String, Animation> animations; + private final Map<String, Model.Bone> bonesMap; + private final Map<Integer, Model.Bone> boneIndexMap; + private final Map<Integer, TransformationSnapshot> boneTransformations; + private final Map<Integer, Matrix4f> boneTransformationMatrices; + + public AnimationController(Map<String, Animation> animations, Map<String, Model.Bone> bonesMap) { + this.animations = animations; + this.bonesMap = bonesMap; + boneIndexMap = new HashMap<>(); + boneTransformations = new HashMap<>(); + boneTransformationMatrices = new HashMap<>(); + 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, Model model) { + //Reset all transformations from last frame + boneTransformations.values().forEach(transformationSnapshot -> { + transformationSnapshot.position().zero(); + transformationSnapshot.rotation().zero(); + transformationSnapshot.scale().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) -> { + 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 (Map.Entry<Integer, Model.Bone> 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() + .scale(boneTransformation.scale()) + .rotateAroundLocal(rotation, bone.getPivotPoint().x, bone.getPivotPoint().y, bone.getPivotPoint().z) + .translate(boneTransformation.position()); + //.translate(bone.getOffset()); + } + } + + public Animation getAnimation(String animationName) { + return animations.get(animationName); + } + + public void stopAll() { + animations.values().forEach(Animation::stop); + } + + public Map<Integer, Matrix4f> getBoneTransformations() { + return boneTransformationMatrices; + } +} 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..991d30d --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/Keyframe.java @@ -0,0 +1,68 @@ +package com.terminalvelocitycabbage.engine.client.renderer.animation; + +import com.terminalvelocitycabbage.engine.util.Easing; +import org.joml.Vector3f; + +/** + * 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; + float startTime; + float endTime; + + 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; + } + + 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, + SCALE + } +} 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 new file mode 100644 index 0000000..5edc7b9 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/animation/bedrock/BedrockAnimationData.java @@ -0,0 +1,212 @@ +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.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; +import com.terminalvelocitycabbage.engine.filesystem.resources.Resource; +import com.terminalvelocitycabbage.engine.util.ConfigUtils; +import com.terminalvelocitycabbage.engine.util.Easing; +import org.joml.Vector3f; + +import java.util.*; + +public class BedrockAnimationData { + + Version formatVersion; + //Animation name, Animation data + Map<String, AnimationData> animations; + + public BedrockAnimationData(Version formatVersion, Map<String, AnimationData> animations) { + this.formatVersion = formatVersion; + this.animations = animations; + } + + public void print() { + Log.info(formatVersion); + for (Map.Entry<String, AnimationData> entry : animations.entrySet()) { + Log.info(entry.getKey() + " " + entry.getValue()); + } + } + + public AnimationController toAnimationController(Model model) { + + Map<String, Animation> convertedAnimations = new HashMap<>(); + Map<String, List<Keyframe>> keyframes; + for (Map.Entry<String, AnimationData> entry : animations.entrySet()) { + var animationName = entry.getKey(); + var data = entry.getValue(); + + //Convert bedrock transformation data into keyframes + keyframes = new HashMap<>(); + + for (Map.Entry<String, List<Keyframe>> 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 new AnimationController(convertedAnimations, model.getBones()); + } + + public record AnimationData ( + boolean loop, + float animationLength, + float startDelay, + float loopDelay, + //Bone name, keyframes + Map<String, List<Keyframe>> boneKeyframes + ) { + + @Override + public String toString() { + return "AnimationData{" + + "loop=" + loop + + ", animationLength=" + animationLength + + ", startDelay=" + startDelay + + ", loopDelay=" + loopDelay + + ", boneKeyframes=" + boneKeyframes + + '}'; + } + } + + public static class Loader { + + static Version formatVersion; + static Map<String, AnimationData> animations = new HashMap<>(); + + 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); + + 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<String, AnimationData> animationData) { + + var animationLength = Float.parseFloat(animation.get("animation_length").toString()); + AnimationData data = new AnimationData( + animation.get("loop"), + animationLength, + Float.parseFloat(animation.get("start_delay").toString()), + Float.parseFloat(animation.get("loop_delay").toString()), + parseBedrockBoneData(animation.get("bones"), animationLength) + ); + + animationData.put(animationName, data); + } + + //bone name, Position, Rotation, Scale + private static Map<String, List<Keyframe>> parseBedrockBoneData(Config bones, float animationLength) { + + Map<String, List<Keyframe>> boneKeyframeMap = new HashMap<>(); + + bones.valueMap().forEach((key, value) -> { + + var bonesConfig = (Config) value; + List<Keyframe> 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 boneKeyframeMap; + } + + //TODO parse molang + private static List<Keyframe> parseTransformationData(Keyframe.Component component, Config transformationConfig, float endTime) { + + if (transformationConfig == null) return Collections.emptyList(); + + List<Keyframe> keyframes = new ArrayList<>(); + int iteration = 0; + for (Map.Entry<String, Object> 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 { + //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) * 1000f; + + //Create the keyframes + if (keyframeConfigOrTransformation.toString().startsWith("[")) { //linear is simplified out in bbmodel + keyframes.add(new Keyframe( + component, + previousKeyframeEndTransformation, + ConfigUtils.numberListToVector3f((List<Number>) 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 keyframes; + } + + } + +} 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/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 f7a9995..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 @@ -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; @@ -35,50 +35,104 @@ public Mesh(VertexFormat format, Vertex[] vertices, int[] indices) { this.indices = indices; } + public static Mesh of(List<Mesh> 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) { + 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 + 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 += mesh.getNumVertices(); + } + + return new Mesh(format1, vertices, indices); + } + /** * Initializes this mesh to be rendered. Only needs to be called once */ public void init() { - try (MemoryStack stack = MemoryStack.stackPush()) { - vboIdList = new ArrayList<>(); - - vaoId = glGenVertexArrays(); - glBindVertexArray(vaoId); - - 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); + + //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; + } + + vboIdList = new ArrayList<>(); + + vaoId = glGenVertexArrays(); + glBindVertexArray(vaoId); + + 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 = 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; } @@ -86,6 +140,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 new file mode 100644 index 0000000..03a9f4d --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/Model.java @@ -0,0 +1,96 @@ +package com.terminalvelocitycabbage.engine.client.renderer.model; + +import com.terminalvelocitycabbage.engine.client.renderer.elements.VertexFormat; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import java.util.Map; + +public class Model { + + VertexFormat format; + Map<String, Bone> parts; + Mesh mesh; + + public Model(VertexFormat format, Map<String, Bone> bones, Mesh mesh) { + this.format = format; + this.parts = bones; + this.parts.values().forEach(bone -> bone.model = this); + this.mesh = mesh; + } + + public void render() { + mesh.render(); + } + + public void cleanup() { + mesh.cleanup(); + } + + public VertexFormat getFormat() { + return format; + } + + public Bone getBone(String partName) { + return parts.get(partName); + } + + public Map<String, Bone> getBones() { + return parts; + } + + public Mesh getMesh() { + return mesh; + } + + public static class Bone { + + Model model; + + String name; + String parentName; + int boneIndex; + + boolean dirty; + + Vector3f pivotPoint; + Quaternionf rotation; + Vector3f scale; + + public Bone(String name, String parentName, Vector3f pivotPoint, Quaternionf rotation, Vector3f scale, int boneIndex) { + this.name = name; + this.parentName = parentName; + + this.dirty = true; + + this.pivotPoint = pivotPoint; + this.rotation = rotation; + this.scale = scale; + + this.boneIndex = boneIndex; + } + + public String getParentName() { + return parentName; + } + + public String getName() { + return name; + } + + //TODO cache this offset so we don't query every frame, do this on model instantiation + public Vector3f getPivotPoint() { + Vector3f retOffset = new Vector3f(pivotPoint); + var parent = model.getBone(parentName); + if (parent != null) { + retOffset.add(parent.getPivotPoint(), retOffset); + } + return retOffset; + } + + public int getBoneIndex() { + return boneIndex; + } + } + +} 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..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 @@ -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 */ @@ -70,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 new file mode 100644 index 0000000..e334aaa --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/client/renderer/model/bedrock/BedrockModelData.java @@ -0,0 +1,430 @@ +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 org.joml.Quaternionf; +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) + .addElement(VertexAttribute.BONE_INDEX) + .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 BedrockCube { + + float[] origin; + int[] size; + int[] uv; + float[] pivot; + float[] rotation; + float[] scale; + + 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; + } + + /** + * + * 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|7 + * 4_______5_______6_______8_______9 --- + * | | | | | + * | E | N | W | S | s1 + * | | | | | + * 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 + * + * 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, int boneIndex) { + + //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(); + 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); + 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[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).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 + // 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; + float[] scale; + 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; + } + + @Override + public String toString() { + return "BedrockBone{" + + "name='" + name + '\'' + + ", parent='" + parent + '\'' + + ", pivot=" + Arrays.toString(pivot) + + ", rotation=" + Arrays.toString(rotation) + + ", scale=" + Arrays.toString(scale) + + ", 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<Config> 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<Config> boneConfigs = config.get("bones"); + List<BedrockBone> 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")); + float[] scale = ConfigUtils.numberListToFloatArray(config.get("scale")); + + return new BedrockBone(name, parent, pivot, rotation, scale, parseCubes(config)); + } + + private static BedrockCube[] parseCubes(Config config) { + + List<Config> cubes = config.get("cubes"); + List<BedrockCube> cubesList = new ArrayList<>(); + + if (cubes != null) 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")); + float[] pivot = ConfigUtils.numberListToFloatArray(cube.get("pivot")); + float[] rotation = ConfigUtils.numberListToFloatArray(cube.get("rotation")); + //TODO verify inflate + float[] scale = ConfigUtils.numberListToFloatArray(cube.get("inflate")); + + return new BedrockCube(origin, size, uv, pivot, rotation, scale); + } + + 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); + } + + } + + public Model toModel() { + + //The information needed to create a model part extracted from all bones + List<Mesh> meshesToCompile = new ArrayList<>(); + Map<String, Model.Bone> modelBones = new HashMap<>(); + + //Loop through all bones to get staging data for a model part + for (int i = 0; i < bones.length; i++) { + //This iteration's bone + BedrockBone bone = bones[i]; + + //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 + meshesToCompile.add(cube.toMesh(geometryDescription.textureWidth, geometryDescription.textureHeight, i)); + } + + //Default Values + var partPivot = new Vector3f(); + var partRotation = new Quaternionf(); + 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); + } + + //Create a model from all the parts and meshes + return new Model(BEDROCK_VERTEX_FORMAT, modelBones, Mesh.of(meshesToCompile)); + } + + public void print() { + Log.info(formatVersion.toString()); + Log.info(geometryDescription.toString()); + for (BedrockBone bone : bones) { + Log.info(bone.toString()); + } + } + +} 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..f813720 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,9 @@ import org.joml.Matrix4f; import org.lwjgl.system.MemoryStack; +import java.nio.FloatBuffer; +import java.util.Map; + import static org.lwjgl.opengl.GL20.*; public class Uniform { @@ -32,7 +35,7 @@ public void create(int shaderProgram) { */ //TODO add a lot more of these supported uniform types public void setUniform(int uniformValue) { - glUniform1i(glGetUniformLocation(shaderProgramId, uniformName), uniformValue); + glUniform1i(uniformLocation, uniformValue); } /** @@ -40,7 +43,19 @@ public void setUniform(int uniformValue) { */ public void setUniform(Matrix4f matrix4f) { try (MemoryStack stack = MemoryStack.stackPush()) { - glUniformMatrix4fv(glGetUniformLocation(shaderProgramId, uniformName), false, matrix4f.get(stack.mallocFloat(16))); + glUniformMatrix4fv(uniformLocation, false, matrix4f.get(stack.mallocFloat(16))); + } + } + + public void setUniforms(Map<Integer, Matrix4f> boneTransformations) { + //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); } } 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); 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 d88cd2e..de9877f 100644 --- a/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java +++ b/src/main/java/com/terminalvelocitycabbage/engine/mod/ModLoader.java @@ -12,7 +12,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/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<float[]> 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<Float> 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<Integer> 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..a62ff03 --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/ConfigUtils.java @@ -0,0 +1,29 @@ +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<Number> list) { + float[] numberArray = numberListToFloatArray(list); + return new Vector3f(numberArray[0], numberArray[1], numberArray[2]); + } + + public static float[] numberListToFloatArray(List<Number> list) { + if (list == null) return new float[0]; + List<Float> convertedList = new ArrayList<>(); + list.forEach(n -> convertedList.add(n.floatValue())); + return ArrayUtils.floatArrayFromClassList(convertedList); + } + + public static int[] numberListToIntArray(List<Number> list) { + if (list == null) return new int[0]; + List<Integer> convertedList = new ArrayList<>(); + list.forEach(n -> convertedList.add(n.intValue())); + return ArrayUtils.intArrayFromClassList(convertedList); + } + +} 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..6efa4da --- /dev/null +++ b/src/main/java/com/terminalvelocitycabbage/engine/util/Easing.java @@ -0,0 +1,277 @@ +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"), + STEP("step"), + 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 STEP -> easeInStep(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 STEP -> easeOutStep(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 STEP -> easeInOutStep(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 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)); + } + + 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; + } + +} 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<A, B, C, D, E, F, G, H, I, J> extends Ennead<A, B, C, D, E, F, G, H, I> { - - 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<A, B, C, D, E, F, G, H, I> extends Octet<A, B, C, D, E, F, G, H> { - - 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<A, B, C, D, E, F, G, H> extends Septet<A, B, C, D, E, F, G> { - - 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<A, B, C, D, E> extends Quartet<A, B, C, D> { - - 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<A, B, C, D, E, F, G> extends Sextet<A, B, C, D, E, F> { - - 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<A, B, C, D, E, F> extends Quintet<A, B, C, D, E> { - - 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<A, B, C, D, E, F, G, H, I, J> extends Ennead<A, B, C, D, E, F, G, H, I> { + + 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<A> 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<A, B> 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<A, B, C> 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<A, B, C, D> 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<A, B, C, D, E> 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<A, B, C, D, E, F> 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<A, B, C, D, E, F, G> 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<A, B, C, D, E, F, G, H> 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<A, B, C, D, E, F, G, H, I> 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<A, B, C, D, E, F, G, H, I> extends Octet<A, B, C, D, E, F, G, H> { + + 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<A> 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<A, B> 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<A, B, C> 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<A, B, C, D> 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<A, B, C, D, E> 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<A, B, C, D, E, F> 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<A, B, C, D, E, F, G> 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<A, B, C, D, E, F, G, H> 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<A, B, C, D, E, F, G, H> extends Septet<A, B, C, D, E, F, G> { + + 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<A> 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<A, B> 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<A, B, C> 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<A, B, C, D> 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<A, B, C, D, E> tuple, F value5, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6, value7); + } + + public Octet(Sextet<A, B, C, D, E, F> tuple, G value6, H value7) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), tuple.getValue5(), value6, value7); + } + + public Octet(Septet<A, B, C, D, E, F, G> 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<A, B> extends Unit<A> { @@ -9,6 +9,10 @@ public Pair(A value0, B value1) { this.value1 = value1; } + public Pair(Unit<A> 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<A, B, C, D> extends Triplet<A, B, C> { @@ -9,6 +9,18 @@ public Quartet(A value0, B value1, C value2, D value3) { this.value3 = value3; } + public Quartet(Unit<A> tuple, B value1, C value2, D value3) { + this(tuple.getValue0(), value1, value2, value3); + } + + public Quartet(Pair<A, B> tuple, C value2, D value3) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3); + } + + public Quartet(Triplet<A, B, C> 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<A, B, C, D, E> extends Quartet<A, B, C, D> { + + 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<A> tuple, B value1, C value2, D value3, E value4) { + this(tuple.getValue0(), value1, value2, value3, value4); + } + + public Quintet(Pair<A, B> tuple, C value2, D value3, E value4) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4); + } + + public Quintet(Triplet<A, B, C> tuple, D value3, E value4) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4); + } + + public Quintet(Quartet<A, B, C, D> 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<A, B, C, D, E, F, G> extends Sextet<A, B, C, D, E, F> { + + 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<A> 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<A, B> tuple, C value2, D value3, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5, value6); + } + + public Septet(Triplet<A, B, C> tuple, D value3, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5, value6); + } + + public Septet(Quartet<A, B, C, D> tuple, E value4, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5, value6); + } + + public Septet(Quintet<A, B, C, D, E> tuple, F value5, G value6) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), tuple.getValue4(), value5, value6); + } + + public Septet(Sextet<A, B, C, D, E, F> 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<A, B, C, D, E, F> extends Quintet<A, B, C, D, E> { + + 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<A> tuple, B value1, C value2, D value3, E value4, F value5) { + this(tuple.getValue0(), value1, value2, value3, value4, value5); + } + + public Sextet(Pair<A, B> tuple, C value2, D value3, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), value2, value3, value4, value5); + } + + public Sextet(Triplet<A, B, C> tuple, D value3, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), value3, value4, value5); + } + + public Sextet(Quartet<A, B, C, D> tuple, E value4, F value5) { + this(tuple.getValue0(), tuple.getValue1(), tuple.getValue2(), tuple.getValue3(), value4, value5); + } + + public Sextet(Quintet<A, B, C, D, E> 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<A, B, C> extends Pair<A, B> { @@ -9,6 +9,14 @@ public Triplet(A value0, B value1, C value2) { this.value2 = value2; } + public Triplet(Unit<A> tuple, B value1, C value2) { + this(tuple.getValue0(), value1, value2); + } + + public Triplet(Pair<A, B> 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<A> { 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; + } +} 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; + } +} 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..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; @@ -38,7 +42,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; }