diff --git a/cocos2dx/cocos2dx-uphone.vcproj b/cocos2dx/cocos2dx-uphone.vcproj
index bea617417d..3b87826d25 100644
--- a/cocos2dx/cocos2dx-uphone.vcproj
+++ b/cocos2dx/cocos2dx-uphone.vcproj
@@ -452,6 +452,10 @@
RelativePath=".\include\CCTileMapAtlas.h"
>
+
+
@@ -772,6 +776,10 @@
RelativePath=".\tileMap_parallax_nodes\CCTileMapAtlas.cpp"
>
+
+
diff --git a/cocos2dx/include/CCSpriteSheet.h b/cocos2dx/include/CCSpriteSheet.h
index 3d526b380a..32f9ea2cda 100644
--- a/cocos2dx/include/CCSpriteSheet.h
+++ b/cocos2dx/include/CCSpriteSheet.h
@@ -169,6 +169,21 @@ protected:
// all descendants: chlidren, gran children, etc...
NSArray *m_pobDescendants;
+protected:
+ /* IMPORTANT XXX IMPORTNAT:
+ * These 2 methods can't be part of CCTMXLayer since they call [super add...], and CCSpriteSheet#add SHALL not be called
+ */
+
+ /* Adds a quad into the texture atlas but it won't be added into the children array.
+ This method should be called only when you are dealing with very big AtlasSrite and when most of the CCSprite won't be updated.
+ For example: a tile map (CCTMXMap) or a label with lots of characgers (BitmapFontAtlas)
+ */
+ void addQuadFromSprite(CCSprite *sprite, unsigned int index);
+ /* This is the opposite of "addQuadFromSprite.
+ It add the sprite to the children and descendants array, but it doesn't update add it to the texture atlas
+ */
+ CCSpriteSheet * addSpriteWithoutQuad(CCSprite*child, unsigned int z, int aTag);
+
};
}//namespace cocos2d
diff --git a/cocos2dx/include/CCTMXLayer.h b/cocos2dx/include/CCTMXLayer.h
new file mode 100644
index 0000000000..a7f4f5e9df
--- /dev/null
+++ b/cocos2dx/include/CCTMXLayer.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+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 __CCTMX_LAYER_H__
+#define __CCTMX_LAYER_H__
+#include "CCTMXObjectGroup.h"
+#include "CCAtlasNode.h"
+#include "CCSpriteSheet.h"
+#include "support/data_support/ccArray.h"
+namespace cocos2d {
+
+ class CCTMXMapInfo;
+ class CCTMXLayerInfo;
+ class CCTMXTilesetInfo;
+
+ /** CCTMXLayer represents the TMX layer.
+
+ It is a subclass of CCSpriteSheet. By default the tiles are rendered using a CCTextureAtlas.
+ If you mofify a tile on runtime, then, that tile will become a CCSprite.
+ The benefits of using CCSprite objects as tiles are:
+ - tiles (CCSprite) can be rotated/scaled/moved with a nice API
+
+ If the layer contains a property named "cc_vertexz" with an integer (in can be positive or negative),
+ then all the tiles belonging to the layer will use that value as their OpenGL vertex Z for depth.
+
+ On the other hand, if the "cc_vertexz" property has the "automatic" value, then the tiles will use an automatic vertex Z value.
+ Also before drawing the tiles, GL_ALPHA_TEST will be enabled, and disabled after drawin them. The used alpha func will be:
+
+ glAlphaFunc( GL_GREATER, value )
+
+ "value" by default is 0, but you can change it from Tiled by adding the "cc_alpha_func" property to the layer.
+ The value 0 should work for most cases, but if you have tiles that are semi-transparent, then you might want to use a differnt
+ value, like 0.5.
+
+ For further information, please see the programming guide:
+
+ http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:tiled_maps
+
+ @since v0.8.1
+ */
+ class CCX_DLL CCTMXLayer : public CCSpriteSheet
+ {
+ /** name of the layer */
+ CCX_SYNTHESIZE(std::string, m_sLayerName, LayerName);
+ /** size of the layer in tiles */
+ CCX_SYNTHESIZE(CGSize, m_tLayerSize, LayerSize);
+ /** size of the map's tile (could be differnt from the tile's size) */
+ CCX_SYNTHESIZE(CGSize, m_tMapTileSize, MapTileSize);
+ /** pointer to the map of tiles */
+ CCX_SYNTHESIZE(unsigned int*, m_pTiles, Tiles);
+ /** Tilset information for the layer */
+ CCX_SYNTHESIZE(CCTMXTilesetInfo*, m_pTileSet, TileSet);
+ /** Layer orientation, which is the same as the map orientation */
+ CCX_SYNTHESIZE(int, m_nLayerOrientation, LayerOrientation);
+ /** properties from the layer. They can be added using Tiled */
+ CCX_SYNTHESIZE(StringToStringDictionary*, m_pProperties, Properties);
+ public:
+ CCTMXLayer();
+ virtual ~CCTMXLayer();
+ /** creates a CCTMXLayer with an tileset info, a layer info and a map info */
+ static CCTMXLayer * layerWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo);
+ /** initializes a CCTMXLayer with a tileset info, a layer info and a map info */
+ bool initWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo);
+
+ /** dealloc the map that contains the tile position from memory.
+ Unless you want to know at runtime the tiles positions, you can safely call this method.
+ If you are going to call [layer tileGIDAt:] then, don't release the map
+ */
+ void releaseMap();
+
+ /** returns the tile (CCSprite) at a given a tile coordinate.
+ The returned CCSprite will be already added to the CCTMXLayer. Don't add it again.
+ The CCSprite can be treated like any other CCSprite: rotated, scaled, translated, opacity, color, etc.
+ You can remove either by calling:
+ - [layer removeChild:sprite cleanup:cleanup];
+ - or [layer removeTileAt:ccp(x,y)];
+ */
+ CCSprite* tileAt(CGPoint tileCoordinate);
+
+ /** returns the tile gid at a given tile coordinate.
+ if it returns 0, it means that the tile is empty.
+ This method requires the the tile map has not been previously released (eg. don't call [layer releaseMap])
+ */
+ unsigned int tileGIDAt(CGPoint tileCoordinate);
+
+ /** sets the tile gid (gid = tile global id) at a given tile coordinate.
+ The Tile GID can be obtained by using the method "tileGIDAt" or by using the TMX editor -> Tileset Mgr +1.
+ If a tile is already placed at that position, then it will be removed.
+ */
+ void setTileGID(unsigned int gid, CGPoint tileCoordinate);
+
+ /** removes a tile at given tile coordinate */
+ void removeTileAt(CGPoint tileCoordinate);
+
+ /** returns the position in pixels of a given tile coordinate */
+ CGPoint positionAt(CGPoint tileCoordinate);
+
+ /** return the value for the specific property name */
+ const char *propertyNamed(const char *propertyName);
+
+ /** Creates the tiles */
+ void setupTiles();
+
+ /** CCTMXLayer doesn't support adding a CCSprite manually.
+ @warning addchild:z:tag: is not supported on CCTMXLayer. Instead of setTileGID:at:/tileAt:
+ */
+ CCNode * addChild(CCNode * child, int zOrder, int tag);
+ // super method
+ void removeChild(CCNode* child, bool cleanup);
+ void draw();
+ private:
+ CGPoint positionForIsoAt(CGPoint pos);
+ CGPoint positionForOrthoAt(CGPoint pos);
+ CGPoint positionForHexAt(CGPoint pos);
+
+ CGPoint calculateLayerOffset(CGPoint offset);
+
+ /* optimization methos */
+ CCSprite* appendTileForGID(unsigned int gid, CGPoint pos);
+ CCSprite* insertTileForGID(unsigned int gid, CGPoint pos);
+ CCSprite* updateTileForGID(unsigned int gid, CGPoint pos);
+
+ /* The layer recognizes some special properties, like cc_vertez */
+ void parseInternalProperties();
+ int vertexZForPos(CGPoint pos);
+
+ // index
+ unsigned int atlasIndexForExistantZ(unsigned int z);
+ unsigned int atlasIndexForNewZ(int z);
+ protected:
+ unsigned char m_cOpacity; // TMX Layer supports opacity
+
+ unsigned int m_uMinGID;
+ unsigned int m_uMaxGID;
+
+ // Only used when vertexZ is used
+ int m_nVertexZvalue;
+ bool m_bUseAutomaticVertexZ;
+ float m_fAlphaFuncValue;
+
+ // used for optimization
+ CCSprite *m_pReusedTile;
+ ccCArray *m_pAtlasIndexArray;
+ };
+
+}// namespace cocos2d
+#endif //__CCTMX_LAYER_H__
+
diff --git a/cocos2dx/include/CCTMXObjectGroup.h b/cocos2dx/include/CCTMXObjectGroup.h
index 8cc5e6ac24..de7c0e21dd 100644
--- a/cocos2dx/include/CCTMXObjectGroup.h
+++ b/cocos2dx/include/CCTMXObjectGroup.h
@@ -34,6 +34,7 @@ namespace cocos2d {
typedef std::map StringToStringDictionary;
typedef std::pair StringToStringPair;
+ /** only used in StringToStringDictionary, return "" if not found*/
const char * valueForKey(std::string key, StringToStringDictionary *dict);
/** CCTMXObjectGroup represents the TMX object group.
diff --git a/cocos2dx/include/CCTileMapAtlas.h b/cocos2dx/include/CCTileMapAtlas.h
index 57b805688e..8b9d0d7d2b 100644
--- a/cocos2dx/include/CCTileMapAtlas.h
+++ b/cocos2dx/include/CCTileMapAtlas.h
@@ -56,7 +56,7 @@ namespace cocos2d {
/** creates a CCTileMap with a tile file (atlas) with a map file and the width and height of each tile.
The tile file will be loaded using the TextureMgr.
*/
- CCTileMapAtlas * tileMapAtlasWithTileFile(const char *tile, const char *mapFile, int tileWidth, int tileHeight);
+ static CCTileMapAtlas * tileMapAtlasWithTileFile(const char *tile, const char *mapFile, int tileWidth, int tileHeight);
/** initializes a CCTileMap with a tile file (atlas) with a map file and the width and height of each tile.
The file will be loaded using the TextureMgr.
*/
diff --git a/cocos2dx/sprite_nodes/CCSpriteSheet.cpp b/cocos2dx/sprite_nodes/CCSpriteSheet.cpp
index 358c860f19..70414297af 100644
--- a/cocos2dx/sprite_nodes/CCSpriteSheet.cpp
+++ b/cocos2dx/sprite_nodes/CCSpriteSheet.cpp
@@ -596,4 +596,60 @@ void CCSpriteSheet::setTexture(CCTexture2D *texture)
{
m_pobTextureAtlas->setTexture(texture);
}
+
+// CCSpriteSheet Extension
+//implementation CCSpriteSheet (TMXTiledMapExtension)
+
+void CCSpriteSheet::addQuadFromSprite(CCSprite *sprite, unsigned int index)
+{
+ NSAssert( sprite != NULL, "Argument must be non-nil");
+ /// @todo NSAssert( [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->useSpriteSheetRender(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->updateTransform();
+}
+
+CCSpriteSheet * CCSpriteSheet::addSpriteWithoutQuad(CCSprite*child, unsigned int z, int aTag)
+{
+ NSAssert( child != NULL, "Argument must be non-nil");
+ /// @todo NSAssert( [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)
+ {
+ NSMutableArray::NSMutableArrayIterator iter;
+ for (iter = m_pobDescendants->begin(); iter != m_pobDescendants->end(); ++iter)
+ {
+ // fast dispatch
+ if (!(*iter) || (*iter)->getAtlasIndex() >=z)
+ {
+ break;
+ }
+ ++i;
+ }
+ }
+ m_pobDescendants->insertObjectAtIndex(child, i);
+
+ // IMPORTANT: Call super, and not self. Avoid adding it to the texture atlas array
+ __super::addChild(child, z, aTag);
+ return this;
+}
}//namespace cocos2d
diff --git a/cocos2dx/tileMap_parallax_nodes/CCTMXLayer.cpp b/cocos2dx/tileMap_parallax_nodes/CCTMXLayer.cpp
new file mode 100644
index 0000000000..a15a3db8b7
--- /dev/null
+++ b/cocos2dx/tileMap_parallax_nodes/CCTMXLayer.cpp
@@ -0,0 +1,632 @@
+/****************************************************************************
+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 "CCLayer.h"
+#include "CCTMXLayer.h"
+#include "CCTMXXMLParser.h"
+#include "CCSprite.h"
+#include "CCSpriteSheet.h"
+#include "CCTextureCache.h"
+#include "CGPointExtension.h"
+
+namespace cocos2d {
+
+
+ // CCTMXLayer - init & alloc & dealloc
+ CCTMXLayer * CCTMXLayer::layerWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
+ {
+ CCTMXLayer *pRet = new CCTMXLayer();
+ if (pRet->initWithTilesetInfo(tilesetInfo, layerInfo, mapInfo))
+ {
+ pRet->autorelease();
+ return pRet;
+ }
+ return NULL;
+ }
+ bool CCTMXLayer::initWithTilesetInfo(CCTMXTilesetInfo *tilesetInfo, CCTMXLayerInfo *layerInfo, CCTMXMapInfo *mapInfo)
+ {
+ // XXX: is 35% a good estimate ?
+ CGSize size = layerInfo->m_tLayerSize;
+ float totalNumberOfTiles = size.width * size.height;
+ float capacity = totalNumberOfTiles * 0.35f + 1; // 35 percent is occupied ?
+
+ CCTexture2D *texture = NULL;
+ if( tilesetInfo )
+ {
+ texture = CCTextureCache::sharedTextureCache()->addImage(tilesetInfo->m_sSourceImage.c_str());
+ }
+
+ if (__super::initWithTexture(texture, (unsigned int)capacity))
+ {
+ // layerInfo
+ m_sLayerName = layerInfo->m_sName;
+ m_tLayerSize = layerInfo->m_tLayerSize;
+ m_pTiles = layerInfo->m_pTiles;
+ m_uMinGID = layerInfo->m_uMinGID;
+ m_uMaxGID = layerInfo->m_uMaxGID;
+ m_cOpacity = layerInfo->m_cOpacity;
+ if (!layerInfo->m_pProperties && layerInfo->m_pProperties->size()>0)
+ {
+ StringToStringDictionary::iterator it;
+ for (it = layerInfo->m_pProperties->begin(); it != layerInfo->m_pProperties->end(); ++it)
+ {
+ m_pProperties->insert(*it);
+ }
+ }
+
+ // tilesetInfo
+ m_pTileSet = tilesetInfo;
+
+ // mapInfo
+ m_tMapTileSize = mapInfo->getTileSize();
+ m_nLayerOrientation = mapInfo->getOrientation();
+
+ // offset (after layer orientation is set);
+ CGPoint offset = this->calculateLayerOffset(layerInfo->m_tOffset);
+ this->setPosition(offset);
+
+ m_pAtlasIndexArray = ccCArrayNew((unsigned int)totalNumberOfTiles);
+
+ this->setContentSize(CGSizeMake(m_tLayerSize.width * m_tMapTileSize.width, m_tLayerSize.height * m_tMapTileSize.height));
+
+ m_bUseAutomaticVertexZ = false;
+ m_nVertexZvalue = 0;
+ m_fAlphaFuncValue = 0;
+ return true;
+ }
+ return false;
+ }
+ CCTMXLayer::CCTMXLayer()
+ :m_pTiles(NULL)
+ ,m_pTileSet(NULL)
+ ,m_pProperties(NULL)
+ ,m_pReusedTile(NULL)
+ ,m_pAtlasIndexArray(NULL)
+ {}
+ CCTMXLayer::~CCTMXLayer()
+ {
+ CCX_SAFE_RELEASE(m_pTileSet);
+ CCX_SAFE_RELEASE(m_pReusedTile);
+ if (m_pProperties)
+ {
+ m_pProperties->clear();
+ delete m_pProperties;
+ }
+
+ if( m_pAtlasIndexArray )
+ {
+ ccCArrayFree(m_pAtlasIndexArray);
+ m_pAtlasIndexArray = NULL;
+ }
+
+ if( m_pTiles )
+ {
+ delete [] m_pTiles;
+ m_pTiles = NULL;
+ }
+ }
+ void CCTMXLayer::releaseMap()
+ {
+ if( m_pTiles )
+ {
+ delete [] m_pTiles;
+ m_pTiles = NULL;
+ }
+
+ if( m_pAtlasIndexArray )
+ {
+ ccCArrayFree(m_pAtlasIndexArray);
+ m_pAtlasIndexArray = NULL;
+ }
+ }
+
+ // CCTMXLayer - setup Tiles
+ void CCTMXLayer::setupTiles()
+ {
+ // Optimization: quick hack that sets the image size on the tileset
+ m_pTileSet->m_tImageSize = m_pobTextureAtlas->getTexture()->getContentSize();
+
+ // By default all the tiles are aliased
+ // pros:
+ // - easier to render
+ // cons:
+ // - difficult to scale / rotate / etc.
+ m_pobTextureAtlas->getTexture()->setAliasTexParameters();
+
+// CFByteOrder o = CFByteOrderGetCurrent();
+
+ // Parse cocos2d properties
+ this->parseInternalProperties();
+
+ for( unsigned int y=0; y < m_tLayerSize.height; y++ )
+ {
+ for( unsigned int x=0; x < m_tLayerSize.width; x++ )
+ {
+ unsigned int pos = x + (unsigned int)m_tLayerSize.width * y;
+ unsigned int gid = m_pTiles[ pos ];
+
+ // gid are stored in little endian.
+ // if host is big endian, then swap
+ //if( o == CFByteOrderBigEndian )
+ // gid = CFSwapInt32( gid );
+ /* We support little endian.*/
+
+ // XXX: gid == 0 --> empty tile
+ if( gid != 0 )
+ {
+ this->appendTileForGID(gid, ccp((float)x, (float)y));
+
+ // Optimization: update min and max GID rendered by the layer
+ m_uMinGID = MIN(gid, m_uMinGID);
+ m_uMaxGID = MAX(gid, m_uMaxGID);
+ }
+ }
+ }
+
+ NSAssert( m_uMaxGID >= m_pTileSet->m_uFirstGid &&
+ m_uMinGID >= m_pTileSet->m_uFirstGid, "TMX: Only 1 tilset per layer is supported");
+ }
+
+ // CCTMXLayer - Properties
+ const char *CCTMXLayer::propertyNamed(const char *propertyName)
+ {
+ return valueForKey(propertyName, m_pProperties);
+ }
+ void CCTMXLayer::parseInternalProperties()
+ {
+ // if cc_vertex=automatic, then tiles will be rendered using vertexz
+
+ std::string vertexz = propertyNamed("cc_vertexz");
+ if( vertexz != "" )
+ {
+ if( vertexz == "automatic" )
+ {
+ m_bUseAutomaticVertexZ = true;
+ }
+ else
+ {
+ m_nVertexZvalue = atoi(vertexz.c_str());
+ }
+ }
+
+ std::string alphaFuncVal = propertyNamed("cc_alpha_func");
+ m_fAlphaFuncValue = (float)atof(alphaFuncVal.c_str());
+ }
+
+ // CCTMXLayer - obtaining tiles/gids
+ CCSprite * CCTMXLayer::tileAt(CGPoint pos)
+ {
+ NSAssert( pos.x < m_tLayerSize.width && pos.y < m_tLayerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
+ NSAssert( m_pTiles && m_pAtlasIndexArray, "TMXLayer: the tiles map has been released");
+
+ CCSprite *tile = NULL;
+ unsigned int gid = this->tileGIDAt(pos);
+
+ // if GID == 0, then no tile is present
+ if( gid )
+ {
+ int z = (int)(pos.x + pos.y * m_tLayerSize.width);
+ tile = (CCSprite*) this->getChildByTag(z);
+
+ // tile not created yet. create it
+ if( ! tile )
+ {
+ CGRect rect = m_pTileSet->rectForGID(gid);
+ tile = new CCSprite();
+ tile->initWithSpriteSheet(this, rect);
+ tile->setPosition(positionAt(pos));
+ tile->setVertexZ((float)vertexZForPos(pos));
+ tile->setAnchorPoint(CGPointZero);
+ tile->setOpacity(m_cOpacity);
+
+ unsigned int indexForZ = atlasIndexForExistantZ(z);
+ this->addSpriteWithoutQuad(tile, indexForZ, z);
+ tile->release();
+ }
+ }
+ return tile;
+ }
+ unsigned int CCTMXLayer::tileGIDAt(CGPoint pos)
+ {
+ NSAssert( pos.x < m_tLayerSize.width && pos.y < m_tLayerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
+ NSAssert( m_pTiles && m_pAtlasIndexArray, "TMXLayer: the tiles map has been released");
+
+ int idx = (int)(pos.x + pos.y * m_tLayerSize.width);
+ return m_pTiles[ idx ];
+ }
+
+ // CCTMXLayer - adding helper methods
+ CCSprite * CCTMXLayer::insertTileForGID(unsigned int gid, CGPoint pos)
+ {
+ CGRect rect = m_pTileSet->rectForGID(gid);
+
+ int z = (int)(pos.x + pos.y * m_tLayerSize.width);
+
+ if( ! m_pReusedTile )
+ {
+ m_pReusedTile = new CCSprite();
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+ else
+ {
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+ m_pReusedTile->setPosition(positionAt(pos));
+ m_pReusedTile->setVertexZ((float)vertexZForPos(pos));
+ m_pReusedTile->setAnchorPoint(CGPointZero);
+ m_pReusedTile->setOpacity(m_cOpacity);
+
+ // get atlas index
+ unsigned int indexForZ = atlasIndexForNewZ(z);
+
+ // Optimization: add the quad without adding a child
+ this->addQuadFromSprite(m_pReusedTile, indexForZ);
+
+ // insert it into the local atlasindex array
+ ccCArrayInsertValueAtIndex(m_pAtlasIndexArray, (void*)z, indexForZ);
+
+ // update possible children
+ if (m_pChildren && m_pChildren->count()>0)
+ {
+ NSMutableArray::NSMutableArrayIterator it;
+ CCSprite *pSprite = NULL;
+ for (it = m_pChildren->begin(); it != m_pChildren->end(); ++it)
+ {
+ pSprite = (CCSprite*)(*it);
+ if (pSprite)
+ {
+ unsigned int ai = pSprite->getAtlasIndex();
+ if ( ai >= indexForZ )
+ {
+ pSprite->setAtlasIndex(ai+1);
+ }
+ }
+ }
+ }
+ m_pTiles[z] = gid;
+ return m_pReusedTile;
+ }
+ CCSprite * CCTMXLayer::updateTileForGID(unsigned int gid, CGPoint pos)
+ {
+ CGRect rect = m_pTileSet->rectForGID(gid);
+ int z = (int)(pos.x + pos.y * m_tLayerSize.width);
+
+ if( ! m_pReusedTile )
+ {
+ m_pReusedTile = new CCSprite();
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+ else
+ {
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+
+ m_pReusedTile->setPosition(positionAt(pos));
+ m_pReusedTile->setVertexZ((float)vertexZForPos(pos));
+ m_pReusedTile->setAnchorPoint(CGPointZero);
+ m_pReusedTile->setOpacity(m_cOpacity);
+
+ // get atlas index
+ unsigned int indexForZ = atlasIndexForExistantZ(z);
+ m_pReusedTile->setAtlasIndex(indexForZ);
+ m_pReusedTile->updateTransform();
+ m_pTiles[z] = gid;
+
+ return m_pReusedTile;
+ }
+
+ // used only when parsing the map. useless after the map was parsed
+ // since lot's of assumptions are no longer true
+ CCSprite * CCTMXLayer::appendTileForGID(unsigned int gid, CGPoint pos)
+ {
+ CGRect rect = m_pTileSet->rectForGID(gid);
+
+ int z = (int)(pos.x + pos.y * m_tLayerSize.width);
+
+ if( ! m_pReusedTile )
+ {
+ m_pReusedTile = new CCSprite();
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+ else
+ {
+ m_pReusedTile->initWithSpriteSheet(this, rect);
+ }
+
+ m_pReusedTile->setPosition(positionAt(pos));
+ m_pReusedTile->setVertexZ((float)vertexZForPos(pos));
+ m_pReusedTile->setAnchorPoint(CGPointZero);
+ m_pReusedTile->setOpacity(m_cOpacity);
+
+ // optimization:
+ // The difference between appendTileForGID and insertTileforGID is that append is faster, since
+ // it appends the tile at the end of the texture atlas
+ unsigned int indexForZ = m_pAtlasIndexArray->num;
+
+ // don't add it using the "standard" way.
+ addQuadFromSprite(m_pReusedTile, indexForZ);
+
+ // append should be after addQuadFromSprite since it modifies the quantity values
+ ccCArrayInsertValueAtIndex(m_pAtlasIndexArray, (void*)z, indexForZ);
+
+ return m_pReusedTile;
+ }
+
+ // CCTMXLayer - atlasIndex and Z
+ int compareInts(const void * a, const void * b)
+ {
+ return ( *(int*)a - *(int*)b );
+ }
+ unsigned int CCTMXLayer::atlasIndexForExistantZ(unsigned int z)
+ {
+ int key=z;
+ int *item = (int*)bsearch((void*)&key, (void*)&m_pAtlasIndexArray->arr[0], m_pAtlasIndexArray->num, sizeof(void*), compareInts);
+
+ NSAssert( item, "TMX atlas index not found. Shall not happen");
+
+ int index = ((int)item - (int)m_pAtlasIndexArray->arr) / sizeof(void*);
+ return index;
+ }
+ unsigned int CCTMXLayer::atlasIndexForNewZ(int z)
+ {
+ // XXX: This can be improved with a sort of binary search
+ unsigned int i=0;
+ for( i=0; i< m_pAtlasIndexArray->num ; i++)
+ {
+ int val = (int) m_pAtlasIndexArray->arr[i];
+ if( z < val )
+ break;
+ }
+ return i;
+ }
+
+ // CCTMXLayer - adding / remove tiles
+ void CCTMXLayer::setTileGID(unsigned int gid, CGPoint pos)
+ {
+ NSAssert( pos.x < m_tLayerSize.width && pos.y < m_tLayerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
+ NSAssert( m_pTiles && m_pAtlasIndexArray, "TMXLayer: the tiles map has been released");
+
+ unsigned int currentGID = tileGIDAt(pos);
+
+ if( currentGID != gid )
+ {
+ // setting gid=0 is equal to remove the tile
+ if( gid == 0 )
+ {
+ removeTileAt(pos);
+ }
+
+ // empty tile. create a new one
+ else if( currentGID == 0 )
+ {
+ insertTileForGID(gid, pos);
+ }
+
+ // modifying an existing tile with a non-empty tile
+ else
+ {
+ unsigned int z = (unsigned int)(pos.x + pos.y * m_tLayerSize.width);
+ CCSprite *sprite = (CCSprite*)getChildByTag(z);
+ if( sprite )
+ {
+ CGRect rect = m_pTileSet->rectForGID(gid);
+ sprite->setTextureRect(rect);
+ m_pTiles[z] = gid;
+ }
+ else
+ {
+ updateTileForGID(gid, pos);
+ }
+ }
+ }
+ }
+ CCNode * CCTMXLayer::addChild(CCNode * child, int zOrder, int tag)
+ {
+ NSAssert(0, "addChild: is not supported on CCTMXLayer. Instead use setTileGID:at:/tileAt:");
+ return NULL;
+ }
+ void CCTMXLayer::removeChild(CCNode* node, bool cleanup)
+ {
+ CCSprite *sprite = (CCSprite*)node;
+ // allows removing nil objects
+ if( ! sprite )
+ return;
+
+ NSAssert( m_pChildren->containsObject(sprite), "Tile does not belong to TMXLayer");
+
+ unsigned int atlasIndex = sprite->getAtlasIndex();
+ unsigned int zz = (unsigned int) m_pAtlasIndexArray->arr[atlasIndex];
+ m_pTiles[zz] = 0;
+ ccCArrayRemoveValueAtIndex(m_pAtlasIndexArray, atlasIndex);
+ __super::removeChild(sprite, cleanup);
+ }
+ void CCTMXLayer::removeTileAt(CGPoint pos)
+ {
+ NSAssert( pos.x < m_tLayerSize.width && pos.y < m_tLayerSize.height && pos.x >=0 && pos.y >=0, "TMXLayer: invalid position");
+ NSAssert( m_pTiles && m_pAtlasIndexArray, "TMXLayer: the tiles map has been released");
+
+ unsigned int gid = tileGIDAt(pos);
+
+ if( gid )
+ {
+ unsigned int z = (unsigned int)(pos.x + pos.y * m_tLayerSize.width);
+ unsigned atlasIndex = atlasIndexForExistantZ(z);
+
+ // remove tile from GID map
+ m_pTiles[z] = 0;
+
+ // remove tile from atlas position array
+ ccCArrayRemoveValueAtIndex(m_pAtlasIndexArray, atlasIndex);
+
+ // remove it from sprites and/or texture atlas
+ CCSprite *sprite = (CCSprite*)getChildByTag(z);
+ if( sprite )
+ {
+ __super::removeChild(sprite, true);
+ }
+ else
+ {
+ m_pobTextureAtlas->removeQuadAtIndex(atlasIndex);
+
+ // update possible children
+ if (m_pChildren && m_pChildren->count()>0)
+ {
+ NSMutableArray::NSMutableArrayIterator it;
+ CCSprite *pSprite = NULL;
+ for (it = m_pChildren->begin(); it != m_pChildren->end(); ++it)
+ {
+ pSprite = (CCSprite*)(*it);
+ if (pSprite)
+ {
+ unsigned int ai = pSprite->getAtlasIndex();
+ if ( ai >= atlasIndex )
+ {
+ pSprite->setAtlasIndex(ai-1);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /** Possible oritentations of the TMX map */
+ enum
+ {
+ /** Orthogonal orientation */
+ CCTMXOrientationOrtho,
+
+ /** Hexagonal orientation */
+ CCTMXOrientationHex,
+
+ /** Isometric orientation */
+ CCTMXOrientationIso,
+ };/// @todo to be deleted
+ //CCTMXLayer - obtaining positions, offset
+ CGPoint CCTMXLayer::calculateLayerOffset(CGPoint pos)
+ {
+ CGPoint ret = CGPointZero;
+ switch( m_nLayerOrientation )
+ {
+ case CCTMXOrientationOrtho:
+ ret = ccp( pos.x * m_tMapTileSize.width, -pos.y *m_tMapTileSize.height);
+ break;
+ case CCTMXOrientationIso:
+ ret = ccp( (m_tMapTileSize.width /2) * (pos.x - pos.y),
+ (m_tMapTileSize.height /2 ) * (-pos.x - pos.y) );
+ break;
+ case CCTMXOrientationHex:
+ NSAssert(CGPoint::CGPointEqualToPoint(pos, CGPointZero), "offset for hexagonal map not implemented yet");
+ break;
+ }
+ return ret;
+ }
+ CGPoint CCTMXLayer::positionAt(CGPoint pos)
+ {
+ CGPoint ret = CGPointZero;
+ switch( m_nLayerOrientation )
+ {
+ case CCTMXOrientationOrtho:
+ ret = positionForOrthoAt(pos);
+ break;
+ case CCTMXOrientationIso:
+ ret = positionForIsoAt(pos);
+ break;
+ case CCTMXOrientationHex:
+ ret = positionForHexAt(pos);
+ break;
+ }
+ return ret;
+ }
+ CGPoint CCTMXLayer::positionForOrthoAt(CGPoint pos)
+ {
+ float x = pos.x * m_tMapTileSize.width + 0.49f;
+ float y = (m_tLayerSize.height - pos.y - 1) * m_tMapTileSize.height + 0.49f;
+ return ccp(x,y);
+ }
+ CGPoint CCTMXLayer::positionForIsoAt(CGPoint pos)
+ {
+ float x = m_tMapTileSize.width /2 * ( m_tLayerSize.width + pos.x - pos.y - 1) + 0.49f;
+ float y = m_tMapTileSize.height /2 * (( m_tLayerSize.height * 2 - pos.x - pos.y) - 2) + 0.49f;
+ return ccp(x, y);
+ }
+ CGPoint CCTMXLayer::positionForHexAt(CGPoint pos)
+ {
+ float diffY = 0;
+ if( (int)pos.x % 2 == 1 )
+ diffY = -m_tMapTileSize.height/2 ;
+
+ float x = pos.x * m_tMapTileSize.width*3/4 + 0.49f;
+ float y = (m_tLayerSize.height - pos.y - 1) * m_tMapTileSize.height + diffY + 0.49f;
+ return ccp(x,y);
+ }
+ int CCTMXLayer::vertexZForPos(CGPoint pos)
+ {
+ int ret = 0;
+ unsigned int maxVal = 0;
+ if( m_bUseAutomaticVertexZ )
+ {
+ switch( m_nLayerOrientation )
+ {
+ case CCTMXOrientationIso:
+ maxVal = (unsigned int)(m_tLayerSize.width + m_tLayerSize.height);
+ ret = (int)(-(maxVal - (pos.x + pos.y)));
+ break;
+ case CCTMXOrientationOrtho:
+ ret = (int)(-(m_tLayerSize.height-pos.y));
+ break;
+ case CCTMXOrientationHex:
+ NSAssert(0, "TMX Hexa zOrder not supported");
+ break;
+ default:
+ NSAssert(0, "TMX invalid value");
+ break;
+ }
+ }
+ else
+ {
+ ret = m_nVertexZvalue;
+ }
+ return ret;
+ }
+
+ // CCTMXLayer - draw
+ void CCTMXLayer::draw()
+ {
+ if( m_bUseAutomaticVertexZ )
+ {
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER, m_fAlphaFuncValue);
+ }
+
+ __super::draw();
+
+ if( m_bUseAutomaticVertexZ )
+ {
+ glDisable(GL_ALPHA_TEST);
+ }
+ }
+
+
+}// namespace cocos2d
+
diff --git a/cocos2dx/tileMap_parallax_nodes/CCTileMapAtlas.cpp b/cocos2dx/tileMap_parallax_nodes/CCTileMapAtlas.cpp
index 5347c2a01a..8cee1f2bbc 100644
--- a/cocos2dx/tileMap_parallax_nodes/CCTileMapAtlas.cpp
+++ b/cocos2dx/tileMap_parallax_nodes/CCTileMapAtlas.cpp
@@ -33,7 +33,7 @@ namespace cocos2d {
CCTileMapAtlas * CCTileMapAtlas::tileMapAtlasWithTileFile(const char *tile, const char *mapFile, int tileWidth, int tileHeight)
{
CCTileMapAtlas *pRet = new CCTileMapAtlas();
- if (initWithTileFile(tile, mapFile, tileWidth, tileHeight))
+ if (pRet->initWithTileFile(tile, mapFile, tileWidth, tileHeight))
{
pRet->autorelease();
return pRet;