+ light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
+ rtlight = &light->rtlight;
+ }
+ else
+ rtlight = r_refdef.scene.lights[lightindex - range];
+ // draw only visible lights (major speedup)
+ if (!rtlight->draw)
+ continue;
+ VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
+ }
+ if (!VectorLength2(lightcolor))
+ continue;
+ // shoot particles from this light
+ // use a calculation for the number of particles that will not
+ // vary with lightstyle, otherwise we get randomized particle
+ // distribution, the seeded random is only consistent for a
+ // consistent number of particles on this light...
+ radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
+ s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
+ lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
+ if (lightindex >= range)
+ lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
+ shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
+ if (!shootparticles)
+ continue;
+ s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
+ VectorScale(lightcolor, s, baseshotcolor);
+ if (VectorLength2(baseshotcolor) < 3.0f)
+ break;
+ r_refdef.stats.bouncegrid_lights++;
+ r_refdef.stats.bouncegrid_particles += shootparticles;
+ for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
+ {
+ if (r_shadow_bouncegrid_stablerandom.integer > 0)
+ seed = lightindex * 11937 + shotparticles;
+ VectorCopy(baseshotcolor, shotcolor);
+ VectorCopy(rtlight->shadoworigin, clipstart);
+ if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ VectorRandom(clipend);
+ else
+ VectorCheeseRandom(clipend);
+ VectorMA(clipstart, radius, clipend, clipend);
+ for (bouncecount = 0;;bouncecount++)
+ {
+ r_refdef.stats.bouncegrid_traces++;
+ //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
+ //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
+ cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
+ //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+ if (cliptrace.fraction >= 1.0f)
+ break;
+ r_refdef.stats.bouncegrid_hits++;
+ if (bouncecount > 0)
+ {
+ r_refdef.stats.bouncegrid_splats++;
+ // figure out which texture pixel this is in
+ tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
+ tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
+ tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
+ if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
+ {
+ // it is within bounds...
+ pixelindex = ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
+ pixel = pixels + 4 * pixelindex;
+ highpixel = highpixels + 3 * pixelindex;
+ // add to the high precision pixel color
+ c[0] = highpixel[0] + (int)shotcolor[2];
+ c[1] = highpixel[1] + (int)shotcolor[1];
+ c[2] = highpixel[2] + (int)shotcolor[0];
+ highpixel[0] = (unsigned short)min(c[0], 65535);
+ highpixel[1] = (unsigned short)min(c[1], 65535);
+ highpixel[2] = (unsigned short)min(c[2], 65535);
+ // update the low precision pixel color
+ pixel[0] = highpixel[0] >> 8;
+ pixel[1] = highpixel[1] >> 8;
+ pixel[2] = highpixel[2] >> 8;
+ pixel[3] = 255;
+ }
+ }
+ if (bouncecount >= maxbounce)
+ break;
+ // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
+ // also clamp the resulting color to never add energy, even if the user requests extreme values
+ if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
+ VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
+ else
+ VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
+ VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
+ surfcolor[0] = min(surfcolor[0], 1.0f);
+ surfcolor[1] = min(surfcolor[1], 1.0f);
+ surfcolor[2] = min(surfcolor[2], 1.0f);
+ VectorMultiply(shotcolor, surfcolor, shotcolor);
+ if (VectorLength2(shotcolor) < 3.0f)
+ break;
+ r_refdef.stats.bouncegrid_bounces++;
+ if (r_shadow_bouncegrid_bounceanglediffuse.integer)
+ {
+ // random direction, primarily along plane normal
+ s = VectorDistance(cliptrace.endpos, clipend);
+ if (r_shadow_bouncegrid_stablerandom.integer < 0)
+ VectorRandom(clipend);
+ else
+ VectorCheeseRandom(clipend);
+ VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
+ VectorNormalize(clipend);
+ VectorScale(clipend, s, clipend);
+ }
+ else
+ {
+ // reflect the remaining portion of the line across plane normal
+ VectorSubtract(clipend, cliptrace.endpos, clipdiff);
+ VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
+ }
+ // calculate the new line start and end
+ VectorCopy(cliptrace.endpos, clipstart);
+ VectorAdd(clipstart, clipend, clipend);