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:
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.
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.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 days ago.
Improve this question
I am unsure why this torus is going vertical and not horizontal:
I've tried adjusting float currentAngle but that just spins it on it's axis, it doesn't lay it down. I don't think it's the glm::translate() settings for that is just moving the object on the x,y,and z axis.
// Roll of Tape
ShapeData ShapeGenerator::makeTapeRoll(uint tesselation)
{
ShapeData ret;
ret.numVertices = tesselation * 4;
ret.vertices = new Vertex[ret.numVertices];
float cylinderHeight = 0.05f;
float cylinderRadius = 0.05f;
float sphereRadius = cylinderRadius * 1.5f;
float currentAngle = -45.0f;
float angleIncrement = (2.0f * PI) / tesselation;
for (uint i = 0; i < tesselation; i++)
{
float x1 = sphereRadius * cos(currentAngle);
float y1 = sphereRadius * sin(currentAngle);
float x2 = cylinderRadius * cos(currentAngle);
float y2 = cylinderRadius * sin(currentAngle);
ret.vertices[i].position = vec3(x1, y1, sphereRadius);
ret.vertices[i].color = randomColor();
ret.vertices[i + tesselation].position = vec3(x2, y2, sphereRadius + cylinderHeight);
ret.vertices[i + tesselation].color = randomColor();
ret.vertices[i + tesselation * 2].position = vec3(x2, y2, sphereRadius);
ret.vertices[i + tesselation * 2].color = randomColor();
ret.vertices[i + tesselation * 3].position = vec3(x1, y1, sphereRadius - cylinderHeight);
ret.vertices[i + tesselation * 3].color = randomColor();
currentAngle += angleIncrement;
}
ret.numIndices = tesselation * 6;
ret.indices = new GLushort[ret.numIndices];
for (uint i = 0; i < tesselation; i++)
{
ret.indices[i * 6] = i;
ret.indices[i * 6 + 1] = (i + 1) % tesselation;
ret.indices[i * 6 + 2] = i + tesselation;
ret.indices[i * 6 + 3] = (i + 1) % tesselation;
ret.indices[i * 6 + 4] = (i + 1) % tesselation + tesselation;
ret.indices[i * 6 + 5] = i + tesselation;
}
return ret;
}
ShapeData tapeRoll = ShapeGenerator::makeTapeRoll(64);
unsigned int tapeRollIndexByteOffset = 0;
unsigned int tapeRollNumIndices = 0;
unsigned int tapeRollVBO{}, tapeRollVAO;
glGenVertexArrays(1, &tapeRollVAO);
glGenBuffers(1, &tapeRollVBO);
glBindVertexArray(tapeRollVAO);
glBindBuffer(GL_ARRAY_BUFFER, tapeRollVBO);
glBufferData(GL_ARRAY_BUFFER, tapeRoll.vertexBufferSize() + tapeRoll.indexBufferSize(), 0, GL_STATIC_DRAW);
currentOffset = 0;
glBufferSubData(GL_ARRAY_BUFFER, currentOffset, tapeRoll.vertexBufferSize(), tapeRoll.vertices);
currentOffset += tapeRoll.vertexBufferSize();
tapeRollIndexByteOffset = currentOffset;
glBufferSubData(GL_ARRAY_BUFFER, currentOffset, tapeRoll.indexBufferSize(), tapeRoll.indices);
tapeRollNumIndices = tapeRoll.numIndices;
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, VERTEX_BYTE_SIZE, (void*)0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, VERTEX_BYTE_SIZE, (void*)(sizeof(float) * 3));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, VERTEX_BYTE_SIZE, (void*)(sizeof(float) * 6));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, tapeRollVBO);
// setup to draw tapeRoll
glBindTexture(GL_TEXTURE_2D, tapeDiffuseMap);
glBindVertexArray(tapeRollVAO);
model = model = glm::mat4(0.8f);
model = glm::translate(model, glm::vec3(2.3f, -0.3f, 3.0f));
model = glm::scale(model, glm::vec3(3.0f));
lightingShader.setMat4("model", model);
// draw tapeRoll
glDrawElements(GL_TRIANGLES, tapeRollNumIndices, GL_UNSIGNED_SHORT, (void*)tapeRollIndexByteOffset);
I work on particles system and I want to use SSBO to make update of velocity and position on my particles with compute shader. But I see for each update-call the compute use same values of positions but compute update position because in draw-call particles are moved.
Load particles into SSBOs
// Load Positions
glGenBuffers(1, &m_SSBOpos);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_SSBOpos);
// Allocation de la mémoire vidéo
glBufferData(GL_SHADER_STORAGE_BUFFER, pb.size() * 4 * sizeof(float), NULL, GL_STATIC_DRAW);
GLint bufMask = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT; // the invalidate makes a big difference when re-writing
float *points = (float *) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, pb.size() * 4 * sizeof(float), bufMask);
for (int i = 0; i < pb.size(); i++)
{
points[i * 4] = pb.at(i).m_Position.x;
points[i * 4 + 1] = pb.at(i).m_Position.y;
points[i * 4 + 2] = pb.at(i).m_Position.z;
points[i * 4 + 3] = 0;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
// Load vélocité
glGenBuffers(1, &m_SSBOvel);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_SSBOvel);
// Allocation de la mémoire vidéo
glBufferData(GL_SHADER_STORAGE_BUFFER, pb.size() * 4 * sizeof(float), NULL, GL_STATIC_DRAW);
float *vels = (float *)glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, pb.size() * 4 * sizeof(float), bufMask);
for (int i = 0; i < pb.size(); i++)
{
vels[i * 4] = pb.at(i).m_Velocity.x;
vels[i * 4 + 1] = pb.at(i).m_Velocity.y;
vels[i * 4 + 2] = pb.at(i).m_Velocity.z;
vels[i * 4 + 3] = 0;
}
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
Update
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, shaderUtil.getSSBOpos());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, shaderUtil.getSSBOvel());
// UPDATE DES PARTICULES
shaderUtil.UseCompute();
glUniform1i(shaderUtil.getDT(), fDeltaTime);
glDispatchCompute(NUM_PARTICLES / WORK_GROUP_SIZE, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
shaderUtil.DeleteCompute();
Draw
shaderUtil.Use();
glUniformMatrix4fv(glGetUniformLocation(shaderUtil.getProgramID(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(glGetUniformLocation(shaderUtil.getProgramID(), "modelview"), 1, GL_FALSE, glm::value_ptr(View * Model));
glPointSize(10);
// Rendu
glBindBuffer(GL_ARRAY_BUFFER, shaderUtil.getSSBOpos());
glVertexPointer(4, GL_FLOAT, 0, (void *)0);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
shaderUtil.Delete();
Comput shader
#version 430 compatibility
#extension GL_ARB_compute_shader : enable
#extension GL_ARB_shader_storage_buffer_object : enable
layout(std140, binding = 4) buffer Pos
{
vec4 Positions[]; // array of structures
};
layout(std140, binding = 5) buffer Vel
{
vec4 Velocities[]; // array of structures
};
uniform float dt;
layout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in;
void main()
{
uint numParticule = gl_GlobalInvocationID.x;
vec4 v = Velocities[numParticule];
vec4 p = Positions[numParticule];
vec4 tmp = vec4(0, -9.81, 0,0) + v * (0.001 / (7. / 1000.));
v += tmp ;
Velocities[numParticule] = v;
p += v ;
Positions[numParticule] = p;
}
Do you know why it's happened ?
I try to implement transforms in my 2D graphics program but I encounter a mystery (even if it's a noob topic, sorry).
My example code tries to translates a quad to the center of the screen then rotate by 45 degrees with the center as a pivot but something goes wrong.
The order of the matrix operation was taken from learnopengl.com
https://learnopengl.com/code_viewer.php?code=in-practice/breakout/sprite_renderer
import math
type
OGLfloat = float32
OGLuint = uint32
OGLint = int32
const
POSITION_LENGTH = 3.OGLint
COLOR_LENGTH = 4.OGLint
const
WINDOW_W = 640
WINDOW_H = 480
let
colorDataOffset = POSITION_LENGTH * OGLint(sizeof(OGLfloat))
#[ Then many Opengl constants and functions translation from C, not pasted here.
Nim users knows it's easy to do.]#
var
vertices = #[OGLfloat(-1.0), 1.0, 0, # Position
0, 0, 1, 1, # Color
0, 1.0, 0,
0, 0, 1, 1,
0, 0, 0,
0, 0, 1, 1,
-1.0, 0.0, 0,
0, 0, 1, 1
]
indices = #[OGLuint(0), 1, 2, 2, 3, 0]
type Mat4x4* = array[16, OGLfloat] # 4 x 4 Matrix
# The operation who will concatenate the translation, rotation and scaling matrices.
proc `*`(a, b:Mat4x4):Mat4x4 =
result[0] = a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3]
result[1] = a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3]
result[2] = a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3]
result[3] = a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3]
result[4] = a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7]
result[5] = a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7]
result[6] = a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7]
result[7] = a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7]
result[8] = a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11]
result[9] = a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11]
result[10] = a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11]
result[11] = a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11]
result[12] = a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15]
result[13] = a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15]
result[14] = a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15]
result[15] = a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15]
proc rotation2D(deg:float):Mat4x4 =
let
rad = PI * deg / 180 # convert degrees to radians
s = OGLfloat(sin(rad))
c = OGLfloat(cos(rad))
result = [c, s, 0, 0,
- s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]
proc translation(x,y:float):Mat4x4 = #{.noInit.} =
result = [OGLfloat(1), 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, 0, 1]
proc scaling(x,y:float):Mat4x4 =
result = [OGLfloat(x), 0, 0, 0,
0, y, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1]
var
#[ The order of the operations was taken from "learnopengl.com"
but without the help of GLM, thanks to the previous functions.]#
modelMatrix = translation(1.0, -1.0) * # move to the screen center
translation(-0.5, 0.5) * # move to the quad center
rotation2D(45.0) * # rotation on Z axis
translation(0.5, -0.5) * # re-move to the quad center ???
scaling(1.0, 1.0) # change nothing with these values.
# Init the system and pop the window.
var glfwErr = glfwInit()
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3)
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)
var winHandle = glfwCreateWindow(WINDOW_W, WINDOW_H)
glfwMakeContextCurrent(winHandle)
var glewErr = glewInit()
# Shaders
var
shadID:OGLuint
vertSrc:cstring = """
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;
out vec4 vColor;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(aPos, 1.0f);
vColor = aColor;
}
"""
fragSrc:cstring = """
#version 330 core
out vec4 FragColor;
in vec4 vColor;
void main()
{
FragColor = vColor;
}
"""
# opengl stuff for sending the shader text and the vertices.
proc send_src(vert:var cstring, frag:var cstring):OGLuint =
var success:OGLint
# vertex
var vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, 1, addr vert, nil)
glCompileShader(vertexShader)
# Check compilation errors.
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, addr success)
if bool(success) == false:
echo(" vertex shader compilation failed (send_src)")
else:
echo("vertexShader compiled (send_src)")
# fragment
var fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, 1, addr frag, nil)
glCompileShader(fragmentShader)
# Check compilation errors.
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, addr success)
if bool(success) == false:
echo("fragment shader compilation failed (send_src)")
else:
echo("fragmentShader compiled (send_src)")
# Shader program
result = glCreateProgram()
glAttachShader(result, vertexShader)
glAttachShader(result, fragmentShader)
glLinkProgram(result)
# Check for linkage errors.
glGetProgramiv(result, GL_LINK_STATUS, addr success)
if success == 0:
echo("program linking failed (send_src)")
else:
echo("shader linked (send_src)")
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
glViewport(0, 0, WINDOW_W, WINDOW_H)
shadID = send_src(vertSrc, fragSrc)
var VAO, VBO, EBO:OGLuint
glGenVertexArrays(1, addr VAO)
glGenBuffers(1, addr VBO)
glGenBuffers(1, addr EBO)
glBindVertexArray(VAO)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.len * sizeof(OGLfloat),
addr vertices[0], GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.len * sizeof(OGLuint),
addr indices[0], GL_STATIC_DRAW)
# Position layout
glVertexAttribPointer(0, POSITION_LENGTH, GL_FLOAT, GL_FALSE, (POSITION_LENGTH + COLOR_LENGTH) * OGLint(sizeof(OGLfloat)),
nil)
glEnableVertexAttribArray(0)
# Color layout
glVertexAttribPointer(1, COLOR_LENGTH, GL_FLOAT, GL_FALSE, (POSITION_LENGTH + COLOR_LENGTH) * OGLint(sizeof(OGLfloat)),
cast[pointer](colorDataOffset))
glEnableVertexAttribArray(1)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glUseProgram(shadID)
# The render loop.
while bool(glfwWindowShouldClose(winHandle)) == false:
glClearColor(0.2, 0.3, 0.3, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
glBindVertexArray(VAO)
glUniformMatrix4fv(glGetUniformLocation(shadID, "model"), 1, char(false), addr modelMatrix[0])
glDrawElements(GL_TRIANGLES, OGLint(indices.len), GL_UNSIGNED_INT, nil)
glfwSwapBuffers(winHandle)
glfwPollEvents()
glDeleteVertexArrays(1, addr VAO)
glDeleteBuffers(1, addr VBO)
glDeleteBuffers(1, addr EBO)
glfwDestroyWindow(winHandle)
glfwTerminate()
And here's the result.
I wish you a happy holiday season.
Since the viewport is rectangular you have to take into account the aspect ratio of the viewport.
Calculate the aspect ration (aspect) of the viewport, which is the width of the viewport divided by its height.
Apply a simple view matrix, to the transformation. The view matrix is a simply scaling of the x axis, by the reciprocal aspect ratio (1.0/aspect).
It is sufficient to move the quad to the enter of the screen first and rotate it then:
modelMatrix = scaling(1.0/aspect, 1.0) * # aspect ratio
rotation2D(45.0) * # rotation on Z axis
translation(0.5, -0.5) * # move to the center of the screen
scaling(1.0, 1.0) # change nothing with these values.
Note, according to the matrix initialization and multiplication operator a transformation followed by a rotation has to be transformed as follows:
model = rotate * translate(-pivot_x, -pivot_y)
See GLSL Programming/Vector and Matrix Operations.
Preview:
Note alternatively you can add a separated (orthographic) projection matrix to the shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;
out vec4 vColor;
uniform mat4 project;
uniform mat4 model;
void main()
{
gl_Position = project * model * vec4(aPos, 1.0f);
vColor = aColor;
}
projMatrix = scaling(1.0/aspect, 1.0)
modelMatrix = rotation2D(45.0) * # rotation on Z axis
translation(0.5, -0.5) * # move to the center of the screen
scaling(1.0, 1.0) # change nothing with these values.
glUniformMatrix4fv(glGetUniformLocation(shadID, "project"), 1, char(false), addr projMatrix[0])
glUniformMatrix4fv(glGetUniformLocation(shadID, "model"), 1, char(false), addr modelMatrix[0])
If you want to rotate around a pivot (pivot_x, pivot_y), then you have to
model = translate(pivot_x, pivot_y) * rotate * translate(-pivot_x, -pivot_y)
e.g. pivot (-0.5, 0.5)
modelMatrix = translation(-0.5, 0.5) * # pivot
rotation2D(45.0) * # rotation on Z axis
translation(0.5, -0.5) * # inverted pivot
scaling(1.0, 1.0)
Preview:
If you finally want to move the pivot of the quad to the center of the screen, then you have to:
model =
translate(widht/2 - pivot_x, height/2 - pivot_y) *
translate(pivot_x, pivot_y) * rotate * translate(-pivot_x, -pivot_y)
e.g.
modelMatrix = translation(float(WINDOW_W/2)-100, float(WINDOW_H/2)-100) *
translation(100, 100) *
rotation2D(45.0) *
translation(-100, -100) *
scaling(1.0, 1.0)
Which is the same as:
model = translate(widht/2, height/2) * rotate * translate(-pivot_x, -pivot_y)
modelMatrix = translation(float(WINDOW_W/2), float(WINDOW_H/2)) *
rotation2D(45.0) *
translation(-100, -100) *
scaling(1.0, 1.0)
I have an array of GLfloats that I use as positions and colors when I draw quads (so 4 floats per vertex). I'd like to add the ability to color my quads as well and figured I would pack the RGBA into a single GLuint and then send that to the GPU along with the positions.
So, can I somehow send 4 GLfloats and then 1 GLuint to the GPU?
Here's the relevant code:
void SpriteRenderer::Init()
{
vertexBufferArrayInserts = 0;
hasBegun = GL_FALSE;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * MAX_VERTEX_BUFFER_SIZE, 0, GL_STREAM_DRAW);
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * MAX_ELEMENT_BUFFER_SIZE, 0, GL_STREAM_DRAW);
//////////////////////////////////////////////////////////////////////////
//LOAD SHADER, CREATE AND USE PROGRAM
//////////////////////////////////////////////////////////////////////////
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
vertexShaderID = LoadShaderFromFile("Shader", GL_VERTEX_SHADER);
fragmentShaderID = LoadShaderFromFile("Shader", GL_FRAGMENT_SHADER);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShaderID);
glAttachShader(shaderProgram, fragmentShaderID);
glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
glUseProgram(shaderProgram);
shaderPosAttrib = glGetAttribLocation(shaderProgram, "position");
glVertexAttribPointer(shaderPosAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
glEnableVertexAttribArray(shaderPosAttrib);
shaderTexCoordAttrib = glGetAttribLocation(shaderProgram, "texCoord");
glVertexAttribPointer(shaderTexCoordAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 2));
glEnableVertexAttribArray(shaderTexCoordAttrib);
shaderColorAttrib = glGetAttribLocation(shaderProgram, "Color");
glVertexAttribPointer(shaderColorAttrib, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 4));
glEnableVertexAttribArray(shaderColorAttrib);
shaderProjMatAttrib = glGetUniformLocation(shaderProgram, "projMat");
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void SpriteRenderer::Draw(Vector2<GLfloat> position, Rect clipRect)
{
//TOP LEFT
vertexBufferArray[vertexBufferArrayInserts * 16] = position.X;
vertexBufferArray[vertexBufferArrayInserts * 16 + 1] = position.Y;
vertexBufferArray[vertexBufferArrayInserts * 16 + 2] = clipRect.GetLeftX() / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 3] = clipRect.GetTopY() / 512.0f;
colorBufferArray[vertexBufferArrayInserts * 4] = PackColor(255, 255, 255, 255);
//TOP RIGHT
vertexBufferArray[vertexBufferArrayInserts * 16 + 4] = position.X + clipRect.GetWidth();
vertexBufferArray[vertexBufferArrayInserts * 16 + 5] = position.Y;
vertexBufferArray[vertexBufferArrayInserts * 16 + 6] = clipRect.GetRightX() / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 7] = clipRect.GetTopY() / 512.0f;
colorBufferArray[vertexBufferArrayInserts * 4 + 1] = PackColor(255, 255, 255, 255);
//BOTTOM RIGHT
vertexBufferArray[vertexBufferArrayInserts * 16 + 8] = position.X + clipRect.GetWidth();
vertexBufferArray[vertexBufferArrayInserts * 16 + 9] = position.Y + clipRect.GetHeight();
vertexBufferArray[vertexBufferArrayInserts * 16 + 10] = clipRect.GetRightX() / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 11] = clipRect.GetBottomY() / 512.0f;
colorBufferArray[vertexBufferArrayInserts * 4 + 2] = PackColor(255, 255, 255, 255);
//BOTTOM LEFT
vertexBufferArray[vertexBufferArrayInserts * 16 + 12] = position.X;
vertexBufferArray[vertexBufferArrayInserts * 16 + 13] = position.Y + clipRect.GetHeight();
vertexBufferArray[vertexBufferArrayInserts * 16 + 14] = clipRect.GetLeftX() / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 15] = clipRect.GetBottomY() / 512.0f;
colorBufferArray[vertexBufferArrayInserts * 4 + 3] = PackColor(255, 255, 255, 255);
//ELEMENT BUFFER
elementBufferArray[vertexBufferArrayInserts * 6] = vertexBufferArrayInserts * 4;
elementBufferArray[vertexBufferArrayInserts * 6 + 1] = vertexBufferArrayInserts * 4 + 1;
elementBufferArray[vertexBufferArrayInserts * 6 + 2] = vertexBufferArrayInserts * 4 + 2;
elementBufferArray[vertexBufferArrayInserts * 6 + 3] = vertexBufferArrayInserts * 4 + 2;
elementBufferArray[vertexBufferArrayInserts * 6 + 4] = vertexBufferArrayInserts * 4 + 3;
elementBufferArray[vertexBufferArrayInserts * 6 + 5] = vertexBufferArrayInserts * 4;
vertexBufferArrayInserts++;
if(vertexBufferArrayInserts == MAX_BUFFER_INSERTS)
Draw();
}
void SpriteRenderer::Draw()
{
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * vertexBufferArrayInserts * 16, vertexBufferArray);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertexBufferArrayInserts * 16, sizeof(GLuint) * vertexBufferArrayInserts * 4, colorBufferArray);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(GLint) * vertexBufferArrayInserts * 6, elementBufferArray);
glDrawElements(GL_TRIANGLES, vertexBufferArrayInserts * 6, GL_UNSIGNED_INT, 0);
vertexBufferArrayInserts = 0;
}
GLuint SpriteRenderer::PackColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) {
GLint returnVal = (r << 24) + (g << 16) + (b << 8) + a;
return returnVal;
}
Your problem lies in:
glVertexAttribPointer(shaderColorAttrib, 1, GL_UNSIGNED_INT,
GL_FALSE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 4));
This will be unpacked as a single component.
Tell the GPU that you are sending four one-byte components (which adds up to a single 32-bit value):
glVertexAttribPointer(shaderColorAttrib, 4, GL_UNSIGNED_BYTE,
GL_TRUE, sizeof(GLfloat) * 5, (void*)(sizeof(GLfloat) * 4));
Note that I set the normalized flag to true. Do this if you're sending this to a vec4 on the shader so that each component is convert to the [0,1] range you likely want it in.
Also, instead of doing the very error-prone math with sizeof(float), consider making a struct and using the size of that struct and offsetof to generate your stride and vertex offsets:
struct vertex {
float4 position;
ubyte4 color;
};
glVertexAttribPointer(shaderColorAttrib, 4, GL_FLOAT,
GL_FALSE, sizeof(vertex), offsetof(vertex, position));
glVertexAttribPointer(shaderColorAttrib, 4, GL_UNSIGNED_BYTE,
GL_TRUE, sizeof(vertex), offsetof(vertex, color));
This becomes way more critical once you start mixing data types. Just be aware of struct padding; using offsetof will ensure things work, but you don't want to be wasteful with your buffer object space.
I want to draw a bunch quads.
Right now I have a problem; drawing works fine and is fast but I'm using std::vector as containers for my quads and they're really, really slow. Coming from XNA I figured I should create something like the spriteBatch so that I can just call DrawQuad() to add the given quad to a list and then finally call End() to draw every quad.
My current code generally prints something like this to the console:
DrawQuad(): 77
End(): 0
Over and over again.
Main.cpp (sf::Clock is the clock class in SFML)
sf::Clock time;
for (int y = 0; y < 100; y++)
for (int x = 0; x < 100; x++)
renderer.DrawQuad("A", Vector2<GLfloat>(-1.0f + x * 0.02f, -1.0f + y * 0.02f));
std::cout << "DrawQuad(): " << time.getElapsedTime().asMilliseconds() << std::endl;
Renderer.cpp:
void TextRenderer::DrawQuad(string text, Vector2<GLfloat> position)
{
//TOP LEFT
vertexBufferVector.push_back(position.X);
vertexBufferVector.push_back(position.Y);
//TOP RIGHT
vertexBufferVector.push_back(position.X + 0.02f);
vertexBufferVector.push_back(position.Y);
//BOTTOM RIGHT
vertexBufferVector.push_back(position.X + 0.02f);
vertexBufferVector.push_back(position.Y + 0.02f);
//BOTTOM LEFT
vertexBufferVector.push_back(position.X);
vertexBufferVector.push_back(position.Y + 0.02f);
int elementCount = elementBufferVector.size() / 6;
elementBufferVector.push_back(elementCount * 4);
elementBufferVector.push_back(elementCount * 4 + 1);
elementBufferVector.push_back(elementCount * 4 + 2);
elementBufferVector.push_back(elementCount * 4 + 2);
elementBufferVector.push_back(elementCount * 4 + 3);
elementBufferVector.push_back(elementCount * 4);
}
void TextRenderer::End()
{
sf::Clock time;
GLfloat* vertexArray = &vertexBufferVector[0];
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertexBufferVector.size(), vertexArray, GL_STATIC_DRAW);
GLint* elementArray = &elementBufferVector[0];
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * elementBufferVector.size(), elementArray, GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, elementBufferVector.size(), GL_UNSIGNED_INT, 0);
vertexBufferVector.clear();
elementBufferVector.clear();
std::cout << "End(): " << time.getElapsedTime().asMilliseconds() << std::endl;
}
How do people who know what they're doing solve this? 10000 quads really shouldn't be an issue.
After writing all this I also increased the looping from (100, 100) to (1000, 100) and now the drawing takes 4-5 ms, is that considered good? I'm thinking no...
Since this is dead I'll just answer my question and maybe it'll help someone.
Instead of using vectors I resorted to using arrays with a set size. This brought the total rendering time for 100000 quads (with textures as well) down to an average of ~3.260ms.
My .h looks like this now:
const int MAX_BUFFER_SIZE = 1000;
const int MAX_VERTEX_BUFFER_SIZE = MAX_BUFFER_SIZE * 16;
const int MAX_ELEMENT_BUFFER_SIZE = MAX_BUFFER_SIZE * 6;
...
GLint vertexBufferArrayInserts;
GLfloat vertexBufferArray[MAX_VERTEX_BUFFER_SIZE];
GLint elementBufferArray[MAX_ELEMENT_BUFFER_SIZE];
And the relevant parts of the .cpp file:
void TextRenderer::DrawQuad(Vector2<GLfloat> position)
{
if(vertexBufferArrayInserts == MAX_BUFFER_SIZE)
End();
//TOP LEFT
vertexBufferArray[vertexBufferArrayInserts * 16] = position.X;
vertexBufferArray[vertexBufferArrayInserts * 16 + 1] = position.Y;
vertexBufferArray[vertexBufferArrayInserts * 16 + 2] = 0.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 3] = 0.0f;
//TOP RIGHT
vertexBufferArray[vertexBufferArrayInserts * 16 + 4] = position.X + 16.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 5] = position.Y;
vertexBufferArray[vertexBufferArrayInserts * 16 + 6] = 24.0f / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 7] = 0.0f;
//BOTTOM RIGHT
vertexBufferArray[vertexBufferArrayInserts * 16 + 8] = position.X + 16.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 9] = position.Y + 16.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 10] = 24.0f / 512.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 11] = 32.0f / 512.0f;
//BOTTOM LEFT
vertexBufferArray[vertexBufferArrayInserts * 16 + 12] = position.X;
vertexBufferArray[vertexBufferArrayInserts * 16 + 13] = position.Y + 16.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 14] = 0.0f;
vertexBufferArray[vertexBufferArrayInserts * 16 + 15] = 32.0f / 512.0f;
//ELEMENT BUFFER
elementBufferArray[vertexBufferArrayInserts * 6] = vertexBufferArrayInserts * 4;
elementBufferArray[vertexBufferArrayInserts * 6 + 1] = vertexBufferArrayInserts * 4 + 1;
elementBufferArray[vertexBufferArrayInserts * 6 + 2] = vertexBufferArrayInserts * 4 + 2;
elementBufferArray[vertexBufferArrayInserts * 6 + 3] = vertexBufferArrayInserts * 4 + 2;
elementBufferArray[vertexBufferArrayInserts * 6 + 4] = vertexBufferArrayInserts * 4 + 3;
elementBufferArray[vertexBufferArrayInserts * 6 + 5] = vertexBufferArrayInserts * 4;
vertexBufferArrayInserts++;
}
void TextRenderer::End()
{
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * vertexBufferArrayInserts * 16, vertexBufferArray);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(GLint) * vertexBufferArrayInserts * 6, elementBufferArray);
glDrawElements(GL_TRIANGLES, vertexBufferArrayInserts * 6, GL_UNSIGNED_INT, 0);
vertexBufferArrayInserts = 0;
}
And this is how I timed it:
sf::Clock timer;
renderer.Begin(projMatrix);
for (int y = 0; y < 100; y++)
for(int x = 0; x < 1000; x++)
renderer.DrawQuad(Vector2<GLfloat>(16.0f * x, 16.0f * y));
renderer.End();
avgDrawTime += timer.getElapsedTime().asMicroseconds();
drawCalls++;
if(drawCalls % 100 == 0)
std::cout << avgDrawTime / drawCalls << std::endl;