/* * cocos2d for iPhone: http://www.cocos2d-iphone.org * * Copyright (c) 2008-2010 Ricardo Quesada * Copyright (c) 2011 Zynga Inc. * * 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. * */ #import "ccConfig.h" #import "CCTileMapAtlas.h" #import "ccMacros.h" #import "Support/CCFileUtils.h" @interface CCTileMapAtlas (Private) -(void) loadTGAfile:(NSString*)file; -(void) calculateItemsToRender; -(void) updateAtlasValueAt:(ccGridSize)pos withValue:(ccColor3B)value withIndex:(NSUInteger)idx; @end @implementation CCTileMapAtlas @synthesize tgaInfo; #pragma mark CCTileMapAtlas - Creation & Init +(id) tileMapAtlasWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h { return [[[self alloc] initWithTileFile:tile mapFile:map tileWidth:w tileHeight:h] autorelease]; } -(id) initWithTileFile:(NSString*)tile mapFile:(NSString*)map tileWidth:(int)w tileHeight:(int)h { [self loadTGAfile: map]; [self calculateItemsToRender]; if( (self=[super initWithTileFile:tile tileWidth:w tileHeight:h itemsToRender: itemsToRender]) ) { posToAtlasIndex = [[NSMutableDictionary dictionaryWithCapacity:itemsToRender] retain]; [self updateAtlasValues]; [self setContentSize: CGSizeMake(tgaInfo->width*itemWidth_, tgaInfo->height*itemHeight_)]; } return self; } -(void) dealloc { if( tgaInfo ) tgaDestroy(tgaInfo); [posToAtlasIndex release]; [super dealloc]; } -(void) releaseMap { if( tgaInfo ) tgaDestroy(tgaInfo); tgaInfo = nil; [posToAtlasIndex release]; posToAtlasIndex = nil; } -(void) calculateItemsToRender { NSAssert( tgaInfo != nil, @"tgaInfo must be non-nil"); itemsToRender = 0; for(int x = 0;x < tgaInfo->width; x++ ) { for(int y = 0; y < tgaInfo->height; y++ ) { ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; ccColor3B value = ptr[x + y * tgaInfo->width]; if( value.r ) itemsToRender++; } } } -(void) loadTGAfile:(NSString*)file { NSAssert( file != nil, @"file must be non-nil"); NSString *path = [CCFileUtils fullPathFromRelativePath:file ]; // //Find the path of the file // NSBundle *mainBndl = [CCDirector sharedDirector].loadingBundle; // NSString *resourcePath = [mainBndl resourcePath]; // NSString * path = [resourcePath stringByAppendingPathComponent:file]; tgaInfo = tgaLoad( [path UTF8String] ); #if 1 if( tgaInfo->status != TGA_OK ) [NSException raise:@"TileMapAtlasLoadTGA" format:@"TileMapAtas cannot load TGA file"]; #endif } #pragma mark CCTileMapAtlas - Atlas generation / updates -(void) setTile:(ccColor3B) tile at:(ccGridSize) pos { NSAssert( tgaInfo != nil, @"tgaInfo must not be nil"); NSAssert( posToAtlasIndex != nil, @"posToAtlasIndex must not be nil"); NSAssert( pos.x < tgaInfo->width, @"Invalid position.x"); NSAssert( pos.y < tgaInfo->height, @"Invalid position.x"); NSAssert( tile.r != 0, @"R component must be non 0"); ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; ccColor3B value = ptr[pos.x + pos.y * tgaInfo->width]; if( value.r == 0 ) CCLOG(@"cocos2d: Value.r must be non 0."); else { ptr[pos.x + pos.y * tgaInfo->width] = tile; // XXX: this method consumes a lot of memory // XXX: a tree of something like that shall be impolemented NSNumber *num = [posToAtlasIndex objectForKey: [NSString stringWithFormat:@"%d,%d", pos.x, pos.y]]; [self updateAtlasValueAt:pos withValue:tile withIndex: [num integerValue]]; } } -(ccColor3B) tileAt:(ccGridSize) pos { NSAssert( tgaInfo != nil, @"tgaInfo must not be nil"); NSAssert( pos.x < tgaInfo->width, @"Invalid position.x"); NSAssert( pos.y < tgaInfo->height, @"Invalid position.y"); ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; ccColor3B value = ptr[pos.x + pos.y * tgaInfo->width]; return value; } -(void) updateAtlasValueAt:(ccGridSize)pos withValue:(ccColor3B)value withIndex:(NSUInteger)idx { ccV3F_C4B_T2F_Quad quad; NSInteger x = pos.x; NSInteger y = pos.y; float row = (value.r % itemsPerRow_); float col = (value.r / itemsPerRow_); float textureWide = [[textureAtlas_ texture] pixelsWide]; float textureHigh = [[textureAtlas_ texture] pixelsHigh]; #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL float left = (2*row*itemWidth_+1)/(2*textureWide); float right = left+(itemWidth_*2-2)/(2*textureWide); float top = (2*col*itemHeight_+1)/(2*textureHigh); float bottom = top+(itemHeight_*2-2)/(2*textureHigh); #else float left = (row*itemWidth_)/textureWide; float right = left+itemWidth_/textureWide; float top = (col*itemHeight_)/textureHigh; float bottom = top+itemHeight_/textureHigh; #endif quad.tl.texCoords.u = left; quad.tl.texCoords.v = top; quad.tr.texCoords.u = right; quad.tr.texCoords.v = top; quad.bl.texCoords.u = left; quad.bl.texCoords.v = bottom; quad.br.texCoords.u = right; quad.br.texCoords.v = bottom; quad.bl.vertices.x = (int) (x * itemWidth_); quad.bl.vertices.y = (int) (y * itemHeight_); quad.bl.vertices.z = 0.0f; quad.br.vertices.x = (int)(x * itemWidth_ + itemWidth_); quad.br.vertices.y = (int)(y * itemHeight_); quad.br.vertices.z = 0.0f; quad.tl.vertices.x = (int)(x * itemWidth_); quad.tl.vertices.y = (int)(y * itemHeight_ + itemHeight_); quad.tl.vertices.z = 0.0f; quad.tr.vertices.x = (int)(x * itemWidth_ + itemWidth_); quad.tr.vertices.y = (int)(y * itemHeight_ + itemHeight_); quad.tr.vertices.z = 0.0f; [textureAtlas_ updateQuad:&quad atIndex:idx]; } -(void) updateAtlasValues { NSAssert( tgaInfo != nil, @"tgaInfo must be non-nil"); int total = 0; for(int x = 0;x < tgaInfo->width; x++ ) { for(int y = 0; y < tgaInfo->height; y++ ) { if( total < itemsToRender ) { ccColor3B *ptr = (ccColor3B*) tgaInfo->imageData; ccColor3B value = ptr[x + y * tgaInfo->width]; if( value.r != 0 ) { [self updateAtlasValueAt:ccg(x,y) withValue:value withIndex:total]; NSString *key = [NSString stringWithFormat:@"%d,%d", x,y]; NSNumber *num = [NSNumber numberWithInt:total]; [posToAtlasIndex setObject:num forKey:key]; total++; } } } } } @end