Drawing tiles on a grid

Started by
1 comment, last by XTAL256 15 years, 8 months ago
To make my 2D map (see this post) i have decided to split it up into smaller (256x256) OpenGL textures. Now i need some code to draw the tiles that are in view on the screen. I don't know whether to loop through all tiles and check if each will be visible on screen, or if i should use some fancy maths to calculate the array index of the start and end tiles in the x and y direction. Here is some of the code i have so far:

/*  numTileX and numTileY are the number of tiles in the x and y direction
 *  texTileSize is the size of the square texture (256x256)
 *  drawGLTexture function is listed below. Ignore imgW, imgH, wrapX, wrapY, and angle as these
 *        are not used here, i don't need to stretch or tile each tile
 */
void Map::draw() {
    // Also need to tile or stretch the background image.
    drawImage(background.image, 0, 0, screenWidth, screenHeight);

    for (int j = 0; j < numTileY; j++) {
        for (int i = 0; i < numTileX; i++) {
            drawGLTexture(tiles[j*numTileY+i].texId, i*texTileSize, j*texTileSize,
                     texTileSize, texTileSize, ...);
        }
    }
}

// In file Graphics.cpp
void graphics::drawGLTexture(GLuint id, int x, int y, int w, int h,
                int imgW, int imgH, int wrapX, int wrapY, float angle) {
    // Rotate the matrix if the image is at an angle
    if (angle != 0) {
        glPushMatrix();
        glRotatef(angle, 1.0f, 0.0f, 0.0f);
    }

    // Scale image coords to texture coords [0.0-1.0]
    float tw = 1.0f, th = 1.0f;
    if (wrapX == TILE)  tw = float(w)/float(imgW);
    if (wrapY == TILE)  th = float(h)/float(imgH);

    // Draw quad with texture
    glBindTexture(GL_TEXTURE_2D, id);
    glBegin(GL_QUADS);
    glTexCoord2f( 0,  0); glVertex2i( x,   y );
    glTexCoord2f( 0, th); glVertex2i( x,  y+h);
    glTexCoord2f(tw, th); glVertex2i(x+w, y+h);
    glTexCoord2f(tw,  0); glVertex2i(x+w,  y );
    glEnd();

    // Restore rotation
    if (angle != 0)
        glPopMatrix();
}


Here is a diagram of what i want: I need to draw the tiles that will be totally or partially visible on the screen. I also don't know if i should manually clip the tiles to the screen by drawing a quad with part of the texture on it, or if it would be faster if i just draw it partially off-screen and let OpenGL do the clipping. If anyone has similar code from their game or knows of a good website that explains how to do it then that would be great. Otherwise i would just like to know the best/easiest way to do it. thanks
[Window Detective] - Windows UI spy utility for programmers
Advertisement
If all you need to render is less than 10 256x256 textures, then you can just render all totally or partly visible tiles, since this is peanuts for even an older graphics card. You will be amazed of just how many commands and textures you can throw after modern cards without notice.
For the detection of which tiles are visible, this will probably not be a bottleneck even with larger maps, but there are anyways at least 2 faster solutions.
One of them is to calculate the array index via the fancy math, as you described, but it really is not that tricky. Assuming your map starts at (0, 0), your world units are pixels, and you have saved the screen position (sp) as the lower left coordinate of the screen space (assuming GL coordinate system), you need to render tiles from x1 = ((sp.x - sp.x % 256) / 256) to x2 = ((sp.x + sp.x % 256) / 256) and from y1 = ((sp.y - sp.y % 256) / 256) to y2 = ((sp.y + sp.y % 256) / 256). It might not be bulletproof (as it is untested), but it should get you an idea of what you need.
The other solution, which probably is not what you really want for a smal-scale project, is to make a quadtree or a kd-tree and make/perform render queries on those. So you probably just want to stick with the first solution :)
Yeah, i think i will do the first option. It's not really fancy maths but it would require a bit of thought. Your equations look pretty straight foward.
And btw, that diagram was just to illustrate what i was doing, in reality there would be more tiles than that. As i think i mentioned, the size was 256x256, and my screen will be 800x600 or a bit longer for wide-screen monitors (i will scale up rather that using actual monitor size). So i will have 6 fully visible tiles with at most 20 tiles (fully or partially visible). This is still probably not a problem even on my machine*. And the size will be read from a settings file so the user can change it if need be.

* Laptop, 1.73GHz Pentium M, Intel 915GM/GMS,910GML
[Window Detective] - Windows UI spy utility for programmers

This topic is closed to new replies.

Advertisement