TileMaps very slooooow

Apprentice
Posts: 14
Joined: 2009.06
Post: #1
Hi, im learning opengl, and starting some games in 2D, actually im stuck with tilemaps, im only acheiving 20fps or less with a simple map 60x40 the tiles are 16x16, so this give us a simple 960x640 pixels map.
Im currently using the vertex arrays, so i draw all the tile quads with only one gl call, and im using a tileAtlas.
Also im only drawing the visible tiles on the screen to gain some performance, but im really disappointed with the result.
My code is based on the opengl template wich comes with xcode.
This is the function im using to draw maps, the maps are stored in an array 3d, level[layers][rows][columns]

Code:
-(void) DrawLevel:(Texture2D *)Surf_Draw  CameraX:(float)CameraX  CameraY:(float)CameraY  Layer:(int)Layer  IndexQuad:(int)indexquad
{

    int index = 0;
    int x,y;
    int xtile, ytile, xpos,ypos;
    
    //add calculations to achieve smooth scroll
    xtile = CameraX / TileSize;
    ytile = CameraY / TileSize;
    xpos = (int)CameraX & TileSize-1;
    ypos = (int)CameraY & TileSize-1;
    
    
    //we only want to render the visible screen plus 1 tile in each direcction
    // if map its more bigger than the screen resolution, that extra tile its
    //for smooth scroll, so we only scan the screen resolution
        for (int i = 0; i < (SCREENY/TileSize)+1; i ++)
        {
            for (int j = 0; j < (SCREENX/TileSize)+1; j++)
            {
            //loop through the map
            index = level[Layer][i+ytile][j+xtile].Tilenum;
            
            //convert map coords into pixels coords
                x=(j*TileSize) - xpos;
                y=(i*TileSize) - ypos;

                //add only visible tiles to the vertex array
if (level[Layer][i][j].visible == YES)
    [Surf_Draw UpdateQuadsAt:CGRectMake(x, y, TileSize, TileSize)
                 OffsetPoint:CGPointMake((index%columns) *TileSize,  (index/columns) * TileSize)
                SubTextureWidth:TileSize
                SubTextureHeight:TileSize
                Flip:1
                withIndex:indexquad];
                indexquad++;

            }
        }
    



}

Then i only need to call this to draw the map on screen
Code:
-(void) drawNumberOfQuads: (NSUInteger)n  
{    

    glColor4f(colourFilter[0], colourFilter[1], colourFilter[2], colourFilter[3]);
    
    if(_name != [sharedGameState currentlyBoundTexture]) {
        [sharedGameState setCurrentlyBoundTexture:_name];
        glBindTexture(GL_TEXTURE_2D, _name);
    }
    

    glVertexPointer(2, GL_FLOAT, 0, verticesTileSheet);
    glTexCoordPointer(2, GL_FLOAT, 0, texCoordsTileSheet);
    glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, indicesTileSheet);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

    
}

Any ideas?

Regards,
Quote this message in a reply
Member
Posts: 25
Joined: 2009.05
Post: #2
Could you tell what is that Surf_Draw and what exactly you do with:

[Surf_Draw UpdateQuadsAt:CGRectMake(x, y, TileSize, TileSize)
OffsetPoint:CGPointMake((index%columns) *TileSize, (index/columns) * TileSize)
SubTextureWidth:TileSize
SubTextureHeight:TileSize
Flip:1
withIndex:indexquad];
indexquad++;
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2009.06
Post: #3
Of course, Surf_draw its a pointer to a texture2d image, im using texture2d class from apple, and here is the updatequads function

Code:
-(void) UpdateQuadsAt:(CGRect)rect OffsetPoint:(CGPoint)offsetPoint  SubTextureWidth:(GLfloat)SubTextureWidth SubTextureHeight:(GLfloat)SubTextureHeight Flip:(int)flip withIndex:(int)idx
{
    
    Quad2 texCoord;
    Quad2 vertex;
    
    //calculate the quad dimensions
    GLfloat texWidthRatio = 1.0f / (float)_width ;
    GLfloat texHeightRatio = 1.0f / (float)_height;
    
    GLfloat cx = texWidthRatio * offsetPoint.x;    // X Position of sprite
    GLfloat cy = texHeightRatio * offsetPoint.y; // Y Position of sprite
    

    
    // top left
    //top right
    //bottom left
    //bottom right
    texCoord.tl_x = cx;
    texCoord.tl_y = cy;
    
    texCoord.tr_x = (texWidthRatio * SubTextureWidth) + cx;
    texCoord.tr_y = cy;
    
    texCoord.bl_x = cx;
    texCoord.bl_y = (texHeightRatio * SubTextureHeight) + cy;
    
    texCoord.br_x = (texWidthRatio * SubTextureWidth) + cx;
    texCoord.br_y = (texHeightRatio * SubTextureHeight) + cy;
    

    
    if (flip == 1)
    {
        vertex.tl_x =  rect.origin.x;
        vertex.tl_y =  rect.origin.y;
        
        vertex.tr_x =  rect.origin.x + rect.size.width;
        vertex.tr_y =  rect.origin.y;
        
        
        vertex.bl_x =  rect.origin.x;
        vertex.bl_y =  rect.origin.y + rect.size.height;
        
        
        vertex.br_x = rect.origin.x + rect.size.width;
        vertex.br_y = rect.origin.y + rect.size.height;
        
        
    }else{
        vertex.tl_x =  rect.origin.x + rect.size.width;
        vertex.tl_y =  rect.origin.y;
        
        vertex.tr_x =  rect.origin.x;
        vertex.tr_y =  rect.origin.y;
        
        
        vertex.bl_x =  rect.origin.x + rect.size.width;
        vertex.bl_y =  rect.origin.y + rect.size.height;
        
        
        vertex.br_x = rect.origin.x;
        vertex.br_y = rect.origin.y + rect.size.height;
        
    }

    
    [self updateQuadWithTexture:&texCoord vertexQuad:&vertex atIndex:idx];

    
}

Quad2, is only a simple struct
Code:
typedef struct _Quad2 {
    float tl_x, tl_y;
    float tr_x, tr_y;
    float bl_x, bl_y;
    float br_x, br_y;
} Quad2;

Regards,
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2009.06
Post: #4
I forgot post the updatequadwithtexture function

Code:
-(void) updateQuadWithTexture: (Quad2*)quadT vertexQuad:(Quad2*)quadV atIndex:(NSUInteger)n
{
    
    texCoordsTileSheet[n] = *quadT;
    verticesTileSheet[n] = *quadV;

}

I dont know why a simple map is rendered too slow Mad
Quote this message in a reply
Member
Posts: 25
Joined: 2009.05
Post: #5
So you reconstruct texture and vertices arrays every frame including only visible quads.
I can not see any reason why it should slow down to 20 fps.
Make sure thumb option for compilation is disabled.

Anyway, there is no need to reconstruct whole array every frame. I believe you could construct array only once and then draw only visible part of them in few draw calls by setting up vertex offset argument in glDrawArray and even without indices.
Quote this message in a reply
Member
Posts: 87
Joined: 2006.08
Post: #6
Have you used either Instruments or Shark to determine where the CPU time is being spent?

If the answer is No, then you're just trying random shots in the dark, and you really should reconsider.
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2009.06
Post: #7
Yes I try instruments to see, and the drawquads function actually are using a 90%, the renderscene is wasting around 7%. The thumb support is also disabled.
Even updating the texture and vertex array in every frame, it shouldnt be too slow
Quote this message in a reply
Apprentice
Posts: 8
Joined: 2009.02
Post: #8
Try increasing the tile size -- something like 128x128 or even larger will work much better from my experience. Let me know if that helps
Quote this message in a reply
Apprentice
Posts: 14
Joined: 2009.06
Post: #9
Deactivating glblend and reducing the total number of tiles was the key to solve this problem Smile
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Question about tmx files (tilemaps) and resolution for Iphone 3gs, Ipad, and Retina appsolutecreations 10 16,338 May 19, 2012 10:02 AM
Last Post: tapouillo