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.
I'm trying to figure out an algorithm to create a cube/box where each dimension can be divided into sections. Something similar to rings and sides when creating a sphere or a cylinder.
For example to get all the vertices for a sphere at once one can do:
for (int r = 0; r < rings-1; ++r)
{
float u = -M_PI_2 + ((r+1) * M_PI / rings);
float v = -M_PI;
for (int s= 0; s < sides; ++s)
{
float x = radius * cos(u) * cos(v);
float y = radius * sin(u);
float z = radius * cos(u) * sin(v);
add_vertex(x, y, z);
v += 2 * M_PI / sides;
}
}
Any help on how to go about doing something like that in theory would be appreciated.
Here is code wich create cude with stacks, wslices and dslices. It was used to draw array buffers to OpenGL. You can simply remove unused normal and color array and use only vertex array. And do not be affraid because of GLint and GLfloat types they are only int and float synonyms.
void DrawBox(GLfloat fWidth,GLfloat fHeight,GLfloat fDepth,GLint wslices,GLint dslices,GLint stacks)
{
// Calculate number of primitives on each side of box
// because we can use different tessalation configurations
// we must calculate separate group of box sides
int iTopButtonQuads = wslices * dslices * 2; // Calculate number of quads in top and button sides
int iLeftRightQuads = dslices * stacks * 2; // Calculate number of quads in left and right sides
int iFrontBackQuads = wslices * stacks * 2; // Calculate number of quads in front and back sides
// If we consider to use quads as primitive then each primitive will
// have 4 points, and each point has color, coord and normal attribute.
// So we create separate array to contain each attibute values.
float* pfVertices = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
float* pfColors = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
float* pfNormals = new float[(iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 3 * 4];
int iVertexIndex = 0;
GLfloat Xstep = fWidth / wslices;
GLfloat Ystep = fHeight / stacks;
GLfloat Zstep = fDepth / dslices;
GLfloat firstX = fWidth / 2.0f;
GLfloat firstY = fHeight / 2.0f;
GLfloat firstZ = fDepth / 2.0f;
GLfloat currX = 0.0f;
GLfloat currY = 0.0f;
GLfloat currZ = 0.0f;
GLfloat x_status = 0.0f;
GLfloat y_status = 0.0f;
GLfloat z_status = 0.0f;
// the bottom and the top of the box
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, -1.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 0.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX,-firstY,currZ};
float pfVertex1[3] = {currX + Xstep,-firstY,currZ};
float pfVertex2[3] = {currX + Xstep,-firstY,currZ + Zstep};
float pfVertex3[3] = {currX,-firstY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 1.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 1.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX + Xstep,firstY,currZ + Zstep};
float pfVertex1[3] = {currX + Xstep,firstY,currZ};
float pfVertex2[3] = {currX,firstY,currZ};
float pfVertex3[3] = {currX,firstY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
// the front and the back of the box
for (currY = -firstY, y_status = 0.0f; currY < firstY - Ystep / 2.0f ; currY += Ystep, y_status += Ystep)
{
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 0.0f, 1.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 0.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX,currY,firstZ};
float pfVertex1[3] = {currX + Xstep,currY,firstZ};
float pfVertex2[3] = {currX + Xstep,currY + Ystep,firstZ};
float pfVertex3[3] = {currX,currY + Ystep,firstZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currX = -firstX, x_status = 0.0f; currX < firstX - Xstep / 2.0f; currX += Xstep, x_status += Xstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 0.0f, 0.0f, -1.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 0.0f, 1.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {currX + Xstep,currY + Ystep,-firstZ};
float pfVertex1[3] = {currX + Xstep,currY,-firstZ};
float pfVertex2[3] = {currX,currY,-firstZ};
float pfVertex3[3] = {currX,currY + Ystep,-firstZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
// Right side and the left side of the box
for (currY = -firstY, y_status = 0.0f; currY < firstY - Ystep / 2.0f; currY += Ystep, y_status += Ystep)
{
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { 1.0f, 0.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 0.0f, 1.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {firstX,currY,currZ};
float pfVertex1[3] = {firstX,currY + Ystep,currZ};
float pfVertex2[3] = {firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {firstX,currY,currZ + Zstep};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
for (currZ = -firstZ, z_status = 0.0f; currZ < firstZ - Zstep / 2.0f; currZ += Zstep, z_status += Zstep)
{
int iCurrentIndex = iVertexIndex * 3 * 4;
float pfNormal[3] = { -1.0f, 0.0f, 0.0f };
memcpy(pfNormals + iCurrentIndex, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 3, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 6, pfNormal, 3 * 4);
memcpy(pfNormals + iCurrentIndex + 9, pfNormal, 3 * 4);
float pfColor[3] = { 1.0f, 1.0f, 0.0f };
memcpy(pfColors + iCurrentIndex, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 3, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 6, pfColor, 3 * 4);
memcpy(pfColors + iCurrentIndex + 9, pfColor, 3 * 4);
float pfVertex0[3] = {-firstX,currY,currZ};
float pfVertex1[3] = {-firstX,currY,currZ + Zstep};
float pfVertex2[3] = {-firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {-firstX,currY + Ystep,currZ};
memcpy(pfVertices + iCurrentIndex, pfVertex0, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 3, pfVertex1, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 6, pfVertex2, 3 * 4);
memcpy(pfVertices + iCurrentIndex + 9, pfVertex3, 3 * 4);
iVertexIndex++;
}
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glColorPointer(3, GL_FLOAT, 0, (void*)pfColors);
glNormalPointer(GL_FLOAT, 0, (void*)pfNormals);
glVertexPointer(3, GL_FLOAT, 0, (void*)pfVertices);
glDrawArrays(GL_QUADS, 0, (iTopButtonQuads + iLeftRightQuads + iFrontBackQuads) * 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
delete [] pfVertices;
delete [] pfNormals;
delete [] pfColors;
}
here is the code to optimize vertex arrays.
// 1254 Verticies
// 2141 Texture Coordinates
// 1227 Normals
// 2248 Triangles
static short face_indicies[2248][9] = {
// Object #-1
{0,15,14 ,0,1,2 ,0,1,2 }, {0,1,15 ,0,3,1 ,0,3,1 }, {1,16,15 ,3,4,1 ,3,4,1 },
{1,2,16 ,3,5,4 ,3,5,4 }, {2,17,16 ,5,6,4 ,5,6,4 }, {2,3,17 ,5,7,6 ,5,7,6 },
{3,18,17 ,7,8,6 ,7,8,6 }, {3,4,18 ,7,9,8 ,7,9,8 }, {4,19,18 ,9,10,8 ,9,10,8 },
//.................................................................
};
static GLfloat vertices [1254][3] = {
{1.32715f,-1.99755f,-0.614826f},{1.32715f,-2.20819f,-0.343913f},{1.32715f,-2.5155f,-0.191263f},
{1.32715f,-2.85867f,-0.187049f},{1.32715f,-3.16964f,-0.332104f},{1.32715f,-3.38686f,-0.597763f},
{1.32715f,-3.46734f,-0.931359f},{1.32715f,-3.39508f,-1.26683f},{1.32715f,-3.18445f,-1.53774f},
//..................................................................
};
static GLfloat normals [1227][3] = {
{-0.45634f,0.376195f,-0.80637f},{0.456348f,0.688811f,-0.563281f},{0.45634f,0.376194f,-0.80637f},
{-0.456348f,0.688811f,-0.563281f},{0.456341f,0.865005f,-0.208615f},{-0.456341f,0.865005f,-0.208615f},
{0.456341f,0.869868f,0.187303f},{-0.456341f,0.869868f,0.187303f},{0.456349f,0.702436f,0.546196f},
//..................................................................
};
static GLfloat textures [2141][2] = {
{0.94929f,0.497934f},{0.99452f,0.477509f},{0.994669f,0.497506f},
{0.949142f,0.47796f},{0.994339f,0.457508f},{0.948961f,0.457992f},
};
////////////////////////////////////////////////////////////////
// These are hard coded for this particular example
GLushort uiIndexes[2248*3]; // Maximum number of indexes
GLfloat vVerts[2248*3][3]; // (Worst case scenario)
GLfloat vText[2248*3][2];
GLfloat vNorms[2248*3][3];
int iLastIndex = 0; // Number of indexes actually used
/////////////////////////////////////////////////////////////////
// Compare two floating point values and return true if they are
// close enough together to be considered the same.
int IsSame(float x, float y, float epsilon)
{
if(fabs(x-y) < epsilon)
return 1;
return 0;
}
///////////////////////////////////////////////////////////////
// Goes through the arrays and looks for duplicate verticies
// that can be shared. This expands the original array somewhat
// and returns the number of true unique verticies that now
// populates the vVerts array.
int IndexTriangles(void)
{
int iFace, iPoint, iMatch;
float e = 0.000001; // How small a difference to equate
// LOOP THROUGH all the faces
int iIndexCount = 0;
for(iFace = 0; iFace < 2248; iFace++)
{
for(iPoint = 0; iPoint < 3; iPoint++)
{
// Search for match
for(iMatch = 0; iMatch < iLastIndex; iMatch++)
{
// If Vertex is the same...
if(IsSame(vertices[face_indicies[iFace][iPoint]][0], vVerts[iMatch][0], e) &&
IsSame(vertices[face_indicies[iFace][iPoint]][1], vVerts[iMatch][1], e) &&
IsSame(vertices[face_indicies[iFace][iPoint]][2], vVerts[iMatch][2], e) &&
// AND the Normal is the same...
IsSame(normals[face_indicies[iFace][iPoint+3]][0], vNorms[iMatch][0], e) &&
IsSame(normals[face_indicies[iFace][iPoint+3]][1], vNorms[iMatch][1], e) &&
IsSame(normals[face_indicies[iFace][iPoint+3]][2], vNorms[iMatch][2], e) &&
// And Texture is the same...
IsSame(textures[face_indicies[iFace][iPoint+6]][0], vText[iMatch][0], e) &&
IsSame(textures[face_indicies[iFace][iPoint+6]][1], vText[iMatch][1], e))
{
// Then add the index only
uiIndexes[iIndexCount] = iMatch;
iIndexCount++;
break;
}
}
// No match found, add this vertex to the end of our list, and update the index array
if(iMatch == iLastIndex)
{
// Add data and new index
memcpy(vVerts[iMatch], vertices[face_indicies[iFace][iPoint]], sizeof(float) * 3);
memcpy(vNorms[iMatch], normals[face_indicies[iFace][iPoint+3]], sizeof(float) * 3);
memcpy(vText[iMatch], textures[face_indicies[iFace][iPoint+6]], sizeof(float) * 2);
uiIndexes[iIndexCount] = iLastIndex;
iIndexCount++;
iLastIndex++;
}
}
}
return iIndexCount;
}
/////////////////////////////////////////////
// Function to stitch the triangles together
// and draw the ship
void DrawModel(void)
{
static int iIndexes = 0;
char cBuffer[32];
// The first time this is called, reindex the triangles. Report the results
// in the window title
if(iIndexes == 0)
{
iIndexes = IndexTriangles();
sprintf(cBuffer,"Verts = %d Indexes = %d", iLastIndex, iIndexes);
glutSetWindowTitle(cBuffer);
}
// Use vertices, normals, and texture coordinates
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Here's where the data is now
glVertexPointer(3, GL_FLOAT,0, vVerts);
glNormalPointer(GL_FLOAT, 0, vNorms);
glTexCoordPointer(2, GL_FLOAT, 0, vText);
// Draw them
glDrawElements(GL_TRIANGLES, iIndexes, GL_UNSIGNED_SHORT, uiIndexes);
}
This algo will works with arbitrary mesh array. Or just place unique values it means remove the values where curr + step occurs so must be left 1 vertex per loop body not all 4. Example
Where we have 4 vertices
float pfVertex0[3] = {-firstX,currY,currZ};
float pfVertex1[3] = {-firstX,currY,currZ + Zstep};
float pfVertex2[3] = {-firstX,currY + Ystep,currZ + Zstep};
float pfVertex3[3] = {-firstX,currY + Ystep,currZ};
The only vertex left will be
float pfVertex0[3] = {-firstX,currY,currZ};
The simple arithmetic shows 24 / 4 = 6 != 8
so to form proper box we just must add extra iteration to 1 side of the box (2 vertices).