From 0de598b20530561971093a15eb0613bc5a3c3cd4 Mon Sep 17 00:00:00 2001 From: Rainnny7 Date: Thu, 11 Apr 2024 05:17:00 -0400 Subject: [PATCH] Add the body part renderer --- .../java/me/braydon/mc/common/ImageUtils.java | 17 ++++++- .../mc/common/renderer/SkinRenderer.java | 48 ++++++++++++------- .../renderer/impl/BodySkinPartRenderer.java | 24 +++++++++- .../impl/IsometricHeadSkinPartRenderer.java | 12 +++-- .../impl/VanillaSkinPartRenderer.java | 5 +- .../me/braydon/mc/model/skin/ISkinPart.java | 44 ++++++++++++++++- .../me/braydon/mc/service/MojangService.java | 2 +- 7 files changed, 123 insertions(+), 29 deletions(-) diff --git a/src/main/java/me/braydon/mc/common/ImageUtils.java b/src/main/java/me/braydon/mc/common/ImageUtils.java index 0323274..ba541a7 100644 --- a/src/main/java/me/braydon/mc/common/ImageUtils.java +++ b/src/main/java/me/braydon/mc/common/ImageUtils.java @@ -39,7 +39,7 @@ public final class ImageUtils { * Scale the given image to the provided size. * * @param image the image to scale - * @param size the size to scale the image to + * @param size the size to scale the image to * @return the scaled image */ @NonNull @@ -50,4 +50,19 @@ public final class ImageUtils { graphics.dispose(); return scaled; } + + /** + * Flip the given image. + * + * @param image the image to flip + * @return the flipped image + */ + @NonNull + public static BufferedImage flip(@NonNull BufferedImage image) { + BufferedImage flipped = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = flipped.createGraphics(); + graphics.drawImage(image, image.getWidth(), 0, 0, image.getHeight(), 0, 0, image.getWidth(), image.getHeight(), null); + graphics.dispose(); + return flipped; + } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/renderer/SkinRenderer.java b/src/main/java/me/braydon/mc/common/renderer/SkinRenderer.java index 4493671..185df5b 100644 --- a/src/main/java/me/braydon/mc/common/renderer/SkinRenderer.java +++ b/src/main/java/me/braydon/mc/common/renderer/SkinRenderer.java @@ -37,18 +37,18 @@ import java.net.URL; /** * A renderer for a {@link ISkinPart}. * - * @author Braydon * @param the type of part to render + * @author Braydon */ public abstract class SkinRenderer { /** * Invoke this render to render the * given skin part for the provided skin. * - * @param skin the skin to render the part for - * @param part the part to render + * @param skin the skin to render the part for + * @param part the part to render * @param overlays whether to render overlays - * @param size the size to scale the skin part to + * @param size the size to scale the skin part to * @return the rendered skin part */ @NonNull public abstract BufferedImage render(@NonNull Skin skin, @NonNull T part, boolean overlays, int size); @@ -63,24 +63,37 @@ public abstract class SkinRenderer { */ @SneakyThrows protected final BufferedImage getVanillaSkinPart(@NonNull Skin skin, @NonNull ISkinPart.Vanilla part, double size) { - return getSkinPartTexture(skin, part.getCoordinates().getX(), part.getCoordinates().getY(), part.getWidth(), part.getHeight(), size); + BufferedImage skinImage = ImageIO.read(new URL(skin.getUrl())); // The skin texture + ISkinPart.Vanilla.Coordinates coordinates = part.getCoordinates(); // The coordinates of the part + + // The skin texture is legacy, use legacy coordinates + if (skinImage.getHeight() == 32 && part.hasLegacyCoordinates()) { + coordinates = part.getLegacyCoordinates(); + } + int width = part.getWidth(); // The width of the part + if (skin.getModel() == Skin.Model.SLIM && part.isArm()) { + width--; + } + BufferedImage partTexture = getSkinPartTexture(skinImage, coordinates.getX(), coordinates.getY(), width, part.getHeight(), size); + if (coordinates instanceof ISkinPart.Vanilla.LegacyCoordinates legacyCoordinates && legacyCoordinates.isFlipped()) { + partTexture = ImageUtils.flip(partTexture); + } + return partTexture; } /** * Get the texture of a specific part of a skin. * - * @param skin the skin to get the part from - * @param x the x position of the part - * @param y the y position of the part - * @param width the width of the part - * @param height the height of the part - * @param size the size to scale the part to + * @param skinImage the skin image to get the part from + * @param x the x position of the part + * @param y the y position of the part + * @param width the width of the part + * @param height the height of the part + * @param size the size to scale the part to * @return the texture of the skin part */ @SneakyThrows - private BufferedImage getSkinPartTexture(@NonNull Skin skin, int x, int y, int width, int height, double size) { - BufferedImage skinImage = ImageIO.read(new URL(skin.getUrl())); // The skin texture - + private BufferedImage getSkinPartTexture(@NonNull BufferedImage skinImage, int x, int y, int width, int height, double size) { // Create a new BufferedImage for the part of the skin texture BufferedImage headTexture = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); @@ -88,8 +101,9 @@ public abstract class SkinRenderer { headTexture.getGraphics().drawImage(skinImage, 0, 0, width, height, x, y, x + width, y + height, null); // Scale the skin part texture - headTexture = ImageUtils.resize(headTexture, size); - + if (size > 0D) { + headTexture = ImageUtils.resize(headTexture, size); + } return headTexture; } @@ -105,7 +119,7 @@ public abstract class SkinRenderer { /** * Apply an overlay to a texture. * - * @param graphics the graphics to overlay on + * @param graphics the graphics to overlay on * @param overlayImage the part to overlay */ protected final void applyOverlay(@NonNull Graphics2D graphics, @NonNull BufferedImage overlayImage) { diff --git a/src/main/java/me/braydon/mc/common/renderer/impl/BodySkinPartRenderer.java b/src/main/java/me/braydon/mc/common/renderer/impl/BodySkinPartRenderer.java index 924e6b7..50e38f2 100644 --- a/src/main/java/me/braydon/mc/common/renderer/impl/BodySkinPartRenderer.java +++ b/src/main/java/me/braydon/mc/common/renderer/impl/BodySkinPartRenderer.java @@ -24,10 +24,12 @@ package me.braydon.mc.common.renderer.impl; import lombok.NonNull; +import me.braydon.mc.common.ImageUtils; import me.braydon.mc.common.renderer.SkinRenderer; import me.braydon.mc.model.skin.ISkinPart; import me.braydon.mc.model.skin.Skin; +import java.awt.*; import java.awt.image.BufferedImage; /** @@ -50,6 +52,26 @@ public final class BodySkinPartRenderer extends SkinRenderer { */ @Override @NonNull public BufferedImage render(@NonNull Skin skin, @NonNull ISkinPart.Custom part, boolean overlays, int size) { - return getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, size); + BufferedImage texture = new BufferedImage(16, 32, BufferedImage.TYPE_INT_ARGB); // The texture to return + Graphics2D graphics = texture.createGraphics(); // Create the graphics for drawing + + // Get the Vanilla skin parts to draw + BufferedImage face = getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, -1); + BufferedImage body = getVanillaSkinPart(skin, ISkinPart.Vanilla.BODY_FRONT, -1); + BufferedImage leftArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_ARM, -1); + BufferedImage rightArm = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_ARM, -1); + BufferedImage leftLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.LEFT_LEG, -1); + BufferedImage rightLeg = getVanillaSkinPart(skin, ISkinPart.Vanilla.RIGHT_LEG, -1); + + // Draw the body parts + graphics.drawImage(face, 4, 0, null); + graphics.drawImage(body, 4, 8, null); + graphics.drawImage(leftArm, skin.getModel() == Skin.Model.SLIM ? 1 : 0, 8, null); + graphics.drawImage(rightArm, 12, 8, null); + graphics.drawImage(leftLeg, 8, 20, null); + graphics.drawImage(rightLeg, 4, 20, null); + + graphics.dispose(); + return ImageUtils.resize(texture, size / 8D); } } \ No newline at end of file diff --git a/src/main/java/me/braydon/mc/common/renderer/impl/IsometricHeadSkinPartRenderer.java b/src/main/java/me/braydon/mc/common/renderer/impl/IsometricHeadSkinPartRenderer.java index 95c457b..e8cd4c8 100644 --- a/src/main/java/me/braydon/mc/common/renderer/impl/IsometricHeadSkinPartRenderer.java +++ b/src/main/java/me/braydon/mc/common/renderer/impl/IsometricHeadSkinPartRenderer.java @@ -63,23 +63,25 @@ public final class IsometricHeadSkinPartRenderer extends SkinRenderer cached = skinPartTextureCache.findById(id); // Get the cached texture if (cached.isPresent()) { // Respond with the cache if present - return cached.get().getTexture(); +// return cached.get().getTexture(); } Skin skin = null; // The target skin to get the skin part of