package com.prupe.mcpatcher.hd; import com.prupe.mcpatcher.Config; import com.prupe.mcpatcher.MCLogger; import com.prupe.mcpatcher.MCPatcherUtils; import com.prupe.mcpatcher.TexturePackAPI; import com.prupe.mcpatcher.TexturePackChangeHandler; import com.prupe.mcpatcher.hd.CustomAnimation$1; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Map.Entry; import net.minecraft.src.ResourceLocation; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; public class CustomAnimation implements Comparable<CustomAnimation> { private static final MCLogger logger = MCLogger.getLogger("Custom Animations", "Animation"); private static final boolean enable = Config.getBoolean("Extended HD", "animations", true); private static final Map<ResourceLocation, Properties> pending = new HashMap(); private static final List<CustomAnimation> animations = new ArrayList(); private final ResourceLocation propertiesName; private final ResourceLocation dstName; private final ResourceLocation srcName; private final int mipmapLevel; private final ByteBuffer imageData; private final int x; private final int y; private final int w; private final int h; private int currentFrame; private int currentDelay; private int numFrames; private int[] tileOrder; private int[] tileDelay; private final int numTiles; private boolean error; public static void updateAll() { if (!pending.isEmpty()) { try { checkPendingAnimations(); } catch (Throwable var2) { var2.printStackTrace(); logger.error("%d remaining animations cleared", new Object[] {Integer.valueOf(pending.size())}); pending.clear(); } } Iterator i$ = animations.iterator(); while (i$.hasNext()) { CustomAnimation animation = (CustomAnimation)i$.next(); animation.update(); } } private static void checkPendingAnimations() { ArrayList done = new ArrayList(); Iterator i$ = pending.entrySet().iterator(); while (i$.hasNext()) { Entry name = (Entry)i$.next(); ResourceLocation name1 = (ResourceLocation)name.getKey(); Properties properties = (Properties)name.getValue(); ResourceLocation textureName = TexturePackAPI.parseResourceLocation(name1, MCPatcherUtils.getStringProperty(properties, "to", "")); if (TexturePackAPI.isTextureLoaded(textureName)) { addStrip(name1, properties); done.add(name1); } } if (!done.isEmpty()) { i$ = done.iterator(); while (i$.hasNext()) { ResourceLocation name2 = (ResourceLocation)i$.next(); pending.remove(name2); } Collections.sort(animations); } } private static void addStrip(ResourceLocation propertiesName, Properties properties) { ResourceLocation dstName = TexturePackAPI.parseResourceLocation(propertiesName, properties.getProperty("to", "")); if (dstName == null) { logger.error("%s: missing to= property", new Object[0]); } else { ResourceLocation srcName = TexturePackAPI.parseResourceLocation(propertiesName, properties.getProperty("from", "")); if (srcName == null) { logger.error("%s: missing from= property", new Object[0]); } else { BufferedImage srcImage = TexturePackAPI.getImage(srcName); if (srcImage == null) { logger.error("%s: image %s not found in texture pack", new Object[] {propertiesName, srcName}); } else { int x = MCPatcherUtils.getIntProperty(properties, "x", 0); int y = MCPatcherUtils.getIntProperty(properties, "y", 0); int w = MCPatcherUtils.getIntProperty(properties, "w", 0); int h = MCPatcherUtils.getIntProperty(properties, "h", 0); if (dstName.toString().startsWith("minecraft:textures/atlas/")) { logger.error("%s: animations cannot have a target of %s", new Object[] {dstName}); } else if (x >= 0 && y >= 0 && w > 0 && h > 0) { TexturePackAPI.bindTexture(dstName); int dstWidth = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); int dstHeight = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); int levels = MipmapHelper.getMipmapLevelsForCurrentTexture(); if (x + w <= dstWidth && y + h <= dstHeight) { int width = srcImage.getWidth(); int height = srcImage.getHeight(); if (width != w) { srcImage = resizeImage(srcImage, w); width = srcImage.getWidth(); height = srcImage.getHeight(); } if (width == w && height >= h) { ByteBuffer imageData = ByteBuffer.allocateDirect(4 * width * height); int[] argb = new int[width * height]; byte[] rgba = new byte[4 * width * height]; srcImage.getRGB(0, 0, width, height, argb, 0, width); ARGBtoRGBA(argb, rgba); imageData.put(rgba).flip(); for (int mipmapLevel = 0; mipmapLevel <= levels; ++mipmapLevel) { add(new CustomAnimation(propertiesName, srcName, dstName, mipmapLevel, x, y, w, h, imageData, height / h, properties)); if (((x | y | w | h) & 1) != 0 || w <= 0 || h <= 0) { break; } ByteBuffer newImage = ByteBuffer.allocateDirect(width * height); MipmapHelper.scaleHalf(imageData.asIntBuffer(), width, height, newImage.asIntBuffer(), 0); imageData = newImage; width >>= 1; height >>= 1; x >>= 1; y >>= 1; w >>= 1; h >>= 1; } } else { logger.error("%s: %s dimensions %dx%d do not match %dx%d", new Object[] {propertiesName, srcName, Integer.valueOf(width), Integer.valueOf(height), Integer.valueOf(w), Integer.valueOf(h)}); } } else { logger.error("%s: %s dimensions x=%d,y=%d,w=%d,h=%d exceed %s size %dx%d", new Object[] {propertiesName, srcName, Integer.valueOf(x), Integer.valueOf(y), Integer.valueOf(w), Integer.valueOf(h), dstName, Integer.valueOf(dstWidth), Integer.valueOf(dstHeight)}); } } else { logger.error("%s: %s has invalid dimensions x=%d,y=%d,w=%d,h=%d", new Object[] {propertiesName, srcName, Integer.valueOf(x), Integer.valueOf(y), Integer.valueOf(w), Integer.valueOf(h)}); } } } } } private static void add(CustomAnimation animation) { if (animation != null) { animations.add(animation); if (animation.mipmapLevel == 0) { logger.fine("new %s", new Object[] {animation}); } } } private CustomAnimation(ResourceLocation propertiesName, ResourceLocation srcName, ResourceLocation dstName, int mipmapLevel, int x, int y, int w, int h, ByteBuffer imageData, int numFrames, Properties properties) { this.propertiesName = propertiesName; this.srcName = srcName; this.dstName = dstName; this.mipmapLevel = mipmapLevel; this.x = x; this.y = y; this.w = w; this.h = h; this.imageData = imageData; this.numFrames = numFrames; this.currentFrame = -1; this.numTiles = numFrames; this.loadProperties(properties); } void update() { if (!this.error) { int texture = TexturePackAPI.getTextureIfLoaded(this.dstName); if (texture >= 0) { if (--this.currentDelay <= 0) { if (++this.currentFrame >= this.numFrames) { this.currentFrame = 0; } TexturePackAPI.bindTexture(texture); this.update(texture, 0, 0); int glError = GL11.glGetError(); if (glError != 0) { logger.severe("%s: %s", new Object[] {this, GLU.gluErrorString(glError)}); this.error = true; } else { this.currentDelay = this.getDelay(); } } } } } public int compareTo(CustomAnimation o) { return this.dstName.toString().compareTo(o.dstName.toString()); } public String toString() { return String.format("CustomAnimation{%s %s %dx%d -> %s%s @ %d,%d (%d frames)}", new Object[] {this.propertiesName, this.srcName, Integer.valueOf(this.w), Integer.valueOf(this.h), this.dstName, this.mipmapLevel > 0 ? "#" + this.mipmapLevel : "", Integer.valueOf(this.x), Integer.valueOf(this.y), Integer.valueOf(this.numFrames)}); } private static void ARGBtoRGBA(int[] src, byte[] dest) { for (int i = 0; i < src.length; ++i) { int v = src[i]; dest[i * 4 + 3] = (byte)(v >> 24 & 255); dest[i * 4 + 0] = (byte)(v >> 16 & 255); dest[i * 4 + 1] = (byte)(v >> 8 & 255); dest[i * 4 + 2] = (byte)(v >> 0 & 255); } } private static BufferedImage resizeImage(BufferedImage image, int width) { if (width == image.getWidth()) { return image; } else { int height = image.getHeight() * width / image.getWidth(); logger.finer("resizing to %dx%d", new Object[] {Integer.valueOf(width), Integer.valueOf(height)}); BufferedImage newImage = new BufferedImage(width, height, 2); Graphics2D graphics2D = newImage.createGraphics(); graphics2D.drawImage(image, 0, 0, width, height, (ImageObserver)null); return newImage; } } private void loadProperties(Properties properties) { this.loadTileOrder(properties); int i; if (this.tileOrder == null) { this.tileOrder = new int[this.numFrames]; for (i = 0; i < this.numFrames; ++i) { this.tileOrder[i] = i % this.numTiles; } } this.tileDelay = new int[this.numFrames]; this.loadTileDelay(properties); for (i = 0; i < this.numFrames; ++i) { this.tileDelay[i] = Math.max(this.tileDelay[i], 1); } } private void loadTileOrder(Properties properties) { if (properties != null) { int i; for (i = 0; getIntValue(properties, "tile.", i) != null; ++i) { ; } if (i > 0) { this.numFrames = i; this.tileOrder = new int[this.numFrames]; for (i = 0; i < this.numFrames; ++i) { this.tileOrder[i] = Math.abs(getIntValue(properties, "tile.", i).intValue()) % this.numTiles; } } } } private void loadTileDelay(Properties properties) { if (properties != null) { Integer defaultValue = getIntValue(properties, "duration"); for (int i = 0; i < this.numFrames; ++i) { Integer value = getIntValue(properties, "duration.", i); if (value != null) { this.tileDelay[i] = value.intValue(); } else if (defaultValue != null) { this.tileDelay[i] = defaultValue.intValue(); } } } } private static Integer getIntValue(Properties properties, String key) { try { String e = properties.getProperty(key); if (e != null && e.matches("^\\d+$")) { return Integer.valueOf(Integer.parseInt(e)); } } catch (NumberFormatException var3) { ; } return null; } private static Integer getIntValue(Properties properties, String prefix, int index) { return getIntValue(properties, prefix + index); } private void update(int texture, int dx, int dy) { GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, this.mipmapLevel, this.x + dx, this.y + dy, this.w, this.h, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer)this.imageData.position(4 * this.w * this.h * this.tileOrder[this.currentFrame])); } private int getDelay() { return this.tileDelay[this.currentFrame]; } static Map access$000() { return pending; } static MCLogger access$100() { return logger; } static List access$200() { return animations; } static boolean access$300() { return enable; } static { TexturePackChangeHandler.register(new CustomAnimation$1("Extended HD", 1)); } }