/* Copyright (c) 2016 Jesper Öqvist <jesper@llbit.se> * * This file is part of Chunky. * * Chunky is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Chunky is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Chunky. If not, see <http://www.gnu.org/licenses/>. */ package se.llbit.chunky.resources.texturepack; import se.llbit.chunky.resources.BitmapImage; import se.llbit.chunky.resources.ShulkerTexture; import se.llbit.resources.ImageLoader; import java.io.IOException; import java.io.InputStream; import java.util.zip.ZipFile; /** * Loads a set of shulker textures for rendering shulker boxes. * * <p>The shulker texture is an entity texture with top and bottom parts for the sides. * For rendering shulker boxes we are only interested in a complete side texture, so * we manually merge the top and bottom parts to form a complete side. * * @author Jesper Öqvist <jesper@llbit.se> */ public class ShulkerTextureLoader extends TextureLoader { private final SimpleTexture topLoader; private final String entityTexture; private final ShulkerTexture texture; public ShulkerTextureLoader(String topTexture, String entityTexture, ShulkerTexture texture) { this.topLoader = new SimpleTexture(topTexture, texture.top); this.entityTexture = entityTexture; this.texture = texture; } @Override protected boolean load(InputStream imageStream) throws IOException, TextureFormatError { BitmapImage image = ImageLoader.read(imageStream); if (image.width != image.height || image.width % 16 != 0) { throw new TextureFormatError( "Shulker texture must have equal width and height, divisible by 16!"); } int imgW = image.width; int scale = imgW / (16 * 4); texture.bottom.setTexture(loadBottom(image, scale, 32, 28)); texture.side.setTexture(loadSide(image, scale)); return true; } private static BitmapImage loadBottom(BitmapImage spritemap, int scale, int u, int v) { BitmapImage image = new BitmapImage(scale * 16, scale * 16); int x0 = u * scale; int x1 = (u + 16) * scale; int y0 = v * scale; int y1 = (v + 16) * scale; for (int y = y0; y < y1; ++y) { int sy = y - y0; for (int x = x0; x < x1; ++x) { int sx = x - x0; image.setPixel(sx, sy, spritemap.getPixel(x, y)); } } return image; } /** * Load the side texture from the shulker entity texture. * This stitches together the top and bottom parts of the first * side texture. */ private static BitmapImage loadSide(BitmapImage spritemap, int scale) { BitmapImage image = new BitmapImage(scale * 16, scale * 16); // Load the top part: int x0 = 0; int x1 = 16 * scale; int y0 = 16 * scale; int y1 = (16 + 12) * scale; for (int y = y0; y < y1; ++y) { int sy = y - y0; for (int x = x0; x < x1; ++x) { int sx = x - x0; image.setPixel(sx, sy, spritemap.getPixel(x, y)); } } // Load the bottom lip: x0 = 4 * scale; x1 = (4 + 8) * scale; y0 = 44 * scale; y1 = 48 * scale; for (int y = y0; y < y1; ++y) { int sy = y - y0 + 8 * scale; for (int x = x0; x < x1; ++x) { int sx = x - x0 + 4 * scale; image.setPixel(sx, sy, spritemap.getPixel(x, y)); } } // Load the rest of the bottom part: x0 = 0; x1 = 16 * scale; y0 = 48 * scale; y1 = 52 * scale; for (int y = y0; y < y1; ++y) { int sy = y - y0 + 12 * scale; for (int x = x0; x < x1; ++x) { int sx = x - x0; image.setPixel(sx, sy, spritemap.getPixel(x, y)); } } return image; } @Override public boolean load(ZipFile texturePack) { return topLoader.load(texturePack) && load(entityTexture, texturePack); } }