diff --git a/src/main/java/com/minelittlepony/client/pony/Pony.java b/src/main/java/com/minelittlepony/client/pony/Pony.java index 07c50669..e5b6c935 100644 --- a/src/main/java/com/minelittlepony/client/pony/Pony.java +++ b/src/main/java/com/minelittlepony/client/pony/Pony.java @@ -1,7 +1,6 @@ package com.minelittlepony.client.pony; import com.google.common.base.MoreObjects; -import com.minelittlepony.client.MineLittlePony; import com.minelittlepony.client.PonyRenderManager; import com.minelittlepony.client.render.IPonyRender; import com.minelittlepony.client.transform.PonyTransformation; @@ -11,8 +10,6 @@ import com.minelittlepony.pony.meta.Race; import com.minelittlepony.pony.meta.Size; import net.minecraft.block.Material; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.texture.NativeImage; -import net.minecraft.client.texture.TextureManager; import net.minecraft.entity.Entity; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.LivingEntity; @@ -20,31 +17,17 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ArmorItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.resource.Resource; import net.minecraft.util.Identifier; import net.minecraft.util.math.Box; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.concurrent.atomic.AtomicInteger; - -import static com.mojang.blaze3d.platform.GlStateManager.getTexLevelParameter; -import static org.lwjgl.opengl.GL11.*; @Immutable public class Pony implements IPony { - private static final AtomicInteger ponyCount = new AtomicInteger(); - - private static final NativeImage.Format[] formats = NativeImage.Format.values(); - - private final int ponyId = ponyCount.getAndIncrement(); - private final Identifier texture; private final IPonyData metadata; @@ -56,19 +39,7 @@ public class Pony implements IPony { } Pony(Identifier resource) { - texture = resource; - metadata = checkSkin(texture); - } - - private IPonyData checkSkin(Identifier resource) { - IPonyData data = checkPonyMeta(resource); - if (data != null) { - return data; - } - - try (NativeImage ponyTexture = getBufferedImage(resource)) { - return checkSkin(ponyTexture); - } + this(resource, PonyData.parse(resource)); } @Override @@ -79,81 +50,6 @@ public class Pony implements IPony { } } - @Nullable - private IPonyData checkPonyMeta(Identifier resource) { - try { - Resource res = MinecraftClient.getInstance().getResourceManager().getResource(resource); - - PonyData data = res.getMetadata(PonyData.SERIALISER); - - if (data != null) { - return data; - } - } catch (FileNotFoundException e) { - // Ignore uploaded texture - } catch (IOException e) { - MineLittlePony.logger.warn("Unable to read {} metadata", resource, e); - } - - return null; - } - - private static NativeImage.Format getFormat(int glFormat) { - for (NativeImage.Format i : formats) { - if (i.getPixelDataFormat() == glFormat) { - return i; - } - } - - throw new RuntimeException("Unsupported image format"); - } - - @Nullable - private static NativeImage getBufferedImage(@Nullable Identifier resource) { - if (resource == null) { - return null; - } - - MinecraftClient mc = MinecraftClient.getInstance(); - TextureManager textures = mc.getTextureManager(); - - if (!mc.isOnThread()) { - throw new RuntimeException("This can only be called from the main thread."); - } - // recreate NativeImage from the GL matrix - textures.bindTexture(resource); - - int format = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT); - int width = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH); - int height = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT); - - if (width * height == 0) { - throw new IllegalStateException("GL texture not uploaded yet"); - } - - NativeImage.Format channels = getFormat(format); - - NativeImage image = new NativeImage(channels, width, height, false); - - // This allocates a new array to store the image every time. - // Don't do this every time. Keep a cache and store it so we don't destroy memory. - try { - image.loadFromTextureImage(0, false); - } catch (IllegalStateException e) { - image.close(); - throw e; - } - return image; - } - - private IPonyData checkSkin(@Nullable NativeImage bufferedimage) { - if (bufferedimage == null) { - return new PonyData(); - } - MineLittlePony.logger.debug("\tStart skin check for pony #{} with image {}.", ponyId, bufferedimage); - return PonyData.parse(bufferedimage); - } - @Override public boolean isPerformingRainboom(LivingEntity entity) { Vec3d motion = entity.getVelocity(); diff --git a/src/main/java/com/minelittlepony/client/pony/PonyData.java b/src/main/java/com/minelittlepony/client/pony/PonyData.java index bef66570..948873a7 100644 --- a/src/main/java/com/minelittlepony/client/pony/PonyData.java +++ b/src/main/java/com/minelittlepony/client/pony/PonyData.java @@ -1,9 +1,14 @@ package com.minelittlepony.client.pony; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.texture.NativeImage; +import net.minecraft.resource.Resource; +import net.minecraft.util.Identifier; import com.google.common.base.MoreObjects; import com.google.gson.annotations.Expose; +import com.minelittlepony.client.MineLittlePony; +import com.minelittlepony.client.util.render.NativeUtil; import com.minelittlepony.pony.IPonyData; import com.minelittlepony.pony.meta.Gender; import com.minelittlepony.pony.meta.Race; @@ -14,8 +19,11 @@ import com.minelittlepony.pony.meta.Wearable; import com.minelittlepony.util.animation.BasicEasingInterpolator; import com.minelittlepony.util.animation.IInterpolator; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.UUID; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** @@ -25,7 +33,33 @@ import javax.annotation.concurrent.Immutable; @Immutable public class PonyData implements IPonyData { - public static final PonyDataSerialiser SERIALISER = new PonyDataSerialiser(); + private static final PonyDataSerialiser SERIALISER = new PonyDataSerialiser(); + + /** + * Parses the given resource into a new IPonyData. + * This may either come from an attached json file or the image itself. + */ + public static IPonyData parse(@Nullable Identifier identifier) { + if (identifier == null) { + return new PonyData(); + } + + try { + Resource res = MinecraftClient.getInstance().getResourceManager().getResource(identifier); + + PonyData data = res.getMetadata(SERIALISER); + + if (data != null) { + return data; + } + } catch (FileNotFoundException e) { + // Ignore uploaded texture + } catch (IOException e) { + MineLittlePony.logger.warn("Unable to read {} metadata", identifier, e); + } + + return NativeUtil.parseImage(identifier, PonyData::new); + } @Expose private final Race race; @@ -100,6 +134,11 @@ public class PonyData implements IPonyData { return wearables[wearable.ordinal()]; } + @Override + public IInterpolator getInterpolator(UUID interpolatorId) { + return BasicEasingInterpolator.getInstance(interpolatorId); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) @@ -111,16 +150,4 @@ public class PonyData implements IPonyData { .add("glowColor", "#" + Integer.toHexString(glowColor)) .toString(); } - - @Override - public IInterpolator getInterpolator(UUID interpolatorId) { - return BasicEasingInterpolator.getInstance(interpolatorId); - } - - /** - * Parses an image buffer into a new IPonyData representing the values stored in it's individual trigger pixels. - */ - public static IPonyData parse(NativeImage image) { - return new PonyData(image); - } } diff --git a/src/main/java/com/minelittlepony/client/util/render/NativeUtil.java b/src/main/java/com/minelittlepony/client/util/render/NativeUtil.java new file mode 100644 index 00000000..563d83e3 --- /dev/null +++ b/src/main/java/com/minelittlepony/client/util/render/NativeUtil.java @@ -0,0 +1,57 @@ +package com.minelittlepony.client.util.render; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.util.Identifier; + +import java.util.function.Function; + +import static com.mojang.blaze3d.platform.GlStateManager.getTexLevelParameter; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_HEIGHT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_INTERNAL_FORMAT; +import static org.lwjgl.opengl.GL11.GL_TEXTURE_WIDTH; + +public class NativeUtil { + private static final NativeImage.Format[] formats = NativeImage.Format.values(); + + public static NativeImage.Format getFormat(int glFormat) { + for (NativeImage.Format i : formats) { + if (i.getPixelDataFormat() == glFormat) { + return i; + } + } + + throw new RuntimeException("Unsupported image format"); + } + + public static T parseImage(Identifier resource, Function consumer) { + MinecraftClient mc = MinecraftClient.getInstance(); + TextureManager textures = mc.getTextureManager(); + + if (!mc.isOnThread()) { + throw new IllegalStateException("This can only be called from the main thread."); + } + + // recreate NativeImage from the GL matrix + textures.bindTexture(resource); + + int format = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT); + int width = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH); + int height = getTexLevelParameter(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT); + + if (width * height == 0) { + throw new IllegalStateException("GL texture not uploaded yet"); + } + + try (NativeImage image = new NativeImage(getFormat(format), width, height, false)) { + // This allocates a new array to store the image every time. + // Don't do this every time. Keep a cache and store it so we don't destroy memory. + image.loadFromTextureImage(0, false); + + return consumer.apply(image); + } + } + +}