Add the body part renderer
This commit is contained in:
parent
4f24b8eee5
commit
0de598b205
@ -50,4 +50,19 @@ public final class ImageUtils {
|
|||||||
graphics.dispose();
|
graphics.dispose();
|
||||||
return scaled;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -37,8 +37,8 @@ import java.net.URL;
|
|||||||
/**
|
/**
|
||||||
* A renderer for a {@link ISkinPart}.
|
* A renderer for a {@link ISkinPart}.
|
||||||
*
|
*
|
||||||
* @author Braydon
|
|
||||||
* @param <T> the type of part to render
|
* @param <T> the type of part to render
|
||||||
|
* @author Braydon
|
||||||
*/
|
*/
|
||||||
public abstract class SkinRenderer<T extends ISkinPart> {
|
public abstract class SkinRenderer<T extends ISkinPart> {
|
||||||
/**
|
/**
|
||||||
@ -63,13 +63,28 @@ public abstract class SkinRenderer<T extends ISkinPart> {
|
|||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
protected final BufferedImage getVanillaSkinPart(@NonNull Skin skin, @NonNull ISkinPart.Vanilla part, double size) {
|
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.
|
* Get the texture of a specific part of a skin.
|
||||||
*
|
*
|
||||||
* @param skin the skin to get the part from
|
* @param skinImage the skin image to get the part from
|
||||||
* @param x the x position of the part
|
* @param x the x position of the part
|
||||||
* @param y the y position of the part
|
* @param y the y position of the part
|
||||||
* @param width the width of the part
|
* @param width the width of the part
|
||||||
@ -78,9 +93,7 @@ public abstract class SkinRenderer<T extends ISkinPart> {
|
|||||||
* @return the texture of the skin part
|
* @return the texture of the skin part
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private BufferedImage getSkinPartTexture(@NonNull Skin skin, int x, int y, int width, int height, double size) {
|
private BufferedImage getSkinPartTexture(@NonNull BufferedImage skinImage, int x, int y, int width, int height, double size) {
|
||||||
BufferedImage skinImage = ImageIO.read(new URL(skin.getUrl())); // The skin texture
|
|
||||||
|
|
||||||
// Create a new BufferedImage for the part of the skin texture
|
// Create a new BufferedImage for the part of the skin texture
|
||||||
BufferedImage headTexture = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage headTexture = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
@ -88,8 +101,9 @@ public abstract class SkinRenderer<T extends ISkinPart> {
|
|||||||
headTexture.getGraphics().drawImage(skinImage, 0, 0, width, height, x, y, x + width, y + height, null);
|
headTexture.getGraphics().drawImage(skinImage, 0, 0, width, height, x, y, x + width, y + height, null);
|
||||||
|
|
||||||
// Scale the skin part texture
|
// Scale the skin part texture
|
||||||
|
if (size > 0D) {
|
||||||
headTexture = ImageUtils.resize(headTexture, size);
|
headTexture = ImageUtils.resize(headTexture, size);
|
||||||
|
}
|
||||||
return headTexture;
|
return headTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,12 @@
|
|||||||
package me.braydon.mc.common.renderer.impl;
|
package me.braydon.mc.common.renderer.impl;
|
||||||
|
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
|
import me.braydon.mc.common.ImageUtils;
|
||||||
import me.braydon.mc.common.renderer.SkinRenderer;
|
import me.braydon.mc.common.renderer.SkinRenderer;
|
||||||
import me.braydon.mc.model.skin.ISkinPart;
|
import me.braydon.mc.model.skin.ISkinPart;
|
||||||
import me.braydon.mc.model.skin.Skin;
|
import me.braydon.mc.model.skin.Skin;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +52,26 @@ public final class BodySkinPartRenderer extends SkinRenderer<ISkinPart.Custom> {
|
|||||||
*/
|
*/
|
||||||
@Override @NonNull
|
@Override @NonNull
|
||||||
public BufferedImage render(@NonNull Skin skin, @NonNull ISkinPart.Custom part, boolean overlays, int size) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -63,23 +63,25 @@ public final class IsometricHeadSkinPartRenderer extends SkinRenderer<ISkinPart.
|
|||||||
double zOffset = scale * 3.5D;
|
double zOffset = scale * 3.5D;
|
||||||
double xOffset = scale * 2D;
|
double xOffset = scale * 2D;
|
||||||
|
|
||||||
BufferedImage texture = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage texture = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); // The texture to return
|
||||||
Graphics2D graphics = texture.createGraphics();
|
Graphics2D graphics = texture.createGraphics(); // Create the graphics for drawing
|
||||||
|
|
||||||
|
// Get the Vanilla skin parts to draw
|
||||||
BufferedImage headTop = getVanillaSkinPart(skin, ISkinPart.Vanilla.HEAD_TOP, scale);
|
BufferedImage headTop = getVanillaSkinPart(skin, ISkinPart.Vanilla.HEAD_TOP, scale);
|
||||||
BufferedImage face = getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, scale);
|
BufferedImage face = getVanillaSkinPart(skin, ISkinPart.Vanilla.FACE, scale);
|
||||||
BufferedImage headLeft = getVanillaSkinPart(skin, ISkinPart.Vanilla.HEAD_LEFT, scale);
|
BufferedImage headLeft = getVanillaSkinPart(skin, ISkinPart.Vanilla.HEAD_LEFT, scale);
|
||||||
|
|
||||||
// Draw the top of the left
|
// Draw the top head part
|
||||||
drawPart(graphics, headTop, HEAD_TOP_TRANSFORM, -0.5 - zOffset, xOffset + zOffset, headTop.getWidth(), headTop.getHeight() + 2);
|
drawPart(graphics, headTop, HEAD_TOP_TRANSFORM, -0.5 - zOffset, xOffset + zOffset, headTop.getWidth(), headTop.getHeight() + 2);
|
||||||
|
|
||||||
// Draw the face of the head
|
// Draw the face part
|
||||||
double x = xOffset + 8 * scale;
|
double x = xOffset + 8 * scale;
|
||||||
drawPart(graphics, face, FACE_TRANSFORM, x, x + zOffset - 0.5, face.getWidth(), face.getHeight());
|
drawPart(graphics, face, FACE_TRANSFORM, x, x + zOffset - 0.5, face.getWidth(), face.getHeight());
|
||||||
|
|
||||||
// Draw the left side of the head
|
// Draw the left head part
|
||||||
drawPart(graphics, headLeft, HEAD_LEFT_TRANSFORM, xOffset + 1, zOffset - 0.5, headLeft.getWidth(), headLeft.getHeight());
|
drawPart(graphics, headLeft, HEAD_LEFT_TRANSFORM, xOffset + 1, zOffset - 0.5, headLeft.getWidth(), headLeft.getHeight());
|
||||||
|
|
||||||
|
graphics.dispose();
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,8 @@ public final class VanillaSkinPartRenderer extends SkinRenderer<ISkinPart.Vanill
|
|||||||
return partImage;
|
return partImage;
|
||||||
}
|
}
|
||||||
// Create a new image, draw our skin part texture, and then apply overlays
|
// Create a new image, draw our skin part texture, and then apply overlays
|
||||||
BufferedImage texture = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage texture = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); // The texture to return
|
||||||
Graphics2D graphics = texture.createGraphics();
|
Graphics2D graphics = texture.createGraphics(); // Create the graphics for drawing
|
||||||
graphics.drawImage(partImage, 0, 0, null);
|
graphics.drawImage(partImage, 0, 0, null);
|
||||||
|
|
||||||
// Draw part overlays
|
// Draw part overlays
|
||||||
@ -68,6 +68,7 @@ public final class VanillaSkinPartRenderer extends SkinRenderer<ISkinPart.Vanill
|
|||||||
applyOverlay(graphics, getVanillaSkinPart(skin, overlay, scale));
|
applyOverlay(graphics, getVanillaSkinPart(skin, overlay, scale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
graphics.dispose();
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -78,7 +78,7 @@ public interface ISkinPart {
|
|||||||
/**
|
/**
|
||||||
* A part of a Vanilla skin texture.
|
* A part of a Vanilla skin texture.
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor @RequiredArgsConstructor @Getter @ToString
|
@RequiredArgsConstructor @Getter @ToString
|
||||||
enum Vanilla implements ISkinPart {
|
enum Vanilla implements ISkinPart {
|
||||||
// Overlays
|
// Overlays
|
||||||
HEAD_OVERLAY_FACE(new Coordinates(40, 8), 8, 8),
|
HEAD_OVERLAY_FACE(new Coordinates(40, 8), 8, 8),
|
||||||
@ -89,7 +89,21 @@ public interface ISkinPart {
|
|||||||
HEAD_LEFT(new Coordinates(0, 8), 8, 8),
|
HEAD_LEFT(new Coordinates(0, 8), 8, 8),
|
||||||
HEAD_RIGHT(new Coordinates(16, 8), 8, 8),
|
HEAD_RIGHT(new Coordinates(16, 8), 8, 8),
|
||||||
HEAD_BOTTOM(new Coordinates(16, 0), 8, 8),
|
HEAD_BOTTOM(new Coordinates(16, 0), 8, 8),
|
||||||
HEAD_BACK(new Coordinates(24, 8), 8, 8);
|
HEAD_BACK(new Coordinates(24, 8), 8, 8),
|
||||||
|
|
||||||
|
// Body
|
||||||
|
BODY_FRONT(new Coordinates(20, 20), 8, 12),
|
||||||
|
BODY_BACK(new Coordinates(20, 36), 8, 12),
|
||||||
|
BODY_LEFT(new Coordinates(32, 52), 4, 12),
|
||||||
|
BODY_RIGHT(new Coordinates(44, 20), 4, 12),
|
||||||
|
|
||||||
|
// Arms
|
||||||
|
LEFT_ARM(new Coordinates(44, 20), 4, 12),
|
||||||
|
RIGHT_ARM(new Coordinates(36, 52), new LegacyCoordinates(44, 20, true), 4, 12),
|
||||||
|
|
||||||
|
// Legs
|
||||||
|
LEFT_LEG(new Coordinates(4, 20), 4, 12),
|
||||||
|
RIGHT_LEG(new Coordinates(20, 52), new LegacyCoordinates(4, 20, true), 4, 12);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The coordinates of this part.
|
* The coordinates of this part.
|
||||||
@ -119,6 +133,14 @@ public interface ISkinPart {
|
|||||||
this(coordinates, null, width, height, overlays);
|
this(coordinates, null, width, height, overlays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vanilla(@NonNull Coordinates coordinates, LegacyCoordinates legacyCoordinates, int width, int height, Vanilla... overlays) {
|
||||||
|
this.coordinates = coordinates;
|
||||||
|
this.legacyCoordinates = legacyCoordinates;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.overlays = overlays;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a part of a skin.
|
* Render a part of a skin.
|
||||||
*
|
*
|
||||||
@ -132,6 +154,24 @@ public interface ISkinPart {
|
|||||||
return VanillaSkinPartRenderer.INSTANCE.render(skin, this, overlays, size);
|
return VanillaSkinPartRenderer.INSTANCE.render(skin, this, overlays, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this part an arm?
|
||||||
|
*
|
||||||
|
* @return whether this part is an arm
|
||||||
|
*/
|
||||||
|
public boolean isArm() {
|
||||||
|
return this == LEFT_ARM || this == RIGHT_ARM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this part have legacy coordinates?
|
||||||
|
*
|
||||||
|
* @return whether this part has legacy coordinates
|
||||||
|
*/
|
||||||
|
public boolean hasLegacyCoordinates() {
|
||||||
|
return legacyCoordinates != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coordinates of a part of a skin.
|
* Coordinates of a part of a skin.
|
||||||
*/
|
*/
|
||||||
|
@ -196,7 +196,7 @@ public final class MojangService {
|
|||||||
|
|
||||||
Optional<CachedSkinPartTexture> cached = skinPartTextureCache.findById(id); // Get the cached texture
|
Optional<CachedSkinPartTexture> cached = skinPartTextureCache.findById(id); // Get the cached texture
|
||||||
if (cached.isPresent()) { // Respond with the cache if present
|
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
|
Skin skin = null; // The target skin to get the skin part of
|
||||||
|
Loading…
Reference in New Issue
Block a user