package org.cocos2d.nodes;
import android.util.Log;
import org.cocos2d.opengl.TextureAtlas;
import org.cocos2d.types.*;
import org.cocos2d.utils.CCFormatter;
import java.util.HashMap;
/** AtlasSprite is a CocosNode object that implements the CocosNodeFrames and CocosNodeRGBA protocols.
*
* AtlasSprite can be used as a replacement of Sprite.
*
* AtlasSprite has all the features from CocosNode with the following additions and limitations:
* - New features
* - It is MUCH faster than Sprite
* - supports flipX, flipY
*
* - Limitations
* - Their parent can only be an AtlasSpriteManager
* - They can't have children
* - Camera is not supported yet (eg: OrbitCamera action doesn't work)
* - GridBase actions are not supported (eg: Lens, Ripple, Twirl)
* - The Alias/Antialias property belongs to AtlasSpriteManager, so you can't individually set the aliased property.
* - The Blending function property belongs to AtlasSpriteManager, so you can't individually set the blending function property.
* - Parallax scroller is not supported, but can be simulated with a "proxy" sprite.
*
*/
public class AtlasSprite extends CocosNode implements CocosNode.CocosNodeSize, CocosNode.CocosNodeFrames, CocosNode.CocosNodeRGBA {
public static final int kIndexNotInitialized = -1;
TextureAtlas textureAtlas_;
int atlasIndex_;
/**
* returns the altas index of the AtlasSprite
*/
public int atlasIndex() {
return atlasIndex_;
}
public void setIndex(int index) {
atlasIndex_ = index;
}
// texture pixels
private CCRect rect_;
// texture coords
// stored as floats in the range [0..1]
private CCQuad2 texCoords_ = new CCQuad2();
// vertex coordinates
// stored as pixel locations
private CCQuad3 vertexCoords_ = new CCQuad3();
// opacity and RGB protocol
private int opacity_;
private CCColor3B color_;
private boolean dirty_;
// Animations that belong to the sprite
HashMap<String, AtlasAnimation> animations;
// image is flipped
private boolean flipX_;
private boolean flipY_;
/**
* whether or not the Sprite's color needs to be updated in the Atlas
*/
public boolean isDirty() {
return dirty_;
}
/**
* returns the rect of the AtlasSprite
*/
public CCRect getTextureRect() {
return rect_;
}
public static AtlasSprite sprite(CCRect rect, AtlasSpriteManager manager) {
return new AtlasSprite(rect, manager);
}
protected AtlasSprite(CCRect rect, AtlasSpriteManager manager) {
textureAtlas_ = manager.atlas();
atlasIndex_ = kIndexNotInitialized;
// default transform anchor: center
setAnchorPoint(0.5f, 0.5f);
// RGB and opacity
opacity_ = (byte) 255;
color_ = new CCColor3B(255, 255, 255);
animations = null; // lazy alloc
setTextureRect(rect);
}
@Override
public String toString() {
return new CCFormatter().format("<%s = %08X | Rect = (%.2f,%.2f,%.2f,%.2f) | tag = %i>", AtlasSprite.class.getSimpleName(),
this, rect_.origin.x, rect_.origin.y, rect_.size.width, rect_.size.height, getTag());
}
private void initAnimationDictionary() {
animations = new HashMap<String, AtlasAnimation>(2);
}
public void setTextureRect(CCRect rect) {
rect_ = rect;
updateTextureCoords();
// Don't update Atlas if index == -1. issue #283
if (atlasIndex_ == kIndexNotInitialized)
dirty_ = true;
else
updateAtlas();
// add these lines
if (!((rect.size.width == getWidth()) && ((rect.size.getHeight()) == getHeight()))) {
setContentSize(rect.size.width, rect.size.height);
dirty_ = true;
}
}
private void updateTextureCoords() {
float atlasWidth = textureAtlas_.getTexture().pixelsWide();
float atlasHeight = textureAtlas_.getTexture().pixelsHigh();
float left = rect_.origin.x / atlasWidth;
float right = (rect_.origin.x + rect_.size.width) / atlasWidth;
float top = rect_.origin.y / atlasHeight;
float bottom = (rect_.origin.y + rect_.size.height) / atlasHeight;
if( flipX_)
{
float temp = left;
left = right;
right = temp;
}
if( flipY_)
{
float temp = top;
top = bottom;
bottom = temp;
}
CCQuad2 newCoords = new CCQuad2(
left, bottom,
right, bottom,
left, top,
right, top);
texCoords_ = newCoords;
}
public void updateColor() {
CCColor4B colorQuad = new CCColor4B(color_.r, color_.g, color_.b, opacity_);
textureAtlas_.updateColor(colorQuad, atlasIndex_);
dirty_ = false;
}
// algorithm from pyglet ( http://www.pyglet.org )
public void updatePosition() {
// if not visible_ then everything is 0
if (!visible_) {
CCQuad3 newVertices = new CCQuad3(
0, 0, 0,
0, 0, 0,
0, 0, 0,
0, 0, 0);
vertexCoords_ = newVertices;
}
// rotation ? -> update: rotation, scale, position
else if (getRotation() != 0) {
float x1 = -getTransformAnchorX() * getScaleX();
float y1 = -getTransformAnchorY() * getScaleY();
float x2 = x1 + rect_.size.width * getScaleX();
float y2 = y1 + rect_.size.height * getScaleY();
float x = getPositionX();
float y = getPositionY();
float r = -CCMacros.CC_DEGREES_TO_RADIANS(getRotation());
float cr = (float)Math.cos(r);
float sr = (float)Math.sin(r);
float ax = x1 * cr - y1 * sr + x;
float ay = x1 * sr + y1 * cr + y;
float bx = x2 * cr - y1 * sr + x;
float by = x2 * sr + y1 * cr + y;
float cx = x2 * cr - y2 * sr + x;
float cy = x2 * sr + y2 * cr + y;
float dx = x1 * cr - y2 * sr + x;
float dy = x1 * sr + y2 * cr + y;
CCQuad3 newVertices = new CCQuad3(
(int) ax, (int) ay, 0,
(int) bx, (int) by, 0,
(int) dx, (int) dy, 0,
(int) cx, (int) cy, 0);
vertexCoords_ = newVertices;
}
// scale ? -> update: scale, position
else if (getScaleX() != 1 || getScaleY() != 1) {
float x = getPositionX();
float y = getPositionY();
float x1 = (x - getTransformAnchorX() * getScaleX());
float y1 = (y - getTransformAnchorY() * getScaleY());
float x2 = (x1 + rect_.size.width * getScaleX());
float y2 = (y1 + rect_.size.height * getScaleY());
CCQuad3 newVertices = new CCQuad3(
(int) x1, (int) y1, 0,
(int) x2, (int) y1, 0,
(int) x1, (int) y2, 0,
(int) x2, (int) y2, 0);
vertexCoords_ = newVertices;
}
// update position
else {
float x = getPositionX();
float y = getPositionY();
float x1 = (x - getTransformAnchorX());
float y1 = (y - getTransformAnchorY());
float x2 = (x1 + rect_.size.width);
float y2 = (y1 + rect_.size.height);
CCQuad3 newVertices = new CCQuad3(
(int) x1, (int) y1, 0,
(int) x2, (int) y1, 0,
(int) x1, (int) y2, 0,
(int) x2, (int) y2, 0);
vertexCoords_ = newVertices;
}
textureAtlas_.updateQuad(texCoords_, vertexCoords_, atlasIndex_);
dirty_ = false;
}
public void updateAtlas() {
textureAtlas_.updateQuad(texCoords_, vertexCoords_, atlasIndex_);
}
public void insertInAtlas(int index) {
atlasIndex_ = index;
textureAtlas_.insertQuad(texCoords_, vertexCoords_, atlasIndex_);
}
@Override
public void setPosition(float x, float y) {
super.setPosition(x, y);
dirty_ = true;
}
@Override
public void setRotation(float rot) {
super.setRotation(rot);
dirty_ = true;
}
@Override
public void setScaleX(float sx) {
super.setScaleX(sx);
dirty_ = true;
}
@Override
public void setScaleY(float sy) {
super.setScaleY(sy);
dirty_ = true;
}
@Override
public void setScale(float s) {
super.scale(s);
dirty_ = true;
}
@Override
public void setVertexZ(float z) {
super.setVertexZ(z);
dirty_ = true;
}
@Override
public void setAnchorPoint(float x, float y) {
super.setAnchorPoint(x, y);
dirty_ = true;
}
@Override
public void setRelativeAnchorPoint(boolean relative) {
Log.w("AtlasSprite", "relativeTransformAnchor_ is ignored in AtlasSprite");
}
@Override
public void setVisible(boolean v) {
super.setVisible(v);
dirty_ = true;
}
public void setFlipX(boolean b)
{
if( flipX_ != b ) {
flipX_ = b;
setTextureRect(rect_);
}
}
public boolean getFlipX()
{
return flipX_;
}
public void setFlipY(boolean b)
{
if( flipY_ != b ) {
flipY_ = b;
setTextureRect(rect_);
}
}
public boolean getFlipY()
{
return flipY_;
}
@Override
public CocosNode addChild(CocosNode child, int z, int aTag) {
assert false : "AtlasSprite can't have children";
return null;
}
public void setOpacity(int opacity) {
opacity_ = opacity;
dirty_ = true;
}
public int getOpacity() {
return opacity_;
}
public void setColor(CCColor3B color) {
color_.r = color.r;
color_.g = color.g;
color_.b = color.b;
dirty_ = true;
}
public CCColor3B getColor() {
return new CCColor3B(color_.r, color_.g, color_.b);
}
// TODO Remove cast
public void setDisplayFrame(Object newFrame) {
if (newFrame instanceof AtlasSpriteFrame) {
AtlasSpriteFrame frame = (AtlasSpriteFrame) newFrame;
CCRect rect = frame.rect;
setTextureRect(rect);
}
}
// TODO Remove cast
public void setDisplayFrame(String animationName, int frameIndex) {
if (animations == null)
initAnimationDictionary();
AtlasAnimation a = animations.get(animationName);
AtlasSpriteFrame frame = (AtlasSpriteFrame) a.frames.get(frameIndex);
assert frame != null : "AtlasSprite#setDisplayFrame. Invalid frame";
CCRect rect = frame.rect;
setTextureRect(rect);
}
// TODO Remove cast
public boolean isFrameDisplayed(Object frame) {
if (frame instanceof AtlasSpriteFrame) {
AtlasSpriteFrame spr = (AtlasSpriteFrame) frame;
CCRect r = spr.rect;
return CCRect.equalToRect(r, rect_);
}
return false;
}
public AtlasSpriteFrame displayFrame() {
return new AtlasSpriteFrame(rect_);
}
public void addAnimation(CocosAnimation anim) {
// lazy alloc
if (animations == null)
initAnimationDictionary();
animations.put(anim.name(), (AtlasAnimation) anim);
}
public CocosAnimation animationByName(String animationName) {
assert animationName != null : "animationName parameter must be non null";
return animations.get(animationName);
}
}
|