Package com.pclewis.mcpatcher.mod

Source Code of com.pclewis.mcpatcher.mod.CustomAnimation$Strip

package com.pclewis.mcpatcher.mod;

import com.pclewis.mcpatcher.MCLogger;
import com.pclewis.mcpatcher.MCPatcherUtils;
import com.pclewis.mcpatcher.TexturePackAPI;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Random;

public class CustomAnimation {
    private static final MCLogger logger = MCLogger.getLogger(MCPatcherUtils.HD_TEXTURES);

    private static final String CLASS_NAME = CustomAnimation.class.getSimpleName();

    private static final Random rand = new Random();
    private static final ArrayList<CustomAnimation> animations = new ArrayList<CustomAnimation>();

    private static int boundTexture = -1;

    private final String dstName;
    private final String srcName;
    private final int mipmapLevel;
    private final ByteBuffer imageData;
    private final int tileCount;
    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 boolean error;

    private Delegate delegate;

    public static void updateAll() {
        boundTexture = -1;
        for (CustomAnimation animation : animations) {
            animation.update();
        }
    }

    static void clear() {
        animations.clear();
    }

    static void addStrip(Properties properties) {
        if (properties == null) {
            return;
        }
        try {
            String textureName = properties.getProperty("to", "");
            String srcName = properties.getProperty("from", "");
            int tileCount = Integer.parseInt(properties.getProperty("tiles", "1"));
            int x = Integer.parseInt(properties.getProperty("x", ""));
            int y = Integer.parseInt(properties.getProperty("y", ""));
            int w = Integer.parseInt(properties.getProperty("w", ""));
            int h = Integer.parseInt(properties.getProperty("h", ""));
            if (!"".equals(textureName) && !"".equals(srcName)) {
                newStrip(textureName, tileCount, srcName, TexturePackAPI.getImage(srcName), x, y, w, h, properties);
            }
        } catch (NumberFormatException e) {
        }
    }

    static void addStripOrTile(String textureName, String name, int tileNumber, int tileCount, int minScrollDelay, int maxScrollDelay) {
        if (!addStrip(textureName, name, tileNumber, tileCount)) {
            add(newTile(textureName, tileCount, tileNumber, minScrollDelay, maxScrollDelay));
        }
    }

    static boolean addStrip(String textureName, String name, int tileNumber, int tileCount) {
        String srcName = "/anim/custom_" + name + ".png";
        BufferedImage srcImage = TexturePackAPI.getImage(srcName);
        if (srcImage == null) {
            return false;
        }
        int tileSize = getTileSize(textureName);
        newStrip(textureName, tileCount, srcName, srcImage, (tileNumber % 16) * tileSize, (tileNumber / 16) * tileSize, tileSize, tileSize, null);
        return true;
    }

    private static void add(CustomAnimation animation) {
        if (animation != null) {
            animations.add(animation);
            if (animation.mipmapLevel == 0) {
                logger.fine("new %s", animation);
            }
        }
    }

    private static void newStrip(String dstName, int tileCount, String srcName, BufferedImage srcImage, int x, int y, int w, int h, Properties properties) {
        if (srcImage == null) {
            logger.severe("%s: image %s not found in texture pack", CLASS_NAME, srcName);
            return;
        }
        if (x < 0 || y < 0 || w <= 0 || h <= 0 || tileCount <= 0) {
            logger.severe("%s: %s invalid dimensions x=%d,y=%d,w=%d,h=%d,count=%d", CLASS_NAME, srcName, x, y, w, h, tileCount);
            return;
        }
        int textureID = MCPatcherUtils.getMinecraft().renderEngine.getTexture(dstName);
        if (textureID <= 0) {
            logger.severe("%s: invalid id %d for texture %s", CLASS_NAME, textureID, dstName);
            return;
        }
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
        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.getMipmapLevels();
        if (x + tileCount * w > dstWidth || y + tileCount * h > dstHeight) {
            logger.severe("%s: %s invalid dimensions x=%d,y=%d,w=%d,h=%d,count=%d", CLASS_NAME, srcName, x, y, w, h, tileCount);
            return;
        }
        int width = srcImage.getWidth();
        int height = srcImage.getHeight();
        if (width != w) {
            srcImage = TextureUtils.resizeImage(srcImage, w);
            width = srcImage.getWidth();
            height = srcImage.getHeight();
        }
        if (width != w || height < h) {
            logger.severe("%s: %s dimensions %dx%d do not match %dx%d", CLASS_NAME, srcName, width, height, w, h);
            return;
        }
        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(srcName, dstName, mipmapLevel, tileCount, x, y, w, h, imageData, height / h, properties));
            if (((x | y | w | h) & 0x1) != 0 || w <= 0 || h <= 0) {
                break;
            }
            ByteBuffer newImage = ByteBuffer.allocateDirect(width * height);
            MipmapHelper.scaleHalf(imageData.asIntBuffer(), width, height, newImage.asIntBuffer());
            imageData = newImage;
            width >>= 1;
            height >>= 1;
            x >>= 1;
            y >>= 1;
            w >>= 1;
            h >>= 1;
        }
    }

    private static CustomAnimation newTile(String textureName, int tileCount, int tileNumber, int minScrollDelay, int maxScrollDelay) {
        int tileSize = getTileSize(textureName);
        int x = (tileNumber % 16) * tileSize;
        int y = (tileNumber / 16) * tileSize;
        int w = tileSize;
        int h = tileSize;
        if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + tileCount * w > 16 * tileSize || y + tileCount * h > 16 * tileSize) {
            logger.severe("%s: %s invalid dimensions x=%d,y=%d,w=%d,h=%d", CLASS_NAME, textureName, x, y, w, h);
            return null;
        }
        try {
            return new CustomAnimation(textureName, tileCount, x, y, w, h, minScrollDelay, maxScrollDelay);
        } catch (IOException e) {
            return null;
        }
    }

    private CustomAnimation(String srcName, String dstName, int mipmapLevel, int tileCount, int x, int y, int w, int h, ByteBuffer imageData, int numFrames, Properties properties) {
        this.srcName = srcName;
        this.dstName = dstName;
        this.mipmapLevel = mipmapLevel;
        this.tileCount = tileCount;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.imageData = imageData;
        this.numFrames = numFrames;
        currentFrame = -1;
        delegate = new Strip(properties);
    }

    private CustomAnimation(String dstName, int tileCount, int x, int y, int w, int h, int minScrollDelay, int maxScrollDelay) throws IOException {
        this.srcName = dstName;
        this.dstName = dstName;
        this.mipmapLevel = 0;
        this.tileCount = tileCount;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.imageData = ByteBuffer.allocateDirect(4 * w * h);
        this.numFrames = h;
        currentFrame = -1;
        delegate = new Tile(minScrollDelay, maxScrollDelay);
    }

    void update() {
        if (error) {
            return;
        }
        int texture = TexturePackAPI.getTextureIfLoaded(dstName);
        if (texture < 0) {
            return;
        }
        if (--currentDelay > 0) {
            return;
        }
        if (++currentFrame >= numFrames) {
            currentFrame = 0;
        }
        if (texture != boundTexture) {
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
            boundTexture = texture;
        }
        for (int i = 0; i < tileCount; i++) {
            for (int j = 0; j < tileCount; j++) {
                delegate.update(texture, i * w, j * h);
                int glError = GL11.glGetError();
                if (glError != 0) {
                    logger.severe("%s: %s", this, GLU.gluErrorString(glError));
                    error = true;
                    return;
                }
            }
        }
        currentDelay = delegate.getDelay();
    }

    @Override
    public String toString() {
        return String.format("%s %s %dx%d -> %s%s @ %d,%d (%d frames)",
            CLASS_NAME, srcName, w, h, dstName, (mipmapLevel > 0 ? "#" + mipmapLevel : ""), x, y, 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) & 0xff);
            dest[(i * 4) + 0] = (byte) ((v >> 16) & 0xff);
            dest[(i * 4) + 1] = (byte) ((v >> 8) & 0xff);
            dest[(i * 4) + 2] = (byte) ((v >> 0) & 0xff);
        }
    }

    private static int getTileSize(String textureName) {
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, MCPatcherUtils.getMinecraft().renderEngine.getTexture(textureName));
        return GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH) / 16;
    }

    private interface Delegate {
        public void update(int texture, int dx, int dy);

        public int getDelay();
    }

    private class Tile implements Delegate {
        private final int minScrollDelay;
        private final int maxScrollDelay;

        Tile(int minScrollDelay, int maxScrollDelay) throws IOException {
            this.minScrollDelay = minScrollDelay;
            this.maxScrollDelay = maxScrollDelay;
            error = this.minScrollDelay < 0;
            BufferedImage tiles = TexturePackAPI.getImage(dstName);
            int rgbInt[] = new int[w * h];
            byte rgbByte[] = new byte[4 * w * h];
            tiles.getRGB(x, y, w, h, rgbInt, 0, w);
            ARGBtoRGBA(rgbInt, rgbByte);
            imageData.put(rgbByte);
        }

        public void update(int texture, int dx, int dy) {
            int rowOffset = h - currentFrame;
            GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, mipmapLevel, x + dx, y + dy + h - rowOffset, w, rowOffset, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) imageData.position(0));
            GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, mipmapLevel, x + dx, y + dy, w, h - rowOffset, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) imageData.position(4 * w * rowOffset));
        }

        public int getDelay() {
            if (maxScrollDelay > 0) {
                return rand.nextInt(maxScrollDelay - minScrollDelay + 1) + minScrollDelay;
            } else {
                return 0;
            }
        }
    }

    private class Strip implements Delegate {
        private int[] tileOrder;
        private int[] tileDelay;
        private final int numTiles;

        Strip(Properties properties) {
            numTiles = numFrames;
            if (properties == null) {
                properties = TexturePackAPI.getProperties(srcName.replace(".png", ".properties"));
            }
            loadProperties(properties);
        }

        private void loadProperties(Properties properties) {
            loadTileOrder(properties);
            if (tileOrder == null) {
                tileOrder = new int[numFrames];
                for (int i = 0; i < numFrames; i++) {
                    tileOrder[i] = i % numTiles;
                }
            }
            tileDelay = new int[numFrames];
            loadTileDelay(properties);
            for (int i = 0; i < numFrames; i++) {
                tileDelay[i] = Math.max(tileDelay[i], 1);
            }
        }

        private void loadTileOrder(Properties properties) {
            if (properties == null) {
                return;
            }
            int i = 0;
            for (; getIntValue(properties, "tile.", i) != null; i++) {
            }
            if (i > 0) {
                numFrames = i;
                tileOrder = new int[numFrames];
                for (i = 0; i < numFrames; i++) {
                    tileOrder[i] = Math.abs(getIntValue(properties, "tile.", i)) % numTiles;
                }
            }
        }

        private void loadTileDelay(Properties properties) {
            if (properties == null) {
                return;
            }
            Integer defaultValue = getIntValue(properties, "duration");
            for (int i = 0; i < numFrames; i++) {
                Integer value = getIntValue(properties, "duration.", i);
                if (value != null) {
                    tileDelay[i] = value;
                } else if (defaultValue != null) {
                    tileDelay[i] = defaultValue;
                }
            }
        }

        private Integer getIntValue(Properties properties, String key) {
            try {
                String value = properties.getProperty(key);
                if (value != null && value.matches("^\\d+$")) {
                    return Integer.parseInt(value);
                }
            } catch (NumberFormatException e) {
            }
            return null;
        }

        private Integer getIntValue(Properties properties, String prefix, int index) {
            return getIntValue(properties, prefix + index);
        }

        public void update(int texture, int dx, int dy) {
            GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, mipmapLevel, x + dx, y + dy, w, h, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) imageData.position(4 * w * h * tileOrder[currentFrame]));
        }

        public int getDelay() {
            return tileDelay[currentFrame];
        }
    }
}
TOP

Related Classes of com.pclewis.mcpatcher.mod.CustomAnimation$Strip

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.