mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-13 00:37:52 +00:00
[1.19.x] Block Model Builder Root Transform Support (#8860)
Co-authored-by: sciwhiz12 <sciwhiz12@gmail.com>
This commit is contained in:
1 parent
ed198f062c
commit
6609708d14
2 files changed
+384
-24
No files matched your search
@@ -5,8 +5,17 @@
|
||||
|
||||
package net.minecraftforge.client.model.generators;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Transformation;
|
||||
import com.mojang.math.Vector3f;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Builder for block models, does not currently provide any additional
|
||||
@@ -16,9 +25,374 @@ import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
* @see ModelProvider
|
||||
* @see ModelBuilder
|
||||
*/
|
||||
public class BlockModelBuilder extends ModelBuilder<BlockModelBuilder> {
|
||||
public class BlockModelBuilder extends ModelBuilder<BlockModelBuilder>
|
||||
{
|
||||
private final RootTransformBuilder rootTransform = new RootTransformBuilder();
|
||||
|
||||
public BlockModelBuilder(ResourceLocation outputLocation, ExistingFileHelper existingFileHelper) {
|
||||
public BlockModelBuilder(ResourceLocation outputLocation, ExistingFileHelper existingFileHelper)
|
||||
{
|
||||
super(outputLocation, existingFileHelper);
|
||||
}
|
||||
|
||||
public RootTransformBuilder rootTransform()
|
||||
{
|
||||
return rootTransform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject toJson()
|
||||
{
|
||||
JsonObject json = super.toJson();
|
||||
|
||||
// If there were any transform properties set, add them to the output.
|
||||
JsonObject transform = rootTransform.toJson();
|
||||
if (transform.size() > 0)
|
||||
{
|
||||
json.add("transform", transform);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public class RootTransformBuilder
|
||||
{
|
||||
private static final Vector3f ONE = new Vector3f(1, 1, 1);
|
||||
|
||||
private Vector3f translation = Vector3f.ZERO;
|
||||
private Quaternion leftRotation = Quaternion.ONE.copy();
|
||||
private Quaternion rightRotation = Quaternion.ONE.copy();
|
||||
private Vector3f scale = ONE;
|
||||
|
||||
private @Nullable TransformOrigin origin;
|
||||
private @Nullable Vector3f originVec;
|
||||
|
||||
private RootTransformBuilder()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation of the root transform.
|
||||
*
|
||||
* @param translation the translation
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code translation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder translation(Vector3f translation)
|
||||
{
|
||||
this.translation = Preconditions.checkNotNull(translation, "Translation must not be null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the translation of the root transform.
|
||||
*
|
||||
* @param x x translation
|
||||
* @param y y translation
|
||||
* @param z z translation
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder translation(float x, float y, float z)
|
||||
{
|
||||
return translation(new Vector3f(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left rotation of the root transform.
|
||||
*
|
||||
* @param rotation the left rotation
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code rotation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder rotation(Quaternion rotation)
|
||||
{
|
||||
this.leftRotation = Preconditions.checkNotNull(rotation, "Rotation must not be null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left rotation of the root transform.
|
||||
*
|
||||
* @param x x rotation
|
||||
* @param y y rotation
|
||||
* @param z z rotation
|
||||
* @param isDegrees whether the rotation is in degrees or radians
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder rotation(float x, float y, float z, boolean isDegrees)
|
||||
{
|
||||
return rotation(new Quaternion(x, y, z, isDegrees));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left rotation of the root transform.
|
||||
*
|
||||
* @param leftRotation the left rotation
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code leftRotation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder leftRotation(Quaternion leftRotation)
|
||||
{
|
||||
return rotation(leftRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left rotation of the root transform.
|
||||
*
|
||||
* @param x x rotation
|
||||
* @param y y rotation
|
||||
* @param z z rotation
|
||||
* @param isDegrees whether the rotation is in degrees or radians
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder leftRotation(float x, float y, float z, boolean isDegrees)
|
||||
{
|
||||
return leftRotation(new Quaternion(x, y, z, isDegrees));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right rotation of the root transform.
|
||||
*
|
||||
* @param rightRotation the right rotation
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code rightRotation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder rightRotation(Quaternion rightRotation)
|
||||
{
|
||||
this.rightRotation = Preconditions.checkNotNull(rightRotation, "Rotation must not be null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right rotation of the root transform.
|
||||
*
|
||||
* @param x x rotation
|
||||
* @param y y rotation
|
||||
* @param z z rotation
|
||||
* @param isDegrees whether the rotation is in degrees or radians
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder rightRotation(float x, float y, float z, boolean isDegrees)
|
||||
{
|
||||
return rightRotation(new Quaternion(x, y, z, isDegrees));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right rotation of the root transform.
|
||||
*
|
||||
* @param postRotation the right rotation
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code rightRotation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder postRotation(Quaternion postRotation)
|
||||
{
|
||||
return rightRotation(postRotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right rotation of the root transform.
|
||||
*
|
||||
* @param x x rotation
|
||||
* @param y y rotation
|
||||
* @param z z rotation
|
||||
* @param isDegrees whether the rotation is in degrees or radians
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder postRotation(float x, float y, float z, boolean isDegrees)
|
||||
{
|
||||
return postRotation(new Quaternion(x, y, z, isDegrees));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scale of the root transform.
|
||||
*
|
||||
* @param scale the scale
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code scale} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder scale(float scale)
|
||||
{
|
||||
return scale(new Vector3f(scale, scale, scale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scale of the root transform.
|
||||
*
|
||||
* @param xScale x scale
|
||||
* @param yScale y scale
|
||||
* @param zScale z scale
|
||||
* @return this builder
|
||||
*/
|
||||
public RootTransformBuilder scale(float xScale, float yScale, float zScale)
|
||||
{
|
||||
return scale(new Vector3f(xScale, yScale, zScale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the scale of the root transform.
|
||||
*
|
||||
* @param scale the scale vector
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code scale} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder scale(Vector3f scale)
|
||||
{
|
||||
this.scale = Preconditions.checkNotNull(scale, "Scale must not be null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root transform.
|
||||
*
|
||||
* @param transformation the transformation to use
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code transformation} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder transform(Transformation transformation)
|
||||
{
|
||||
Preconditions.checkNotNull(transformation, "Transformation must not be null");
|
||||
this.translation = transformation.getTranslation();
|
||||
this.leftRotation = transformation.getLeftRotation();
|
||||
this.rightRotation = transformation.getRightRotation();
|
||||
this.scale = transformation.getScale();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the root transform.
|
||||
*
|
||||
* @param origin the origin vector
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code origin} is {@code null}
|
||||
*/
|
||||
public RootTransformBuilder origin(Vector3f origin)
|
||||
{
|
||||
this.originVec = Preconditions.checkNotNull(origin, "Origin must not be null");
|
||||
this.origin = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the root transform.
|
||||
*
|
||||
* @param origin the origin name
|
||||
* @return this builder
|
||||
* @throws NullPointerException if {@code origin} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code origin} is not {@code center}, {@code corner} or {@code opposing-corner}
|
||||
*/
|
||||
public RootTransformBuilder origin(TransformOrigin origin)
|
||||
{
|
||||
this.origin = Preconditions.checkNotNull(origin, "Origin must not be null");
|
||||
this.originVec = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish configuring the parent builder
|
||||
* @return the parent block model builder
|
||||
*/
|
||||
public BlockModelBuilder end()
|
||||
{
|
||||
return BlockModelBuilder.this;
|
||||
}
|
||||
|
||||
public JsonObject toJson() {
|
||||
// Write the transform to an object
|
||||
JsonObject transform = new JsonObject();
|
||||
|
||||
if (!translation.equals(Vector3f.ZERO))
|
||||
{
|
||||
transform.add("translation", writeVec3(translation));
|
||||
}
|
||||
|
||||
if (!scale.equals(ONE))
|
||||
{
|
||||
transform.add("scale", writeVec3(scale));
|
||||
}
|
||||
|
||||
if (!leftRotation.equals(Quaternion.ONE))
|
||||
{
|
||||
transform.add("rotation", writeQuaternion(leftRotation));
|
||||
}
|
||||
|
||||
if (!rightRotation.equals(Quaternion.ONE))
|
||||
{
|
||||
transform.add("post_rotation", writeQuaternion(rightRotation));
|
||||
}
|
||||
|
||||
if (origin != null)
|
||||
{
|
||||
transform.addProperty("origin", origin.getSerializedName());
|
||||
}
|
||||
else if (originVec != null && !originVec.equals(Vector3f.ZERO))
|
||||
{
|
||||
transform.add("origin", writeVec3(originVec));
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
public enum TransformOrigin implements StringRepresentable
|
||||
{
|
||||
CENTER(new Vector3f(.5f, .5f, .5f), "origin"),
|
||||
CORNER(Vector3f.ZERO, "corner"),
|
||||
OPPOSING_CORNER(ONE, "opposing_corner");
|
||||
|
||||
private final Vector3f vec;
|
||||
private final String name;
|
||||
|
||||
TransformOrigin(Vector3f vec, String name)
|
||||
{
|
||||
this.vec = vec;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Vector3f getVector()
|
||||
{
|
||||
return vec;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getSerializedName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public static @Nullable TransformOrigin fromString(String originName)
|
||||
{
|
||||
if (CENTER.getSerializedName().equals(originName))
|
||||
{
|
||||
return CENTER;
|
||||
}
|
||||
if (CORNER.getSerializedName().equals(originName))
|
||||
{
|
||||
return CORNER;
|
||||
}
|
||||
if (OPPOSING_CORNER.getSerializedName().equals(originName))
|
||||
{
|
||||
return OPPOSING_CORNER;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private JsonArray writeVec3(Vector3f vector)
|
||||
{
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(vector.x());
|
||||
array.add(vector.y());
|
||||
array.add(vector.z());
|
||||
return array;
|
||||
}
|
||||
|
||||
private JsonArray writeQuaternion(Quaternion quaternion)
|
||||
{
|
||||
JsonArray array = new JsonArray();
|
||||
array.add(quaternion.i());
|
||||
array.add(quaternion.j());
|
||||
array.add(quaternion.k());
|
||||
array.add(quaternion.r());
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Transformation;
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.mojang.math.Vector4f;
|
||||
import net.minecraftforge.client.model.generators.BlockModelBuilder.RootTransformBuilder.TransformOrigin;
|
||||
|
||||
public final class TransformationHelper
|
||||
{
|
||||
@@ -108,10 +109,6 @@ public final class TransformationHelper
|
||||
|
||||
public static class Deserializer implements JsonDeserializer<Transformation>
|
||||
{
|
||||
private static final Vector3f ORIGIN_CORNER = new Vector3f();
|
||||
private static final Vector3f ORIGIN_OPPOSING_CORNER = new Vector3f(1f, 1f, 1f);
|
||||
private static final Vector3f ORIGIN_CENTER = new Vector3f(.5f, .5f, .5f);
|
||||
|
||||
@Override
|
||||
public Transformation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
@@ -151,7 +148,7 @@ public final class TransformationHelper
|
||||
Quaternion rightRot = null;
|
||||
// TODO: Default origin is opposing corner, due to a mistake.
|
||||
// This should probably be replaced with center in future versions.
|
||||
Vector3f origin = ORIGIN_OPPOSING_CORNER; // TODO: Changing this to ORIGIN_CENTER breaks models, function content needs changing too -C
|
||||
Vector3f origin = TransformOrigin.OPPOSING_CORNER.getVector(); // TODO: Changing this to ORIGIN_CENTER breaks models, function content needs changing too -C
|
||||
Set<String> elements = new HashSet<>(obj.keySet());
|
||||
if (obj.has("translation"))
|
||||
{
|
||||
@@ -207,10 +204,10 @@ public final class TransformationHelper
|
||||
Transformation matrix = new Transformation(translation, leftRot, scale, rightRot);
|
||||
|
||||
// Use a different origin if needed.
|
||||
if (!ORIGIN_CENTER.equals(origin))
|
||||
if (!TransformOrigin.CENTER.getVector().equals(origin))
|
||||
{
|
||||
Vector3f originFromCenter = origin.copy();
|
||||
originFromCenter.sub(ORIGIN_CENTER);
|
||||
originFromCenter.sub(TransformOrigin.CENTER.getVector());
|
||||
matrix = matrix.applyOrigin(originFromCenter);
|
||||
}
|
||||
return matrix;
|
||||
@@ -219,7 +216,7 @@ public final class TransformationHelper
|
||||
private static Vector3f parseOrigin(JsonObject obj) {
|
||||
Vector3f origin = null;
|
||||
|
||||
// Two types supported: string ("center", "corner") and array ([x, y, z])
|
||||
// Two types supported: string ("center", "corner", "opposing-corner") and array ([x, y, z])
|
||||
JsonElement originElement = obj.get("origin");
|
||||
if (originElement.isJsonArray())
|
||||
{
|
||||
@@ -228,23 +225,12 @@ public final class TransformationHelper
|
||||
else if (originElement.isJsonPrimitive())
|
||||
{
|
||||
String originString = originElement.getAsString();
|
||||
if ("center".equals(originString))
|
||||
{
|
||||
origin = ORIGIN_CENTER;
|
||||
}
|
||||
else if ("corner".equals(originString))
|
||||
{
|
||||
origin = ORIGIN_CORNER;
|
||||
}
|
||||
else if ("opposing-corner".equals(originString))
|
||||
{
|
||||
// This option can be used to not break models that were written with this origin once the default is changed
|
||||
origin = ORIGIN_OPPOSING_CORNER;
|
||||
}
|
||||
else
|
||||
TransformOrigin originEnum = TransformOrigin.fromString(originString);
|
||||
if (originEnum == null)
|
||||
{
|
||||
throw new JsonParseException("Origin: expected one of 'center', 'corner', 'opposing-corner'");
|
||||
}
|
||||
origin = originEnum.getVector();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user