{
}
+#define BATCHSIZE 256
+int particle_element3i[BATCHSIZE*6];
+float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16];
+
void R_Particles_Init (void)
{
+ int i;
+ for (i = 0;i < BATCHSIZE;i++)
+ {
+ particle_element3i[i*6+0] = i*4+0;
+ particle_element3i[i*6+1] = i*4+1;
+ particle_element3i[i*6+2] = i*4+2;
+ particle_element3i[i*6+3] = i*4+0;
+ particle_element3i[i*6+4] = i*4+2;
+ particle_element3i[i*6+5] = i*4+3;
+ }
+
Cvar_RegisterVariable(&r_drawparticles);
R_RegisterModule("R_Particles", r_part_start, r_part_shutdown, r_part_newmap);
}
-float particle_vertex3f[12], particle_texcoord2f[8];
-
-void R_DrawParticle_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- const particle_t *p = cl.particles + surfacenumber;
- rmeshstate_t m;
+ int surfacelistindex;
+ int batchstart, batchcount;
+ const particle_t *p;
pblend_t blendmode;
- float org[3], up2[3], v[3], right[3], up[3], fog, ifog, cr, cg, cb, ca, size;
- particletexture_t *tex;
-
- VectorCopy(p->org, org);
-
- blendmode = p->type->blendmode;
- tex = &particletexture[p->texnum];
- cr = p->color[0] * (1.0f / 255.0f);
- cg = p->color[1] * (1.0f / 255.0f);
- cb = p->color[2] * (1.0f / 255.0f);
- ca = p->alpha * (1.0f / 255.0f);
- if (blendmode == PBLEND_MOD)
- {
- cr *= ca;
- cg *= ca;
- cb *= ca;
- cr = min(cr, 1);
- cg = min(cg, 1);
- cb = min(cb, 1);
- ca = 1;
- }
- ca /= cl_particles_quality.value;
- if (p->type->lighting)
- {
- float ambient[3], diffuse[3], diffusenormal[3];
- R_CompleteLightPoint(ambient, diffuse, diffusenormal, org, true);
- cr *= (ambient[0] + 0.5 * diffuse[0]);
- cg *= (ambient[1] + 0.5 * diffuse[1]);
- cb *= (ambient[2] + 0.5 * diffuse[2]);
- }
- if (fogenabled)
- {
- fog = VERTEXFOGTABLE(VectorDistance(org, r_vieworigin));
- ifog = 1 - fog;
- cr = cr * ifog;
- cg = cg * ifog;
- cb = cb * ifog;
- if (blendmode == PBLEND_ALPHA)
- {
- cr += fogcolor[0] * fog;
- cg += fogcolor[1] * fog;
- cb += fogcolor[2] * fog;
- }
- }
+ rtexture_t *texture;
+ float *v3f, *t2f, *c4f;
R_Mesh_Matrix(&identitymatrix);
-
+ R_Mesh_ResetTextureState();
R_Mesh_VertexPointer(particle_vertex3f);
- R_Mesh_ColorPointer(NULL);
- memset(&m, 0, sizeof(m));
- m.tex[0] = R_GetTexture(tex->texture);
- m.pointer_texcoord[0] = particle_texcoord2f;
- R_Mesh_TextureState(&m);
-
- GL_Color(cr, cg, cb, ca);
-
- if (blendmode == PBLEND_ALPHA)
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- else if (blendmode == PBLEND_ADD)
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
- else //if (blendmode == PBLEND_MOD)
- GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+ R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f);
+ R_Mesh_ColorPointer(particle_color4f);
GL_DepthMask(false);
GL_DepthTest(true);
- size = p->size * cl_particles_size.value;
- if (p->type->orientation == PARTICLE_BILLBOARD || p->type->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
+
+ // first generate all the vertices at once
+ for (surfacelistindex = 0, v3f = particle_vertex3f, t2f = particle_texcoord2f, c4f = particle_color4f;surfacelistindex < numsurfaces;surfacelistindex++, v3f += 3*4, t2f += 2*4, c4f += 4*4)
{
- if (p->type->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
+ particletexture_t *tex;
+ const float *org;
+ float up2[3], v[3], right[3], up[3], fog, ifog, cr, cg, cb, ca, size;
+
+ p = cl.particles + surfacelist[surfacelistindex];
+
+ blendmode = p->type->blendmode;
+
+ cr = p->color[0] * (1.0f / 255.0f);
+ cg = p->color[1] * (1.0f / 255.0f);
+ cb = p->color[2] * (1.0f / 255.0f);
+ ca = p->alpha * (1.0f / 255.0f);
+ if (blendmode == PBLEND_MOD)
+ {
+ cr *= ca;
+ cg *= ca;
+ cb *= ca;
+ cr = min(cr, 1);
+ cg = min(cg, 1);
+ cb = min(cb, 1);
+ ca = 1;
+ }
+ ca /= cl_particles_quality.value;
+ if (p->type->lighting)
+ {
+ float ambient[3], diffuse[3], diffusenormal[3];
+ R_CompleteLightPoint(ambient, diffuse, diffusenormal, p->org, true);
+ cr *= (ambient[0] + 0.5 * diffuse[0]);
+ cg *= (ambient[1] + 0.5 * diffuse[1]);
+ cb *= (ambient[2] + 0.5 * diffuse[2]);
+ }
+ if (fogenabled)
+ {
+ fog = VERTEXFOGTABLE(VectorDistance(p->org, r_vieworigin));
+ ifog = 1 - fog;
+ cr = cr * ifog;
+ cg = cg * ifog;
+ cb = cb * ifog;
+ if (blendmode == PBLEND_ALPHA)
+ {
+ cr += fogcolor[0] * fog;
+ cg += fogcolor[1] * fog;
+ cb += fogcolor[2] * fog;
+ }
+ }
+ c4f[0] = c4f[4] = c4f[8] = c4f[12] = cr;
+ c4f[1] = c4f[5] = c4f[9] = c4f[13] = cg;
+ c4f[2] = c4f[6] = c4f[10] = c4f[14] = cb;
+ c4f[3] = c4f[7] = c4f[11] = c4f[15] = ca;
+
+ size = p->size * cl_particles_size.value;
+ org = p->org;
+ tex = &particletexture[p->texnum];
+ if (p->type->orientation == PARTICLE_BILLBOARD)
+ {
+ VectorScale(r_viewleft, -size, right);
+ VectorScale(r_viewup, size, up);
+ v3f[ 0] = org[0] - right[0] - up[0];
+ v3f[ 1] = org[1] - right[1] - up[1];
+ v3f[ 2] = org[2] - right[2] - up[2];
+ v3f[ 3] = org[0] - right[0] + up[0];
+ v3f[ 4] = org[1] - right[1] + up[1];
+ v3f[ 5] = org[2] - right[2] + up[2];
+ v3f[ 6] = org[0] + right[0] + up[0];
+ v3f[ 7] = org[1] + right[1] + up[1];
+ v3f[ 8] = org[2] + right[2] + up[2];
+ v3f[ 9] = org[0] + right[0] - up[0];
+ v3f[10] = org[1] + right[1] - up[1];
+ v3f[11] = org[2] + right[2] - up[2];
+ t2f[0] = tex->s1;t2f[1] = tex->t2;
+ t2f[2] = tex->s1;t2f[3] = tex->t1;
+ t2f[4] = tex->s2;t2f[5] = tex->t1;
+ t2f[6] = tex->s2;t2f[7] = tex->t2;
+ }
+ else if (p->type->orientation == PARTICLE_ORIENTED_DOUBLESIDED)
{
// double-sided
if (DotProduct(p->vel, r_vieworigin) > DotProduct(p->vel, org))
VectorVectors(p->vel, right, up);
VectorScale(right, size, right);
VectorScale(up, size, up);
+ v3f[ 0] = org[0] - right[0] - up[0];
+ v3f[ 1] = org[1] - right[1] - up[1];
+ v3f[ 2] = org[2] - right[2] - up[2];
+ v3f[ 3] = org[0] - right[0] + up[0];
+ v3f[ 4] = org[1] - right[1] + up[1];
+ v3f[ 5] = org[2] - right[2] + up[2];
+ v3f[ 6] = org[0] + right[0] + up[0];
+ v3f[ 7] = org[1] + right[1] + up[1];
+ v3f[ 8] = org[2] + right[2] + up[2];
+ v3f[ 9] = org[0] + right[0] - up[0];
+ v3f[10] = org[1] + right[1] - up[1];
+ v3f[11] = org[2] + right[2] - up[2];
+ t2f[0] = tex->s1;t2f[1] = tex->t2;
+ t2f[2] = tex->s1;t2f[3] = tex->t1;
+ t2f[4] = tex->s2;t2f[5] = tex->t1;
+ t2f[6] = tex->s2;t2f[7] = tex->t2;
+ }
+ else if (p->type->orientation == PARTICLE_SPARK)
+ {
+ VectorMA(org, -0.02, p->vel, v);
+ VectorMA(org, 0.02, p->vel, up2);
+ R_CalcBeam_Vertex3f(v3f, v, up2, size);
+ t2f[0] = tex->s1;t2f[1] = tex->t2;
+ t2f[2] = tex->s1;t2f[3] = tex->t1;
+ t2f[4] = tex->s2;t2f[5] = tex->t1;
+ t2f[6] = tex->s2;t2f[7] = tex->t2;
+ }
+ else if (p->type->orientation == PARTICLE_BEAM)
+ {
+ R_CalcBeam_Vertex3f(v3f, org, p->vel, size);
+ VectorSubtract(p->vel, org, up);
+ VectorNormalize(up);
+ v[0] = DotProduct(org, up) * (1.0f / 64.0f);
+ v[1] = DotProduct(p->vel, up) * (1.0f / 64.0f);
+ t2f[0] = 1;t2f[1] = v[0];
+ t2f[2] = 0;t2f[3] = v[0];
+ t2f[4] = 0;t2f[5] = v[1];
+ t2f[6] = 1;t2f[7] = v[1];
}
else
{
- VectorScale(r_viewleft, -size, right);
- VectorScale(r_viewup, size, up);
+ Con_Printf("R_DrawParticles: unknown particle orientation %i\n", p->type->orientation);
+ return;
}
- particle_vertex3f[ 0] = org[0] - right[0] - up[0];
- particle_vertex3f[ 1] = org[1] - right[1] - up[1];
- particle_vertex3f[ 2] = org[2] - right[2] - up[2];
- particle_vertex3f[ 3] = org[0] - right[0] + up[0];
- particle_vertex3f[ 4] = org[1] - right[1] + up[1];
- particle_vertex3f[ 5] = org[2] - right[2] + up[2];
- particle_vertex3f[ 6] = org[0] + right[0] + up[0];
- particle_vertex3f[ 7] = org[1] + right[1] + up[1];
- particle_vertex3f[ 8] = org[2] + right[2] + up[2];
- particle_vertex3f[ 9] = org[0] + right[0] - up[0];
- particle_vertex3f[10] = org[1] + right[1] - up[1];
- particle_vertex3f[11] = org[2] + right[2] - up[2];
- particle_texcoord2f[0] = tex->s1;particle_texcoord2f[1] = tex->t2;
- particle_texcoord2f[2] = tex->s1;particle_texcoord2f[3] = tex->t1;
- particle_texcoord2f[4] = tex->s2;particle_texcoord2f[5] = tex->t1;
- particle_texcoord2f[6] = tex->s2;particle_texcoord2f[7] = tex->t2;
- }
- else if (p->type->orientation == PARTICLE_SPARK)
- {
- VectorMA(p->org, -0.02, p->vel, v);
- VectorMA(p->org, 0.02, p->vel, up2);
- R_CalcBeam_Vertex3f(particle_vertex3f, v, up2, size);
- particle_texcoord2f[0] = tex->s1;particle_texcoord2f[1] = tex->t2;
- particle_texcoord2f[2] = tex->s1;particle_texcoord2f[3] = tex->t1;
- particle_texcoord2f[4] = tex->s2;particle_texcoord2f[5] = tex->t1;
- particle_texcoord2f[6] = tex->s2;particle_texcoord2f[7] = tex->t2;
- }
- else if (p->type->orientation == PARTICLE_BEAM)
- {
- R_CalcBeam_Vertex3f(particle_vertex3f, p->org, p->vel, size);
- VectorSubtract(p->vel, p->org, up);
- VectorNormalize(up);
- v[0] = DotProduct(p->org, up) * (1.0f / 64.0f);
- v[1] = DotProduct(p->vel, up) * (1.0f / 64.0f);
- particle_texcoord2f[0] = 1;particle_texcoord2f[1] = v[0];
- particle_texcoord2f[2] = 0;particle_texcoord2f[3] = v[0];
- particle_texcoord2f[4] = 0;particle_texcoord2f[5] = v[1];
- particle_texcoord2f[6] = 1;particle_texcoord2f[7] = v[1];
}
- else
+
+ // now render batches of particles based on blendmode and texture
+ blendmode = PBLEND_ADD;
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ texture = particletexture[63].texture;
+ R_Mesh_TexBind(0, R_GetTexture(texture));
+ GL_LockArrays(0, numsurfaces*4);
+ batchstart = 0;
+ batchcount = 0;
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
{
- Con_Printf("R_DrawParticles: unknown particle orientation %i\n", p->type->orientation);
- return;
- }
+ p = cl.particles + surfacelist[surfacelistindex];
+
+ if (blendmode != p->type->blendmode)
+ {
+ if (batchcount > 0)
+ R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6);
+ batchcount = 0;
+ batchstart = surfacelistindex;
+ blendmode = p->type->blendmode;
+ if (blendmode == PBLEND_ALPHA)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ else if (blendmode == PBLEND_ADD)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else //if (blendmode == PBLEND_MOD)
+ GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
+ }
+ if (texture != particletexture[p->texnum].texture)
+ {
+ if (batchcount > 0)
+ R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6);
+ batchcount = 0;
+ batchstart = surfacelistindex;
+ texture = particletexture[p->texnum].texture;
+ R_Mesh_TexBind(0, R_GetTexture(texture));
+ }
- R_Mesh_Draw(0, 4, 2, polygonelements);
+ batchcount++;
+ }
+ if (batchcount > 0)
+ R_Mesh_Draw(batchstart * 4, batchcount * 4, batchcount * 2, particle_element3i + batchstart * 6);
+ GL_LockArrays(0, 0);
}
void R_DrawParticles (void)
{
renderstats.particles++;
if (DotProduct(p->org, r_viewforward) >= minparticledist || p->type->orientation == PARTICLE_BEAM)
- {
- if (p->type == particletype + pt_decal)
- R_DrawParticle_TransparentCallback(0, i, 0);
- else
- R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL);
- }
+ R_MeshQueue_AddTransparent(p->org, R_DrawParticle_TransparentCallback, NULL, i, NULL);
}
}
}
0.5f, 0.0f, 0.0f, 1.0f
};
-void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
int i;
float f1, f2, *c;
float color4f[6*4];
+ // this is only called once per entity so numsurfaces is always 1, and
+ // surfacelist is always {0}, so this code does not handle batches
R_Mesh_Matrix(&ent->matrix);
if (ent->flags & EF_ADDITIVE)
}
}
-static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+#define BATCHSIZE 256
+static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- msurface_t *surface = ent->model->data_surfaces + surfacenumber;
+ int surfacelistindex;
+ int batchcount;
+ texture_t *t;
+ msurface_t *texturesurfacelist[BATCHSIZE];
+ RSurf_ActiveEntity(ent);
+ batchcount = 0;
+ t = NULL;
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
- if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
- return; // transparent sky is too difficult
+ if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture)
+ {
+ if (batchcount > 0)
+ R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
+ batchcount = 0;
+ t = surface->texture;
+ rsurface_lightmaptexture = surface->lightmaptexture;
+ R_UpdateTextureInfo(ent, t);
+ rsurface_texture = t->currentframe;
+ }
+ if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)
+ continue; // transparent sky is too difficult
- RSurf_ActiveEntity(ent);
- R_UpdateTextureInfo(ent, surface->texture);
- rsurface_texture = surface->texture->currentframe;
- R_DrawTextureSurfaceList(1, &surface);
+ texturesurfacelist[batchcount++] = surface;
+ }
+ if (batchcount > 0)
+ R_DrawTextureSurfaceList(batchcount, texturesurfacelist);
RSurf_CleanUp();
}
=============================================================
*/
-static void R_DrawPortal_Callback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
+ // due to the hacky nature of this function's parameters, this is never
+ // called with a batch, so numsurfaces is always 1, and the surfacelist
+ // contains only a leaf number for coloring purposes
const mportal_t *portal = (mportal_t *)ent;
int i, numpoints;
float *v;
R_Mesh_ColorPointer(NULL);
R_Mesh_ResetTextureState();
- i = surfacenumber;
+ i = surfacelist[0];
GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
((i & 0x0038) >> 3) * (1.0f / 7.0f),
((i & 0x01C0) >> 6) * (1.0f / 7.0f),
}
}
-static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+#define BATCHSIZE 256
+
+static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- msurface_t *surface = ent->model->data_surfaces + surfacenumber;
- R_UpdateTextureInfo(ent, surface->texture);
+ int surfacelistindex, batchcount;
+ texture_t *t;
+ msurface_t *batchsurfaces[BATCHSIZE];
+ // note: in practice this never actualy batches, oh well
R_Shadow_RenderMode_Begin();
R_Shadow_RenderMode_ActiveLight((rtlight_t *)rtlight);
R_Shadow_RenderMode_Lighting(false, true);
R_Shadow_SetupEntityLight(ent);
- rsurface_texture = surface->texture->currentframe;
- R_Shadow_RenderSurfacesLighting(1, &surface);
+ t = NULL;
+ batchcount = 0;
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ msurface_t *surface = ent->model->data_surfaces + surfacelist[surfacelistindex];
+ if (t != surface->texture)
+ {
+ if (batchcount > 0)
+ R_Shadow_RenderSurfacesLighting(batchcount, batchsurfaces);
+ batchcount = 0;
+ t = surface->texture;
+ R_UpdateTextureInfo(ent, t);
+ rsurface_texture = t->currentframe;
+ }
+ batchsurfaces[batchcount++] = surface;
+ }
+ if (batchcount > 0)
+ R_Shadow_RenderSurfacesLighting(batchcount, batchsurfaces);
R_Shadow_RenderMode_End();
}
typedef struct meshqueue_s
{
struct meshqueue_s *next;
- void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
+ void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
const entity_render_t *ent;
int surfacenumber;
const rtlight_t *rtlight;
void R_MeshQueue_Render(void)
{
+ // this is only used by one piece of code in prvm_cmds, why is it used at all?
meshqueue_t *mq;
if (!mq_count)
return;
for (mq = mq_listhead;mq;mq = mq->next)
- mq->callback(mq->ent, mq->surfacenumber, mq->rtlight);
+ mq->callback(mq->ent, mq->rtlight, 1, &mq->surfacenumber);
mq_count = 0;
mq_listhead = NULL;
}
mqt_total = newtotal;
}
-void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
{
+ // this is only used by one piece of code in prvm_cmds, why is it used at all?
meshqueue_t *mq, **mqnext;
if (r_meshqueue_immediaterender.integer)
{
- callback(ent, surfacenumber, rtlight);
+ callback(ent, rtlight, 1, &surfacenumber);
return;
}
if (mq_count >= mq_total)
*mqnext = mq;
}
-void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
{
meshqueue_t *mq;
if (mqt_count >= mqt_total)
{
int i;
int hashdist;
+ int batchnumsurfaces;
float distscale;
+ const entity_render_t *ent;
+ const rtlight_t *rtlight;
+ void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfaceindices);
meshqueue_t *mqt;
meshqueue_t *hash[4096], **hashpointer[4096];
+ int batchsurfaceindex[256];
if (mq_count)
R_MeshQueue_Render();
if (!mqt_count)
*hashpointer[hashdist] = mqt;
hashpointer[hashdist] = &mqt->next;
}
+ callback = NULL;
+ ent = NULL;
+ rtlight = NULL;
+ batchnumsurfaces = 0;
for (i = 4095;i >= 0;i--)
+ {
if (hash[i])
+ {
for (mqt = hash[i];mqt;mqt = mqt->next)
- mqt->callback(mqt->ent, mqt->surfacenumber, mqt->rtlight);
+ {
+ if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256)
+ {
+ if (batchnumsurfaces)
+ callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
+ batchnumsurfaces = 0;
+ ent = mqt->ent;
+ rtlight = mqt->rtlight;
+ callback = mqt->callback;
+ }
+ batchsurfaceindex[batchnumsurfaces++] = mqt->surfacenumber;
+ }
+ }
+ }
+ if (batchnumsurfaces)
+ callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
mqt_count = 0;
}
#define MESHQUEUE_H
void R_MeshQueue_Init(void);
-void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
-void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
+void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
+void R_MeshQueue_AddTransparent(const vec3_t center, void (*callback)(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist), const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight);
void R_MeshQueue_BeginScene(void);
void R_MeshQueue_Render(void);
void R_MeshQueue_RenderTransparent(void);
vm_polygons_initialized = true;
}
-void VM_DrawPolygonCallback (const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- const vm_polygon_t *p = &vm_polygons[surfacenumber];
- int flags = p->flags & 0x0f;
+ int surfacelistindex;
+ // LordHavoc: FIXME: this is stupid code
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
+ int flags = p->flags & 0x0f;
- if(flags == DRAWFLAG_ADDITIVE)
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
- else if(flags == DRAWFLAG_MODULATE)
- GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
- else if(flags == DRAWFLAG_2XMODULATE)
- GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
- else
- GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if(flags == DRAWFLAG_ADDITIVE)
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+ else if(flags == DRAWFLAG_MODULATE)
+ GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
+ else if(flags == DRAWFLAG_2XMODULATE)
+ GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
+ else
+ GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- R_Mesh_TexBind(0, R_GetTexture(p->tex));
+ R_Mesh_TexBind(0, R_GetTexture(p->tex));
- CHECKGLERROR
- //[515]: is speed is max ?
- if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
- {
- qglLineWidth(p->data[13]);CHECKGLERROR
- qglBegin(GL_LINE_LOOP);
- qglTexCoord1f (p->data[12]);
- qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
- qglVertex3f (p->data[0] , p->data[1], p->data[2]);
+ CHECKGLERROR
+ //[515]: is speed is max ?
+ if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
+ {
+ qglLineWidth(p->data[13]);CHECKGLERROR
+ qglBegin(GL_LINE_LOOP);
+ qglTexCoord1f (p->data[12]);
+ qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
+ qglVertex3f (p->data[0] , p->data[1], p->data[2]);
- qglTexCoord1f (p->data[14]);
- qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
- qglVertex3f (p->data[3] , p->data[4], p->data[5]);
+ qglTexCoord1f (p->data[14]);
+ qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
+ qglVertex3f (p->data[3] , p->data[4], p->data[5]);
- if(p->flags & VM_POLYGON_FL3V)
- {
- qglTexCoord1f (p->data[16]);
+ if(p->flags & VM_POLYGON_FL3V)
+ {
+ qglTexCoord1f (p->data[16]);
+ qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
+ qglVertex3f (p->data[6] , p->data[7], p->data[8]);
+
+ if(p->flags & VM_POLYGON_FL4V)
+ {
+ qglTexCoord1f (p->data[18]);
+ qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
+ qglVertex3f (p->data[9] , p->data[10], p->data[11]);
+ }
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ else
+ {
+ qglBegin(GL_POLYGON);
+ qglTexCoord2f (p->data[12], p->data[13]);
+ qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
+ qglVertex3f (p->data[0] , p->data[1], p->data[2]);
+
+ qglTexCoord2f (p->data[14], p->data[15]);
+ qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
+ qglVertex3f (p->data[3] , p->data[4], p->data[5]);
+
+ qglTexCoord2f (p->data[16], p->data[17]);
qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
qglVertex3f (p->data[6] , p->data[7], p->data[8]);
if(p->flags & VM_POLYGON_FL4V)
{
- qglTexCoord1f (p->data[18]);
+ qglTexCoord2f (p->data[18], p->data[19]);
qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
qglVertex3f (p->data[9] , p->data[10], p->data[11]);
}
- }
- qglEnd();
- CHECKGLERROR
- }
- else
- {
- qglBegin(GL_POLYGON);
- qglTexCoord2f (p->data[12], p->data[13]);
- qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
- qglVertex3f (p->data[0] , p->data[1], p->data[2]);
-
- qglTexCoord2f (p->data[14], p->data[15]);
- qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
- qglVertex3f (p->data[3] , p->data[4], p->data[5]);
-
- qglTexCoord2f (p->data[16], p->data[17]);
- qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
- qglVertex3f (p->data[6] , p->data[7], p->data[8]);
-
- if(p->flags & VM_POLYGON_FL4V)
- {
- qglTexCoord2f (p->data[18], p->data[19]);
- qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
- qglVertex3f (p->data[9] , p->data[10], p->data[11]);
- }
- qglEnd();
- CHECKGLERROR
+ qglEnd();
+ CHECKGLERROR
+ }
}
}
}
}
-static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- const explosion_t *e = explosion + surfacenumber;
- int numtriangles, numverts;
- float alpha;
+ int surfacelistindex = 0;
+ const int numtriangles = EXPLOSIONTRIS, numverts = EXPLOSIONVERTS;
rmeshstate_t m;
-
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
GL_DepthMask(false);
GL_DepthTest(true);
R_Mesh_Matrix(&identitymatrix);
- numtriangles = EXPLOSIONTRIS;
- numverts = EXPLOSIONVERTS;
- alpha = e->alpha;
-
- R_Mesh_VertexPointer(e->vert[0]);
R_Mesh_ColorPointer(NULL);
memset(&m, 0, sizeof(m));
m.tex[0] = R_GetTexture(explosiontexture);
m.pointer_texcoord[0] = explosiontexcoord2f[0];
R_Mesh_TextureState(&m);
-
- GL_Color(alpha, alpha, alpha, 1);
-
- GL_LockArrays(0, numverts);
- R_Mesh_Draw(0, numverts, numtriangles, explosiontris[0]);
- GL_LockArrays(0, 0);
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ const explosion_t *e = explosion + surfacelist[surfacelistindex];
+ R_Mesh_VertexPointer(e->vert[0]);
+ GL_Color(e->alpha, e->alpha, e->alpha, 1);
+ GL_LockArrays(0, numverts);
+ R_Mesh_Draw(0, numverts, numtriangles, explosiontris[0]);
+ GL_LockArrays(0, 0);
+ }
}
static void R_MoveExplosion(explosion_t *e)
float beamrepeatscale;
-void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
- const beam_t *b = cl.beams + surfacenumber;
+ int surfacelistindex;
rmeshstate_t m;
- vec3_t beamdir, right, up, offset;
- float length, t1, t2;
float vertex3f[12*3];
float texcoord2f[12*2];
float color4f[12*4];
-
R_Mesh_Matrix(&identitymatrix);
-
- // calculate beam direction (beamdir) vector and beam length
- // get difference vector
- VectorSubtract(b->end, b->start, beamdir);
- // find length of difference vector
- length = sqrt(DotProduct(beamdir, beamdir));
- // calculate scale to make beamdir a unit vector (normalized)
- t1 = 1.0f / length;
- // scale beamdir so it is now normalized
- VectorScale(beamdir, t1, beamdir);
-
- // calculate up vector such that it points toward viewer, and rotates around the beamdir
- // get direction from start of beam to viewer
- VectorSubtract(r_vieworigin, b->start, up);
- // remove the portion of the vector that moves along the beam
- // (this leaves only a vector pointing directly away from the beam)
- t1 = -DotProduct(up, beamdir);
- VectorMA(up, t1, beamdir, up);
- // generate right vector from forward and up, the result is unnormalized
- CrossProduct(beamdir, up, right);
- // now normalize the right vector and up vector
- VectorNormalize(right);
- VectorNormalize(up);
-
- // calculate T coordinate scrolling (start and end texcoord along the beam)
- t1 = r_refdef.time * -r_lightningbeam_scroll.value;// + beamrepeatscale * DotProduct(b->start, beamdir);
- t1 = t1 - (int) t1;
- t2 = t1 + beamrepeatscale * length;
-
- // the beam is 3 polygons in this configuration:
- // * 2
- // * *
- // 1******
- // * *
- // * 3
- // they are showing different portions of the beam texture, creating an
- // illusion of a beam that appears to curl around in 3D space
- // (and realize that the whole polygon assembly orients itself to face
- // the viewer)
-
GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
GL_DepthMask(false);
GL_DepthTest(true);
if (!r_lightningbeam_qmbtexture.integer && r_lightningbeamtexture == NULL)
r_lightningbeams_setuptexture();
- // polygon 1, verts 0-3
- VectorScale(right, r_lightningbeam_thickness.value, offset);
- R_CalcLightningBeamPolygonVertex3f(vertex3f + 0, b->start, b->end, offset);
- // polygon 2, verts 4-7
- VectorAdd(right, up, offset);
- VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
- R_CalcLightningBeamPolygonVertex3f(vertex3f + 12, b->start, b->end, offset);
- // polygon 3, verts 8-11
- VectorSubtract(right, up, offset);
- VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
- R_CalcLightningBeamPolygonVertex3f(vertex3f + 24, b->start, b->end, offset);
- R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 0, t1, t2);
- R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 8, t1 + 0.33, t2 + 0.33);
- R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 16, t1 + 0.66, t2 + 0.66);
-
R_Mesh_VertexPointer(vertex3f);
if (fogenabled)
{
m.pointer_texcoord[0] = texcoord2f;
R_Mesh_TextureState(&m);
- // draw the 3 polygons as one batch of 6 triangles using the 12 vertices
- GL_LockArrays(0, 12);
- R_Mesh_Draw(0, 12, 6, r_lightningbeamelements);
- GL_LockArrays(0, 0);
+ for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
+ {
+ const beam_t *b = cl.beams + surfacelist[surfacelistindex];
+ vec3_t beamdir, right, up, offset;
+ float length, t1, t2;
+
+ // calculate beam direction (beamdir) vector and beam length
+ // get difference vector
+ VectorSubtract(b->end, b->start, beamdir);
+ // find length of difference vector
+ length = sqrt(DotProduct(beamdir, beamdir));
+ // calculate scale to make beamdir a unit vector (normalized)
+ t1 = 1.0f / length;
+ // scale beamdir so it is now normalized
+ VectorScale(beamdir, t1, beamdir);
+
+ // calculate up vector such that it points toward viewer, and rotates around the beamdir
+ // get direction from start of beam to viewer
+ VectorSubtract(r_vieworigin, b->start, up);
+ // remove the portion of the vector that moves along the beam
+ // (this leaves only a vector pointing directly away from the beam)
+ t1 = -DotProduct(up, beamdir);
+ VectorMA(up, t1, beamdir, up);
+ // generate right vector from forward and up, the result is unnormalized
+ CrossProduct(beamdir, up, right);
+ // now normalize the right vector and up vector
+ VectorNormalize(right);
+ VectorNormalize(up);
+
+ // calculate T coordinate scrolling (start and end texcoord along the beam)
+ t1 = r_refdef.time * -r_lightningbeam_scroll.value;// + beamrepeatscale * DotProduct(b->start, beamdir);
+ t1 = t1 - (int) t1;
+ t2 = t1 + beamrepeatscale * length;
+
+ // the beam is 3 polygons in this configuration:
+ // * 2
+ // * *
+ // 1******
+ // * *
+ // * 3
+ // they are showing different portions of the beam texture, creating an
+ // illusion of a beam that appears to curl around in 3D space
+ // (and realize that the whole polygon assembly orients itself to face
+ // the viewer)
+
+ // polygon 1, verts 0-3
+ VectorScale(right, r_lightningbeam_thickness.value, offset);
+ R_CalcLightningBeamPolygonVertex3f(vertex3f + 0, b->start, b->end, offset);
+ // polygon 2, verts 4-7
+ VectorAdd(right, up, offset);
+ VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
+ R_CalcLightningBeamPolygonVertex3f(vertex3f + 12, b->start, b->end, offset);
+ // polygon 3, verts 8-11
+ VectorSubtract(right, up, offset);
+ VectorScale(offset, r_lightningbeam_thickness.value * 0.70710681f, offset);
+ R_CalcLightningBeamPolygonVertex3f(vertex3f + 24, b->start, b->end, offset);
+ R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 0, t1, t2);
+ R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 8, t1 + 0.33, t2 + 0.33);
+ R_CalcLightningBeamPolygonTexCoord2f(texcoord2f + 16, t1 + 0.66, t2 + 0.66);
+ if (fogenabled)
+ {
+ // per vertex colors if fog is used
+ R_FogLightningBeam_Vertex3f_Color4f(vertex3f, color4f, 12, r_lightningbeam_color_red.value, r_lightningbeam_color_green.value, r_lightningbeam_color_blue.value, 1);
+ }
+
+ // draw the 3 polygons as one batch of 6 triangles using the 12 vertices
+ GL_LockArrays(0, 12);
+ R_Mesh_Draw(0, 12, 6, r_lightningbeamelements);
+ GL_LockArrays(0, 0);
+ }
}
void R_DrawLightningBeams(void)
r_shadow_selectedlight->selected = true;
}
-void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
+ // this is never batched (there can be only one)
float scale = r_editlights_cursorgrid.value * 0.5f;
R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[1]->tex, NULL, false, r_editlights_cursorlocation, r_viewright, r_viewup, scale, -scale, -scale, scale, 1, 1, 1, 0.5f);
}
-void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
+ // this is never batched (due to the ent parameter changing every time)
+ // so numsurfaces == 1 and surfacelist[0] == lightnumber
float intensity;
const dlight_t *light = (dlight_t *)ent;
intensity = 0.5;
intensity = 0.75 + 0.25 * sin(realtime * M_PI * 4.0);
if (!light->shadow)
intensity *= 0.5f;
- R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacenumber]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
+ R_DrawSprite(GL_SRC_ALPHA, GL_ONE, r_crosshairs[surfacelist[0]]->tex, NULL, false, light->origin, r_viewright, r_viewup, 8, -8, -8, 8, intensity, intensity, intensity, 0.5);
}
void R_Shadow_DrawLightSprites(void)
#include "quakedef.h"
#include "r_shadow.h"
-void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, int surfacenumber, const rtlight_t *rtlight)
+void R_Model_Sprite_Draw_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
{
int i;
model_t *model = ent->model;