void FGLRenderer::SetViewAngle(DAngle viewangle) { mAngles.Yaw = float(270.0-viewangle.Degrees); DVector2 v = ViewAngle.ToVector(); mViewVector.X = v.X; mViewVector.Y = v.Y; R_SetViewAngle(); }
// Draws any recorded sky boxes and then frees them. // // The process: // 1. Move the camera to coincide with the SkyViewpoint. // 2. Clear out the old planes. (They have already been drawn.) // 3. Clear a window out of the ClipSegs just large enough for the plane. // 4. Pretend the existing vissprites and drawsegs aren't there. // 5. Create a drawseg at 0 distance to clip sprites to the visplane. It // doesn't need to be associated with a line in the map, since there // will never be any sprites in front of it. // 6. Render the BSP, then planes, then masked stuff. // 7. Restore the previous vissprites and drawsegs. // 8. Repeat for any other sky boxes. // 9. Put the camera back where it was to begin with. // void RenderPortal::RenderPlanePortals() { numskyboxes = 0; VisiblePlaneList *planes = Thread->PlaneList.get(); DrawSegmentList *drawseglist = Thread->DrawSegments.get(); if (!planes->HasPortalPlanes()) return; Thread->Clip3D->EnterSkybox(); CurrentPortalInSkybox = true; int savedextralight = Thread->Viewport->viewpoint.extralight; DVector3 savedpos = Thread->Viewport->viewpoint.Pos; DRotator savedangles = Thread->Viewport->viewpoint.Angles; double savedvisibility = Thread->Light->GetVisibility(); AActor *savedcamera = Thread->Viewport->viewpoint.camera; sector_t *savedsector = Thread->Viewport->viewpoint.sector; for (VisiblePlane *pl = planes->PopFirstPortalPlane(); pl != nullptr; pl = planes->PopFirstPortalPlane()) { if (pl->right < pl->left || !r_skyboxes || numskyboxes == MAX_SKYBOX_PLANES || pl->portal == nullptr) { pl->Render(Thread, OPAQUE, false, false); continue; } numskyboxes++; FSectorPortal *port = pl->portal; switch (port->mType) { case PORTS_SKYVIEWPOINT: { // Don't let gun flashes brighten the sky box AActor *sky = port->mSkybox; Thread->Viewport->viewpoint.extralight = 0; Thread->Light->SetVisibility(Thread->Viewport.get(), sky->args[0] * 0.25f); Thread->Viewport->viewpoint.Pos = sky->InterpolatedPosition(Thread->Viewport->viewpoint.TicFrac); Thread->Viewport->viewpoint.Angles.Yaw = savedangles.Yaw + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * Thread->Viewport->viewpoint.TicFrac); CopyStackedViewParameters(); break; } case PORTS_STACKEDSECTORTHING: case PORTS_PORTAL: case PORTS_LINKEDPORTAL: Thread->Viewport->viewpoint.extralight = pl->extralight; Thread->Light->SetVisibility(Thread->Viewport.get(), pl->visibility); Thread->Viewport->viewpoint.Pos.X = pl->viewpos.X + port->mDisplacement.X; Thread->Viewport->viewpoint.Pos.Y = pl->viewpos.Y + port->mDisplacement.Y; Thread->Viewport->viewpoint.Pos.Z = pl->viewpos.Z; Thread->Viewport->viewpoint.Angles.Yaw = pl->viewangle; break; case PORTS_HORIZON: case PORTS_PLANE: // not implemented yet default: pl->Render(Thread, OPAQUE, false, false); numskyboxes--; continue; } SetInSkyBox(port); if (port->mPartner > 0) SetInSkyBox(&level.sectorPortals[port->mPartner]); Thread->Viewport->viewpoint.camera = nullptr; Thread->Viewport->viewpoint.sector = port->mDestination; assert(Thread->Viewport->viewpoint.sector != nullptr); R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); Thread->OpaquePass->ClearSeenSprites(); Thread->Clip3D->ClearFakeFloors(); planes->ClearKeepFakePlanes(); Thread->ClipSegments->Clear(pl->left, pl->right); WindowLeft = pl->left; WindowRight = pl->right; auto ceilingclip = Thread->OpaquePass->ceilingclip; auto floorclip = Thread->OpaquePass->floorclip; for (int i = pl->left; i < pl->right; i++) { if (pl->top[i] == 0x7fff) { ceilingclip[i] = viewheight; floorclip[i] = -1; } else { ceilingclip[i] = pl->top[i]; floorclip[i] = pl->bottom[i]; } } drawseglist->PushPortal(); Thread->SpriteList->PushPortal(); viewposStack.Push(Thread->Viewport->viewpoint.Pos); visplaneStack.Push(pl); // Create a drawseg to clip sprites to the sky plane DrawSegment *draw_segment = Thread->FrameMemory->NewObject<DrawSegment>(); draw_segment->CurrentPortalUniq = CurrentPortalUniq; draw_segment->siz1 = INT_MAX; draw_segment->siz2 = INT_MAX; draw_segment->sz1 = 0; draw_segment->sz2 = 0; draw_segment->x1 = pl->left; draw_segment->x2 = pl->right; draw_segment->silhouette = SIL_BOTH; draw_segment->sprbottomclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left); draw_segment->sprtopclip = Thread->FrameMemory->AllocMemory<short>(pl->right - pl->left); draw_segment->maskedtexturecol = nullptr; draw_segment->swall = nullptr; draw_segment->bFogBoundary = false; draw_segment->curline = nullptr; draw_segment->foggy = false; memcpy(draw_segment->sprbottomclip, floorclip + pl->left, (pl->right - pl->left) * sizeof(short)); memcpy(draw_segment->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left) * sizeof(short)); drawseglist->Push(draw_segment); Thread->OpaquePass->RenderScene(); Thread->Clip3D->ResetClip(); // reset clips (floor/ceiling) planes->Render(); ClearInSkyBox(port); if (port->mPartner > 0) SetInSkyBox(&level.sectorPortals[port->mPartner]); } // Draw all the masked textures in a second pass, in the reverse order they // were added. This must be done separately from the previous step for the // sake of nested skyboxes. while (viewposStack.Size() > 0) { // Masked textures and planes need the view coordinates restored for proper positioning. viewposStack.Pop(Thread->Viewport->viewpoint.Pos); Thread->TranslucentPass->Render(); VisiblePlane *pl = nullptr; // quiet, GCC! visplaneStack.Pop(pl); if (pl->Alpha > 0 && pl->picnum != skyflatnum) { pl->Render(Thread, pl->Alpha, pl->Additive, true); } Thread->SpriteList->PopPortal(); drawseglist->PopPortal(); } Thread->Viewport->viewpoint.camera = savedcamera; Thread->Viewport->viewpoint.sector = savedsector; Thread->Viewport->viewpoint.Pos = savedpos; Thread->Light->SetVisibility(Thread->Viewport.get(), savedvisibility); Thread->Viewport->viewpoint.extralight = savedextralight; Thread->Viewport->viewpoint.Angles = savedangles; R_SetViewAngle(Thread->Viewport->viewpoint, Thread->Viewport->viewwindow); CurrentPortalInSkybox = false; Thread->Clip3D->LeaveSkybox(); if (Thread->Clip3D->fakeActive) return; planes->ClearPortalPlanes(); }
void R_DrawPortals () { static TArray<size_t> interestingStack; static TArray<ptrdiff_t> drawsegStack; static TArray<ptrdiff_t> visspriteStack; static TArray<DVector3> viewposStack; static TArray<visplane_t *> visplaneStack; numskyboxes = 0; if (visplanes[MAXVISPLANES] == NULL) return; R_3D_EnterSkybox(); CurrentPortalInSkybox = true; int savedextralight = extralight; DVector3 savedpos = ViewPos; DAngle savedangle = ViewAngle; ptrdiff_t savedvissprite_p = vissprite_p - vissprites; ptrdiff_t savedds_p = ds_p - drawsegs; ptrdiff_t savedlastopening = lastopening; size_t savedinteresting = FirstInterestingDrawseg; double savedvisibility = R_GetVisibility(); AActor *savedcamera = camera; sector_t *savedsector = viewsector; int i; visplane_t *pl; for (pl = visplanes[MAXVISPLANES]; pl != NULL; pl = visplanes[MAXVISPLANES]) { // Pop the visplane off the list now so that if this skybox adds more // skyboxes to the list, they will be drawn instead of skipped (because // new skyboxes go to the beginning of the list instead of the end). visplanes[MAXVISPLANES] = pl->next; pl->next = NULL; if (pl->right < pl->left || !r_skyboxes || numskyboxes == MAX_SKYBOX_PLANES || pl->portal == NULL) { R_DrawSinglePlane (pl, OPAQUE, false, false); *freehead = pl; freehead = &pl->next; continue; } numskyboxes++; FSectorPortal *port = pl->portal; switch (port->mType) { case PORTS_SKYVIEWPOINT: { // Don't let gun flashes brighten the sky box ASkyViewpoint *sky = barrier_cast<ASkyViewpoint*>(port->mSkybox); extralight = 0; R_SetVisibility(sky->args[0] * 0.25f); ViewPos = sky->InterpolatedPosition(r_TicFracF); ViewAngle = savedangle + (sky->PrevAngles.Yaw + deltaangle(sky->PrevAngles.Yaw, sky->Angles.Yaw) * r_TicFracF); R_CopyStackedViewParameters(); break; } case PORTS_STACKEDSECTORTHING: case PORTS_PORTAL: case PORTS_LINKEDPORTAL: extralight = pl->extralight; R_SetVisibility (pl->visibility); ViewPos.X = pl->viewpos.X + port->mDisplacement.X; ViewPos.Y = pl->viewpos.Y + port->mDisplacement.Y; ViewPos.Z = pl->viewpos.Z; ViewAngle = pl->viewangle; break; case PORTS_HORIZON: case PORTS_PLANE: // not implemented yet default: R_DrawSinglePlane(pl, OPAQUE, false, false); *freehead = pl; freehead = &pl->next; numskyboxes--; continue; } port->mFlags |= PORTSF_INSKYBOX; if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags |= PORTSF_INSKYBOX; camera = NULL; viewsector = port->mDestination; assert(viewsector != NULL); R_SetViewAngle (); validcount++; // Make sure we see all sprites R_ClearPlanes (false); R_ClearClipSegs (pl->left, pl->right); WindowLeft = pl->left; WindowRight = pl->right; for (i = pl->left; i < pl->right; i++) { if (pl->top[i] == 0x7fff) { ceilingclip[i] = viewheight; floorclip[i] = -1; } else { ceilingclip[i] = pl->top[i]; floorclip[i] = pl->bottom[i]; } } // Create a drawseg to clip sprites to the sky plane R_CheckDrawSegs (); ds_p->CurrentPortalUniq = CurrentPortalUniq; ds_p->siz1 = INT_MAX; ds_p->siz2 = INT_MAX; ds_p->sz1 = 0; ds_p->sz2 = 0; ds_p->x1 = pl->left; ds_p->x2 = pl->right; ds_p->silhouette = SIL_BOTH; ds_p->sprbottomclip = R_NewOpening (pl->right - pl->left); ds_p->sprtopclip = R_NewOpening (pl->right - pl->left); ds_p->maskedtexturecol = ds_p->swall = -1; ds_p->bFogBoundary = false; ds_p->curline = NULL; ds_p->fake = 0; memcpy (openings + ds_p->sprbottomclip, floorclip + pl->left, (pl->right - pl->left)*sizeof(short)); memcpy (openings + ds_p->sprtopclip, ceilingclip + pl->left, (pl->right - pl->left)*sizeof(short)); firstvissprite = vissprite_p; firstdrawseg = ds_p++; FirstInterestingDrawseg = InterestingDrawsegs.Size(); interestingStack.Push (FirstInterestingDrawseg); ptrdiff_t diffnum = firstdrawseg - drawsegs; drawsegStack.Push (diffnum); diffnum = firstvissprite - vissprites; visspriteStack.Push (diffnum); viewposStack.Push(ViewPos); visplaneStack.Push (pl); InSubsector = NULL; R_RenderBSPNode (nodes + numnodes - 1); R_3D_ResetClip(); // reset clips (floor/ceiling) R_DrawPlanes (); port->mFlags &= ~PORTSF_INSKYBOX; if (port->mPartner > 0) sectorPortals[port->mPartner].mFlags &= ~PORTSF_INSKYBOX; } // Draw all the masked textures in a second pass, in the reverse order they // were added. This must be done separately from the previous step for the // sake of nested skyboxes. while (interestingStack.Pop (FirstInterestingDrawseg)) { ptrdiff_t pd = 0; drawsegStack.Pop (pd); firstdrawseg = drawsegs + pd; visspriteStack.Pop (pd); firstvissprite = vissprites + pd; // Masked textures and planes need the view coordinates restored for proper positioning. viewposStack.Pop(ViewPos); R_DrawMasked (); ds_p = firstdrawseg; vissprite_p = firstvissprite; visplaneStack.Pop (pl); if (pl->Alpha > 0 && pl->picnum != skyflatnum) { R_DrawSinglePlane (pl, pl->Alpha, pl->Additive, true); } *freehead = pl; freehead = &pl->next; } firstvissprite = vissprites; vissprite_p = vissprites + savedvissprite_p; firstdrawseg = drawsegs; ds_p = drawsegs + savedds_p; InterestingDrawsegs.Resize ((unsigned int)FirstInterestingDrawseg); FirstInterestingDrawseg = savedinteresting; lastopening = savedlastopening; camera = savedcamera; viewsector = savedsector; ViewPos = savedpos; R_SetVisibility(savedvisibility); extralight = savedextralight; ViewAngle = savedangle; R_SetViewAngle (); CurrentPortalInSkybox = false; R_3D_LeaveSkybox(); if(fakeActive) return; for (*freehead = visplanes[MAXVISPLANES], visplanes[MAXVISPLANES] = NULL; *freehead; ) freehead = &(*freehead)->next; }