From 96175f8db661871ffa3a16a20f68cf8552250dcf Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 8 Nov 2009 17:06:13 +0000 Subject: [PATCH] new decal system (cl_decals_newsystem 1 to activate) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9455 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_main.c | 9 + cl_parse.c | 1 + cl_particles.c | 81 ++++++++- client.h | 7 +- clvm_cmds.c | 1 + gl_rmain.c | 451 +++++++++++++++++++++++++++++++++---------------- model_shared.h | 2 - render.h | 2 + 8 files changed, 399 insertions(+), 155 deletions(-) diff --git a/cl_main.c b/cl_main.c index 5e6521f2..8d3468ea 100644 --- a/cl_main.c +++ b/cl_main.c @@ -190,6 +190,7 @@ void CL_ClearState(void) ent->render.alpha = 1; ent->render.flags = RENDER_SHADOW | RENDER_LIGHT; Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1); + ent->render.allowdecals = true; CL_UpdateRenderEntity(&ent->render); // noclip is turned off at start @@ -1098,6 +1099,7 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat e->render.flags |= RENDER_DOUBLESIDED; // make the other useful stuff + e->render.allowdecals = true; CL_UpdateRenderEntity(&e->render); } @@ -1236,6 +1238,8 @@ void CL_UpdateNetworkCollisionEntities(void) } } +extern void R_DecalSystem_Reset(decalsystem_t *decalsystem); + /* =============== CL_UpdateNetworkEntities @@ -1260,7 +1264,10 @@ void CL_UpdateNetworkEntities(void) CL_UpdateNetworkEntityTrail(ent); } else + { + R_DecalSystem_Reset(&ent->render.decalsystem); cl.entities_active[i] = false; + } } } } @@ -1479,6 +1486,7 @@ void CL_RelinkWorld(void) ent->render.flags |= RENDER_LIGHT; VectorSet(ent->render.colormod, 1, 1, 1); VectorSet(ent->render.glowmod, 1, 1, 1); + ent->render.allowdecals = true; CL_UpdateRenderEntity(&ent->render); r_refdef.scene.worldentity = &ent->render; r_refdef.scene.worldmodel = cl.worldmodel; @@ -1508,6 +1516,7 @@ static void CL_RelinkStaticEntities(void) VectorSet(e->render.colormod, 1, 1, 1); VectorSet(e->render.glowmod, 1, 1, 1); R_LerpAnimation(&e->render); + e->render.allowdecals = true; CL_UpdateRenderEntity(&e->render); r_refdef.scene.entities[r_refdef.scene.numentities++] = &e->render; } diff --git a/cl_parse.c b/cl_parse.c index e41b20fb..a57cab57 100644 --- a/cl_parse.c +++ b/cl_parse.c @@ -2144,6 +2144,7 @@ void CL_ParseStatic (int large) //VectorCopy (ent->state_baseline.angles, ent->render.angles); Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, ent->state_baseline.origin[0], ent->state_baseline.origin[1], ent->state_baseline.origin[2], ent->state_baseline.angles[0], ent->state_baseline.angles[1], ent->state_baseline.angles[2], 1); + ent->render.allowdecals = true; CL_UpdateRenderEntity(&ent->render); } diff --git a/cl_particles.c b/cl_particles.c index 663e656d..51fe7c24 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -217,6 +217,8 @@ cvar_t cl_decals = {CVAR_SAVE, "cl_decals", "1", "enables decals (bullet holes, cvar_t cl_decals_visculling = {CVAR_SAVE, "cl_decals_visculling", "1", "perform a very cheap check if each decal is visible before drawing"}; cvar_t cl_decals_time = {CVAR_SAVE, "cl_decals_time", "20", "how long before decals start to fade away"}; cvar_t cl_decals_fadetime = {CVAR_SAVE, "cl_decals_fadetime", "1", "how long decals take to fade away"}; +cvar_t cl_decals_newsystem = {CVAR_SAVE, "cl_decals_newsystem", "0", "enables new advanced decal system"}; +cvar_t cl_decals_bias = {CVAR_SAVE, "cl_decals_bias", "0.125", "distance to bias decals from surface to prevent depth fighting"}; void CL_Particles_ParseEffectInfo(const char *textstart, const char *textend) @@ -497,12 +499,17 @@ void CL_Particles_Init (void) Cvar_RegisterVariable (&cl_decals_visculling); Cvar_RegisterVariable (&cl_decals_time); Cvar_RegisterVariable (&cl_decals_fadetime); + Cvar_RegisterVariable (&cl_decals_newsystem); + Cvar_RegisterVariable (&cl_decals_bias); } void CL_Particles_Shutdown (void) { } +void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha); +void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size, float alpha, int texnum, int color1, int color2); + // list of all 26 parameters: // ptype - any of the pt_ enum values (pt_static, pt_blood, etc), see ptype_t near the top of this file // pcolor1,pcolor2 - minimum and maximum ranges of color, randomly interpolated to decide particle color @@ -641,15 +648,57 @@ particle_t *CL_NewParticle(unsigned short ptypeindex, int pcolor1, int pcolor2, trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, true, false, NULL, false); part->delayedcollisions = cl.time + lifetime * trace.fraction - 0.1; } + return part; } +static void CL_ImmediateBloodStain(particle_t *part) +{ + vec3_t v; + int staintex; + + // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot + if (part->staintexnum >= 0 && cl_decals_newsystem.integer && cl_decals.integer) + { + VectorCopy(part->vel, v); + VectorNormalize(v); + staintex = part->staintexnum; + R_DecalSystem_SplatEntities(part->org, v, 1-((part->staincolor>>16)&255)*(1.0f/255.0f), 1-((part->staincolor>>8)&255)*(1.0f/255.0f), 1-((part->staincolor)&255)*(1.0f/255.0f), part->alpha*(1.0f/255.0f), particletexture[staintex].s1, particletexture[staintex].t1, particletexture[staintex].s2, particletexture[staintex].t2, part->size * 2); + } + + // blood creates a splash at spawn, not just at impact, this makes monsters bloody where they are shot + if (part->typeindex == pt_blood && cl_decals_newsystem.integer && cl_decals.integer) + { + VectorCopy(part->vel, v); + VectorNormalize(v); + staintex = tex_blooddecal[rand()&7]; + R_DecalSystem_SplatEntities(part->org, v, part->color[0]*(1.0f/255.0f), part->color[1]*(1.0f/255.0f), part->color[2]*(1.0f/255.0f), part->alpha*(1.0f/255.0f), particletexture[staintex].s1, particletexture[staintex].t1, particletexture[staintex].s2, particletexture[staintex].t2, part->size * 2); + } +} + void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t normal, int color1, int color2, int texnum, float size, float alpha) { int l1, l2; decal_t *decal; + entity_render_t *ent = &cl.entities[hitent].render; + unsigned char color[3]; if (!cl_decals.integer) return; + if (!ent->allowdecals) + return; + + l2 = (int)lhrandom(0.5, 256.5); + l1 = 256 - l2; + color[0] = ((((color1 >> 16) & 0xFF) * l1 + ((color2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; + color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; + color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + + if (cl_decals_newsystem.integer) + { + R_DecalSystem_SplatEntities(org, normal, color[0]*(1.0f/255.0f), color[1]*(1.0f/255.0f), color[2]*(1.0f/255.0f), alpha*(1.0f/255.0f), particletexture[texnum].s1, particletexture[texnum].t1, particletexture[texnum].s2, particletexture[texnum].t2, size); + return; + } + for (;cl.free_decal < cl.max_decals && cl.decals[cl.free_decal].typeindex;cl.free_decal++); if (cl.free_decal >= cl.max_decals) return; @@ -659,16 +708,14 @@ void CL_SpawnDecalParticleForSurface(int hitent, const vec3_t org, const vec3_t memset(decal, 0, sizeof(*decal)); decal->typeindex = pt_decal; decal->texnum = texnum; - VectorAdd(org, normal, decal->org); + VectorMA(org, cl_decals_bias.value, normal, decal->org); VectorCopy(normal, decal->normal); decal->size = size; decal->alpha = alpha; decal->time2 = cl.time; - l2 = (int)lhrandom(0.5, 256.5); - l1 = 256 - l2; - decal->color[0] = ((((color1 >> 16) & 0xFF) * l1 + ((color2 >> 16) & 0xFF) * l2) >> 8) & 0xFF; - decal->color[1] = ((((color1 >> 8) & 0xFF) * l1 + ((color2 >> 8) & 0xFF) * l2) >> 8) & 0xFF; - decal->color[2] = ((((color1 >> 0) & 0xFF) * l1 + ((color2 >> 0) & 0xFF) * l2) >> 8) & 0xFF; + decal->color[0] = color[0]; + decal->color[1] = color[1]; + decal->color[2] = color[2]; decal->owner = hitent; decal->clusterindex = -1000; // no vis culling unless we're sure if (hitent) @@ -722,6 +769,7 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o { vec3_t center; matrix4x4_t tempmatrix; + particle_t *part; VectorLerp(originmins, 0.5, originmaxs, center); Matrix4x4_CreateTranslate(&tempmatrix, center[0], center[1], center[2]); if (effectnameindex == EFFECT_SVC_PARTICLE) @@ -839,10 +887,18 @@ void CL_ParticleEffect_Fallback(int effectnameindex, float count, const vec3_t o else { static double bloodaccumulator = 0; + qboolean immediatebloodstain = true; //CL_NewParticle(pt_alphastatic, 0x4f0000,0x7f0000, tex_particle, 2.5, 0, 256, 256, 0, 0, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), 0, 0, 0, 1, 4, 0, 0, true, 0, 1, PBLEND_ALPHA, PARTICLE_BILLBOARD); bloodaccumulator += count * 0.333 * cl_particles_quality.value; for (;bloodaccumulator > 0;bloodaccumulator--) - CL_NewParticle(pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, cl_particles_blood_alpha.value * 768, cl_particles_blood_alpha.value * 384, 1, -1, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64, true, 0, 1, PBLEND_INVMOD, PARTICLE_BILLBOARD, -1, -1, -1); + { + part = CL_NewParticle(pt_blood, 0xFFFFFF, 0xFFFFFF, tex_bloodparticle[rand()&7], 8, 0, cl_particles_blood_alpha.value * 768, cl_particles_blood_alpha.value * 384, 1, -1, lhrandom(originmins[0], originmaxs[0]), lhrandom(originmins[1], originmaxs[1]), lhrandom(originmins[2], originmaxs[2]), lhrandom(velocitymins[0], velocitymaxs[0]), lhrandom(velocitymins[1], velocitymaxs[1]), lhrandom(velocitymins[2], velocitymaxs[2]), 1, 4, 0, 64, true, 0, 1, PBLEND_INVMOD, PARTICLE_BILLBOARD, -1, -1, -1); + if (immediatebloodstain && part) + { + immediatebloodstain = false; + CL_ImmediateBloodStain(part); + } + } } } else if (effectnameindex == EFFECT_TE_SPARK) @@ -1256,6 +1312,8 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins vec_t traillen; vec_t trailstep; qboolean underwater; + qboolean immediatebloodstain; + particle_t *part; // note this runs multiple effects with the same name, each one spawns only one kind of particle, so some effects need more than one VectorLerp(originmins, 0.5, originmaxs, center); VectorLerp(velocitymins, 0.5, velocitymaxs, centervelocity); @@ -1338,11 +1396,13 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins { info->particleaccumulator += traillen / info->trailspacing * cl_particles_quality.value; trailstep = info->trailspacing / cl_particles_quality.value; + immediatebloodstain = false; } else { info->particleaccumulator += info->countabsolute + pcount * info->countmultiplier * cl_particles_quality.value; trailstep = 0; + immediatebloodstain = info->particletype == pt_blood || staintex; } info->particleaccumulator = bound(0, info->particleaccumulator, 16384); for (;info->particleaccumulator >= 1;info->particleaccumulator--) @@ -1359,7 +1419,12 @@ void CL_ParticleTrail(int effectnameindex, float pcount, const vec3_t originmins trailpos[2] = lhrandom(originmins[2], originmaxs[2]); } VectorRandom(rvec); - CL_NewParticle(info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], info->gravity, info->bounce, trailpos[0] + info->originoffset[0] + info->originjitter[0] * rvec[0], trailpos[1] + info->originoffset[1] + info->originjitter[1] * rvec[1], trailpos[2] + info->originoffset[2] + info->originjitter[2] * rvec[2], lhrandom(velocitymins[0], velocitymaxs[0]) * info->velocitymultiplier + info->velocityoffset[0] + info->velocityjitter[0] * rvec[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2], info->airfriction, info->liquidfriction, 0, 0, info->countabsolute <= 0, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex); + part = CL_NewParticle(info->particletype, info->color[0], info->color[1], tex, lhrandom(info->size[0], info->size[1]), info->size[2], lhrandom(info->alpha[0], info->alpha[1]), info->alpha[2], info->gravity, info->bounce, trailpos[0] + info->originoffset[0] + info->originjitter[0] * rvec[0], trailpos[1] + info->originoffset[1] + info->originjitter[1] * rvec[1], trailpos[2] + info->originoffset[2] + info->originjitter[2] * rvec[2], lhrandom(velocitymins[0], velocitymaxs[0]) * info->velocitymultiplier + info->velocityoffset[0] + info->velocityjitter[0] * rvec[0], lhrandom(velocitymins[1], velocitymaxs[1]) * info->velocitymultiplier + info->velocityoffset[1] + info->velocityjitter[1] * rvec[1], lhrandom(velocitymins[2], velocitymaxs[2]) * info->velocitymultiplier + info->velocityoffset[2] + info->velocityjitter[2] * rvec[2], info->airfriction, info->liquidfriction, 0, 0, info->countabsolute <= 0, lhrandom(info->time[0], info->time[1]), info->stretchfactor, info->blendmode, info->orientation, info->staincolor[0], info->staincolor[1], staintex); + if (immediatebloodstain && part) + { + immediatebloodstain = false; + CL_ImmediateBloodStain(part); + } if (trailstep) VectorMA(trailpos, trailstep, traildir, trailpos); } diff --git a/client.h b/client.h index 4e62011c..c57c0177 100644 --- a/client.h +++ b/client.h @@ -39,10 +39,8 @@ typedef struct tridecal_s { // color and initial alpha value unsigned char colors[3][4]; - // alpha of this decal, starting at 1 (cl_decals_fadetime) - float alpha; - // timer before fade begins (cl_decals_time) - float fade; + // how long this decal has lived so far (the actual fade begins at cl_decals_time) + float lived; // if >= 0 this indicates the decal should follow an animated triangle int triangleindex; } @@ -50,6 +48,7 @@ tridecal_t; typedef struct decalsystem_s { + dp_model_t *model; double lastupdatetime; int maxdecals; int freedecal; diff --git a/clvm_cmds.c b/clvm_cmds.c index fc0ad585..d509e74c 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -1479,6 +1479,7 @@ static void VM_CL_makestatic (void) if (staticent->render.effects & EF_DOUBLESIDED) staticent->render.flags |= RENDER_DOUBLESIDED; + staticent->render.allowdecals = true; CL_UpdateRenderEntity(&staticent->render); } else diff --git a/gl_rmain.c b/gl_rmain.c index b9d2283f..5e7bcb1a 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -85,7 +85,9 @@ cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlightin cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"}; cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"}; cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; -cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "4", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; +cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"}; +cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"}; +cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"}; cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"}; cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"}; @@ -3014,6 +3016,8 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_q1bsp_skymasking); Cvar_RegisterVariable(&r_polygonoffset_submodel_factor); Cvar_RegisterVariable(&r_polygonoffset_submodel_offset); + Cvar_RegisterVariable(&r_polygonoffset_decals_factor); + Cvar_RegisterVariable(&r_polygonoffset_decals_offset); Cvar_RegisterVariable(&r_fog_exp2); Cvar_RegisterVariable(&r_drawfog); Cvar_RegisterVariable(&r_textureunits); @@ -3645,6 +3649,28 @@ static void R_DrawModelsAddWaterPlanes(void) } } +static void R_DrawModelDecals_Entity(entity_render_t *ent); +static void R_DrawModelDecals(void) +{ + int i; + entity_render_t *ent; + + R_DrawModelDecals_Entity(r_refdef.scene.worldentity); + + if (!r_drawentities.integer || r_showsurfaces.integer) + return; + + for (i = 0;i < r_refdef.scene.numentities;i++) + { + if (!r_refdef.viewcache.entityvisible[i]) + continue; + ent = r_refdef.scene.entities[i]; + r_refdef.stats.entities++; + if (ent->decalsystem.numdecals) + R_DrawModelDecals_Entity(ent); + } +} + static void R_View_SetFrustum(void) { int i; @@ -4934,6 +4960,7 @@ extern void R_DrawPortals (void); extern cvar_t cl_locs_show; static void R_DrawLocs(void); static void R_DrawEntityBBoxes(void); +extern cvar_t cl_decals_newsystem; void R_RenderScene(void) { r_refdef.stats.renders++; @@ -5037,13 +5064,18 @@ void R_RenderScene(void) if (cl.csqc_vidvars.drawworld) { - R_DrawLightningBeams(); - if (r_timereport_active) - R_TimeReport("lightning"); - - R_DrawDecals(); - if (r_timereport_active) - R_TimeReport("decals"); + if (cl_decals_newsystem.integer) + { + R_DrawModelDecals(); + if (r_timereport_active) + R_TimeReport("modeldecals"); + } + else + { + R_DrawDecals(); + if (r_timereport_active) + R_TimeReport("decals"); + } R_DrawParticles(); if (r_timereport_active) @@ -5052,6 +5084,10 @@ void R_RenderScene(void) R_DrawExplosions(); if (r_timereport_active) R_TimeReport("explosions"); + + R_DrawLightningBeams(); + if (r_timereport_active) + R_TimeReport("lightning"); } R_SetupGenericShader(true); @@ -8124,6 +8160,8 @@ void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, co { float *v3f; float *tc2f; + float *c4f; + float ca; tridecal_t *decal; tridecal_t *decals; int i; @@ -8136,12 +8174,12 @@ void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, co qboolean useshortelements; decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2); useshortelements = decalsystem->maxdecals * 3 <= 65536; - decalsystem->decals = Mem_Alloc(r_main_mempool, decalsystem->maxdecals * (sizeof(tridecal_t) + sizeof(float[3][3]) + sizeof(float[3][2]) + sizeof(float[3][4]) + sizeof(int[3]) + useshortelements ? sizeof(unsigned short[3]) : 0)); - decalsystem->vertex3f = (float *)(decalsystem->decals + decalsystem->maxdecals); - decalsystem->texcoord2f = (float *)(decalsystem->vertex3f + decalsystem->maxdecals*9); - decalsystem->color4f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6); - decalsystem->element3i = (int *)(decalsystem->color4f + decalsystem->maxdecals*12); - decalsystem->element3s = useshortelements ? (unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3) : NULL; + decalsystem->decals = Mem_Alloc(cls.levelmempool, decalsystem->maxdecals * (sizeof(tridecal_t) + sizeof(float[3][3]) + sizeof(float[3][2]) + sizeof(float[3][4]) + sizeof(int[3]) + (useshortelements ? sizeof(unsigned short[3]) : 0))); + decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals); + decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12); + decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6); + decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9); + decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL); if (decalsystem->numdecals) { memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t)); @@ -8149,6 +8187,7 @@ void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, co memcpy(decalsystem->texcoord2f, old.texcoord2f, decalsystem->numdecals * sizeof(float[3][2])); memcpy(decalsystem->color4f, old.color4f, decalsystem->numdecals * sizeof(float[3][4])); } + Mem_Free(old.decals); for (i = 0;i < decalsystem->maxdecals*3;i++) decalsystem->element3i[i] = i; if (useshortelements) @@ -8162,27 +8201,28 @@ void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, co decal = decalsystem->decals + (i = decalsystem->freedecal++); v3f = decalsystem->vertex3f + 9*i; tc2f = decalsystem->texcoord2f + 6*i; - for (i = decalsystem->freedecal;i < maxdecals && decals[i].alpha;i++) + c4f = decalsystem->color4f + 12*i; + for (i = decalsystem->freedecal;i < maxdecals && decals[i].colors[0][3];i++) ; decalsystem->freedecal = i; if (decalsystem->numdecals <= i) decalsystem->numdecals = i + 1; // initialize the decal - decal->fade = cl_decals_time.value; - decal->alpha = 1.0f; + decal->lived = 0; + decal->triangleindex = triangleindex; decal->colors[0][0] = (unsigned char)(c0[0]*255.0f); decal->colors[0][1] = (unsigned char)(c0[1]*255.0f); decal->colors[0][2] = (unsigned char)(c0[2]*255.0f); - decal->colors[0][3] = (unsigned char)(c0[3]*255.0f); + decal->colors[0][3] = 255; decal->colors[1][0] = (unsigned char)(c1[0]*255.0f); decal->colors[1][1] = (unsigned char)(c1[1]*255.0f); decal->colors[1][2] = (unsigned char)(c1[2]*255.0f); - decal->colors[1][3] = (unsigned char)(c1[3]*255.0f); + decal->colors[1][3] = 255; decal->colors[2][0] = (unsigned char)(c2[0]*255.0f); decal->colors[2][1] = (unsigned char)(c2[1]*255.0f); decal->colors[2][2] = (unsigned char)(c2[2]*255.0f); - decal->colors[2][3] = (unsigned char)(c2[3]*255.0f); + decal->colors[2][3] = 255; v3f[0] = v0[0]; v3f[1] = v0[1]; v3f[2] = v0[2]; @@ -8198,146 +8238,280 @@ void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, co tc2f[3] = t1[1]; tc2f[4] = t2[0]; tc2f[5] = t2[1]; -} - -void R_DecalSystem_Splat(decalsystem_t *decalsystem, int numvertices, const float *vertex3f, int numtriangles, const int *element3i, const matrix4x4_t *projection, float r, float g, float b, float a, qboolean dynamic) -{ - int vertexindex; + ca = (1.0f/255.0f); + c4f[ 0] = decal->colors[0][0] * ca; + c4f[ 1] = decal->colors[0][1] * ca; + c4f[ 2] = decal->colors[0][2] * ca; + c4f[ 3] = 1; + c4f[ 4] = decal->colors[1][0] * ca; + c4f[ 5] = decal->colors[1][1] * ca; + c4f[ 6] = decal->colors[1][2] * ca; + c4f[ 7] = 1; + c4f[ 8] = decal->colors[2][0] * ca; + c4f[ 9] = decal->colors[2][1] * ca; + c4f[10] = decal->colors[2][2] * ca; + c4f[11] = 1; +} + +extern cvar_t cl_decals_bias; +void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize) +{ + matrix4x4_t projection; + decalsystem_t *decalsystem; + qboolean dynamic; + dp_model_t *model; + const float *vertex3f; + const msurface_t *surface; + const msurface_t *surfaces; + const int *surfacelist; + int numvertices; + int numtriangles; + int numsurfacelist; + int surfacelistindex; int triangleindex; int cornerindex; int index; int numpoints; const int *e; + float localorigin[3]; + float localnormal[3]; + float localmins[3]; + float localmaxs[3]; + float localsize; + float ilocalsize; float v[9][3]; - float tc[9][3]; // third coord is distance fade + float tc[9][2]; float c[9][4]; - float *temp; - float origin[3]; - float normal[3]; - float planes[6][3]; + //float normal[3]; + float planes[6][4]; float f; float points[2][9][3]; - temp = Mem_Alloc(tempmempool, numvertices * sizeof(float[3])); - for (vertexindex = 0;vertexindex < numvertices;vertexindex++) - Matrix4x4_Transform(projection, vertex3f + 3*vertexindex, temp + 3*vertexindex); - for (triangleindex = 0, e = element3i;triangleindex < numtriangles;triangleindex++, e += 3) + float angles[3]; + float temp[3]; + + model = ent->model; + if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST))) { - for (cornerindex = 0;cornerindex < 3;cornerindex++) - { - index = 3*e[cornerindex]; - VectorCopy(temp + index, tc[cornerindex]); - } - // cull triangles that are entirely outside the projection - if (min(tc[0][0], min(tc[1][0], tc[2][0])) >= 1) - continue; - if (min(tc[0][1], min(tc[1][1], tc[2][1])) >= 1) - continue; - if (min(tc[0][2], min(tc[1][2], tc[2][2])) >= 1) - continue; - if (max(tc[0][0], max(tc[1][0], tc[2][0])) <= -1) - continue; - if (max(tc[0][1], max(tc[1][1], tc[2][1])) <= -1) - continue; - if (max(tc[0][2], max(tc[1][2], tc[2][2])) <= -1) + R_DecalSystem_Reset(&ent->decalsystem); + return; + } + + decalsystem = &ent->decalsystem; + if (decalsystem->model != model) + R_DecalSystem_Reset(decalsystem); + decalsystem->model = model; + + RSurf_ActiveModelEntity(ent, false, false); + + Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin); + Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal); + VectorNormalize(localnormal); + localsize = worldsize*rsurface.inversematrixscale; + ilocalsize = 1.0f / localsize; + localmins[0] = localorigin[0] - localsize; + localmins[1] = localorigin[1] - localsize; + localmins[2] = localorigin[2] - localsize; + localmaxs[0] = localorigin[0] + localsize; + localmaxs[1] = localorigin[1] + localsize; + localmaxs[2] = localorigin[2] + localsize; + + //VectorCopy(localnormal, planes[4]); + //VectorVectors(planes[4], planes[2], planes[0]); + AnglesFromVectors(angles, localnormal, NULL, false); + AngleVectors(angles, planes[0], planes[2], planes[4]); + VectorNegate(planes[0], planes[1]); + VectorNegate(planes[2], planes[3]); + VectorNegate(planes[4], planes[5]); + planes[0][3] = DotProduct(planes[0], localorigin) - localsize; + planes[1][3] = DotProduct(planes[1], localorigin) - localsize; + planes[2][3] = DotProduct(planes[2], localorigin) - localsize; + planes[3][3] = DotProduct(planes[3], localorigin) - localsize; + planes[4][3] = DotProduct(planes[4], localorigin) - localsize; + planes[5][3] = DotProduct(planes[5], localorigin) - localsize; + +#if 1 +// works +{ + matrix4x4_t forwardprojection; + Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize); + Matrix4x4_Invert_Simple(&projection, &forwardprojection); +} +#else +// broken +{ + float projectionvector[4][3]; + VectorScale(planes[0], ilocalsize, projectionvector[0]); + VectorScale(planes[2], ilocalsize, projectionvector[1]); + VectorScale(planes[4], ilocalsize, projectionvector[2]); + projectionvector[0][0] = planes[0][0] * ilocalsize; + projectionvector[0][1] = planes[1][0] * ilocalsize; + projectionvector[0][2] = planes[2][0] * ilocalsize; + projectionvector[1][0] = planes[0][1] * ilocalsize; + projectionvector[1][1] = planes[1][1] * ilocalsize; + projectionvector[1][2] = planes[2][1] * ilocalsize; + projectionvector[2][0] = planes[0][2] * ilocalsize; + projectionvector[2][1] = planes[1][2] * ilocalsize; + projectionvector[2][2] = planes[2][2] * ilocalsize; + projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]); + projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]); + projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]); + Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]); +} +#endif + + dynamic = model->surfmesh.isanimated; + vertex3f = rsurface.modelvertex3f; + numsurfacelist = model->nummodelsurfaces; + surfacelist = model->sortedmodelsurfaces; + surfaces = model->data_surfaces; + for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++) + { + surface = surfaces + surfacelist[surfacelistindex]; + // skip transparent surfaces + if ((surface->texture->surfaceflags & Q3SURFACEFLAG_NOMARKS) || surface->texture->currentalpha < 1 || (surface->texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))) continue; - // cull backfaces - TriangleNormal(tc[0], tc[1], tc[2], normal); - if (normal[2] < 0) + if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs)) continue; - // we accept this triangle - for (cornerindex = 0;cornerindex < 3;cornerindex++) - { - index = 3*e[cornerindex]; - VectorCopy(vertex3f + index, v[cornerindex]); - // calculate distance fade from the projection origin - f = a * (1-fabs(tc[cornerindex][2])); - c[cornerindex][0] = r * f; - c[cornerindex][1] = g * f; - c[cornerindex][2] = b * f; - c[cornerindex][3] = 1; - } - if (dynamic) - { - R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex); - } - else + numvertices = surface->num_vertices; + numtriangles = surface->num_triangles; + for (triangleindex = 0, e = model->surfmesh.data_element3i + 3*surface->num_firsttriangle;triangleindex < numtriangles;triangleindex++, e += 3) { + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + index = 3*e[cornerindex]; + VectorCopy(vertex3f + index, v[cornerindex]); + } + // cull backfaces + //TriangleNormal(v[0], v[1], v[2], normal); + //if (DotProduct(normal, localnormal) < 0.0f) + // continue; // clip by each of the box planes formed from the projection matrix - Matrix4x4_ToVectors(projection, planes[0], planes[2], planes[4], origin); - VectorNegate(planes[0], planes[1]); - VectorNegate(planes[2], planes[3]); - VectorNegate(planes[4], planes[5]); - VectorCopy(planes[4], normal); - VectorNormalize(normal); - VectorMA(v[0], 0.125f, planes[4], v[0]); - VectorMA(v[1], 0.125f, planes[4], v[1]); - VectorMA(v[2], 0.125f, planes[4], v[2]); - numpoints = PolygonF_Clip(3 , v[0] , planes[0][0], planes[0][1], planes[0][2], DotProduct(planes[0], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); - numpoints = PolygonF_Clip(numpoints, points[1][0], planes[1][0], planes[1][1], planes[1][2], DotProduct(planes[1], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); - numpoints = PolygonF_Clip(numpoints, points[0][0], planes[2][0], planes[2][1], planes[2][2], DotProduct(planes[2], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); - numpoints = PolygonF_Clip(numpoints, points[1][0], planes[3][0], planes[3][1], planes[3][2], DotProduct(planes[3], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); - numpoints = PolygonF_Clip(numpoints, points[0][0], planes[4][0], planes[4][1], planes[4][2], DotProduct(planes[4], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); - numpoints = PolygonF_Clip(numpoints, points[1][0], planes[5][0], planes[5][1], planes[5][2], DotProduct(planes[5], origin) - 1, 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), v[0]); + // if anything survives, we emit the decal + numpoints = PolygonF_Clip(3 , v[0] , planes[0][0], planes[0][1], planes[0][2], planes[0][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[1][0], planes[1][1], planes[1][2], planes[1][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); + numpoints = PolygonF_Clip(numpoints, points[0][0], planes[2][0], planes[2][1], planes[2][2], planes[2][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[3][0], planes[3][1], planes[3][2], planes[3][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]); + numpoints = PolygonF_Clip(numpoints, points[0][0], planes[4][0], planes[4][1], planes[4][2], planes[4][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]); + numpoints = PolygonF_Clip(numpoints, points[1][0], planes[5][0], planes[5][1], planes[5][2], planes[5][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), v[0]); + if (numpoints < 3) + continue; + // some part of the triangle survived, so we have to accept it... + if (dynamic) + { + // dynamic always uses the original triangle + numpoints = 3; + for (cornerindex = 0;cornerindex < 3;cornerindex++) + { + index = 3*e[cornerindex]; + VectorCopy(vertex3f + index, v[cornerindex]); + } + } for (cornerindex = 0;cornerindex < numpoints;cornerindex++) { // convert vertex positions to texcoords - Matrix4x4_Transform(projection, v[cornerindex], tc[cornerindex]); + Matrix4x4_Transform(&projection, v[cornerindex], temp); + tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1; + tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1; // calculate distance fade from the projection origin - f = a * (1-fabs(tc[cornerindex][2])); + f = a * (1.0f-fabs(temp[0])); + f = max(0.0f, f); c[cornerindex][0] = r * f; c[cornerindex][1] = g * f; c[cornerindex][2] = b * f; - c[cornerindex][3] = 1; + c[cornerindex][3] = 1.0f; + //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]); } - for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++) - R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1); + if (dynamic) + R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex); + else + for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++) + R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1); } } } +void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize) +{ + int renderentityindex; + float worldmins[3]; + float worldmaxs[3]; + entity_render_t *ent; + + worldmins[0] = worldorigin[0] - worldsize; + worldmins[1] = worldorigin[1] - worldsize; + worldmins[2] = worldorigin[2] - worldsize; + worldmaxs[0] = worldorigin[0] + worldsize; + worldmaxs[1] = worldorigin[1] + worldsize; + worldmaxs[2] = worldorigin[2] + worldsize; + + R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize); + + for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++) + { + ent = r_refdef.scene.entities[renderentityindex]; + if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs)) + continue; + + R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize); + } +} + extern skinframe_t *decalskinframe; -void RSurf_DrawTriDecals(void) +static void R_DrawModelDecals_Entity(entity_render_t *ent) { int i; - decalsystem_t *decalsystem = &rsurface.entity->decalsystem; - int numdecals = decalsystem->numdecals; - tridecal_t *decal = decalsystem->decals; - float frametime = cl.time - decalsystem->lastupdatetime; - float decalfade; - float alphascale; - float ca; + decalsystem_t *decalsystem = &ent->decalsystem; + int numdecals; + tridecal_t *decal; + float frametime; + float fadedelay; + float faderate; + float alpha; float *v3f; float *c4f; const int *e; - decalsystem->lastupdatetime = cl.time; - if (!decalsystem->numdecals) return; - decalfade = 1.0f / max(0.001f, cl_decals_fadetime.value); - alphascale = (1.0f / 255.0f); + if (r_showsurfaces.integer) + return; - if (rsurface.ent_color[3] < 1 || (rsurface.ent_flags & RENDER_ADDITIVE)) + if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE)) { - Mem_Free(decalsystem->decals); - memset(decalsystem, 0, sizeof(*decalsystem)); + R_DecalSystem_Reset(decalsystem); return; } - if (decalfade < 0) - decalfade = 0; + // if the model is static it doesn't matter what value we give for + // wantnormals and wanttangents, so this logic uses only rules applicable + // to a model, knowing that they are meaningless otherwise + if (ent == r_refdef.scene.worldentity) + RSurf_ActiveWorldEntity(); + else + RSurf_ActiveModelEntity(ent, false, false); + + if (decalsystem->lastupdatetime) + frametime = cl.time - decalsystem->lastupdatetime; + else + frametime = 0; + decalsystem->lastupdatetime = cl.time; + decal = decalsystem->decals; + numdecals = decalsystem->numdecals; + + fadedelay = cl_decals_time.value; + faderate = 1.0f / max(0.001f, cl_decals_fadetime.value); for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++) { - if (!decal->alpha) + if (!decal->colors[0][3]) continue; - decal->fade -= frametime; - if (decal->fade <= 0) + decal->lived += frametime; + if (decal->lived >= fadedelay) { - decal->alpha -= decalfade; - if (decal->alpha <= 0) + alpha = 1 - faderate * (decal->lived - cl_decals_time.value); + if (alpha <= 0) { // kill the decal by zeroing vertex data memset(decalsystem->vertex3f + 9*i, 0, sizeof(float[3][3])); @@ -8348,44 +8522,43 @@ void RSurf_DrawTriDecals(void) decalsystem->freedecal = i; continue; } - } - // update color values for fading decals - ca = decal->alpha * alphascale; - c4f = decalsystem->color4f + 12*i; - c4f[ 0] = decal->colors[0][0] * ca; - c4f[ 1] = decal->colors[0][1] * ca; - c4f[ 2] = decal->colors[0][2] * ca; - c4f[ 3] = 1; - c4f[ 4] = decal->colors[1][0] * ca; - c4f[ 5] = decal->colors[1][1] * ca; - c4f[ 6] = decal->colors[1][2] * ca; - c4f[ 7] = 1; - c4f[ 8] = decal->colors[2][0] * ca; - c4f[ 9] = decal->colors[2][1] * ca; - c4f[10] = decal->colors[2][2] * ca; - c4f[11] = 1; + // update color values for fading decals + alpha *= (1.0f/255.0f); + c4f = decalsystem->color4f + 12*i; + c4f[ 0] = decal->colors[0][0] * alpha; + c4f[ 1] = decal->colors[0][1] * alpha; + c4f[ 2] = decal->colors[0][2] * alpha; + c4f[ 3] = 1; + c4f[ 4] = decal->colors[1][0] * alpha; + c4f[ 5] = decal->colors[1][1] * alpha; + c4f[ 6] = decal->colors[1][2] * alpha; + c4f[ 7] = 1; + c4f[ 8] = decal->colors[2][0] * alpha; + c4f[ 9] = decal->colors[2][1] * alpha; + c4f[10] = decal->colors[2][2] * alpha; + c4f[11] = 1; + } // update vertex positions for animated models if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnum_triangles) { e = rsurface.modelelement3i + 3*decal->triangleindex; - v3f = decalsystem->vertex3f + i*i; + v3f = decalsystem->vertex3f + 9*i; VectorCopy(rsurface.vertex3f + 3*e[0], v3f); VectorCopy(rsurface.vertex3f + 3*e[1], v3f + 3); VectorCopy(rsurface.vertex3f + 3*e[2], v3f + 6); } - - r_refdef.stats.decals++; } // reduce numdecals if possible - while (numdecals > 0 && !decalsystem->decals[numdecals - 1].alpha) + while (numdecals > 0 && !decalsystem->decals[numdecals - 1].colors[0][3]) numdecals--; decalsystem->numdecals = numdecals; if (numdecals > 0) { + r_refdef.stats.decals += numdecals; // now render the decals all at once // (this assumes they all use one particle font texture!) RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numdecals, decalsystem->element3i, decalsystem->element3s, false, false); @@ -8396,16 +8569,18 @@ void RSurf_DrawTriDecals(void) R_SetupGenericShader(true); GL_DepthMask(false); GL_DepthRange(0, 1); - GL_PolygonOffset(0, 0); + GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value); GL_DepthTest(true); GL_CullFace(GL_NONE); GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); R_Mesh_TexBind(0, R_GetTexture(decalskinframe->base)); + //R_Mesh_TexBind(0, R_GetTexture(r_texture_white)); GL_LockArrays(0, numdecals * 3); R_Mesh_Draw(0, numdecals * 3, 0, numdecals, decalsystem->element3i, decalsystem->element3s, 0, 0); GL_LockArrays(0, 0); } - else + + if (numdecals <= 0) { // if there are no decals left, reset decalsystem R_DecalSystem_Reset(decalsystem); @@ -8643,9 +8818,6 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles; } - // draw decals - RSurf_DrawTriDecals(); - rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } @@ -8737,9 +8909,6 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles; } - // draw decals - RSurf_DrawTriDecals(); - rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity } diff --git a/model_shared.h b/model_shared.h index 986bad00..4caa59e0 100644 --- a/model_shared.h +++ b/model_shared.h @@ -856,8 +856,6 @@ typedef struct model_s // range of collision brush numbers in this (sub)model int firstmodelbrush; int nummodelbrushes; - // list of surface numbers in this (sub)model - int *surfacelist; // for md3 models int num_tags; int num_tagframes; diff --git a/render.h b/render.h index 1bcee791..a8936258 100644 --- a/render.h +++ b/render.h @@ -387,6 +387,8 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist); void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist); +void R_DecalSystem_SplatEntities(const vec3_t org, const vec3_t normal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float size); + typedef enum rsurfacepass_e { RSURFPASS_BASE, -- 2.39.2