0

I am trying to batch multiple sprites into one large buffer but I am running into some technical difficulties. I think I am not setting up my vbo sizes correctly but let's see.

This currently renders only 1 colored quad, although I would like to render two.

int SPRITE_COUNT = 2;
cg_sprite** sprites;

float* v_buff;
float* c_buff;
float* t_buff;

vec4 *i0, *i1, *i2, *i3; //tmp vec4 used to hold pre transform vertex
vec4 *o0, *o1, *o2, *o3; //tmp vec4 used to hold pos transformed vertex

float v_buffer[16];   //tmp buffers to hold vertex data
float c_buffer[16];   //color

this is how I setup my vbo.

//setting up the buffers to hold concat vertex and color data
v_buff = (float*)calloc(
    1, (sizeof(float) * sizeof(sprites[0]->quad->vertices) * SPRITE_COUNT));
c_buff = (float*)calloc(
    1, (sizeof(float) * sizeof(sprites[0]->quad->colors) * SPRITE_COUNT));
t_buff = (float*)calloc(
    1,
    (sizeof(float) * sizeof(sprites[0]->quad->tex_coords) * SPRITE_COUNT));
i_buff = (short*)calloc(
    1, (sizeof(short) * sizeof(sprites[0]->quad->indices) * SPRITE_COUNT));

glGenBuffers(1, &vao);
glBindVertexArray(vao);

glEnableVertexAttribArray(0);
glGenBuffers(1, &vert_buff);
glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
glBufferData(GL_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->vertices), v_buff,
             GL_STREAM_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat),
                      (GLvoid*)0);

glEnableVertexAttribArray(1);
glGenBuffers(1, &col_buff);
glBindBuffer(GL_ARRAY_BUFFER, col_buff);
glBufferData(GL_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->colors), c_buff,
             GL_STREAM_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
                      (GLvoid*)0);

glGenBuffers(1, &ind_buff);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
             SPRITE_COUNT * sizeof(sprites[0]->quad->indices), i_buff,
             GL_STREAM_DRAW);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

here's a look at the sprite objects.

typedef struct {
    vec3 angles;
    GLshort vertex_count;
    GLfloat vertices[12];
    GLfloat colors[16];
    GLshort indices[6];
    GLfloat tex_coords[8];
} cg_quad;

typedef struct sprite {
    cg_quad* quad;
    vec3 scale;
    vec3 pos;
    vec3 angl;
    mat4 m_mat;
    GLuint texture_id;
}cg_sprite;

Since I am trying to draw to sprites, I manually create them like this: sprite function prototype:

cg_sprite* cg_sprite_new(const float x_pos, const float y_pos, const float z, const float w, const float h);

sprites = calloc(1, sizeof(cg_sprite*) * SPRITE_COUNT);
sprites[0] = cg_sprite_new(-100, 50, 0, 100, 100);
sprites[1] = cg_sprite_new(100, -50, 0, 100, 100);

I also create a bunch of temporary structures to use to do the calculations for each sprite, although I would like to simplify this if possible:

for(int i = 0; i < SPRITE_COUNT; i++) {
    i0 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i1 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i2 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    i3 = calloc(1, sizeof(vec4) * SPRITE_COUNT);

    o0 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o1 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o2 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
    o3 = calloc(1, sizeof(vec4) * SPRITE_COUNT);
}

this is the rendering loop:

void variable_render(double alpha) {
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(ce_get_default_shader()->shader_program);
    glBindVertexArray(vao);

    //--------------- update vertex data ---------------------
    for (int i = 0; i < SPRITE_COUNT; i++) {
        vmathT3MakeIdentity(&rot);
        vmathT3MakeIdentity(&scal);
        vmathT3MakeIdentity(&trns);
        vmathT3MakeIdentity(&tmp);

        vmathT3MakeScale(&scal, &sprites[i]->scale);
        vmathT3MakeRotationZYX(&rot, &sprites[i]->angl);
        vmathT3MakeTranslation(&trns, &sprites[i]->pos);
        vmathT3Mul(&tmp, &trns, &scal);  // scale then trnslate
        vmathT3Mul(&tmp, &tmp, &rot);    // scale then translate then rotate

        vmathM4MakeFromT3(&sprites[i]->m_mat, &tmp);

        cg_quad_getquadverts(&i0[i], &i1[i], &i2[i], &i3[i], sprites[i]->quad);
        vmathM4MulV4(&o0[i], &sprites[i]->m_mat, &i0[i]);
        vmathM4MulV4(&o1[i], &sprites[i]->m_mat, &i1[i]);
        vmathM4MulV4(&o2[i], &sprites[i]->m_mat, &i2[i]);
        vmathM4MulV4(&o3[i], &sprites[i]->m_mat, &i3[i]);

        v_buff[(i * 12) + 0] = o0[i].x; //copy over vertex data
        v_buff[(i * 12) + 1] = o0[i].y;
        v_buff[(i * 12) + 2] = o0[i].z;

        v_buff[(i * 12) + 3] = o1[i].x;
        v_buff[(i * 12) + 4] = o1[i].y;
        v_buff[(i * 12) + 5] = o1[i].z;

        v_buff[(i * 12) + 6] = o2[i].x;
        v_buff[(i * 12) + 7] = o2[i].y;
        v_buff[(i * 12) + 8] = o2[i].z;

        v_buff[(i * 12) + 9] = o3[i].x;
        v_buff[(i * 12) + 10] = o3[i].y;
        v_buff[(i * 12) + 11] = o3[i].z;

        c_buff[(i * 16) + 0] = sprites[i]->quad->colors[0]; //color
        c_buff[(i * 16) + 1] = sprites[i]->quad->colors[1];
        c_buff[(i * 16) + 2] = sprites[i]->quad->colors[2];
        c_buff[(i * 16) + 3] = sprites[i]->quad->colors[3];
        c_buff[(i * 16) + 4] = sprites[i]->quad->colors[4];
        c_buff[(i * 16) + 5] = sprites[i]->quad->colors[5];
        c_buff[(i * 16) + 6] = sprites[i]->quad->colors[6];
        c_buff[(i * 16) + 7] = sprites[i]->quad->colors[7];
        c_buff[(i * 16) + 8] = sprites[i]->quad->colors[8];
        c_buff[(i * 16) + 9] = sprites[i]->quad->colors[9];
        c_buff[(i * 16) + 10] = sprites[i]->quad->colors[10];
        c_buff[(i * 16) + 11] = sprites[i]->quad->colors[11];
        c_buff[(i * 16) + 12] = sprites[i]->quad->colors[12];
        c_buff[(i * 16) + 13] = sprites[i]->quad->colors[13];
        c_buff[(i * 16) + 14] = sprites[i]->quad->colors[14];
        c_buff[(i * 16) + 15] = sprites[i]->quad->colors[15];

        i_buff[(i * 6) + 0] = sprites[i]->quad->indices[0]; //indices
        i_buff[(i * 6) + 1] = sprites[i]->quad->indices[1];
        i_buff[(i * 6) + 2] = sprites[i]->quad->indices[2];

        i_buff[(i * 6) + 3] = sprites[i]->quad->indices[3];
        i_buff[(i * 6) + 4] = sprites[i]->quad->indices[4];
        i_buff[(i * 6) + 5] = sprites[i]->quad->indices[5];

        print_vbuff(v_buff, SPRITE_COUNT, "v_buffer");
        print_cbuff(c_buff, SPRITE_COUNT, "c_buffer");
        print_ibuff(i_buff, SPRITE_COUNT, "i_buffer");
    }

    vmathM4Mul(&mvp_mat, &p_mat, &v_mat);

    glUniformMatrix4fv(view_mat_loc, 1, GL_FALSE, vmathM4GetData(&v_mat));
    glUniformMatrix4fv(proj_mat_loc, 1, GL_FALSE, vmathM4GetData(&p_mat));
    glUniformMatrix4fv(mvp_matrix_loc, 1, GL_FALSE, vmathM4GetData(&mvp_mat));

    glBindBuffer(GL_ARRAY_BUFFER, vert_buff);
    glBufferData(GL_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->vertices), v_buff,
                 GL_STREAM_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, col_buff);
    glBufferData(GL_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->colors), c_buff,
                 GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind_buff);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 SPRITE_COUNT * sizeof(sprites[0]->quad->indices), i_buff,
                 GL_STREAM_DRAW);

    glDrawElements(GL_TRIANGLES, SPRITE_COUNT * sprites[0]->quad->vertex_count,
                   GL_UNSIGNED_SHORT, 0);

    glBindVertexArray(0);
}

currently this only draws 1 quad, it's colored correctly and the output from my logging look alright so I am not sure where am I going wrong.

here's a sample output from the above code.

void print_vbuff(float* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1 v2 v3                    \n"
            "-------------------------------------\n "
            "x%d   %3.0f %3.0f %3.0f %3.0f \n "
            "y%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n\n ",
            k, i[(12 * k) + 0], i[(12 * k) + 3], i[(12 * k) + 6],
            i[(12 * k) + 9], k, i[(12 * k) + 1], i[(12 * k) + 4],
            i[(12 * k) + 7], i[(12 * k) + 10], k, i[(12 * k) + 2],
            i[(12 * k) + 5], i[(12 * k) + 8], i[(12 * k) + 11]);
    }
    printf("\n\n\n");
}

void print_cbuff(float* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1 v2 v3                    \n"
            "-------------------------------------\n "
            "x%d   %3.0f %3.0f %3.0f %3.0f \n "
            "y%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n "
            "z%d   %3.0f %3.0f %3.0f %3.0f \n\n ",
            k, i[(16 * k) + 0], i[(16 * k) + 4], i[(16 * k) + 8],
            i[(16 * k) + 12], k, i[(16 * k) + 1], i[(16 * k) + 5],
            i[(16 * k) + 9], i[(16 * k) + 13], k, i[(16 * k) + 2],
            i[(16 * k) + 6], i[(16 * k) + 10], i[(16 * k) + 14], k,
            i[(16 * k) + 3], i[(16 * k) + 7], i[(16 * k) + 11],
            i[(16 * k) + 15]);
    }
    printf("\n\n\n");
}

void print_ibuff(short* i, int count, char* tag) {
    printf("%s\n", tag);
    for (int k = 0; k < count; k++) {
        printf(
            "      v0 v1                          \n"
            "-------------------------------------\n "
            "x%d  %3d %3d \n "
            "y%d  %3d %3d \n "
            "z%d  %3d %3d \n\n ",
            k, i[(6 * k) + 0], i[(6 * k) + 3], k, i[(6 * k) + 1],
            i[(6 * k) + 4], k, i[(6 * k) + 2], i[(6 * k) + 5]);
    }
    printf("\n\n\n");
}

this is some example output from running this code:

v_buffer
      v0 v1 v2 v3
-------------------------------------
 x0   -50 -50  50  50
 y0   -50  50  50 -50
 z0     0   0   0   0

       v0 v1 v2 v3
-------------------------------------
 x1   -50 -50  50  50
 y1   -50  50  50 -50
 z1     0   0   0   0




c_buffer
      v0 v1 v2 v3
-------------------------------------
 x0     1   0   0   1
 y0     0   1   0   1
 z0     0   0   1   0
 z0     1   1   1   1

       v0 v1 v2 v3
-------------------------------------
 x1     1   0   0   1
 y1     0   1   0   1
 z1     0   0   1   0
 z1     1   1   1   1




i_buffer
      v0 v1
-------------------------------------
 x0    0   0
 y0    1   2
 z0    2   3

       v0 v1
-------------------------------------
 x1    0   0
 y1    1   2
 z1    2   3

image:enter image description here

am I setting up my opengl buffers incorrectly? Why is it rendering only one quad? Especially when the output shows the vertex information and color information for both quads in the v_buff data structure?

I don't understand why I am only rendering 1 quad.

user1610950
  • 1,837
  • 5
  • 33
  • 49
  • Are you uploading more than one quad of index data? To me it looks like you're only uploading 1 quad in your index buffer. – Henk De Boer Jan 12 '16 at 10:14
  • Initially I wasn't but I created another buffer to hold all the indices, fill it up and upload it and still, it only renders one quad. – user1610950 Jan 12 '16 at 10:59
  • I made an edit and updated the code with filling a buffer for only the indices as well, but still only rendering 1 quad. – user1610950 Jan 12 '16 at 11:15

1 Answers1

0

Each time you use glBufferData you pass SPRITE_COUNT * 48 (or 64) without multiplying it by sizeof(float). It didn't backfired at you yet.

Your GL_ELEMENT_ARRAY_BUFFER is set to sprites[0]->quad->indices and never updated. spires[1] never contributes to indices. You need to append each sprite to index buffer, with index shift applied (or draw with base vertex parameter specified).

void quad_copy(void* dest, size_t dest_index, cg_quad* q) {
    memcpy(&dest[dest_index], &q->vertices, 12 * sizeof(float));
}

Probably just copypaste error, typeof(dest) is void*, you cannot directly dereference it with array index, it should result in compilation error.

With sofrware transform you'll have poor performance, but that is different matter.

Explaination of index offset, as requested:

Having vertex array (let's say it is positions, but in terms of GL all arrays share the same indices, so doesn't really matter), your first quad's vertices A1, B1, C1 and D1 placed linearly in array:

|A1B1C1D1|

So vertex indices are 0, 1, 2 and 3.

Now adding second quad to arrays tail:

|A1B1C1D1A2B2C2D2|

Index of A2 - first vertex of second quad - is no longer zero, as it was in separate array, but 4. This is second quad's 'base index' (often called 'base vertex') - basically offset from beginning of vertex array where this object's data starts. Third quad will start at index 8, and so on.

In generic case, you need to save current number of vertices in array, and use it as base index when appending another object, but because your case is simple and you only have quads (and not arbitrary-sized objects) you can easily convert objectc count to base index. Since each quad have only 4 unique vertices, each quad occupy 4 indices, so base index for quad N is N*4.

keltar
  • 17,711
  • 2
  • 37
  • 42
  • I made those edits but it still only renders the one quad. – user1610950 Jan 12 '16 at 10:59
  • You didn't add offset to indices, e.g. `i_buff[(i * 6) + 0] = i*6 + sprites[i]->quad->indices[0];`, if each quad have 6 vertices - since quad2 vertices starts where quad1 vertices ends, not at 0. Also size of index buffer, if I'm not mistaken, is `SPRITE_COUNT * sizeof(sprites[0]->quad->indices)`. – keltar Jan 12 '16 at 11:41
  • I used the raw numbers, ex: `SPRITE_COUNT * 48 because SPRITE_COUNT * sizeof(sprite[0]->quad->indices)` is a bit verbose although they are both 12 bytes so that function still evaluates out to 24 bytes atm. Can expand more on adding the offset? I wrote a function to print out the index buffer that I built and it's showing what seems to be the correct output. – user1610950 Jan 12 '16 at 12:11
  • Well I don't see the rest of your code; you do. What's your actual index buffer values, from 0 to 11th element? Also with linear indices you probably could just use `glDrawArrays` for now and see how it works. – keltar Jan 12 '16 at 12:17
  • I updated the the post, I only have 6 indices 0, 1, 2, 0,2,3. I have 4 vertices 3 floats each and I have 4 colors 4 floats so that each corner can have a distinct color. – user1610950 Jan 12 '16 at 12:30
  • 1
    As expected, indices are wrong. Index is a place where you put data in vertex buffer; you have 3 indices per triangle, one for each vertex. Your index output is misleading; you have 2 triangles, [0, 1, 2] and [0, 2, 3]. Ok for first quad, but second quad's data starts at index 4 (my bad, I refered to 6 in comment above), so its indices should be [4, 5, 6] and [4, 6, 7] (basically adding `i*4` to each element). With your current indices your `DrawElements` draws exactly the same quad twice. – keltar Jan 12 '16 at 12:38
  • are you saying i * 4 for each index? Could you elaborate a bit more? Changing the indicies to i*4, it only renders 1/2 of a triangle, the upper left hand side. – user1610950 Jan 12 '16 at 12:47
  • e.g. `i_buff[(i * 6) + 0] = i*4 + sprites[i]->quad->indices[0];` when forming index buffer, and the same for the rest. – keltar Jan 12 '16 at 12:49
  • that worked in getting the quads to show up. Although the second quad is all white. Can you write an answer as to why I needed the i * 4 and maybe why the second quad is white? – user1610950 Jan 12 '16 at 13:07
  • edit, I didn't need the i * 4 for the colors but I did need them for the vertex and index positions. but still, if you can expand on your answer as to why I needed the i * 4 in an answer so that I can accept it! – user1610950 Jan 12 '16 at 13:09