CL_Particles_LoadEffectInfo();
}
-#define BATCHSIZE 256
-unsigned short particle_elements[BATCHSIZE*6];
-float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16];
+unsigned short particle_elements[MESHQUEUE_TRANSPARENT_BATCHSIZE*6];
+float particle_vertex3f[MESHQUEUE_TRANSPARENT_BATCHSIZE*12], particle_texcoord2f[MESHQUEUE_TRANSPARENT_BATCHSIZE*8], particle_color4f[MESHQUEUE_TRANSPARENT_BATCHSIZE*16];
void R_Particles_Init (void)
{
int i;
- for (i = 0;i < BATCHSIZE;i++)
+ for (i = 0;i < MESHQUEUE_TRANSPARENT_BATCHSIZE;i++)
{
particle_elements[i*6+0] = i*4+0;
particle_elements[i*6+1] = i*4+1;
cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
+cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
+cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
Cvar_RegisterVariable(&r_fog_clear);
Cvar_RegisterVariable(&r_drawfog);
Cvar_RegisterVariable(&r_transparentdepthmasking);
+ Cvar_RegisterVariable(&r_transparent_sortmaxdist);
+ Cvar_RegisterVariable(&r_transparent_sortarraysize);
Cvar_RegisterVariable(&r_texture_dds_load);
Cvar_RegisterVariable(&r_texture_dds_save);
Cvar_RegisterVariable(&r_texture_sRGB_2d);
int texturenumsurfaces, endsurface;
texture_t *texture;
const msurface_t *surface;
-#define MAXBATCH_TRANSPARENTSURFACES 256
- const msurface_t *texturesurfacelist[MAXBATCH_TRANSPARENTSURFACES];
+ const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
// if the model is static it doesn't matter what value we give for
// wantnormals and wanttangents, so this logic uses only rules applicable
texture = surface->texture;
rsurface.texture = R_GetCurrentTexture(texture);
// scan ahead until we find a different texture
- endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces);
+ endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
texturenumsurfaces = 0;
texturesurfacelist[texturenumsurfaces++] = surface;
if(FAKELIGHT_ENABLED)
for (kend = k;kend < batchnumsurfaces && tex == batchsurfacelist[kend]->texture;kend++)
;
// now figure out what to do with this particular range of surfaces
- if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
+ // VorteX: added MATERIALFLAG_NORTLIGHT
+ if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WALL + MATERIALFLAG_NORTLIGHT)) != MATERIALFLAG_WALL)
continue;
if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
continue;
}
meshqueue_t;
+int trans_sortarraysize;
+meshqueue_t **trans_hash = NULL;
+meshqueue_t ***trans_hashpointer = NULL;
+extern cvar_t r_transparent_sortarraysize;
+extern cvar_t r_transparent_sortmaxdist;
+
float mqt_viewplanedist;
+float mqt_viewmindist;
float mqt_viewmaxdist;
meshqueue_t *mqt_array;
int mqt_count;
mqt_count = 0;
mqt_viewplanedist = DotProduct(r_refdef.view.origin, r_refdef.view.forward);
mqt_viewmaxdist = 0;
+ mqt_viewmindist = 999999999;
}
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)
mq->dist = DotProduct(center, r_refdef.view.forward) - mqt_viewplanedist;
mq->next = NULL;
mqt_viewmaxdist = max(mqt_viewmaxdist, mq->dist);
+ mqt_viewmindist = min(mqt_viewmindist, mq->dist);
}
void R_MeshQueue_RenderTransparent(void)
{
- int i;
- int hashdist;
- int batchnumsurfaces;
+ int i, hashindex, maxhashindex, 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);
+ int batchsurfaceindex[MESHQUEUE_TRANSPARENT_BATCHSIZE];
meshqueue_t *mqt;
- static meshqueue_t *hash[4096], **hashpointer[4096];
- int batchsurfaceindex[256];
+
if (!mqt_count)
return;
- memset(hash, 0, sizeof(hash));
- for (i = 0;i < 4096;i++)
- hashpointer[i] = &hash[i];
- distscale = 4095.0f / max(mqt_viewmaxdist, 4095);
- for (i = 0, mqt = mqt_array;i < mqt_count;i++, mqt++)
+
+ // check for bad cvars
+ if (r_transparent_sortarraysize.integer < 1 || r_transparent_sortarraysize.integer > 32768)
+ Cvar_SetValueQuick(&r_transparent_sortarraysize, bound(1, r_transparent_sortarraysize.integer, 32768));
+ if (r_transparent_sortmaxdist.integer < 1 || r_transparent_sortmaxdist.integer > 32768)
+ Cvar_SetValueQuick(&r_transparent_sortmaxdist, bound(1, r_transparent_sortmaxdist.integer, 32768));
+
+ // update hash array
+ if (trans_sortarraysize != r_transparent_sortarraysize.integer)
{
- // generate index
- hashdist = (int) (mqt->dist * distscale);
- hashdist = bound(0, hashdist, 4095);
+ trans_sortarraysize = r_transparent_sortarraysize.integer;
+ if (trans_hash)
+ Mem_Free(trans_hash);
+ trans_hash = Mem_Alloc(cls.permanentmempool, sizeof(trans_hash) * trans_sortarraysize);
+ if (trans_hashpointer)
+ Mem_Free(trans_hashpointer);
+ trans_hashpointer = Mem_Alloc(cls.permanentmempool, sizeof(trans_hashpointer) * trans_sortarraysize);
+ }
+
+ // build index
+ memset(trans_hash, 0, sizeof(trans_hash) * trans_sortarraysize);
+ for (i = 0; i < trans_sortarraysize; i++)
+ trans_hashpointer[i] = &trans_hash[i];
+ distscale = (trans_sortarraysize - 1) / max( min(mqt_viewmaxdist, r_transparent_sortmaxdist.integer) - mqt_viewmindist, 64 );
+ maxhashindex = trans_sortarraysize - 1;
+ for (i = 0, mqt = mqt_array; i < mqt_count; i++, mqt++)
+ {
+ hashindex = bound(0, (int)(min(mqt->dist - mqt_viewmindist, r_transparent_sortmaxdist.integer) * distscale - 0.1), maxhashindex);
// link to tail of hash chain (to preserve render order)
mqt->next = NULL;
- *hashpointer[hashdist] = mqt;
- hashpointer[hashdist] = &mqt->next;
+ *trans_hashpointer[hashindex] = mqt;
+ trans_hashpointer[hashindex] = &mqt->next;
}
callback = NULL;
ent = NULL;
rtlight = NULL;
batchnumsurfaces = 0;
- for (i = 4095;i >= 0;i--)
+
+ // draw
+ for (i = maxhashindex; i >= 0; i--)
{
- if (hash[i])
+ if (trans_hash[i])
{
- for (mqt = hash[i];mqt;mqt = mqt->next)
+ for (mqt = trans_hash[i]; mqt; mqt = mqt->next)
{
- if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= 256)
+ if (ent != mqt->ent || rtlight != mqt->rtlight || callback != mqt->callback || batchnumsurfaces >= MESHQUEUE_TRANSPARENT_BATCHSIZE)
{
if (batchnumsurfaces)
callback(ent, rtlight, batchnumsurfaces, batchsurfaceindex);
#ifndef MESHQUEUE_H
#define MESHQUEUE_H
+// VorteX: seems this value is hardcoded in other several defines as it's changing makes mess
+#define MESHQUEUE_TRANSPARENT_BATCHSIZE 256
+
void R_MeshQueue_BeginScene(void);
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_RenderTransparent(void);
#define MATERIALFLAG_TRANSDEPTH 33554432
// like refraction, but doesn't distort etc.
#define MATERIALFLAG_CAMERA 67108864
+// disable rtlight on surface, use R_LightPoint instead
+#define MATERIALFLAG_NORTLIGHT 134217728
// combined mask of all attributes that require depth sorted rendering
#define MATERIALFLAGMASK_DEPTHSORTED (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)
// combined mask of all attributes that cause some sort of transparency
shader.dpshadow = true;
else if (!strcasecmp(parameter[0], "dpnoshadow"))
shader.dpnoshadow = true;
+ else if (!strcasecmp(parameter[0], "dpnortlight"))
+ shader.dpnortlight = true;
else if (!strcasecmp(parameter[0], "dpreflectcube"))
strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
if (shader->dpnoshadow)
texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
+ if (shader->dpnortlight)
+ texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
texture->reflectmin = shader->reflectmin;
texture->reflectmax = shader->reflectmax;
// dp-specific additions:
// shadow control
+ qboolean dpnortlight;
qboolean dpshadow;
qboolean dpnoshadow;