0

I seem to have ran into a strange issue with OpenGL. Everything works fine with my class until I make the map too big (around 800x800 is the max), and then OpenGL doesn't draw anything. I have made calls to glGetBufferSubData, and as far as I could tell the data seemed correct in both the vertex and index buffers, yet nothing is being drawn? At first I assumed an overflow somewhere in my code, but according to std::numeric_limits my vertex and index iterators don't seem to come anywhere close to the max size of a (signed) int. I use a lot of wrapper classes around OpenGL objects, but they are very simple, usually inline calls to their OpenGL equivalent. Same for the "M_" typedefs around primitive types. Below are the main loop I render in, the class where I believe the issue lies, and 2 screenshots of the output.

Correct output: https://i.stack.imgur.com/AxQG2.png

Blank ouput, after expanding map: https://i.stack.imgur.com/xRGU1.png

Main loop:

int main(){
//open window
Memento::MainWindow& main_window = Memento::MainWindow::GetInstance();
Memento::MainWindow::Init();
main_window.SetTitle("Memento");
main_window.Open();

//matrices
glmx_mat4 ortho_matrix = {};
glmx_mat4_ortho(0.0f, 800.0f, 600.0f, 0.0f, 5.0f, 25.0f, ortho_matrix);

glmx_mat4 modelview_matrix = {};
glmx_mat4_identity(modelview_matrix);

glmx_vec3 translate_vec = {0.0f, 0.0f, -10.0f};
glmx_mat4_translate(modelview_matrix, translate_vec, modelview_matrix);

glmx_mat4_multiply(ortho_matrix, modelview_matrix, ortho_matrix);

//shaders
Memento::GLShader default_vert_shader("default.vert", GL_VERTEX_SHADER);
default_vert_shader.Compile();

Memento::GLShader default_frag_shader("default.frag", GL_FRAGMENT_SHADER);
default_frag_shader.Compile();

//program
Memento::GLProgram default_program;
default_program.Create();
default_program.AttachShader(default_vert_shader);
default_program.AttachShader(default_frag_shader);

Memento::GLVertexArray default_vert_array;
default_vert_array.Create();
default_vert_array.Bind();

//BufferGameMap class- where I believe the issue lies
Memento::TextureAtlas atlas1("atlas/cat_image.png", "atlas/cat_source.xml");
Memento::BufferGameMap map1("tryagain.tmx", atlas1);

//bind buffers
map1.GetVertexBuffer().Bind();
map1.GetIndexBuffer().Bind();

//upload vertex attributes
default_vert_array.EnableIndex(0);
default_vert_array.IndexData(0, 2, GL_FLOAT, NULL, 8 * sizeof(Memento::M_float));
default_vert_array.BindIndex(default_program, 0, "map_vert");

//link, validate, and use program
default_program.Link();
default_program.Validate();
default_program.Use();

//upload matrix as uniform
glUniformMatrix4fv(default_program.GetUniformLocation("modelviewprojection_matrix"),
        1, GL_FALSE, ortho_matrix);

//main draw loop
while(not glfwGetKey(GLFW_KEY_ESC)){
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, map1.GetIndexBufferLength(), GL_UNSIGNED_INT, NULL);
    glfwSwapBuffers();
}

//close window & exit
main_window.Close();

return (0);

}

BufferGameMap class (issue is probably here!):

Memento::BufferGameMap::BufferGameMap(std::string const& file, const Memento::TextureAtlas& atlas):
    TmxMap::GameMap(), background_color_color4(), vertex_buffer(), index_buffer(),
    vertex_buffer_len(0), index_buffer_len(0){

    Create(file, atlas);
}

Memento::M_void Memento::BufferGameMap::Create(std::string const& file, const       Memento::TextureAtlas& atlas){

if(IsCreated())Destroy();
TmxMap::GameMap::CreateFromFile(file);

std::vector<TmxMap::Layer> const& layers = GetLayers();

if(not layers.empty()){
    const std::vector<TmxMap::Layer>::const_iterator layers_end = layers.end();
    std::vector<TmxMap::Layer>::const_iterator layers_iter = layers.begin();

    Memento::M_float* vertex_buffer_data = NULL;
    Memento::M_uint* index_buffer_data = NULL;

    for(; layers_iter != layers_end; ++layers_iter){
        vertex_buffer_len += layers_iter -> GetMapTiles().size() * (4 * (2 +
                2 + 2 + 2));
        index_buffer_len += layers_iter -> GetMapTiles().size() * 6;
    }

    vertex_buffer_data = new Memento::M_float[vertex_buffer_len];
    index_buffer_data = new Memento::M_uint[index_buffer_len];

    //fill data to send to the gl
    Memento::M_sizei vertex_buffer_iter = 0, index_buffer_iter = 0, index_buffer_quad_iter = 0;

    //map data
    const Memento::M_uint map_size_x = GetMapSize().x, map_size_y = GetMapSize().y;
    const Memento::M_float map_tile_size_x = GetTileSize().x, map_tile_size_y = GetTileSize().y;

    //per layer data
    std::vector<TmxMap::MapTile> const* map_tiles = NULL;
    std::vector<TmxMap::MapTile>::const_iterator map_tiles_iter, map_tiles_end;

    //per tile data
    Memento::M_float map_origin_x = 0.0f, map_origin_y = 0.0f;

    for(layers_iter = layers.begin(); layers_iter != layers_end; ++layers_iter){

        map_tiles = &layers_iter -> GetMapTiles();
        for(map_tiles_iter = map_tiles -> begin(), map_tiles_end = map_tiles -> end();
                map_tiles_iter != map_tiles_end; ++map_tiles_iter,
                vertex_buffer_iter += 4 * (2 + 2 + 2 +
                        2), index_buffer_iter += 6,
                        index_buffer_quad_iter += 4){

            map_origin_x = static_cast<Memento::M_float>(map_tiles_iter -> map_tile_index /
                    map_size_y) * map_tile_size_x;
            map_origin_y = static_cast<Memento::M_float>(map_tiles_iter -> map_tile_index %
                    map_size_y) * map_tile_size_y;

            vertex_buffer_data[vertex_buffer_iter] = map_origin_x;
            vertex_buffer_data[vertex_buffer_iter + 1] = map_origin_y;
            //=========================================================
            vertex_buffer_data[vertex_buffer_iter + 8] = map_origin_x;
            vertex_buffer_data[vertex_buffer_iter + 9] = map_origin_y + map_tile_size_y;
            //=========================================================
            vertex_buffer_data[vertex_buffer_iter + 16] = map_origin_x + map_tile_size_x;
            vertex_buffer_data[vertex_buffer_iter + 17] = map_origin_y + map_tile_size_y;
            //=========================================================
            vertex_buffer_data[vertex_buffer_iter + 24] = map_origin_x + map_tile_size_x;
            vertex_buffer_data[vertex_buffer_iter + 25] = map_origin_y;
            //=========================================================

            index_buffer_data[index_buffer_iter] = index_buffer_quad_iter;
            index_buffer_data[index_buffer_iter + 1] = index_buffer_quad_iter + 1;
            index_buffer_data[index_buffer_iter + 2] = index_buffer_quad_iter + 2;
            index_buffer_data[index_buffer_iter + 3] = index_buffer_quad_iter;
            index_buffer_data[index_buffer_iter + 4] = index_buffer_quad_iter + 2;
            index_buffer_data[index_buffer_iter + 5] = index_buffer_quad_iter + 3;
        }

    }

    vertex_buffer.Create(GL_ARRAY_BUFFER, GL_STATIC_DRAW);
    vertex_buffer.Bind();
    vertex_buffer.AllocateRef(vertex_buffer_len * sizeof(Memento::M_float),
            static_cast<const Memento::M_void*>(vertex_buffer_data));
    vertex_buffer.Unbind();

    index_buffer.Create(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW);
    index_buffer.Bind();
    index_buffer.AllocateRef(index_buffer_len * sizeof(Memento::M_uint),
            static_cast<const Memento::M_void*>(index_buffer_data));
    index_buffer.Unbind();

    delete[] vertex_buffer_data;
    delete[] index_buffer_data;
}

}

Vertex shader:

#version 140

precision highp float;

uniform mat4 modelviewprojection_matrix;

in vec2 map_vert;

void main(){
    gl_Position = modelviewprojection_matrix * vec4(map_vert, 0, 1);
}

Fragment shader:

#version 140

precision highp float;

out vec4 frag_color;

void main(){
    frag_color = vec4(0.4, 0.2, 0.6, 0.5);
}
Shokwav
  • 654
  • 8
  • 19
  • Where do you even define this map size? So I assume it defines the number of vertices or number of tiles? Does it work for 400 x 400 and lower? – Grimmy Jun 11 '13 at 05:38
  • @Grimmy: TmxMap::GameMap::CreateFromFile(file); defines all the map data. The map size defines the number of tiles, so 400x400 would mean 400 tiles on the x axis and 400 tiles on the y axis. And generally speaking (it depends on the tile size) it works up to about 700x700. Then I get no display. Very strange. – Shokwav Jun 11 '13 at 05:47
  • That all depends on the map data. I guess with size 800 you're reaching the point were one tile is one pixel? Not sure how it looks in 400 x 400 and what the colors represent here. – Grimmy Jun 11 '13 at 05:54
  • Inspect the coordinates for one tile. Maybe `x1 - x2` and `y1 - y2` = 0 – Grimmy Jun 11 '13 at 06:00
  • @Grammy: I see what you're saying, but the map doesn't stretch/shrink to compensate for the increase (It's not tied to a ratio). It's as simple as it displaying when it's 750x750, then I adjust it to 751x750 and everything disappears. I swear it's an overflow but there's no sign of one. Also, not sure what you mean by your second comment, I never subtract anything. – Shokwav Jun 11 '13 at 06:27
  • I see no error checking (say, `glGetError`) at all. You might exceed `GL_MAX_ELEMENTS_INDICES` or some other limit without knowing, or you might have a `GL_OUT_OF_MEMORY` or such. Impossible to know if you don't check. – Damon Jun 11 '13 at 09:49
  • @Damon: Forgot to mention I have intact checked glGetError with no issues. – Shokwav Jun 11 '13 at 16:11

1 Answers1

0

I think you are running out of stack memory.

By allocating the data on the heap you can use all the memory available to your process, while the stack is limited to 1MB.

In other words: Move the object allocation outside of the main scope to the global scope.

Memento::TextureAtlas * atlas1;//("atlas/cat_image.png", "atlas/cat_source.xml");
Memento::BufferGameMap * map1;//("tryagain.tmx", atlas1);

int main(){

    atlas1 =    new Memento::TextureAtlas("atlas/cat_image.png", "atlas/cat_source.xml");
    map1 =      new Memento::BufferGameMap("tryagain.tmx", atlas1);

    //.... acess with ->

}

or if this will not cause compiler errors:

Memento::TextureAtlas atlas1("atlas/cat_image.png", "atlas/cat_source.xml");
Memento::BufferGameMap map1("tryagain.tmx", atlas1);

int main(){
    //.... acess with .

}
Community
  • 1
  • 1
  • 1
    Running out of stack memory would result in an application crash, though. "OpenGL does not draw anything" is something different. Nevertheless, you make a fair point. – Damon Jun 11 '13 at 09:41
  • Maybe he try/catches without cathing anything? :P(I did that when I was working with memory hacking dlls). Let the OP try my solution, if it's not working then we can exclude stack overflow –  Jun 11 '13 at 09:42
  • @GamErix: Stack Overflow (not this Q&A forum) is one of those things you can't catch with an exception handler (just as you can't properly catch segfaults). – datenwolf Jun 11 '13 at 09:53
  • ah oki ;o Well something learnt by answering withmy toughts :P –  Jun 11 '13 at 09:54
  • 1
    Besides, using `new` and `std::vector` will always work on the heap. So this is definitely not the issue. – datenwolf Jun 11 '13 at 09:54
  • hm didn't know that! Then it's indeed another issue.. I think –  Jun 11 '13 at 09:56
  • Yeah, it's definately not stack overflow, as thought result in a crash. Plus, I'm doing most of my stuff on the heap – Shokwav Jun 11 '13 at 16:37