Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
package com.tiedup.remake.client.gltf;
|
||||
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderStateShard;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
/**
|
||||
* Submits CPU-skinned glTF mesh vertices to Minecraft's rendering pipeline.
|
||||
* Uses TRIANGLES mode RenderType (same pattern as ObjModelRenderer).
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public final class GltfMeshRenderer extends RenderStateShard {
|
||||
|
||||
private static final ResourceLocation WHITE_TEXTURE =
|
||||
ResourceLocation.fromNamespaceAndPath("tiedup", "models/obj/shared/white.png");
|
||||
|
||||
/** Cached default RenderType (white texture). Created once, reused every frame. */
|
||||
private static RenderType cachedDefaultRenderType;
|
||||
|
||||
/** Cache for texture-specific RenderTypes, keyed by ResourceLocation. */
|
||||
private static final Map<ResourceLocation, RenderType> RENDER_TYPE_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private GltfMeshRenderer() {
|
||||
super("tiedup_gltf_renderer", () -> {}, () -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default TRIANGLES-mode RenderType (white texture), creating it once if needed.
|
||||
*/
|
||||
private static RenderType getDefaultRenderType() {
|
||||
if (cachedDefaultRenderType == null) {
|
||||
cachedDefaultRenderType = createTriangleRenderType(WHITE_TEXTURE);
|
||||
}
|
||||
return cachedDefaultRenderType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public accessor for the default RenderType (white texture).
|
||||
* Used by external renderers that need the same RenderType for tinted rendering.
|
||||
*/
|
||||
public static RenderType getRenderTypeForDefaultTexture() {
|
||||
return getDefaultRenderType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a RenderType for a specific texture, caching it for reuse.
|
||||
*
|
||||
* @param texture the texture ResourceLocation
|
||||
* @return the cached or newly created RenderType
|
||||
*/
|
||||
private static RenderType getRenderTypeForTexture(ResourceLocation texture) {
|
||||
return RENDER_TYPE_CACHE.computeIfAbsent(texture,
|
||||
GltfMeshRenderer::createTriangleRenderType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TRIANGLES-mode RenderType for glTF mesh rendering with the given texture.
|
||||
*/
|
||||
private static RenderType createTriangleRenderType(ResourceLocation texture) {
|
||||
RenderType.CompositeState state = RenderType.CompositeState.builder()
|
||||
.setShaderState(RENDERTYPE_ENTITY_CUTOUT_NO_CULL_SHADER)
|
||||
.setTextureState(
|
||||
new RenderStateShard.TextureStateShard(texture, false, false)
|
||||
)
|
||||
.setTransparencyState(NO_TRANSPARENCY)
|
||||
.setCullState(NO_CULL)
|
||||
.setLightmapState(LIGHTMAP)
|
||||
.setOverlayState(OVERLAY)
|
||||
.createCompositeState(true);
|
||||
|
||||
return RenderType.create(
|
||||
"tiedup_gltf_triangles",
|
||||
DefaultVertexFormat.NEW_ENTITY,
|
||||
VertexFormat.Mode.TRIANGLES,
|
||||
256 * 1024,
|
||||
true,
|
||||
false,
|
||||
state
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cached RenderTypes. Call on resource reload so that re-exported
|
||||
* textures are picked up without restarting the game.
|
||||
*/
|
||||
public static void clearRenderTypeCache() {
|
||||
cachedDefaultRenderType = null;
|
||||
RENDER_TYPE_CACHE.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a skinned glTF mesh using the default white texture.
|
||||
*
|
||||
* @param data parsed glTF data
|
||||
* @param jointMatrices computed joint matrices from skinning engine
|
||||
* @param poseStack current pose stack
|
||||
* @param buffer multi-buffer source
|
||||
* @param packedLight packed light value
|
||||
* @param packedOverlay packed overlay value
|
||||
*/
|
||||
public static void renderSkinned(
|
||||
GltfData data, Matrix4f[] jointMatrices,
|
||||
PoseStack poseStack, MultiBufferSource buffer,
|
||||
int packedLight, int packedOverlay
|
||||
) {
|
||||
renderSkinnedInternal(data, jointMatrices, poseStack, buffer,
|
||||
packedLight, packedOverlay, getDefaultRenderType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a skinned glTF mesh using a custom texture.
|
||||
*
|
||||
* @param data parsed glTF data
|
||||
* @param jointMatrices computed joint matrices from skinning engine
|
||||
* @param poseStack current pose stack
|
||||
* @param buffer multi-buffer source
|
||||
* @param packedLight packed light value
|
||||
* @param packedOverlay packed overlay value
|
||||
* @param texture the texture to use for rendering
|
||||
*/
|
||||
public static void renderSkinned(
|
||||
GltfData data, Matrix4f[] jointMatrices,
|
||||
PoseStack poseStack, MultiBufferSource buffer,
|
||||
int packedLight, int packedOverlay,
|
||||
ResourceLocation texture
|
||||
) {
|
||||
renderSkinnedInternal(data, jointMatrices, poseStack, buffer,
|
||||
packedLight, packedOverlay, getRenderTypeForTexture(texture));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal rendering implementation shared by both overloads.
|
||||
*/
|
||||
private static void renderSkinnedInternal(
|
||||
GltfData data, Matrix4f[] jointMatrices,
|
||||
PoseStack poseStack, MultiBufferSource buffer,
|
||||
int packedLight, int packedOverlay,
|
||||
RenderType renderType
|
||||
) {
|
||||
Matrix4f pose = poseStack.last().pose();
|
||||
Matrix3f normalMat = poseStack.last().normal();
|
||||
|
||||
VertexConsumer vc = buffer.getBuffer(renderType);
|
||||
|
||||
int[] indices = data.indices();
|
||||
float[] texCoords = data.texCoords();
|
||||
|
||||
float[] outPos = new float[3];
|
||||
float[] outNormal = new float[3];
|
||||
|
||||
// Pre-allocate scratch vectors outside the loop to avoid per-vertex allocations
|
||||
Vector4f tmpPos = new Vector4f();
|
||||
Vector4f tmpNorm = new Vector4f();
|
||||
|
||||
for (int idx : indices) {
|
||||
// Skin this vertex
|
||||
GltfSkinningEngine.skinVertex(data, idx, jointMatrices, outPos, outNormal, tmpPos, tmpNorm);
|
||||
|
||||
// UV coordinates
|
||||
float u = texCoords[idx * 2];
|
||||
float v = texCoords[idx * 2 + 1];
|
||||
|
||||
vc.vertex(pose, outPos[0], outPos[1], outPos[2])
|
||||
.color(255, 255, 255, 255)
|
||||
.uv(u, 1.0f - v)
|
||||
.overlayCoords(packedOverlay)
|
||||
.uv2(packedLight)
|
||||
.normal(normalMat, outNormal[0], outNormal[1], outNormal[2])
|
||||
.endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a skinned glTF mesh with per-primitive tint colors.
|
||||
*
|
||||
* <p>Each primitive in the mesh is checked against the tintColors map.
|
||||
* If a primitive is tintable and its channel is present in the map,
|
||||
* the corresponding RGB color is applied as vertex color (multiplied
|
||||
* against the texture by the {@code rendertype_entity_cutout_no_cull} shader).
|
||||
* Non-tintable primitives render with white (no tint).</p>
|
||||
*
|
||||
* <p>This is a single VertexConsumer stream — all primitives share the
|
||||
* same RenderType and draw call, only the vertex color differs per range.</p>
|
||||
*
|
||||
* @param data parsed glTF data (must have primitives)
|
||||
* @param jointMatrices computed joint matrices from skinning engine
|
||||
* @param poseStack current pose stack
|
||||
* @param buffer multi-buffer source
|
||||
* @param packedLight packed light value
|
||||
* @param packedOverlay packed overlay value
|
||||
* @param renderType the RenderType to use
|
||||
* @param tintColors channel name to RGB int (0xRRGGBB); empty map = white everywhere
|
||||
*/
|
||||
public static void renderSkinnedTinted(
|
||||
GltfData data, Matrix4f[] jointMatrices,
|
||||
PoseStack poseStack, MultiBufferSource buffer,
|
||||
int packedLight, int packedOverlay,
|
||||
RenderType renderType,
|
||||
Map<String, Integer> tintColors
|
||||
) {
|
||||
Matrix4f pose = poseStack.last().pose();
|
||||
Matrix3f normalMat = poseStack.last().normal();
|
||||
|
||||
VertexConsumer vc = buffer.getBuffer(renderType);
|
||||
float[] texCoords = data.texCoords();
|
||||
|
||||
float[] outPos = new float[3];
|
||||
float[] outNormal = new float[3];
|
||||
Vector4f tmpPos = new Vector4f();
|
||||
Vector4f tmpNorm = new Vector4f();
|
||||
|
||||
List<GltfData.Primitive> primitives = data.primitives();
|
||||
|
||||
for (GltfData.Primitive prim : primitives) {
|
||||
// Determine color for this primitive
|
||||
int r = 255, g = 255, b = 255;
|
||||
if (prim.tintable() && prim.tintChannel() != null) {
|
||||
Integer colorInt = tintColors.get(prim.tintChannel());
|
||||
if (colorInt != null) {
|
||||
r = (colorInt >> 16) & 0xFF;
|
||||
g = (colorInt >> 8) & 0xFF;
|
||||
b = colorInt & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
for (int idx : prim.indices()) {
|
||||
GltfSkinningEngine.skinVertex(data, idx, jointMatrices, outPos, outNormal, tmpPos, tmpNorm);
|
||||
|
||||
float u = texCoords[idx * 2];
|
||||
float v = texCoords[idx * 2 + 1];
|
||||
|
||||
vc.vertex(pose, outPos[0], outPos[1], outPos[2])
|
||||
.color(r, g, b, 255)
|
||||
.uv(u, 1.0f - v)
|
||||
.overlayCoords(packedOverlay)
|
||||
.uv2(packedLight)
|
||||
.normal(normalMat, outNormal[0], outNormal[1], outNormal[2])
|
||||
.endVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user