int HWDrawInfo::SetupLightsForOtherPlane(subsector_t * sub, FDynLightData &lightdata, const secplane_t *plane) { if (Level->HasDynamicLights && !isFullbrightScene()) { Plane p; FLightNode * node = sub->section->lighthead; lightdata.Clear(); while (node) { FDynamicLight * light = node->lightsource; if (!light->IsActive()) { node = node->nextLight; continue; } iter_dlightf++; p.Set(plane->Normal(), plane->fD()); draw_dlightf += lightdata.GetLight(sub->sector->PortalGroup, p, light, true); node = node->nextLight; } return screen->mLights->UploadLights(lightdata); } else return -1; }
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 GLFlat::SetupSubsectorLights(int pass, subsector_t * sub, int *dli) { Plane p; if (dli != NULL && *dli != -1) { gl_RenderState.ApplyLightIndex(GLRenderer->mLights->GetIndex(*dli)); (*dli)++; return; } lightdata.Clear(); FLightNode * node = sub->lighthead; while (node) { ADynamicLight * light = node->lightsource; if (light->flags2&MF2_DORMANT) { node=node->nextLight; continue; } iter_dlightf++; // we must do the side check here because gl_SetupLight needs the correct plane orientation // which we don't have for Legacy-style 3D-floors fixed_t planeh = plane.plane.ZatPoint(light->x, light->y); if (gl_lights_checkside && ((planeh<light->z && ceiling) || (planeh>light->z && !ceiling))) { node=node->nextLight; continue; } p.Set(plane.plane); gl_GetLight(p, light, false, false, lightdata); node = node->nextLight; } int d = GLRenderer->mLights->UploadLights(lightdata); if (pass == GLPASS_LIGHTSONLY) { GLRenderer->mLights->StoreIndex(d); } else { gl_RenderState.ApplyLightIndex(d); } }
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 GLWall::SetupLights() { float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } for(int i=0;i<2;i++) { FLightNode *node; if (!seg->bPolySeg) { // Iterate through all dynamic lights which touch this wall and render them if (seg->sidedef) { node = seg->sidedef->lighthead[i]; } else node = NULL; } else if (sub) { // To avoid constant rechecking for polyobjects use the subsector's lightlist instead node = sub->lighthead[i]; } else node = NULL; while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->x); float y = FIXED2FLOAT(node->lightsource->y); float z = FIXED2FLOAT(node->lightsource->z); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, Colormap.colormap, true, false, lightdata); } } } node = node->nextLight; } } int numlights[3]; lightdata.Combine(numlights, gl.MaxLights()); if (numlights[2] > 0) { draw_dlight+=numlights[2]/2; gl_RenderState.EnableLight(true); gl_RenderState.SetLights(numlights, &lightdata.arrays[0][0]); } }
void GLWall::SetupLights() { // check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.) switch (type) { case RENDERWALL_FOGBOUNDARY: case RENDERWALL_MIRRORSURFACE: case RENDERWALL_COLOR: case RENDERWALL_COLORLAYER: return; } float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Init(vtx,4); if (!p.ValidNormal()) { return; } FLightNode *node; if (seg->sidedef == NULL) { node = NULL; } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { node = seg->sidedef->lighthead; } else if (sub) { // Polobject segs cannot be checked per sidedef so use the subsector instead. node = sub->lighthead; } else node = NULL; // Iterate through all dynamic lights which touch this wall and render them while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; Vector fn, pos; float x = FIXED2FLOAT(node->lightsource->X()); float y = FIXED2FLOAT(node->lightsource->Y()); float z = FIXED2FLOAT(node->lightsource->Z()); float dist = fabsf(p.DistToPoint(x, z, y)); float radius = (node->lightsource->GetRadius() * gl_lights_size); float scale = 1.0f / ((2.f * radius) - dist); if (radius > 0.f && dist < radius) { Vector nearPt, up, right; pos.Set(x,z,y); fn=p.Normal(); fn.GetRightUp(right, up); Vector tmpVec = fn * dist; nearPt = pos + tmpVec; Vector t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1.Set(&vtx[i*3]); Vector nearToVert = t1 - nearPt; tcs[i].u = (nearToVert.Dot(right) * scale) + 0.5f; tcs[i].v = (nearToVert.Dot(up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(p, node->lightsource, true, false, lightdata); } } } node = node->nextLight; } dynlightindex = GLRenderer->mLights->UploadLights(lightdata); }
void GLWall::SetupLights() { if (RenderStyle == STYLE_Add && !glset.lightadditivesurfaces) return; // no lights on additively blended surfaces. // check for wall types which cannot have dynamic lights on them (portal types never get here so they don't need to be checked.) switch (type) { case RENDERWALL_FOGBOUNDARY: case RENDERWALL_MIRRORSURFACE: case RENDERWALL_COLOR: return; } float vtx[]={glseg.x1,zbottom[0],glseg.y1, glseg.x1,ztop[0],glseg.y1, glseg.x2,ztop[1],glseg.y2, glseg.x2,zbottom[1],glseg.y2}; Plane p; lightdata.Clear(); p.Set(&glseg); /* if (!p.ValidNormal()) { return; } */ FLightNode *node; if (seg->sidedef == NULL) { node = NULL; } else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) { node = seg->sidedef->lighthead; } else if (sub) { // Polobject segs cannot be checked per sidedef so use the subsector instead. node = sub->lighthead; } else node = NULL; // Iterate through all dynamic lights which touch this wall and render them while (node) { if (!(node->lightsource->flags2&MF2_DORMANT)) { iter_dlight++; DVector3 posrel = node->lightsource->PosRelative(seg->frontsector); float x = posrel.X; float y = posrel.Y; float z = posrel.Z; float dist = fabsf(p.DistToPoint(x, z, y)); float radius = node->lightsource->GetRadius(); float scale = 1.0f / ((2.f * radius) - dist); FVector3 fn, pos; if (radius > 0.f && dist < radius) { FVector3 nearPt, up, right; pos = { x, z, y }; fn = p.Normal(); fn.GetRightUp(right, up); FVector3 tmpVec = fn * dist; nearPt = pos + tmpVec; FVector3 t1; int outcnt[4]={0,0,0,0}; texcoord tcs[4]; // do a quick check whether the light touches this polygon for(int i=0;i<4;i++) { t1 = FVector3(&vtx[i*3]); FVector3 nearToVert = t1 - nearPt; tcs[i].u = ((nearToVert | right) * scale) + 0.5f; tcs[i].v = ((nearToVert | up) * scale) + 0.5f; if (tcs[i].u<0) outcnt[0]++; if (tcs[i].u>1) outcnt[1]++; if (tcs[i].v<0) outcnt[2]++; if (tcs[i].v>1) outcnt[3]++; } if (outcnt[0]!=4 && outcnt[1]!=4 && outcnt[2]!=4 && outcnt[3]!=4) { gl_GetLight(seg->frontsector->PortalGroup, p, node->lightsource, true, lightdata); } } } node = node->nextLight; } dynlightindex = GLRenderer->mLights->UploadLights(lightdata); }