/* * Aphelion * Copyright (c) 2013 Joris van der Wel * * This file is part of Aphelion * * Aphelion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3 of the License. * * Aphelion 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 Affero General Public License * along with Aphelion. If not, see <http://www.gnu.org/licenses/>. * * In addition, the following supplemental terms apply, based on section 7 of * the GNU Affero General Public License (version 3): * a) Preservation of all legal notices and author attributions * b) Prohibition of misrepresentation of the origin of this material, and * modified versions are required to be marked in reasonable ways as * different from the original version (for example by appending a copyright notice). * * Linking this library statically or dynamically with other modules is making a * combined work based on this library. Thus, the terms and conditions of the * GNU Affero General Public License cover the whole combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent modules, * and to copy and distribute the resulting executable under terms of your * choice, provided that you also meet, for each linked independent module, * the terms and conditions of the license of that module. An independent * module is a module which is not derived from or based on this library. */ package aphelion.shared.gameconfig; import aphelion.client.resource.AsyncTexture; import aphelion.shared.resource.ResourceDB; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import org.newdawn.slick.Animation; import org.newdawn.slick.Image; import org.newdawn.slick.SpriteSheet; import org.newdawn.slick.SpriteSheetCounted; /** * * @author Joris */ public class GCImage extends WrappedValueAbstract { private static final Logger log = Logger.getLogger("aphelion.config"); final ResourceDB db; private String resourceKey; private int offsetX, offsetY, offsetWidth, offsetHeight; private int tilesHorizontal = 1, tilesVertical = 1; private int[] frameDuration; private AsyncTexture texture; private Image image; // only set if used private SpriteSheetCounted spriteSheet; // only set if used private boolean tmpDirty = false; /*resource: classic.bombs offset: [0, 0, 208, 16] # x, y, width, height tiles: [10, 1] frame-duration: 60 */ public GCImage(ConfigSelection selection, String key, ResourceDB db) { super(selection, key); this.db = db; } private void unset() { if (set) tmpDirty = true; resourceKey = null; offsetX = offsetY = offsetWidth = offsetHeight = 0; tilesHorizontal = tilesVertical = 1; frameDuration = new int[]{100}; texture = null; image = null; spriteSheet = null; set = false; } @Override boolean newValue(Object value_) { tmpDirty = false; if (value_ == null) { unset(); } else { try { Map value = (Map) value_; setResourceKey((String) value.get("resource")); List offset = (List) value.get("offset"); List animation = (List) value.get("tiles"); Object frameDurationObj = value.get("frame-duration"); if (frameDurationObj == null) { setFrameDuration(new int[]{100}); } else if (frameDurationObj instanceof Integer) { setFrameDuration(new int[]{(Integer) frameDurationObj}); } else { List frameDurationList = (List) frameDurationObj; int[] arr = new int[frameDurationList.size()]; for (int i = 0; i < frameDurationList.size(); ++i) { arr[i] = (Integer) frameDurationList.get(i); } setFrameDuration(arr); } if (offset != null && offset.size() >= 2) { setOffsetX((Integer) offset.get(0)); setOffsetY((Integer) offset.get(1)); } else { setOffsetX(0); setOffsetY(0); } if (offset != null && offset.size() >= 4) { setOffsetWidth((Integer) offset.get(2)); setOffsetHeight((Integer) offset.get(3)); } else { setOffsetWidth(0); setOffsetHeight(0); } if (animation != null && animation.size() >= 2) { setTilesHorizontal((Integer) animation.get(0)); setTilesVertical((Integer) animation.get(1)); } else { setTilesHorizontal(0); setTilesVertical(0); } set = true; } catch (ClassCastException | NullPointerException ex) { log.log(Level.WARNING, "Malformed GCImage value with key " + this.key, ex); unset(); } } if (tmpDirty) { tmpDirty = false; fireChangeListener(); return true; } return false; } public boolean isTextureError() { if (texture == null) { return true; } return texture.isError(); } public AsyncTexture getTexture() { return texture; } public Image getImage() { if (texture == null || !texture.isLoaded()) { return null; } if (image == null) { image = texture.getCachedImage(); if (offsetX > 0 || offsetY > 0 || offsetWidth > 0 || offsetHeight > 0) { int width = this.offsetWidth; int height = this.offsetHeight; if (width == 0) { width = texture.getImageWidth() - 1; } if (height == 0) { height = texture.getImageHeight() - 1; } image = image.getSubImage( offsetX, offsetY, width, height); } } return image; } public SpriteSheetCounted getSpriteSheet() { if (spriteSheet == null) { Image image = getImage(); if (image == null) { return null; } int tileWidth = image.getWidth() / this.tilesHorizontal; int tileHeight = image.getHeight() / this.tilesVertical; if (tileWidth == 0) { tileWidth = 1; } if (tileHeight == 0) { tileHeight = 1; } spriteSheet = new SpriteSheetCounted(image, tileWidth, tileHeight); } return spriteSheet; } public Animation newAnimation() { SpriteSheetCounted sprite = getSpriteSheet(); if (sprite == null) { return null; } Animation anim = new Animation(); anim.setAutoUpdate(true); for (int tile = 0; tile < sprite.getTilesCount(); tile++) { int duration; if (tile < this.frameDuration.length) { duration = this.frameDuration[tile]; } else { duration = this.frameDuration[this.frameDuration.length-1]; } anim.addFrame(sprite.getSubImage(tile), duration); } return anim; } public String getResourceKey() { return resourceKey; } public int getOffsetX() { return offsetX; } public int getOffsetY() { return offsetY; } /** . * @return if 0, use the highest x value for the image */ public int getOffsetWidth() { return offsetWidth; } /** . * @return if 0, use the highest y value for the image */ public int getOffsetHeight() { return offsetHeight; } public int getTilesHorizontal() { return tilesHorizontal; } public int getTilesVertical() { return tilesVertical; } public int[] getFrameDuration() { return frameDuration; } private void setResourceKey(String resourceKey) { if (!Objects.equals(this.resourceKey, resourceKey)) { tmpDirty = true; texture = null; if (resourceKey != null) { texture = db.getTextureLoader().getTexture(resourceKey); } this.image = null; this.spriteSheet = null; } this.resourceKey = resourceKey; } private void setOffsetX(int x) { if (this.offsetX != x) { tmpDirty = true; this.image = null; this.spriteSheet = null; } this.offsetX = x; if (this.offsetX < 0) this.offsetX = 0; } private void setOffsetY(int y) { if (this.offsetY != y) { tmpDirty = true; this.image = null; this.spriteSheet = null; } this.offsetY = y; if (this.offsetY < 0) this.offsetY = 0; } private void setOffsetWidth(int width) { if (this.offsetWidth != width) { tmpDirty = true; this.image = null; this.spriteSheet = null; } this.offsetWidth = width; if (this.offsetWidth < 0) this.offsetWidth = 0; } private void setOffsetHeight(int height) { if (this.offsetHeight != height) { tmpDirty = true; this.image = null; this.spriteSheet = null; } this.offsetHeight = height; if (this.offsetHeight < 0) this.offsetHeight = 0; } private void setTilesHorizontal(int tilesHorizontal) { if (this.tilesHorizontal != tilesHorizontal) { tmpDirty = true; this.spriteSheet = null; } this.tilesHorizontal = tilesHorizontal; if (this.tilesHorizontal < 1) this.tilesHorizontal = 1; } private void setTilesVertical(int tilesVertical) { if (this.tilesVertical != tilesVertical) { tmpDirty = true; this.spriteSheet = null; } this.tilesVertical = tilesVertical; if (this.tilesVertical < 1) this.tilesVertical = 1; } private void setFrameDuration(int frameDuration[]) { if (!Arrays.equals(this.frameDuration, frameDuration)) { tmpDirty = true; } this.frameDuration = frameDuration; } }