Gnampf
Gnampf

Reputation: 995

glMultiDrawArrays buffering

This might be again some stupid question and perhaps it's something really obvious what I am missing, but I having trouble to get glMultiDrawArrays working in OpenGL4.

I found plenty of explanations like this:

for (int i = 0; i < numarrays; i++)
    glDrawArrays (GL_TRIANGLE_FAN, arrayfirsts[i], arraycounts[i]);

is similar to that:

glMultiDrawArrays (GL_TRIANGLE_FAN, arrayfirsts, arraycounts, numarrays);

And I am perfectly fine with that explanation. However, what I couldn't find out so far is- how has buffering to be done when I want to use glMultiDrawArrays?

Currently I have my code like this:

UINT vertssize = FloatsPerVertex * 4;
UINT texsize = TexCoords2D * 4;

VertsBuf[0] = RFX2*Z*(X - FX2);
VertsBuf[1] = RFY2*Z*(Y - FY2);
VertsBuf[2] = Z;
VertsBuf[3] = (U)*TexInfo[0].UMult;
VertsBuf[4] = (V)*TexInfo[0].VMult;

VertsBuf[5] = RFX2*Z*(X + XL - FX2);
VertsBuf[6] = RFY2*Z*(Y - FY2);
VertsBuf[7] = Z;
VertsBuf[8] = (U + UL)*TexInfo[0].UMult;
VertsBuf[9] = (V)*TexInfo[0].VMult;

VertsBuf[10] = RFX2*Z*(X + XL - FX2);
VertsBuf[11] = RFY2*Z*(Y + YL - FY2);
VertsBuf[12] = Z;
VertsBuf[13] = (U + UL)*TexInfo[0].UMult;
VertsBuf[14] = (V + VL)*TexInfo[0].VMult;

VertsBuf[15] = RFX2*Z*(X - FX2);
VertsBuf[16] = RFY2*Z*(Y + YL - FY2);
VertsBuf[17] = Z;
VertsBuf[18] = (U)*TexInfo[0].UMult;
VertsBuf[19] = (V + VL)*TexInfo[0].VMult;

DrawVerts(DrawVertsBuf, vertssize, texsize, Color);

with DrawVerts looking like that:

void DrawVerts(FLOAT* verts, UINT vertsize, UINT texsize, vec4f DrawColor)
{
    UINT TotalSize = vertsize + texsize;
    UINT stride = (sizeof(float) * FloatsPerVertex) + (sizeof(float) * TexCoords2D);
    UINT vertoffset = (sizeof(float) * FloatsPerVertex);

    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * TotalSize, verts, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(VERTEX_COORD_ATTRIB);
    glEnableVertexAttribArray(TEXTURE_COORD_ATTRIB);
    glVertexAttribPointer(VERTEX_COORD_ATTRIB, 3, GL_FLOAT, GL_FALSE, stride, 0);
    glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, stride, (void*)vertoffset);

    glUniform4f(DrawTileDrawColor, DrawColor.X, DrawColor.Y, DrawColor.Z, DrawColor.W);

    // Draw
    glDrawArrays(GL_TRIANGLE_FAN, 0, vertsize / FloatsPerVertex);

    // Clean up
    glDisableVertexAttribArray(VERTEX_COORD_ATTRIB);
    glDisableVertexAttribArray(TEXTURE_COORD_ATTRIB);
}

How do I have to change that in order to call successfully glMultiDrawArrays? Of course I do have to add a counter then, that's obvious. I also tried some, but only ended up in crashing or no drawing so far. Tutorials and examples I found either spare the buffering part or they are for OpenGL1.x which I understand moving over to OpenGL4. Currently its called up to 1000 times and I want to give it a try to optimize my code with it.

Upvotes: 1

Views: 2936

Answers (1)

keltar
keltar

Reputation: 18389

Here is an example drawing two quads:

#include <stdio.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/glut.h>

typedef struct {
    int elements_count;
    float *array;
} fan_s;


GLuint vbo_id;
#define VBO_SIZE 4096

static void setup_vbo(void) {
    glGenBuffers(1, &vbo_id);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
    glBufferData(GL_ARRAY_BUFFER, VBO_SIZE, NULL, GL_DYNAMIC_DRAW);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 0, 0);
}

static void draw_fans(const fan_s *fans, int num_fans) {
#define MAX_FANS 1024
    GLint fans_starts[MAX_FANS];
    GLsizei fans_sizes[MAX_FANS];

    float *mapping = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);

    int i;
    int num_elements_total = 0;
    for(i = 0; i != num_fans; ++i) {
        memcpy(mapping, fans[i].array, fans[i].elements_count * 3 * sizeof(float));
        mapping += fans[i].elements_count * 3;

        fans_starts[i] = num_elements_total;
        fans_sizes[i] = fans[i].elements_count;

        num_elements_total += fans[i].elements_count;
    }

    glUnmapBuffer(GL_ARRAY_BUFFER);

    glMultiDrawArrays(GL_TRIANGLE_FAN, fans_starts, fans_sizes, num_fans);
}

static void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);

    float fan0_data[] = {
        0.0, 0.0, 0.0,
        0.0, 100.0, 0.0,
        100.0, 100.0, 0.0,
        100.0, 0.0, 0.0
    };
    float fan1_data[] = {
        200.0, 0.0, 0.0,
        200.0, 100.0, 0.0,
        300.0, 100.0, 0.0,
        300.0, 0.0, 0.0
    };
    fan_s fans[] = {
        4, fan0_data,
        4, fan1_data
    };
    draw_fans(fans, 2);

    glutSwapBuffers();
}

static void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, w, h, 0);
    glMatrixMode(GL_MODELVIEW);
}

static void keyboard(unsigned char key, int x, int y) {
    if(key == 27) {
        exit(0);
    }
}

int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(500, 150);
    glutCreateWindow("");

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glColor4f(1.0, 1.0, 1.0, 1.0);
    glewInit();

    setup_vbo();

    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);

    glutMainLoop();

    return 0;
}

For simplicity sake, I haven't checked any errors, including overflow (see VBO_SIZE and MAX_FANS).

Upvotes: 2

Related Questions