cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
-cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
+cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
+cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
unsigned int r_texture_gammaramps_serial;
//rtexture_t *r_texture_fogintensity;
-unsigned int r_queries[R_MAX_OCCLUSION_QUERIES];
+unsigned int r_queries[MAX_OCCLUSION_QUERIES];
unsigned int r_numqueries;
unsigned int r_maxqueries;
}
r_glsl_permutation_t;
-#define SHADERPERMUTATION_HASHSIZE 4096
+#define SHADERPERMUTATION_HASHSIZE 256
/// information about each possible shader permutation
r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
}
-void R_Main_AllocViewCache(void)
+void R_Main_ResizeViewCache(void)
{
- memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
- r_refdef.viewcache.maxentities = r_refdef.scene.maxentities;
- if (r_refdef.viewcache.maxentities)
+ int numentities = r_refdef.scene.numentities;
+ int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
+ int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
+ int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
+ int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
+ if (r_refdef.viewcache.maxentities < numentities)
+ {
+ r_refdef.viewcache.maxentities = numentities;
+ if (r_refdef.viewcache.entityvisible)
+ Mem_Free(r_refdef.viewcache.entityvisible);
r_refdef.viewcache.entityvisible = Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
- if (cl.worldmodel)
- {
- r_refdef.viewcache.world_numclusters = cl.worldmodel->brush.num_pvsclusters;
- r_refdef.viewcache.world_numleafs = cl.worldmodel->brush.num_leafs;
- r_refdef.viewcache.world_numsurfaces = cl.worldmodel->num_surfaces;
- r_refdef.viewcache.world_pvsbits = Mem_Alloc(r_main_mempool, (r_refdef.viewcache.world_numclusters+7)>>3);
+ }
+ if (r_refdef.viewcache.world_numclusters != numclusters)
+ {
+ r_refdef.viewcache.world_numclusters = numclusters;
+ r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
+ if (r_refdef.viewcache.world_pvsbits)
+ Mem_Free(r_refdef.viewcache.world_pvsbits);
+ r_refdef.viewcache.world_pvsbits = Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
+ }
+ if (r_refdef.viewcache.world_numleafs != numleafs)
+ {
+ r_refdef.viewcache.world_numleafs = numleafs;
+ if (r_refdef.viewcache.world_leafvisible)
+ Mem_Free(r_refdef.viewcache.world_leafvisible);
r_refdef.viewcache.world_leafvisible = Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
+ }
+ if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
+ {
+ r_refdef.viewcache.world_numsurfaces = numsurfaces;
+ if (r_refdef.viewcache.world_surfacevisible)
+ Mem_Free(r_refdef.viewcache.world_surfacevisible);
r_refdef.viewcache.world_surfacevisible = Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
}
}
void gl_main_start(void)
{
- R_Main_AllocViewCache();
-
r_numqueries = 0;
r_maxqueries = 0;
memset(r_queries, 0, sizeof(r_queries));
CL_ParseEntityLump(cl.worldmodel->brush.entities);
}
R_Main_FreeViewCache();
- R_Main_AllocViewCache();
}
void GL_Main_Init(void)
Cvar_RegisterVariable(&r_drawentities);
Cvar_RegisterVariable(&r_cullentities_trace);
Cvar_RegisterVariable(&r_cullentities_trace_samples);
+ Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
Cvar_RegisterVariable(&r_cullentities_trace_delay);
Cvar_RegisterVariable(&r_drawviewmodel);
typedef struct r_animcache_s
{
- r_animcache_entity_t entity[MAX_EDICTS*2];
+ r_animcache_entity_t entity[MAX_EDICTS];
int maxindex;
int currentindex;
}
if (c->wanttangents)
wanttangents = false;
if (wantnormals || wanttangents)
- model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
}
else
{
c = r_animcachestate.entity + ent->animcacheindex;
c->wantnormals = wantnormals;
c->wanttangents = wanttangents;
- model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
+ model->AnimateVertices(model, ent->frameblend, ent->skeleton, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
}
return true;
}
static void R_View_UpdateEntityVisible (void)
{
- int i, renderimask;
+ int i;
+ int renderimask;
+ int samples;
entity_render_t *ent;
if (!r_drawentities.integer)
ent = r_refdef.scene.entities[i];
if(r_refdef.viewcache.entityvisible[i] && !(ent->flags & (RENDER_VIEWMODEL | RENDER_NOCULL | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
{
- if(R_CanSeeBox(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
+ samples = ent->entitynumber ? r_cullentities_trace_samples.integer : r_cullentities_trace_tempentitysamples.integer;
+ if (samples < 0)
+ continue; // temp entities do pvs only
+ if(R_CanSeeBox(samples, r_cullentities_trace_enlarge.value, r_refdef.view.origin, ent->mins, ent->maxs))
ent->last_trace_visibility = realtime;
if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
r_refdef.viewcache.entityvisible[i] = 0;
}
}
-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;
void R_View_Update(void)
{
+ R_Main_ResizeViewCache();
R_View_SetFrustum();
R_View_WorldVisibility(r_refdef.view.useclipplane);
R_View_UpdateEntityVisible();
extern cvar_t cl_locs_show;
static void R_DrawLocs(void);
static void R_DrawEntityBBoxes(void);
+static void R_DrawModelDecals(void);
extern cvar_t cl_decals_newsystem;
void R_RenderScene(void)
{
//if (rsurface.entity == r_refdef.scene.worldentity)
// return;
rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.skeleton = NULL;
rsurface.ent_skinnum = 0;
rsurface.ent_qwskin = -1;
rsurface.ent_shadertime = 0;
//if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
// return;
rsurface.entity = (entity_render_t *)ent;
+ rsurface.skeleton = ent->skeleton;
rsurface.ent_skinnum = ent->skinnum;
rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
rsurface.ent_shadertime = ent->shadertime;
rsurface.modelsvector3f = rsurface.array_modelsvector3f;
rsurface.modeltvector3f = rsurface.array_modeltvector3f;
rsurface.modelnormal3f = rsurface.array_modelnormal3f;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
}
else if (wantnormals)
{
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
rsurface.modelnormal3f = rsurface.array_modelnormal3f;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
}
else
{
rsurface.modelsvector3f = NULL;
rsurface.modeltvector3f = NULL;
rsurface.modelnormal3f = NULL;
- model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
+ model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, NULL, NULL, NULL);
}
rsurface.modelvertex3f_bufferobject = 0;
rsurface.modelvertex3f_bufferoffset = 0;
void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
{
rsurface.entity = r_refdef.scene.worldentity;
+ rsurface.skeleton = NULL;
rsurface.ent_skinnum = 0;
rsurface.ent_qwskin = -1;
rsurface.ent_shadertime = shadertime;
memset(decalsystem, 0, sizeof(*decalsystem));
}
-void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex)
+static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, int decalsequence)
{
- float *v3f;
- float *tc2f;
- float *c4f;
- float ca;
tridecal_t *decal;
tridecal_t *decals;
int i;
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));
- memcpy(decalsystem->vertex3f, old.vertex3f, decalsystem->numdecals * sizeof(float[3][3]));
- 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;
maxdecals = decalsystem->maxdecals;
decals = decalsystem->decals;
decal = decalsystem->decals + (i = decalsystem->freedecal++);
- v3f = decalsystem->vertex3f + 9*i;
- tc2f = decalsystem->texcoord2f + 6*i;
- c4f = decalsystem->color4f + 12*i;
- for (i = decalsystem->freedecal;i < maxdecals && decals[i].colors[0][3];i++)
+ for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4ub[0][3];i++)
;
decalsystem->freedecal = i;
if (decalsystem->numdecals <= i)
// initialize the decal
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] = 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] = 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] = 255;
- v3f[0] = v0[0];
- v3f[1] = v0[1];
- v3f[2] = v0[2];
- v3f[3] = v1[0];
- v3f[4] = v1[1];
- v3f[5] = v1[2];
- v3f[6] = v2[0];
- v3f[7] = v2[1];
- v3f[8] = v2[2];
- tc2f[0] = t0[0];
- tc2f[1] = t0[1];
- tc2f[2] = t1[0];
- tc2f[3] = t1[1];
- tc2f[4] = t2[0];
- tc2f[5] = t2[1];
- 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;
+ decal->surfaceindex = surfaceindex;
+ decal->decalsequence = decalsequence;
+ decal->color4ub[0][0] = (unsigned char)(c0[0]*255.0f);
+ decal->color4ub[0][1] = (unsigned char)(c0[1]*255.0f);
+ decal->color4ub[0][2] = (unsigned char)(c0[2]*255.0f);
+ decal->color4ub[0][3] = 255;
+ decal->color4ub[1][0] = (unsigned char)(c1[0]*255.0f);
+ decal->color4ub[1][1] = (unsigned char)(c1[1]*255.0f);
+ decal->color4ub[1][2] = (unsigned char)(c1[2]*255.0f);
+ decal->color4ub[1][3] = 255;
+ decal->color4ub[2][0] = (unsigned char)(c2[0]*255.0f);
+ decal->color4ub[2][1] = (unsigned char)(c2[1]*255.0f);
+ decal->color4ub[2][2] = (unsigned char)(c2[2]*255.0f);
+ decal->color4ub[2][3] = 255;
+ decal->vertex3f[0][0] = v0[0];
+ decal->vertex3f[0][1] = v0[1];
+ decal->vertex3f[0][2] = v0[2];
+ decal->vertex3f[1][0] = v1[0];
+ decal->vertex3f[1][1] = v1[1];
+ decal->vertex3f[1][2] = v1[2];
+ decal->vertex3f[2][0] = v2[0];
+ decal->vertex3f[2][1] = v2[1];
+ decal->vertex3f[2][2] = v2[2];
+ decal->texcoord2f[0][0] = t0[0];
+ decal->texcoord2f[0][1] = t0[1];
+ decal->texcoord2f[1][0] = t1[0];
+ decal->texcoord2f[1][1] = t1[1];
+ decal->texcoord2f[2][0] = t2[0];
+ decal->texcoord2f[2][1] = t2[1];
}
extern cvar_t cl_decals_bias;
extern cvar_t cl_decals_models;
-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)
+extern cvar_t cl_decals_newsystem_intensitymultiplier;
+static 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, int decalsequence)
{
matrix4x4_t projection;
decalsystem_t *decalsystem;
int numtriangles;
int numsurfacelist;
int surfacelistindex;
+ int surfaceindex;
int triangleindex;
+ int decalsurfaceindex;
int cornerindex;
int index;
int numpoints;
surfaces = model->data_surfaces;
for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
{
- surface = surfaces + surfacelist[surfacelistindex];
+ surfaceindex = surfacelist[surfacelistindex];
+ surface = surfaces + surfaceindex;
// skip transparent surfaces
texture = surface->texture;
if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
continue;
if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
continue;
- if (texture->currentalpha < 1)
- continue;
if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
continue;
+ decalsurfaceindex = ent == r_refdef.scene.worldentity ? surfaceindex : -1;
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)
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.0f-fabs(temp[0]));
- f = max(0.0f, f);
+ f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
+ f = bound(0.0f, f, 1.0f);
c[cornerindex][0] = r * f;
c[cornerindex][1] = g * f;
c[cornerindex][2] = b * f;
//VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
}
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);
+ R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex+surface->num_firsttriangle, surfaceindex, decalsequence);
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);
+ 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, surfaceindex, decalsequence);
}
}
}
-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)
+// do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
+static void R_DecalSystem_ApplySplatEntities(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 decalsequence)
{
int renderentityindex;
float worldmins[3];
float worldmaxs[3];
entity_render_t *ent;
+ if (!cl_decals_newsystem.integer)
+ return;
+
worldmins[0] = worldorigin[0] - worldsize;
worldmins[1] = worldorigin[1] - worldsize;
worldmins[2] = worldorigin[2] - 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);
+ R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;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);
+ R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
+ }
+}
+
+typedef struct r_decalsystem_splatqueue_s
+{
+ vec3_t worldorigin;
+ vec3_t worldnormal;
+ float color[4];
+ float tcrange[4];
+ float worldsize;
+ int decalsequence;
+}
+r_decalsystem_splatqueue_t;
+
+int r_decalsystem_numqueued = 0;
+#define MAX_DECALSYSTEM_QUEUE 1024
+r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
+
+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)
+{
+ r_decalsystem_splatqueue_t *queue;
+
+ if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
+ return;
+
+ queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
+ VectorCopy(worldorigin, queue->worldorigin);
+ VectorCopy(worldnormal, queue->worldnormal);
+ Vector4Set(queue->color, r, g, b, a);
+ Vector4Set(queue->tcrange, s1, t1, s2, t2);
+ queue->worldsize = worldsize;
+ queue->decalsequence = cl.decalsequence++;
+}
+
+static void R_DecalSystem_ApplySplatEntitiesQueue(void)
+{
+ int i;
+ r_decalsystem_splatqueue_t *queue;
+
+ for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
+ R_DecalSystem_ApplySplatEntities(queue->worldorigin, queue->worldnormal, queue->color[0], queue->color[1], queue->color[2], queue->color[3], queue->tcrange[0], queue->tcrange[1], queue->tcrange[2], queue->tcrange[3], queue->worldsize, queue->decalsequence);
+ r_decalsystem_numqueued = 0;
+}
+
+extern cvar_t cl_decals_max;
+static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
+{
+ int i;
+ decalsystem_t *decalsystem = &ent->decalsystem;
+ int numdecals;
+ int killsequence;
+ tridecal_t *decal;
+ float frametime;
+ float lifetime;
+
+ if (!decalsystem->numdecals)
+ return;
+
+ if (r_showsurfaces.integer)
+ return;
+
+ if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
+ {
+ R_DecalSystem_Reset(decalsystem);
+ return;
+ }
+
+ killsequence = cl.decalsequence - max(1, cl_decals_max.integer);
+ lifetime = cl_decals_time.value + cl_decals_fadetime.value;
+
+ if (decalsystem->lastupdatetime)
+ frametime = (cl.time - decalsystem->lastupdatetime);
+ else
+ frametime = 0;
+ decalsystem->lastupdatetime = cl.time;
+ decal = decalsystem->decals;
+ numdecals = decalsystem->numdecals;
+
+ for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
+ {
+ if (decal->color4ub[0][3])
+ {
+ decal->lived += frametime;
+ if (killsequence - decal->decalsequence > 0 || decal->lived >= lifetime)
+ {
+ memset(decal, 0, sizeof(*decal));
+ if (decalsystem->freedecal > i)
+ decalsystem->freedecal = i;
+ }
+ }
+ }
+ decal = decalsystem->decals;
+ while (numdecals > 0 && !decal[numdecals-1].color4ub[0][3])
+ numdecals--;
+
+ // collapse the array by shuffling the tail decals into the gaps
+ for (;;)
+ {
+ while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4ub[0][3])
+ decalsystem->freedecal++;
+ if (decalsystem->freedecal == numdecals)
+ break;
+ decal[decalsystem->freedecal] = decal[--numdecals];
+ }
+
+ decalsystem->numdecals = numdecals;
+
+ if (numdecals <= 0)
+ {
+ // if there are no decals left, reset decalsystem
+ R_DecalSystem_Reset(decalsystem);
}
}
decalsystem_t *decalsystem = &ent->decalsystem;
int numdecals;
tridecal_t *decal;
- float frametime;
float fadedelay;
float faderate;
float alpha;
float *v3f;
float *c4f;
+ float *t2f;
const int *e;
+ const unsigned char *surfacevisible = r_refdef.viewcache.world_surfacevisible;
+ int numtris = 0;
- if (!decalsystem->numdecals)
+ numdecals = decalsystem->numdecals;
+ if (!numdecals)
return;
if (r_showsurfaces.integer)
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);
+ // update vertex positions for animated models
+ v3f = decalsystem->vertex3f;
+ c4f = decalsystem->color4f;
+ t2f = decalsystem->texcoord2f;
for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
{
- if (!decal->colors[0][3])
+ if (!decal->color4ub[0][3])
continue;
- decal->lived += frametime;
- if (decal->lived >= fadedelay)
+ if (decal->surfaceindex >= 0 && !surfacevisible[decal->surfaceindex])
+ continue;
+
+ // update color values for fading decals
+ if (decal->lived >= cl_decals_time.value)
{
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]));
- memset(decalsystem->texcoord2f + 6*i, 0, sizeof(float[3][2]));
- memset(decalsystem->color4f + 12*i, 0, sizeof(float[3][4]));
- memset(decal, 0, sizeof(*decal));
- if (decalsystem->freedecal > i)
- decalsystem->freedecal = i;
- continue;
- }
-
- // 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;
}
+ else
+ alpha = 1.0f/255.0f;
+
+ c4f[ 0] = decal->color4ub[0][0] * alpha;
+ c4f[ 1] = decal->color4ub[0][1] * alpha;
+ c4f[ 2] = decal->color4ub[0][2] * alpha;
+ c4f[ 3] = 1;
+ c4f[ 4] = decal->color4ub[1][0] * alpha;
+ c4f[ 5] = decal->color4ub[1][1] * alpha;
+ c4f[ 6] = decal->color4ub[1][2] * alpha;
+ c4f[ 7] = 1;
+ c4f[ 8] = decal->color4ub[2][0] * alpha;
+ c4f[ 9] = decal->color4ub[2][1] * alpha;
+ c4f[10] = decal->color4ub[2][2] * alpha;
+ c4f[11] = 1;
+
+ t2f[0] = decal->texcoord2f[0][0];
+ t2f[1] = decal->texcoord2f[0][1];
+ t2f[2] = decal->texcoord2f[1][0];
+ t2f[3] = decal->texcoord2f[1][1];
+ t2f[4] = decal->texcoord2f[2][0];
+ t2f[5] = decal->texcoord2f[2][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 + 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);
}
- }
+ else
+ {
+ VectorCopy(decal->vertex3f[0], v3f);
+ VectorCopy(decal->vertex3f[1], v3f + 3);
+ VectorCopy(decal->vertex3f[2], v3f + 6);
+ }
- // reduce numdecals if possible
- while (numdecals > 0 && !decalsystem->decals[numdecals - 1].colors[0][3])
- numdecals--;
- decalsystem->numdecals = numdecals;
+ v3f += 9;
+ c4f += 12;
+ t2f += 6;
+ numtris++;
+ }
- if (numdecals > 0)
+ if (numtris > 0)
{
- r_refdef.stats.decals += numdecals;
+ r_refdef.stats.drawndecals += numtris;
// 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);
+ 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, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
R_Mesh_ResetTextureState();
R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0);
R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0);
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, numtris * 3);
+ R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0);
GL_LockArrays(0, 0);
}
+}
- if (numdecals <= 0)
+static void R_DrawModelDecals(void)
+{
+ int i, numdecals;
+
+ // fade faster when there are too many decals
+ numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
+
+ R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ if (r_refdef.scene.entities[i]->decalsystem.numdecals)
+ R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
+
+ R_DecalSystem_ApplySplatEntitiesQueue();
+
+ numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
+ for (i = 0;i < r_refdef.scene.numentities;i++)
+ numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
+
+ r_refdef.stats.totaldecals += numdecals;
+
+ if (r_showsurfaces.integer)
+ return;
+
+ R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
+
+ if (!r_drawentities.integer)
+ return;
+
+ for (i = 0;i < r_refdef.scene.numentities;i++)
{
- // if there are no decals left, reset decalsystem
- R_DecalSystem_Reset(decalsystem);
+ if (!r_refdef.viewcache.entityvisible[i])
+ continue;
+ if (r_refdef.scene.entities[i]->decalsystem.numdecals)
+ R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
}
}