I came down on OpenGL a little heavier than on D3D in the last post, so to redress the balance I have to say that OpenGL instancing is very nice indeed; much nicer than D3D.
Here's some code:
void R_DrawParticles (void)
{
int i, j;
particle_t *p;
if (!r_newrefdef.num_particles) return;
GL_UseProgram (gl_particleprog);
glUniformMatrix4fv (u_partmatrix, 1, GL_FALSE, r_mvpmatrix.m[0]);
glUniform3fv (u_partrorigin, 1, r_origin);
glUniform3fv (u_partvpn, 1, vpn);
glUniform3fv (u_partvright, 1, vright);
glUniform3fv (u_partvup, 1, vup);
GL_Enable ((BLEND_BIT | DEPTHTEST_BIT) | (gl_cull->value ? CULLFACE_BIT : 0));
GL_EnableVertexAttribArrays (VAA0 | VAA1 | VAA2);
glBindBuffer (GL_ARRAY_BUFFER, gl_particledynamicvbo);
if (r_firstparticle + r_newrefdef.num_particles >= MAX_PARTICLES)
{
glBufferData (GL_ARRAY_BUFFER, MAX_PARTICLES * sizeof (particle_t), NULL, GL_STREAM_DRAW);
r_firstparticle = 0;
}
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, sizeof (particle_t), (void *) (r_firstparticle * sizeof (particle_t)));
glVertexAttribPointer (1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof (particle_t), (void *) (r_firstparticle * sizeof (particle_t) + 12));
if ((p = glMapBufferRange (GL_ARRAY_BUFFER, r_firstparticle * sizeof (particle_t), r_newrefdef.num_particles * sizeof (particle_t), BUFFER_MAP_BITS)) == NULL)
{
ri.Con_Printf (PRINT_ALL, "R_DrawParticles : glMapBufferRange failed\n");
return;
}
memcpy (p, r_newrefdef.particles, r_newrefdef.num_particles * sizeof (particle_t));
glUnmapBuffer (GL_ARRAY_BUFFER);
glBindBuffer (GL_ARRAY_BUFFER, gl_particletexcoordvbo);
glVertexAttribPointer (2, 2, GL_FLOAT, GL_FALSE, 0, (void *) 0);
glVertexAttribDivisor (0, 1);
glVertexAttribDivisor (1, 1);
glDrawArraysInstanced (GL_TRIANGLE_FAN, 0, 4, r_newrefdef.num_particles);
glVertexAttribDivisor (0, 0);
glVertexAttribDivisor (1, 0);
r_firstparticle += r_newrefdef.num_particles;
}

