package org.newdawn.slick.geom; import java.util.ArrayList; /** * A shape that morphs between a set of other shapes * * @author kevin */ public class MorphShape extends Shape { /** The shapes to morph between */ private ArrayList shapes = new ArrayList(); /** The offset between the shapes */ private float offset; /** The current shape */ private Shape current; /** The next shape */ private Shape next; /** * Create a new mighty morphin shape * * @param base The base shape we're starting the morph from */ public MorphShape(Shape base) { shapes.add(base); float[] copy = base.points; this.points = new float[copy.length]; current = base; next = base; } /** * Add a subsequent shape that we should morph too in order * * @param shape The new shape that forms part of the morphing shape */ public void addShape(Shape shape) { if (shape.points.length != points.length) { throw new RuntimeException("Attempt to morph between two shapes with different vertex counts"); } Shape prev = (Shape) shapes.get(shapes.size()-1); if (equalShapes(prev, shape)) { shapes.add(prev); } else { shapes.add(shape); } if (shapes.size() == 2) { next = (Shape) shapes.get(1); } } /** * Check if the shape's points are all equal * * @param a The first shape to compare * @param b The second shape to compare * @return True if the shapes are equal */ private boolean equalShapes(Shape a, Shape b) { a.checkPoints(); b.checkPoints(); for (int i=0;i<a.points.length;i++) { if (a.points[i] != b.points[i]) { return false; } } return true; } /** * Set the "time" index for this morph. This is given in terms of shapes, so * 0.5f would give you the position half way between the first and second shapes. * * @param time The time index to represent on this shape */ public void setMorphTime(float time) { int p = (int) time; int n = p + 1; float offset = time - p; p = rational(p); n = rational(n); setFrame(p, n, offset); } /** * Update the morph time and hence the curent frame * * @param delta The amount to change the morph time by */ public void updateMorphTime(float delta) { offset += delta; if (offset < 0) { int index = shapes.indexOf(current); if (index < 0) { index = shapes.size() - 1; } int nframe = rational(index+1); setFrame(index, nframe, offset); offset += 1; } else if (offset > 1) { int index = shapes.indexOf(next); if (index < 1) { index = 0; } int nframe = rational(index+1); setFrame(index, nframe, offset); offset -= 1; } else { pointsDirty = true; } } /** * Set the current frame * * @param current The current frame */ public void setExternalFrame(Shape current) { this.current = current; next = (Shape) shapes.get(0); offset = 0; } /** * Get an index that is rational, i.e. fits inside this set of shapes * * @param n The index to rationalize * @return The index rationalized */ private int rational(int n) { while (n >= shapes.size()) { n -= shapes.size(); } while (n < 0) { n += shapes.size(); } return n; } /** * Set the frame to be represented * * @param a The index of the first shape * @param b The index of the second shape * @param offset The offset between the two shapes to represent */ private void setFrame(int a, int b, float offset) { current = (Shape) shapes.get(a); next = (Shape) shapes.get(b); this.offset = offset; pointsDirty = true; } /** * @see MorphShape#createPoints() */ protected void createPoints() { if (current == next) { System.arraycopy(current.points,0,points,0,points.length); return; } float[] apoints = current.points; float[] bpoints = next.points; for (int i=0;i<points.length;i++) { points[i] = apoints[i] * (1 - offset); points[i] += bpoints[i] * offset; } } /** * @see MorphShape#transform(Transform) */ public Shape transform(Transform transform) { createPoints(); Polygon poly = new Polygon(points); return poly; } }