/* * Layer.java * Transform * * Copyright (c) 2001-2010 Flagstone Software 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 Flagstone Software Ltd. 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 com.flagstone.transform.util.movie; import java.util.ArrayList; import java.util.List; /** * The Layer class can be used to simplify the creation of movies. It provides a * series of methods that can be used to control how an object is displayed and * provides an API that is easier to use when compared to creating the commands * (PlaceObject, RemoveObject, etc.) used to manipulate the Flash Player's * display list directly. The following code: * * <pre> * Layer layer = new Layer(1); * * layer.select(shape); * layer.move(x1, y1); * layer.show(); * layer.move(x2, y2); * layer.show(); * * movie.add(layer.getObjects()); * </pre> * * is equivalent to: * * <pre> * movie.add(shape); * movie.add(new PlaceObject2(shape.getIdentifier, 1, x1, y1)); * movie.add(ShowFrame.getInstance()); * movie.add(new PlaceObject2(1, x2, y2)); * movie.add(ShowFrame.getInstance()); * </pre> * * After each set of commands the display list is updated by executing the * show() method - this adds a ShowFrame instruction to the final movie which * tells the Flash Player to render the display list on the screen. * * The select() method is only used when displaying an object for the first time * or re-displaying it after it was deleted from the display list. * * The commands that manipulate the display list can also be combined to apply * several operations at once: * * <pre> * layer.select(shape); * layer.move(x, y); * layer.morph(0.9); * layer.color(r, g, b); * layer.show(); * </pre> * * is equivalent to: * * <pre> * CoordTransform coord = new CoordTransform(x, y); * ColorTransform color = new ColorTransform(r, g, b); * PlaceObject2 place = new PlaceObject2(shape.getIdentifier, 1, coord, color) * place.setRatio(0.9); * * movie.add(shape); * movie.add(place); * movie.add(ShowFrame.getInstance()); * </pre> * * An operation is use to set the attributes on either an PlaceObject2 or * RemoveObject2 object so operations of the same type cannot be combined to * create a cumulative effect. For example: * * <pre> * layer.move(x1, y1); * layer.move(x2, y2); * </pre> * * is the same as: * * <pre> * layer.move(x2, y2); * </pre> * * and not: * * <pre> * layer.move(x1 + x2, y1 + y2); * </pre> * * The most obvious benefit is code that is easier to write and read however the * benefits of using layers come to the fore when creating movies with multiple * objects. Currently the movie object represents the main time-line and the * commands to control and display each object must be interleaved together. * This quickly becomes unwieldy and error prone if several objects are * involved. With layers, each can be regarded as the time-line for a single * object. The object can then be manipulated more easily and the final set of * Layers merged together to create a single time-line. The only limitation in * the merging process is that all the Layers must start at the same point in * time. * * Each Layer object created must be assigned a unique number. In Flash an * object to be displayed is assigned to a given layer with (typically) only one * object displayed on a given layer. The layer number is used to control the * order in which the objects are displayed. Objects placed on a higher layer * number are displayed in front of object placed on a lower layer number. * */ public final class Layer { /** * Merge layers together to create a single time-line. Each layer is assumed * to start at the same point in time. The process steps through each of the * layers, frame by frame, adding all the commands used to manipulate the * Flash Player's display list into a single group. * * @param layers * a list of Layer objects. * * @return a list of all the objects contained in each layer. This list * can then be added to the movie. */ public static List<Frame> merge(final List<Layer> layers) { int lastFrame = 0; for (Layer layer : layers) { for (Frame frame : layer.getFrames()) { if (frame.getNumber() > lastFrame) { lastFrame = frame.getNumber(); } } } final ArrayList<Frame> merged = new ArrayList<Frame>(lastFrame); for (int i = 1; i <= lastFrame; i++) { merged.add(new Frame(i)); } Frame selected; for (Layer layer : layers) { for (Frame frame : layer.getFrames()) { selected = merged.get(frame.getNumber() - 1); selected.setActions(frame.getActions()); selected.setCommands(frame.getCommands()); selected.setDefinitions(frame.getDefinitions()); if (frame.getLabel() != null) { selected.setLabel(frame.getLabel()); } } } return merged; } /** The layer number. */ private final transient int layerNumber; /** The list of frames for the object displayed on this layer. */ private final transient List<Frame> frames; /** * Create a new Layer object. Layers are used to define the order in which * objects are displayed. Objects placed on a high layer number are * displayed in front of those on a lower layer. * * @param number * the layer number on the display list. */ public Layer(final int number) { layerNumber = number; frames = new ArrayList<Frame>(); } /** * Get the layer number. The Flash Player assumes that there is only one * object placed on each layer and so each must have a unique number. * * @return the layer number. */ public int getLayer() { return layerNumber; } /** * Get the list of frames. * * @return the Frames defined for the Layer. */ public List<Frame> getFrames() { return frames; } /** * Add a frame to the layer. The object may be selected later for display. * * @param frame * a Frame object. * @return this object. */ public Layer add(final Frame frame) { frames.add(frame); frame.setNumber(frames.size()); return this; } }