bool FDrawInfo::CheckAnchorFloor(subsector_t * sub) { // This subsector has a one sided wall and can be used. if (sub->hacked==3) return true; if (sub->degenerate) return false; for(DWORD j=0; j<sub->numlines; j++) { seg_t * seg = sub->firstline + j; if (!seg->PartnerSeg) return true; subsector_t * backsub = seg->PartnerSeg->Subsector; // Find a linedef with a different visplane on the other side. if (!backsub->degenerate && seg->linedef && (sub->render_sector != backsub->render_sector && sub->sector != backsub->sector)) { // I'm ignoring slopes, scaling and rotation here. The likelihood of ZDoom maps // using such crap hacks is simply too small if (sub->render_sector->GetTexture(sector_t::floor)==backsub->render_sector->GetTexture(sector_t::floor) && sub->render_sector->GetPlaneTexZ(sector_t::floor)==backsub->render_sector->GetPlaneTexZ(sector_t::floor) && GetFloorLight(sub->render_sector)==GetFloorLight(backsub->render_sector)) { continue; } // This means we found an adjoining subsector that clearly would go into another // visplane. That means that this subsector can be used as an anchor. return true; } } return false; }
bool FDrawInfo::CollectSubsectorsFloor(subsector_t * sub, sector_t * anchor) { // mark it checked sub->validcount=validcount; // We must collect any subsector that either is connected to this one with a miniseg // or has the same visplane. // We must not collect any subsector that has the anchor's visplane! if (!sub->degenerate) { // Is not being rendered so don't bother. if (!(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return true; if (sub->render_sector->GetTexture(sector_t::floor) != anchor->GetTexture(sector_t::floor) || sub->render_sector->GetPlaneTexZ(sector_t::floor)!=anchor->GetPlaneTexZ(sector_t::floor) || GetFloorLight(sub->render_sector)!=GetFloorLight(anchor)) { if (sub==viewsubsector && viewz<anchor->GetPlaneTexZ(sector_t::floor)) inview=true; HandledSubsectors.Push (sub); } } // We can assume that all segs in this subsector are connected to a subsector that has // to be checked as well for(DWORD j=0; j<sub->numlines; j++) { seg_t * seg = sub->firstline + j; if (seg->PartnerSeg) { subsector_t * backsub = seg->PartnerSeg->Subsector; // could be an anchor itself. if (!CheckAnchorFloor (backsub)) // must not be an anchor itself! { if (backsub->validcount!=validcount) { if (!CollectSubsectorsFloor (backsub, anchor)) return false; } } else if (sub->render_sector == backsub->render_sector) { // Any anchor not within the original anchor's visplane terminates the processing. if (sub->render_sector->GetTexture(sector_t::floor)!=anchor->GetTexture(sector_t::floor) || sub->render_sector->GetPlaneTexZ(sector_t::floor)!=anchor->GetPlaneTexZ(sector_t::floor) || GetFloorLight(sub->render_sector)!=GetFloorLight(anchor)) { return false; } } if (!seg->linedef || (seg->frontsector==seg->backsector && sub->render_sector!=backsub->render_sector)) lowersegs.Push(seg); } } return true; }
void FDrawInfo::CollectSectorStacksFloor(subsector_t * sub, sector_t * anchor) { sector_t fake; // mark it checked sub->validcount=validcount; // Has a sector stack or skybox itself! if (sub->render_sector->FloorSkyBox && sub->render_sector->FloorSkyBox->bAlways) return; // Don't bother processing unrendered subsectors if (sub->numlines>2 && !(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return; // Must be the exact same visplane sector_t * me = gl_FakeFlat(sub->render_sector, &fake, false); if (me->GetTexture(sector_t::floor) != anchor->GetTexture(sector_t::floor) || me->floorplane != anchor->floorplane || GetFloorLight(me) != GetFloorLight(anchor) || me->ColorMap != anchor->ColorMap || me->GetXOffset(sector_t::floor) != anchor->GetXOffset(sector_t::floor) || me->GetYOffset(sector_t::floor) != anchor->GetYOffset(sector_t::floor) || me->GetXScale(sector_t::floor) != anchor->GetXScale(sector_t::floor) || me->GetYScale(sector_t::floor) != anchor->GetYScale(sector_t::floor) || me->GetAngle(sector_t::floor) != anchor->GetAngle(sector_t::floor)) { // different visplane so it can't belong to this stack return; } HandledSubsectors.Push (sub); for(DWORD j=0; j<sub->numlines; j++) { seg_t * seg = sub->firstline + j; if (seg->PartnerSeg) { subsector_t * backsub = seg->PartnerSeg->Subsector; if (backsub->validcount!=validcount) CollectSectorStacksFloor (backsub, anchor); } } }
sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) { // [RH] allow per-plane lighting if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (sec); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (sec); } FakeSide = FAKED_Center; const sector_t *s = sec->GetHeightSec(); if (s != NULL) { sector_t *heightsec = viewsector->heightsec; bool underwater = r_fakingunderwater || (heightsec && viewz <= heightsec->floorplane.ZatPoint (viewx, viewy)); bool doorunderwater = false; int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES); // Replace sector being drawn with a copy to be hacked *tempsec = *sec; // Replace floor and ceiling height with control sector's heights. if (diffTex) { if (CopyPlaneIfValid (&tempsec->floorplane, &s->floorplane, &sec->ceilingplane)) { tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false); } else if (s->MoreFlags & SECF_FAKEFLOORONLY) { if (underwater) { tempsec->ColorMap = s->ColorMap; if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_BelowFloor; return tempsec; } return sec; } } else { tempsec->floorplane = s->floorplane; } if (!(s->MoreFlags & SECF_FAKEFLOORONLY)) { if (diffTex) { if (CopyPlaneIfValid (&tempsec->ceilingplane, &s->ceilingplane, &sec->floorplane)) { tempsec->SetTexture(sector_t::ceiling, s->GetTexture(sector_t::ceiling), false); } } else { tempsec->ceilingplane = s->ceilingplane; } } // fixed_t refflorz = s->floorplane.ZatPoint (viewx, viewy); fixed_t refceilz = s->ceilingplane.ZatPoint (viewx, viewy); // fixed_t orgflorz = sec->floorplane.ZatPoint (viewx, viewy); fixed_t orgceilz = sec->ceilingplane.ZatPoint (viewx, viewy); #if 1 // [RH] Allow viewing underwater areas through doors/windows that // are underwater but not in a water sector themselves. // Only works if you cannot see the top surface of any deep water // sectors at the same time. if (back && !r_fakingunderwater && curline->frontsector->heightsec == NULL) { if (rw_frontcz1 <= s->floorplane.ZatPoint (curline->v1->x, curline->v1->y) && rw_frontcz2 <= s->floorplane.ZatPoint (curline->v2->x, curline->v2->y)) { // Check that the window is actually visible for (int z = WallSX1; z < WallSX2; ++z) { if (floorclip[z] > ceilingclip[z]) { doorunderwater = true; r_fakingunderwater = true; break; } } } } #endif if (underwater || doorunderwater) { tempsec->floorplane = sec->floorplane; tempsec->ceilingplane = s->floorplane; tempsec->ceilingplane.FlipVert (); tempsec->ceilingplane.ChangeHeight (-1); tempsec->ColorMap = s->ColorMap; } // killough 11/98: prevent sudden light changes from non-water sectors: if ((underwater && !back) || doorunderwater) { // head-below-floor hack tempsec->SetTexture(sector_t::floor, diffTex ? sec->GetTexture(sector_t::floor) : s->GetTexture(sector_t::floor), false); tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform; tempsec->ceilingplane = s->floorplane; tempsec->ceilingplane.FlipVert (); tempsec->ceilingplane.ChangeHeight (-1); if (s->GetTexture(sector_t::ceiling) == skyflatnum) { tempsec->floorplane = tempsec->ceilingplane; tempsec->floorplane.FlipVert (); tempsec->floorplane.ChangeHeight (+1); tempsec->SetTexture(sector_t::ceiling, tempsec->GetTexture(sector_t::floor), false); tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform; } else { tempsec->SetTexture(sector_t::ceiling, diffTex ? s->GetTexture(sector_t::floor) : s->GetTexture(sector_t::ceiling), false); tempsec->planes[sector_t::ceiling].xform = s->planes[sector_t::ceiling].xform; } if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_BelowFloor; } else if (heightsec && viewz >= heightsec->ceilingplane.ZatPoint (viewx, viewy) && orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY)) { // Above-ceiling hack tempsec->ceilingplane = s->ceilingplane; tempsec->floorplane = s->ceilingplane; tempsec->floorplane.FlipVert (); tempsec->floorplane.ChangeHeight (+1); tempsec->ColorMap = s->ColorMap; tempsec->ColorMap = s->ColorMap; tempsec->SetTexture(sector_t::ceiling, diffTex ? sec->GetTexture(sector_t::ceiling) : s->GetTexture(sector_t::ceiling), false); tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::ceiling), false); tempsec->planes[sector_t::ceiling].xform = tempsec->planes[sector_t::floor].xform = s->planes[sector_t::ceiling].xform; if (s->GetTexture(sector_t::floor) != skyflatnum) { tempsec->ceilingplane = sec->ceilingplane; tempsec->SetTexture(sector_t::floor, s->GetTexture(sector_t::floor), false); tempsec->planes[sector_t::floor].xform = s->planes[sector_t::floor].xform; } if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_AboveCeiling; } sec = tempsec; // Use other sector } return sec; }
//========================================================================== // // Draw the plane segment into the gap // //========================================================================== void GLDrawInfo::DrawFloodedPlane(wallseg * ws, float planez, sector_t * sec, bool ceiling) { GLSectorPlane plane; int lightlevel; FColormap Colormap; FGLTexture * gltexture; plane.GetFromSector(sec, ceiling); gltexture=FGLTexture::ValidateTexture(plane.texture); if (!gltexture) return; if (gl_fixedcolormap) { Colormap.GetFixedColormap(); lightlevel=255; } else { Colormap=sec->ColorMap; if (gltexture->tex->isFullbright()) { Colormap.LightColor.r = Colormap.LightColor.g = Colormap.LightColor.b = 0xff; lightlevel=255; } else lightlevel=abs(ceiling? GetCeilingLight(sec) : GetFloorLight(sec)); } int rel = extralight * gl_weaponlight; gl_SetColor(lightlevel, rel, &Colormap, 1.0f); gl_SetFog(lightlevel, rel, &Colormap, false); gltexture->Bind(Colormap.LightColor.a); gl_SetPlaneTextureRotation(&plane, gltexture); float fviewx = TO_GL(viewx); float fviewy = TO_GL(viewy); float fviewz = TO_GL(viewz); gl_ApplyShader(); gl.Begin(GL_TRIANGLE_FAN); float prj_fac1 = (planez-fviewz)/(ws->z1-fviewz); float prj_fac2 = (planez-fviewz)/(ws->z2-fviewz); float px1 = fviewx + prj_fac1 * (ws->x1-fviewx); float py1 = fviewy + prj_fac1 * (ws->y1-fviewy); float px2 = fviewx + prj_fac2 * (ws->x1-fviewx); float py2 = fviewy + prj_fac2 * (ws->y1-fviewy); float px3 = fviewx + prj_fac2 * (ws->x2-fviewx); float py3 = fviewy + prj_fac2 * (ws->y2-fviewy); float px4 = fviewx + prj_fac1 * (ws->x2-fviewx); float py4 = fviewy + prj_fac1 * (ws->y2-fviewy); gl.TexCoord2f(px1 / 64, -py1 / 64); gl.Vertex3f(px1, planez, py1); gl.TexCoord2f(px2 / 64, -py2 / 64); gl.Vertex3f(px2, planez, py2); gl.TexCoord2f(px3 / 64, -py3 / 64); gl.Vertex3f(px3, planez, py3); gl.TexCoord2f(px4 / 64, -py4 / 64); gl.Vertex3f(px4, planez, py4); gl.End(); gl.MatrixMode(GL_TEXTURE); gl.PopMatrix(); gl.MatrixMode(GL_MODELVIEW); }
sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, int *floorlightlevel, int *ceilinglightlevel, bool back) { // [ZDoomGL] - convenience, so you don't have to check for NULL before calling function if (!sec) { return NULL; } // [RH] allow per-plane lighting if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (sec); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (sec); } FakeSide = FAKED_Center; if (sec->heightsec && !(sec->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)) { const sector_t *s = sec->heightsec; sector_t *heightsec = viewsector->heightsec; bool underwater = r_fakingunderwater || (heightsec && viewz <= heightsec->floorplane.ZatPoint (viewx, viewy)); bool doorunderwater = false; int diffTex = (s->MoreFlags & SECF_CLIPFAKEPLANES); // Replace sector being drawn with a copy to be hacked *tempsec = *sec; // Replace floor and ceiling height with control sector's heights. if (diffTex) { if (CopyPlaneIfValid (&tempsec->floorplane, &s->floorplane, &sec->ceilingplane)) { tempsec->floorpic = s->floorpic; } else if (s->MoreFlags & SECF_FAKEFLOORONLY) { if (underwater) { tempsec->ColorMap = s->ColorMap; if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_BelowFloor; return tempsec; } return sec; } } else { tempsec->floorplane = s->floorplane; } if (!(s->MoreFlags & SECF_FAKEFLOORONLY)) { if (diffTex) { if (CopyPlaneIfValid (&tempsec->ceilingplane, &s->ceilingplane, &sec->floorplane)) { tempsec->ceilingpic = s->ceilingpic; } } else { tempsec->ceilingplane = s->ceilingplane; } } // fixed_t refflorz = s->floorplane.ZatPoint (viewx, viewy); fixed_t refceilz = s->ceilingplane.ZatPoint (viewx, viewy); // fixed_t orgflorz = sec->floorplane.ZatPoint (viewx, viewy); fixed_t orgceilz = sec->ceilingplane.ZatPoint (viewx, viewy); #if 1 if ( OPENGL_GetCurrentRenderer( ) == RENDERER_SOFTWARE ) { // [RH] Allow viewing underwater areas through doors/windows that // are underwater but not in a water sector themselves. // Only works if you cannot see the top surface of any deep water // sectors at the same time. if (back && !r_fakingunderwater && curline->frontsector->heightsec == NULL) { if (rw_frontcz1 <= s->floorplane.ZatPoint (curline->v1->x, curline->v1->y) && rw_frontcz2 <= s->floorplane.ZatPoint (curline->v2->x, curline->v2->y)) { // Check that the window is actually visible for (int z = WallSX1; z < WallSX2; ++z) { if (floorclip[z] > ceilingclip[z]) { doorunderwater = true; r_fakingunderwater = true; break; } } } } } else { // have to do this a different way for the hardware engine... } #endif if (underwater || doorunderwater) { tempsec->floorplane = sec->floorplane; tempsec->ceilingplane = s->floorplane; tempsec->ceilingplane.FlipVert (); tempsec->ceilingplane.ChangeHeight (-1); tempsec->ColorMap = s->ColorMap; } // killough 11/98: prevent sudden light changes from non-water sectors: if ((underwater && !back) || doorunderwater) { // head-below-floor hack tempsec->floorpic = diffTex ? sec->floorpic : s->floorpic; tempsec->floor_xoffs = s->floor_xoffs; tempsec->floor_yoffs = s->floor_yoffs; tempsec->floor_xscale = s->floor_xscale; tempsec->floor_yscale = s->floor_yscale; tempsec->floor_angle = s->floor_angle; tempsec->base_floor_angle = s->base_floor_angle; tempsec->base_floor_yoffs = s->base_floor_yoffs; tempsec->ceilingplane = s->floorplane; tempsec->ceilingplane.FlipVert (); tempsec->ceilingplane.ChangeHeight (-1); if (s->ceilingpic == skyflatnum) { tempsec->floorplane = tempsec->ceilingplane; tempsec->floorplane.FlipVert (); tempsec->floorplane.ChangeHeight (+1); tempsec->ceilingpic = tempsec->floorpic; tempsec->ceiling_xoffs = tempsec->floor_xoffs; tempsec->ceiling_yoffs = tempsec->floor_yoffs; tempsec->ceiling_xscale = tempsec->floor_xscale; tempsec->ceiling_yscale = tempsec->floor_yscale; tempsec->ceiling_angle = tempsec->floor_angle; tempsec->base_ceiling_angle = tempsec->base_floor_angle; tempsec->base_ceiling_yoffs = tempsec->base_floor_yoffs; } else { tempsec->ceilingpic = diffTex ? s->floorpic : s->ceilingpic; tempsec->ceiling_xoffs = s->ceiling_xoffs; tempsec->ceiling_yoffs = s->ceiling_yoffs; tempsec->ceiling_xscale = s->ceiling_xscale; tempsec->ceiling_yscale = s->ceiling_yscale; tempsec->ceiling_angle = s->ceiling_angle; tempsec->base_ceiling_angle = s->base_ceiling_angle; tempsec->base_ceiling_yoffs = s->base_ceiling_yoffs; } if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_BelowFloor; } else if (heightsec && viewz >= heightsec->ceilingplane.ZatPoint (viewx, viewy) && orgceilz > refceilz && !(s->MoreFlags & SECF_FAKEFLOORONLY)) { // Above-ceiling hack tempsec->ceilingplane = s->ceilingplane; tempsec->floorplane = s->ceilingplane; tempsec->floorplane.FlipVert (); tempsec->floorplane.ChangeHeight (+1); tempsec->ColorMap = s->ColorMap; tempsec->ColorMap = s->ColorMap; tempsec->ceilingpic = diffTex ? sec->ceilingpic : s->ceilingpic; tempsec->floorpic = s->ceilingpic; tempsec->floor_xoffs = tempsec->ceiling_xoffs = s->ceiling_xoffs; tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs; tempsec->floor_xscale = tempsec->ceiling_xscale = s->ceiling_xscale; tempsec->floor_yscale = tempsec->ceiling_yscale = s->ceiling_yscale; tempsec->floor_angle = tempsec->ceiling_angle = s->ceiling_angle; tempsec->base_floor_angle = tempsec->base_ceiling_angle = s->base_ceiling_angle; tempsec->base_floor_yoffs = tempsec->base_ceiling_yoffs = s->base_ceiling_yoffs; if (s->floorpic != skyflatnum) { tempsec->ceilingplane = sec->ceilingplane; tempsec->floorpic = s->floorpic; tempsec->floor_xoffs = s->floor_xoffs; tempsec->floor_yoffs = s->floor_yoffs; tempsec->floor_xscale = s->floor_xscale; tempsec->floor_yscale = s->floor_yscale; tempsec->floor_angle = s->floor_angle; } if (!(s->MoreFlags & SECF_NOFAKELIGHT)) { tempsec->lightlevel = s->lightlevel; if (floorlightlevel != NULL) { *floorlightlevel = GetFloorLight (s); } if (ceilinglightlevel != NULL) { *ceilinglightlevel = GetCeilingLight (s); } } FakeSide = FAKED_AboveCeiling; } sec = tempsec; // Use other sector } return sec; }