// // CL_PredictPlayers // void CL_PredictPlayer (player_t *p) { if (p->playerstate == PST_DEAD) { P_DeathThink (p); p->mo->RunThink(); P_CalcHeight(p); } else { P_MovePlayer(p); P_CalcHeight(p); p->mo->RunThink(); } }
// // CL_PredictSpying // // Handles calling the thinker routines for the player being spied with spynext. // static void CL_PredictSpying() { player_t *player = &displayplayer(); if (consoleplayer_id == displayplayer_id) return; predicting = false; P_PlayerThink(player); P_CalcHeight(player); }
// // CL_PredictSpectator // // static void CL_PredictSpectator() { player_t *player = &consoleplayer(); if (!player->spectator) return; predicting = true; P_PlayerThink(player); P_CalcHeight(player); predicting = false; }
// // CL_PredicMove // void CL_PredictMove (void) { if (noservermsgs) return; player_t *p = &consoleplayer(); if (!p->tic || !p->mo) return; // Save player angle, viewheight,deltaviewheight and jumpTics. // Will use it later to predict movements cl_angle[gametic%MAXSAVETICS] = p->mo->angle; cl_pitch[gametic%MAXSAVETICS] = p->mo->pitch; cl_viewheight[gametic%MAXSAVETICS] = p->viewheight; cl_deltaviewheight[gametic%MAXSAVETICS] = p->deltaviewheight; cl_jumpTics[gametic%MAXSAVETICS] = p->jumpTics; reactiontime[gametic%MAXSAVETICS] = p->mo->reactiontime; // Disable sounds, etc, during prediction predicting = true; // Set predictable items to their last received positions CL_ResetPlayers(); CL_ResetSectors(); int predtic = gametic - MAXSAVETICS; if(predtic < 0) predtic = 0; // Predict each tic while(++predtic < gametic) { CL_PredictPlayers(predtic); CL_PredictSectors(predtic); } predicting = false; CL_PredictPlayers(predtic); CL_PredictSectors(predtic); P_PlayerThink (p); P_CalcHeight(p); }
void P_Ticker (void) { int i; // pause if in menu and at least one tic has been run // // killough 9/29/98: note that this ties in with basetic, // since G_Ticker does the pausing during recording or // playback, and compensates by incrementing basetic. // // All of this complicated mess is used to preserve demo sync. if (paused || (menuactive && !demoplayback && !netgame && players[consoleplayer].viewz != 1)) return; // not if this is an intermission screen if(gamestate==GS_LEVEL) for (i=0; i<MAXPLAYERS; i++) if (playeringame[i]) { players[i].predicted = NULL; // sf: nothing predicted yet P_PlayerThink(&players[i]); } reset_viewz = false; // sf P_RunThinkers(); P_UpdateSpecials(); P_RespawnSpecials(); leveltime++; // for par times // sf: on original doom, sometimes if you activated a hyperlift // while standing on it, your viewz was left behind and appeared // to "jump". code in p_floor.c detects if a hyperlift has been // activated and viewz is reset appropriately here. if(reset_viewz && gamestate == GS_LEVEL) P_CalcHeight (&players[displayplayer]); // Determines view height and bobbing T_DelayedScripts(); }
// [RH] Modified to support different source and destination ids. // [RH] Modified some more to be accurate. bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBOOL reverse) { int i; line_t *l; if (side || thing->flags2 & MF2_NOTELEPORT || !line || line->sidedef[1] == NULL) return false; FLineIdIterator itr(id); while ((i = itr.Next()) >= 0) { if (line->Index() == i) continue; if ((l=&level.lines[i]) != line && l->backsector) { // Get the thing's position along the source linedef double pos; DVector2 npos; // offsets from line double den; den = line->Delta().LengthSquared(); if (den == 0) { pos = 0; npos.Zero(); } else { double num = (thing->Pos().XY() - line->v1->fPos()) | line->Delta(); if (num <= 0) { pos = 0; } else if (num >= den) { pos = 1; } else { pos = num / den; } npos = thing->Pos().XY() - line->v1->fPos() - line->Delta() * pos; } // Get the angle between the two linedefs, for rotating // orientation and velocity. Rotate 180 degrees, and flip // the position across the exit linedef, if reversed. DAngle angle = l->Delta().Angle() - line->Delta().Angle(); if (!reverse) { angle += 180.; pos = 1 - pos; } // Sine, cosine of angle adjustment double s = angle.Sin(); double c = angle.Cos(); DVector2 p; // Rotate position along normal to match exit linedef p.X = npos.X*c - npos.Y*s; p.Y = npos.Y*c + npos.X*s; // Interpolate position across the exit linedef p += l->v1->fPos() + pos*l->Delta(); // Whether this is a player, and if so, a pointer to its player_t. // Voodoo dolls are excluded by making sure thing->player->mo==thing. player_t *player = thing->player && thing->player->mo == thing ? thing->player : NULL; // Whether walking towards first side of exit linedef steps down bool stepdown = l->frontsector->floorplane.ZatPoint(p) < l->backsector->floorplane.ZatPoint(p); // Height of thing above ground double z = thing->Z() - thing->floorz; // Side to exit the linedef on positionally. // // Notes: // // This flag concerns exit position, not momentum. Due to // roundoff error, the thing can land on either the left or // the right side of the exit linedef, and steps must be // taken to make sure it does not end up on the wrong side. // // Exit momentum is always towards side 1 in a reversed // teleporter, and always towards side 0 otherwise. // // Exiting positionally on side 1 is always safe, as far // as avoiding oscillations and stuck-in-wall problems, // but may not be optimum for non-reversed teleporters. // // Exiting on side 0 can cause oscillations if momentum // is towards side 1, as it is with reversed teleporters. // // Exiting on side 1 slightly improves player viewing // when going down a step on a non-reversed teleporter. // Is this really still necessary with real math instead of imprecise trig tables? #if 1 int side = reverse || (player && stepdown); int fudge = FUDGEFACTOR; double dx = line->Delta().X; double dy = line->Delta().Y; // Make sure we are on correct side of exit linedef. while (P_PointOnLineSidePrecise(p, l) != side && --fudge >= 0) { if (fabs(dx) > fabs(dy)) p.Y -= (dx < 0) != side ? -1 : 1; else p.X += (dy < 0) != side ? -1 : 1; } #endif // Adjust z position to be same height above ground as before. // Ground level at the exit is measured as the higher of the // two floor heights at the exit linedef. z = z + l->sidedef[stepdown]->sector->floorplane.ZatPoint(p); // Attempt to teleport, aborting if blocked if (!P_TeleportMove (thing, DVector3(p, z), false)) { return false; } if (thing == players[consoleplayer].camera) { R_ResetViewInterpolation (); } // Rotate thing's orientation according to difference in linedef angles thing->Angles.Yaw += angle; // Rotate thing's velocity to come out of exit just like it entered p = thing->Vel.XY(); thing->Vel.X = p.X*c - p.Y*s; thing->Vel.Y = p.Y*c + p.X*s; // Adjust a player's view, in case there has been a height change if (player && player->mo == thing) { // Adjust player's local copy of velocity p = player->Vel; player->Vel.X = p.X*c - p.Y*s; player->Vel.Y = p.Y*c + p.X*s; // Save the current deltaviewheight, used in stepping double deltaviewheight = player->deltaviewheight; // Clear deltaviewheight, since we don't want any changes now player->deltaviewheight = 0; // Set player's view according to the newly set parameters P_CalcHeight(player); // Reset the delta to have the same dynamics as before player->deltaviewheight = deltaviewheight; } return true; } } return false; }
void Stereo3D::render(FGLRenderer& renderer, GL_IRECT * bounds, float fov0, float ratio0, float fovratio0, bool toscreen, sector_t * viewsector, player_t * player) { if (doBufferHud) LocalHudRenderer::unbind(); // Reset pitch and roll when leaving Rift mode if ( (mode == OCULUS_RIFT) && ((int)mode != vr_mode) ) { renderer.mAngles.Roll = 0; renderer.mAngles.Pitch = 0; } setMode(vr_mode); // Restore actual screen, instead of offscreen single-eye buffer, // in case we just exited Rift mode. adaptScreenSize = false; GLboolean supportsStereo = false; GLboolean supportsBuffered = false; // Task: manually calibrate oculusFov by slowly yawing view. // If subjects approach center of view too fast, oculusFov is too small. // If subjects approach center of view too slowly, oculusFov is too large. // If subjects approach correctly , oculusFov is just right. // 90 is too large, 80 is too small. // float oculusFov = 85 * fovratio; // Hard code probably wider fov for oculus // use vr_rift_fov if (mode == OCULUS_RIFT) { // if (false) { renderer.mCurrentFoV = vr_rift_fov; // needed for Frustum angle calculation // Adjust player eye height, but only in oculus rift mode... if (player != NULL) { // null check to avoid aliens crash if (savedPlayerViewHeight == 0) { savedPlayerViewHeight = player->mo->ViewHeight; } fixed_t testHeight = savedPlayerViewHeight + FLOAT2FIXED(vr_view_yoffset); if (player->mo->ViewHeight != testHeight) { player->mo->ViewHeight = testHeight; P_CalcHeight(player); } } } else { // Revert player eye height when leaving Rift mode if ( (savedPlayerViewHeight != 0) && (player->mo->ViewHeight != savedPlayerViewHeight) ) { player->mo->ViewHeight = savedPlayerViewHeight; savedPlayerViewHeight = 0; P_CalcHeight(player); } } angle_t a1 = renderer.FrustumAngle(); switch(mode) { case MONO: setViewportFull(renderer, bounds); setMonoView(renderer, fov0, ratio0, fovratio0, player); renderer.RenderOneEye(a1, toscreen, true); renderer.EndDrawScene(viewsector); break; case GREEN_MAGENTA: setViewportFull(renderer, bounds); { // Local scope for color mask // Left eye green LocalScopeGLColorMask colorMask(0,1,0,1); // green setLeftEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, toscreen, false); } // Right eye magenta colorMask.setColorMask(1,0,1,1); // magenta setRightEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } } // close scope to auto-revert glColorMask renderer.EndDrawScene(viewsector); break; case RED_CYAN: setViewportFull(renderer, bounds); { // Local scope for color mask // Left eye red LocalScopeGLColorMask colorMask(1,0,0,1); // red setLeftEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, toscreen, false); } // Right eye cyan colorMask.setColorMask(0,1,1,1); // cyan setRightEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } } // close scope to auto-revert glColorMask renderer.EndDrawScene(viewsector); break; case SIDE_BY_SIDE: { // FIRST PASS - 3D // Temporarily modify global variables, so HUD could draw correctly // each view is half width int oldViewwidth = viewwidth; viewwidth = viewwidth/2; // left setViewportLeft(renderer, bounds); setLeftEyeView(renderer, fov0, ratio0/2, fovratio0, player); // TODO is that fovratio? { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, false, false); // False, to not swap yet } // right // right view is offset to right int oldViewwindowx = viewwindowx; viewwindowx += viewwidth; setViewportRight(renderer, bounds); setRightEyeView(renderer, fov0, ratio0/2, fovratio0, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } // // SECOND PASS weapon sprite renderer.EndDrawScene(viewsector); // right view viewwindowx -= viewwidth; renderer.EndDrawScene(viewsector); // left view // // restore global state viewwidth = oldViewwidth; viewwindowx = oldViewwindowx; break; } case SIDE_BY_SIDE_SQUISHED: { // FIRST PASS - 3D // Temporarily modify global variables, so HUD could draw correctly // each view is half width int oldViewwidth = viewwidth; viewwidth = viewwidth/2; // left setViewportLeft(renderer, bounds); setLeftEyeView(renderer, fov0, ratio0, fovratio0*2, player); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, toscreen, false); } // right // right view is offset to right int oldViewwindowx = viewwindowx; viewwindowx += viewwidth; setViewportRight(renderer, bounds); setRightEyeView(renderer, fov0, ratio0, fovratio0*2, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, false, true); } // // SECOND PASS weapon sprite renderer.EndDrawScene(viewsector); // right view viewwindowx -= viewwidth; renderer.EndDrawScene(viewsector); // left view // // restore global state viewwidth = oldViewwidth; viewwindowx = oldViewwindowx; break; } case OCULUS_RIFT: { if ( (oculusTexture == NULL) || (! oculusTexture->checkSize(SCREENWIDTH, SCREENHEIGHT)) ) { if (oculusTexture) delete(oculusTexture); oculusTexture = new OculusTexture(SCREENWIDTH, SCREENHEIGHT); } if ( (hudTexture == NULL) || (! hudTexture->checkSize(SCREENWIDTH/2, SCREENHEIGHT)) ) { if (hudTexture) delete(hudTexture); hudTexture = new HudTexture(SCREENWIDTH/2, SCREENHEIGHT); hudTexture->bindToFrameBuffer(); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); hudTexture->unbind(); } // Render unwarped image to offscreen frame buffer if (doBufferOculus) { oculusTexture->bindToFrameBuffer(); } // FIRST PASS - 3D // Temporarily modify global variables, so HUD could draw correctly // each view is half width int oldViewwidth = viewwidth; viewwidth = viewwidth/2; int oldScreenBlocks = screenblocks; screenblocks = 12; // full screen // // TODO correct geometry for oculus // float ratio = vr_rift_aspect; float fovy = 2.0*atan(tan(0.5*vr_rift_fov*3.14159/180.0)/ratio) * 180.0/3.14159; float fovratio = vr_rift_fov/fovy; // // left GL_IRECT riftBounds; // Always use full screen with Oculus Rift riftBounds.width = SCREENWIDTH; riftBounds.height = SCREENHEIGHT; riftBounds.left = 0; riftBounds.top = 0; setViewportLeft(renderer, &riftBounds); setLeftEyeView(renderer, vr_rift_fov, ratio, fovratio, player, false); glEnable(GL_DEPTH_TEST); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, false, false); } // right // right view is offset to right int oldViewwindowx = viewwindowx; viewwindowx += viewwidth; setViewportRight(renderer, &riftBounds); setRightEyeView(renderer, vr_rift_fov, ratio, fovratio, player, false); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, false, true); } // Second pass sprites (especially weapon) int oldViewwindowy = viewwindowy; const bool showSprites = true; if (showSprites) { // SECOND PASS weapon sprite glEnable(GL_TEXTURE_2D); screenblocks = 12; float fullWidth = SCREENWIDTH / 2.0; viewwidth = RIFT_HUDSCALE * fullWidth; float left = (1.0 - RIFT_HUDSCALE) * fullWidth * 0.5; // left edge of scaled viewport // TODO Sprite needs some offset to appear at correct distance, rather than at infinity. int spriteOffsetX = (int)(0.021*fullWidth); // kludge to set weapon distance viewwindowx = left + fullWidth - spriteOffsetX; int spriteOffsetY = (int)(-0.01 * vr_weapon_height * viewheight); // nudge gun up/down // Counteract effect of status bar on weapon position if (oldScreenBlocks <= 10) { // lower weapon in status mode spriteOffsetY += 0.227 * viewwidth; // empirical - lines up brutal doom down sight in 1920x1080 Rift mode } viewwindowy += spriteOffsetY; renderer.EndDrawScene(viewsector); // right view setViewportLeft(renderer, &riftBounds); viewwindowx = left + spriteOffsetX; renderer.EndDrawScene(viewsector); // left view } // Third pass HUD if (doBufferHud) { screenblocks = max(oldScreenBlocks, 10); // Don't vignette main 3D view // Draw HUD again, to avoid flashing? - and render to screen blitHudTextureToScreen(true); // HUD pass now occurs in main doom loop! Since I delegated screen->Update to stereo3d.updateScreen(). } // // restore global state viewwidth = oldViewwidth; viewwindowx = oldViewwindowx; viewwindowy = oldViewwindowy; // Update orientation for NEXT frame, after expensive render has occurred this frame setViewDirection(renderer); // Set up 2D rendering to write to our hud renderbuffer if (doBufferHud) { bindHudTexture(true); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); bindHudTexture(false); LocalHudRenderer::bind(); } break; } case LEFT_EYE_VIEW: setViewportFull(renderer, bounds); setLeftEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } renderer.EndDrawScene(viewsector); break; case RIGHT_EYE_VIEW: setViewportFull(renderer, bounds); setRightEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } renderer.EndDrawScene(viewsector); break; case QUAD_BUFFERED: setViewportFull(renderer, bounds); glGetBooleanv(GL_STEREO, &supportsStereo); glGetBooleanv(GL_DOUBLEBUFFER, &supportsBuffered); if (supportsStereo && supportsBuffered && toscreen) { // Right first this time, so more generic GL_BACK_LEFT will remain for other modes glDrawBuffer(GL_BACK_RIGHT); setRightEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_RIGHT, player, renderer); renderer.RenderOneEye(a1, toscreen, false); } // Left glDrawBuffer(GL_BACK_LEFT); setLeftEyeView(renderer, fov0, ratio0, fovratio0, player); { ViewShifter vs(EYE_VIEW_LEFT, player, renderer); renderer.RenderOneEye(a1, toscreen, true); } // Want HUD in both views glDrawBuffer(GL_BACK); } else { // mono view, in case hardware stereo is not supported setMonoView(renderer, fov0, ratio0, fovratio0, player); renderer.RenderOneEye(a1, toscreen, true); } renderer.EndDrawScene(viewsector); break; default: setViewportFull(renderer, bounds); setMonoView(renderer, fov0, ratio0, fovratio0, player); renderer.RenderOneEye(a1, toscreen, true); renderer.EndDrawScene(viewsector); break; } }