code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2009-2010 Ricardo Quesada
Copyright (c) 2009      Matt Oswald
Copyright (c) 2011      Zynga Inc.

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCSpriteBatchNode.h"
#include "ccConfig.h"
#include "CCSprite.h"
#include "effects/CCGrid.h"
#include "CCDrawingPrimitives.h"
#include "CCTextureCache.h"
#include "CCPointExtension.h"

namespace cocos2d
{
	const int defaultCapacity = 29;

	/*
	* creation with CCTexture2D
	*/
	CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithTexture(CCTexture2D *tex)
	{
		CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
		batchNode->initWithTexture(tex, defaultCapacity);
		batchNode->autorelease();

		return batchNode;
	}

	CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity)
	{
		CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
		batchNode->initWithTexture(tex, capacity);
		batchNode->autorelease();

		return batchNode;
	}

	/*
	* creation with File Image
	*/
	CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithFile(const char *fileImage, unsigned int capacity)
	{
		CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
		batchNode->initWithFile(fileImage, capacity);
		batchNode->autorelease();

		return batchNode;
	}

	CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithFile(const char *fileImage)
	{
		CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
		batchNode->initWithFile(fileImage, defaultCapacity);
		batchNode->autorelease();

		return batchNode;
	}

	/*
	* init with CCTexture2D
	*/
	bool CCSpriteBatchNode::initWithTexture(CCTexture2D *tex, unsigned int capacity)
	{
		m_blendFunc.src = CC_BLEND_SRC;
		m_blendFunc.dst = CC_BLEND_DST;
		m_pobTextureAtlas = new CCTextureAtlas();
		m_pobTextureAtlas->initWithTexture(tex, capacity);

		updateBlendFunc();

		// no lazy alloc in this node
        m_pChildren = CCArray::array();
		m_pobDescendants = CCArray::array();
        m_pChildren->retain();
        m_pobDescendants->retain();

		return true;
	}

	/*
	* init with FileImage
	*/
	bool CCSpriteBatchNode::initWithFile(const char* fileImage, unsigned int capacity)
	{
		CCTexture2D *pTexture2D = CCTextureCache::sharedTextureCache()->addImage(fileImage);
		return initWithTexture(pTexture2D, capacity);
	}

	CCSpriteBatchNode::~CCSpriteBatchNode()
	{
		CC_SAFE_RELEASE(m_pobTextureAtlas);
		CC_SAFE_RELEASE(m_pobDescendants);
	}

	// override visit
	// don't call visit on it's children
	void CCSpriteBatchNode::visit(void)
	{
		// CAREFUL:
		// This visit is almost identical to CocosNode#visit
		// with the exception that it doesn't call visit on it's children
		//
		// The alternative is to have a void CCSprite#visit, but
		// although this is less mantainable, is faster
		//
		if (! m_bIsVisible)
		{
			return;
		}

		glPushMatrix();

		if (m_pGrid && m_pGrid->isActive())
		{
			m_pGrid->beforeDraw();
			transformAncestors();
		}

		transform();

		draw();

		if (m_pGrid && m_pGrid->isActive())
		{
			m_pGrid->afterDraw(this);
		}

		glPopMatrix();
	}

	void CCSpriteBatchNode::addChild(CCNode *child, int zOrder, int tag)
	{
		CCAssert(child != NULL, "child should not be null");

		CCSprite *pSprite = (CCSprite*)(child);
		// check CCSprite is using the same texture id
		CCAssert(pSprite->getTexture()->getName() == m_pobTextureAtlas->getTexture()->getName(), "");

		CCNode::addChild(child, zOrder, tag);

		unsigned int uIndex = atlasIndexForChild(pSprite, zOrder);
		insertChild(pSprite, uIndex);
	}

	void CCSpriteBatchNode::addChild(CCNode *child)
	{
		CCNode::addChild(child);
	}

	void CCSpriteBatchNode::addChild(CCNode *child, int zOrder)
	{
		CCNode::addChild(child, zOrder);
	}

	// override reorderChild
	void CCSpriteBatchNode::reorderChild(CCNode *child, int zOrder)
	{
		CCAssert(child != NULL, "the child should not be null");
		CCAssert(m_pChildren->containsObject(child), "sprite batch node should contain the child");

		if (zOrder == child->getZOrder())
		{
			return;
		}

		// xxx: instead of removing/adding, it is more efficient ot reorder manually
		child->retain();
		removeChild((CCSprite*)child, false);
		addChild(child, zOrder);
		child->release();
	}

	// override remove child
	void CCSpriteBatchNode::removeChild(CCNode *child, bool cleanup)
	{
		CCSprite *pSprite = (CCSprite*)(child);

		// explicit null handling
		if (pSprite == NULL)
		{
			return;
		}

		CCAssert(m_pChildren->containsObject(pSprite), "sprite batch node should contain the child");

		// cleanup before removing
		removeSpriteFromAtlas(pSprite);

		CCNode::removeChild(pSprite, cleanup);
	}

	void CCSpriteBatchNode::removeChildAtIndex(unsigned int uIndex, bool bDoCleanup)
	{
		removeChild((CCSprite*)(m_pChildren->objectAtIndex(uIndex)), bDoCleanup);
	}

	void CCSpriteBatchNode::removeAllChildrenWithCleanup(bool bCleanup)
	{
		// Invalidate atlas index. issue #569
		if (m_pChildren && m_pChildren->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(m_pChildren, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild)
                {
                    removeSpriteFromAtlas(pChild);
                }
            }
		}

		CCNode::removeAllChildrenWithCleanup(bCleanup);

		m_pobDescendants->removeAllObjects();
		m_pobTextureAtlas->removeAllQuads();
	}

	// draw
	void CCSpriteBatchNode::draw(void)
	{
		CCNode::draw();

		// Optimization: Fast Dispatch
		if (m_pobTextureAtlas->getTotalQuads() == 0)
		{
			return;
		}

		if (m_pobDescendants && m_pobDescendants->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(m_pobDescendants, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild)
                {
                    // fast dispatch
                    pChild->updateTransform();

#if CC_SPRITEBATCHNODE_DEBUG_DRAW
                    // issue #528
                    CCRect rect = pChild->boundingBox();
                    CCPoint vertices[4]={
                        ccp(rect.origin.x,rect.origin.y),
                        ccp(rect.origin.x+rect.size.width,rect.origin.y),
                        ccp(rect.origin.x+rect.size.width,rect.origin.y+rect.size.height),
                        ccp(rect.origin.x,rect.origin.y+rect.size.height),
                    };
                    ccDrawPoly(vertices, 4, true);
#endif // CC_SPRITEBATCHNODE_DEBUG_DRAW
                }
            }
		}

		// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Unneeded states: -
		bool newBlend = m_blendFunc.src != CC_BLEND_SRC || m_blendFunc.dst != CC_BLEND_DST;
		if (newBlend)
		{
			glBlendFunc(m_blendFunc.src, m_blendFunc.dst);
		}

		m_pobTextureAtlas->drawQuads();
		if (newBlend)
		{
			glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
		}
	}

	void CCSpriteBatchNode::increaseAtlasCapacity(void)
	{
		// if we're going beyond the current TextureAtlas's capacity,
		// all the previously initialized sprites will need to redo their texture coords
		// this is likely computationally expensive
		unsigned int quantity = (m_pobTextureAtlas->getCapacity() + 1) * 4 / 3;

        CCLOG("cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [%lu] to [%lu].",
            (long)m_pobTextureAtlas->getCapacity(),
            (long)quantity);

		if (! m_pobTextureAtlas->resizeCapacity(quantity))
		{
			// serious problems
			CCLOG("cocos2d: WARNING: Not enough memory to resize the atlas");
			CCAssert(false, "Not enough memory to resize the atla");
		}
	}

	unsigned int CCSpriteBatchNode::rebuildIndexInOrder(CCSprite *pobParent, unsigned int uIndex)
	{
		CCArray *pChildren = pobParent->getChildren();

		if (pChildren && pChildren->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(pChildren, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild && (pChild->getZOrder() < 0))
                {
                    uIndex = rebuildIndexInOrder(pChild, uIndex);
                }
            }
		}

		// ignore self (batch node)
		if (! pobParent->isEqual(this))
		{
			pobParent->setAtlasIndex(uIndex);
			uIndex++;
		}

		if (pChildren && pChildren->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(pChildren, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild && (pChild->getZOrder() >= 0))
                {
                    uIndex = rebuildIndexInOrder(pChild, uIndex);
                }
            }
		}

		return uIndex;
	}

	unsigned int CCSpriteBatchNode::highestAtlasIndexInChild(CCSprite *pSprite)
	{
		CCArray *pChildren = pSprite->getChildren();

		if (! pChildren || pChildren->count() == 0)
		{
			return pSprite->getAtlasIndex();
		}
		else
		{
			return highestAtlasIndexInChild((CCSprite*)(pChildren->lastObject()));
		}
	}

	unsigned int CCSpriteBatchNode::lowestAtlasIndexInChild(CCSprite *pSprite)
	{
		CCArray *pChildren = pSprite->getChildren();

		if (! pChildren || pChildren->count() == 0)
		{
			return pSprite->getAtlasIndex();
		}
		else
		{
			return lowestAtlasIndexInChild((CCSprite*)(pChildren->objectAtIndex(0)));
		}
	}

	unsigned int CCSpriteBatchNode::atlasIndexForChild(CCSprite *pobSprite, int nZ)
	{
		CCArray *pBrothers = pobSprite->getParent()->getChildren();
		unsigned int uChildIndex = pBrothers->indexOfObject(pobSprite);

		// ignore parent Z if parent is spriteSheet
		bool bIgnoreParent = (CCSpriteBatchNode*)(pobSprite->getParent()) == this;
		CCSprite *pPrevious = NULL;
		if (uChildIndex > 0 &&
            uChildIndex < UINT_MAX)
		{
			pPrevious = (CCSprite*)(pBrothers->objectAtIndex(uChildIndex - 1));
		}

		// first child of the sprite sheet
		if (bIgnoreParent)
		{
			if (uChildIndex == 0)
			{
				return 0;
			}

			return highestAtlasIndexInChild(pPrevious) + 1;
		}

		// parent is a CCSprite, so, it must be taken into account

		// first child of an CCSprite ?
		if (uChildIndex == 0)
		{
			CCSprite *p = (CCSprite*)(pobSprite->getParent());

			// less than parent and brothers
			if (nZ < 0)
			{
				return p->getAtlasIndex();
			}
			else
			{
				return p->getAtlasIndex() + 1;
			}
		}
		else
		{
			// previous & sprite belong to the same branch
			if ((pPrevious->getZOrder() < 0 && nZ < 0) || (pPrevious->getZOrder() >= 0 && nZ >= 0))
			{
				return highestAtlasIndexInChild(pPrevious) + 1;
			}

			// else (previous < 0 and sprite >= 0 )
			CCSprite *p = (CCSprite*)(pobSprite->getParent());
			return p->getAtlasIndex() + 1;
		}

		// Should not happen. Error calculating Z on SpriteSheet
		CCAssert(0, "should not run here");
		return 0;
	}

	// add child helper

	void CCSpriteBatchNode::insertChild(CCSprite *pobSprite, unsigned int uIndex)
	{
		pobSprite->useBatchNode(this);
		pobSprite->setAtlasIndex(uIndex);
		pobSprite->setDirty(true);

		if (m_pobTextureAtlas->getTotalQuads() == m_pobTextureAtlas->getCapacity())
		{
			increaseAtlasCapacity();
		}

		ccV3F_C4B_T2F_Quad quad = pobSprite->getQuad();
		m_pobTextureAtlas->insertQuad(&quad, uIndex);

		m_pobDescendants->insertObject(pobSprite, uIndex);

		// update indices
		unsigned int i = 0;
		if (m_pobDescendants && m_pobDescendants->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(m_pobDescendants, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild)
                {
                    if (i > uIndex)
                    {
                        pChild->setAtlasIndex(pChild->getAtlasIndex() + 1);
                    }

                    ++i;
                }
            }
		}

		// add children recursively
		CCArray *pChildren = pobSprite->getChildren();
		if (pChildren && pChildren->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(pChildren, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild)
                {
                    unsigned int uIndex = atlasIndexForChild(pChild, pChild->getZOrder());
                    insertChild(pChild, uIndex);
                }
            }
		}
	}

	void CCSpriteBatchNode::removeSpriteFromAtlas(CCSprite *pobSprite)
	{
		// remove from TextureAtlas
		m_pobTextureAtlas->removeQuadAtIndex(pobSprite->getAtlasIndex());

		// Cleanup sprite. It might be reused (issue #569)
		pobSprite->useSelfRender();

		unsigned int uIndex = m_pobDescendants->indexOfObject(pobSprite);
		if (uIndex != UINT_MAX)
		{
			m_pobDescendants->removeObjectAtIndex(uIndex);

			// update all sprites beyond this one
			unsigned int count = m_pobDescendants->count();

			for(; uIndex < count; ++uIndex)
			{
				CCSprite* s = (CCSprite*)(m_pobDescendants->objectAtIndex(uIndex));
				s->setAtlasIndex( s->getAtlasIndex() - 1 );
			}
		}

		// remove children recursively
		CCArray *pChildren = pobSprite->getChildren();
		if (pChildren && pChildren->count() > 0)
		{
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(pChildren, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild)
                {
                    removeSpriteFromAtlas(pChild);
                }
            }
		}
	}

	void CCSpriteBatchNode::updateBlendFunc(void)
	{
		if (! m_pobTextureAtlas->getTexture()->getHasPremultipliedAlpha())
		{
			m_blendFunc.src = GL_SRC_ALPHA;
			m_blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
		}
	}

	// CocosNodeTexture protocol
	void CCSpriteBatchNode::setBlendFunc(ccBlendFunc blendFunc)
	{
		m_blendFunc = blendFunc;
	}

	ccBlendFunc CCSpriteBatchNode::getBlendFunc(void)
	{
		return m_blendFunc;
	}

	CCTexture2D* CCSpriteBatchNode::getTexture(void)
	{
		return m_pobTextureAtlas->getTexture();
	}

	void CCSpriteBatchNode::setTexture(CCTexture2D *texture)
	{
		m_pobTextureAtlas->setTexture(texture);
		updateBlendFunc();
	}

    // CCSpriteSheet Extension
    //implementation CCSpriteSheet (TMXTiledMapExtension)

    void CCSpriteBatchNode::addQuadFromSprite(CCSprite *sprite, unsigned int index)
    {
        CCAssert( sprite != NULL, "Argument must be non-nil");
        /// @todo CCAssert( [sprite isKindOfClass:[CCSprite class]], @"CCSpriteSheet only supports CCSprites as children");

        while(index >= m_pobTextureAtlas->getCapacity() || m_pobTextureAtlas->getCapacity() == m_pobTextureAtlas->getTotalQuads())
        {
            this->increaseAtlasCapacity();
        }
        //
        // update the quad directly. Don't add the sprite to the scene graph
        //
        sprite->useBatchNode(this);
        sprite->setAtlasIndex(index);

        ccV3F_C4B_T2F_Quad quad = sprite->getQuad();
        m_pobTextureAtlas->insertQuad(&quad, index);

        // XXX: updateTransform will update the textureAtlas too using updateQuad.
        // XXX: so, it should be AFTER the insertQuad
        sprite->setDirty(true);
        sprite->updateTransform();
    }

    CCSpriteBatchNode * CCSpriteBatchNode::addSpriteWithoutQuad(CCSprite*child, unsigned int z, int aTag)
    {
        CCAssert( child != NULL, "Argument must be non-nil");
        /// @todo CCAssert( [child isKindOfClass:[CCSprite class]], @"CCSpriteSheet only supports CCSprites as children");

        // quad index is Z
        child->setAtlasIndex(z);

        // XXX: optimize with a binary search
        int i=0;
        if (m_pobDescendants && m_pobDescendants->count() > 0)
        {
            CCObject* pObject = NULL;
            CCARRAY_FOREACH(m_pobDescendants, pObject)
            {
                CCSprite* pChild = (CCSprite*) pObject;
                if (pChild && (pChild->getAtlasIndex() >= z))
                {
                    ++i;
                }
            }
        }
        m_pobDescendants->insertObject(child, i);

        // IMPORTANT: Call super, and not self. Avoid adding it to the texture atlas array
        CCNode::addChild(child, z, aTag);
        return this;
    }

}


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2011 Ricardo Quesada
Copyright (c) 2011      Zynga Inc.

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include "CCSpriteFrame.h"
#include "CCDirector.h"

namespace   cocos2d {
// implementation of CCSpriteFrame

CCSpriteFrame* CCSpriteFrame::frameWithTexture(CCTexture2D *pobTexture, const CCRect& rect)
{
	CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
	pSpriteFrame->initWithTexture(pobTexture, rect);
	pSpriteFrame->autorelease();

	return pSpriteFrame;
}

CCSpriteFrame* CCSpriteFrame::frameWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
    CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
	pSpriteFrame->initWithTexture(pobTexture, rect, rotated, offset, originalSize);
	pSpriteFrame->autorelease();

	return pSpriteFrame;
}

bool CCSpriteFrame::initWithTexture(CCTexture2D* pobTexture, const CCRect& rect)
{
	CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS(rect);
	return initWithTexture(pobTexture, rectInPixels, false, CCPointZero, rectInPixels.size);
}

bool CCSpriteFrame::initWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
	m_pobTexture = pobTexture;

    if (pobTexture)
    {
        pobTexture->retain();
    }

	m_obRectInPixels = rect;
	m_obRect = CC_RECT_PIXELS_TO_POINTS(rect);
	m_bRotated = rotated;
	m_obOffsetInPixels = offset;

	m_obOriginalSizeInPixels = originalSize;

	return true;
}

CCSpriteFrame::~CCSpriteFrame(void)
{
	CCLOGINFO("cocos2d: deallocing %p", this);
	CC_SAFE_RELEASE(m_pobTexture);
}

CCObject* CCSpriteFrame::copyWithZone(CCZone *pZone)
{
    CC_UNUSED_PARAM(pZone);
	CCSpriteFrame *pCopy = new CCSpriteFrame();

	pCopy->initWithTexture(m_pobTexture, m_obRectInPixels, m_bRotated, m_obOffsetInPixels, m_obOriginalSizeInPixels);

	return pCopy;
}

void CCSpriteFrame::setRect(const CCRect& rect)
{
    m_obRect = rect;
    m_obRectInPixels = CC_RECT_POINTS_TO_PIXELS(m_obRect);
}

void CCSpriteFrame::setRectInPixels(const CCRect& rectInPixels)
{
    m_obRectInPixels = rectInPixels;
    m_obRect = CC_RECT_PIXELS_TO_POINTS(rectInPixels);
}

}//namespace   cocos2d

license: mit


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2008-2010 Ricardo Quesada
Copyright (c) 2009      Jason Booth
Copyright (c) 2009      Robert J Payne
Copyright (c) 2011      Zynga Inc.

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include "cocoa/CCNS.h"
#include "ccMacros.h"
#include "CCTextureCache.h"
#include "CCSpriteFrameCache.h"
#include "CCSpriteFrame.h"
#include "CCSprite.h"
#include "support/TransformUtils.h"
#include "CCFileUtils.h"
#include "CCString.h"

namespace   cocos2d {

static CCSpriteFrameCache *pSharedSpriteFrameCache = NULL;

CCSpriteFrameCache* CCSpriteFrameCache::sharedSpriteFrameCache(void)
{
	if (! pSharedSpriteFrameCache)
	{
		pSharedSpriteFrameCache = new CCSpriteFrameCache();
        pSharedSpriteFrameCache->init();
	}

	return pSharedSpriteFrameCache;
}

void CCSpriteFrameCache::purgeSharedSpriteFrameCache(void)
{
	CC_SAFE_RELEASE_NULL(pSharedSpriteFrameCache);
}

bool CCSpriteFrameCache::init(void)
{
	m_pSpriteFrames= new CCDictionary<std::string, CCSpriteFrame*>();
	m_pSpriteFramesAliases = new CCDictionary<std::string, CCString*>();
	return true;
}

CCSpriteFrameCache::~CCSpriteFrameCache(void)
{
	CC_SAFE_RELEASE(m_pSpriteFrames);
	CC_SAFE_RELEASE(m_pSpriteFramesAliases);
}

void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary<std::string, CCObject*> *dictionary, CCTexture2D *pobTexture)
{
	/*
	Supported Zwoptex Formats:

	ZWTCoordinatesFormatOptionXMLLegacy = 0, // Flash Version
	ZWTCoordinatesFormatOptionXML1_0 = 1, // Desktop Version 0.0 - 0.4b
	ZWTCoordinatesFormatOptionXML1_1 = 2, // Desktop Version 1.0.0 - 1.0.1
	ZWTCoordinatesFormatOptionXML1_2 = 3, // Desktop Version 1.0.2+
	*/

	CCDictionary<std::string, CCObject*> *metadataDict = (CCDictionary<std::string, CCObject*>*)dictionary->objectForKey(std::string("metadata"));
	CCDictionary<std::string, CCObject*> *framesDict = (CCDictionary<std::string, CCObject*>*)dictionary->objectForKey(std::string("frames"));
	int format = 0;

	// get the format
	if(metadataDict != NULL)
	{
		format = atoi(valueForKey("format", metadataDict));
	}

	// check the format
	CCAssert(format >=0 && format <= 3, "");

	framesDict->begin();
	std::string key = "";
	CCDictionary<std::string, CCObject*> *frameDict = NULL;
	while( (frameDict = (CCDictionary<std::string, CCObject*>*)framesDict->next(&key)) )
	{
		CCSpriteFrame *spriteFrame = m_pSpriteFrames->objectForKey(key);
		if (spriteFrame)
		{
			continue;
		}

		if(format == 0)
		{
			float x = (float)atof(valueForKey("x", frameDict));
			float y = (float)atof(valueForKey("y", frameDict));
			float w = (float)atof(valueForKey("width", frameDict));
			float h = (float)atof(valueForKey("height", frameDict));
			float ox = (float)atof(valueForKey("offsetX", frameDict));
			float oy = (float)atof(valueForKey("offsetY", frameDict));
			int ow = atoi(valueForKey("originalWidth", frameDict));
			int oh = atoi(valueForKey("originalHeight", frameDict));
			// check ow/oh
			if(!ow || !oh)
			{
				CCLOG("cocos2d: WARNING: originalWidth/Height not found on the CCSpriteFrame. AnchorPoint won't work as expected. Regenrate the .plist");
			}
			// abs ow/oh
			ow = abs(ow);
			oh = abs(oh);
			// create frame
			spriteFrame = new CCSpriteFrame();
			spriteFrame->initWithTexture(pobTexture,
				                        CCRectMake(x, y, w, h),
										false,
                                        CCPointMake(ox, oy),
                                        CCSizeMake((float)ow, (float)oh)
										);
		}
		else if(format == 1 || format == 2)
		{
			CCRect frame = CCRectFromString(valueForKey("frame", frameDict));
			bool rotated = false;

			// rotation
			if (format == 2)
			{
				rotated = atoi(valueForKey("rotated", frameDict)) == 0 ? false : true;
			}

			CCPoint offset = CCPointFromString(valueForKey("offset", frameDict));
			CCSize sourceSize = CCSizeFromString(valueForKey("sourceSize", frameDict));

			// create frame
			spriteFrame = new CCSpriteFrame();
			spriteFrame->initWithTexture(pobTexture,
				frame,
				rotated,
				offset,
				sourceSize
				);
		} else
		if (format == 3)
		{
			// get values
			CCSize spriteSize = CCSizeFromString(valueForKey("spriteSize", frameDict));
			CCPoint spriteOffset = CCPointFromString(valueForKey("spriteOffset", frameDict));
			CCSize spriteSourceSize = CCSizeFromString(valueForKey("spriteSourceSize", frameDict));
			CCRect textureRect = CCRectFromString(valueForKey("textureRect", frameDict));
            bool textureRotated = atoi(valueForKey("textureRotated", frameDict)) == 0 ? false : true;

			// get aliases
			CCMutableArray<CCString*> *aliases = (CCMutableArray<CCString*> *) (frameDict->objectForKey(std::string("aliases")));
            CCMutableArray<CCString*>::CCMutableArrayIterator iter;

            CCString * frameKey = new CCString(key.c_str());
            for (iter = aliases->begin(); iter != aliases->end(); ++iter)
            {
                std::string oneAlias = ((CCString*) (*iter))->m_sString;
                if (m_pSpriteFramesAliases->objectForKey(oneAlias))
                {
                    CCLOG("cocos2d: WARNING: an alias with name %s already exists", oneAlias.c_str());
                }

                m_pSpriteFramesAliases->setObject(frameKey, oneAlias);
            }
            frameKey->release();
            // create frame
            spriteFrame = new CCSpriteFrame();
            spriteFrame->initWithTexture(pobTexture,
                            CCRectMake(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height),
                            textureRotated,
                            spriteOffset,
                            spriteSourceSize);
		}

		// add sprite frame
		m_pSpriteFrames->setObject(spriteFrame, key);
		spriteFrame->release();
	}
}

void CCSpriteFrameCache::addSpriteFramesWithFile(const char *pszPlist, CCTexture2D *pobTexture)
{
	const char *pszPath = CCFileUtils::fullPathFromRelativePath(pszPlist);
	CCDictionary<std::string, CCObject*> *dict = CCFileUtils::dictionaryWithContentsOfFileThreadSafe(pszPath);

	addSpriteFramesWithDictionary(dict, pobTexture);

	dict->release();
}

void CCSpriteFrameCache::addSpriteFramesWithFile(const char* plist, const char* textureFileName)
{
	CCAssert(textureFileName, "texture name should not be null");
	CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage(textureFileName);

	if (texture)
	{
		addSpriteFramesWithFile(plist, texture);
	}
	else
	{
		CCLOG("cocos2d: CCSpriteFrameCache: couldn't load texture file. File not found %s", textureFileName);
	}
}

void CCSpriteFrameCache::addSpriteFramesWithFile(const char *pszPlist)
{
	const char *pszPath = CCFileUtils::fullPathFromRelativePath(pszPlist);
	CCDictionary<std::string, CCObject*> *dict = CCFileUtils::dictionaryWithContentsOfFileThreadSafe(pszPath);

	string texturePath("");

	CCDictionary<std::string, CCObject*>* metadataDict = (CCDictionary<std::string, CCObject*>*)dict->objectForKey(string("metadata"));
    if (metadataDict)
	{
		// try to read  texture file name from meta data
		texturePath = string(valueForKey("textureFileName", metadataDict));
	}

	if (! texturePath.empty())
	{
		// build texture path relative to plist file
        texturePath = CCFileUtils::fullPathFromRelativeFile(texturePath.c_str(), pszPath);
	}
	else
	{
		// build texture path by replacing file extension
        texturePath = pszPath;

		// remove .xxx
		size_t startPos = texturePath.find_last_of(".");
		texturePath = texturePath.erase(startPos);

		// append .png
		texturePath = texturePath.append(".png");

		CCLOG("cocos2d: CCSpriteFrameCache: Trying to use file %s as texture", texturePath.c_str());
	}

	CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(texturePath.c_str());

	if (pTexture)
	{
        addSpriteFramesWithDictionary(dict, pTexture);
	}
	else
	{
		CCLOG("cocos2d: CCSpriteFrameCache: Couldn't load texture");
	}

	dict->release();
}

void CCSpriteFrameCache::addSpriteFrame(CCSpriteFrame *pobFrame, const char *pszFrameName)
{
	m_pSpriteFrames->setObject(pobFrame, std::string(pszFrameName));
}

void CCSpriteFrameCache::removeSpriteFrames(void)
{
	m_pSpriteFrames->removeAllObjects();
	m_pSpriteFramesAliases->removeAllObjects();
}

void CCSpriteFrameCache::removeUnusedSpriteFrames(void)
{
	m_pSpriteFrames->begin();
	std::string key = "";
	CCSpriteFrame *spriteFrame = NULL;
	while( (spriteFrame = m_pSpriteFrames->next(&key)) )
	{
		if( spriteFrame->retainCount() == 1 )
		{
			CCLOG("cocos2d: CCSpriteFrameCache: removing unused frame: %s", key.c_str());
			m_pSpriteFrames->removeObjectForKey(key);
		}
	}
	m_pSpriteFrames->end();
}

void CCSpriteFrameCache::removeSpriteFrameByName(const char *pszName)
{
	// explicit nil handling
	if( ! pszName )
	{
		return;
	}

	// Is this an alias ?
	CCString *key = (CCString*)m_pSpriteFramesAliases->objectForKey(string(pszName));

	if (key)
	{
        m_pSpriteFrames->removeObjectForKey(key->m_sString);
		m_pSpriteFramesAliases->removeObjectForKey(key->m_sString);
	}
	else
	{
        m_pSpriteFrames->removeObjectForKey(std::string(pszName));
	}
}

void CCSpriteFrameCache::removeSpriteFramesFromFile(const char* plist)
{
	const char* path = CCFileUtils::fullPathFromRelativePath(plist);
	CCDictionary<std::string, CCObject*>* dict = CCFileUtils::dictionaryWithContentsOfFileThreadSafe(path);

	removeSpriteFramesFromDictionary((CCDictionary<std::string, CCSpriteFrame*>*)dict);

	dict->release();
}

void CCSpriteFrameCache::removeSpriteFramesFromDictionary(CCDictionary<std::string, CCSpriteFrame*> *dictionary)
{
	CCDictionary<std::string, CCObject*>* framesDict = (CCDictionary<std::string, CCObject*>*)dictionary->objectForKey(string("frames"));
	vector<string> keysToRemove;

	framesDict->begin();
	std::string key = "";
	CCDictionary<std::string, CCObject*> *frameDict = NULL;
	while( (frameDict = (CCDictionary<std::string, CCObject*>*)framesDict->next(&key)) )
	{
		if (m_pSpriteFrames->objectForKey(key))
		{
			keysToRemove.push_back(key);
		}
	}
	framesDict->end();

	vector<string>::iterator iter;
	for (iter = keysToRemove.begin(); iter != keysToRemove.end(); ++iter)
	{
		m_pSpriteFrames->removeObjectForKey(*iter);
	}
}

void CCSpriteFrameCache::removeSpriteFramesFromTexture(CCTexture2D* texture)
{
	vector<string> keysToRemove;

	m_pSpriteFrames->begin();
	std::string key = "";
	CCDictionary<std::string, CCObject*> *frameDict = NULL;
	while( (frameDict = (CCDictionary<std::string, CCObject*>*)m_pSpriteFrames->next(&key)) )
	{
		CCSpriteFrame *frame = m_pSpriteFrames->objectForKey(key);
		if (frame && (frame->getTexture() == texture))
		{
			keysToRemove.push_back(key);
		}
	}
	m_pSpriteFrames->end();

	vector<string>::iterator iter;
	for (iter = keysToRemove.begin(); iter != keysToRemove.end(); ++iter)
	{
		m_pSpriteFrames->removeObjectForKey(*iter);
	}
}

CCSpriteFrame* CCSpriteFrameCache::spriteFrameByName(const char *pszName)
{
	CCSpriteFrame *frame = m_pSpriteFrames->objectForKey(std::string(pszName));
	if (! frame)
	{
		// try alias dictionary
		CCString *key = (CCString*)m_pSpriteFramesAliases->objectForKey(string(pszName));
		if (key)
		{
			frame = m_pSpriteFrames->objectForKey(key->m_sString);
			if (! frame)
			{
				CCLOG("cocos2d: CCSpriteFrameCahce: Frame '%s' not found", pszName);
			}
		}
	}
	return frame;
}

const char * CCSpriteFrameCache::valueForKey(const char *key, CCDictionary<std::string, CCObject*> *dict)
{
	if (dict)
	{
		CCString *pString = (CCString*)dict->objectForKey(std::string(key));
		return pString ? pString->m_sString.c_str() : "";
	}
	return "";
}
}//namespace   cocos2d


code:
/****************************************************************************
Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com
Copyright (c) 2010 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include "CCArray.h"

namespace cocos2d
{

CCArray* CCArray::array()
{
    CCArray* pArray = new CCArray();

    if (pArray && pArray->init())
    {
        pArray->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(pArray);
    }

    return pArray;
}

CCArray* CCArray::arrayWithCapacity(unsigned int capacity)
{
    CCArray* pArray = new CCArray();

    if (pArray && pArray->initWithCapacity(capacity))
    {
        pArray->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(pArray);
    }

    return pArray;
}

CCArray* CCArray::arrayWithArray(CCArray* otherArray)
{
    CCArray* pArray = new CCArray();

    if (pArray && pArray->initWithArray(otherArray))
    {
        pArray->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(pArray);
    }

    return pArray;
}

bool CCArray::init()
{
    return initWithCapacity(1);
}

bool CCArray::initWithCapacity(unsigned int capacity)
{
    data = ccArrayNew(capacity);
    return true;
}

bool CCArray::initWithArray(CCArray* otherArray)
{
    bool bRet = false;
    do
    {
        CC_BREAK_IF(! initWithCapacity(otherArray->data->num));

        addObjectsFromArray(otherArray);
        bRet = true;
    } while (0);

    return bRet;
}

unsigned int CCArray::count()
{
    return data->num;
}

unsigned int CCArray::capacity()
{
    return data->max;
}

unsigned int CCArray::indexOfObject(CCObject* object)
{
    return ccArrayGetIndexOfObject(data, object);
}

CCObject* CCArray::objectAtIndex(unsigned int index)
{
    CCAssert(index < data->num, "index out of range in objectAtIndex()");

    return data->arr[index];
}

CCObject* CCArray::lastObject()
{
    if( data->num > 0 )
        return data->arr[data->num-1];

    return NULL;
}

CCObject* CCArray::randomObject()
{
    if(data->num==0) return NULL;

    return data->arr[(int)(data->num*CCRANDOM_0_1())];
}

bool CCArray::containsObject(CCObject* object)
{
    return ccArrayContainsObject(data, object);
}

void CCArray::addObject(CCObject* object)
{
    ccArrayAppendObjectWithResize(data, object);
}

void CCArray::addObjectsFromArray(CCArray* otherArray)
{
    ccArrayAppendArrayWithResize(data, otherArray->data);
}

void CCArray::insertObject(CCObject* object, unsigned int index)
{
    ccArrayInsertObjectAtIndex(data, object, index);
}

void CCArray::removeLastObject()
{
    CCAssert(data->num, "no objects added");
    ccArrayRemoveObjectAtIndex(data, data->num-1);
}

void CCArray::removeObject(CCObject* object)
{
    ccArrayRemoveObject(data, object);
}

void CCArray::removeObjectAtIndex(unsigned int index)
{
    ccArrayRemoveObjectAtIndex(data, index);
}

void CCArray::removeObjectsInArray(CCArray* otherArray)
{
    ccArrayRemoveArray(data, otherArray->data);
}

void CCArray::removeAllObjects()
{
    ccArrayRemoveAllObjects(data);
}

void CCArray::fastRemoveObjectAtIndex(unsigned int index)
{
    ccArrayFastRemoveObjectAtIndex(data, index);
}

void CCArray::fastRemoveObject(CCObject* object)
{
    ccArrayFastRemoveObject(data, object);
}

void CCArray::exchangeObject(CCObject* object1, CCObject* object2)
{
    unsigned int index1 = ccArrayGetIndexOfObject(data, object1);
    if(index1 == UINT_MAX)
    {
        return;
    }

    unsigned int index2 = ccArrayGetIndexOfObject(data, object2);
    if(index2 == UINT_MAX)
    {
        return;
    }

    ccArraySwapObjectsAtIndexes(data, index1, index2);
}

void CCArray::exchangeObjectAtIndex(unsigned int index1, unsigned int index2)
{
    ccArraySwapObjectsAtIndexes(data, index1, index2);
}

void CCArray::reverseObjects()
{
    if (data->num > 1)
    {
        //floor it since in case of a oneven number the number of swaps stays the same
        int count = (int) floorf(data->num/2.f);
        unsigned int maxIndex = data->num - 1;

        for (int i = 0; i < count ; i++)
        {
            ccArraySwapObjectsAtIndexes(data, i, maxIndex);
            maxIndex--;
        }
    }
}

void CCArray::reduceMemoryFootprint()
{
    ccArrayShrink(data);
}

CCArray::~CCArray()
{
    ccArrayFree(data);
}

}


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2007      Scott Lembcke
Copyright (c) 2010      Lam Pham

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include "CCPointExtension.h"
#include "ccMacros.h" // FLT_EPSILON
#include <stdio.h>
namespace   cocos2d {

#define kCCPointEpsilon FLT_EPSILON

CGFloat
ccpLength(const CCPoint& v)
{
	return sqrtf(ccpLengthSQ(v));
}

CGFloat
ccpDistance(const CCPoint& v1, const CCPoint& v2)
{
	return ccpLength(ccpSub(v1, v2));
}

CCPoint
ccpNormalize(const CCPoint& v)
{
	return ccpMult(v, 1.0f/ccpLength(v));
}

CCPoint
ccpForAngle(const CGFloat a)
{
	return ccp(cosf(a), sinf(a));
}

CGFloat
ccpToAngle(const CCPoint& v)
{
	return atan2f(v.y, v.x);
}

CCPoint ccpLerp(const CCPoint& a, const CCPoint& b, float alpha)
{
	return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha));
}

float clampf(float value, float min_inclusive, float max_inclusive)
{
	if (min_inclusive > max_inclusive) {
        CC_SWAP(min_inclusive, max_inclusive, float);
	}
	return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive;
}

CCPoint ccpClamp(const CCPoint& p, const CCPoint& min_inclusive, const CCPoint& max_inclusive)
{
	return ccp(clampf(p.x,min_inclusive.x,max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y));
}

CCPoint ccpFromSize(const CCSize& s)
{
	return ccp(s.width, s.height);
}

CCPoint ccpCompOp(const CCPoint& p, float (*opFunc)(float))
{
	return ccp(opFunc(p.x), opFunc(p.y));
}

bool ccpFuzzyEqual(const CCPoint& a, const CCPoint& b, float var)
{
	if(a.x - var <= b.x && b.x <= a.x + var)
		if(a.y - var <= b.y && b.y <= a.y + var)
			return true;
	return false;
}

CCPoint ccpCompMult(const CCPoint& a, const CCPoint& b)
{
	return ccp(a.x * b.x, a.y * b.y);
}

float ccpAngleSigned(const CCPoint& a, const CCPoint& b)
{
	CCPoint a2 = ccpNormalize(a);
    CCPoint b2 = ccpNormalize(b);
	float angle = atan2f(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2));
	if( fabs(angle) < kCCPointEpsilon ) return 0.f;
	return angle;
}

CCPoint ccpRotateByAngle(const CCPoint& v, const CCPoint& pivot, float angle)
{
	CCPoint r = ccpSub(v, pivot);
    float cosa = cosf(angle), sina = sinf(angle);
	float t = r.x;
    r.x = t*cosa - r.y*sina + pivot.x;
    r.y = t*sina + r.y*cosa + pivot.y;
	return r;
}

bool ccpSegmentIntersect(const CCPoint& A, const CCPoint& B, const CCPoint& C, const CCPoint& D)
{
    float S, T;

    if( ccpLineIntersect(A, B, C, D, &S, &T )
        && (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f) )
        return true;

    return false;
}

CCPoint ccpIntersectPoint(const CCPoint& A, const CCPoint& B, const CCPoint& C, const CCPoint& D)
{
    float S, T;

    if( ccpLineIntersect(A, B, C, D, &S, &T) )
    {
        // Point of intersection
        CCPoint P;
        P.x = A.x + S * (B.x - A.x);
        P.y = A.y + S * (B.y - A.y);
        return P;
    }

    return CCPointZero;
}

bool ccpLineIntersect(const CCPoint& A, const CCPoint& B,
					  const CCPoint& C, const CCPoint& D,
					  float *S, float *T)
{
    // FAIL: Line undefined
    if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) )
    {
        return false;
    }
    const float BAx = B.x - A.x;
    const float BAy = B.y - A.y;
    const float DCx = D.x - C.x;
    const float DCy = D.y - C.y;
    const float ACx = A.x - C.x;
    const float ACy = A.y - C.y;

    const float denom = DCy*BAx - DCx*BAy;

    *S = DCx*ACy - DCy*ACx;
    *T = BAx*ACy - BAy*ACx;

    if (denom == 0)
    {
        if (*S == 0 || *T == 0)
        {
            // Lines incident
            return true;
        }
        // Lines parallel and not incident
        return false;
    }

    *S = *S / denom;
    *T = *T / denom;

    // Point of intersection
    // CGPoint P;
    // P.x = A.x + *S * (B.x - A.x);
    // P.y = A.y + *S * (B.y - A.y);

    return true;
}

float ccpAngle(const CCPoint& a, const CCPoint& b)
{
	float angle = acosf(ccpDot(ccpNormalize(a), ccpNormalize(b)));
	if( fabs(angle) < kCCPointEpsilon ) return 0.f;
	return angle;
}
}//namespace   cocos2d


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2010      Stuart Carnie

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCProfiling.h"

#if CC_ENABLE_PROFILERS

namespace cocos2d
{
	using namespace std;
	static CCProfiler *g_sSharedProfiler;

	CCProfiler* CCProfiler::sharedProfiler(void)
	{
        if (! g_sSharedProfiler)
		{
			g_sSharedProfiler = new CCProfiler();
			g_sSharedProfiler->init();
		}

		return g_sSharedProfiler;
	}

	CCProfilingTimer* CCProfiler::timerWithName(const char *pszTimerName, CCObject *pInstance)
	{
		CCProfiler *p = CCProfiler::sharedProfiler();
		CCProfilingTimer *t = new CCProfilingTimer();
		t->initWithName(pszTimerName, pInstance);
		p->m_pActiveTimers->addObject(t);
		t->release();

		return t;
	}

	void CCProfiler::releaseTimer(CCProfilingTimer *pTimer)
	{
		CCProfiler *p = CCProfiler::sharedProfiler();
		p->m_pActiveTimers->removeObject(pTimer);

        if (0 == (p->m_pActiveTimers->count()))
        {
            CC_SAFE_DELETE(g_sSharedProfiler);
        }
	}

	bool CCProfiler::init()
	{
        m_pActiveTimers = CCArray::array();
        m_pActiveTimers->retain();

		return true;
	}

	CCProfiler::~CCProfiler(void)
	{
		CC_SAFE_RELEASE(m_pActiveTimers);
	}

	void CCProfiler::displayTimers()
	{
        CCObject* pObject = NULL;
        CCProfilingTimer* pTimer = NULL;
        CCARRAY_FOREACH(m_pActiveTimers, pObject)
		{
            pTimer = (CCProfilingTimer*) pObject;
			char *pszDescription = pTimer->description();
			CCLog(pszDescription);
			delete pszDescription;
		}
	}

	// implementation of CCProfilingTimer

	bool CCProfilingTimer::initWithName(const char* pszTimerName, CCObject *pInstance)
	{
		char tmp[160];
		sprintf(tmp, "%s (0x%.8x)", pszTimerName, (unsigned int)pInstance);
		m_NameStr = string(tmp);
        m_dAverageTime = 0.0;

		return true;
	}

	CCProfilingTimer::~CCProfilingTimer(void)
	{

	}

	char* CCProfilingTimer::description()
	{
        char *pszDes = new char[m_NameStr.length() + sizeof(double) + 32];
		sprintf(pszDes, "%s: avg time, %fms", m_NameStr.c_str(), m_dAverageTime);
		return pszDes;
	}

	void CCProfilingBeginTimingBlock(CCProfilingTimer *pTimer)
	{
		CCTime::gettimeofdayCocos2d(pTimer->getStartTime(), NULL);
	}

	void CCProfilingEndTimingBlock(CCProfilingTimer *pTimer)
	{
        struct cc_timeval currentTime;
		CCTime::gettimeofdayCocos2d(&currentTime, NULL);
		CCTime::timersubCocos2d(&currentTime, pTimer->getStartTime(), &currentTime);
		double duration = currentTime.tv_sec * 1000.0 + currentTime.tv_usec / 1000.0;

		// return in milliseconds
		pTimer->setAverageTime((pTimer->getAverageTime() + duration) / 2.0f);
	}

} // end of namespace cocos2d

#endif // CC_ENABLE_PROFILERS


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2010      Stuart Carnie

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __SUPPORT_CCPROFILING_H__
#define __SUPPORT_CCPROFILING_H__

#include "ccConfig.h"

#if CC_ENABLE_PROFILERS

#include <string>

#include "CCObject.h"
#include "platform/platform.h"
#include "CCArray.h"

namespace cocos2d
{
	class CCProfilingTimer;

	class CC_DLL CCProfiler : public CCObject
	{
	public:
		~CCProfiler(void);
		void displayTimers(void);
		bool init(void);

	public:
		static CCProfiler* sharedProfiler(void);
		static CCProfilingTimer* timerWithName(const char *pszTimerName, CCObject *pInstance);
		static void releaseTimer(CCProfilingTimer *pTimer);

	protected:
		CCArray *m_pActiveTimers;
	};

	class CCProfilingTimer : public CCObject
	{
	public:
		bool initWithName(const char* pszTimerName, CCObject *pInstance);
		~CCProfilingTimer(void);
		char* description(void);
		inline struct cc_timeval * getStartTime(void) { return &m_sStartTime; };
		inline void setAverageTime(double value) { m_dAverageTime = value; }
		inline double getAverageTime(void) { return m_dAverageTime; }

	protected:
		std::string m_NameStr;
        struct cc_timeval m_sStartTime;
		double m_dAverageTime;
	};

	void CC_DLL CCProfilingBeginTimingBlock(CCProfilingTimer *pTimer);
	void CC_DLL CCProfilingEndTimingBlock(CCProfilingTimer *pTimer);

} // end of namespace cocos2d

#endif // CC_ENABLE_PROFILERS
#endif // __SUPPORT_CCPROFILING_H__


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCUserDefault.h"
#include "platform/CCFileUtils.h"

#ifdef Q_OS_SYMBIAN
#else
#include <libxml/parser.h>
#include <libxml/tree.h>
#endif

// root name of xml
#define USERDEFAULT_ROOT_NAME	"userDefaultRoot"

#define XML_FILE_NAME "UserDefault.xml"

using namespace std;

NS_CC_BEGIN;

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
static xmlDocPtr g_sharedDoc = NULL;

/**
 * define the functions here because we don't want to
 * export xmlNodePtr and other types in "CCUserDefault.h"
 */

static xmlNodePtr getXMLNodeForKey(const char* pKey, xmlNodePtr *rootNode)
{
    xmlNodePtr curNode = NULL;

    // check the key value
    if (! pKey)
    {
        return NULL;
    }

    do
    {
        // get root node
        *rootNode = xmlDocGetRootElement(g_sharedDoc);
        if (NULL == *rootNode)
        {
            CCLOG("read root node error");
            break;
        }

        // find the node
        curNode = (*rootNode)->xmlChildrenNode;
        while (NULL != curNode)
        {
            if (! xmlStrcmp(curNode->name, BAD_CAST pKey))
            {
                break;
            }

            curNode = curNode->next;
        }
    } while (0);

    return curNode;
}

static inline const char* getValueForKey(const char* pKey)
{
    const char* ret = NULL;
    xmlNodePtr rootNode;
    xmlNodePtr node = getXMLNodeForKey(pKey, &rootNode);

    // find the node
    if (node)
    {
        ret = (const char*)xmlNodeGetContent(node);
    }

    return ret;
}

static void setValueForKey(const char* pKey, const char* pValue)
{
    xmlNodePtr rootNode;
    xmlNodePtr node;

    // check the params
    if (! pKey || ! pValue)
    {
        return;
    }

    // find the node
    node = getXMLNodeForKey(pKey, &rootNode);

    // if node exist, change the content
    if (node)
    {
        xmlNodeSetContent(node, BAD_CAST pValue);
    }
    else
    {
        if (rootNode)
        {
            // the node doesn't exist, add a new one
            // libxml in android donesn't support xmlNewTextChild, so use this approach
            xmlNodePtr tmpNode = xmlNewNode(NULL, BAD_CAST pKey);
            xmlNodePtr content = xmlNewText(BAD_CAST pValue);
            xmlAddChild(rootNode, tmpNode);
            xmlAddChild(tmpNode, content);
        }
    }
}
#endif

/**
 * implements of CCUserDefault
 */

CCUserDefault* CCUserDefault::m_spUserDefault = 0;

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
string CCUserDefault::m_sFilePath = string("");
bool CCUserDefault::m_sbIsFilePathInitialized = false;
#else
QSettings* CCUserDefault::m_settings = NULL;
#endif

/**
 * If the user invoke delete CCUserDefault::sharedUserDefault(), should set m_spUserDefault
 * to null to avoid error when he invoke CCUserDefault::sharedUserDefault() later.
 */
CCUserDefault::~CCUserDefault()
{
    flush();
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    if (g_sharedDoc)
    {
        xmlFreeDoc(g_sharedDoc);
        g_sharedDoc = NULL;
    }

    m_spUserDefault = NULL;
#endif
}

CCUserDefault::CCUserDefault()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    g_sharedDoc = xmlReadFile(getXMLFilePath().c_str(), "utf-8", XML_PARSE_RECOVER);
#else
    m_settings = new QSettings();
#endif
}

void CCUserDefault::purgeSharedUserDefault()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)

    CC_SAFE_DELETE(m_spUserDefault);
    m_spUserDefault = NULL;
#else
    if(m_settings)
        delete m_settings;
#endif
}

bool CCUserDefault::getBoolForKey(const char* pKey, bool defaultValue)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    const char* value = getValueForKey(pKey);
    bool ret = defaultValue;

    if (value)
    {
        ret = (! strcmp(value, "true"));
        xmlFree((void*)value);
    }

    return ret;
#else
    return m_settings->value(pKey, defaultValue).toBool();
#endif
}

int CCUserDefault::getIntegerForKey(const char* pKey, int defaultValue)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    const char* value = getValueForKey(pKey);
    int ret = defaultValue;

    if (value)
    {
        ret = atoi(value);
        xmlFree((void*)value);
    }

    return ret;
#else
    return m_settings->value(pKey, defaultValue).toInt();
#endif
}

float CCUserDefault::getFloatForKey(const char* pKey, float defaultValue)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    float ret = (float)getDoubleForKey(pKey, (double)defaultValue);

    return ret;
#else
    return m_settings->value(pKey, defaultValue).toFloat();
#endif
}

double CCUserDefault::getDoubleForKey(const char* pKey, double defaultValue)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    const char* value = getValueForKey(pKey);
    double ret = defaultValue;

    if (value)
    {
        ret = atof(value);
        xmlFree((void*)value);
    }

    return ret;
#else
    return m_settings->value(pKey, defaultValue).toDouble();
#endif
}

string CCUserDefault::getStringForKey(const char* pKey, const std::string & defaultValue)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    const char* value = getValueForKey(pKey);
    string ret = defaultValue;

    if (value)
    {
        ret = string(value);
        xmlFree((void*)value);
    }

    return ret;
#else
    QString str = m_settings->value(pKey, defaultValue.c_str()).toString();
    QByteArray ba = str.toAscii();
    string ret(ba.constData());
    return ret;
#endif
}

void CCUserDefault::setBoolForKey(const char* pKey, bool value)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    // save bool value as sring

    if (true == value)
    {
        setStringForKey(pKey, "true");
    }
    else
    {
        setStringForKey(pKey, "false");
    }
#else
    m_settings->setValue(pKey, value);
#endif
}

void CCUserDefault::setIntegerForKey(const char* pKey, int value)
{
    // check key
    if (! pKey)
    {
        return;
    }

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    // format the value
    char tmp[50];
    memset(tmp, 0, 50);
    sprintf(tmp, "%d", value);

    setValueForKey(pKey, tmp);
#else
    m_settings->setValue(pKey, value);
#endif
}

void CCUserDefault::setFloatForKey(const char* pKey, float value)
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    setDoubleForKey(pKey, value);
#else
    m_settings->setValue(pKey, value);
#endif
}

void CCUserDefault::setDoubleForKey(const char* pKey, double value)
{
    // check key
    if (! pKey)
    {
        return;
    }

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    // format the value
    char tmp[50];
    memset(tmp, 0, 50);
    sprintf(tmp, "%f", value);

    setValueForKey(pKey, tmp);
#else
    m_settings->setValue(pKey, value);
#endif
}

void CCUserDefault::setStringForKey(const char* pKey, const std::string & value)
{
    // check key
    if (! pKey)
    {
        return;
    }

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    setValueForKey(pKey, value.c_str());
#else
    m_settings->setValue(pKey, value.c_str());
#endif
}

CCUserDefault* CCUserDefault::sharedUserDefault()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    initXMLFilePath();

    // only create xml file one time
    // the file exists after the programe exit
    if ((! isXMLFileExist()) && (! createXMLFile()))
    {
        return NULL;
    }
#endif

    if (! m_spUserDefault)
    {
        m_spUserDefault = new CCUserDefault();
    }

    return m_spUserDefault;
}

#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
bool CCUserDefault::isXMLFileExist()
{
    FILE *fp = fopen(m_sFilePath.c_str(), "r");
    bool bRet = false;

    if (fp)
    {
        bRet = true;
        fclose(fp);
    }

    return bRet;
}

void CCUserDefault::initXMLFilePath()
{
    if (! m_sbIsFilePathInitialized)
    {
        m_sFilePath += CCFileUtils::getWriteablePath() + XML_FILE_NAME;
        m_sbIsFilePathInitialized = true;
    }
}

// create new xml file
bool CCUserDefault::createXMLFile()
{
    bool bRet = false;
    xmlDocPtr doc = NULL;

    do
    {
        // new doc
        doc = xmlNewDoc(BAD_CAST"1.0");
        if (doc == NULL)
        {
            CCLOG("can not create xml doc");
            break;
        }

        // new root node
        xmlNodePtr rootNode = xmlNewNode(NULL, BAD_CAST USERDEFAULT_ROOT_NAME);
        if (rootNode == NULL)
        {
            CCLOG("can not create root node");
            break;
        }

        // set root node
        xmlDocSetRootElement(doc, rootNode);

        // save xml file
        xmlSaveFile(m_sFilePath.c_str(), doc);

        bRet = true;
    } while (0);

    // if doc is not null, free it
    if (doc)
    {
        xmlFreeDoc(doc);
    }

    return bRet;
}
#endif

const string& CCUserDefault::getXMLFilePath()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    return m_sFilePath;
#else
    // TODO: ...
    static string tmp("");
    return tmp;
#endif
}

void CCUserDefault::flush()
{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_QT)
    // save to file
    if (g_sharedDoc)
    {
        xmlSaveFile(CCUserDefault::sharedUserDefault()->getXMLFilePath().c_str(), g_sharedDoc);
    }
#else
    // TODO: ...
    m_settings->sync();
#endif
}

NS_CC_END;


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2009      Valentin Milea

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include "TransformUtils.h"
#include "CCAffineTransform.h"
namespace   cocos2d {

void CGAffineToGL(const CCAffineTransform *t, GLfloat *m)
{
	// | m[0] m[4] m[8]  m[12] |     | m11 m21 m31 m41 |     | a c 0 tx |
	// | m[1] m[5] m[9]  m[13] |     | m12 m22 m32 m42 |     | b d 0 ty |
	// | m[2] m[6] m[10] m[14] | <=> | m13 m23 m33 m43 | <=> | 0 0 1  0 |
	// | m[3] m[7] m[11] m[15] |     | m14 m24 m34 m44 |     | 0 0 0  1 |

	m[2] = m[3] = m[6] = m[7] = m[8] = m[9] = m[11] = m[14] = 0.0f;
	m[10] = m[15] = 1.0f;
	m[0] = t->a; m[4] = t->c; m[12] = t->tx;
	m[1] = t->b; m[5] = t->d; m[13] = t->ty;
}

void GLToCGAffine(const GLfloat *m, CCAffineTransform *t)
{
	t->a = m[0]; t->c = m[4]; t->tx = m[12];
	t->b = m[1]; t->d = m[5]; t->ty = m[13];
}
}//namespace   cocos2d


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2009      Valentin Milea

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#ifndef __SUPPORT_TRANSFORM_UTILS_H__
#define __SUPPORT_TRANSFORM_UTILS_H__

///@todo
// when in MAC or windows, it includes <OpenGL/gl.h>
#include "CCGL.h"

namespace   cocos2d {

struct CCAffineTransform;

void CGAffineToGL(const CCAffineTransform *t, GLfloat *m);
void GLToCGAffine(const GLfloat *m, CCAffineTransform *t);
}//namespace   cocos2d

#endif // __SUPPORT_TRANSFORM_UTILS_H__


code:
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "base64.h"
namespace   cocos2d {

unsigned char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len );

int _base64Decode( unsigned char *input, unsigned int input_len, unsigned char *output, unsigned int *output_len )
{
    static char inalphabet[256], decoder[256];
    int i, bits, c = 0, char_count, errors = 0;
	unsigned int input_idx = 0;
	unsigned int output_idx = 0;

    for (i = (sizeof alphabet) - 1; i >= 0 ; i--) {
		inalphabet[alphabet[i]] = 1;
		decoder[alphabet[i]] = i;
    }

    char_count = 0;
    bits = 0;
	for( input_idx=0; input_idx < input_len ; input_idx++ ) {
		c = input[ input_idx ];
		if (c == '=')
			break;
		if (c > 255 || ! inalphabet[c])
			continue;
		bits += decoder[c];
		char_count++;
		if (char_count == 4) {
			output[ output_idx++ ] = (bits >> 16);
			output[ output_idx++ ] = ((bits >> 8) & 0xff);
			output[ output_idx++ ] = ( bits & 0xff);
			bits = 0;
			char_count = 0;
		} else {
			bits <<= 6;
		}
    }

	if( c == '=' ) {
		switch (char_count) {
			case 1:
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
				std::fprintf(stderr, "base64Decode: encoding incomplete: at least 2 bits missing");
#endif
				errors++;
				break;
			case 2:
				output[ output_idx++ ] = ( bits >> 10 );
				break;
			case 3:
				output[ output_idx++ ] = ( bits >> 16 );
				output[ output_idx++ ] = (( bits >> 8 ) & 0xff);
				break;
			}
	} else if ( input_idx < input_len ) {
		if (char_count) {
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
			std::fprintf(stderr, "base64 encoding incomplete: at least %d bits truncated",
					((4 - char_count) * 6));
#endif
			errors++;
		}
    }

	*output_len = output_idx;
	return errors;
}

int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out)
{
	unsigned int outLength = 0;

	//should be enough to store 6-bit buffers in 8-bit buffers
	*out = new unsigned char[(size_t)(inLength * 3.0f / 4.0f + 1)];
	if( *out ) {
		int ret = _base64Decode(in, inLength, *out, &outLength);

		if (ret > 0 )
		{
#if (CC_TARGET_PLATFORM != CC_PLATFORM_BADA)
			printf("Base64Utils: error decoding");
#endif
			delete [] *out;
			*out = NULL;
			outLength = 0;
		}
	}
    return outLength;
}
}//namespace   cocos2d


code:
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

#ifndef __SUPPORT_BASE64_H__
#define __SUPPORT_BASE64_H__

#ifdef __cplusplus
extern "C" {
#endif

namespace   cocos2d {

/** @file
 base64 helper functions
 */

/**
 * Decodes a 64base encoded memory. The decoded memory is
 * expected to be freed by the caller.
 *
 * @returns the length of the out buffer
 *
 @since v0.8.1
 */
int base64Decode(unsigned char *in, unsigned int inLength, unsigned char **out);
}//namespace   cocos2d

#ifdef __cplusplus
}
#endif

#endif // __SUPPORT_BASE64_H__


code:
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "ccUtils.h"

namespace cocos2d
{
	unsigned long ccNextPOT(unsigned long x)
	{
		x = x - 1;
		x = x | (x >> 1);
		x = x | (x >> 2);
		x = x | (x >> 4);
		x = x | (x >> 8);
		x = x | (x >>16);
		return x + 1;
	}
}


code:
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __SUPPORT_CC_UTILS_H__
#define __SUPPORT_CC_UTILS_H__

/** @file ccUtils.h
Misc free functions
*/

namespace cocos2d
{
	/*
	ccNextPOT function is licensed under the same license that is used in CCTexture2D.m.
	*/

	/** returns the Next Power of Two value.

	Examples:
	- If "value" is 15, it will return 16.
	- If "value" is 16, it will return 16.
	- If "value" is 17, it will return 32.

	@since v0.99.5
	*/

	unsigned long ccNextPOT( unsigned long value );
}

#endif // __SUPPORT_CC_UTILS_H__


code:
/****************************************************************************
Copyright (c) 2010-2011 cocos2d-x.org
Copyright (c) 2007      Scott Lembcke

http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/

/**
 @file
 Based on Chipmunk cpArray.
 ccArray is a faster alternative to CCMutableArray, it does pretty much the
 same thing (stores CCObjects and retains/releases them appropriately). It's
 faster because:
 - it uses a plain C interface so it doesn't incur Objective-c messaging overhead
 - it assumes you know what you're doing, so it doesn't spend time on safety checks
   (index out of bounds, required capacity etc.)
 - comparisons are done using pointer equality instead of isEqual
 */

#ifndef CC_ARRAY_H
#define CC_ARRAY_H

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "ccMacros.h"
#include "CCObject.h"
#include "ccMacros.h"

namespace cocos2d {

	// Easy integration
#define CCARRAYDATA_FOREACH(__array__, __object__)															\
	__object__=__array__->arr[0]; for(unsigned int i=0, num=__array__->num; i<num; i++, __object__=__array__->arr[i])	\

typedef struct _ccArray
{
	unsigned int num, max;
	CCObject**    arr; //equals CCObject** arr;
} ccArray;

/** Allocates and initializes a new array with specified capacity */
static inline ccArray* ccArrayNew(unsigned int capacity)
{
	if (capacity == 0)
	{
		capacity = 1;
	}

	ccArray *arr = (ccArray*)malloc( sizeof(ccArray) );
	arr->num = 0;

	arr->arr =  (CCObject**)malloc( capacity * sizeof(CCObject*) );
	arr->max = capacity;

	return arr;
}

static inline void ccArrayRemoveAllObjects(ccArray *arr);

/** Frees array after removing all remaining objects. Silently ignores nil arr. */
static inline void ccArrayFree(ccArray *arr)
{
	if( arr == NULL )
	{
		return;
	}

	ccArrayRemoveAllObjects(arr);

	//delete arr->m_pObjectArray;
	free(arr->arr);

	free(arr);
}

/** Doubles array capacity */
static inline void ccArrayDoubleCapacity(ccArray *arr)
{
	arr->max *= 2;
    CCObject** newArr = (CCObject**)realloc( arr->arr, arr->max * sizeof(CCObject*) );
    // will fail when there's not enough memory
    CCAssert(newArr != NULL, "ccArrayDoubleCapacity failed. Not enough memory");
    arr->arr = newArr;
}

/** Increases array capacity such that max >= num + extra. */
static inline void ccArrayEnsureExtraCapacity(ccArray *arr, unsigned int extra)
{
	while (arr->max < arr->num + extra)
	{
		ccArrayDoubleCapacity(arr);
	}
}

/** shrinks the array so the memory footprint corresponds with the number of items */
static inline void ccArrayShrink(ccArray *arr)
{
    unsigned int newSize;

    //only resize when necessary
    if (arr->max > arr->num && !(arr->num==0 && arr->max==1))
    {
        if (arr->num!=0)
        {
            newSize=arr->num;
            arr->max=arr->num;
        }
        else
        {//minimum capacity of 1, with 0 elements the array would be free'd by realloc
            newSize=1;
            arr->max=1;
        }

        arr->arr = (CCObject**) realloc(arr->arr,newSize * sizeof(CCObject*) );
        CCAssert(arr->arr != NULL, "could not reallocate the memory");
    }
}

/** Returns index of first occurence of object, UXNotFound if object not found. */
static inline unsigned int ccArrayGetIndexOfObject(ccArray *arr, CCObject* object)
{
	for ( unsigned int i = 0; i < arr->num; i++)
	{
		if (arr->arr[i] == object)
		{
			return i;
		}
	}

	return UINT_MAX;
}

/** Returns a Boolean value that indicates whether object is present in array. */
static inline bool ccArrayContainsObject(ccArray *arr, CCObject* object)
{
	return ccArrayGetIndexOfObject(arr, object) != UINT_MAX;
}

/** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */
static inline void ccArrayAppendObject(ccArray *arr, CCObject* object)
{
	arr->arr[arr->num] = object; object->retain();
	arr->num++;
}

/** Appends an object. Capacity of arr is increased if needed. */
static inline void ccArrayAppendObjectWithResize(ccArray *arr, CCObject* object)
{
	ccArrayEnsureExtraCapacity(arr, 1);
	ccArrayAppendObject(arr, object);
}

/** Appends objects from plusArr to arr. Behaviour undefined if arr doesn't have
 enough capacity. */
static inline void ccArrayAppendArray(ccArray *arr, ccArray *plusArr)
{
	for( unsigned int i = 0; i < plusArr->num; i++)
	{
		ccArrayAppendObject(arr, plusArr->arr[i]);
	}
}

/** Appends objects from plusArr to arr. Capacity of arr is increased if needed. */
static inline void ccArrayAppendArrayWithResize(ccArray *arr, ccArray *plusArr)
{
	ccArrayEnsureExtraCapacity(arr, plusArr->num);
	ccArrayAppendArray(arr, plusArr);
}

/** Inserts an object at index */
static inline void ccArrayInsertObjectAtIndex(ccArray *arr, CCObject* object, unsigned int index)
{
    CCAssert(index<=arr->num, "Invalid index. Out of bounds");

    ccArrayEnsureExtraCapacity(arr, 1);

    unsigned int remaining = arr->num - index;
    if( remaining > 0)
        memmove(&arr->arr[index+1], &arr->arr[index], sizeof(CCObject*) * remaining );

    object->retain();
    arr->arr[index] = object;
    arr->num++;
}

/** Swaps two objects */
static inline void ccArraySwapObjectsAtIndexes(ccArray *arr, unsigned int index1, unsigned int index2)
{
    CCAssert(index1 < arr->num, "(1) Invalid index. Out of bounds");
    CCAssert(index2 < arr->num, "(2) Invalid index. Out of bounds");

    CCObject* object1 = arr->arr[index1];

    arr->arr[index1] = arr->arr[index2];
    arr->arr[index2] = object1;
}

/** Removes all objects from arr */
static inline void ccArrayRemoveAllObjects(ccArray *arr)
{
	while(arr->num > 0)
	{
		arr->arr[--arr->num]->release();
	}
}

/** Removes object at specified index and pushes back all subsequent objects.
 Behaviour undefined if index outside [0, num-1]. */
static inline void ccArrayRemoveObjectAtIndex(ccArray *arr, unsigned int index)
{
	arr->arr[index]->release();
	arr->num--;

	unsigned int remaining = arr->num - index;
	if (remaining > 0)
	{
			memmove(&arr->arr[index], &arr->arr[index+1], remaining * sizeof(void*));
	}
}

/** Removes object at specified index and fills the gap with the last object,
 thereby avoiding the need to push back subsequent objects.
 Behaviour undefined if index outside [0, num-1]. */
static inline void ccArrayFastRemoveObjectAtIndex(ccArray *arr, unsigned int index)
{
	arr->arr[index]->release();

	unsigned int last = --arr->num;
	arr->arr[index] = arr->arr[last];
}

static inline void ccArrayFastRemoveObject(ccArray *arr, CCObject* object)
{
    unsigned int index = ccArrayGetIndexOfObject(arr, object);
    if (index != UINT_MAX)
        ccArrayFastRemoveObjectAtIndex(arr, index);
}

/** Searches for the first occurance of object and removes it. If object is not
 found the function has no effect. */
static inline void ccArrayRemoveObject(ccArray *arr, CCObject* object)
{
	unsigned int index = ccArrayGetIndexOfObject(arr, object);

	if (index != UINT_MAX)
	{
		ccArrayRemoveObjectAtIndex(arr, index);
	}
}

/** Removes from arr all objects in minusArr. For each object in minusArr, the
 first matching instance in arr will be removed. */
static inline void ccArrayRemoveArray(ccArray *arr, ccArray *minusArr)
{
	for( unsigned int i = 0; i < minusArr->num; i++)
	{
		ccArrayRemoveObject(arr, minusArr->arr[i]);
	}
}

/** Removes from arr all objects in minusArr. For each object in minusArr, all
 matching instances in arr will be removed. */
static inline void ccArrayFullRemoveArray(ccArray *arr, ccArray *minusArr)
{
	unsigned int back = 0;

	for( unsigned int i = 0; i < arr->num; i++)
	{
		if( ccArrayContainsObject(minusArr, arr->arr[i]) )
		{
			delete arr->arr[i];
			back++;
		}
		else
		{
			arr->arr[i - back] = arr->arr[i];
		}
	}

	arr->num -= back;
}

typedef struct _ccCArray
{
	unsigned int num, max;
	void**    arr; //equals CCObject** arr;
} ccCArray;

static inline void ccCArrayRemoveAllValues(ccCArray *arr);

/** Allocates and initializes a new C array with specified capacity */
static inline ccCArray* ccCArrayNew(unsigned int capacity)
{
	if (capacity == 0)
	{
		capacity = 1;
	}

	ccCArray *arr = (ccCArray*)malloc( sizeof(ccCArray) );
	arr->num = 0;
	arr->arr =  (void**) malloc( capacity * sizeof(void*) );
	arr->max = capacity;

	return arr;
}

/** Frees C array after removing all remaining values. Silently ignores nil arr. */
static inline void ccCArrayFree(ccCArray *arr)
{
	if( arr == NULL )
	{
		return;
	}

	ccCArrayRemoveAllValues(arr);

	free(arr->arr);
	free(arr);
}

/** Doubles C array capacity */
static inline void ccCArrayDoubleCapacity(ccCArray *arr)
{
	ccArrayDoubleCapacity((ccArray*)arr);
}

/** Increases array capacity such that max >= num + extra. */
static inline void ccCArrayEnsureExtraCapacity(ccCArray *arr, unsigned int extra)
{
	ccArrayEnsureExtraCapacity((ccArray*)arr,extra);
}

/** Returns index of first occurence of value, NSNotFound if value not found. */
static inline int ccCArrayGetIndexOfValue(ccCArray *arr, void* value)
{
	for (unsigned int i = 0; i < arr->num; i++)
	{
		if (arr->arr[i] == value)
		{
			return i;
		}
	}

	return -1;
}

/** Returns a Boolean value that indicates whether value is present in the C array. */
static inline bool ccCArrayContainsValue(ccCArray *arr, void* value)
{
	return ccCArrayGetIndexOfValue(arr, value) != -1;
}

/** Inserts a value at a certain position. The valid index is [0, num] */
static inline void ccCArrayInsertValueAtIndex( ccCArray *arr, void* value, unsigned int index)
{
    CCAssert( index < arr->max, "ccCArrayInsertValueAtIndex: invalid index");
	unsigned int remaining = arr->num - index;

	// make sure it has enough capacity
	if (arr->num + 1 == arr->max)
	{
        ccCArrayDoubleCapacity(arr);
	}

	// last Value doesn't need to be moved
	if( remaining > 0)
	{
		// tex coordinates
		memmove( &arr->arr[index+1],&arr->arr[index], sizeof(void*) * remaining );
	}

	arr->num++;
	arr->arr[index] = value;
}

/** Appends an value */
static inline void ccCArrayAppendValue(ccCArray *arr, void* value)
{
	arr->arr[arr->num] =  value;
	arr->num++;

	// double the capacity for the next append action
	// if the num >= max
	if (arr->num >= arr->max)
	{
		ccCArrayDoubleCapacity(arr);
	}
}

/** Appends an value. Capacity of arr is increased if needed. */
static inline void ccCArrayAppendValueWithResize(ccCArray *arr, void* value)
{
	ccCArrayEnsureExtraCapacity(arr, 1);
	ccCArrayAppendValue(arr, value);
}

/** Appends values from plusArr to arr. Behaviour undefined if arr doesn't have
 enough capacity. */
static inline void ccCArrayAppendArray(ccCArray *arr, ccCArray *plusArr)
{
	for (unsigned int i = 0; i < plusArr->num; i++)
	{
		ccCArrayAppendValue(arr, plusArr->arr[i]);
	}
}

/** Appends values from plusArr to arr. Capacity of arr is increased if needed. */
static inline void ccCArrayAppendArrayWithResize(ccCArray *arr, ccCArray *plusArr)
{
	ccCArrayEnsureExtraCapacity(arr, plusArr->num);
	ccCArrayAppendArray(arr, plusArr);
}

/** Removes all values from arr */
static inline void ccCArrayRemoveAllValues(ccCArray *arr)
{
	arr->num = 0;
}

/** Removes value at specified index and pushes back all subsequent values.
 Behaviour undefined if index outside [0, num-1]. */
static inline void ccCArrayRemoveValueAtIndex(ccCArray *arr, unsigned int index)
{
	for (unsigned int last = --arr->num; index < last; index++)
	{
		arr->arr[index] = arr->arr[index + 1];
	}
}

/** Removes value at specified index and fills the gap with the last value,
 thereby avoiding the need to push back subsequent values.
 Behaviour undefined if index outside [0, num-1]. */
static inline void ccCArrayFastRemoveValueAtIndex(ccCArray *arr, unsigned int index)
{
	unsigned int last = --arr->num;
	arr->arr[index] = arr->arr[last];
}

/** Searches for the first occurance of value and removes it. If value is not
 found the function has no effect. */
static inline void ccCArrayRemoveValue(ccCArray *arr, void* value)
{
	unsigned int index = ccCArrayGetIndexOfValue(arr, value);
	if (index != UINT_MAX)
	{
		ccCArrayRemoveValueAtIndex(arr, index);
	}
}

/** Removes from arr all values in minusArr. For each Value in minusArr, the
 first matching instance in arr will be removed. */
static inline void ccCArrayRemoveArray(ccCArray *arr, ccCArray *minusArr)
{
	for( unsigned int i = 0; i < minusArr->num; i++)
	{
		ccCArrayRemoveValue(arr, minusArr->arr[i]);
	}
}

/** Removes from arr all values in minusArr. For each value in minusArr, all
 matching instances in arr will be removed. */
static inline void ccCArrayFullRemoveArray(ccCArray *arr, ccCArray *minusArr)
{
	unsigned int back = 0;

	for (unsigned int i = 0; i < arr->num; i++)
	{
		if( ccCArrayContainsValue(minusArr, arr->arr[i]) )
		{
			back++;
		} else
		{
			arr->arr[i - back] = arr->arr[i];
		}
	}

	arr->num -= back;
}

}

#endif // CC_ARRAY_H