X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=bd40407fb7be70ff332961c2aec4f5551c6748fd;hb=149a19636b5fcea9d572d56267005d94747a1690;hp=8bf14a8afd42673e1fa13b42bc2deb6f3dcad96b;hpb=2af7bf1a4eb9a5c9a1cfe76f9f8690523bafbd3e;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 8bf14a8a..bd40407f 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "csprogs.h" #include "cl_video.h" #include "dpsoftrast.h" +#include "cl_collision.h" #ifdef SUPPORTD3D #include @@ -93,6 +94,7 @@ cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbyne cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"}; cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"}; cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"}; +cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%, 10 = 100%)" }; cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"}; cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"}; cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"}; @@ -109,10 +111,12 @@ cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"}; cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"}; cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"}; cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"}; +cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" }; 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_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"}; cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"}; cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"}; cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"}; @@ -1115,6 +1119,27 @@ static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode geomstrings_list[geomstrings_count++] = "#define GLSL130\n"; fragstrings_list[fragstrings_count++] = "#define GLSL130\n"; } + // if we can do #version 120, we should (this adds the invariant keyword) + else if(vid.support.glshaderversion >= 120) + { + vertstrings_list[vertstrings_count++] = "#version 120\n"; + geomstrings_list[geomstrings_count++] = "#version 120\n"; + fragstrings_list[fragstrings_count++] = "#version 120\n"; + vertstrings_list[vertstrings_count++] = "#define GLSL120\n"; + geomstrings_list[geomstrings_count++] = "#define GLSL120\n"; + fragstrings_list[fragstrings_count++] = "#define GLSL120\n"; + } + // GLES also adds several things from GLSL120 + switch(vid.renderpath) + { + case RENDERPATH_GLES2: + vertstrings_list[vertstrings_count++] = "#define GLES\n"; + geomstrings_list[geomstrings_count++] = "#define GLES\n"; + fragstrings_list[fragstrings_count++] = "#define GLES\n"; + break; + default: + break; + } // the first pretext is which type of shader to compile as // (later these will all be bound together as a program object) @@ -4316,6 +4341,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_transparent_useplanardistance); Cvar_RegisterVariable(&r_showoverdraw); Cvar_RegisterVariable(&r_showbboxes); + Cvar_RegisterVariable(&r_showbboxes_client); Cvar_RegisterVariable(&r_showsurfaces); Cvar_RegisterVariable(&r_showtris); Cvar_RegisterVariable(&r_shownormals); @@ -4330,10 +4356,12 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_draw2d); Cvar_RegisterVariable(&r_drawworld); Cvar_RegisterVariable(&r_cullentities_trace); + Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion); 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_cullentities_trace_eyejitter); Cvar_RegisterVariable(&r_sortentities); Cvar_RegisterVariable(&r_drawviewmodel); Cvar_RegisterVariable(&r_drawexteriormodel); @@ -5197,42 +5225,88 @@ static void R_View_UpdateEntityLighting (void) } } -#define MAX_LINEOFSIGHTTRACES 64 - -static qboolean R_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs) +qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs) { int i; + vec3_t eyemins, eyemaxs; vec3_t boxmins, boxmaxs; vec3_t start; vec3_t end; dp_model_t *model = r_refdef.scene.worldmodel; + static vec3_t positions[] = { + { 0.5f, 0.5f, 0.5f }, + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f }, + { 0.0f, 1.0f, 1.0f }, + { 1.0f, 0.0f, 0.0f }, + { 1.0f, 0.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f }, + { 1.0f, 1.0f, 1.0f }, + }; + + // sample count can be set to -1 to skip this logic, for flicker-prone objects + if (numsamples < 0) + return true; + + // view origin is not used for culling in portal/reflection/refraction renders or isometric views + if (r_refdef.view.useclipplane || !r_refdef.view.useperspective || r_trippy.integer) + return true; - if (!model || !model->brush.TraceLineOfSight) + if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight)) return true; + // expand the eye box a little + eyemins[0] = eye[0] - eyejitter; + eyemaxs[0] = eye[0] + eyejitter; + eyemins[1] = eye[1] - eyejitter; + eyemaxs[1] = eye[1] + eyejitter; + eyemins[2] = eye[2] - eyejitter; + eyemaxs[2] = eye[2] + eyejitter; // expand the box a little - boxmins[0] = (enlarge+1) * entboxmins[0] - enlarge * entboxmaxs[0]; - boxmaxs[0] = (enlarge+1) * entboxmaxs[0] - enlarge * entboxmins[0]; - boxmins[1] = (enlarge+1) * entboxmins[1] - enlarge * entboxmaxs[1]; - boxmaxs[1] = (enlarge+1) * entboxmaxs[1] - enlarge * entboxmins[1]; - boxmins[2] = (enlarge+1) * entboxmins[2] - enlarge * entboxmaxs[2]; - boxmaxs[2] = (enlarge+1) * entboxmaxs[2] - enlarge * entboxmins[2]; - - // return true if eye is inside enlarged box - if (BoxesOverlap(boxmins, boxmaxs, eye, eye)) + boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0]; + boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0]; + boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1]; + boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1]; + boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2]; + boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2]; + + // return true if eye overlaps enlarged box + if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs)) return true; - // try center - VectorCopy(eye, start); - VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end); - if (model->brush.TraceLineOfSight(model, start, end)) + // try specific positions in the box first - note that these can be cached + if (r_cullentities_trace_entityocclusion.integer) + { + for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++) + { + VectorCopy(eye, start); + end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0]; + end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1]; + end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2]; + //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true); + trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT); + // not picky - if the trace ended anywhere in the box we're good + if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs)) + return true; + } + } + else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs)) return true; // try various random positions - for (i = 0;i < numsamples;i++) + for (i = 0; i < numsamples; i++) { + VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2])); VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2])); - if (model->brush.TraceLineOfSight(model, start, end)) + if (r_cullentities_trace_entityocclusion.integer) + { + trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT); + // not picky - if the trace ended anywhere in the box we're good + if (BoxesOverlap(trace.endpos, trace.endpos, boxmins, boxmaxs)) + return true; + } + else if (model->brush.TraceLineOfSight(model, start, end, boxmins, boxmaxs)) return true; } @@ -5281,22 +5355,19 @@ static void R_View_UpdateEntityVisible (void) r_refdef.viewcache.entityvisible[i] = true; } } - if(r_cullentities_trace.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.TraceLineOfSight && !r_refdef.view.useclipplane && !r_trippy.integer) - // sorry, this check doesn't work for portal/reflection/refraction renders as the view origin is not useful for culling + if (r_cullentities_trace.integer) { for (i = 0;i < r_refdef.scene.numentities;i++) { if (!r_refdef.viewcache.entityvisible[i]) continue; ent = r_refdef.scene.entities[i]; - if(!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*'))) + if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*'))) { - 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)) + samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer; + if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, 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) + if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value) r_refdef.viewcache.entityvisible[i] = 0; } } @@ -6625,6 +6696,7 @@ static void R_Bloom_MakeTexture(void) r_fb.bloomindex = 0; R_Mesh_SetRenderTargets(r_fb.bloomfbo[r_fb.bloomindex], NULL, r_fb.bloomtexture[r_fb.bloomindex], NULL, NULL, NULL); R_SetViewport(&r_fb.bloomviewport); + GL_CullFace(GL_NONE); GL_DepthTest(false); GL_BlendFunc(GL_ONE, GL_ZERO); GL_Color(colorscale, colorscale, colorscale, 1); @@ -7380,7 +7452,7 @@ void R_RenderWaterPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortex extern cvar_t cl_locs_show; static void R_DrawLocs(void); -static void R_DrawEntityBBoxes(void); +static void R_DrawEntityBBoxes(prvm_prog_t *prog); static void R_DrawModelDecals(void); extern cvar_t cl_decals_newsystem; extern qboolean r_shadow_usingdeferredprepass; @@ -7540,10 +7612,6 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) R_DrawExplosions(); if (r_timereport_active) R_TimeReport("explosions"); - - R_DrawLightningBeams(); - if (r_timereport_active) - R_TimeReport("lightning"); } if (cl.csqc_loaded) @@ -7565,11 +7633,17 @@ void R_RenderScene(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture) R_TimeReport("portals"); } + if (r_showbboxes_client.value > 0) + { + R_DrawEntityBBoxes(CLVM_prog); + if (r_timereport_active) + R_TimeReport("clbboxes"); + } if (r_showbboxes.value > 0) { - R_DrawEntityBBoxes(); + R_DrawEntityBBoxes(SVVM_prog); if (r_timereport_active) - R_TimeReport("bboxes"); + R_TimeReport("svbboxes"); } } @@ -7633,10 +7707,36 @@ static const unsigned short bboxelements[36] = 1, 0, 2, 1, 2, 3, }; +#define BBOXEDGES 13 +static const float bboxedges[BBOXEDGES][6] = +{ + // whole box + { 0, 0, 0, 1, 1, 1 }, + // bottom edges + { 0, 0, 0, 0, 1, 0 }, + { 0, 0, 0, 1, 0, 0 }, + { 0, 1, 0, 1, 1, 0 }, + { 1, 0, 0, 1, 1, 0 }, + // top edges + { 0, 0, 1, 0, 1, 1 }, + { 0, 0, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 1, 1 }, + { 1, 0, 1, 1, 1, 1 }, + // vertical edges + { 0, 0, 0, 0, 0, 1 }, + { 1, 0, 0, 1, 0, 1 }, + { 0, 1, 0, 0, 1, 1 }, + { 1, 1, 0, 1, 1, 1 }, +}; + static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca) { - int i; - float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4]; + int numvertices = BBOXEDGES * 8; + float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4]; + int numtriangles = BBOXEDGES * 12; + unsigned short elements[BBOXEDGES * 36]; + int i, edge; + float *v, *c, f1, f2, edgemins[3], edgemaxs[3]; RSurf_ActiveWorldEntity(); @@ -7644,20 +7744,29 @@ static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float c GL_DepthMask(false); GL_DepthRange(0, 1); GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); -// R_Mesh_ResetTextureState(); - vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; // - vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2]; - vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2]; - vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2]; - vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2]; - vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2]; - vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2]; - vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2]; - R_FillColors(color4f, 8, cr, cg, cb, ca); + for (edge = 0; edge < BBOXEDGES; edge++) + { + for (i = 0; i < 3; i++) + { + edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f; + edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f; + } + vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2]; + vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2]; + vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2]; + vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2]; + vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2]; + vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2]; + vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2]; + vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2]; + for (i = 0; i < 36; i++) + elements[edge * 36 + i] = edge * 8 + bboxelements[i]; + } + R_FillColors(color4f, numvertices, cr, cg, cb, ca); if (r_refdef.fogenabled) { - for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4) + for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4) { f1 = RSurf_FogVertex(v); f2 = 1 - f1; @@ -7666,23 +7775,20 @@ static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float c c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2; } } - R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL); + R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL); R_Mesh_ResetTextureState(); R_SetupShader_Generic_NoTexture(false, false); - R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); + R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0); } static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) { - prvm_prog_t *prog = SVVM_prog; + // hacky overloading of the parameters + prvm_prog_t *prog = (prvm_prog_t *)rtlight; int i; float color[4]; prvm_edict_t *edict; - // this function draws bounding boxes of server entities - if (!sv.active) - return; - GL_CullFace(GL_NONE); R_SetupShader_Generic_NoTexture(false, false); @@ -7699,37 +7805,37 @@ static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtligh case SOLID_CORPSE: Vector4Set(color, 1, 0.5, 0, 0.05);break; default: Vector4Set(color, 0, 0, 0, 0.50);break; } - color[3] *= r_showbboxes.value; + if (prog == CLVM_prog) + color[3] *= r_showbboxes_client.value; + else + color[3] *= r_showbboxes.value; color[3] = bound(0, color[3], 1); GL_DepthTest(!r_showdisabledepthtest.integer); - GL_CullFace(r_refdef.view.cullface_front); R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]); } } -static void R_DrawEntityBBoxes(void) +static void R_DrawEntityBBoxes(prvm_prog_t *prog) { int i; prvm_edict_t *edict; vec3_t center; - prvm_prog_t *prog = SVVM_prog; - // this function draws bounding boxes of server entities - if (!sv.active) + if (prog == NULL) return; - for (i = 0;i < prog->num_edicts;i++) + for (i = 0; i < prog->num_edicts; i++) { edict = PRVM_EDICT_NUM(i); if (edict->priv.server->free) continue; // exclude the following for now, as they don't live in world coordinate space and can't be solid: - if(PRVM_serveredictedict(edict, tag_entity) != 0) + if (PRVM_serveredictedict(edict, tag_entity) != 0) continue; - if(PRVM_serveredictedict(edict, viewmodelforclient) != 0) + if (PRVM_serveredictedict(edict, viewmodelforclient) != 0) continue; VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center); - R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL); + R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog); } }