Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
org.gradle.jvmargs = -Xmx1G

# Fabric Properties
loom_version = 0.12-SNAPSHOT
minecraft_version = 1.19
loom_version = 1.0.+
minecraft_version = 1.19.3
# https://maven.fabricmc.net/net/fabricmc/yarn
yarn_mappings = 1.19+build.2
yarn_mappings = 1.19.3+build.3
# https://maven.fabricmc.net/net/fabricmc/fabric-loader
loader_version = 0.14.7
loader_version = 0.14.11

# Mod Properties
mod_version = 1.0.3+1.19
mod_version = 1.0.3+1.19.3
maven_group = me.pepperbell
archives_base_name = item-model-fix

# Dependencies
# https://maven.terraformersmc.com/releases/com/terraformersmc/modmenu
modmenu_version = 4.0.0
modmenu_version = 5.0.2
# https://www.curseforge.com/minecraft/mc-mods/cloth-config/files
cloth_config_version = 7.0.72
cloth_config_version = 9.0.94
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,53 @@
import java.util.Map;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;

import me.pepperbell.itemmodelfix.ItemModelFix;
import me.pepperbell.itemmodelfix.model.ItemModelGenerationType;
import me.pepperbell.itemmodelfix.model.ItemModelUtil;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.render.model.json.ModelElement;
import net.minecraft.client.render.model.json.ModelElementFace;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteContents;
import net.minecraft.util.math.Direction;

@Mixin(ItemModelGenerator.class)
public class ItemModelGeneratorMixin {
@Inject(at = @At(value = "HEAD"), method = "addLayerElements(ILjava/lang/String;Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;", cancellable = true)
private void onHeadAddLayerElements(int layer, String key, Sprite sprite, CallbackInfoReturnable<List<ModelElement>> cir) {
@Unique
private Sprite itemmodelfix$sprite;

@Redirect(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/texture/Sprite;getContents()Lnet/minecraft/client/texture/SpriteContents;"), method = "create")
private SpriteContents captureSprite(Sprite sprite) {
this.itemmodelfix$sprite = sprite;
return sprite.getContents();
}

@Inject(at = @At(value = "RETURN"), method = "create")
private void releaseSprite(CallbackInfoReturnable<JsonUnbakedModel> cir) {
this.itemmodelfix$sprite = null;
}

@Inject(at = @At(value = "HEAD"), method = "addLayerElements(ILjava/lang/String;Lnet/minecraft/client/texture/SpriteContents;)Ljava/util/List;", cancellable = true)
private void onHeadAddLayerElements(int layer, String key, SpriteContents contents, CallbackInfoReturnable<List<ModelElement>> cir) {
if (ItemModelFix.getConfig().getOptions().generationType == ItemModelGenerationType.OUTLINE) {
cir.setReturnValue(ItemModelUtil.createOutlineLayerElements(layer, key, sprite));
cir.setReturnValue(ItemModelUtil.createOutlineLayerElements(layer, key, this.itemmodelfix$sprite));
} else if (ItemModelFix.getConfig().getOptions().generationType == ItemModelGenerationType.PIXEL) {
cir.setReturnValue(ItemModelUtil.createPixelLayerElements(layer, key, sprite));
cir.setReturnValue(ItemModelUtil.createPixelLayerElements(layer, key, contents));
}
}

@Inject(at = @At(value = "TAIL"), method = "addLayerElements(ILjava/lang/String;Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;", locals = LocalCapture.CAPTURE_FAILHARD)
private void onTailAddLayerElements(int layer, String key, Sprite sprite, CallbackInfoReturnable<List<ModelElement>> cir, Map<Direction, ModelElementFace> map, List<ModelElement> list) {
@Inject(at = @At(value = "TAIL"), method = "addLayerElements(ILjava/lang/String;Lnet/minecraft/client/texture/SpriteContents;)Ljava/util/List;", locals = LocalCapture.CAPTURE_FAILHARD)
private void onTailAddLayerElements(int layer, String key, SpriteContents contents, CallbackInfoReturnable<List<ModelElement>> cir, Map<Direction, ModelElementFace> map, List<ModelElement> list) {
if (ItemModelFix.getConfig().getOptions().generationType == ItemModelGenerationType.UNLERP) {
ItemModelUtil.unlerpElements(list, sprite.getAnimationFrameDelta());
ItemModelUtil.unlerpElements(list, this.itemmodelfix$sprite.getAnimationFrameDelta());
}
}
}
61 changes: 32 additions & 29 deletions src/main/java/me/pepperbell/itemmodelfix/model/ItemModelUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import java.util.List;
import java.util.Map;

import org.joml.Vector3f;

import me.pepperbell.itemmodelfix.util.MathUtil;
import net.minecraft.client.render.model.json.ModelElement;
import net.minecraft.client.render.model.json.ModelElementFace;
import net.minecraft.client.render.model.json.ModelElementTexture;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteContents;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3f;

public class ItemModelUtil {
public static void unlerpElements(List<ModelElement> elements, float delta) {
Expand All @@ -23,19 +25,20 @@ public static void unlerpElements(List<ModelElement> elements, float delta) {
}

public static List<ModelElement> createOutlineLayerElements(int layer, String key, Sprite sprite) {
SpriteContents contents = sprite.getContents();
List<ModelElement> elements = new ArrayList<>();

int width = sprite.getWidth();
int height = sprite.getHeight();
int width = contents.getWidth();
int height = contents.getHeight();
float xFactor = width / 16.0F;
float yFactor = height / 16.0F;
float animationFrameDelta = sprite.getAnimationFrameDelta();
int[] frames = sprite.getDistinctFrameCount().toArray();
int[] frames = contents.getDistinctFrameCount().toArray();

Map<Direction, ModelElementFace> map = new EnumMap<>(Direction.class);
map.put(Direction.SOUTH, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { 0.0F, 0.0F, 16.0F, 16.0F }, 0, animationFrameDelta)));
map.put(Direction.NORTH, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { 16.0F, 0.0F, 0.0F, 16.0F }, 0, animationFrameDelta)));
elements.add(new ModelElement(new Vec3f(0.0F, 0.0F, 7.5F), new Vec3f(16.0F, 16.0F, 8.5F), map, null, true));
elements.add(new ModelElement(new Vector3f(0.0F, 0.0F, 7.5F), new Vector3f(16.0F, 16.0F, 8.5F), map, null, true));

int first1 = -1;
int first2 = -1;
Expand All @@ -44,14 +47,14 @@ public static List<ModelElement> createOutlineLayerElements(int layer, String ke

for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (!isPixelAlwaysTransparent(sprite, frames, x, y)) {
if (doesPixelHaveEdge(sprite, frames, x, y, PixelDirection.DOWN)) {
if (!isPixelAlwaysTransparent(contents, frames, x, y)) {
if (doesPixelHaveEdge(contents, frames, x, y, PixelDirection.DOWN)) {
if (first1 == -1) {
first1 = x;
}
last1 = x;
}
if (doesPixelHaveEdge(sprite, frames, x, y, PixelDirection.UP)) {
if (doesPixelHaveEdge(contents, frames, x, y, PixelDirection.UP)) {
if (first2 == -1) {
first2 = x;
}
Expand Down Expand Up @@ -81,14 +84,14 @@ public static List<ModelElement> createOutlineLayerElements(int layer, String ke

for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
if (!isPixelAlwaysTransparent(sprite, frames, x, y)) {
if (doesPixelHaveEdge(sprite, frames, x, y, PixelDirection.RIGHT)) {
if (!isPixelAlwaysTransparent(contents, frames, x, y)) {
if (doesPixelHaveEdge(contents, frames, x, y, PixelDirection.RIGHT)) {
if (first1 == -1) {
first1 = y;
}
last1 = y;
}
if (doesPixelHaveEdge(sprite, frames, x, y, PixelDirection.LEFT)) {
if (doesPixelHaveEdge(contents, frames, x, y, PixelDirection.LEFT)) {
if (first2 == -1) {
first2 = y;
}
Expand Down Expand Up @@ -122,76 +125,76 @@ public static List<ModelElement> createOutlineLayerElements(int layer, String ke
public static ModelElement createHorizontalOutlineElement(Direction direction, int layer, String key, int start, int end, int y, int height, float animationFrameDelta, float xFactor, float yFactor) {
Map<Direction, ModelElementFace> faces = new EnumMap<>(Direction.class);
faces.put(direction, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { start / xFactor, y / yFactor, (end + 1) / xFactor, (y + 1) / yFactor }, 0, animationFrameDelta)));
return new ModelElement(new Vec3f(start / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vec3f((end + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true);
return new ModelElement(new Vector3f(start / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vector3f((end + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true);
}

public static ModelElement createVerticalOutlineElement(Direction direction, int layer, String key, int start, int end, int x, int height, float animationFrameDelta, float xFactor, float yFactor) {
Map<Direction, ModelElementFace> faces = new EnumMap<>(Direction.class);
faces.put(direction, new ModelElementFace(null, layer, key, createUnlerpedTexture(new float[] { (x + 1) / xFactor, start / yFactor, x / xFactor, (end + 1) / yFactor }, 0, animationFrameDelta)));
return new ModelElement(new Vec3f(x / xFactor, (height - (end + 1)) / yFactor, 7.5F), new Vec3f((x + 1) / xFactor, (height - start) / yFactor, 8.5F), faces, null, true);
return new ModelElement(new Vector3f(x / xFactor, (height - (end + 1)) / yFactor, 7.5F), new Vector3f((x + 1) / xFactor, (height - start) / yFactor, 8.5F), faces, null, true);
}

public static ModelElementTexture createUnlerpedTexture(float[] uvs, int rotation, float delta) {
return new ModelElementTexture(MathUtil.unlerpUVs(uvs, delta), rotation);
}

public static List<ModelElement> createPixelLayerElements(int layer, String key, Sprite sprite) {
public static List<ModelElement> createPixelLayerElements(int layer, String key, SpriteContents contents) {
List<ModelElement> elements = new ArrayList<>();

int width = sprite.getWidth();
int height = sprite.getHeight();
int width = contents.getWidth();
int height = contents.getHeight();
float xFactor = width / 16.0F;
float yFactor = height / 16.0F;
int[] frames = sprite.getDistinctFrameCount().toArray();
int[] frames = contents.getDistinctFrameCount().toArray();

for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
if (!isPixelAlwaysTransparent(sprite, frames, x, y)) {
if (!isPixelAlwaysTransparent(contents, frames, x, y)) {
Map<Direction, ModelElementFace> faces = new EnumMap<>(Direction.class);
ModelElementFace face = new ModelElementFace(null, layer, key, new ModelElementTexture(new float[] { x / xFactor, y / yFactor, (x + 1) / xFactor, (y + 1) / yFactor }, 0));
ModelElementFace flippedFace = new ModelElementFace(null, layer, key, new ModelElementTexture(new float[] { (x + 1) / xFactor, y / yFactor, x / xFactor, (y + 1) / yFactor }, 0));

faces.put(Direction.SOUTH, face);
faces.put(Direction.NORTH, flippedFace);
for (PixelDirection pixelDirection : PixelDirection.VALUES) {
if (doesPixelHaveEdge(sprite, frames, x, y, pixelDirection)) {
if (doesPixelHaveEdge(contents, frames, x, y, pixelDirection)) {
faces.put(pixelDirection.getDirection(), pixelDirection.isVertical() ? face : flippedFace);
}
}

elements.add(new ModelElement(new Vec3f(x / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vec3f((x + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true));
elements.add(new ModelElement(new Vector3f(x / xFactor, (height - (y + 1)) / yFactor, 7.5F), new Vector3f((x + 1) / xFactor, (height - y) / yFactor, 8.5F), faces, null, true));
}
}
}

return elements;
}

public static boolean isPixelOutsideSprite(Sprite sprite, int x, int y) {
return x < 0 || y < 0 || x >= sprite.getWidth() || y >= sprite.getHeight();
public static boolean isPixelOutsideSprite(SpriteContents contents, int x, int y) {
return x < 0 || y < 0 || x >= contents.getWidth() || y >= contents.getHeight();
}

public static boolean isPixelTransparent(Sprite sprite, int frame, int x, int y) {
return isPixelOutsideSprite(sprite, x, y) ? true : sprite.isPixelTransparent(frame, x, y);
public static boolean isPixelTransparent(SpriteContents contents, int frame, int x, int y) {
return isPixelOutsideSprite(contents, x, y) ? true : contents.isPixelTransparent(frame, x, y);
}

public static boolean isPixelAlwaysTransparent(Sprite sprite, int[] frames, int x, int y) {
public static boolean isPixelAlwaysTransparent(SpriteContents contents, int[] frames, int x, int y) {
for (int frame : frames) {
if (!isPixelTransparent(sprite, frame, x, y)) {
if (!isPixelTransparent(contents, frame, x, y)) {
return false;
}
}
return true;
}

public static boolean doesPixelHaveEdge(Sprite sprite, int[] frames, int x, int y, PixelDirection direction) {
public static boolean doesPixelHaveEdge(SpriteContents contents, int[] frames, int x, int y, PixelDirection direction) {
int x1 = x + direction.getOffsetX();
int y1 = y + direction.getOffsetY();
if (isPixelOutsideSprite(sprite, x1, y1)) {
if (isPixelOutsideSprite(contents, x1, y1)) {
return true;
}
for (int frame : frames) {
if (!isPixelTransparent(sprite, frame, x, y) && isPixelTransparent(sprite, frame, x1, y1)) {
if (!isPixelTransparent(contents, frame, x, y) && isPixelTransparent(contents, frame, x1, y1)) {
return true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

"depends": {
"fabricloader": ">=0.14.7",
"minecraft": ">=1.19",
"minecraft": ">=1.19.3",
"java": ">=17"
},
"recommends": {
Expand Down