diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj b/build/cocos2d_libs.xcodeproj/project.pbxproj index 2f28263747..abbf67adac 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj @@ -1775,6 +1775,14 @@ B3AF01A31842FBA400A98B85 /* b2MotorJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = B3AF019F1842FBA400A98B85 /* b2MotorJoint.h */; }; B3B12A5A17E7F44000026B4A /* libchipmunk Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A03F2CB81780BD04006731B9 /* libchipmunk Mac.a */; }; B3B12A5B17E7F45C00026B4A /* libchipmunk iOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A07A4F3B178387670073F6A7 /* libchipmunk iOS.a */; }; + C0940CAC19419BDA00B8BB48 /* CCTMXLayer2.h in Headers */ = {isa = PBXBuildFile; fileRef = C0940CA819419BDA00B8BB48 /* CCTMXLayer2.h */; }; + C0940CAD19419BDA00B8BB48 /* CCTMXLayer2.h in Headers */ = {isa = PBXBuildFile; fileRef = C0940CA819419BDA00B8BB48 /* CCTMXLayer2.h */; }; + C0940CAE19419BDA00B8BB48 /* CCTMXTiledMap2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0940CA919419BDA00B8BB48 /* CCTMXTiledMap2.cpp */; }; + C0940CAF19419BDA00B8BB48 /* CCTMXTiledMap2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0940CA919419BDA00B8BB48 /* CCTMXTiledMap2.cpp */; }; + C0940CB019419BDA00B8BB48 /* CCTMXTiledMap2.h in Headers */ = {isa = PBXBuildFile; fileRef = C0940CAA19419BDA00B8BB48 /* CCTMXTiledMap2.h */; }; + C0940CB119419BDA00B8BB48 /* CCTMXTiledMap2.h in Headers */ = {isa = PBXBuildFile; fileRef = C0940CAA19419BDA00B8BB48 /* CCTMXTiledMap2.h */; }; + C0940CB219419BDA00B8BB48 /* CCTMXLayer2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0940CAB19419BDA00B8BB48 /* CCTMXLayer2.cpp */; }; + C0940CB319419BDA00B8BB48 /* CCTMXLayer2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0940CAB19419BDA00B8BB48 /* CCTMXLayer2.cpp */; }; ED9C6A9418599AD8000A5232 /* CCNodeGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED9C6A9218599AD8000A5232 /* CCNodeGrid.cpp */; }; ED9C6A9518599AD8000A5232 /* CCNodeGrid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ED9C6A9218599AD8000A5232 /* CCNodeGrid.cpp */; }; ED9C6A9618599AD8000A5232 /* CCNodeGrid.h in Headers */ = {isa = PBXBuildFile; fileRef = ED9C6A9318599AD8000A5232 /* CCNodeGrid.h */; }; @@ -2810,6 +2818,10 @@ B375104F1823AC7B00B3BA6A /* CCPhysicsWorldInfo_chipmunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCPhysicsWorldInfo_chipmunk.h; sourceTree = ""; }; B3AF019E1842FBA400A98B85 /* b2MotorJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = b2MotorJoint.cpp; sourceTree = ""; }; B3AF019F1842FBA400A98B85 /* b2MotorJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = b2MotorJoint.h; sourceTree = ""; }; + C0940CA819419BDA00B8BB48 /* CCTMXLayer2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCTMXLayer2.h; sourceTree = ""; }; + C0940CA919419BDA00B8BB48 /* CCTMXTiledMap2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCTMXTiledMap2.cpp; sourceTree = ""; }; + C0940CAA19419BDA00B8BB48 /* CCTMXTiledMap2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCTMXTiledMap2.h; sourceTree = ""; }; + C0940CAB19419BDA00B8BB48 /* CCTMXLayer2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CCTMXLayer2.cpp; sourceTree = ""; }; ED9C6A9218599AD8000A5232 /* CCNodeGrid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = CCNodeGrid.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; ED9C6A9318599AD8000A5232 /* CCNodeGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCNodeGrid.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -3307,6 +3319,10 @@ 1A5702DF180BCE610088DEC7 /* tilemap-parallax-nodes */ = { isa = PBXGroup; children = ( + C0940CA819419BDA00B8BB48 /* CCTMXLayer2.h */, + C0940CAB19419BDA00B8BB48 /* CCTMXLayer2.cpp */, + C0940CA919419BDA00B8BB48 /* CCTMXTiledMap2.cpp */, + C0940CAA19419BDA00B8BB48 /* CCTMXTiledMap2.h */, 1A5702FE180BCE890088DEC7 /* CCParallaxNode.cpp */, 1A5702FF180BCE890088DEC7 /* CCParallaxNode.h */, 1A5702E0180BCE750088DEC7 /* CCTileMapAtlas.cpp */, @@ -4998,6 +5014,7 @@ 50ABBED51925AB6F00A911A9 /* utlist.h in Headers */, 50FCEBAD18C72017004AD434 /* PageViewReader.h in Headers */, 1A5702F4180BCE750088DEC7 /* CCTMXObjectGroup.h in Headers */, + C0940CB019419BDA00B8BB48 /* CCTMXTiledMap2.h in Headers */, 50ABBDAF1925AB4100A911A9 /* CCRenderer.h in Headers */, 1A5702F8180BCE750088DEC7 /* CCTMXTiledMap.h in Headers */, 5034CA21191D591100CE6051 /* ccShader_PositionTextureColorAlphaTest.frag in Headers */, @@ -5114,6 +5131,7 @@ 1AAF536C180E3374000584C8 /* HttpClient.h in Headers */, 50ABBD9D1925AB4100A911A9 /* ccGLStateCache.h in Headers */, 50ABBEB91925AB6F00A911A9 /* ccUTF8.h in Headers */, + C0940CAC19419BDA00B8BB48 /* CCTMXLayer2.h in Headers */, 1AAF536E180E3374000584C8 /* HttpRequest.h in Headers */, 29CB8F551929D7A900C841D6 /* UIScrollInterface.h in Headers */, 1AAF5370180E3374000584C8 /* HttpResponse.h in Headers */, @@ -5467,6 +5485,7 @@ 1A570230180BCC1A0088DEC7 /* CCParticleSystemQuad.h in Headers */, 5034CA2C191D591100CE6051 /* ccShader_PositionTextureA8Color.vert in Headers */, 50ABBE981925AB6F00A911A9 /* CCProtocols.h in Headers */, + C0940CB119419BDA00B8BB48 /* CCTMXTiledMap2.h in Headers */, 2905FA8B18CF08D100240AA3 /* UITextField.h in Headers */, 50FCEBA618C72017004AD434 /* ListViewReader.h in Headers */, 50ABBD431925AB0000A911A9 /* CCMathBase.h in Headers */, @@ -5478,6 +5497,7 @@ 50ABBE701925AB6F00A911A9 /* CCEventListenerKeyboard.h in Headers */, 1A57028D180BCC900088DEC7 /* CCSpriteFrameCache.h in Headers */, 1A570295180BCCAB0088DEC7 /* CCAnimation.h in Headers */, + C0940CAD19419BDA00B8BB48 /* CCTMXLayer2.h in Headers */, 50ABBDB81925AB4100A911A9 /* CCTexture2D.h in Headers */, 50ABBE341925AB6F00A911A9 /* CCConfiguration.h in Headers */, 1A570299180BCCAB0088DEC7 /* CCAnimationCache.h in Headers */, @@ -6121,6 +6141,7 @@ 50ABBD831925AB4100A911A9 /* CCBatchCommand.cpp in Sources */, 1A5701C7180BCB5A0088DEC7 /* CCLabelTextFormatter.cpp in Sources */, 1A5701CB180BCB5A0088DEC7 /* CCLabelTTF.cpp in Sources */, + C0940CAE19419BDA00B8BB48 /* CCTMXTiledMap2.cpp in Sources */, 50ABBE711925AB6F00A911A9 /* CCEventListenerMouse.cpp in Sources */, 1A5701DE180BCB8C0088DEC7 /* CCLayer.cpp in Sources */, 1A5701E2180BCB8C0088DEC7 /* CCScene.cpp in Sources */, @@ -6208,6 +6229,7 @@ 1AD71DE5180E26E600808F54 /* CCMenuItemImageLoader.cpp in Sources */, 50ABBD8B1925AB4100A911A9 /* CCGLProgram.cpp in Sources */, 1AD71DE9180E26E600808F54 /* CCMenuItemLoader.cpp in Sources */, + C0940CB219419BDA00B8BB48 /* CCTMXLayer2.cpp in Sources */, 50ABBDA31925AB4100A911A9 /* CCQuadCommand.cpp in Sources */, 2905FA6A18CF08D100240AA3 /* UIPageView.cpp in Sources */, B29594C61926D61F003EEF37 /* CCObjLoader.cpp in Sources */, @@ -6550,6 +6572,7 @@ 503DD8E21926736A00CD74DD /* CCCommon.mm in Sources */, 1A5701A2180BCB590088DEC7 /* CCFontAtlas.cpp in Sources */, 50ABC00E1926664800A911A9 /* CCFileUtils.cpp in Sources */, + C0940CB319419BDA00B8BB48 /* CCTMXLayer2.cpp in Sources */, 50ABBE241925AB6F00A911A9 /* base64.cpp in Sources */, 1A5701A6180BCB590088DEC7 /* CCFontAtlasCache.cpp in Sources */, 1A5701B2180BCB590088DEC7 /* CCFontFNT.cpp in Sources */, @@ -6733,6 +6756,7 @@ 50ABC0001926664800A911A9 /* CCFileUtilsApple.mm in Sources */, 2905FA7918CF08D100240AA3 /* UISlider.cpp in Sources */, 1A8C59A4180E930E00EF57C3 /* CCArmatureAnimation.cpp in Sources */, + C0940CAF19419BDA00B8BB48 /* CCTMXTiledMap2.cpp in Sources */, 1A8C59A8180E930E00EF57C3 /* CCArmatureDataManager.cpp in Sources */, 2905FA8918CF08D100240AA3 /* UITextField.cpp in Sources */, 1A8C59AC180E930E00EF57C3 /* CCArmatureDefine.cpp in Sources */, diff --git a/cocos/2d/CCTMXLayer2.cpp b/cocos/2d/CCTMXLayer2.cpp new file mode 100644 index 0000000000..cb9c798755 --- /dev/null +++ b/cocos/2d/CCTMXLayer2.cpp @@ -0,0 +1,805 @@ +/**************************************************************************** +Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2010-2012 cocos2d-x.org +Copyright (c) 2011 Zynga Inc. +Copyright (c) 2013-2014 Chukong Technologies Inc. + +Copyright (c) 2011 HKASoftware + +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. +****************************************************************************/ + +/* + Original rewrite of TMXLayer was based on HKTMXTiledMap by HKASoftware http://hkasoftware.com + Further info: http://www.cocos2d-iphone.org/forums/topic/hktmxtiledmap/ + + It was rewritten again, and only a small part of the original HK ideas/code remains in this implementation + + */ +#include "CCTMXLayer2.h" +#include "CCTMXXMLParser.h" +#include "CCTMXTiledMap.h" +#include "CCSprite.h" +#include "CCTextureCache.h" +#include "CCGLProgramCache.h" +#include "CCGLProgram.h" +#include "ccCArray.h" +#include "CCDirector.h" +#include "CCConfiguration.h" +#include "renderer/CCRenderer.h" +#include "deprecated/CCString.h" + +NS_CC_BEGIN + +namespace +{ + static const int MAX_QUADS_COUNT = 65536 / 6; +} + +// TMXLayer2 - init & alloc & dealloc + +TMXLayer2 * TMXLayer2::create(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo) +{ + TMXLayer2 *ret = new TMXLayer2(); + if (ret->initWithTilesetInfo(tilesetInfo, layerInfo, mapInfo)) + { + ret->autorelease(); + return ret; + } + return nullptr; +} +bool TMXLayer2::initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo) +{ + + if( tilesetInfo ) + { + _texture = Director::getInstance()->getTextureCache()->addImage(tilesetInfo->_sourceImage); + _texture->retain(); + } + + // layerInfo + _layerName = layerInfo->_name; + _layerSize = layerInfo->_layerSize; + _tiles = layerInfo->_tiles; + setOpacity( layerInfo->_opacity ); + setProperties(layerInfo->getProperties()); + + // tilesetInfo + _tileSet = tilesetInfo; + CC_SAFE_RETAIN(_tileSet); + + // mapInfo + _mapTileSize = mapInfo->getTileSize(); + _layerOrientation = mapInfo->getOrientation(); + + // offset (after layer orientation is set); + Point offset = this->calculateLayerOffset(layerInfo->_offset); + this->setPosition(CC_POINT_PIXELS_TO_POINTS(offset)); + + this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(Size(_layerSize.width * _mapTileSize.width, _layerSize.height * _mapTileSize.height))); + + this->tileToNodeTransform(); + + // shader, and other stuff + setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR)); + + _useAutomaticVertexZ = false; + _vertexZvalue = 0; + + return true; +} + +TMXLayer2::TMXLayer2() +:_layerName("") +,_layerSize(Size::ZERO) +,_mapTileSize(Size::ZERO) +,_tiles(nullptr) +,_tileSet(nullptr) +,_layerOrientation(TMXOrientationOrtho) +,_texture(nullptr) +,_reusedTile(nullptr) +,_previousRect(0,0,0,0) +,_verticesToDraw(0) +,_vertexZvalue(0) +,_useAutomaticVertexZ(false) +,_quads(nullptr) +,_indices(nullptr) +,_numQuads(0) +{} + +TMXLayer2::~TMXLayer2() +{ + CC_SAFE_RELEASE(_tileSet); + CC_SAFE_RELEASE(_texture); + CC_SAFE_DELETE_ARRAY(_tiles); + CC_SAFE_FREE(_quads); + CC_SAFE_FREE(_indices); +} + +void TMXLayer2::draw(Renderer *renderer, const Mat4& transform, uint32_t flags) +{ + _customCommand.init(_globalZOrder); + _customCommand.func = CC_CALLBACK_0(TMXLayer2::onDraw, this, transform, flags); + renderer->addCommand(&_customCommand); +} + +void TMXLayer2::onDraw(const Mat4 &transform, bool transformUpdated) +{ + GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_TEX_COORD); + GL::bindTexture2D( _texture->getName() ); + + + // tex coords + indices + glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); + + + if( transformUpdated ) { + + Size s = Director::getInstance()->getWinSize(); + auto rect = Rect(0, 0, s.width, s.height); + + Mat4 inv = transform; + inv.inverse(); + rect = RectApplyTransform(rect, inv); + + if( !rect.equals(_previousRect) ) + { + if (Configuration::getInstance()->supportsShareableVAO()) + { + V2F_T2F_Quad* quads = (V2F_T2F_Quad*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + GLushort* indices = (GLushort *)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY); + _verticesToDraw = updateTiles(rect, quads, indices); + glUnmapBuffer(GL_ARRAY_BUFFER); + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + } + else + { + _verticesToDraw = updateTiles(rect, nullptr, nullptr); + + if (_quads != nullptr && _indices != nullptr && _verticesToDraw > 0) + { + glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _numQuads , _quads, GL_DYNAMIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _numQuads * 6 , _indices, GL_STATIC_DRAW); + } + } + + _previousRect = rect; + } + + // don't draw more than 65535 vertices since we are using GL_UNSIGNED_SHORT for indices + _verticesToDraw = std::min(_verticesToDraw, 65535); + } + + if(_verticesToDraw > 0) { + + getGLProgram()->use(); + getGLProgram()->setUniformsForBuiltins(_modelViewTransform); + + // vertices + glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_T2F), (GLvoid*) offsetof(V2F_T2F, vertices)); + + // tex coords + glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORDS, 2, GL_FLOAT, GL_FALSE, sizeof(V2F_T2F), (GLvoid*) offsetof(V2F_T2F, texCoords)); + + // color + glVertexAttrib4f(GLProgram::VERTEX_ATTRIB_COLOR, _displayedColor.r/255.0f, _displayedColor.g/255.0f, _displayedColor.b/255.0f, _displayedOpacity/255.0f); + + glDrawElements(GL_TRIANGLES, _verticesToDraw, GL_UNSIGNED_SHORT, nullptr); + CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,_verticesToDraw); + } + + // cleanup + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +int TMXLayer2::updateTiles(const Rect& culledRect, V2F_T2F_Quad *quads, GLushort *indices) +{ + int tilesUsed = 0; + + Rect visibleTiles = culledRect; + Size mapTileSize = CC_SIZE_PIXELS_TO_POINTS(_mapTileSize); + Size tileSize = CC_SIZE_PIXELS_TO_POINTS(_tileSet->_tileSize); + Mat4 nodeToTile = _tileToNodeTransform; + nodeToTile.inverse(); + //transform to tile + visibleTiles = RectApplyTransform(visibleTiles, nodeToTile); + + visibleTiles.origin.x = floor(visibleTiles.origin.x); + visibleTiles.origin.y = floor(visibleTiles.origin.y); + visibleTiles.size.width = ceil(visibleTiles.size.width); + visibleTiles.size.height = ceil(visibleTiles.size.height); + + V2F_T2F_Quad* quadsTmp = quads; + GLushort* indicesTmp = indices; + // doesn't support VBO + if (quadsTmp == nullptr) + { + int quadsNeed = std::min(static_cast((visibleTiles.size.width + 1) * (visibleTiles.size.height + 1)), MAX_QUADS_COUNT); + if (_numQuads < quadsNeed) + { + _numQuads = quadsNeed; + _quads = (V2F_T2F_Quad*)realloc(_quads, _numQuads * sizeof(V2F_T2F_Quad)); + _indices = (GLushort*)realloc(_indices, _numQuads * 6 * sizeof(GLushort)); + } + + quadsTmp = _quads; + indicesTmp = _indices; + } + + int rows_per_tile = ceil(tileSize.height / mapTileSize.height) - 1; + + Size texSize = _tileSet->_imageSize; + for (int y = visibleTiles.origin.y - rows_per_tile; y <= visibleTiles.origin.y + visibleTiles.size.height; ++y) + { + if(y<0 || y >= _layerSize.height) + continue; + for (int x = visibleTiles.origin.x; x <= visibleTiles.origin.x + visibleTiles.size.width; x++) + { + if(x<0 || x >= _layerSize.width) + continue; + + int tileGID = _tiles[x + y * (int)_layerSize.width]; + + // GID==0 empty tile + if(tileGID!=0) { + + V2F_T2F_Quad *quad = &quadsTmp[tilesUsed]; + + Vec3 nodePos(static_cast(x), static_cast(y), 0); + _tileToNodeTransform.transformPoint(&nodePos); + + float left, right, top, bottom; + + // vertices + left = nodePos.x; + right = nodePos.x + tileSize.width; + bottom = nodePos.y + tileSize.height; + top = nodePos.y; + + if(tileGID & kTMXTileVerticalFlag) + std::swap(top, bottom); + if(tileGID & kTMXTileHorizontalFlag) + std::swap(left, right); + + if(tileGID & kTMXTileDiagonalFlag) + { + // XXX: not working correcly + quad->bl.vertices.x = left; + quad->bl.vertices.y = bottom; + quad->br.vertices.x = left; + quad->br.vertices.y = top; + quad->tl.vertices.x = right; + quad->tl.vertices.y = bottom; + quad->tr.vertices.x = right; + quad->tr.vertices.y = top; + } + else + { + quad->bl.vertices.x = left; + quad->bl.vertices.y = bottom; + quad->br.vertices.x = right; + quad->br.vertices.y = bottom; + quad->tl.vertices.x = left; + quad->tl.vertices.y = top; + quad->tr.vertices.x = right; + quad->tr.vertices.y = top; + } + + // texcoords + Rect tileTexture = _tileSet->getRectForGID(tileGID); + left = (tileTexture.origin.x / texSize.width); + right = left + (tileTexture.size.width / texSize.width); + bottom = (tileTexture.origin.y / texSize.height); + top = bottom + (tileTexture.size.height / texSize.height); + + quad->bl.texCoords.u = left; + quad->bl.texCoords.v = bottom; + quad->br.texCoords.u = right; + quad->br.texCoords.v = bottom; + quad->tl.texCoords.u = left; + quad->tl.texCoords.v = top; + quad->tr.texCoords.u = right; + quad->tr.texCoords.v = top; + + + GLushort *idxbase = indicesTmp + tilesUsed * 6; + int vertexbase = tilesUsed * 4; + + idxbase[0] = vertexbase; + idxbase[1] = vertexbase + 1; + idxbase[2] = vertexbase + 2; + idxbase[3] = vertexbase + 3; + idxbase[4] = vertexbase + 2; + idxbase[5] = vertexbase + 1; + + tilesUsed++; + } + + if (tilesUsed >= MAX_QUADS_COUNT) + { + break; + } + } // for x + + if (tilesUsed >= MAX_QUADS_COUNT) + { + break; + } + } // for y + + return tilesUsed * 6; +} + +void TMXLayer2::setupVBO() +{ + glGenBuffers(2, &_buffersVBO[0]); + + // 10922 = 65536/6 + int total = std::min(static_cast(_layerSize.width * _layerSize.height), MAX_QUADS_COUNT); + + // Vertex + Tex Coords + glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); + glBufferData(GL_ARRAY_BUFFER, total * sizeof(V2F_T2F_Quad), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // Indices + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, total * 6 * sizeof(GLushort), NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + CHECK_GL_ERROR_DEBUG(); +} + +// TMXLayer2 - setup Tiles +void TMXLayer2::setupTiles() +{ + // Optimization: quick hack that sets the image size on the tileset + _tileSet->_imageSize = _texture->getContentSizeInPixels(); + + // By default all the tiles are aliased + // pros: easier to render + // cons: difficult to scale / rotate / etc. + _texture->setAliasTexParameters(); + + //CFByteOrder o = CFByteOrderGetCurrent(); + + // Parse cocos2d properties + this->parseInternalProperties(); + + Size screenSize = Director::getInstance()->getWinSize(); + + switch (_layerOrientation) + { + case TMXOrientationOrtho: + _screenGridSize.width = ceil(screenSize.width / _mapTileSize.width) + 1; + _screenGridSize.height = ceil(screenSize.height / _mapTileSize.height) + 1; + + // tiles could be bigger than the grid, add additional rows if needed + _screenGridSize.height += _tileSet->_tileSize.height / _mapTileSize.height; + break; + case TMXOrientationIso: + _screenGridSize.width = ceil(screenSize.width / _mapTileSize.width) + 2; + _screenGridSize.height = ceil(screenSize.height / (_mapTileSize.height/2)) + 4; + break; + case TMXOrientationHex: + break; + } + + _screenTileCount = _screenGridSize.width * _screenGridSize.height; + + setupVBO(); +} + +Mat4 TMXLayer2::tileToNodeTransform() +{ + float w = _mapTileSize.width / CC_CONTENT_SCALE_FACTOR(); + float h = _mapTileSize.height / CC_CONTENT_SCALE_FACTOR(); + float offY = (_layerSize.height - 1) * h; + + switch(_layerOrientation) + { + case TMXOrientationOrtho: + { + _tileToNodeTransform = Mat4 + ( + w, 0.0f, 0.0f, 0.0f, + 0.0f, -h, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, offY, 0.0f, 1.0f + ); + + return _tileToNodeTransform; + } + case TMXOrientationIso: + { + float offX = (_layerSize.width - 1) * w / 2; + _tileToNodeTransform = Mat4 + ( + w/2, -h/2, 0.0f, 0.0f, + -w/2, -h/2, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + offX, offY, 0.0f, 1.0f + + ); + return _tileToNodeTransform; + } + case TMXOrientationHex: + { + _tileToNodeTransform = Mat4::IDENTITY; + return _tileToNodeTransform; + } + default: + { + _tileToNodeTransform = Mat4::IDENTITY; + return _tileToNodeTransform; + } + } + +} + +// removing / getting tiles +Sprite* TMXLayer2::getTileAt(const Point& tileCoordinate) +{ + CCASSERT( tileCoordinate.x < _layerSize.width && tileCoordinate.y < _layerSize.height && tileCoordinate.x >=0 && tileCoordinate.y >=0, "TMXLayer: invalid position"); + CCASSERT( _tiles, "TMXLayer: the tiles map has been released"); + + Sprite *tile = nullptr; + int gid = this->getTileGIDAt(tileCoordinate); + + // if GID == 0, then no tile is present + if( gid ) { + int index = tileCoordinate.x + tileCoordinate.y * _layerSize.width; + + auto it = _spriteContainer.find(index); + if (it != _spriteContainer.end()) + { + tile = it->second.first; + } + else + { + // tile not created yet. create it + Rect rect = _tileSet->getRectForGID(gid); + rect = CC_RECT_PIXELS_TO_POINTS(rect); + tile = Sprite::createWithTexture(_texture, rect); + + Point p = this->getPositionAt(tileCoordinate); + tile->setAnchorPoint(Point::ZERO); + tile->setPosition(p); + tile->setPositionZ((float)getVertexZForPos(tileCoordinate)); + tile->setOpacity(this->getOpacity()); + tile->setTag(index); + this->addChild(tile, -index); + _spriteContainer.insert(std::pair >(index, std::pair(tile, gid))); + + // tile is converted to sprite. + _tiles[index] = 0; + } + } + return tile; +} + +int TMXLayer2::getTileGIDAt(const Point& tileCoordinate, TMXTileFlags* flags/* = nullptr*/) +{ + CCASSERT(tileCoordinate.x < _layerSize.width && tileCoordinate.y < _layerSize.height && tileCoordinate.x >=0 && tileCoordinate.y >=0, "TMXLayer: invalid position"); + CCASSERT(_tiles, "TMXLayer: the tiles map has been released"); + + int idx = static_cast((tileCoordinate.x + tileCoordinate.y * _layerSize.width)); + + // Bits on the far end of the 32-bit global tile ID are used for tile flags + int tile = _tiles[idx]; + auto it = _spriteContainer.find(idx); + + // converted to sprite. + if (tile == 0 && it != _spriteContainer.end()) + { + tile = it->second.second; + } + + // issue1264, flipped tiles can be changed dynamically + if (flags) + { + *flags = (TMXTileFlags)(tile & kTMXFlipedAll); + } + + return (tile & kTMXFlippedMask); +} + +Point TMXLayer2::getPositionAt(const Point& pos) +{ + return PointApplyTransform(pos, _tileToNodeTransform); +} + +int TMXLayer2::getVertexZForPos(const Point& pos) +{ + int ret = 0; + int maxVal = 0; + if (_useAutomaticVertexZ) + { + switch (_layerOrientation) + { + case TMXOrientationIso: + maxVal = static_cast(_layerSize.width + _layerSize.height); + ret = static_cast(-(maxVal - (pos.x + pos.y))); + break; + case TMXOrientationOrtho: + ret = static_cast(-(_layerSize.height-pos.y)); + break; + case TMXOrientationHex: + CCASSERT(0, "TMX Hexa zOrder not supported"); + break; + default: + CCASSERT(0, "TMX invalid value"); + break; + } + } + else + { + ret = _vertexZvalue; + } + + return ret; +} + +void TMXLayer2::removeTileAt(const Point& tileCoordinate) +{ + + CCASSERT( tileCoordinate.x < _layerSize.width && tileCoordinate.y < _layerSize.height && tileCoordinate.x >=0 && tileCoordinate.y >=0, "TMXLayer: invalid position"); + CCASSERT( _tiles, "TMXLayer: the tiles map has been released"); + + uint32_t gid = this->getTileGIDAt(tileCoordinate); + + if( gid ) { + + int z = tileCoordinate.x + tileCoordinate.y * _layerSize.width; + + // remove tile from GID map + _tiles[z] = 0; + + // remove it from sprites + auto it = _spriteContainer.find(z); + if (it != _spriteContainer.end()) + { + this->removeChild(it->second.first); + } + } +} + + + +void TMXLayer2::removeChild(Node* node, bool cleanup) +{ + int tag = node->getTag(); + auto it = _spriteContainer.find(tag); + if (it != _spriteContainer.end() && it->second.first == node) + { + _spriteContainer.erase(it); + } + Node::removeChild(node, cleanup); +} + +// TMXLayer2 - Properties +Value TMXLayer2::getProperty(const std::string& propertyName) const +{ + if (_properties.find(propertyName) != _properties.end()) + return _properties.at(propertyName); + + return Value(); +} + +void TMXLayer2::parseInternalProperties() +{ + auto vertexz = getProperty("cc_vertexz"); + if (!vertexz.isNull()) + { + std::string vertexZStr = vertexz.asString(); + // If "automatic" is on, then parse the "cc_alpha_func" too + if (vertexZStr == "automatic") + { + _useAutomaticVertexZ = true; + auto alphaFuncVal = getProperty("cc_alpha_func"); + float alphaFuncValue = alphaFuncVal.asFloat(); + setGLProgram(GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_ALPHA_TEST)); + + GLint alphaValueLocation = glGetUniformLocation(getGLProgram()->getProgram(), GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE); + + // NOTE: alpha test shader is hard-coded to use the equivalent of a glAlphaFunc(GL_GREATER) comparison + + // use shader program to set uniform + getGLProgram()->use(); + getGLProgram()->setUniformLocationWith1f(alphaValueLocation, alphaFuncValue); + CHECK_GL_ERROR_DEBUG(); + } + else + { + _vertexZvalue = vertexz.asInt(); + } + } +} + + +//CCTMXLayer2 - obtaining positions, offset +Point TMXLayer2::calculateLayerOffset(const Point& pos) +{ + Point ret = Point::ZERO; + switch (_layerOrientation) + { + case TMXOrientationOrtho: + ret = Point( pos.x * _mapTileSize.width, -pos.y *_mapTileSize.height); + break; + case TMXOrientationIso: + ret = Point((_mapTileSize.width /2) * (pos.x - pos.y), + (_mapTileSize.height /2 ) * (-pos.x - pos.y)); + break; + case TMXOrientationHex: + CCASSERT(pos.equals(Point::ZERO), "offset for hexagonal map not implemented yet"); + break; + } + return ret; +} + +//void TMXLayer2::releaseMap() +//{ +// if (_tiles) +// { +// delete [] _tiles; +// _tiles = nullptr; +// } +//} + +// TMXLayer - adding / remove tiles +void TMXLayer2::setTileGID(int gid, const Point& tileCoordinate) +{ + setTileGID(gid, tileCoordinate, (TMXTileFlags)0); +} + +void TMXLayer2::setTileGID(int gid, const Point& tileCoordinate, TMXTileFlags flags) +{ + CCASSERT(tileCoordinate.x < _layerSize.width && tileCoordinate.y < _layerSize.height && tileCoordinate.x >=0 && tileCoordinate.y >=0, "TMXLayer: invalid position"); + CCASSERT(_tiles, "TMXLayer: the tiles map has been released"); + CCASSERT(gid == 0 || gid >= _tileSet->_firstGid, "TMXLayer: invalid gid" ); + + TMXTileFlags currentFlags; + int currentGID = getTileGIDAt(tileCoordinate, ¤tFlags); + + if (currentGID != gid || currentFlags != flags) + { + int gidAndFlags = gid | flags; + + // setting gid=0 is equal to remove the tile + if (gid == 0) + { + removeTileAt(tileCoordinate); + } + // empty tile. create a new one + else if (currentGID == 0) + { + int z = tileCoordinate.x + tileCoordinate.y * _layerSize.width; + _tiles[z] = gidAndFlags; + } + // modifying an existing tile with a non-empty tile + else + { + int z = tileCoordinate.x + tileCoordinate.y * _layerSize.width; + auto it = _spriteContainer.find(z); + if (it != _spriteContainer.end()) + { + Sprite *sprite = it->second.first; + Rect rect = _tileSet->getRectForGID(gid); + rect = CC_RECT_PIXELS_TO_POINTS(rect); + + sprite->setTextureRect(rect, false, rect.size); + this->reorderChild(sprite, z); + if (flags) + { + setupTileSprite(sprite, sprite->getPosition(), gidAndFlags); + } + + it->second.second = gidAndFlags; + } + else + { + _tiles[z] = gidAndFlags; + } + } + } +} + +void TMXLayer2::setupTileSprite(Sprite* sprite, Point pos, int gid) +{ + sprite->setPosition(getPositionAt(pos)); + sprite->setPositionZ((float)getVertexZForPos(pos)); + sprite->setAnchorPoint(Point::ZERO); + sprite->setOpacity(this->getOpacity()); + + //issue 1264, flip can be undone as well + sprite->setFlippedX(false); + sprite->setFlippedY(false); + sprite->setRotation(0.0f); + + // Rotation in tiled is achieved using 3 flipped states, flipping across the horizontal, vertical, and diagonal axes of the tiles. + if (gid & kTMXTileDiagonalFlag) + { + // put the anchor in the middle for ease of rotation. + sprite->setAnchorPoint(Point(0.5f,0.5f)); + sprite->setPosition(Point(getPositionAt(pos).x + sprite->getContentSize().height/2, + getPositionAt(pos).y + sprite->getContentSize().width/2 ) ); + + int flag = gid & (kTMXTileHorizontalFlag | kTMXTileVerticalFlag ); + + // handle the 4 diagonally flipped states. + if (flag == kTMXTileHorizontalFlag) + { + sprite->setRotation(90.0f); + } + else if (flag == kTMXTileVerticalFlag) + { + sprite->setRotation(270.0f); + } + else if (flag == (kTMXTileVerticalFlag | kTMXTileHorizontalFlag) ) + { + sprite->setRotation(90.0f); + sprite->setFlippedX(true); + } + else + { + sprite->setRotation(270.0f); + sprite->setFlippedX(true); + } + } + else + { + if (gid & kTMXTileHorizontalFlag) + { + sprite->setFlippedX(true); + } + + if (gid & kTMXTileVerticalFlag) + { + sprite->setFlippedY(true); + } + } +} + +Sprite* TMXLayer2::reusedTileWithRect(Rect rect) +{ + if (! _reusedTile) + { + _reusedTile = Sprite::createWithTexture(_texture, rect); + _reusedTile->retain(); + } + else + { + // Re-init the sprite + _reusedTile->setTextureRect(rect, false, rect.size); + } + + return _reusedTile; +} + +std::string TMXLayer2::getDescription() const +{ + return StringUtils::format("", _tag, (int)_mapTileSize.width, (int)_mapTileSize.height); +} + +NS_CC_END + diff --git a/cocos/2d/CCTMXLayer2.h b/cocos/2d/CCTMXLayer2.h new file mode 100644 index 0000000000..c2e56094e3 --- /dev/null +++ b/cocos/2d/CCTMXLayer2.h @@ -0,0 +1,261 @@ +/**************************************************************************** +Copyright (c) 2008-2010 Ricardo Quesada +Copyright (c) 2010-2012 cocos2d-x.org +Copyright (c) 2011 Zynga Inc. +Copyright (c) 2013-2014 Chukong Technologies 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. +****************************************************************************/ +#ifndef __CCTMX_LAYER2_H__ +#define __CCTMX_LAYER2_H__ + +#include "CCTMXObjectGroup.h" +#include "CCTMXXMLParser.h" +#include "CCNode.h" +#include "renderer/CCCustomCommand.h" + +#include + +NS_CC_BEGIN + +class TMXMapInfo; +class TMXLayerInfo; +class TMXTilesetInfo; +class Texture2D; +class Sprite; +struct _ccCArray; + +/** + * @addtogroup tilemap_parallax_nodes + * @{ + */ + +/** @brief TMXLayer2 represents the TMX layer. + +It is a subclass of SpriteBatchNode. By default the tiles are rendered using a TextureAtlas. +If you modify a tile on runtime, then, that tile will become a Sprite, otherwise no Sprite objects are created. +The benefits of using Sprite objects as tiles are: +- tiles (Sprite) 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 drawing 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 different +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 +Tiles can have tile flags for additional properties. At the moment only flip horizontal and flip vertical are used. These bit flags are defined in TMXXMLParser.h. + +@since 1.1 +*/ + +class CC_DLL TMXLayer2 : public Node +{ +public: + /** creates a TMXLayer2 with an tileset info, a layer info and a map info */ + static TMXLayer2 * create(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo); + /** + * @js ctor + */ + TMXLayer2(); + /** + * @js NA + * @lua NA + */ + virtual ~TMXLayer2(); + + /** returns the tile gid at a given tile coordinate. It also returns the tile flags. + */ + int getTileGIDAt(const Point& tileCoordinate, TMXTileFlags* flags = nullptr); + CC_DEPRECATED_ATTRIBUTE int tileGIDAt(const Point& tileCoordinate, TMXTileFlags* flags = nullptr){ + return getTileGIDAt(tileCoordinate, flags); + }; + + /** 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(int gid, const Point& 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. + + Use withFlags if the tile flags need to be changed as well + */ + + void setTileGID(int gid, const Point& tileCoordinate, TMXTileFlags flags); + + /** removes a tile at given tile coordinate */ + void removeTileAt(const Point& tileCoordinate); + + /** returns the position in points of a given tile coordinate */ + Point getPositionAt(const Point& tileCoordinate); + CC_DEPRECATED_ATTRIBUTE Point positionAt(const Point& tileCoordinate) { return getPositionAt(tileCoordinate); }; + + /** return the value for the specific property name */ + Value getProperty(const std::string& propertyName) const; + CC_DEPRECATED_ATTRIBUTE Value propertyNamed(const std::string& propertyName) const { return getProperty(propertyName); }; + + /** Creates the tiles */ + void setupTiles(); + + inline const std::string& getLayerName(){ return _layerName; } + inline void setLayerName(const std::string& layerName){ _layerName = layerName; } + + /** size of the layer in tiles */ + inline const Size& getLayerSize() const { return _layerSize; }; + inline void setLayerSize(const Size& size) { _layerSize = size; }; + + /** size of the map's tile (could be different from the tile's size) */ + inline const Size& getMapTileSize() const { return _mapTileSize; }; + inline void setMapTileSize(const Size& size) { _mapTileSize = size; }; + + /** pointer to the map of tiles + * @js NA + * @lua NA + */ + uint32_t* getTiles() const { return _tiles; }; + void setTiles(uint32_t* tiles) { _tiles = tiles; }; + + /** Tileset information for the layer */ + inline TMXTilesetInfo* getTileSet() const { return _tileSet; }; + inline void setTileSet(TMXTilesetInfo* info) { + CC_SAFE_RETAIN(info); + CC_SAFE_RELEASE(_tileSet); + _tileSet = info; + }; + + /** Layer orientation, which is the same as the map orientation */ + inline int getLayerOrientation() const { return _layerOrientation; }; + inline void setLayerOrientation(int orientation) { _layerOrientation = orientation; }; + + /** properties from the layer. They can be added using Tiled */ + inline const ValueMap& getProperties() const { return _properties; }; + inline ValueMap& getProperties() { return _properties; }; + inline void setProperties(const ValueMap& properties) { + _properties = properties; + }; + + /** returns the tile (Sprite) at a given a tile coordinate. + The returned Sprite will be already added to the TMXLayer. Don't add it again. + The Sprite can be treated like any other Sprite: rotated, scaled, translated, opacity, color, etc. + You can remove either by calling: + - layer->removeChild(sprite, cleanup); + */ + Sprite* getTileAt(const Point& tileCoordinate); + + Sprite* reusedTileWithRect(Rect rect); + + Sprite* updateTileForGID(int gid, const Point& pos); + + void setupTileSprite(Sprite* sprite, Point pos, int gid); + + // + // Override + // + virtual std::string getDescription() const override; + virtual void draw(Renderer *renderer, const Mat4& transform, uint32_t flags) override; + void removeChild(Node* child, bool cleanup = true) override; + +protected: + + bool initWithTilesetInfo(TMXTilesetInfo *tilesetInfo, TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo); + int updateTiles(const Rect& culledRect, V2F_T2F_Quad *quads, GLushort *indices); + void setupVBO(); + Point calculateLayerOffset(const Point& offset); + + /* The layer recognizes some special properties, like cc_vertez */ + void parseInternalProperties(); + + Mat4 tileToNodeTransform(); + Rect tileBoundsForClipTransform(const Mat4 &tileToClip); + + void onDraw(const Mat4 &transform, bool transformUpdated); + + int getVertexZForPos(const Point& pos); + + void insertTileForGID(int gid, const Point& pos); + +protected: + CustomCommand _customCommand; + + //! name of the layer + std::string _layerName; + + /** size of the layer in tiles */ + Size _layerSize; + /** size of the map's tile (could be different from the tile's size) */ + Size _mapTileSize; + /** pointer to the map of tiles */ + uint32_t* _tiles; + /** Tileset information for the layer */ + TMXTilesetInfo* _tileSet; + /** Layer orientation, which is the same as the map orientation */ + int _layerOrientation; + /** properties from the layer. They can be added using Tiled */ + ValueMap _properties; + + Texture2D *_texture; + Sprite* _reusedTile; + + /** container for sprite children. map > */ + std::map > _spriteContainer; + + GLuint _buffersVBO[3]; //0: vertex, 1: tex coords, 2: indices + + Size _screenGridSize; + Rect _screenGridRect; + int _screenTileCount; + Rect _previousRect; + int _verticesToDraw; + + int _vertexZvalue; + bool _useAutomaticVertexZ; + + + /** tile coordinate to node coordinate transform */ + Mat4 _tileToNodeTransform; + /** quads to be rendered */ + V2F_T2F_Quad* _quads; + /** number of quads */ + int _numQuads; + /** indices */ + GLushort* _indices; +}; + +// end of tilemap_parallax_nodes group +/// @} + +NS_CC_END + +#endif //__CCTMX_LAYER2_H__ + diff --git a/cocos/2d/CCTMXTiledMap2.cpp b/cocos/2d/CCTMXTiledMap2.cpp new file mode 100644 index 0000000000..b737cafd9b --- /dev/null +++ b/cocos/2d/CCTMXTiledMap2.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +Copyright (c) 2009-2010 Ricardo Quesada +Copyright (c) 2010-2012 cocos2d-x.org +Copyright (c) 2011 Zynga Inc. +Copyright (c) 2013-2014 Chukong Technologies 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 "CCTMXTiledMap2.h" + +#include + +#include "CCTMXXMLParser.h" +#include "CCTMXLayer2.h" +#include "CCSprite.h" +#include "deprecated/CCString.h" + +NS_CC_BEGIN + +// implementation TMXTiledMap2 + +TMXTiledMap2 * TMXTiledMap2::create(const std::string& tmxFile) +{ + TMXTiledMap2 *ret = new TMXTiledMap2(); + if (ret->initWithTMXFile(tmxFile)) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +TMXTiledMap2* TMXTiledMap2::createWithXML(const std::string& tmxString, const std::string& resourcePath) +{ + TMXTiledMap2 *ret = new TMXTiledMap2(); + if (ret->initWithXML(tmxString, resourcePath)) + { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} + +bool TMXTiledMap2::initWithTMXFile(const std::string& tmxFile) +{ + CCASSERT(tmxFile.size()>0, "TMXTiledMap2: tmx file should not be empty"); + + setContentSize(Size::ZERO); + + TMXMapInfo *mapInfo = TMXMapInfo::create(tmxFile); + + if (! mapInfo) + { + return false; + } + CCASSERT( !mapInfo->getTilesets().empty(), "TMXTiledMap2: Map not found. Please check the filename."); + buildWithMapInfo(mapInfo); + + return true; +} + +bool TMXTiledMap2::initWithXML(const std::string& tmxString, const std::string& resourcePath) +{ + setContentSize(Size::ZERO); + + TMXMapInfo *mapInfo = TMXMapInfo::createWithXML(tmxString, resourcePath); + + CCASSERT( !mapInfo->getTilesets().empty(), "TMXTiledMap2: Map not found. Please check the filename."); + buildWithMapInfo(mapInfo); + + return true; +} + +TMXTiledMap2::TMXTiledMap2() + :_mapSize(Size::ZERO) + ,_tileSize(Size::ZERO) +{ +} + +TMXTiledMap2::~TMXTiledMap2() +{ +} + +// private +TMXLayer2 * TMXTiledMap2::parseLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo) +{ + TMXTilesetInfo *tileset = tilesetForLayer(layerInfo, mapInfo); + TMXLayer2 *layer = TMXLayer2::create(tileset, layerInfo, mapInfo); + + // tell the layerinfo to release the ownership of the tiles map. + layerInfo->_ownTiles = false; + layer->setupTiles(); + + return layer; +} + +TMXTilesetInfo * TMXTiledMap2::tilesetForLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo) +{ + Size size = layerInfo->_layerSize; + auto& tilesets = mapInfo->getTilesets(); + if (tilesets.size()>0) + { + TMXTilesetInfo* tileset = nullptr; + for (auto iter = tilesets.crbegin(); iter != tilesets.crend(); ++iter) + { + tileset = *iter; + if (tileset) + { + for( int y=0; y < size.height; y++ ) + { + for( int x=0; x < size.width; x++ ) + { + int pos = static_cast(x + size.width * y); + int gid = layerInfo->_tiles[ 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 ) + { + // Optimization: quick return + // if the layer is invalid (more than 1 tileset per layer) an CCAssert will be thrown later + if( (gid & kTMXFlippedMask) >= tileset->_firstGid ) + return tileset; + } + } + } + } + } + } + + // If all the tiles are 0, return empty tileset + CCLOG("cocos2d: Warning: TMX Layer '%s' has no tiles", layerInfo->_name.c_str()); + return nullptr; +} + +void TMXTiledMap2::buildWithMapInfo(TMXMapInfo* mapInfo) +{ + _mapSize = mapInfo->getMapSize(); + _tileSize = mapInfo->getTileSize(); + _mapOrientation = mapInfo->getOrientation(); + + _objectGroups = mapInfo->getObjectGroups(); + + _properties = mapInfo->getProperties(); + + _tileProperties = mapInfo->getTileProperties(); + + int idx=0; + + auto& layers = mapInfo->getLayers(); + for(const auto &layerInfo : layers) { + if (layerInfo->_visible) + { + TMXLayer2 *child = parseLayer(layerInfo, mapInfo); + addChild(child, idx, idx); + + // update content size with the max size + const Size& childSize = child->getContentSize(); + Size currentSize = this->getContentSize(); + currentSize.width = std::max( currentSize.width, childSize.width ); + currentSize.height = std::max( currentSize.height, childSize.height ); + this->setContentSize(currentSize); + + idx++; + } + } +} + +// public +TMXLayer2 * TMXTiledMap2::getLayer(const std::string& layerName) const +{ + CCASSERT(layerName.size() > 0, "Invalid layer name!"); + + for (auto& child : _children) + { + TMXLayer2* layer = dynamic_cast(child); + if(layer) + { + if(layerName.compare( layer->getLayerName()) == 0) + { + return layer; + } + } + } + + // layer not found + return nullptr; +} + +TMXObjectGroup * TMXTiledMap2::getObjectGroup(const std::string& groupName) const +{ + CCASSERT(groupName.size() > 0, "Invalid group name!"); + + if (_objectGroups.size()>0) + { + TMXObjectGroup* objectGroup = nullptr; + for (auto iter = _objectGroups.cbegin(); iter != _objectGroups.cend(); ++iter) + { + objectGroup = *iter; + if (objectGroup && objectGroup->getGroupName() == groupName) + { + return objectGroup; + } + } + } + + // objectGroup not found + return nullptr; +} + +Value TMXTiledMap2::getProperty(const std::string& propertyName) const +{ + if (_properties.find(propertyName) != _properties.end()) + return _properties.at(propertyName); + + return Value(); +} + +Value TMXTiledMap2::getPropertiesForGID(int GID) const +{ + if (_tileProperties.find(GID) != _tileProperties.end()) + return _tileProperties.at(GID); + + return Value(); +} + +std::string TMXTiledMap2::getDescription() const +{ + return StringUtils::format("(_children.size())); +} + + +NS_CC_END + diff --git a/cocos/2d/CCTMXTiledMap2.h b/cocos/2d/CCTMXTiledMap2.h new file mode 100644 index 0000000000..9f1999af03 --- /dev/null +++ b/cocos/2d/CCTMXTiledMap2.h @@ -0,0 +1,222 @@ +/**************************************************************************** +Copyright (c) 2009-2010 Ricardo Quesada +Copyright (c) 2010-2012 cocos2d-x.org +Copyright (c) 2011 Zynga Inc. +Copyright (c) 2013-2014 Chukong Technologies 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. +****************************************************************************/ +#ifndef __CCTMX_TILE_MAP2_H__ +#define __CCTMX_TILE_MAP2_H__ + +#include "CCNode.h" +#include "CCTMXObjectGroup.h" +#include "CCValue.h" + +NS_CC_BEGIN + +class TMXObjectGroup; +class TMXLayer2; +class TMXLayerInfo; +class TMXTilesetInfo; +class TMXMapInfo; + +/** + * @addtogroup tilemap_parallax_nodes + * @{ + */ + +/** Possible orientations of the TMX map */ +enum +{ + /** Orthogonal orientation */ + TMXOrientationOrtho2, + + /** Hexagonal orientation */ + TMXOrientationHex2, + + /** Isometric orientation */ + TMXOrientationIso2, +}; + +/** @brief TMXTiledMap2 knows how to parse and render a TMX map. + +It adds support for the TMX tiled map format used by http://www.mapeditor.org +It supports isometric, hexagonal and orthogonal tiles. +It also supports object groups, objects, and properties. + +Features: +- Each tile will be treated as an Sprite +- The sprites are created on demand. They will be created only when you call "layer->tileAt(position)" +- Each tile can be rotated / moved / scaled / tinted / "opaqued", since each tile is a Sprite +- Tiles can be added/removed in runtime +- The z-order of the tiles can be modified in runtime +- Each tile has an anchorPoint of (0,0) +- The anchorPoint of the TMXTileMap is (0,0) +- The TMX layers will be added as a child +- The TMX layers will be aliased by default +- The tileset image will be loaded using the TextureCache +- Each tile will have a unique tag +- Each tile will have a unique z value. top-left: z=1, bottom-right: z=max z +- Each object group will be treated as an MutableArray +- Object class which will contain all the properties in a dictionary +- Properties can be assigned to the Map, Layer, Object Group, and Object + +Limitations: +- It only supports one tileset per layer. +- Embedded images are not supported +- It only supports the XML format (the JSON format is not supported) + +Technical description: +Each layer is created using an TMXLayer2 (subclass of SpriteBatchNode). If you have 5 layers, then 5 TMXLayer2 will be created, +unless the layer visibility is off. In that case, the layer won't be created at all. +You can obtain the layers (TMXLayer2 objects) at runtime by: +- map->getChildByTag(tag_number); // 0=1st layer, 1=2nd layer, 2=3rd layer, etc... +- map->getLayer(name_of_the_layer); + +Each object group is created using a TMXObjectGroup which is a subclass of MutableArray. +You can obtain the object groups at runtime by: +- map->getObjectGroup(name_of_the_object_group); + +Each object is a TMXObject. + +Each property is stored as a key-value pair in an MutableDictionary. +You can obtain the properties at runtime by: + +map->getProperty(name_of_the_property); +layer->getProperty(name_of_the_property); +objectGroup->getProperty(name_of_the_property); +object->getProperty(name_of_the_property); + +@since v0.8.1 +*/ +class CC_DLL TMXTiledMap2 : public Node +{ +public: + /** creates a TMX Tiled Map with a TMX file.*/ + static TMXTiledMap2* create(const std::string& tmxFile); + + /** initializes a TMX Tiled Map with a TMX formatted XML string and a path to TMX resources */ + static TMXTiledMap2* createWithXML(const std::string& tmxString, const std::string& resourcePath); + + /** return the TMXLayer2 for the specific layer */ + TMXLayer2* getLayer(const std::string& layerName) const; + /** + * @js NA + * @lua NA + */ + CC_DEPRECATED_ATTRIBUTE TMXLayer2* layerNamed(const std::string& layerName) const { return getLayer(layerName); }; + + /** return the TMXObjectGroup for the specific group */ + TMXObjectGroup* getObjectGroup(const std::string& groupName) const; + /** + * @js NA + * @lua NA + */ + CC_DEPRECATED_ATTRIBUTE TMXObjectGroup* objectGroupNamed(const std::string& groupName) const { return getObjectGroup(groupName); }; + + /** return the value for the specific property name */ + Value getProperty(const std::string& propertyName) const; + /** + * @js NA + * @lua NA + */ + CC_DEPRECATED_ATTRIBUTE Value propertyNamed(const char *propertyName) const { return getProperty(propertyName); }; + + /** return properties dictionary for tile GID */ + Value getPropertiesForGID(int GID) const; + CC_DEPRECATED_ATTRIBUTE Value propertiesForGID(int GID) const { return getPropertiesForGID(GID); }; + + /** the map's size property measured in tiles */ + inline const Size& getMapSize() const { return _mapSize; }; + inline void setMapSize(const Size& mapSize) { _mapSize = mapSize; }; + + /** the tiles's size property measured in pixels */ + inline const Size& getTileSize() const { return _tileSize; }; + inline void setTileSize(const Size& tileSize) { _tileSize = tileSize; }; + + /** map orientation */ + inline int getMapOrientation() const { return _mapOrientation; }; + inline void setMapOrientation(int mapOrientation) { _mapOrientation = mapOrientation; }; + + /** object groups */ + inline const Vector& getObjectGroups() const { return _objectGroups; }; + inline Vector& getObjectGroups() { return _objectGroups; }; + inline void setObjectGroups(const Vector& groups) { + _objectGroups = groups; + }; + + /** properties */ + inline ValueMap& getProperties() { return _properties; }; + inline void setProperties(const ValueMap& properties) { + _properties = properties; + }; + + virtual std::string getDescription() const override; + +protected: + /** + * @js ctor + */ + TMXTiledMap2(); + /** + * @js NA + * @lua NA + */ + virtual ~TMXTiledMap2(); + + /** initializes a TMX Tiled Map with a TMX file */ + bool initWithTMXFile(const std::string& tmxFile); + + /** initializes a TMX Tiled Map with a TMX formatted XML string and a path to TMX resources */ + bool initWithXML(const std::string& tmxString, const std::string& resourcePath); + + TMXLayer2 * parseLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo); + TMXTilesetInfo * tilesetForLayer(TMXLayerInfo *layerInfo, TMXMapInfo *mapInfo); + void buildWithMapInfo(TMXMapInfo* mapInfo); + + /** the map's size property measured in tiles */ + Size _mapSize; + /** the tiles's size property measured in pixels */ + Size _tileSize; + /** map orientation */ + int _mapOrientation; + /** object groups */ + Vector _objectGroups; + /** properties */ + ValueMap _properties; + + //! tile properties + ValueMapIntKey _tileProperties; + +private: + CC_DISALLOW_COPY_AND_ASSIGN(TMXTiledMap2); + +}; + +// end of tilemap_parallax_nodes group +/// @} + +NS_CC_END + +#endif //__CCTMX_TILE_MAP2_H__ + + diff --git a/cocos/base/ccTypes.h b/cocos/base/ccTypes.h index f447c4de5b..5b63599b35 100644 --- a/cocos/base/ccTypes.h +++ b/cocos/base/ccTypes.h @@ -254,6 +254,15 @@ struct V3F_C4B_T2F Tex2F texCoords; // 8 bytes }; +//! a Vec2 with a vertex point, a tex coord point +struct V2F_T2F +{ + //! vertices (2F) + Vec2 vertices; + //! tex coords (2F) + Tex2F texCoords; +}; + //! A Triangle of V2F_C4B_T2F struct V2F_C4B_T2F_Triangle { @@ -304,6 +313,18 @@ struct V2F_C4F_T2F_Quad V2F_C4F_T2F tr; }; +struct V2F_T2F_Quad +{ + //! bottom left + V2F_T2F bl; + //! bottom right + V2F_T2F br; + //! top left + V2F_T2F tl; + //! top right + V2F_T2F tr; +}; + //! Blend Function used for textures struct BlendFunc {