/* ================== V_CalcRefdef ================== */ void V_CalcNormalRefdef(struct ref_params_s *pparams) { cl_entity_t * ent, *view; int i; vec3_t angles; float bob, waterOffset; static viewinterp_t ViewInterp; static float oldz = 0; static float lasttime; static float lastang[3]; vec3_t angdelta; vec3_t camAngles, camForward, camRight, camUp; cl_entity_t *pwater; // don't allow cheats in multiplayer if(pparams->maxclients > 1) { scr_ofsx->value = 0.0; scr_ofsy->value = 0.0; scr_ofsz->value = 0.0; } V_DriftPitch(pparams); // ent is the player model ( visible when out of body ) ent = gEngfuncs.GetLocalPlayer(); // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); // transform the view offset by the model's matrix to get the offset from // model origin for the view bob = V_CalcBob(pparams); // Observer angle capturing and smoothing if(iHasNewViewOrigin) { // Get the angles from the physics code VectorCopy(vecNewViewOrigin, pparams->vieworg); VectorCopy(vecNewViewOrigin, pparams->simorg); } // refresh position VectorCopy(pparams->simorg, pparams->vieworg); pparams->vieworg[2] += (bob); VectorAdd(pparams->vieworg, pparams->viewheight, pparams->vieworg); // Observer angle capturing and smoothing if(iHasNewViewAngles) { // Get the angles from the physics code VectorCopy(vecNewViewAngles, pparams->cl_viewangles); } else if(pparams->health == -5) { CAM_ToThirdPerson(); // Lock mouse movement iMouseInUse = 1; pparams->cl_viewangles[0] = 89; // Spin the view float flTimeDelta = (pparams->time - g_flStartScaleTime); if(flTimeDelta > 0) { float flROFSpin = 1.0 + (flTimeDelta * 2.0); float flSpin = flTimeDelta * 45; pparams->cl_viewangles[1] = flSpin * flROFSpin; } } else { CAM_ToFirstPerson(); // Unlock mouse movement iMouseInUse = 0; } VectorSubtract(pparams->cl_viewangles, lastang, angdelta); if(Length(angdelta) != 0.0) { VectorCopy(pparams->cl_viewangles, ViewInterp.Angles[ViewInterp.CurrentAngle & ORIGIN_MASK]); ViewInterp.AngleTime[ViewInterp.CurrentAngle & ORIGIN_MASK] = pparams->time; ViewInterp.CurrentAngle++; VectorCopy(pparams->cl_viewangles, lastang); } if(cl_vsmoothing && cl_vsmoothing->value && (iIsSpectator & SPEC_SMOOTH_ANGLES)) { int foundidx; int i; float t; if(cl_vsmoothing->value < 0.0) { gEngfuncs.Cvar_SetValue("cl_vsmoothing", 0.0); } t = pparams->time - cl_vsmoothing->value; for(i = 1; i < ORIGIN_MASK; i++) { foundidx = ViewInterp.CurrentAngle - 1 - i; if(ViewInterp.AngleTime[foundidx & ORIGIN_MASK] <= t) break; } if(i < ORIGIN_MASK && ViewInterp.AngleTime[foundidx & ORIGIN_MASK] != 0.0) { // Interpolate double dt; dt = ViewInterp.AngleTime[(foundidx + 1) & ORIGIN_MASK] - ViewInterp.AngleTime[foundidx & ORIGIN_MASK]; if(dt > 0.0) { double frac; frac = (t - ViewInterp.AngleTime[foundidx & ORIGIN_MASK]) / dt; frac = min(1.0, frac); // interpolate angles V_InterpolateAngles(ViewInterp.Angles[foundidx & ORIGIN_MASK], ViewInterp.Angles[(foundidx + 1) & ORIGIN_MASK], pparams->cl_viewangles, frac); VectorCopy(pparams->cl_viewangles, vecNewViewAngles); } } } VectorCopy(pparams->cl_viewangles, pparams->viewangles); gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake(pparams->vieworg, pparams->viewangles, 1.0); // never let view origin sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // FIXME, we send origin at 1/128 now, change this? // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis pparams->vieworg[0] += 1.0 / 32; pparams->vieworg[1] += 1.0 / 32; pparams->vieworg[2] += 1.0 / 32; // Check for problems around water, move the viewer artificially if necessary // -- this prevents drawing errors in GL due to waves waterOffset = 0; if(pparams->waterlevel >= 2) { int i, contents, waterDist, waterEntity; vec3_t point; waterDist = cl_waterdist->value; if(pparams->hardware) { waterEntity = gEngfuncs.PM_WaterEntity(pparams->simorg); if(waterEntity >= 0 && waterEntity < pparams->max_entities) { pwater = gEngfuncs.GetEntityByIndex(waterEntity); if(pwater && (pwater->model != NULL)) { waterDist += (pwater->curstate.scale * 16); // Add in wave height } } } else { waterEntity = 0; // Don't need this in software } VectorCopy(pparams->vieworg, point); // Eyes are above water, make sure we're above the waves if(pparams->waterlevel == 2) { point[2] -= waterDist; for(i = 0; i < waterDist; i++) { contents = gEngfuncs.PM_PointContents(point, NULL); if(contents > CONTENTS_WATER) break; point[2] += 1; } waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; } else { // eyes are under water. Make sure we're far enough under point[2] += waterDist; for(i = 0; i < waterDist; i++) { contents = gEngfuncs.PM_PointContents(point, NULL); if(contents <= CONTENTS_WATER) break; point[2] -= 1; } waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; } } pparams->vieworg[2] += waterOffset; V_CalcViewRoll(pparams); V_AddIdle(pparams); // offsets VectorCopy(pparams->cl_viewangles, angles); AngleVectors(angles, pparams->forward, pparams->right, pparams->up); for(i = 0; i < 3; i++) { pparams->vieworg[i] += scr_ofsx->value * pparams->forward[i] + scr_ofsy->value * pparams->right[i] + scr_ofsz->value * pparams->up[i]; } // Treating cam_ofs[2] as the distance if(CL_IsThirdPerson()) { vec3_t ofs; ofs[0] = ofs[1] = ofs[2] = 0.0; CL_CameraOffset((float *)&ofs); VectorCopy(ofs, camAngles); camAngles[ROLL] = 0; AngleVectors(camAngles, camForward, camRight, camUp); // Is the player in a falling anim? If so, raise camera above and look down if(pparams->health == -5) { pparams->vieworg[2] += 92; } else { for(i = 0; i < 3; i++) { pparams->vieworg[i] += -ofs[2] * camForward[i]; } pparams->vieworg[2] += 20; } } // Give gun our viewangles VectorCopy(pparams->cl_viewangles, view->angles); // set up gun position V_CalcGunAngle(pparams); // Use predicted origin as view origin. VectorCopy(pparams->simorg, view->origin); view->origin[2] += (waterOffset); VectorAdd(view->origin, pparams->viewheight, view->origin); // Let the viewmodel shake at about 10% of the amplitude gEngfuncs.V_ApplyShake(view->origin, view->angles, 0.9); for(i = 0; i < 3; i++) { view->origin[i] += bob * 0.4 * pparams->forward[i]; } view->origin[2] += bob; // throw in a little tilt. view->angles[YAW] -= bob * 0.5; view->angles[ROLL] -= bob * 1; view->angles[PITCH] -= bob * 0.3; // pushing the view origin down off of the same X/Z plane as the ent's origin will give the // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem // with view model distortion, this may be a cause. (SJB). view->origin[2] -= 1; // fudge position around to keep amount of weapon visible // roughly equal with different FOV if(pparams->viewsize == 110) { view->origin[2] += 1; } else if(pparams->viewsize == 100) { view->origin[2] += 2; } else if(pparams->viewsize == 90) { view->origin[2] += 1; } else if(pparams->viewsize == 80) { view->origin[2] += 0.5; } // Add in the punchangle, if any VectorAdd(pparams->viewangles, pparams->punchangle, pparams->viewangles); // Include client side punch, too VectorAdd(pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); V_DropPunchAngle(pparams->frametime, (float *)&ev_punchangle); // smooth out stair step ups #if 1 if(!pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) { float steptime; steptime = pparams->time - lasttime; if(steptime < 0) //FIXME I_Error ("steptime < 0"); steptime = 0; oldz += steptime * 150; if(oldz > pparams->simorg[2]) oldz = pparams->simorg[2]; if(pparams->simorg[2] - oldz > 18) oldz = pparams->simorg[2] - 18; pparams->vieworg[2] += oldz - pparams->simorg[2]; view->origin[2] += oldz - pparams->simorg[2]; } else { oldz = pparams->simorg[2]; } #endif { static float lastorg[3]; vec3_t delta; VectorSubtract(pparams->simorg, lastorg, delta); if(Length(delta) != 0.0) { VectorCopy(pparams->simorg, ViewInterp.Origins[ViewInterp.CurrentOrigin & ORIGIN_MASK]); ViewInterp.OriginTime[ViewInterp.CurrentOrigin & ORIGIN_MASK] = pparams->time; ViewInterp.CurrentOrigin++; VectorCopy(pparams->simorg, lastorg); } } // Smooth out whole view in multiplayer when on trains, lifts if(cl_vsmoothing && cl_vsmoothing->value && ((iIsSpectator & SPEC_SMOOTH_ORIGIN) || (pparams->smoothing && (pparams->maxclients > 1)))) { int foundidx; int i; float t; if(cl_vsmoothing->value < 0.0) { gEngfuncs.Cvar_SetValue("cl_vsmoothing", 0.0); } t = pparams->time - cl_vsmoothing->value; for(i = 1; i < ORIGIN_MASK; i++) { foundidx = ViewInterp.CurrentOrigin - 1 - i; if(ViewInterp.OriginTime[foundidx & ORIGIN_MASK] <= t) break; } if(i < ORIGIN_MASK && ViewInterp.OriginTime[foundidx & ORIGIN_MASK] != 0.0) { // Interpolate vec3_t delta; double frac; double dt; vec3_t neworg; dt = ViewInterp.OriginTime[(foundidx + 1) & ORIGIN_MASK] - ViewInterp.OriginTime[foundidx & ORIGIN_MASK]; if(dt > 0.0) { frac = (t - ViewInterp.OriginTime[foundidx & ORIGIN_MASK]) / dt; frac = min(1.0, frac); VectorSubtract(ViewInterp.Origins[(foundidx + 1) & ORIGIN_MASK], ViewInterp.Origins[foundidx & ORIGIN_MASK], delta); VectorMA(ViewInterp.Origins[foundidx & ORIGIN_MASK], frac, delta, neworg); // Dont interpolate large changes if(Length(delta) < 64) { VectorSubtract(neworg, pparams->simorg, delta); VectorAdd(pparams->simorg, delta, pparams->simorg); VectorAdd(pparams->vieworg, delta, pparams->vieworg); VectorAdd(view->origin, delta, view->origin); VectorCopy(pparams->simorg, vecNewViewOrigin); } } } } // Store off v_angles before munging for third person v_angles = pparams->viewangles; if(CL_IsThirdPerson()) { VectorCopy(camAngles, pparams->viewangles); } // override all previous settings if the viewent isn't the client if(pparams->viewentity > pparams->maxclients) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex(pparams->viewentity); if(viewentity) { VectorCopy(viewentity->origin, pparams->vieworg); VectorCopy(viewentity->angles, pparams->viewangles); // Store off overridden viewangles v_angles = pparams->viewangles; } } lasttime = pparams->time; v_origin = pparams->vieworg; }
void V_CalcNormalRefdef ( struct ref_params_s *pparams ) { cl_entity_t *ent, *view; int i; vec3_t angles; float bob, waterOffset; static viewinterp_t ViewInterp; static float oldz = 0; static float lasttime; vec3_t camAngles, camForward, camRight, camUp; cl_entity_t *pwater; static struct model_s *savedviewmodel; //LRC - if this is the second pass through, then we've just drawn the sky, and now we're setting up the normal view. if (pparams->nextView == 1) { gHUD.m_iSkyMode = SKY_ON; //This means that an env_sky is in the level but we are drawing the normal view this time. view = gEngfuncs.GetViewModel(); view->model = savedviewmodel; pparams->viewangles[0] = v_angles.x; pparams->viewangles[1] = v_angles.y; pparams->viewangles[2] = v_angles.z; pparams->vieworg[0] = v_origin.x; pparams->vieworg[1] = v_origin.y; pparams->vieworg[2] = v_origin.z; pparams->nextView = 0; if (gHUD.viewFlags & 1 ) // custom view active (trigger_viewset) //AJH (copied function from below) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( gHUD.viewEntityIndex ); if (viewentity) { pparams->vieworg[0] = viewentity->origin[0]; pparams->vieworg[1] = viewentity->origin[1]; pparams->vieworg[2] = viewentity->origin[2]; pparams->vieworg[2] = viewentity->origin[2]; pparams->viewangles[0] = viewentity->angles[0]; pparams->viewangles[1] = viewentity->angles[1]; pparams->viewangles[2] = viewentity->angles[2]; pparams->crosshairangle[PITCH] = 100; // test // ugly method to remove crosshair from screen if(gHUD.viewFlags & 8 ) //AJH Do we draw the player in the camera? { gHUD.m_iCameraMode=2; } if(gHUD.viewFlags & 4 ) //AJH Invert the x view angle again if we are using an item camera? { pparams->viewangles[0] = -viewentity->angles[0]; } } else { gEngfuncs.Con_DPrintf( "Warning : invalid view ent index: %i\n", gHUD.viewEntityIndex ); } } else { pparams->crosshairangle[PITCH] = 0; // test } return; } V_DriftPitch ( pparams ); if ( gEngfuncs.IsSpectateOnly() ) { ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); } else { // ent is the player model ( visible when out of body ) ent = gEngfuncs.GetLocalPlayer(); } // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); // trigger_viewset - dont show weapon model when custom view is enabled if (gHUD.viewFlags & 1) view->model = NULL; //LRC - don't show weapon models when we're drawing the sky. if (gHUD.m_iSkyMode == SKY_ON) { savedviewmodel = view->model; view->model = NULL; } // transform the view offset by the model's matrix to get the offset from // model origin for the view bob = V_CalcBob ( pparams ); // refresh position VectorCopy ( pparams->simorg, pparams->vieworg ); pparams->vieworg[2] += ( bob ); VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); // never let view origin sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // FIXME, we send origin at 1/128 now, change this? // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis pparams->vieworg[0] += 1.0/32; pparams->vieworg[1] += 1.0/32; pparams->vieworg[2] += 1.0/32; // Check for problems around water, move the viewer artificially if necessary // -- this prevents drawing errors in GL due to waves waterOffset = 0; if ( pparams->waterlevel >= 2 ) { int i, contents, waterDist, waterEntity; vec3_t point; waterDist = cl_waterdist->value; if ( pparams->hardware ) { waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) { pwater = gEngfuncs.GetEntityByIndex( waterEntity ); if ( pwater && ( pwater->model != NULL ) ) { waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height } } } else { waterEntity = 0; // Don't need this in software } VectorCopy( pparams->vieworg, point ); // Eyes are above water, make sure we're above the waves if ( pparams->waterlevel == 2 ) { point[2] -= waterDist; for ( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); if ( contents > CONTENTS_WATER ) break; point[2] += 1; } waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; } else { // eyes are under water. Make sure we're far enough under point[2] += waterDist; for ( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); if ( contents <= CONTENTS_WATER ) break; point[2] -= 1; } waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; } } pparams->vieworg[2] += waterOffset; V_CalcViewRoll ( pparams ); V_AddIdle ( pparams ); // offsets VectorCopy( pparams->cl_viewangles, angles ); AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); // don't allow cheats in multiplayer if ( pparams->maxclients <= 1 ) { for ( i=0 ; i<3 ; i++ ) { pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; } } // Give gun our viewangles VectorCopy ( pparams->cl_viewangles, view->angles ); // set up gun position V_CalcGunAngle ( pparams ); // Use predicted origin as view origin. VectorCopy ( pparams->simorg, view->origin ); view->origin[2] += ( waterOffset ); VectorAdd( view->origin, pparams->viewheight, view->origin ); // Let the viewmodel shake at about 10% of the amplitude gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); for ( i = 0; i < 3; i++ ) { view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; } view->origin[2] += bob; // throw in a little tilt. view->angles[YAW] -= bob * 0.5; view->angles[ROLL] -= bob * 1; view->angles[PITCH] -= bob * 0.3; // pushing the view origin down off of the same X/Z plane as the ent's origin will give the // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem // with view model distortion, this may be a cause. (SJB). view->origin[2] -= 1; // fudge position around to keep amount of weapon visible // roughly equal with different FOV if (pparams->viewsize == 110) { view->origin[2] += 1; } else if (pparams->viewsize == 100) { view->origin[2] += 2; } else if (pparams->viewsize == 90) { view->origin[2] += 1; } else if (pparams->viewsize == 80) { view->origin[2] += 0.5; } // Add in the punchangle, if any VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); // Include client side punch, too VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); // smooth out stair step ups #if 1 if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) { float steptime; steptime = pparams->time - lasttime; if (steptime < 0) //FIXME I_Error ("steptime < 0"); steptime = 0; oldz += steptime * 150; if (oldz > pparams->simorg[2]) oldz = pparams->simorg[2]; if (pparams->simorg[2] - oldz > 18) oldz = pparams->simorg[2]- 18; pparams->vieworg[2] += oldz - pparams->simorg[2]; view->origin[2] += oldz - pparams->simorg[2]; } else { oldz = pparams->simorg[2]; } #endif { static float lastorg[3]; vec3_t delta; VectorSubtract( pparams->simorg, lastorg, delta ); if ( Length( delta ) != 0.0 ) { VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentOrigin++; VectorCopy( pparams->simorg, lastorg ); } } // Smooth out whole view in multiplayer when on trains, lifts if ( cl_vsmoothing && cl_vsmoothing->value && ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) { int foundidx; int i; float t; if ( cl_vsmoothing->value < 0.0 ) { gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); } t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentOrigin - 1 - i; if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate vec3_t delta; double frac; double dt; vec3_t neworg; dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 ) { frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); // Dont interpolate large changes if ( Length( delta ) < 64 ) { VectorSubtract( neworg, pparams->simorg, delta ); VectorAdd( pparams->simorg, delta, pparams->simorg ); VectorAdd( pparams->vieworg, delta, pparams->vieworg ); VectorAdd( view->origin, delta, view->origin ); } } } } // Store off v_angles before munging for third person v_angles = pparams->viewangles; v_lastAngles = pparams->viewangles; // v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! // override all previous settings if the viewent isn't the client if ( pparams->viewentity > pparams->maxclients ) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); if ( viewentity ) { VectorCopy( viewentity->origin, pparams->vieworg ); VectorCopy( viewentity->angles, pparams->viewangles ); // Store off overridden viewangles v_angles = pparams->viewangles; } } lasttime = pparams->time; v_origin = pparams->vieworg; //LRC 1.8 - clear to the fog color (if any) on the first pass if ( pparams->nextView == 0 ) { ClearToFogColor(); } //LRC 1.8 - no fog in the env_sky if ( gHUD.m_iSkyMode != SKY_ON_DRAWING ) { RenderFog(); } if (gHUD.viewFlags & 1 && gHUD.m_iSkyMode == SKY_OFF) // custom view active (trigger_viewset) //AJH (added skymode check and copied function to above) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( gHUD.viewEntityIndex ); if (viewentity) { pparams->vieworg[0] = viewentity->origin[0]; pparams->vieworg[1] = viewentity->origin[1]; pparams->vieworg[2] = viewentity->origin[2]; pparams->vieworg[2] = viewentity->origin[2]; pparams->viewangles[0] = viewentity->angles[0]; pparams->viewangles[1] = viewentity->angles[1]; pparams->viewangles[2] = viewentity->angles[2]; pparams->crosshairangle[PITCH] = 100; // test // ugly method to remove crosshair from screen if(gHUD.viewFlags & 8 ) //AJH Do we draw the player in the camera? { gHUD.m_iCameraMode=2; } if(gHUD.viewFlags & 4 ) //AJH Invert the x view angle again if we are using an item camera? { pparams->viewangles[0] = -viewentity->angles[0]; } } else gEngfuncs.Con_Printf( "Warning : invalid view ent index: %i\n", gHUD.viewEntityIndex ); } else pparams->crosshairangle[PITCH] = 0; // test // LRC - override the view position if we're drawing a sky, rather than the player's view if (gHUD.m_iSkyMode >= SKY_ON && pparams->nextView == 0) { gHUD.m_iSkyMode = SKY_ON_DRAWING; if (gHUD.m_iSkyScale == 0) //AJH No parallax (old behaviour) { pparams->vieworg[0] = gHUD.m_vecSkyPos.x; pparams->vieworg[1] = gHUD.m_vecSkyPos.y; pparams->vieworg[2] = gHUD.m_vecSkyPos.z; } else { VectorCopy(gHUD.m_vecSkyPos + v_origin/gHUD.m_iSkyScale,pparams->vieworg); } if (gHUD.viewFlags & 1)//AJH (to allow skys and cameras to coexist) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( gHUD.viewEntityIndex ); if (viewentity) { pparams->viewangles[0] = viewentity->angles[0]; pparams->viewangles[1] = viewentity->angles[1]; pparams->viewangles[2] = viewentity->angles[2]; } else gEngfuncs.Con_Printf( "Warning : invalid view ent index: %i\n", gHUD.viewEntityIndex ); } pparams->nextView = 1; } }
//========================== // V_CalcFirstPersonRefdef //========================== void V_CalcFirstPersonRefdef( struct ref_params_s *pparams ) { V_DriftPitch( pparams ); float bob = V_CalcBob( pparams ); pparams->vieworg = pparams->simorg; pparams->vieworg += pparams->viewheight; pparams->vieworg.z += bob; pparams->viewangles = pparams->cl_viewangles; gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0f ); V_CalcSendOrigin( pparams ); float waterOffset = V_CalcWaterLevel( pparams ); pparams->vieworg[2] += waterOffset; V_CalcViewRoll( pparams ); V_AddIdle( pparams ); // offsets AngleVectors( pparams->cl_viewangles, pparams->forward, pparams->right, pparams->up ); cl_entity_t *view = GET_VIEWMODEL(); Vector lastAngles = view->angles = pparams->cl_viewangles; V_CalcGunAngle( pparams ); // use predicted origin as view origin. view->origin = pparams->simorg; view->origin += pparams->viewheight; view->origin.z += waterOffset; // Let the viewmodel shake at about 10% of the amplitude gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9f ); view->origin += pparams->forward * bob * 0.4f; view->origin.z += bob; view->angles[PITCH] -= bob * 0.3f; view->angles[YAW] -= bob * 0.5f; view->angles[ROLL] -= bob * 1.0f; view->origin.z -= 1; // fudge position around to keep amount of weapon visible // roughly equal with different FOV if( pparams->viewsize == 110 ) { view->origin[2] += 1; } else if( pparams->viewsize == 100 ) { view->origin[2] += 2; } else if( pparams->viewsize == 90 ) { view->origin[2] += 1; } else if( pparams->viewsize == 80 ) { view->origin[2] += 0.5; } V_CalcViewModelLag( pparams, view->origin, view->angles, lastAngles ); pparams->viewangles += pparams->punchangle; pparams->viewangles += ev_punchangle; V_DropPunchAngle(pparams->frametime,ev_punchangle); static float lasttime, oldz = 0; if( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0.0f ) { float steptime; steptime = pparams->time - lasttime; if( steptime < 0 ) steptime = 0; oldz += steptime * 150.0f; if( oldz > pparams->simorg[2] ) oldz = pparams->simorg[2]; if( pparams->simorg[2] - oldz > pparams->movevars->stepsize ) oldz = pparams->simorg[2] - pparams->movevars->stepsize; pparams->vieworg[2] += oldz - pparams->simorg[2]; view->origin.z += oldz - pparams->simorg[2]; } else { oldz = pparams->simorg[2]; } lasttime = pparams->time; // smooth player view in multiplayer V_InterpolatePos( pparams ); }
/* ================== V_CalcRefdef ================== */ void V_CalcNormalRefdef ( ref_params_t *pparams ) { cl_entity_t *ent, *view; int i; Vector angles; float bob, waterOffset; static viewinterp_t ViewInterp; static float oldz = 0; static float lasttime; Vector camAngles, camForward, camRight, camUp; cl_entity_t *pwater; V_DriftPitch ( pparams ); if ( gEngfuncs.IsSpectateOnly() ) { ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); } else { // ent is the player model ( visible when out of body ) ent = gEngfuncs.GetLocalPlayer(); } // view is the weapon model (only visible from inside body ) view = gEngfuncs.GetViewModel(); // transform the view offset by the model's matrix to get the offset from // model origin for the view bob = V_CalcBob ( pparams ); // refresh position pparams->vieworg = pparams->simorg; pparams->vieworg[2] += ( bob ); pparams->vieworg = pparams->vieworg + pparams->viewheight; pparams->viewangles = pparams->cl_viewangles; gEngfuncs.V_CalcShake(); gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); // never let view origin sit exactly on a node line, because a water plane can // dissapear when viewed with the eye exactly on it. // FIXME, we send origin at 1/128 now, change this? // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis pparams->vieworg[0] += 1.0/32; pparams->vieworg[1] += 1.0/32; pparams->vieworg[2] += 1.0/32; // Check for problems around water, move the viewer artificially if necessary // -- this prevents drawing errors in GL due to waves waterOffset = 0; if ( pparams->waterlevel >= WATERLEVEL_WAIST ) { int i, contents, waterDist, waterEntity; Vector point; waterDist = cl_waterdist->value; if ( pparams->hardware ) { waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) { pwater = gEngfuncs.GetEntityByIndex( waterEntity ); if ( pwater && ( pwater->model != NULL ) ) { waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height } } } else { waterEntity = 0; // Don't need this in software } point = pparams->vieworg; // Eyes are above water, make sure we're above the waves if ( pparams->waterlevel == WATERLEVEL_WAIST ) { point[2] -= waterDist; for ( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); if ( contents > CONTENTS_WATER ) break; point[2] += 1; } waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; } else { // eyes are under water. Make sure we're far enough under point[2] += waterDist; for ( i = 0; i < waterDist; i++ ) { contents = gEngfuncs.PM_PointContents( point, NULL ); if ( contents <= CONTENTS_WATER ) break; point[2] -= 1; } waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; } } pparams->vieworg[2] += waterOffset; V_CalcViewRoll ( pparams ); V_AddIdle ( pparams ); // offsets angles = pparams->cl_viewangles; AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); // don't allow cheats in multiplayer if ( pparams->maxclients <= 1 ) { for ( i=0 ; i<3 ; i++ ) { pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; } } // Treating cam_ofs[2] as the distance if( CL_IsThirdPerson() ) { Vector ofs; ofs[0] = ofs[1] = ofs[2] = 0.0; CL_CameraOffset( ofs ); camAngles = ofs; camAngles[ ROLL ] = 0; AngleVectors( camAngles, camForward, camRight, camUp ); for ( i = 0; i < 3; i++ ) { pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; } } // Give gun our viewangles view->angles = pparams->cl_viewangles; // set up gun position V_CalcGunAngle ( pparams ); // Use predicted origin as view origin. view->origin = pparams->simorg; view->origin[2] += ( waterOffset ); view->origin = view->origin + pparams->viewheight; // Let the viewmodel shake at about 10% of the amplitude gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); for ( i = 0; i < 3; i++ ) { view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; } view->origin[2] += bob; // throw in a little tilt. view->angles[YAW] -= bob * 0.5; view->angles[ROLL] -= bob * 1; view->angles[PITCH] -= bob * 0.3; // pushing the view origin down off of the same X/Z plane as the ent's origin will give the // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem // with view model distortion, this may be a cause. (SJB). view->origin[2] -= 1; // fudge position around to keep amount of weapon visible // roughly equal with different FOV if (pparams->viewsize == 110) { view->origin[2] += 1; } else if (pparams->viewsize == 100) { view->origin[2] += 2; } else if (pparams->viewsize == 90) { view->origin[2] += 1; } else if (pparams->viewsize == 80) { view->origin[2] += 0.5; } // Add in the punchangle, if any pparams->viewangles = pparams->viewangles + pparams->punchangle; // Include client side punch, too pparams->viewangles = pparams->viewangles + ev_punchangle; V_DropPunchAngle ( pparams->frametime, ev_punchangle ); // smooth out stair step ups #if 1 if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) { float steptime; steptime = pparams->time - lasttime; if (steptime < 0) //FIXME I_Error ("steptime < 0"); steptime = 0; oldz += steptime * 150; if (oldz > pparams->simorg[2]) oldz = pparams->simorg[2]; if (pparams->simorg[2] - oldz > 18) oldz = pparams->simorg[2]- 18; pparams->vieworg[2] += oldz - pparams->simorg[2]; view->origin[2] += oldz - pparams->simorg[2]; } else { oldz = pparams->simorg[2]; } #endif { static Vector lastorg; const Vector delta = pparams->simorg - lastorg; if ( delta.Length() != 0.0 ) { ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->simorg; ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; ViewInterp.CurrentOrigin++; lastorg = pparams->simorg; } } // Smooth out whole view in multiplayer when on trains, lifts if ( cl_vsmoothing && cl_vsmoothing->value && ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) { int foundidx; int i; float t; if ( cl_vsmoothing->value < 0.0 ) { gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); } t = pparams->time - cl_vsmoothing->value; for ( i = 1; i < ORIGIN_MASK; i++ ) { foundidx = ViewInterp.CurrentOrigin - 1 - i; if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) break; } if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) { // Interpolate Vector delta; double frac; double dt; Vector neworg; dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; if ( dt > 0.0 ) { frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; frac = min( 1.0, frac ); delta = ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ] - ViewInterp.Origins[ foundidx & ORIGIN_MASK ]; VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); // Dont interpolate large changes if ( delta.Length() < 64 ) { delta = neworg - pparams->simorg; pparams->simorg = pparams->simorg + delta; pparams->vieworg = pparams->vieworg + delta; view->origin = view->origin + delta; } } } } // Store off v_angles before munging for third person v_angles = pparams->viewangles; v_client_aimangles = pparams->cl_viewangles; v_lastAngles = pparams->viewangles; // v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! if ( CL_IsThirdPerson() ) { pparams->viewangles = camAngles; float pitch = camAngles[ 0 ]; // Normalize angles if ( pitch > 180 ) pitch -= 360.0; else if ( pitch < -180 ) pitch += 360; // Player pitch is inverted pitch /= -3.0; // Slam local player's pitch value ent->angles[ 0 ] = pitch; ent->curstate.angles[ 0 ] = pitch; ent->prevstate.angles[ 0 ] = pitch; ent->latched.prevangles[ 0 ] = pitch; } // override all previous settings if the viewent isn't the client if ( pparams->viewentity > pparams->maxclients ) { cl_entity_t *viewentity; viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); if ( viewentity ) { pparams->vieworg = viewentity->origin; pparams->viewangles = viewentity->angles; // Store off overridden viewangles v_angles = pparams->viewangles; } } lasttime = pparams->time; v_origin = pparams->vieworg; }