void FTraceInfo::EnterLinePortal(FPathTraverse &pt, intercept_t *in) { line_t *li = in->d.line; FLinePortal *port = li->getPortal(); double frac = in->frac + EQUAL_EPSILON; double enterdist = MaxDist * frac; DVector3 exit = Start + MaxDist * in->frac * Vec; P_TranslatePortalXY(li, Start.X, Start.Y); P_TranslatePortalZ(li, Start.Z); P_TranslatePortalVXVY(li, Vec.X, Vec.Y); P_TranslatePortalZ(li, limitz); CurSector = P_PointInSector(Start + enterdist * Vec); EnterDist = enterdist; inshootthrough = true; startfrac = frac; Results->unlinked |= (port->mType != PORTT_LINKED); pt.PortalRelocate(in, ptflags); if ((TraceFlags & TRACE_ReportPortals) && TraceCallback != NULL) { enterdist = MaxDist * in->frac; Results->HitType = TRACE_CrossingPortal; Results->HitPos = exit; P_TranslatePortalXY(li, exit.X, exit.Y); P_TranslatePortalZ(li, exit.Z); Results->SrcFromTarget = exit; Results->HitVector = Vec; TraceCallback(*Results, TraceCallbackData); } }
//----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- void GLLineToLinePortal::DrawContents() { // TODO: Handle recursion more intelligently if (renderdepth>r_mirror_recursions) { ClearScreen(); return; } GLRenderer->mClipPortal = this; line_t *origin = glport->lines[0]->mOrigin; P_TranslatePortalXY(origin, ViewPos.X, ViewPos.Y); P_TranslatePortalAngle(origin, ViewAngle); P_TranslatePortalZ(origin, ViewPos.Z); P_TranslatePortalXY(origin, ViewPath[0].X, ViewPath[0].Y); P_TranslatePortalXY(origin, ViewPath[1].X, ViewPath[1].Y); if (!r_showviewer && camera != nullptr && P_PointOnLineSidePrecise(ViewPath[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(ViewPath[1], glport->lines[0]->mDestination)) { double distp = (ViewPath[0] - ViewPath[1]).Length(); if (distp > EQUAL_EPSILON) { double dist1 = (ViewPos - ViewPath[0]).Length(); double dist2 = (ViewPos - ViewPath[1]).Length(); if (dist1 + dist2 < distp + 1) { camera->renderflags |= RF_INVISIBLE; } } } SaveMapSection(); for (unsigned i = 0; i < lines.Size(); i++) { line_t *line = lines[i].seg->linedef->getPortalDestination(); subsector_t *sub; if (line->sidedef[0]->Flags & WALLF_POLYOBJ) sub = R_PointInSubsector(line->v1->fixX(), line->v1->fixY()); else sub = line->frontsector->subsectors[0]; int mapsection = sub->mapsection; currentmapsection[mapsection >> 3] |= 1 << (mapsection & 7); } GLRenderer->mViewActor = nullptr; GLRenderer->SetupView(ViewPos.X, ViewPos.Y, ViewPos.Z, ViewAngle, !!(MirrorFlag&1), !!(PlaneMirrorFlag&1)); ClearClipper(); gl_RenderState.SetClipLine(glport->lines[0]->mDestination); gl_RenderState.EnableClipLine(true); GLRenderer->DrawScene(DM_PORTAL); gl_RenderState.EnableClipLine(false); RestoreMapSection(); }
//----------------------------------------------------------------------------- // // // //----------------------------------------------------------------------------- bool HWLineToLinePortal::Setup(HWDrawInfo *di, FRenderState &rstate, Clipper *clipper) { // TODO: Handle recursion more intelligently auto &state = mState; if (state->renderdepth>r_mirror_recursions) { return false; } auto &vp = di->Viewpoint; di->mClipPortal = this; line_t *origin = glport->lines[0]->mOrigin; P_TranslatePortalXY(origin, vp.Pos.X, vp.Pos.Y); P_TranslatePortalXY(origin, vp.ActorPos.X, vp.ActorPos.Y); P_TranslatePortalAngle(origin, vp.Angles.Yaw); P_TranslatePortalZ(origin, vp.Pos.Z); P_TranslatePortalXY(origin, vp.Path[0].X, vp.Path[0].Y); P_TranslatePortalXY(origin, vp.Path[1].X, vp.Path[1].Y); if (!vp.showviewer && vp.camera != nullptr && P_PointOnLineSidePrecise(vp.Path[0], glport->lines[0]->mDestination) != P_PointOnLineSidePrecise(vp.Path[1], glport->lines[0]->mDestination)) { double distp = (vp.Path[0] - vp.Path[1]).Length(); if (distp > EQUAL_EPSILON) { double dist1 = (vp.Pos - vp.Path[0]).Length(); double dist2 = (vp.Pos - vp.Path[1]).Length(); if (dist1 + dist2 < distp + 1) { vp.camera->renderflags |= RF_MAYBEINVISIBLE; } } } for (unsigned i = 0; i < lines.Size(); i++) { line_t *line = lines[i].seg->linedef->getPortalDestination(); subsector_t *sub; if (line->sidedef[0]->Flags & WALLF_POLYOBJ) sub = di->Level->PointInRenderSubsector(line->v1->fixX(), line->v1->fixY()); else sub = line->frontsector->subsectors[0]; di->CurrentMapSections.Set(sub->mapsection); } vp.ViewActor = nullptr; di->SetClipLine(glport->lines[0]->mDestination); di->SetupView(rstate, vp.Pos.X, vp.Pos.Y, vp.Pos.Z, !!(state->MirrorFlag & 1), !!(state->PlaneMirrorFlag & 1)); ClearClipper(di, clipper); return true; }
void PolyDrawLinePortal::SaveGlobals() { auto &viewpoint = PolyRenderer::Instance()->Viewpoint; const auto &viewwindow = PolyRenderer::Instance()->Viewwindow; SavedViewpoint = viewpoint; SavedInvisibility = viewpoint.camera ? (viewpoint.camera->renderflags & RF_INVISIBLE) == RF_INVISIBLE : false; if (Mirror) { DAngle startang = viewpoint.Angles.Yaw; DVector3 startpos = viewpoint.Pos; vertex_t *v1 = Mirror->v1; // Reflect the current view behind the mirror. if (Mirror->Delta().X == 0) { // vertical mirror viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX(); } else if (Mirror->Delta().Y == 0) { // horizontal mirror viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY(); } else { // any mirror vertex_t *v2 = Mirror->v2; double dx = v2->fX() - v1->fX(); double dy = v2->fY() - v1->fY(); double x1 = v1->fX(); double y1 = v1->fY(); double x = startpos.X; double y = startpos.Y; // the above two cases catch len == 0 double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); viewpoint.Pos.X = (x1 + r * dx) * 2 - x; viewpoint.Pos.Y = (y1 + r * dy) * 2 - y; } viewpoint.Angles.Yaw = Mirror->Delta().Angle() * 2 - startang; if (viewpoint.camera) viewpoint.camera->renderflags &= ~RF_INVISIBLE; } else { auto src = Portal->mOrigin; auto dst = Portal->mDestination; P_TranslatePortalXY(src, viewpoint.Pos.X, viewpoint.Pos.Y); P_TranslatePortalZ(src, viewpoint.Pos.Z); P_TranslatePortalAngle(src, viewpoint.Angles.Yaw); P_TranslatePortalXY(src, viewpoint.Path[0].X, viewpoint.Path[0].Y); P_TranslatePortalXY(src, viewpoint.Path[1].X, viewpoint.Path[1].Y); if (viewpoint.camera && !viewpoint.showviewer) viewpoint.camera->renderflags |= RF_INVISIBLE; /* What is this code trying to do? if (viewpoint.camera) { viewpoint.camera->renderflags &= ~RF_INVISIBLE; if (!viewpoint.showviewer && P_PointOnLineSidePrecise(viewpoint.Path[0], dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], dst)) { double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length(); if (distp > EQUAL_EPSILON) { double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length(); double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length(); if (dist1 + dist2 < distp + 1) { viewpoint.camera->renderflags |= RF_INVISIBLE; } } } } */ } viewpoint.camera = nullptr; viewpoint.sector = viewpoint.ViewLevel->PointInRenderSubsector(viewpoint.Pos)->sector; viewpoint.SetViewAngle(viewwindow); }
void RenderPortal::RenderLinePortal(PortalDrawseg* pds, int depth) { auto viewport = Thread->Viewport.get(); auto &viewpoint = viewport->viewpoint; // [ZZ] check depth. fill portal with black if it's exceeding the visual recursion limit, and continue like nothing happened. if (depth >= r_portal_recursions) { uint8_t color = (uint8_t)BestColor((uint32_t *)GPalette.BaseColors, 0, 0, 0, 0, 255); int spacing = viewport->RenderTarget->GetPitch(); for (int x = pds->x1; x < pds->x2; x++) { if (x < 0 || x >= viewport->RenderTarget->GetWidth()) continue; int Ytop = pds->ceilingclip[x - pds->x1]; int Ybottom = pds->floorclip[x - pds->x1]; if (viewport->RenderTarget->IsBgra()) { uint32_t *dest = (uint32_t*)viewport->RenderTarget->GetBuffer() + x + Ytop * spacing; uint32_t c = GPalette.BaseColors[color].d; for (int y = Ytop; y <= Ybottom; y++) { *dest = c; dest += spacing; } } else { uint8_t *dest = viewport->RenderTarget->GetBuffer() + x + Ytop * spacing; for (int y = Ytop; y <= Ybottom; y++) { *dest = color; dest += spacing; } } } if (r_highlight_portals) RenderLinePortalHighlight(pds); return; } DAngle startang = viewpoint.Angles.Yaw; DVector3 startpos = viewpoint.Pos; DVector3 savedpath[2] = { viewpoint.Path[0], viewpoint.Path[1] }; ActorRenderFlags savedvisibility = viewpoint.camera ? viewpoint.camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0); viewpoint.camera->renderflags &= ~RF_INVISIBLE; CurrentPortalUniq++; unsigned int portalsAtStart = WallPortals.Size(); if (pds->mirror) { //vertex_t *v1 = ds->curline->v1; vertex_t *v1 = pds->src->v1; // Reflect the current view behind the mirror. if (pds->src->Delta().X == 0) { // vertical mirror viewpoint.Pos.X = v1->fX() - startpos.X + v1->fX(); } else if (pds->src->Delta().Y == 0) { // horizontal mirror viewpoint.Pos.Y = v1->fY() - startpos.Y + v1->fY(); } else { // any mirror vertex_t *v2 = pds->src->v2; double dx = v2->fX() - v1->fX(); double dy = v2->fY() - v1->fY(); double x1 = v1->fX(); double y1 = v1->fY(); double x = startpos.X; double y = startpos.Y; // the above two cases catch len == 0 double r = ((x - x1)*dx + (y - y1)*dy) / (dx*dx + dy*dy); viewpoint.Pos.X = (x1 + r * dx) * 2 - x; viewpoint.Pos.Y = (y1 + r * dy) * 2 - y; } viewpoint.Angles.Yaw = pds->src->Delta().Angle() * 2 - startang; } else { P_TranslatePortalXY(pds->src, viewpoint.Pos.X, viewpoint.Pos.Y); P_TranslatePortalZ(pds->src, viewpoint.Pos.Z); P_TranslatePortalAngle(pds->src, viewpoint.Angles.Yaw); P_TranslatePortalXY(pds->src, viewpoint.Path[0].X, viewpoint.Path[0].Y); P_TranslatePortalXY(pds->src, viewpoint.Path[1].X, viewpoint.Path[1].Y); if (!viewpoint.showviewer && viewpoint.camera && P_PointOnLineSidePrecise(viewpoint.Path[0], pds->dst) != P_PointOnLineSidePrecise(viewpoint.Path[1], pds->dst)) { double distp = (viewpoint.Path[0] - viewpoint.Path[1]).Length(); if (distp > EQUAL_EPSILON) { double dist1 = (viewpoint.Pos - viewpoint.Path[0]).Length(); double dist2 = (viewpoint.Pos - viewpoint.Path[1]).Length(); if (dist1 + dist2 < distp + 1) { viewpoint.camera->renderflags |= RF_INVISIBLE; } } } } viewpoint.Sin = viewpoint.Angles.Yaw.Sin(); viewpoint.Cos = viewpoint.Angles.Yaw.Cos(); viewpoint.TanSin = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Sin; viewpoint.TanCos = Thread->Viewport->viewwindow.FocalTangent * viewpoint.Cos; CopyStackedViewParameters(); validcount++; PortalDrawseg* prevpds = CurrentPortal; CurrentPortal = pds; Thread->PlaneList->ClearKeepFakePlanes(); Thread->ClipSegments->Clear(pds->x1, pds->x2); WindowLeft = pds->x1; WindowRight = pds->x2; // RF_XFLIP should be removed before calling the root function int prevmf = MirrorFlags; if (pds->mirror) { if (MirrorFlags & RF_XFLIP) MirrorFlags &= ~RF_XFLIP; else MirrorFlags |= RF_XFLIP; } // some portals have height differences, account for this here Thread->Clip3D->EnterSkybox(); // push 3D floor height map CurrentPortalInSkybox = false; // first portal in a skybox should set this variable to false for proper clipping in skyboxes. // first pass, set clipping auto ceilingclip = Thread->OpaquePass->ceilingclip; auto floorclip = Thread->OpaquePass->floorclip; memcpy(ceilingclip + pds->x1, &pds->ceilingclip[0], pds->len * sizeof(*ceilingclip)); memcpy(floorclip + pds->x1, &pds->floorclip[0], pds->len * sizeof(*floorclip)); Thread->OpaquePass->RenderScene(); Thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) if (!savedvisibility && viewpoint.camera) viewpoint.camera->renderflags &= ~RF_INVISIBLE; Thread->PlaneList->Render(); RenderPlanePortals(); double vzp = viewpoint.Pos.Z; int prevuniq = CurrentPortalUniq; // depth check is in another place right now unsigned int portalsAtEnd = WallPortals.Size(); for (; portalsAtStart < portalsAtEnd; portalsAtStart++) { RenderLinePortal(WallPortals[portalsAtStart], depth + 1); } int prevuniq2 = CurrentPortalUniq; CurrentPortalUniq = prevuniq; if (Thread->MainThread) NetUpdate(); Thread->TranslucentPass->Render(); // this is required since with portals there often will be cases when more than 80% of the view is inside a portal. if (Thread->MainThread) NetUpdate(); Thread->Clip3D->LeaveSkybox(); // pop 3D floor height map CurrentPortalUniq = prevuniq2; // draw a red line around a portal if it's being highlighted if (r_highlight_portals) RenderLinePortalHighlight(pds); CurrentPortal = prevpds; MirrorFlags = prevmf; viewpoint.Angles.Yaw = startang; viewpoint.Pos = startpos; viewpoint.Path[0] = savedpath[0]; viewpoint.Path[1] = savedpath[1]; }