/src/worm/features/LayersFeature.java
Java | 454 lines | 313 code | 48 blank | 93 comment | 96 complexity | 46ac40a65f4bfd53b881b1855216e0c8 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0
- /*
- * Copyright (c) 2003-onwards Shaven Puppy Ltd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'Shaven Puppy' nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package worm.features;
-
- import java.util.List;
-
- import net.puppygames.applet.Screen;
- import net.puppygames.applet.effects.Emitter;
- import net.puppygames.applet.effects.EmitterFeature;
-
- import org.lwjgl.util.*;
- import org.w3c.dom.Element;
-
- import worm.*;
- import worm.animation.ThingWithLayers;
-
- import com.shavenpuppy.jglib.Point2f;
- import com.shavenpuppy.jglib.resources.Feature;
- import com.shavenpuppy.jglib.resources.MappedColor;
- import com.shavenpuppy.jglib.sprites.*;
- import com.shavenpuppy.jglib.util.FPMath;
- import com.shavenpuppy.jglib.util.XMLUtil;
-
- /**
- * Describes layers of animation
- */
- public class LayersFeature extends Feature {
-
- /**
- * The name of shadows colours
- */
- public static final String SHADOW_COLOR_NAME = "shadow".intern();
-
- private static final long serialVersionUID = 1L;
-
- private static final Color TEMP = new Color();
-
- /*
- * Resource data
- */
-
- /** The various layers */
- private Layer[] sprite;
- private EmitterLayer[] emitter;
- private float scale = 1.0f;
- private Point offset;
- private float ySortOffset;
-
- /*
- * Transient data
- */
-
- /** Whether we have any "colored" sprites */
- private transient boolean hasColored;
-
- /** Whether any of the colored sprites are attenuated */
- private transient boolean hasAttenuated;
-
- /** Layers */
- private static class Layer extends Feature {
-
- private String id;
- private int layer;
- private int subLayer;
- private Point2f offset;
- private float ySortOffset;
- private String animation;
- private String image;
- private boolean doChildOffset;
-
- // Either we use colored, to color the whole sprite; or we use topColored and bottomColored, to color the top and bottom of the sprite
- private MappedColor colored;
- private MappedColor topColored, bottomColored;
-
- /** If true, then we'll attenuate the colors with the level colors attenuation colour according to approx. distance from map centre */
- private boolean attenuated;
-
- private transient Animation animationResource;
- private transient SpriteImage imageResource;
-
- public Layer() {
- setAutoCreated();
- setSubResource(true);
- }
-
- }
-
- /** Emitters */
- private static class EmitterLayer extends Feature {
- private String emitter;
- private Point2f offset;
- private float ySortOffset;
- private boolean doChildOffset;
-
- private transient EmitterFeature emitterFeature;
-
- public EmitterLayer() {
- setAutoCreated();
- setSubResource(true);
- }
- }
-
- /**
- * C'tor
- */
- public LayersFeature() {
- setAutoCreated();
- }
-
- /**
- * C'tor
- * @param name
- */
- public LayersFeature(String name) {
- super(name);
- setAutoCreated();
- }
-
- @Override
- public void load(Element element, Loader loader) throws Exception {
- super.load(element, loader);
-
- List<Element> layerElements = XMLUtil.getChildren(element, "sprite");
- if (layerElements.size() > 0) {
- sprite = new Layer[layerElements.size()];
- int count = 0;
- for (Element child : layerElements) {
- sprite[count] = new Layer();
- sprite[count].load(child, loader);
- count ++;
- }
- }
-
- List<Element> emitterLayerElements = XMLUtil.getChildren(element, "emitter");
- if (emitterLayerElements.size() > 0) {
- emitter = new EmitterLayer[emitterLayerElements.size()];
- int emitterCount = 0;
- for (Element child : emitterLayerElements) {
- emitter[emitterCount] = new EmitterLayer();
- emitter[emitterCount].load(child, loader);
- emitterCount ++;
- }
- }
-
- }
-
- @Override
- protected void doCreate() {
- super.doCreate();
-
- if (sprite != null) {
- for (Layer element : sprite) {
- element.create();
- if (element.colored != null || element.topColored != null && element.bottomColored != null) {
- hasColored = true;
- if (element.attenuated) {
- hasAttenuated = true;
- }
- }
- }
- }
- if (emitter != null) {
- for (EmitterLayer element : emitter) {
- element.create();
- }
- }
- }
-
- @Override
- protected void doDestroy() {
- super.doDestroy();
-
- if (sprite != null) {
- for (Layer element : sprite) {
- element.destroy();
- }
- }
- if (emitter != null) {
- for (EmitterLayer element : emitter) {
- element.destroy();
- }
- }
- }
-
- /**
- * Find a layer by name
- * @param id Name; cannot be null
- * @return an index, or -1
- */
- public int getLayer(String id) {
- if (sprite == null) {
- return -1;
- }
- for (int i = 0; i < sprite.length; i ++) {
- if (id.equals(sprite[i].id)) {
- return i;
- }
- }
- return -1;
- }
-
- /**
- * Create the sprites for an entity
- * @param allocator The screen to create the sprites on
- * @param owner Owner of the sprites
- */
- public void createSprites(SpriteAllocator allocator, ThingWithLayers owner) {
- createSprites(allocator, 0.0f, 0.0f, owner);
- }
-
- /**
- * Create the sprites for an entity
- * @param allocator The screen to create the sprites on
- * @param mapX location of the entity's centre
- * @param mapY location of the entity's centre
- * @param owner Owner of the sprites
- */
- public void createSprites(SpriteAllocator allocator, float mapX, float mapY, ThingWithLayers owner) {
- if (sprite == null) {
- owner.setSprites(new Sprite[0]);
- return;
- }
-
- Sprite[] s = new Sprite[sprite.length];
- float ox, oy;
- if (offset != null) {
- ox = offset.getX();
- oy = offset.getY();
- } else {
- ox = 0.0f;
- oy = 0.0f;
- }
- for (int i = 0; i < s.length; i ++) {
- s[i] = allocator.allocateSprite(owner);
- }
- owner.setSprites(s);
- for (int i = 0; i < s.length; i ++) {
- if (sprite[i].animationResource != null) {
- s[i].setAnimation(sprite[i].animationResource);
- } else {
- s[i].setImage(sprite[i].imageResource);
- }
- s[i].setLayer(sprite[i].layer);
- s[i].setSubLayer(sprite[i].subLayer);
- s[i].setScale(FPMath.fpValue(scale));
- if (sprite[i].offset != null) {
- s[i].setOffset((sprite[i].offset.getX() + ox) * scale, (sprite[i].offset.getY() + oy) * scale, 0.0f);
- } else {
- s[i].setOffset(ox * scale, oy * scale, 0.0f);
- }
- s[i].setYSortOffset((ySortOffset + sprite[i].ySortOffset) * scale);
- if (sprite[i].doChildOffset) {
- s[i].setDoChildOffset(true);
- }
- }
- createColors(s);
- updateColors(s, mapX, mapY);
- }
-
- public void updateLocation(Sprite[] existingSprite, float x, float y) {
- for (Sprite element : existingSprite) {
- element.setLocation(x, y, 0.0f);
- }
- }
-
- /**
- * Create the emitters at a specific location
- * @param screen TODO
- * @param x
- * @param y
- * @return an array of emitters (may be empty but won't be null)
- */
- public Emitter[] createEmitters(Screen screen, float x, float y) {
- if (emitter == null) {
- return new Emitter[0];
- }
- Emitter[] e = new Emitter[emitter.length];
- for (int i = 0; i < e.length; i ++) {
- if (emitter[i].emitterFeature != null) {
- e[i] = emitter[i].emitterFeature.spawn(screen);
- float ox, oy;
- if (emitter[i].offset != null) {
- ox = emitter[i].offset.getX() * scale;
- oy = emitter[i].offset.getY() * scale;
- } else {
- ox = 0;
- oy = 0;
- }
- e[i].setLocation(x + ox, y + oy);
- e[i].setYOffset(emitter[i].ySortOffset * scale);
- }
- }
- return e;
- }
-
- /**
- * Update an existing array of emitters
- * @param existingEmitters
- * @param x TODO
- * @param y TODO
- */
- public void updateEmitters(Emitter[] existingEmitters, float x, float y) {
- for (int i = 0; i < existingEmitters.length; i ++) {
- if (existingEmitters[i] != null) {
- float ox, oy;
- if (emitter[i].offset != null) {
- ox = emitter[i].offset.getX() * scale;
- oy = emitter[i].offset.getY() * scale;
- } else {
- ox = 0;
- oy = 0;
- }
- existingEmitters[i].setLocation(x + ox, y + oy);
- }
- }
- }
-
- public void updateScale(Sprite[] existingSprites, float newScale) {
- for (int i = 0; i < existingSprites.length; i ++) {
- existingSprites[i].setScale(FPMath.fpValue(newScale * scale));
- if (sprite[i].offset != null) {
- existingSprites[i].setOffset(sprite[i].offset.getX() * newScale * scale, sprite[i].offset.getY() * newScale * scale, 0.0f);
- }
- existingSprites[i].setYSortOffset(sprite[i].ySortOffset * newScale * scale);
- }
- }
-
- public void updateColors(Sprite[] existingSprites, float mapX, float mapY) {
- if (!hasColored) {
- return;
- }
- float mapWidth, mapHeight, ratio = 0.0f;
- if (hasAttenuated) {
- mapWidth = Worm.getGameState().getMap().getWidth();
- mapHeight = Worm.getGameState().getMap().getHeight();
- ratio = ColorAttenuationConstants.dist(mapX / MapRenderer.TILE_SIZE, mapY / MapRenderer.TILE_SIZE, mapWidth, mapHeight) / ColorAttenuationConstants.getMaxDist();
- }
- updateColors(existingSprites, ratio);
- }
-
- public void updateColors(Sprite[] existingSprites, float ratio) {
- if (!hasColored) {
- return;
- }
- updateColors(existingSprites, ratio, ratio, ratio, ratio, 0, 0, 0, 0);
- }
-
- public void updateColors(Sprite[] existingSprites, float ratio00, float ratio10, float ratio11, float ratio01, int fade00, int fade10, int fade11, int fade01) {
- if (!hasColored) {
- return;
- }
- for (int i = 0; i < existingSprites.length; i ++) {
- if ((sprite[i].colored != null || sprite[i].topColored != null && sprite[i].bottomColored != null) && sprite[i].attenuated) {
- if (existingSprites[i].getColor(0) instanceof AttenuatedColor) { // animcolor command puts ordinary Colors back into sprites. Bah
- ((AttenuatedColor) existingSprites[i].getColor(0)).setRatio(ratio00);
- ((AttenuatedColor) existingSprites[i].getColor(1)).setRatio(ratio10);
- ((AttenuatedColor) existingSprites[i].getColor(2)).setRatio(ratio11);
- ((AttenuatedColor) existingSprites[i].getColor(3)).setRatio(ratio01);
- ((AttenuatedColor) existingSprites[i].getColor(0)).setFade(fade00);
- ((AttenuatedColor) existingSprites[i].getColor(1)).setFade(fade10);
- ((AttenuatedColor) existingSprites[i].getColor(2)).setFade(fade11);
- ((AttenuatedColor) existingSprites[i].getColor(3)).setFade(fade01);
- }
- }
- }
- }
-
- private void createColors(Sprite[] existingSprites) {
- if (!hasColored) {
- return;
- }
- for (int i = 0; i < existingSprites.length; i ++) {
- if (sprite[i].colored != null) {
- MappedColor c = sprite[i].colored;
- if (c != null) {
- if (sprite[i].attenuated) {
- if (c.getColorName() != null && c.getColorName().intern() == SHADOW_COLOR_NAME) {
- existingSprites[i].setColor(0, new AttenuatedColor(c, true));
- existingSprites[i].setColor(1, new AttenuatedColor(c, true));
- existingSprites[i].setColor(2, new AttenuatedColor(c, true));
- existingSprites[i].setColor(3, new AttenuatedColor(c, true));
- } else {
- existingSprites[i].setColor(0, new AttenuatedColor(c));
- existingSprites[i].setColor(1, new AttenuatedColor(c));
- existingSprites[i].setColor(2, new AttenuatedColor(c));
- existingSprites[i].setColor(3, new AttenuatedColor(c));
- }
- } else {
- existingSprites[i].setColors(c);
- }
- }
- } else if (sprite[i].topColored != null && sprite[i].bottomColored != null) {
- MappedColor topColor = sprite[i].topColored;
- MappedColor bottomColor = sprite[i].bottomColored;
- if (topColor != null && bottomColor != null) {
- if (sprite[i].attenuated) {
- existingSprites[i].setColor(0, new AttenuatedColor(bottomColor));
- existingSprites[i].setColor(1, new AttenuatedColor(bottomColor));
- existingSprites[i].setColor(2, new AttenuatedColor(topColor));
- existingSprites[i].setColor(3, new AttenuatedColor(topColor));
- } else {
- existingSprites[i].setColor(0, bottomColor);
- existingSprites[i].setColor(1, bottomColor);
- existingSprites[i].setColor(2, topColor);
- existingSprites[i].setColor(3, topColor);
- }
- }
- }
- }
- }
-
- /**
- * @return the scale
- */
- public float getScale() {
- return scale;
- }
-
- /**
- * @return the offset
- */
- public ReadablePoint getOffset() {
- return offset;
- }
- }