WIP: initial epic fight core extraction (Phase 0)
83 files forkés d'Epic Fight (~18k LOC). Base non-compilable en l'état.
Contenu extrait :
- math/ — OpenMatrix4f, Vec3f/4f/2f, QuaternionUtils, MathUtils, ...
- armature/ — Armature, Joint, JointTransform, HumanoidArmature
- anim/ — Animator, ServerAnimator, ClientAnimator, LivingMotion, ...
- anim/types/ — StaticAnimation, DynamicAnimation, MovementAnimation, LinkAnimation,
ConcurrentLinkAnimation, LayerOffAnimation, EntityState
- anim/client/ — Layer, ClientAnimator, JointMask
- mesh/ — SkinnedMesh, SingleGroupVertexBuilder, Mesh, HumanoidMesh, ...
- cloth/ — AbstractSimulator, ClothSimulator (dépendance transitive de StaticMesh)
- asset/ — JsonAssetLoader, AssetAccessor
- patch/ — EntityPatch, LivingEntityPatch, PlayerPatch, ClientPlayerPatch
- util/ — ParseUtil, TypeFlexibleHashMap
- exception/ — AssetLoadingException
- event/ — PatchedRenderersEvent, PrepareModelEvent, RegisterResourceLayersEvent
- render/ — TiedUpRenderTypes
Headers GPLv3 + attribution injectés sur tous les .java.
Package declarations fixées sur Armature.java et TiedUpRenderTypes.java.
115 imports résiduels à résoudre manuellement :
- yesman.epicfight.main (EpicFightMod, EpicFightSharedConstants) — 30
- yesman.epicfight.gameasset (Animations, Armatures, EpicFightSounds) — 12
- yesman.epicfight.api.physics + physics.ik (combat physics) — 16
- yesman.epicfight.network.* (combat packets) — 13
- yesman.epicfight.world.* (combat entity logic) — 10
- yesman.epicfight.config.ClientConfig — 3
- yesman.epicfight.skill, .client.gui, .particle, .collider — divers combat/UI
Stratégie fix (2-3 sem manuel) : strip usage combat, stubs pour refs
core (EpicFightMod → TiedUpMod, SharedConstants → TiedUpRigConstants,
ClientConfig → TiedUpAnimationConfig).
This commit is contained in:
104
src/main/java/com/tiedup/remake/rig/mesh/ClassicMesh.java
Normal file
104
src/main/java/com/tiedup/remake/rig/mesh/ClassicMesh.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import com.tiedup.remake.rig.mesh.ClassicMesh.ClassicMeshPart;
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import yesman.epicfight.main.EpicFightMod;
|
||||
|
||||
public class ClassicMesh extends StaticMesh<ClassicMeshPart> {
|
||||
public ClassicMesh(Map<String, Number[]> arrayMap, Map<MeshPartDefinition, List<VertexBuilder>> partBuilders, ClassicMesh parent, RenderProperties properties) {
|
||||
super(arrayMap, partBuilders, parent, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, ClassicMeshPart> createModelPart(Map<MeshPartDefinition, List<VertexBuilder>> partBuilders) {
|
||||
Map<String, ClassicMeshPart> parts = Maps.newHashMap();
|
||||
|
||||
partBuilders.forEach((partDefinition, vertexBuilder) -> {
|
||||
parts.put(partDefinition.partName(), new ClassicMeshPart(vertexBuilder, partDefinition.renderProperties(), partDefinition.getModelPartAnimationProvider()));
|
||||
});
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ClassicMeshPart getOrLogException(Map<String, ClassicMeshPart> parts, String name) {
|
||||
if (!parts.containsKey(name)) {
|
||||
EpicFightMod.LOGGER.debug("Can not find the mesh part named " + name + " in " + this.getClass().getCanonicalName());
|
||||
return null;
|
||||
}
|
||||
|
||||
return parts.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, VertexConsumer vertexConsumer, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay) {
|
||||
for (ClassicMeshPart part : this.parts.values()) {
|
||||
part.draw(poseStack, vertexConsumer, drawingFunction, packedLight, r, g, b, a, overlay);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPosed(PoseStack poseStack, VertexConsumer vertexConsumer, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, Armature armature, OpenMatrix4f[] poses) {
|
||||
this.draw(poseStack, vertexConsumer, drawingFunction, packedLight, r, g, b, a, overlay);
|
||||
}
|
||||
|
||||
public class ClassicMeshPart extends MeshPart {
|
||||
public ClassicMeshPart(List<VertexBuilder> verticies, @Nullable Mesh.RenderProperties renderProperties, @Nullable Supplier<OpenMatrix4f> vanillaPartTracer) {
|
||||
super(verticies, renderProperties, vanillaPartTracer);
|
||||
}
|
||||
|
||||
protected static final Vector4f POSITION = new Vector4f();
|
||||
protected static final Vector3f NORMAL = new Vector3f();
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, VertexConsumer bufferbuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay) {
|
||||
if (this.isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector4f color = this.getColor(r, g, b, a);
|
||||
poseStack.pushPose();
|
||||
OpenMatrix4f transform = this.getVanillaPartTransform();
|
||||
|
||||
if (transform != null) {
|
||||
poseStack.mulPoseMatrix(OpenMatrix4f.exportToMojangMatrix(transform));
|
||||
}
|
||||
|
||||
Matrix4f matrix4f = poseStack.last().pose();
|
||||
Matrix3f matrix3f = poseStack.last().normal();
|
||||
|
||||
for (VertexBuilder vi : this.getVertices()) {
|
||||
getVertexPosition(vi.position, POSITION);
|
||||
getVertexNormal(vi.normal, NORMAL);
|
||||
POSITION.mul(matrix4f);
|
||||
NORMAL.mul(matrix3f);
|
||||
|
||||
drawingFunction.draw(bufferbuilder, POSITION.x(), POSITION.y(), POSITION.z(), NORMAL.x(), NORMAL.y(), NORMAL.z(), packedLight, color.x, color.y, color.z, color.w, uvs[vi.uv * 2], uvs[vi.uv * 2 + 1], overlay);
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
77
src/main/java/com/tiedup/remake/rig/mesh/CompositeMesh.java
Normal file
77
src/main/java/com/tiedup/remake/rig/mesh/CompositeMesh.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulatable;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObjectBuilder;
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
public class CompositeMesh implements Mesh, SoftBodyTranslatable {
|
||||
private final StaticMesh<?> staticMesh;
|
||||
private final SoftBodyTranslatable softBodyMesh;
|
||||
|
||||
public CompositeMesh(StaticMesh<?> staticMesh, SoftBodyTranslatable softBodyMesh) {
|
||||
this.staticMesh = staticMesh;
|
||||
this.softBodyMesh = softBodyMesh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.staticMesh.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, VertexConsumer bufferBuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay) {
|
||||
this.staticMesh.draw(poseStack, bufferBuilder, drawingFunction, packedLight, r, g, b, a, overlay);
|
||||
this.softBodyMesh.getOriginalMesh().draw(poseStack, bufferBuilder, drawingFunction, packedLight, r, g, b, a, overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPosed(PoseStack poseStack, VertexConsumer bufferBuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, Armature armature, OpenMatrix4f[] poses) {
|
||||
this.staticMesh.drawPosed(poseStack, bufferBuilder, drawingFunction, packedLight, r, g, b, a, overlay, armature, poses);
|
||||
this.softBodyMesh.getOriginalMesh().drawPosed(poseStack, bufferBuilder, drawingFunction, packedLight, r, g, b, a, overlay, armature, poses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStartSoftBodySimulation() {
|
||||
return this.softBodyMesh.canStartSoftBodySimulation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClothObject createSimulationData(@Nullable SoftBodyTranslatable provider, ClothSimulatable simOwner, ClothObjectBuilder simBuilder) {
|
||||
return this.softBodyMesh.createSimulationData(this, simOwner, simBuilder);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public StaticMesh<?> getStaticMesh() {
|
||||
return this.staticMesh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StaticMesh<?> getOriginalMesh() {
|
||||
return (StaticMesh<?>)this.softBodyMesh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putSoftBodySimulationInfo(Map<String, ClothSimulationInfo> sofyBodySimulationInfo) {
|
||||
this.softBodyMesh.putSoftBodySimulationInfo(sofyBodySimulationInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ClothSimulationInfo> getSoftBodySimulationInfo() {
|
||||
return this.softBodyMesh.getSoftBodySimulationInfo();
|
||||
}
|
||||
}
|
||||
65
src/main/java/com/tiedup/remake/rig/mesh/HumanoidMesh.java
Normal file
65
src/main/java/com/tiedup/remake/rig/mesh/HumanoidMesh.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import com.tiedup.remake.rig.asset.AssetAccessor;
|
||||
import com.tiedup.remake.rig.mesh.MeshPartDefinition;
|
||||
import com.tiedup.remake.rig.mesh.Meshes;
|
||||
import com.tiedup.remake.rig.mesh.SkinnedMesh;
|
||||
import com.tiedup.remake.rig.mesh.VertexBuilder;
|
||||
|
||||
public class HumanoidMesh extends SkinnedMesh {
|
||||
public final SkinnedMeshPart head;
|
||||
public final SkinnedMeshPart torso;
|
||||
public final SkinnedMeshPart leftArm;
|
||||
public final SkinnedMeshPart rightArm;
|
||||
public final SkinnedMeshPart leftLeg;
|
||||
public final SkinnedMeshPart rightLeg;
|
||||
public final SkinnedMeshPart hat;
|
||||
public final SkinnedMeshPart jacket;
|
||||
public final SkinnedMeshPart leftSleeve;
|
||||
public final SkinnedMeshPart rightSleeve;
|
||||
public final SkinnedMeshPart leftPants;
|
||||
public final SkinnedMeshPart rightPants;
|
||||
|
||||
public HumanoidMesh(Map<String, Number[]> arrayMap, Map<MeshPartDefinition, List<VertexBuilder>> parts, SkinnedMesh parent, RenderProperties properties) {
|
||||
super(arrayMap, parts, parent, properties);
|
||||
|
||||
this.head = this.getOrLogException(this.parts, "head");
|
||||
this.torso = this.getOrLogException(this.parts, "torso");
|
||||
this.leftArm = this.getOrLogException(this.parts, "leftArm");
|
||||
this.rightArm = this.getOrLogException(this.parts, "rightArm");
|
||||
this.leftLeg = this.getOrLogException(this.parts, "leftLeg");
|
||||
this.rightLeg = this.getOrLogException(this.parts, "rightLeg");
|
||||
|
||||
this.hat = this.getOrLogException(this.parts, "hat");
|
||||
this.jacket = this.getOrLogException(this.parts, "jacket");
|
||||
this.leftSleeve = this.getOrLogException(this.parts, "leftSleeve");
|
||||
this.rightSleeve = this.getOrLogException(this.parts, "rightSleeve");
|
||||
this.leftPants = this.getOrLogException(this.parts, "leftPants");
|
||||
this.rightPants = this.getOrLogException(this.parts, "rightPants");
|
||||
}
|
||||
|
||||
public AssetAccessor<? extends SkinnedMesh> getHumanoidArmorModel(EquipmentSlot slot) {
|
||||
switch (slot) {
|
||||
case HEAD:
|
||||
return Meshes.HELMET;
|
||||
case CHEST:
|
||||
return Meshes.CHESTPLATE;
|
||||
case LEGS:
|
||||
return Meshes.LEGGINS;
|
||||
case FEET:
|
||||
return Meshes.BOOTS;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
214
src/main/java/com/tiedup/remake/rig/mesh/Mesh.java
Normal file
214
src/main/java/com/tiedup/remake/rig/mesh/Mesh.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.extensions.IForgeVertexConsumer;
|
||||
import net.minecraftforge.client.model.IQuadTransformer;
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import com.tiedup.remake.rig.math.Vec3f;
|
||||
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
||||
|
||||
public interface Mesh {
|
||||
|
||||
void initialize();
|
||||
|
||||
/* Draw wihtout mesh deformation */
|
||||
void draw(PoseStack poseStack, VertexConsumer vertexConsumer, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay);
|
||||
|
||||
/* Draw with mesh deformation */
|
||||
void drawPosed(PoseStack poseStack, VertexConsumer vertexConsumer, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, @Nullable Armature armature, OpenMatrix4f[] poses);
|
||||
|
||||
/* Universal method */
|
||||
default void draw(PoseStack poseStack, MultiBufferSource bufferSources, RenderType renderType, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, @Nullable Armature armature, OpenMatrix4f[] poses) {
|
||||
this.drawPosed(poseStack, bufferSources.getBuffer(EpicFightRenderTypes.getTriangulated(renderType)), drawingFunction, packedLight, r, g, b, a, overlay, armature, poses);
|
||||
}
|
||||
|
||||
public static record RenderProperties(ResourceLocation customTexturePath, Vec3f customColor, boolean isTransparent) {
|
||||
public static class Builder {
|
||||
protected String customTexturePath;
|
||||
protected Vec3f customColor = new Vec3f();
|
||||
protected boolean isTransparent;
|
||||
|
||||
public RenderProperties.Builder customTexturePath(String path) {
|
||||
this.customTexturePath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderProperties.Builder transparency(boolean isTransparent) {
|
||||
this.isTransparent = isTransparent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderProperties.Builder customColor(float r, float g, float b) {
|
||||
this.customColor.x = r;
|
||||
this.customColor.y = g;
|
||||
this.customColor.z = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RenderProperties build() {
|
||||
return new RenderProperties(this.customTexturePath == null ? null : ResourceLocation.parse(this.customTexturePath), this.customColor, this.isTransparent);
|
||||
}
|
||||
|
||||
public static RenderProperties.Builder create() {
|
||||
return new RenderProperties.Builder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface DrawingFunction {
|
||||
public static final DrawingFunction NEW_ENTITY = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ, r, g, b, a, u, v, overlay, packedLight, normX, normY, normZ);
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_TEX = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.uv(u, v);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_TEX_COLOR_NORMAL = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.uv(u, v);
|
||||
builder.color(r, g, b, a);
|
||||
builder.normal(normX, normY, normZ);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_TEX_COLOR_LIGHTMAP = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.uv(u, v);
|
||||
builder.color(r, g, b, a);
|
||||
builder.uv2(packedLight);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_COLOR_LIGHTMAP = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.color(r, g, b, a);
|
||||
builder.uv2(packedLight);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_COLOR_NORMAL = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.color(r, g, b, a);
|
||||
builder.normal(normX, normY, normZ);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public static final DrawingFunction POSITION_COLOR_TEX_LIGHTMAP = (builder, posX, posY, posZ, normX, normY, normZ, packedLight, r, g, b, a, u, v, overlay) -> {
|
||||
builder.vertex(posX, posY, posZ);
|
||||
builder.color(r, g, b, a);
|
||||
builder.uv(u, v);
|
||||
builder.uv2(packedLight);
|
||||
builder.endVertex();
|
||||
};
|
||||
|
||||
public void draw(VertexConsumer vertexConsumer, float posX, float posY, float posZ, float normX, float normY, float normZ, int packedLight, float r, float g, float b, float a, float u, float v, int overlay);
|
||||
|
||||
default void putBulkData(PoseStack.Pose pose, BakedQuad bakedQuad, VertexConsumer vertexConsumer, float red, float green, float blue, float alpha, int packedLight, int packedOverlay, boolean readExistingColor) {
|
||||
putBulkDataWithDrawingFunction(this, vertexConsumer, pose, bakedQuad, new float[] { 1.0F, 1.0F, 1.0F, 1.0F }, red, green, blue, alpha, new int[] { packedLight, packedLight, packedLight, packedLight }, packedOverlay, readExistingColor);
|
||||
}
|
||||
|
||||
static void putBulkDataWithDrawingFunction(DrawingFunction drawingFunction, VertexConsumer builder, PoseStack.Pose pPoseEntry, BakedQuad pQuad, float[] pColorMuls, float pRed, float pGreen, float pBlue, float alpha, int[] pCombinedLights, int pCombinedOverlay, boolean pMulColor) {
|
||||
float[] afloat = new float[] { pColorMuls[0], pColorMuls[1], pColorMuls[2], pColorMuls[3] };
|
||||
int[] aint1 = pQuad.getVertices();
|
||||
Vec3i vec3i = pQuad.getDirection().getNormal();
|
||||
Matrix4f matrix4f = pPoseEntry.pose();
|
||||
Vector3f vector3f = pPoseEntry.normal().transform(new Vector3f((float) vec3i.getX(), (float) vec3i.getY(), (float) vec3i.getZ()));
|
||||
int j = aint1.length / 8;
|
||||
|
||||
try (MemoryStack memorystack = MemoryStack.stackPush()) {
|
||||
ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormat.BLOCK.getVertexSize());
|
||||
IntBuffer intbuffer = bytebuffer.asIntBuffer();
|
||||
|
||||
for (int k = 0; k < j; ++k) {
|
||||
intbuffer.clear();
|
||||
intbuffer.put(aint1, k * 8, 8);
|
||||
float f = bytebuffer.getFloat(0);
|
||||
float f1 = bytebuffer.getFloat(4);
|
||||
float f2 = bytebuffer.getFloat(8);
|
||||
float f3;
|
||||
float f4;
|
||||
float f5;
|
||||
|
||||
if (pMulColor) {
|
||||
float f6 = (float) (bytebuffer.get(12) & 255) / 255.0F;
|
||||
float f7 = (float) (bytebuffer.get(13) & 255) / 255.0F;
|
||||
float f8 = (float) (bytebuffer.get(14) & 255) / 255.0F;
|
||||
f3 = f6 * afloat[k] * pRed;
|
||||
f4 = f7 * afloat[k] * pGreen;
|
||||
f5 = f8 * afloat[k] * pBlue;
|
||||
} else {
|
||||
f3 = afloat[k] * pRed;
|
||||
f4 = afloat[k] * pGreen;
|
||||
f5 = afloat[k] * pBlue;
|
||||
}
|
||||
|
||||
int l = applyBakedLighting(pCombinedLights[k], bytebuffer);
|
||||
float f9 = bytebuffer.getFloat(16);
|
||||
float f10 = bytebuffer.getFloat(20);
|
||||
Vector4f vector4f = matrix4f.transform(new Vector4f(f, f1, f2, 1.0F));
|
||||
applyBakedNormals(vector3f, bytebuffer, pPoseEntry.normal());
|
||||
float vertexAlpha = pMulColor ? alpha * (float) (bytebuffer.get(15) & 255) / 255.0F : alpha;
|
||||
drawingFunction.draw(builder, vector4f.x(), vector4f.y(), vector4f.z(), vector3f.x(), vector3f.y(), vector3f.z(), l, f3, f4, f5, vertexAlpha, f9, f10, pCombinedOverlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Code copy from {@link IForgeVertexConsumer#applyBakedLighting}
|
||||
*/
|
||||
static int applyBakedLighting(int packedLight, ByteBuffer data) {
|
||||
int bl = packedLight & 0xFFFF;
|
||||
int sl = (packedLight >> 16) & 0xFFFF;
|
||||
int offset = IQuadTransformer.UV2 * 4; // int offset for vertex 0 * 4 bytes per int
|
||||
int blBaked = Short.toUnsignedInt(data.getShort(offset));
|
||||
int slBaked = Short.toUnsignedInt(data.getShort(offset + 2));
|
||||
bl = Math.max(bl, blBaked);
|
||||
sl = Math.max(sl, slBaked);
|
||||
return bl | (sl << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Code copy from {@link IForgeVertexConsumer#applyBakedNormals}
|
||||
*/
|
||||
static void applyBakedNormals(Vector3f generated, ByteBuffer data, Matrix3f normalTransform) {
|
||||
byte nx = data.get(28);
|
||||
byte ny = data.get(29);
|
||||
byte nz = data.get(30);
|
||||
if (nx != 0 || ny != 0 || nz != 0)
|
||||
{
|
||||
generated.set(nx / 127f, ny / 127f, nz / 127f);
|
||||
generated.mul(normalTransform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
src/main/java/com/tiedup/remake/rig/mesh/MeshPart.java
Normal file
89
src/main/java/com/tiedup/remake/rig/mesh/MeshPart.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
||||
|
||||
public abstract class MeshPart {
|
||||
protected final List<VertexBuilder> verticies;
|
||||
protected final Mesh.RenderProperties renderProperties;
|
||||
protected final Supplier<OpenMatrix4f> vanillaPartTracer;
|
||||
protected boolean isHidden;
|
||||
|
||||
public MeshPart(List<VertexBuilder> vertices, @Nullable Mesh.RenderProperties renderProperties, @Nullable Supplier<OpenMatrix4f> vanillaPartTracer) {
|
||||
this.verticies = vertices;
|
||||
this.renderProperties = renderProperties;
|
||||
this.vanillaPartTracer = vanillaPartTracer;
|
||||
}
|
||||
|
||||
public abstract void draw(PoseStack poseStack, VertexConsumer bufferbuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay);
|
||||
|
||||
public void setHidden(boolean hidden) {
|
||||
this.isHidden = hidden;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return this.isHidden;
|
||||
}
|
||||
|
||||
public List<VertexBuilder> getVertices() {
|
||||
return this.verticies;
|
||||
}
|
||||
|
||||
public OpenMatrix4f getVanillaPartTransform() {
|
||||
if (this.vanillaPartTracer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.vanillaPartTracer.get();
|
||||
}
|
||||
|
||||
public VertexConsumer getBufferBuilder(RenderType renderType, MultiBufferSource bufferSource) {
|
||||
if (this.renderProperties.customTexturePath() != null) {
|
||||
return bufferSource.getBuffer(EpicFightRenderTypes.replaceTexture(this.renderProperties.customTexturePath(), renderType));
|
||||
}
|
||||
|
||||
return bufferSource.getBuffer(renderType);
|
||||
}
|
||||
|
||||
protected static final Vector4f COLOR = new Vector4f();
|
||||
|
||||
public Vector4f getColor(float r, float g, float b, float a) {
|
||||
if (this.renderProperties != null && this.renderProperties.customColor() != null) {
|
||||
COLOR.set(
|
||||
this.renderProperties.customColor().x
|
||||
, this.renderProperties.customColor().y
|
||||
, this.renderProperties.customColor().z
|
||||
, a
|
||||
);
|
||||
|
||||
return COLOR;
|
||||
} else {
|
||||
COLOR.set(
|
||||
r
|
||||
, g
|
||||
, b
|
||||
, a
|
||||
);
|
||||
|
||||
return COLOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
public interface MeshPartDefinition {
|
||||
String partName();
|
||||
Mesh.RenderProperties renderProperties();
|
||||
Supplier<OpenMatrix4f> getModelPartAnimationProvider();
|
||||
}
|
||||
225
src/main/java/com/tiedup/remake/rig/mesh/Meshes.java
Normal file
225
src/main/java/com/tiedup/remake/rig/mesh/Meshes.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import com.tiedup.remake.rig.asset.AssetAccessor;
|
||||
import com.tiedup.remake.rig.asset.JsonAssetLoader;
|
||||
import com.tiedup.remake.rig.mesh.Mesh.RenderProperties;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulatable;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObjectBuilder;
|
||||
import com.tiedup.remake.rig.mesh.CreeperMesh;
|
||||
import com.tiedup.remake.rig.mesh.DragonMesh;
|
||||
import com.tiedup.remake.rig.mesh.EndermanMesh;
|
||||
import com.tiedup.remake.rig.mesh.HoglinMesh;
|
||||
import com.tiedup.remake.rig.mesh.HumanoidMesh;
|
||||
import com.tiedup.remake.rig.mesh.IronGolemMesh;
|
||||
import com.tiedup.remake.rig.mesh.PiglinMesh;
|
||||
import com.tiedup.remake.rig.mesh.RavagerMesh;
|
||||
import com.tiedup.remake.rig.mesh.SpiderMesh;
|
||||
import com.tiedup.remake.rig.mesh.VexMesh;
|
||||
import com.tiedup.remake.rig.mesh.VillagerMesh;
|
||||
import com.tiedup.remake.rig.mesh.WitherMesh;
|
||||
import yesman.epicfight.main.EpicFightMod;
|
||||
|
||||
public class Meshes implements PreparableReloadListener {
|
||||
private static final Map<ResourceLocation, MeshAccessor<? extends Mesh>> ACCESSORS = Maps.newHashMap();
|
||||
private static final Map<MeshAccessor<? extends Mesh>, Mesh> MESHES = Maps.newHashMap();
|
||||
private static ResourceManager resourceManager = null;
|
||||
|
||||
//For resource reloader
|
||||
public static final Meshes INSTANCE = new Meshes();
|
||||
|
||||
// Entities
|
||||
public static final MeshAccessor<HumanoidMesh> ALEX = MeshAccessor.create(EpicFightMod.MODID, "entity/biped_slim_arm", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HumanoidMesh::new));
|
||||
public static final MeshAccessor<HumanoidMesh> BIPED = MeshAccessor.create(EpicFightMod.MODID, "entity/biped", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HumanoidMesh::new));
|
||||
public static final MeshAccessor<HumanoidMesh> BIPED_OLD_TEX = MeshAccessor.create(EpicFightMod.MODID, "entity/biped_old_texture", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HumanoidMesh::new));
|
||||
public static final MeshAccessor<HumanoidMesh> BIPED_OUTLAYER = MeshAccessor.create(EpicFightMod.MODID, "entity/biped_outlayer", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HumanoidMesh::new));
|
||||
public static final MeshAccessor<VillagerMesh> VILLAGER_ZOMBIE = MeshAccessor.create(EpicFightMod.MODID, "entity/zombie_villager", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(VillagerMesh::new));
|
||||
public static final MeshAccessor<CreeperMesh> CREEPER = MeshAccessor.create(EpicFightMod.MODID, "entity/creeper", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(CreeperMesh::new));
|
||||
public static final MeshAccessor<EndermanMesh> ENDERMAN = MeshAccessor.create(EpicFightMod.MODID, "entity/enderman", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(EndermanMesh::new));
|
||||
public static final MeshAccessor<HumanoidMesh> SKELETON = MeshAccessor.create(EpicFightMod.MODID, "entity/skeleton", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HumanoidMesh::new));
|
||||
public static final MeshAccessor<SpiderMesh> SPIDER = MeshAccessor.create(EpicFightMod.MODID, "entity/spider", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SpiderMesh::new));
|
||||
public static final MeshAccessor<IronGolemMesh> IRON_GOLEM = MeshAccessor.create(EpicFightMod.MODID, "entity/iron_golem", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(IronGolemMesh::new));
|
||||
public static final MeshAccessor<HumanoidMesh> ILLAGER = MeshAccessor.create(EpicFightMod.MODID, "entity/illager", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(VillagerMesh::new));
|
||||
public static final MeshAccessor<VillagerMesh> WITCH = MeshAccessor.create(EpicFightMod.MODID, "entity/witch", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(VillagerMesh::new));
|
||||
public static final MeshAccessor<RavagerMesh> RAVAGER = MeshAccessor.create(EpicFightMod.MODID, "entity/ravager",(jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(RavagerMesh::new));
|
||||
public static final MeshAccessor<VexMesh> VEX = MeshAccessor.create(EpicFightMod.MODID, "entity/vex", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(VexMesh::new));
|
||||
public static final MeshAccessor<PiglinMesh> PIGLIN = MeshAccessor.create(EpicFightMod.MODID, "entity/piglin", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(PiglinMesh::new));
|
||||
public static final MeshAccessor<HoglinMesh> HOGLIN = MeshAccessor.create(EpicFightMod.MODID, "entity/hoglin", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(HoglinMesh::new));
|
||||
public static final MeshAccessor<DragonMesh> DRAGON = MeshAccessor.create(EpicFightMod.MODID, "entity/dragon", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(DragonMesh::new));
|
||||
public static final MeshAccessor<WitherMesh> WITHER = MeshAccessor.create(EpicFightMod.MODID, "entity/wither", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(WitherMesh::new));
|
||||
|
||||
// Armors
|
||||
public static final MeshAccessor<SkinnedMesh> HELMET = MeshAccessor.create(EpicFightMod.MODID, "armor/helmet", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
public static final MeshAccessor<SkinnedMesh> HELMET_PIGLIN = MeshAccessor.create(EpicFightMod.MODID, "armor/piglin_helmet", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
public static final MeshAccessor<SkinnedMesh> HELMET_VILLAGER = MeshAccessor.create(EpicFightMod.MODID, "armor/villager_helmet", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
public static final MeshAccessor<SkinnedMesh> CHESTPLATE = MeshAccessor.create(EpicFightMod.MODID, "armor/chestplate", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
public static final MeshAccessor<SkinnedMesh> LEGGINS = MeshAccessor.create(EpicFightMod.MODID, "armor/leggins", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
public static final MeshAccessor<SkinnedMesh> BOOTS = MeshAccessor.create(EpicFightMod.MODID, "armor/boots", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
|
||||
// Particles
|
||||
public static final MeshAccessor<ClassicMesh> AIR_BURST = MeshAccessor.create(EpicFightMod.MODID, "particle/air_burst", (jsonModelLoader) -> jsonModelLoader.loadClassicMesh(ClassicMesh::new));
|
||||
public static final MeshAccessor<ClassicMesh> FORCE_FIELD = MeshAccessor.create(EpicFightMod.MODID, "particle/force_field", (jsonModelLoader) -> jsonModelLoader.loadClassicMesh(ClassicMesh::new));
|
||||
public static final MeshAccessor<ClassicMesh> LASER = MeshAccessor.create(EpicFightMod.MODID, "particle/laser", (jsonModelLoader) -> jsonModelLoader.loadClassicMesh(ClassicMesh::new));
|
||||
|
||||
// Layers
|
||||
public static final MeshAccessor<SkinnedMesh> CAPE_DEFAULT = MeshAccessor.create(EpicFightMod.MODID, "layer/default_cape", (jsonModelLoader) -> jsonModelLoader.loadSkinnedMesh(SkinnedMesh::new));
|
||||
|
||||
public static void reload(ResourceManager resourceManager) {
|
||||
Meshes.resourceManager = resourceManager;
|
||||
|
||||
ACCESSORS.entrySet().removeIf(entry -> !entry.getValue().inRegistry);
|
||||
|
||||
MESHES.values().forEach((mesh) -> {
|
||||
if (mesh instanceof SkinnedMesh skinnedMesh) {
|
||||
skinnedMesh.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
MESHES.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static <M extends Mesh> AssetAccessor<M> get(ResourceLocation id) {
|
||||
return (AssetAccessor<M>) ACCESSORS.get(id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <M extends Mesh> AssetAccessor<M> getOrCreate(ResourceLocation id, Function<JsonAssetLoader, M> jsonLoader) {
|
||||
return ACCESSORS.containsKey(id) ? (AssetAccessor<M>)ACCESSORS.get(id) : MeshAccessor.create(id, jsonLoader, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <M extends Mesh> Set<AssetAccessor<M>> entry(Class<? extends Mesh> filter) {
|
||||
return ACCESSORS.values().stream().filter((accessor) -> filter.isAssignableFrom(accessor.get().getClass())).map((accessor) -> (AssetAccessor<M>)accessor).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static ResourceLocation wrapLocation(ResourceLocation rl) {
|
||||
return rl.getPath().matches("animmodels/.*\\.json") ? rl : ResourceLocation.fromNamespaceAndPath(rl.getNamespace(), "animmodels/" + rl.getPath() + ".json");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> reload(PreparableReloadListener.PreparationBarrier stage, ResourceManager resourceManager, ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, Executor backgroundExecutor, Executor gameExecutor) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
Meshes.reload(resourceManager);
|
||||
}, gameExecutor).thenCompose(stage::wait);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface MeshContructor<P extends MeshPart, V extends VertexBuilder, M extends StaticMesh<P>> {
|
||||
M invoke(Map<String, Number[]> arrayMap, Map<MeshPartDefinition, List<V>> parts, M parent, RenderProperties properties);
|
||||
}
|
||||
|
||||
public static record MeshAccessor<M extends Mesh> (ResourceLocation registryName, Function<JsonAssetLoader, M> jsonLoader, boolean inRegistry) implements AssetAccessor<M>, SoftBodyTranslatable {
|
||||
public static <M extends Mesh> MeshAccessor<M> create(String namespaceId, String path, Function<JsonAssetLoader, M> jsonLoader) {
|
||||
return create(ResourceLocation.fromNamespaceAndPath(namespaceId, path), jsonLoader, true);
|
||||
}
|
||||
|
||||
private static <M extends Mesh> MeshAccessor<M> create(ResourceLocation id, Function<JsonAssetLoader, M> jsonLoader, boolean inRegistry) {
|
||||
MeshAccessor<M> accessor = new MeshAccessor<M> (id, jsonLoader, inRegistry);
|
||||
ACCESSORS.put(id, accessor);
|
||||
return accessor;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public M get() {
|
||||
if (!MESHES.containsKey(this)) {
|
||||
JsonAssetLoader jsonModelLoader = new JsonAssetLoader(resourceManager, wrapLocation(this.registryName));
|
||||
MESHES.put(this, this.jsonLoader.apply(jsonModelLoader));
|
||||
}
|
||||
|
||||
return (M)MESHES.get(this);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.registryName.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.registryName.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (obj instanceof MeshAccessor armatureAccessor) {
|
||||
return this.registryName.equals(armatureAccessor.registryName());
|
||||
} else if (obj instanceof ResourceLocation rl) {
|
||||
return this.registryName.equals(rl);
|
||||
} else if (obj instanceof String name) {
|
||||
return this.registryName.toString().equals(name);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canStartSoftBodySimulation() {
|
||||
Mesh mesh = this.get();
|
||||
|
||||
if (mesh instanceof StaticMesh<?> staticMesh) {
|
||||
return staticMesh.canStartSoftBodySimulation();
|
||||
} else if (mesh instanceof CompositeMesh compositeMesh) {
|
||||
return compositeMesh.canStartSoftBodySimulation();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClothObject createSimulationData(SoftBodyTranslatable provider, ClothSimulatable simOwner, ClothObjectBuilder simBuilder) {
|
||||
Mesh mesh = this.get();
|
||||
|
||||
if (mesh instanceof StaticMesh<?> staticMesh) {
|
||||
return staticMesh.createSimulationData(provider, simOwner, simBuilder);
|
||||
} else if (mesh instanceof CompositeMesh compositeMesh) {
|
||||
return compositeMesh.createSimulationData(provider, simOwner, simBuilder);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putSoftBodySimulationInfo(Map<String, ClothSimulationInfo> sofyBodySimulationInfo) {
|
||||
Mesh mesh = this.get();
|
||||
|
||||
if (mesh instanceof SoftBodyTranslatable softBodyTranslatable) {
|
||||
softBodyTranslatable.putSoftBodySimulationInfo(sofyBodySimulationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ClothSimulationInfo> getSoftBodySimulationInfo() {
|
||||
Mesh mesh = this.get();
|
||||
|
||||
if (mesh instanceof SoftBodyTranslatable softBodyTranslatable) {
|
||||
return softBodyTranslatable.getSoftBodySimulationInfo();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.floats.FloatList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import com.tiedup.remake.rig.math.Vec2f;
|
||||
import com.tiedup.remake.rig.math.Vec3f;
|
||||
|
||||
public class SingleGroupVertexBuilder {
|
||||
private Vec3f position;
|
||||
private Vec3f normal;
|
||||
private Vec2f textureCoordinate;
|
||||
private Vec3f effectiveJointIDs;
|
||||
private Vec3f effectiveJointWeights;
|
||||
private int effectiveJointNumber;
|
||||
|
||||
public SingleGroupVertexBuilder() {
|
||||
this.position = null;
|
||||
this.normal = null;
|
||||
this.textureCoordinate = null;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder(SingleGroupVertexBuilder vertex) {
|
||||
this.position = vertex.position;
|
||||
this.effectiveJointIDs = vertex.effectiveJointIDs;
|
||||
this.effectiveJointWeights = vertex.effectiveJointWeights;
|
||||
this.effectiveJointNumber = vertex.effectiveJointNumber;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setPosition(Vec3f position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setNormal(Vec3f vector) {
|
||||
this.normal = vector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setTextureCoordinate(Vec2f vector) {
|
||||
this.textureCoordinate = vector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setEffectiveJointIDs(Vec3f effectiveJointIDs) {
|
||||
this.effectiveJointIDs = effectiveJointIDs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setEffectiveJointWeights(Vec3f effectiveJointWeights) {
|
||||
this.effectiveJointWeights = effectiveJointWeights;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SingleGroupVertexBuilder setEffectiveJointNumber(int count) {
|
||||
this.effectiveJointNumber = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
public State compareTextureCoordinateAndNormal(Vec3f normal, Vec2f textureCoord) {
|
||||
if (this.textureCoordinate == null) {
|
||||
return State.EMPTY;
|
||||
} else if (this.textureCoordinate.equals(textureCoord) && this.normal.equals(normal)) {
|
||||
return State.EQUAL;
|
||||
} else {
|
||||
return State.DIFFERENT;
|
||||
}
|
||||
}
|
||||
|
||||
public static SkinnedMesh loadVertexInformation(List<SingleGroupVertexBuilder> vertices, Map<MeshPartDefinition, IntList> indices) {
|
||||
FloatList positions = new FloatArrayList();
|
||||
FloatList normals = new FloatArrayList();
|
||||
FloatList texCoords = new FloatArrayList();
|
||||
IntList animationIndices = new IntArrayList();
|
||||
FloatList jointWeights = new FloatArrayList();
|
||||
IntList affectCountList = new IntArrayList();
|
||||
|
||||
for (int i = 0; i < vertices.size(); i++) {
|
||||
SingleGroupVertexBuilder vertex = vertices.get(i);
|
||||
Vec3f position = vertex.position;
|
||||
Vec3f normal = vertex.normal;
|
||||
Vec2f texCoord = vertex.textureCoordinate;
|
||||
positions.add(position.x);
|
||||
positions.add(position.y);
|
||||
positions.add(position.z);
|
||||
normals.add(normal.x);
|
||||
normals.add(normal.y);
|
||||
normals.add(normal.z);
|
||||
texCoords.add(texCoord.x);
|
||||
texCoords.add(texCoord.y);
|
||||
|
||||
Vec3f effectIDs = vertex.effectiveJointIDs;
|
||||
Vec3f weights = vertex.effectiveJointWeights;
|
||||
int count = Math.min(vertex.effectiveJointNumber, 3);
|
||||
affectCountList.add(count);
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
switch (j) {
|
||||
case 0:
|
||||
animationIndices.add((int) effectIDs.x);
|
||||
jointWeights.add(weights.x);
|
||||
animationIndices.add(jointWeights.size() - 1);
|
||||
break;
|
||||
case 1:
|
||||
animationIndices.add((int) effectIDs.y);
|
||||
jointWeights.add(weights.y);
|
||||
animationIndices.add(jointWeights.size() - 1);
|
||||
break;
|
||||
case 2:
|
||||
animationIndices.add((int) effectIDs.z);
|
||||
jointWeights.add(weights.z);
|
||||
animationIndices.add(jointWeights.size() - 1);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Float[] positionList = positions.toArray(new Float[0]);
|
||||
Float[] normalList = normals.toArray(new Float[0]);
|
||||
Float[] texCoordList = texCoords.toArray(new Float[0]);
|
||||
Integer[] affectingJointIndices = animationIndices.toArray(new Integer[0]);
|
||||
Float[] jointWeightList = jointWeights.toArray(new Float[0]);
|
||||
Integer[] affectJointCounts = affectCountList.toArray(new Integer[0]);
|
||||
Map<String, Number[]> arrayMap = Maps.newHashMap();
|
||||
Map<MeshPartDefinition, List<VertexBuilder>> meshDefinitions = Maps.newHashMap();
|
||||
|
||||
arrayMap.put("positions", positionList);
|
||||
arrayMap.put("normals", normalList);
|
||||
arrayMap.put("uvs", texCoordList);
|
||||
arrayMap.put("weights", jointWeightList);
|
||||
arrayMap.put("vcounts", affectJointCounts);
|
||||
arrayMap.put("vindices", affectingJointIndices);
|
||||
|
||||
for (Map.Entry<MeshPartDefinition, IntList> e : indices.entrySet()) {
|
||||
meshDefinitions.put(e.getKey(), VertexBuilder.create(e.getValue().toIntArray()));
|
||||
}
|
||||
|
||||
return new SkinnedMesh(arrayMap, meshDefinitions, null, null);
|
||||
}
|
||||
|
||||
public enum State {
|
||||
EMPTY, EQUAL, DIFFERENT
|
||||
}
|
||||
}
|
||||
398
src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java
Normal file
398
src/main/java/com/tiedup/remake/rig/mesh/SkinnedMesh.java
Normal file
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import com.tiedup.remake.rig.asset.JsonAssetLoader;
|
||||
import com.tiedup.remake.rig.mesh.SkinnedMesh.SkinnedMeshPart;
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.util.ParseUtil;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import com.tiedup.remake.rig.math.Vec4f;
|
||||
import com.tiedup.remake.rig.render.TiedUpRenderTypes;
|
||||
import yesman.epicfight.client.renderer.shader.compute.ComputeShaderSetup;
|
||||
import yesman.epicfight.client.renderer.shader.compute.loader.ComputeShaderProvider;
|
||||
import yesman.epicfight.config.ClientConfig;
|
||||
import yesman.epicfight.main.EpicFightMod;
|
||||
import yesman.epicfight.main.EpicFightSharedConstants;
|
||||
|
||||
public class SkinnedMesh extends StaticMesh<SkinnedMeshPart> {
|
||||
protected final float[] weights;
|
||||
protected final int[] affectingJointCounts;
|
||||
protected final int[][] affectingWeightIndices;
|
||||
protected final int[][] affectingJointIndices;
|
||||
|
||||
private final int maxJointCount;
|
||||
|
||||
@Nullable
|
||||
private ComputeShaderSetup computerShaderSetup;
|
||||
|
||||
public SkinnedMesh(@Nullable Map<String, Number[]> arrayMap, @Nullable Map<MeshPartDefinition, List<VertexBuilder>> partBuilders, @Nullable SkinnedMesh parent, RenderProperties properties) {
|
||||
super(arrayMap, partBuilders, parent, properties);
|
||||
|
||||
this.weights = parent == null ? ParseUtil.unwrapFloatWrapperArray(arrayMap.get("weights")) : parent.weights;
|
||||
this.affectingJointCounts = parent == null ? ParseUtil.unwrapIntWrapperArray(arrayMap.get("vcounts")) : parent.affectingJointCounts;
|
||||
|
||||
if (parent != null) {
|
||||
this.affectingJointIndices = parent.affectingJointIndices;
|
||||
this.affectingWeightIndices = parent.affectingWeightIndices;
|
||||
} else {
|
||||
int[] vindices = ParseUtil.unwrapIntWrapperArray(arrayMap.get("vindices"));
|
||||
this.affectingJointIndices = new int[this.affectingJointCounts.length][];
|
||||
this.affectingWeightIndices = new int[this.affectingJointCounts.length][];
|
||||
int idx = 0;
|
||||
|
||||
for (int i = 0; i < this.affectingJointCounts.length; i++) {
|
||||
int count = this.affectingJointCounts[i];
|
||||
int[] jointId = new int[count];
|
||||
int[] weights = new int[count];
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
jointId[j] = vindices[idx * 2];
|
||||
weights[j] = vindices[idx * 2 + 1];
|
||||
idx++;
|
||||
}
|
||||
|
||||
this.affectingJointIndices[i] = jointId;
|
||||
this.affectingWeightIndices[i] = weights;
|
||||
}
|
||||
}
|
||||
|
||||
int maxJointId = 0;
|
||||
|
||||
for (int[] i : this.affectingJointIndices) {
|
||||
for (int j : i) {
|
||||
if (maxJointId < j) {
|
||||
maxJointId = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.maxJointCount = maxJointId;
|
||||
|
||||
if (ComputeShaderProvider.supportComputeShader()) {
|
||||
if (RenderSystem.isOnRenderThread()) {
|
||||
this.computerShaderSetup = ComputeShaderProvider.getComputeShaderSetup(this);
|
||||
} else {
|
||||
RenderSystem.recordRenderCall(() -> {
|
||||
this.computerShaderSetup = ComputeShaderProvider.getComputeShaderSetup(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (RenderSystem.isOnRenderThread()) {
|
||||
if (this.computerShaderSetup != null) {
|
||||
this.computerShaderSetup.destroyBuffers();
|
||||
}
|
||||
} else {
|
||||
RenderSystem.recordRenderCall(() -> {
|
||||
if (this.computerShaderSetup != null) {
|
||||
this.computerShaderSetup.destroyBuffers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, SkinnedMeshPart> createModelPart(Map<MeshPartDefinition, List<VertexBuilder>> partBuilders) {
|
||||
Map<String, SkinnedMeshPart> parts = Maps.newHashMap();
|
||||
|
||||
partBuilders.forEach((partDefinition, vertexBuilder) -> {
|
||||
parts.put(partDefinition.partName(), new SkinnedMeshPart(vertexBuilder, partDefinition.renderProperties(), partDefinition.getModelPartAnimationProvider()));
|
||||
});
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SkinnedMeshPart getOrLogException(Map<String, SkinnedMeshPart> parts, String name) {
|
||||
if (!parts.containsKey(name)) {
|
||||
if (EpicFightSharedConstants.IS_DEV_ENV) {
|
||||
EpicFightMod.LOGGER.debug("Cannot find the mesh part named " + name + " in " + this.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return parts.get(name);
|
||||
}
|
||||
|
||||
private static final Vec4f TRANSFORM = new Vec4f();
|
||||
private static final Vec4f POS = new Vec4f();
|
||||
private static final Vec4f TOTAL_POS = new Vec4f();
|
||||
|
||||
@Override
|
||||
public void getVertexPosition(int positionIndex, Vector4f dest, @Nullable OpenMatrix4f[] poses) {
|
||||
int index = positionIndex * 3;
|
||||
|
||||
POS.set(this.positions[index], this.positions[index + 1], this.positions[index + 2], 1.0F);
|
||||
TOTAL_POS.set(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
|
||||
for (int i = 0; i < this.affectingJointCounts[positionIndex]; i++) {
|
||||
int jointIndex = this.affectingJointIndices[positionIndex][i];
|
||||
int weightIndex = this.affectingWeightIndices[positionIndex][i];
|
||||
float weight = this.weights[weightIndex];
|
||||
|
||||
Vec4f.add(OpenMatrix4f.transform(poses[jointIndex], POS, TRANSFORM).scale(weight), TOTAL_POS, TOTAL_POS);
|
||||
}
|
||||
|
||||
dest.set(TOTAL_POS.x, TOTAL_POS.y, TOTAL_POS.z, 1.0F);
|
||||
}
|
||||
|
||||
private static final Vec4f NORM = new Vec4f();
|
||||
private static final Vec4f TOTAL_NORM = new Vec4f();
|
||||
|
||||
@Override
|
||||
public void getVertexNormal(int positionIndex, int normalIndex, Vector3f dest, @Nullable OpenMatrix4f[] poses) {
|
||||
int index = normalIndex * 3;
|
||||
NORM.set(this.normals[index], this.normals[index + 1], this.normals[index + 2], 1.0F);
|
||||
TOTAL_NORM.set(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
|
||||
for (int i = 0; i < this.affectingJointCounts[positionIndex]; i++) {
|
||||
int jointIndex = this.affectingJointIndices[positionIndex][i];
|
||||
int weightIndex = this.affectingWeightIndices[positionIndex][i];
|
||||
float weight = this.weights[weightIndex];
|
||||
Vec4f.add(OpenMatrix4f.transform(poses[jointIndex], NORM, TRANSFORM).scale(weight), TOTAL_NORM, TOTAL_NORM);
|
||||
}
|
||||
|
||||
dest.set(TOTAL_NORM.x, TOTAL_NORM.y, TOTAL_NORM.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the model without applying animation
|
||||
*/
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, VertexConsumer bufferbuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay) {
|
||||
for (SkinnedMeshPart part : this.parts.values()) {
|
||||
part.draw(poseStack, bufferbuilder, drawingFunction, packedLight, r, g, b, a, overlay);
|
||||
}
|
||||
}
|
||||
|
||||
protected static final Vector4f POSITION = new Vector4f();
|
||||
protected static final Vector3f NORMAL = new Vector3f();
|
||||
|
||||
/**
|
||||
* Draws the model to vanilla buffer
|
||||
*/
|
||||
@Override
|
||||
public void drawPosed(PoseStack poseStack, VertexConsumer bufferbuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, @Nullable Armature armature, OpenMatrix4f[] poses) {
|
||||
Matrix4f pose = poseStack.last().pose();
|
||||
Matrix3f normal = poseStack.last().normal();
|
||||
|
||||
for (SkinnedMeshPart part : this.parts.values()) {
|
||||
if (!part.isHidden()) {
|
||||
OpenMatrix4f transform = part.getVanillaPartTransform();
|
||||
|
||||
for (int i = 0; i < poses.length; i++) {
|
||||
ComputeShaderSetup.TOTAL_POSES[i].load(poses[i]);
|
||||
|
||||
if (armature != null) {
|
||||
ComputeShaderSetup.TOTAL_POSES[i].mulBack(armature.searchJointById(i).getToOrigin());
|
||||
}
|
||||
|
||||
if (transform != null) {
|
||||
ComputeShaderSetup.TOTAL_POSES[i].mulBack(transform);
|
||||
}
|
||||
|
||||
ComputeShaderSetup.TOTAL_NORMALS[i] = ComputeShaderSetup.TOTAL_POSES[i].removeTranslation();
|
||||
}
|
||||
|
||||
for (VertexBuilder vi : part.getVertices()) {
|
||||
this.getVertexPosition(vi.position, POSITION, ComputeShaderSetup.TOTAL_POSES);
|
||||
this.getVertexNormal(vi.position, vi.normal, NORMAL, ComputeShaderSetup.TOTAL_NORMALS);
|
||||
|
||||
POSITION.mul(pose);
|
||||
NORMAL.mul(normal);
|
||||
|
||||
drawingFunction.draw(bufferbuilder, POSITION.x, POSITION.y, POSITION.z, NORMAL.x, NORMAL.y, NORMAL.z, packedLight, r, g, b, a, this.uvs[vi.uv * 2], this.uvs[vi.uv * 2 + 1], overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the model depending on animation shader option
|
||||
* @param armature give this parameter as null if @param poses already bound origin translation
|
||||
* @param poses
|
||||
*/
|
||||
public void draw(PoseStack poseStack, MultiBufferSource bufferSources, RenderType renderType, int packedLight, float r, float g, float b, float a, int overlay, @Nullable Armature armature, OpenMatrix4f[] poses) {
|
||||
this.draw(poseStack, bufferSources, renderType, Mesh.DrawingFunction.NEW_ENTITY, packedLight, r, g, b, a, overlay, armature, poses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, MultiBufferSource bufferSources, RenderType renderType, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay, @Nullable Armature armature, OpenMatrix4f[] poses) {
|
||||
if (ClientConfig.activateComputeShader && this.computerShaderSetup != null) {
|
||||
this.computerShaderSetup.drawWithShader(this, poseStack, bufferSources, EpicFightRenderTypes.getTriangulated(renderType), packedLight, r, g, b, a, overlay, armature, poses);
|
||||
} else {
|
||||
this.drawPosed(poseStack, bufferSources.getBuffer(EpicFightRenderTypes.getTriangulated(renderType)), drawingFunction, packedLight, r, g, b, a, overlay, armature, poses);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxJointCount() {
|
||||
return this.maxJointCount;
|
||||
}
|
||||
|
||||
public float[] weights() {
|
||||
return this.weights;
|
||||
}
|
||||
|
||||
public int[] affectingJointCounts() {
|
||||
return this.affectingJointCounts;
|
||||
}
|
||||
|
||||
public int[][] affectingWeightIndices() {
|
||||
return this.affectingWeightIndices;
|
||||
}
|
||||
|
||||
public int[][] affectingJointIndices() {
|
||||
return this.affectingJointIndices;
|
||||
}
|
||||
|
||||
public class SkinnedMeshPart extends MeshPart {
|
||||
private ComputeShaderSetup.MeshPartBuffer partVBO;
|
||||
|
||||
public SkinnedMeshPart(List<VertexBuilder> animatedMeshPartList, @Nullable Mesh.RenderProperties renderProperties, @Nullable Supplier<OpenMatrix4f> vanillaPartTracer) {
|
||||
super(animatedMeshPartList, renderProperties, vanillaPartTracer);
|
||||
}
|
||||
|
||||
public void initVBO(ComputeShaderSetup.MeshPartBuffer partVBO) {
|
||||
this.partVBO = partVBO;
|
||||
}
|
||||
|
||||
public ComputeShaderSetup.MeshPartBuffer getPartVBO() {
|
||||
return this.partVBO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(PoseStack poseStack, VertexConsumer bufferBuilder, Mesh.DrawingFunction drawingFunction, int packedLight, float r, float g, float b, float a, int overlay) {
|
||||
if (this.isHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vector4f color = this.getColor(r, g, b, a);
|
||||
Matrix4f pose = poseStack.last().pose();
|
||||
Matrix3f normal = poseStack.last().normal();
|
||||
|
||||
for (VertexBuilder vi : this.getVertices()) {
|
||||
getVertexPosition(vi.position, POSITION);
|
||||
getVertexNormal(vi.normal, NORMAL);
|
||||
POSITION.mul(pose);
|
||||
NORMAL.mul(normal);
|
||||
drawingFunction.draw(bufferBuilder, POSITION.x(), POSITION.y(), POSITION.z(), NORMAL.x(), NORMAL.y(), NORMAL.z(), packedLight, color.x, color.y, color.z, color.w, uvs[vi.uv * 2], uvs[vi.uv * 2 + 1], overlay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this model as Json format
|
||||
*/
|
||||
public JsonObject toJsonObject() {
|
||||
JsonObject root = new JsonObject();
|
||||
JsonObject vertices = new JsonObject();
|
||||
float[] positions = this.positions.clone();
|
||||
float[] normals = this.normals.clone();
|
||||
|
||||
for (int i = 0; i < positions.length / 3; i++) {
|
||||
int k = i * 3;
|
||||
Vec4f posVector = new Vec4f(positions[k], positions[k+1], positions[k+2], 1.0F);
|
||||
posVector.transform(JsonAssetLoader.MINECRAFT_TO_BLENDER_COORD);
|
||||
positions[k] = posVector.x;
|
||||
positions[k+1] = posVector.y;
|
||||
positions[k+2] = posVector.z;
|
||||
}
|
||||
|
||||
for (int i = 0; i < normals.length / 3; i++) {
|
||||
int k = i * 3;
|
||||
Vec4f normVector = new Vec4f(normals[k], normals[k+1], normals[k+2], 1.0F);
|
||||
normVector.transform(JsonAssetLoader.MINECRAFT_TO_BLENDER_COORD);
|
||||
normals[k] = normVector.x;
|
||||
normals[k+1] = normVector.y;
|
||||
normals[k+2] = normVector.z;
|
||||
}
|
||||
|
||||
IntList affectingJointAndWeightIndices = new IntArrayList();
|
||||
|
||||
for (int i = 0; i < this.affectingJointCounts.length; i++) {
|
||||
for (int j = 0; j < this.affectingJointCounts[j]; j++) {
|
||||
affectingJointAndWeightIndices.add(this.affectingJointIndices[i][j]);
|
||||
affectingJointAndWeightIndices.add(this.affectingWeightIndices[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
vertices.add("positions", ParseUtil.farrayToJsonObject(positions, 3));
|
||||
vertices.add("uvs", ParseUtil.farrayToJsonObject(this.uvs, 2));
|
||||
vertices.add("normals", ParseUtil.farrayToJsonObject(normals, 3));
|
||||
vertices.add("vcounts", ParseUtil.iarrayToJsonObject(this.affectingJointCounts, 1));
|
||||
vertices.add("weights", ParseUtil.farrayToJsonObject(this.weights, 1));
|
||||
vertices.add("vindices", ParseUtil.iarrayToJsonObject(affectingJointAndWeightIndices.toIntArray(), 1));
|
||||
|
||||
if (!this.parts.isEmpty()) {
|
||||
JsonObject parts = new JsonObject();
|
||||
|
||||
for (Map.Entry<String, SkinnedMeshPart> partEntry : this.parts.entrySet()) {
|
||||
IntList indicesArray = new IntArrayList();
|
||||
|
||||
for (VertexBuilder vertexIndicator : partEntry.getValue().getVertices()) {
|
||||
indicesArray.add(vertexIndicator.position);
|
||||
indicesArray.add(vertexIndicator.uv);
|
||||
indicesArray.add(vertexIndicator.normal);
|
||||
}
|
||||
|
||||
parts.add(partEntry.getKey(), ParseUtil.iarrayToJsonObject(indicesArray.toIntArray(), 3));
|
||||
}
|
||||
|
||||
vertices.add("parts", parts);
|
||||
} else {
|
||||
int i = 0;
|
||||
int[] indices = new int[this.vertexCount * 3];
|
||||
|
||||
for (SkinnedMeshPart part : this.parts.values()) {
|
||||
for (VertexBuilder vertexIndicator : part.getVertices()) {
|
||||
indices[i * 3] = vertexIndicator.position;
|
||||
indices[i * 3 + 1] = vertexIndicator.uv;
|
||||
indices[i * 3 + 2] = vertexIndicator.normal;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
vertices.add("indices", ParseUtil.iarrayToJsonObject(indices, 3));
|
||||
}
|
||||
|
||||
root.add("vertices", vertices);
|
||||
|
||||
if (this.renderProperties != null) {
|
||||
JsonObject renderProperties = new JsonObject();
|
||||
renderProperties.addProperty("texture_path", this.renderProperties.customTexturePath().toString());
|
||||
renderProperties.addProperty("transparent", this.renderProperties.isTransparent());
|
||||
root.add("render_properties", renderProperties);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.tiedup.remake.rig.mesh.Meshes.MeshAccessor;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulatable;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject.ClothPart.ConstraintType;
|
||||
import yesman.epicfight.api.physics.SimulationProvider;
|
||||
|
||||
public interface SoftBodyTranslatable extends SimulationProvider<ClothSimulatable, ClothSimulator.ClothObject, ClothSimulator.ClothObjectBuilder, SoftBodyTranslatable> {
|
||||
public static final List<ClothSimulatable> TRACKING_SIMULATION_SUBJECTS = Lists.newArrayList();
|
||||
|
||||
default boolean canStartSoftBodySimulation() {
|
||||
return this.getSoftBodySimulationInfo() != null;
|
||||
}
|
||||
|
||||
void putSoftBodySimulationInfo(Map<String, ClothSimulationInfo> sofyBodySimulationInfo);
|
||||
|
||||
Map<String, ClothSimulationInfo> getSoftBodySimulationInfo();
|
||||
|
||||
default StaticMesh<?> getOriginalMesh() {
|
||||
if (this instanceof MeshAccessor<?> meshAccessor) {
|
||||
return (StaticMesh<?>)meshAccessor.get();
|
||||
} else {
|
||||
return (StaticMesh<?>)this;
|
||||
}
|
||||
}
|
||||
|
||||
public static record ClothSimulationInfo(float particleMass, float selfCollision, List<int[]> constraints, ConstraintType[] constraintTypes, float[] compliances, int[] particles, float[] weights, float[] rootDistance, int[] normalOffsetMapping) {
|
||||
}
|
||||
}
|
||||
150
src/main/java/com/tiedup/remake/rig/mesh/StaticMesh.java
Normal file
150
src/main/java/com/tiedup/remake/rig/mesh/StaticMesh.java
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulatable;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator;
|
||||
import com.tiedup.remake.rig.cloth.ClothSimulator.ClothObject;
|
||||
import com.tiedup.remake.rig.util.ParseUtil;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
public abstract class StaticMesh<P extends MeshPart> implements Mesh, SoftBodyTranslatable {
|
||||
protected final float[] positions;
|
||||
protected final float[] normals;
|
||||
protected final float[] uvs;
|
||||
|
||||
protected final int vertexCount;
|
||||
protected final Mesh.RenderProperties renderProperties;
|
||||
protected final Map<String, P> parts;
|
||||
protected final List<Vec3> normalList;
|
||||
|
||||
private Map<String, ClothSimulationInfo> softBodySimulationInfo;
|
||||
|
||||
/**
|
||||
* @param arrayMap Null if parent is not null
|
||||
* @param partBuilders Null if parent is not null
|
||||
* @param parent Null if arrayMap and parts are not null
|
||||
* @param renderProperties
|
||||
*/
|
||||
public StaticMesh(@Nullable Map<String, Number[]> arrayMap, @Nullable Map<MeshPartDefinition, List<VertexBuilder>> partBuilders, @Nullable StaticMesh<P> parent, Mesh.RenderProperties renderProperties) {
|
||||
this.positions = (parent == null) ? ParseUtil.unwrapFloatWrapperArray(arrayMap.get("positions")) : parent.positions;
|
||||
this.normals = (parent == null) ? ParseUtil.unwrapFloatWrapperArray(arrayMap.get("normals")) : parent.normals;
|
||||
this.uvs = (parent == null) ? ParseUtil.unwrapFloatWrapperArray(arrayMap.get("uvs")) : parent.uvs;
|
||||
this.parts = (parent == null) ? this.createModelPart(partBuilders) : parent.parts;
|
||||
this.renderProperties = renderProperties;
|
||||
|
||||
int totalV = 0;
|
||||
|
||||
for (MeshPart modelpart : this.parts.values()) {
|
||||
totalV += modelpart.getVertices().size();
|
||||
}
|
||||
|
||||
this.vertexCount = totalV;
|
||||
|
||||
if (this.canStartSoftBodySimulation()) {
|
||||
ImmutableList.Builder<Vec3> normalBuilder = ImmutableList.builder();
|
||||
|
||||
for (int i = 0; i < this.normals.length / 3; i++) {
|
||||
normalBuilder.add(new Vec3(this.normals[i * 3], this.normals[i * 3 + 1], this.normals[i * 3 + 2]));
|
||||
}
|
||||
|
||||
this.normalList = normalBuilder.build();
|
||||
} else {
|
||||
this.normalList = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Map<String, P> createModelPart(Map<MeshPartDefinition, List<VertexBuilder>> partBuilders);
|
||||
protected abstract P getOrLogException(Map<String, P> parts, String name);
|
||||
|
||||
public boolean hasPart(String part) {
|
||||
return this.parts.containsKey(part);
|
||||
}
|
||||
|
||||
public MeshPart getPart(String part) {
|
||||
return this.parts.get(part);
|
||||
}
|
||||
|
||||
public Collection<P> getAllParts() {
|
||||
return this.parts.values();
|
||||
}
|
||||
|
||||
public Set<Map.Entry<String, P>> getPartEntry() {
|
||||
return this.parts.entrySet();
|
||||
}
|
||||
|
||||
public void putSoftBodySimulationInfo(Map<String, ClothSimulationInfo> sofyBodySimulationInfo) {
|
||||
this.softBodySimulationInfo = sofyBodySimulationInfo;
|
||||
}
|
||||
|
||||
public Map<String, ClothSimulationInfo> getSoftBodySimulationInfo() {
|
||||
return this.softBodySimulationInfo;
|
||||
}
|
||||
|
||||
public Mesh.RenderProperties getRenderProperties() {
|
||||
return this.renderProperties;
|
||||
}
|
||||
|
||||
public void getVertexPosition(int positionIndex, Vector4f dest) {
|
||||
int index = positionIndex * 3;
|
||||
dest.set(this.positions[index], this.positions[index + 1], this.positions[index + 2], 1.0F);
|
||||
}
|
||||
|
||||
public void getVertexNormal(int normalIndex, Vector3f dest) {
|
||||
int index = normalIndex * 3;
|
||||
dest.set(this.normals[index], this.normals[index + 1], this.normals[index + 2]);
|
||||
}
|
||||
|
||||
public void getVertexPosition(int positionIndex, Vector4f dest, @Nullable OpenMatrix4f[] poses) {
|
||||
this.getVertexPosition(positionIndex, dest);
|
||||
}
|
||||
|
||||
public void getVertexNormal(int positionIndex, int normalIndex, Vector3f dest, @Nullable OpenMatrix4f[] poses) {
|
||||
this.getVertexNormal(normalIndex, dest);
|
||||
}
|
||||
|
||||
public float[] positions() {
|
||||
return this.positions;
|
||||
}
|
||||
|
||||
public float[] normals() {
|
||||
return this.normals;
|
||||
}
|
||||
|
||||
public float[] uvs() {
|
||||
return this.uvs;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Vec3> normalList() {
|
||||
return this.normalList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.parts.values().forEach((part) -> part.setHidden(false));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public ClothSimulator.ClothObject createSimulationData(@Nullable SoftBodyTranslatable provider, ClothSimulatable simObject, ClothSimulator.ClothObjectBuilder simBuilder) {
|
||||
return new ClothObject(simBuilder, provider == null ? this : provider, (Map<String, MeshPart>)this.parts, this.positions);
|
||||
}
|
||||
}
|
||||
62
src/main/java/com/tiedup/remake/rig/mesh/VertexBuilder.java
Normal file
62
src/main/java/com/tiedup/remake/rig/mesh/VertexBuilder.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
|
||||
* by the Epic Fight Team, licensed under GPLv3.
|
||||
* Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.mesh;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
|
||||
|
||||
// Vertex Indices
|
||||
public class VertexBuilder {
|
||||
public static List<VertexBuilder> create(int[] drawingIndices) {
|
||||
List<VertexBuilder> vertexIndicators = Lists.newArrayList();
|
||||
|
||||
for (int i = 0; i < drawingIndices.length / 3; i++) {
|
||||
int k = i * 3;
|
||||
int position = drawingIndices[k];
|
||||
int uv = drawingIndices[k + 1];
|
||||
int normal = drawingIndices[k + 2];
|
||||
VertexBuilder vi = new VertexBuilder(position, uv, normal);
|
||||
vertexIndicators.add(vi);
|
||||
}
|
||||
|
||||
return vertexIndicators;
|
||||
}
|
||||
|
||||
public final int position;
|
||||
public final int uv;
|
||||
public final int normal;
|
||||
|
||||
public VertexBuilder(int position, int uv, int normal) {
|
||||
this.position = position;
|
||||
this.uv = uv;
|
||||
this.normal = normal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof VertexBuilder vb) {
|
||||
return this.position == vb.position && this.uv == vb.uv && this.normal == vb.normal;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
result = prime * result + this.position;
|
||||
result = prime * result + this.uv;
|
||||
result = prime * result + this.normal;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user