Advertisement Jump to content

OpenGL What is the correct way to draw a tilemap using OpenGL?

Recommended Posts


Hi, I'm starting to learn OpenGL and it's been really fun because of the amount of things I can do. I would like to implement a tilemap in my game engine, but the way I'm trying to do this is consuming a lot of CPU and GPU, just to draw parts of the texture, without entities or animations. The approach I'm using is to load a texture with all the tiles (tileset) and traverse the image by drawing only parts of it in specific (side-by-side) positions in the visible region of the screen.

The OpenGL version is 3.3. And the code can be seen below.

I think there must be a right way to do it, because old games like Diablo 2 draw a big map with several things happening during the game and consume practically nothing, even playing for hours.


 void GameMap::draw()
        // Use shader

        // Use texture


        // Draw map
        for (size_t r = 0; r < 10; r++)
            for (size_t c = 0; c < 10; c++)
                // Tile position

                // Isometric perspective

                // Draw tile by index

    void GameMap::drawTile(GLint index)
        // Identity matrix
        glm::mat4 position_coord = glm::mat4(1.0f);
        glm::mat4 texture_coord = glm::mat4(1.0f);
        // Part of the texture
        m_srcX = index * m_tileWidth;
        GLfloat clipX = m_srcX / m_texture->m_width;
        GLfloat clipY = m_srcY / m_texture->m_height;
        // Coordinates of the texture
        texture_coord = glm::translate(texture_coord, glm::vec3(clipX, clipY, 0.0f));

        // Coordinates of the vertices
        position_coord = glm::translate(position_coord, glm::vec3(m_tileCoord->getX(), m_tileCoord->getY(), 0.0f));
        position_coord = glm::scale(position_coord, glm::vec3(m_tileWidth, m_tileHeight, 1.0f));

        // Change the shader
        m_shader->setMatrix4("texture_coord", texture_coord);
        m_shader->setMatrix4("position_coord", position_coord);
        // Draws part of the texture
        glDrawArrays(GL_TRIANGLES, 0, 6);

    void GameMap::initRenderData()
        // Coordinates
        GLfloat posX = (GLfloat)m_tileWidth / m_texture->m_width;
        GLfloat posY = (GLfloat)m_tileHeight / m_texture->m_height;

        // Configure VAO/VBO
        GLuint VBO;
        GLfloat vertices[] = {
            // Left triangle
            // Pos      // Tex
            0.0f, 1.0f, 0.0f, posY, // Bottom left corner
            1.0f, 0.0f, posX, 0.0f, // Top right corner 
            0.0f, 0.0f, 0.0f, 0.0f,    // Upper left corner

            // Right triangle
            0.0f, 1.0f, 0.0f, posY, // Lower left corner
            1.0f, 1.0f, posX, posY, // Bottom right corner
            1.0f, 0.0f, posX, 0.0f // Top right corner 

        glGenVertexArrays(1, &m_quadVAO);
        glGenBuffers(1, &VBO);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
    // ------------------------------------------------------------------------------------------
    // Vertex Shader
    #version 330 core
    layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>

    out vec4 TexCoords;

    uniform mat4 texture_coord;
    uniform mat4 position_coord;
    uniform mat4 projection;

    void main()
        TexCoords =       texture_coord * vec4(vertex.z, vertex.w, 1.0, 1.0);
        gl_Position =   projection * position_coord * vec4(vertex.xy, 0.0, 1.0);
    // Fragment Shader
    #version 330 core
    out vec4 FragColor;

    in vec4 TexCoords;

    uniform sampler2D image;

    void main()
        FragColor =  texture(image, vec2(TexCoords.x, TexCoords.y));







Share this post

Link to post
Share on other sites

I think it's due to you issuing a drawcall for each tile, if you batch them all together in one drawcall it'll be much faster!

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement

Important Information

By using, you agree to our community Guidelines, Terms of Use, and Privacy Policy. is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!