MineLittlePony/src/main/java/com/minelittlepony/client/model/AbstractPonyModel.java

774 lines
26 KiB
Java
Raw Normal View History

2019-03-23 20:49:34 +01:00
package com.minelittlepony.client.model;
2019-05-28 10:26:26 +02:00
import com.minelittlepony.client.model.armour.ModelPonyArmour;
import com.minelittlepony.client.model.armour.ArmourWrapper;
2019-03-23 20:49:34 +01:00
import com.minelittlepony.client.model.components.PonySnout;
import com.minelittlepony.client.model.components.PonyTail;
import com.minelittlepony.client.transform.PonyTransformation;
import com.minelittlepony.client.util.render.AbstractRenderer;
import com.minelittlepony.client.util.render.PonyRenderer;
import com.minelittlepony.client.util.render.plane.PlaneRenderer;
import com.minelittlepony.model.BodyPart;
import com.minelittlepony.model.IPart;
import com.minelittlepony.model.armour.IEquestrianArmour;
2019-05-27 17:59:15 +02:00
import net.minecraft.client.model.Cuboid;
2015-08-02 00:36:33 +02:00
import net.minecraft.entity.Entity;
2019-05-27 17:59:15 +02:00
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.AbsoluteHand;
2016-05-04 03:23:57 +02:00
import net.minecraft.util.math.MathHelper;
2015-08-02 00:36:33 +02:00
import java.util.function.Consumer;
2016-11-25 05:40:19 +01:00
2019-05-27 17:59:15 +02:00
import static com.mojang.blaze3d.platform.GlStateManager.*;
2016-11-25 05:40:19 +01:00
/**
* Foundation class for all types of ponies.
*/
2019-05-27 17:59:15 +02:00
public abstract class AbstractPonyModel<T extends LivingEntity> extends ClientPonyModel<T> {
protected PlaneRenderer upperTorso;
protected PlaneRenderer neck;
protected IPart tail;
protected PonySnout snout;
public AbstractPonyModel(boolean arms) {
super(0, arms);
2015-08-02 00:36:33 +02:00
}
@Override
2019-03-23 20:49:34 +01:00
public IEquestrianArmour<?> createArmour() {
2019-05-28 10:26:26 +02:00
return new ArmourWrapper<>(new ModelPonyArmour<>(), new ModelPonyArmour<>());
}
/**
* Sets the model's various rotation angles.
*
* @param move Entity motion parameter
* i.e. velocity in no specific direction used in bipeds to calculate step amount.
* @param swing Degree to which each 'limb' swings.
* @param ticks Total whole and partial ticks since the entity's existence.
* Used in animations together with {@code swing} and {@code move}.
* @param headYaw Horizontal head motion in radians.
* @param headPitch Vertical head motion in radians.
* @param scale Scaling factor used to render this model.
* Determined by the return value of {@link RenderLivingBase.prepareScale}.
* Usually {@code 0.0625F}.
* @param entity The entity we're being called for.
*/
@Override
2019-05-27 17:59:15 +02:00
public void setAngles(T entity, float move, float swing, float ticks, float headYaw, float headPitch, float scale) {
attributes.checkRainboom(entity, swing, canFly());
2019-05-27 17:59:15 +02:00
super.setAngles(entity, move, swing, ticks, headYaw, headPitch, scale);
updateHeadRotation(headYaw, headPitch);
2018-06-03 16:38:03 +02:00
shakeBody(move, swing, getWobbleAmount(), ticks);
rotateLegs(move, swing, ticks, entity);
if (!attributes.isSwimming && !attributes.isGoingFast) {
holdItem(swing);
}
swingItem(entity);
if (attributes.isCrouching) {
2018-12-09 22:02:04 +01:00
ponyCrouch();
} else if (isRiding) {
2018-12-09 22:02:04 +01:00
ponyRide();
} else {
2018-08-18 00:24:58 +02:00
adjustBody(BODY_ROT_X_NOTSNEAK, BODY_RP_Y_NOTSNEAK, BODY_RP_Z_NOTSNEAK);
2019-05-27 17:59:15 +02:00
rightLeg.rotationPointY = FRONT_LEG_RP_Y_NOTSNEAK;
leftLeg.rotationPointY = FRONT_LEG_RP_Y_NOTSNEAK;
if (!attributes.isSleeping) {
animateBreathing(ticks);
}
if (attributes.isSwimming) {
head.setRotationPoint(0, -2, -2);
} else {
head.setRotationPoint(0, 0, 0);
}
}
if (attributes.isSleeping) {
2018-12-09 22:02:04 +01:00
ponySleep();
}
animateWears();
snout.setGender(getMetadata().getGender());
}
2018-12-09 22:02:04 +01:00
/**
* Aligns legs to a sneaky position.
*/
protected void ponyCrouch() {
adjustBody(BODY_ROT_X_SNEAK, BODY_RP_Y_SNEAK, BODY_RP_Z_SNEAK);
head.setRotationPoint(0, 6, -2);
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
rightArm.pitch -= LEG_ROT_X_SNEAK_ADJ;
leftArm.pitch -= LEG_ROT_X_SNEAK_ADJ;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
leftLeg.rotationPointY = FRONT_LEG_RP_Y_SNEAK;
rightLeg.rotationPointY = FRONT_LEG_RP_Y_SNEAK;
2018-12-09 22:02:04 +01:00
}
protected void ponySleep() {
2019-05-27 17:59:15 +02:00
rightArm.pitch = ROTATE_270;
leftArm.pitch = ROTATE_270;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
rightLeg.pitch = ROTATE_90;
leftLeg.pitch = ROTATE_90;
2018-12-09 22:02:04 +01:00
head.setRotationPoint(1, 2, isSneaking ? -1 : 1);
2018-12-09 22:02:04 +01:00
AbstractRenderer.shiftRotationPoint(rightArm, 0, 2, 6);
AbstractRenderer.shiftRotationPoint(leftArm, 0, 2, 6);
2019-05-27 17:59:15 +02:00
AbstractRenderer.shiftRotationPoint(rightLeg, 0, 2, -8);
AbstractRenderer.shiftRotationPoint(leftLeg, 0, 2, -8);
2018-12-09 22:02:04 +01:00
}
protected void ponyRide() {
if (attributes.isSitting) {
adjustBodyComponents(BODY_ROT_X_RIDING * 2, BODY_RP_Y_RIDING, BODY_RP_Z_RIDING);
adjustNeck(BODY_ROT_X_NOTSNEAK * 2, BODY_RP_Y_NOTSNEAK, BODY_RP_Z_NOTSNEAK - 4);
head.setRotationPoint(0, -2, -5);
} else {
adjustBodyComponents(BODY_ROT_X_RIDING, BODY_RP_Y_RIDING, BODY_RP_Z_RIDING);
adjustNeck(BODY_ROT_X_NOTSNEAK, BODY_RP_Y_NOTSNEAK, BODY_RP_Z_NOTSNEAK);
head.setRotationPoint(0, 0, 0);
}
2019-05-27 17:59:15 +02:00
leftLeg.rotationPointZ = 15;
leftLeg.rotationPointY = 9;
leftLeg.pitch = -PI / 4;
leftLeg.yaw = -PI / 5;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
rightLeg.rotationPointZ = 15;
rightLeg.rotationPointY = 9;
rightLeg.pitch = -PI / 4;
rightLeg.yaw = PI / 5;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
leftArm.roll = -PI * 0.06f;
rightArm.roll = PI * 0.06f;
if (attributes.isSitting) {
2019-05-27 17:59:15 +02:00
leftLeg.yaw = PI / 15;
leftLeg.pitch = PI / 9;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
leftLeg.rotationPointZ = 10;
leftLeg.rotationPointY = 7;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
rightLeg.yaw = -PI / 15;
rightLeg.pitch = PI / 9;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
rightLeg.rotationPointZ = 10;
rightLeg.rotationPointY = 7;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
leftArm.pitch = PI / 6;
rightArm.pitch = PI / 6;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
leftArm.roll *= 2;
rightArm.roll *= 2;
2018-12-09 22:02:04 +01:00
}
}
/**
* Sets the model's various rotation angles.
*
* @param move Entity motion parameter - i.e. velocity in no specific direction used in bipeds to calculate step amount.
* @param swing Degree to which each 'limb' swings.
* @param bodySwing Horizontal (Y) body rotation.
* @param ticks Total whole and partial ticks since the entity's existance. Used in animations together with {@code swing} and {@code move}.
*/
2018-06-03 16:38:03 +02:00
protected void shakeBody(float move, float swing, float bodySwing, float ticks) {
tail.setRotationAndAngles(attributes.isSwimming || attributes.isGoingFast, attributes.interpolatorId, move, swing, bodySwing * 5, ticks);
2019-05-27 17:59:15 +02:00
upperTorso.yaw = bodySwing;
body.yaw = bodySwing;
neck.yaw = bodySwing;
}
private void animateWears() {
2019-05-27 17:59:15 +02:00
leftArmOverlay.copyRotation(leftArm);
rightArmOverlay.copyRotation(rightArm);
leftLegOverlay.copyRotation(leftLeg);
rightLegOverlay.copyRotation(rightLeg);
bodyOverlay.copyRotation(body);
headwear.copyRotation(head);
}
/**
* Called to update the head rotation.
*
* @param x New rotation X
* @param y New rotation Y
*/
private void updateHeadRotation(float headYaw, float headPitch) {
head.yaw = attributes.isSleeping ? (Math.abs(attributes.interpolatorId.getMostSignificantBits()) % 2.8F) - 1.9F : headYaw / 57.29578F;
headPitch = attributes.isSleeping ? 0.1f : headPitch / 57.29578F;
if (attributes.isSwimming) {
headPitch -= 0.9F;
}
float pitch = (float)Math.toRadians(attributes.motionPitch);
head.pitch = MathHelper.clamp(headPitch, -1.25f - pitch, 0.5f - pitch);
}
/**
*
* Used to set the legs rotation based on walking/crouching animations.
*
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*
*/
2019-05-27 17:59:15 +02:00
protected void rotateLegs(float move, float swing, float ticks, T entity) {
if (attributes.isSwimming) {
rotateLegsSwimming(move, swing, ticks, entity);
} else if (attributes.isGoingFast) {
rotateLegsInFlight(move, swing, ticks, entity);
} else {
rotateLegsOnGround(move, swing, ticks, entity);
}
2019-05-27 17:59:15 +02:00
float sin = MathHelper.sin(body.yaw) * 5;
float cos = MathHelper.cos(body.yaw) * 5;
2018-06-03 16:38:03 +02:00
float spread = attributes.isGoingFast ? 2 : 1;
2019-05-27 17:59:15 +02:00
rightArm.rotationPointZ = spread + sin;
leftArm.rotationPointZ = spread - sin;
2018-06-03 16:38:03 +02:00
2018-10-28 15:26:00 +01:00
float legRPX = cos - getLegOutset() - 0.001F;
2018-06-03 16:38:03 +02:00
legRPX = getMetadata().getInterpolator(attributes.interpolatorId).interpolate("legOffset", legRPX, 3);
2019-05-27 17:59:15 +02:00
rightArm.rotationPointX = -legRPX;
rightLeg.rotationPointX = -legRPX;
2018-06-03 16:38:03 +02:00
2019-05-27 17:59:15 +02:00
leftArm.rotationPointX = legRPX;
leftLeg.rotationPointX = legRPX;
2018-06-03 16:38:03 +02:00
2019-05-27 17:59:15 +02:00
rightArm.yaw += body.yaw;
leftArm.yaw += body.yaw;
2018-06-03 16:38:03 +02:00
2019-05-27 17:59:15 +02:00
rightArm.rotationPointY = leftArm.rotationPointY = 8;
rightLeg.rotationPointZ = leftLeg.rotationPointZ = 10;
}
/**
* Rotates legs in a quopy fashion whilst swimming.
*
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*/
2019-05-27 17:59:15 +02:00
protected void rotateLegsSwimming(float move, float swing, float ticks, T entity) {
float lerp = entity.isSwimming() ? (float)attributes.motionLerp : 1;
float legLeft = (ROTATE_90 + MathHelper.sin((move / 3) + 2 * PI/3) / 2) * lerp;
float left = (ROTATE_90 + MathHelper.sin((move / 3) + 2 * PI) / 2) * lerp;
float right = (ROTATE_90 + MathHelper.sin(move / 3) / 2) * lerp;
2019-05-27 17:59:15 +02:00
leftArm.pitch = -left;
leftArm.yaw = -left/2;
leftArm.roll = left/2;
2019-05-27 17:59:15 +02:00
rightArm.pitch = -right;
rightArm.yaw = right/2;
rightArm.roll = -right/2;
2019-05-27 17:59:15 +02:00
leftLeg.pitch = legLeft;
rightLeg.pitch = right;
2019-05-27 17:59:15 +02:00
leftLeg.yaw = 0;
rightLeg.yaw = 0;
}
2018-06-03 16:38:03 +02:00
/**
* Rotates legs in quopy fashion whilst flying.
*
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*
*/
protected void rotateLegsInFlight(float move, float swing, float ticks, Entity entity) {
float armX = attributes.isGoingFast ? ROTATE_270 : MathHelper.sin(-swing / 2);
float legX = attributes.isGoingFast ? ROTATE_90 : MathHelper.sin(swing / 2);
2019-05-27 17:59:15 +02:00
leftArm.pitch = armX;
rightArm.pitch = armX;
2019-05-27 17:59:15 +02:00
leftLeg.pitch = legX;
rightLeg.pitch = legX;
2019-05-27 17:59:15 +02:00
leftArm.yaw = -0.2F;
leftLeg.yaw = 0.2F;
2019-05-27 17:59:15 +02:00
rightArm.yaw = 0.2F;
rightLeg.yaw = -0.2F;
2018-10-21 17:15:42 +02:00
2019-05-27 17:59:15 +02:00
rightArm.roll = 0;
leftArm.roll = 0;
}
/**
* Rotates legs in quopy fashion for walking.
*
* Takes the same parameters as {@link AbstractPonyModel.setRotationAndAngles}
*
*/
2019-05-27 17:59:15 +02:00
protected void rotateLegsOnGround(float move, float swing, float ticks, T entity) {
float angle = PI * (float) Math.pow(swing, 16);
float baseRotation = move * 0.6662F; // magic number ahoy
float scale = swing / 4;
2019-05-27 17:59:15 +02:00
leftArm.pitch = MathHelper.cos(baseRotation + angle) * scale;
rightArm.pitch = MathHelper.cos(baseRotation + PI + angle / 2) * scale;
2019-05-27 17:59:15 +02:00
leftLeg.pitch = MathHelper.cos(baseRotation + PI - (angle * 0.4f)) * scale;
rightLeg.pitch = MathHelper.cos(baseRotation + angle / 5) * scale;
2019-05-27 17:59:15 +02:00
leftArm.yaw = 0;
rightArm.yaw = 0;
2019-05-27 17:59:15 +02:00
leftLeg.yaw = 0;
rightLeg.yaw = 0;
2018-10-21 17:15:42 +02:00
2019-05-27 17:59:15 +02:00
rightArm.roll = 0;
leftArm.roll = 0;
}
protected float getLegOutset() {
if (attributes.isSleeping) {
2018-12-09 22:02:04 +01:00
return 3.6f;
}
if (attributes.isCrouching) {
2018-12-09 22:02:04 +01:00
return 1;
}
return 5;
}
/**
* Adjusts legs as if holding an item. Delegates to the correct arm/leg/limb as necessary.
*/
protected void holdItem(float swing) {
boolean both = leftArmPose == ArmPose.ITEM && rightArmPose == ArmPose.ITEM;
2019-05-27 17:59:15 +02:00
alignArmForAction(leftArm, leftArmPose, rightArmPose, both, swing, 1);
alignArmForAction(rightArm, rightArmPose, leftArmPose, both, swing, -1);
}
2019-04-14 22:06:25 +02:00
@Override
2019-05-27 17:59:15 +02:00
public Cuboid getBodyPart(BodyPart part) {
2019-04-14 22:06:25 +02:00
switch (part) {
default:
2019-05-27 17:59:15 +02:00
case HEAD: return head;
2019-04-14 22:06:25 +02:00
case NECK: return neck;
case TAIL:
case LEGS:
2019-05-27 17:59:15 +02:00
case BODY: return body;
2019-04-14 22:06:25 +02:00
}
}
/**
* Aligns an arm for the appropriate arm pose
*
* @param arm The arm model to align
* @param pose The post to align to
* @param both True if we have something in both hands
* @param swing Degree to which each 'limb' swings.
*/
2019-05-27 17:59:15 +02:00
protected void alignArmForAction(Cuboid arm, ArmPose pose, ArmPose complement, boolean both, float swing, float reflect) {
switch (pose) {
case ITEM:
arm.yaw = 0;
if ((!both || reflect == (attributes.isLeftHanded ? 1 : -1)) && complement != ArmPose.BLOCK) {
float swag = 1;
if (!isFlying() && both) {
swag -= (float)Math.pow(swing, 2);
}
float mult = 1 - swag/2;
arm.pitch = arm.pitch * mult - (PI / 10) * swag;
arm.roll = -reflect * (PI / 15);
if (attributes.isCrouching) {
arm.rotationPointX -= reflect * 2;
}
2018-06-03 16:38:03 +02:00
}
break;
case EMPTY:
2019-05-27 17:59:15 +02:00
arm.yaw = 0;
break;
case BLOCK:
2019-05-27 17:59:15 +02:00
arm.pitch = (arm.pitch / 2 - 0.9424779F) - 0.3F;
arm.yaw = reflect * PI / 9;
if (complement == pose) {
2019-05-27 17:59:15 +02:00
arm.yaw -= reflect * PI / 18;
}
arm.rotationPointX += reflect;
arm.rotationPointZ += 3;
if (attributes.isCrouching) {
arm.rotationPointY += 4;
2018-06-03 16:38:03 +02:00
}
break;
case BOW_AND_ARROW:
aimBow(arm, swing);
break;
case CROSSBOW_HOLD:
aimBow(arm, swing);
arm.pitch = head.pitch - ROTATE_90;
arm.yaw = head.yaw + 0.06F;
break;
case CROSSBOW_CHARGE:
aimBow(arm, swing);
arm.pitch = -0.8F;
arm.yaw = head.yaw + 0.06F;
break;
case THROW_SPEAR:
arm.pitch = ROTATE_90 * 2;
break;
}
}
2019-05-27 17:59:15 +02:00
protected void aimBow(Cuboid arm, float ticks) {
arm.pitch = ROTATE_270 + head.pitch + (MathHelper.sin(ticks * 0.067F) * 0.05F);
arm.yaw = head.yaw - 0.06F;
arm.roll = MathHelper.cos(ticks * 0.09F) * 0.05F + 0.05F;
2018-12-09 22:02:04 +01:00
2019-05-27 17:59:15 +02:00
if (isSneaking) {
2018-06-03 16:38:03 +02:00
arm.rotationPointY += 4;
}
}
/**
* Animates arm swinging. Delegates to the correct arm/leg/limb as neccessary.
*
* @param entity The entity we are being called for.
*/
2019-05-27 17:59:15 +02:00
protected void swingItem(T entity) {
if (getSwingAmount() > 0 && !attributes.isSleeping) {
2019-05-27 17:59:15 +02:00
AbsoluteHand mainSide = getPreferedHand(entity);
2019-05-27 17:59:15 +02:00
swingArm(getArm(mainSide));
}
}
/**
* Animates arm swinging.
*
* @param arm The arm to swing
*/
2019-05-27 17:59:15 +02:00
protected void swingArm(Cuboid arm) {
float swing = 1 - (float)Math.pow(1 - getSwingAmount(), 3);
float deltaX = MathHelper.sin(swing * PI);
2019-05-27 17:59:15 +02:00
float deltaZ = MathHelper.sin(getSwingAmount() * PI);
2019-05-27 17:59:15 +02:00
float deltaAim = deltaZ * (0.7F - head.pitch) * 0.75F;
2019-05-27 17:59:15 +02:00
arm.pitch -= deltaAim + deltaX * 1.2F;
arm.yaw += body.yaw * 2;
arm.roll = -deltaZ * 0.4F;
}
/**
* Animates the arm's breathing animation when holding items.
*
* @param ticks Total whole and partial ticks since the entity's existence.
* Used in animations together with {@code swing} and {@code move}.
*/
protected void animateBreathing(float ticks) {
float cos = MathHelper.cos(ticks * 0.09F) * 0.05F + 0.05F;
float sin = MathHelper.sin(ticks * 0.067F) * 0.05F;
boolean animateLeft =
(leftArmPose != ArmPose.EMPTY && (leftArmPose != rightArmPose || attributes.isLeftHanded))
&& rightArmPose != ArmPose.BLOCK;
boolean animateRight =
(rightArmPose != ArmPose.EMPTY && (leftArmPose != rightArmPose || !attributes.isLeftHanded))
&& leftArmPose != ArmPose.BLOCK;
if (animateRight) {
2019-05-27 17:59:15 +02:00
rightArm.roll += cos;
rightArm.pitch += sin;
}
if (animateLeft) {
2019-05-27 17:59:15 +02:00
leftArm.roll += cos;
leftArm.pitch += sin;
}
}
protected void adjustBody(float rotateAngleX, float rotationPointY, float rotationPointZ) {
adjustBodyComponents(rotateAngleX, rotationPointY, rotationPointZ);
adjustNeck(rotateAngleX, rotationPointY, rotationPointZ);
}
protected void adjustBodyComponents(float rotateAngleX, float rotationPointY, float rotationPointZ) {
2019-05-27 17:59:15 +02:00
body.pitch = rotateAngleX;
body.rotationPointY = rotationPointY;
body.rotationPointZ = rotationPointZ;
2019-05-27 17:59:15 +02:00
upperTorso.pitch = rotateAngleX;
upperTorso.rotationPointY = rotationPointY;
upperTorso.rotationPointZ = rotationPointZ;
}
private void adjustNeck(float rotateAngleX, float rotationPointY, float rotationPointZ) {
neck.setRotationPoint(NECK_ROT_X + rotateAngleX, rotationPointY, rotationPointZ);
}
2018-09-07 21:16:07 +02:00
@Override
public void init(float yOffset, float stretch) {
2019-05-27 17:59:15 +02:00
cuboidList.clear();
initHead(yOffset, stretch);
initBody(yOffset, stretch);
initLegs(yOffset, stretch);
initTail(yOffset, stretch);
}
protected void initHead(float yOffset, float stretch) {
2019-05-27 17:59:15 +02:00
head = new PonyRenderer(this, 0, 0)
.offset(HEAD_CENTRE_X, HEAD_CENTRE_Y, HEAD_CENTRE_Z)
.around(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z - 2)
2018-08-24 13:54:24 +02:00
.box(-4, -4, -4, 8, 8, 8, stretch);
2019-05-27 17:59:15 +02:00
initEars(((PonyRenderer)head), yOffset, stretch);
2019-05-27 17:59:15 +02:00
headwear = new PonyRenderer(this, 32, 0)
.offset(HEAD_CENTRE_X, HEAD_CENTRE_Y, HEAD_CENTRE_Z)
.around(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z - 2)
.box(-4, -4, -4, 8, 8, 8, stretch + 0.5F);
2018-06-29 19:14:11 +02:00
snout = new PonySnout(this);
snout.init(yOffset, stretch);
}
2018-08-24 13:54:24 +02:00
protected void initEars(PonyRenderer head, float yOffset, float stretch) {
head.tex(12, 16).box(-4, -6, 1, 2, 2, 2, stretch) // right ear
.flip().box( 2, -6, 1, 2, 2, 2, stretch); // left ear
}
protected void initTail(float yOffset, float stretch) {
tail = new PonyTail(this);
tail.init(yOffset, stretch);
}
/**
* Creates the main torso and neck.
*/
protected void initBody(float yOffset, float stretch) {
if (textureHeight == 64) {
2019-05-27 17:59:15 +02:00
bodyOverlay.boxes.clear();
cuboidList.add(bodyOverlay);
}
2019-05-27 17:59:15 +02:00
body = new PonyRenderer(this, 16, 16)
.around(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z)
.box(-4, 4, -2, 8, 8, 4, stretch);
2019-05-27 17:59:15 +02:00
bodyOverlay.addBox(-4, 4, -2, 8, 8, 4, stretch + 0.25F);
bodyOverlay.setRotationPoint(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z);
upperTorso = new PlaneRenderer(this, 24, 0);
upperTorso.offset(BODY_CENTRE_X, BODY_CENTRE_Y, BODY_CENTRE_Z)
.around(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z)
.tex(24, 0) .east( 4, -4, -4, 8, 8, stretch)
.tex(4, 0) .east( 4, -4, 4, 8, 4, stretch)
.tex(56, 0) .bottom(-4, 4, -4, 8, 8, stretch)
2018-10-31 19:47:50 +01:00
.tex(36, 16) .north(-4, -4, 8, 8, 4, stretch)
.north(-4, 0, 8, 8, 4, stretch)
.bottom(-4, 4, 4, 8, 4, stretch)
.flipZ().tex(32, 20).top(-4, -4, -4, 8, 12, stretch)
.tex(24, 0).west(-4, -4, -4, 8, 8, stretch)
.tex(4, 0) .west(-4, -4, 4, 8, 4, stretch)
// Tail stub
.child(0)
.tex(32, 0).top(-1, 2, 2, 2, 6, stretch)
.bottom(-1, 4, 2, 2, 6, stretch)
.east( 1, 2, 2, 2, 6, stretch)
.south(-1, 2, 8, 2, 2, stretch)
.flipZ().west(-1, 2, 2, 2, 6, stretch)
.rotate(0.5F, 0, 0);
neck = new PlaneRenderer(this, 0, 16)
.at(NECK_CENTRE_X, NECK_CENTRE_Y, NECK_CENTRE_Z)
.rotate(NECK_ROT_X, 0, 0).around(HEAD_RP_X, HEAD_RP_Y + yOffset, HEAD_RP_Z)
.north(0, 0, 0, 4, 4, stretch)
.south(0, 0, 4, 4, 4, stretch)
.east(4, 0, 0, 4, 4, stretch)
.west(0, 0, 0, 4, 4, stretch);
}
protected void preInitLegs() {
2019-05-27 17:59:15 +02:00
leftArm = new Cuboid(this, 32, 48);
rightArm = new Cuboid(this, 40, 16);
2019-05-27 17:59:15 +02:00
leftLeg = new Cuboid(this, 16, 48);
rightLeg = new Cuboid(this, 0, 16);
}
protected void preInitLegwear() {
2019-05-27 17:59:15 +02:00
leftArmOverlay.boxes.clear();
rightArmOverlay.boxes.clear();
leftLegOverlay.boxes.clear();
rightLegOverlay.boxes.clear();
}
protected void initLegs(float yOffset, float stretch) {
preInitLegs();
preInitLegwear();
int armLength = attributes.armLength;
int armWidth = attributes.armWidth;
int armDepth = attributes.armDepth;
float rarmX = attributes.armRotationX;
float rarmY = attributes.armRotationY;
float armX = THIRDP_ARM_CENTRE_X;
2018-06-22 17:58:18 +02:00
float armY = THIRDP_ARM_CENTRE_Y;
float armZ = BODY_CENTRE_Z / 2 - 1 - armDepth;
2019-06-20 03:23:15 +02:00
leftArm .setRotationPoint( rarmX, yOffset + rarmY, 0);
rightArm .setRotationPoint(-rarmX, yOffset + rarmY, 0);
leftArmOverlay .setRotationPoint(rarmX, yOffset + rarmY, 0);
rightArmOverlay.setRotationPoint(-rarmX, yOffset + rarmY, 0);
2019-06-20 03:23:15 +02:00
leftLeg .setRotationPoint( rarmX, yOffset, 0);
rightLeg .setRotationPoint(-rarmX, yOffset, 0);
leftLegOverlay .setRotationPoint(rarmX, yOffset, 0);
rightLegOverlay.setRotationPoint(-rarmX, yOffset, 0);
2019-06-20 03:23:15 +02:00
leftArm .addBox(armX, armY, armZ, armWidth, armLength, armDepth, stretch);
rightArm .addBox(armX - armWidth, armY, armZ, armWidth, armLength, armDepth, stretch);
leftArmOverlay .addBox(armX, armY, armZ, armWidth, armLength, armDepth, stretch + 0.25f);
2019-05-27 17:59:15 +02:00
rightArmOverlay.addBox(armX - armWidth, armY, armZ, armWidth, armLength, armDepth, stretch + 0.25f);
2019-06-20 03:23:15 +02:00
leftLeg .addBox(armX, armY, armZ, armWidth, armLength, armDepth, stretch);
rightLeg .addBox(armX - armWidth, armY, armZ, armWidth, armLength, armDepth, stretch);
leftLegOverlay .addBox(armX, armY, armZ, armWidth, armLength, armDepth, stretch + 0.25f);
2019-05-27 17:59:15 +02:00
rightLegOverlay.addBox(armX - armWidth, armY, armZ, armWidth, armLength, armDepth, stretch + 0.25f);
}
2015-08-02 00:36:33 +02:00
@Override
public float getRiderYOffset() {
2018-07-22 17:20:14 +02:00
if (isChild()) {
2018-07-22 17:20:14 +02:00
return 0.25F;
}
switch (getSize()) {
case NORMAL: return 0.4F;
2018-07-22 17:20:14 +02:00
case FOAL:
case TALL:
case BULKY:
2018-07-22 17:20:14 +02:00
default: return 0.25F;
}
}
/**
* Sets the model's various rotation angles.
*
* @param entity The entity we're being called for.
* @param move Entity motion parameter - i.e. velocity in no specific direction used in bipeds to calculate step amount.
* @param swing Degree to which each 'limb' swings.
* @param ticks Total whole and partial ticks since the entity's existance. Used in animations together with {@code swing} and {@code move}.
* @param headYaw Horizontal head motion in radians.
* @param headPitch Vertical head motion in radians.
* @param scale Scaling factor used to render this model. Determined by the return value of {@link RenderLivingBase.prepareScale}. Usually {@code 0.0625F}.
*/
@Override
2019-05-27 17:59:15 +02:00
public void render(T entity, float move, float swing, float ticks, float headYaw, float headPitch, float scale) {
renderStage(BodyPart.BODY, scale, this::renderBody);
renderStage(BodyPart.NECK, scale, this::renderNeck);
renderStage(BodyPart.HEAD, scale, this::renderHead);
renderStage(BodyPart.LEGS, scale, this::renderLegs);
if (textureHeight == 64) {
renderStage(BodyPart.LEGS, scale, this::renderSleeves);
renderStage(BodyPart.BODY, scale, this::renderVest);
}
renderStage(BodyPart.HEAD, scale, this::renderHelmet);
}
2018-08-24 13:54:24 +02:00
protected void renderStage(BodyPart part, float scale, Consumer<Float> action) {
pushMatrix();
2019-07-01 21:12:18 +02:00
transform(part);
action.accept(scale);
popMatrix();
}
protected void renderHead(float scale) {
2019-05-27 17:59:15 +02:00
head.render(scale);
}
protected void renderHelmet(float scale) {
headwear.render(scale);
}
protected void renderNeck(float scale) {
2019-05-27 17:59:15 +02:00
scalef(0.9F, 0.9F, 0.9F);
neck.render(scale);
}
protected void renderBody(float scale) {
2019-05-27 17:59:15 +02:00
body.render(scale);
upperTorso.render(scale);
2019-05-27 17:59:15 +02:00
body.applyTransform(scale);
tail.renderPart(scale, attributes.interpolatorId);
}
protected void renderVest(float scale) {
bodyOverlay.render(scale);
}
protected void renderLegs(float scale) {
if (!isSneaking) {
body.applyTransform(scale);
}
2019-05-27 17:59:15 +02:00
leftArm.render(scale);
rightArm.render(scale);
leftLeg.render(scale);
rightLeg.render(scale);
}
protected void renderSleeves(float scale) {
leftArmOverlay.render(scale);
rightArmOverlay.render(scale);
leftLegOverlay.render(scale);
rightLegOverlay.render(scale);
}
2018-04-29 11:56:26 +02:00
@Override
public void transform(BodyPart part) {
if (attributes.isSleeping) {
2019-03-24 18:55:15 +01:00
rotatef(90, 1, 0, 0);
rotatef(180, 0, 1, 0);
}
if (part == BodyPart.HEAD) {
rotatef(attributes.motionPitch, 1, 0, 0);
}
2019-03-23 20:49:34 +01:00
PonyTransformation.forSize(getSize()).transform(this, part);
}
2015-08-02 00:36:33 +02:00
}