From 5d04684b45d2ebb6f28f7ab0d2563b1de9d713cc Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 26 Apr 2006 12:57:21 +0000 Subject: [PATCH] now does batching of transparent surfaces, such as particles, this raised performance in bigass1.dem from 143fps to 184fps (it uses a lot of particles) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@6332 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 301 ++++++++++++++++++++++++++++++------------------- gl_rmain.c | 40 +++++-- gl_rsurf.c | 37 ++++-- meshqueue.c | 40 ++++++- meshqueue.h | 4 +- prvm_cmds.c | 115 ++++++++++--------- r_explosion.c | 28 ++--- r_lightning.c | 136 +++++++++++----------- r_shadow.c | 9 +- r_sprites.c | 2 +- 10 files changed, 431 insertions(+), 281 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index a1842bd8..d7ba1661 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -1962,87 +1962,122 @@ static void r_part_newmap(void) { } +#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)) @@ -2054,58 +2089,93 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, int surfacen 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) @@ -2127,12 +2197,7 @@ 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); } } } diff --git a/gl_rmain.c b/gl_rmain.c index 96e1a8d3..608ef9d7 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -2039,11 +2039,13 @@ float nomodelcolor4f[6*4] = 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) @@ -3150,17 +3152,37 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur } } -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(); } diff --git a/gl_rsurf.c b/gl_rsurf.c index 1ebbfecb..6db1aa00 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -337,8 +337,11 @@ void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ============================================================= */ -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; @@ -356,7 +359,7 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, int surfacenumber, 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), @@ -776,16 +779,36 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, } } -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(); } diff --git a/meshqueue.c b/meshqueue.c index b7087c01..6b6ff076 100644 --- a/meshqueue.c +++ b/meshqueue.c @@ -9,7 +9,7 @@ cvar_t r_meshqueue_sort = {0, "r_meshqueue_sort", "0", "whether to sort meshes i 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; @@ -37,11 +37,12 @@ void R_MeshQueue_Init(void) 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; } @@ -59,12 +60,13 @@ static void R_MeshQueue_EnlargeTransparentArray(int newtotal) 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) @@ -108,7 +110,7 @@ void R_MeshQueue_Add(void (*callback)(const entity_render_t *ent, int surfacenum *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) @@ -127,9 +129,14 @@ void R_MeshQueue_RenderTransparent(void) { 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) @@ -148,10 +155,31 @@ void R_MeshQueue_RenderTransparent(void) *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; } diff --git a/meshqueue.h b/meshqueue.h index fd6cce45..be2e3f08 100644 --- a/meshqueue.h +++ b/meshqueue.h @@ -3,8 +3,8 @@ #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); diff --git a/prvm_cmds.c b/prvm_cmds.c index a3eacce9..0ea7436e 100644 --- a/prvm_cmds.c +++ b/prvm_cmds.c @@ -2855,75 +2855,80 @@ void VM_InitPolygons (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 + } } } diff --git a/r_explosion.c b/r_explosion.c index 4dd9f853..a486f42d 100644 --- a/r_explosion.c +++ b/r_explosion.c @@ -180,34 +180,30 @@ void R_NewExplosion(const vec3_t org) } } -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) diff --git a/r_lightning.c b/r_lightning.c index fb219273..8bc56007 100644 --- a/r_lightning.c +++ b/r_lightning.c @@ -229,57 +229,14 @@ void R_FogLightningBeam_Vertex3f_Color4f(const float *v, float *c, int numverts, 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); @@ -288,21 +245,6 @@ void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, int sur 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) { @@ -324,10 +266,76 @@ void R_DrawLightningBeam_TransparentCallback(const entity_render_t *ent, int sur 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) diff --git a/r_shadow.c b/r_shadow.c index d845cb3b..c54e8b75 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -2649,14 +2649,17 @@ void R_Shadow_SelectLight(dlight_t *light) 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; @@ -2664,7 +2667,7 @@ void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, in 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) diff --git a/r_sprites.c b/r_sprites.c index 0c1b922f..02f7f2e1 100644 --- a/r_sprites.c +++ b/r_sprites.c @@ -2,7 +2,7 @@ #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; -- 2.39.2