void gl_SetDynModelLight(AActor *self, bool hudmodel) { // Legacy and deferred render paths gets the old flat model light if (gl.lightmethod != LM_DIRECT) { gl_SetDynSpriteLight(self, nullptr); return; } modellightdata.Clear(); if (self) { static std::vector<ADynamicLight*> addedLights; // static so that we build up a reserve (memory allocations stop) addedLights.clear(); float x = self->X(); float y = self->Y(); float z = self->Center(); float radiusSquared = self->renderradius * self->renderradius; BSPWalkCircle(x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor { FLightNode * node = subsector->lighthead; while (node) // check all lights touching a subsector { ADynamicLight *light = node->lightsource; if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) { int group = subsector->sector->PortalGroup; DVector3 pos = light->PosRelative(group); float radius = light->GetRadius(); double dx = pos.X - x; double dy = pos.Y - y; double dz = pos.Z - z; double distSquared = dx * dx + dy * dy + dz * dz; if (distSquared < radiusSquared + radius * radius) // Light and actor touches { if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector { gl_AddLightToList(group, light, modellightdata, hudmodel); addedLights.push_back(light); } } } node = node->nextLight; } }); } gl_RenderState.SetDynLight(0, 0, 0); modellightindex = GLRenderer->mLights->UploadLights(modellightdata); }
void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata) { modellightdata.Clear(); if (self) { auto &addedLights = addedLightsArray; // avoid going through the thread local storage for each use. addedLights.Clear(); float x = (float)self->X(); float y = (float)self->Y(); float z = (float)self->Center(); float radiusSquared = (float)(self->renderradius * self->renderradius); dl_validcount++; BSPWalkCircle(self->Level, x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor { auto section = subsector->section; if (section->validcount == dl_validcount) return; // already done from a previous subsector. FLightNode * node = section->lighthead; while (node) // check all lights touching a subsector { FDynamicLight *light = node->lightsource; if (light->ShouldLightActor(self)) { int group = subsector->sector->PortalGroup; DVector3 pos = light->PosRelative(group); float radius = (float)(light->GetRadius() + self->renderradius); double dx = pos.X - x; double dy = pos.Y - y; double dz = pos.Z - z; double distSquared = dx * dx + dy * dy + dz * dz; if (distSquared < radius * radius) // Light and actor touches { if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector { modellightdata.AddLightToList(group, light, true); addedLights.Push(light); } } } node = node->nextLight; } }); } }
void PolyModelRenderer::AddLights(AActor *actor) { if (r_dynlights && actor) { auto &addedLights = Thread->AddedLightsArray; addedLights.Clear(); float x = (float)actor->X(); float y = (float)actor->Y(); float z = (float)actor->Center(); float radiusSquared = (float)(actor->renderradius * actor->renderradius); BSPWalkCircle(x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor { FLightNode * node = subsector->lighthead; while (node) // check all lights touching a subsector { ADynamicLight *light = node->lightsource; if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != actor) && !(light->lightflags&LF_DONTLIGHTACTORS)) { int group = subsector->sector->PortalGroup; DVector3 pos = light->PosRelative(group); float radius = (float)(light->GetRadius() + actor->renderradius); double dx = pos.X - x; double dy = pos.Y - y; double dz = pos.Z - z; double distSquared = dx * dx + dy * dy + dz * dz; if (distSquared < radius * radius) // Light and actor touches { if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector { addedLights.Push(light); } } } node = node->nextLight; } }); NumLights = addedLights.Size(); Lights = Thread->FrameMemory->AllocMemory<PolyLight>(NumLights); for (int i = 0; i < NumLights; i++) { ADynamicLight *lightsource = addedLights[i]; bool is_point_light = (lightsource->lightflags & LF_ATTENUATE) != 0; uint32_t red = lightsource->GetRed(); uint32_t green = lightsource->GetGreen(); uint32_t blue = lightsource->GetBlue(); PolyLight &light = Lights[i]; light.x = (float)lightsource->X(); light.y = (float)lightsource->Y(); light.z = (float)lightsource->Z(); light.radius = 256.0f / lightsource->GetRadius(); light.color = (red << 16) | (green << 8) | blue; if (is_point_light) light.radius = -light.radius; } } }