/*
* JSwiff is an open source Java API for Macromedia Flash file generation
* and manipulation
*
* Copyright (C) 2004-2006 Ralf Terdic (contact@jswiff.com)
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.jswiff.swfrecords.tags;
import com.jswiff.io.InputBitStream;
import com.jswiff.io.OutputBitStream;
import com.jswiff.swfrecords.BlendMode;
import com.jswiff.swfrecords.CXformWithAlpha;
import com.jswiff.swfrecords.ClipActions;
import com.jswiff.swfrecords.Filter;
import com.jswiff.swfrecords.Matrix;
import java.io.IOException;
import java.util.List;
import org.swfparser.util.UnsignedByte;
import org.apache.log4j.Logger;
/**
* TODO: Comments
*/
public final class PlaceObject3 extends Tag {
private boolean move;
private int depth;
private int characterId;
private Matrix matrix;
private CXformWithAlpha colorTransform;
private int ratio;
private String name;
private int clipDepth;
private ClipActions clipActions;
private List filters;
private short blendMode;
private boolean hasClipActions;
private boolean hasClipDepth;
private boolean hasName;
private boolean hasRatio;
private boolean hasColorTransform;
private boolean hasMatrix;
private boolean hasCharacter;
private boolean cacheAsBitmap;
private boolean hasBlendMode;
private boolean hasFilters;
private short bitmapId;
/**
* Creates a new PlaceObject3 tag.
*
* @param depth depth the character is placed at
*/
public PlaceObject3(int depth) {
code = TagConstants.PLACE_OBJECT_3;
this.depth = depth;
}
PlaceObject3() {
// empty
}
/**
* TODO: Comments
*
* @param blendMode TODO: Comments
*
* @see BlendMode
*/
public void setBlendMode(short blendMode) {
this.blendMode = blendMode;
hasBlendMode = true;
}
/**
* TODO: Comments
*
* @return TODO: Comments
*
* @see BlendMode
*/
public short getBlendMode() {
return blendMode;
}
/**
* TODO: Comments
*
* @param cacheAsBitmap TODO: Comments
*/
public void setCacheAsBitmap(boolean cacheAsBitmap) {
this.cacheAsBitmap = cacheAsBitmap;
}
/**
* TODO: Comments
*
* @return TODO: Comments
*/
public boolean isCacheAsBitmap() {
return cacheAsBitmap;
}
/**
* Sets the character ID. If this ID is set, the corresponding character is
* displayed at the depth specified with the constructor.
*
* @param characterId The characterId to set.
*/
public void setCharacterId(int characterId) {
this.characterId = characterId;
hasCharacter = true;
}
/**
* Returns the character ID. If this ID is set, the corresponding character
* is displayed at the depth specified with the constructor. Check with
* <code>hasCharacter()</code> if set.
*
* @return Returns the characterId.
*/
public int getCharacterId() {
return characterId;
}
/**
* Sets the event handlers (only for sprite characters).
*
* @param clipActions event handlers
*/
public void setClipActions(ClipActions clipActions) {
this.clipActions = clipActions;
hasClipActions = (clipActions != null);
}
/**
* Returns the event handlers (only for sprite characters). Check with
* <code>hasClipActions()</code> if set.
*
* @return Returns the clipActions.
*/
public ClipActions getClipActions() {
return clipActions;
}
/**
* Sets the clip depth, indicating that the character is a clipping character
* which masks characters at depths up to and including the specified clip
* depth
*
* @param clipDepth the clip depth
*/
public void setClipDepth(int clipDepth) {
this.clipDepth = clipDepth;
hasClipDepth = true;
}
/**
* Returs the clip depth (which indicates that the character is a clipping
* character masking characters at depths up to and including the specified
* clip depth). Check with <code>hasclipDepth()</code> if set.
*
* @return clip depth of character
*/
public int getClipDepth() {
return clipDepth;
}
/**
* Sets the color transform, allowing color effects to be applied to the
* character to be displayed.
*
* @param colorTransform a color transform
*/
public void setColorTransform(CXformWithAlpha colorTransform) {
this.colorTransform = colorTransform;
hasColorTransform = (colorTransform != null);
}
/**
* Returns the color transform which allows color effects to be applied to
* the character to be displayed. Check with
* <code>hasColorTransform()</code> if set.
*
* @return Returns the colorTransform.
*/
public CXformWithAlpha getColorTransform() {
return colorTransform;
}
/**
* Sets the depth the character will be displayed at.
*
* @param depth display depth
*/
public void setDepth(int depth) {
this.depth = depth;
}
/**
* Returns the depth the character will be displayed at.
*
* @return display depth
*/
public int getDepth() {
return depth;
}
/**
* TODO: Comments
*
* @param filters TODO: Comments
*/
public void setFilters(List filters) {
this.filters = filters;
hasFilters = (filters != null);
}
/**
* TODO: Comments
*
* @return TODO: Comments
*/
public List getFilters() {
return filters;
}
/**
* Sets the tranform matrix, specifying position, scale, rotation etc. of the
* character to be displayed.
*
* @param matrix transform matrix
*/
public void setMatrix(Matrix matrix) {
this.matrix = matrix;
hasMatrix = (matrix != null);
}
/**
* Returns the tranform matrix, which specifies position, scale, rotation
* etc. of the character to be displayed. Check with
* <code>hasMatrix()</code> if set.
*
* @return transform matrix
*/
public Matrix getMatrix() {
return matrix;
}
/**
* <p>
* Sets the move flag. If set, the character at the given depth is removed.
* It is replaced either by a modified instance of the removed character or
* (if a character ID is specified) by a new character.
* </p>
*
* <p>
* Mainly used for moving a character: first frame specifies depth, character
* ID and initial matrix. Subsequent frames have the move flag set for this
* depth and replace the translate values of the matrix with new ones.
* </p>
*/
public void setMove() {
move = true;
}
/**
* Sets or clears the move flag.
*
* @param move value of move flag
*
* @see PlaceObject3#setMove()
*/
public void setMove(boolean move) {
this.move = move;
}
/**
* Checks the move flag. If set, the character at the given depth is removed.
* It is replaced either by a modified instance of the removed character or
* (if a character ID is specified) by a new character.
*
* @return <code>true</code> if move flag set, else <code>false</code>
*/
public boolean isMove() {
return move;
}
/**
* Assigns a name to the instance of the character to be placed, in order to
* be able to reference this instance by the assigend name (e.g. within
* <code>With</code>).
*
* @param name instance name
*/
public void setName(String name) {
this.name = name;
hasName = (name != null);
}
/**
* Returns the name assigned to the instance of the character to be placed,
* in order to be able to reference this instance by the assigend name (e.g.
* within <code>With</code>). Check with <code>hasName()</code> if set.
*
* @return instance name
*/
public String getName() {
return name;
}
/**
* Sets the morph ratio which indicates how far the morph has progressed
* (only for characters defined with <code>DefineMorphShape</code>). Values
* between 0 and 65535 are permitted. A ratio of 0 displays the character at
* morph start, 65535 causes the character to be displayed at the end of the
* morph. Values between 0 and 65535 cause the Flash Player to interpolate
* between start and end shapes.
*
* @param ratio morph ratio
*/
public void setRatio(int ratio) {
if (ratio < 0) {
this.ratio = 0;
} else if (ratio > 65535) {
this.ratio = 65535;
} else {
this.ratio = ratio;
}
hasRatio = true;
}
/**
* <p>
* Sets the morph ratio which indicates how far the morph has progressed
* (only for characters defined with <code>DefineMorphShape</code>). Values
* between 0 and 65535 are returned. A ratio of 0 displays the character at
* morph start, 65535 causes the character to be displayed at the end of the
* morph. Values between 0 and 65535 cause the Flash Player to interpolate
* between start and end shapes.
* </p>
*
* <p>
* Check with <code>hasRatio()</code> if set.
* </p>
*
* @return Returns the ratio.
*/
public int getRatio() {
return ratio;
}
/**
* TODO: Comments
*
* @return TODO: Comments
*/
public boolean hasBlendMode() {
return hasBlendMode;
}
/**
* Checks whether the character ID is set.
*
* @return <code>true</code> if character ID set, else <code>false</code>
*/
public boolean hasCharacter() {
return hasCharacter;
}
/**
* Checks whether clip actions (sprite event handlers) have been specified.
*
* @return <code>true</code> if clip actions set, else <code>false</code>
*/
public boolean hasClipActions() {
return hasClipActions;
}
/**
* Checks if the value of the clip depth was set.
*
* @return <code>true</code> if clip depth set, else <code>false</code>
*/
public boolean hasClipDepth() {
return hasClipDepth;
}
/**
* Checks whether the color transform is specified.
*
* @return <code>true</code> if color transform set, else <code>false</code>
*/
public boolean hasColorTransform() {
return hasColorTransform;
}
/**
* TODO: Comments
*
* @return TODO: Comments
*/
public boolean hasFilters() {
return hasFilters;
}
/**
* Checks if a transform matrix is specified.
*
* @return <code>true</code> if transform matrix set, else <code>false</code>
*/
public boolean hasMatrix() {
return hasMatrix;
}
/**
* Checks if a name is assigned to the character instance to be displayed.
*
* @return <code>true</code> if character instance name set, else
* <code>false</code>
*/
public boolean hasName() {
return hasName;
}
/**
* Checks if the morph ratio is set.
*
* @return <code>true</code> if ratio set, else <code>false</code>
*/
public boolean hasRatio() {
return hasRatio;
}
protected void writeData(OutputBitStream outStream) throws IOException {
outStream.writeBooleanBit(hasClipActions);
outStream.writeBooleanBit(hasClipDepth);
outStream.writeBooleanBit(hasName);
outStream.writeBooleanBit(hasRatio);
outStream.writeBooleanBit(hasColorTransform);
outStream.writeBooleanBit(hasMatrix);
outStream.writeBooleanBit(hasCharacter);
outStream.writeBooleanBit(move);
outStream.writeUnsignedBits(0, 5);
outStream.writeBooleanBit(cacheAsBitmap);
outStream.writeBooleanBit(hasBlendMode);
outStream.writeBooleanBit(hasFilters);
outStream.writeUI16(depth);
if (hasCharacter) {
outStream.writeUI16(characterId);
}
if (hasMatrix) {
matrix.write(outStream);
}
if (hasColorTransform) {
colorTransform.write(outStream);
}
if (hasRatio) {
outStream.writeUI16(ratio);
}
if (hasName) {
outStream.writeString(name);
}
if (hasClipDepth) {
outStream.writeUI16(clipDepth);
}
if (hasFilters) {
Filter.writeFilters(filters, outStream);
}
if (hasBlendMode) {
outStream.writeUI8(blendMode);
}
// stealth: NOT in a spec, but it seems the right place to go, see flasm code...
if (cacheAsBitmap) {
outStream.writeUI8(bitmapId);
}
if (hasClipActions) {
clipActions.write(outStream, getSWFVersion());
}
}
private static Logger logger = Logger.getLogger(PlaceObject3.class);
void setData(byte[] data) throws IOException {
InputBitStream inStream = new InputBitStream(data);
int start = inStream.available();
logger.debug("DMP: "+UnsignedByte.dump(data));
hasClipActions = inStream.readBooleanBit();
logger.debug("hasClipActions="+hasClipActions);
hasClipDepth = inStream.readBooleanBit();
logger.debug("hasClipDepth="+hasClipDepth);
hasName = inStream.readBooleanBit();
logger.debug("hasName="+hasName);
hasRatio = inStream.readBooleanBit();
logger.debug("hasRatio="+hasRatio);
hasColorTransform = inStream.readBooleanBit();
logger.debug("hasColorTransform="+hasColorTransform);
hasMatrix = inStream.readBooleanBit();
logger.debug("hasMatrix="+hasMatrix);
hasCharacter = inStream.readBooleanBit();
logger.debug("hasCharacter="+hasCharacter);
move = inStream.readBooleanBit();
inStream.readUnsignedBits(5);
cacheAsBitmap = inStream.readBooleanBit();
logger.debug("cacheAsBitmap="+cacheAsBitmap);
hasBlendMode = inStream.readBooleanBit();
logger.debug("hasBlendMode="+hasBlendMode);
hasFilters = inStream.readBooleanBit();
logger.debug("hasFilters="+hasFilters);;
depth = inStream.readUI16();
if (hasCharacter) {
characterId = inStream.readUI16();
}
if (hasMatrix) {
matrix = new Matrix(inStream);
}
if (hasColorTransform) {
colorTransform = new CXformWithAlpha(inStream);
}
if (hasRatio) {
ratio = inStream.readUI16();
}
if (hasName) {
name = inStream.readString();
logger.debug("name="+name);
}
if (hasClipDepth) {
clipDepth = inStream.readUI16();
}
if (hasFilters) {
inStream.align();
filters = Filter.readFilters(inStream);
}
if (hasBlendMode) {
blendMode = inStream.readUI8();
if (blendMode == 0) {
blendMode = BlendMode.NORMAL;
}
}
// stealth: NOT in a spec, but it seems the right place to go, see flasm code...
if (cacheAsBitmap) {
bitmapId = inStream.readUI8();
}
int end = inStream.available();
logger.debug("#setData() inStream end:"+UnsignedByte.hex(end));
logger.debug("DMP: "+UnsignedByte.dump(data,start-end));
if (hasClipActions) {
clipActions = new ClipActions(inStream, getSWFVersion());
}
}
}