void CGCam_Enable( void ) { if (!cg.refdef.height) { CG_CalcVrect(); } client_camera.bar_alpha = 0.0f; client_camera.bar_time = cg.time; client_camera.bar_alpha_source = 0.0f; client_camera.bar_alpha_dest = 1.0f; client_camera.bar_height_source = 0.0f; client_camera.bar_height_dest = cg.refdef.height/10; client_camera.bar_height = 0.0f; client_camera.info_state |= CAMERA_BAR_FADING; client_camera.FOV = CAMERA_DEFAULT_FOV; client_camera.FOV2 = CAMERA_DEFAULT_FOV; in_camera = true; client_camera.next_roff_time = 0; if ( &g_entities[0] && g_entities[0].client ) { //Player zero not allowed to do anything VectorClear( g_entities[0].client->ps.velocity ); g_entities[0].contents = 0; } }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_s* ps; // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; cg.refdefViewOrigin = ps->origin; cg.refdefViewAngles = ps->viewangles; // add first person / third person view offset if ( cg_thirdPerson.integer ) { // back away from character CG_OffsetThirdPersonView(); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); } cg.refdefViewAxis.fromAngles( cg.refdefViewAngles ); if ( cg_printCurCamPos.getInt() ) { CG_Printf( "CG_CalcViewValues: camera eye is at %f %f %f\n", cg.refdefViewOrigin[0], cg.refdefViewOrigin[1], cg.refdefViewOrigin[2] ); } if ( cg_printCurFarPlane.getInt() ) { CG_Printf( "CG_CalcViewValues: cg.farPlane is %f\n", cg.farPlane ); } projDef_s projDef; projDef.setDefaults(); if ( cg.farPlane >= 8.f ) { projDef.zFar = cg.farPlane; } rf->setupProjection3D( &projDef ); rf->setup3DView( cg.refdefViewOrigin, cg.refdefViewAngles, cg_thirdPerson.integer ); return 0; }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // calculate size of 3D view CG_CalcVrect( ); ps = &cg.predictedPlayerState; // intermission view if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_FREEZE || ps->pm_type == PM_SPECTATOR ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov( ); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] + ps->velocity[ 1 ] * ps->velocity[ 1 ] ); // the bob velocity should't get too fast to avoid jerking if( cg.xyspeed > 300.0f ) cg.xyspeed = 300.0f; VectorCopy( ps->origin, cg.refdef.vieworg ); if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) ) CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles ); else if( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) ) CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles ); else VectorCopy( ps->viewangles, cg.refdefViewAngles ); //clumsy logic, but it needs to be this way round because the CS propogation //delay screws things up otherwise if( !BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) ) { if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f ); } // add error decay if( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if( f > 0 && f < 1 ) VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); else cg.predictedErrorTime = 0; } //shut off the poison cloud effect if it's still on the go if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) ) CG_DestroyParticleSystem( &cg.poisonCloudPS ); } else cg.wasDeadLastFrame = qfalse; if( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView( ); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView( ); } // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if( cg.hyperspace ) cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; //draw the surface normal looking at if( cg_drawSurfNormal.integer ) CG_DrawSurfNormal( ); // field of view return CG_CalcFov( ); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // strings for in game rendering // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) ); // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; /* if (cg.cameraMode) { vec3_t origin, angles; if (trap_getCameraInfo(cg.time, &origin, &angles)) { VectorCopy(origin, cg.refdef.vieworg); angles[ROLL] = 0; VectorCopy(angles, cg.refdefViewAngles); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } else { cg.cameraMode = qfalse; } } */ // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); if (cg_cameraOrbit.integer) { if (cg.time > cg.nextOrbitTime) { cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer; cg_thirdPersonAngle.value += cg_cameraOrbit.value; } } // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } if ( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView(); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); } // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } // field of view return CG_CalcFov(); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; CG_CalcColorGradingForPoint( ps->origin ); CG_AddColorGradingEffects( ps ); CG_AddReverbEffects( ps->origin ); // intermission view if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_FREEZE || ps->pm_type == PM_SPECTATOR ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] + ps->velocity[ 1 ] * ps->velocity[ 1 ] ); // to avoid jerking, the bob velocity shouldn't be too high if ( cg.xyspeed > 300.0f ) { cg.xyspeed = 300.0f; } VectorCopy( ps->origin, cg.refdef.vieworg ); if ( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLCLIMBER ) ) { CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles ); } else if ( BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) ) { CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles ); } else { VectorCopy( ps->viewangles, cg.refdefViewAngles ); } //clumsy logic, but it needs to be this way around because the CS propagation //delay screws things up otherwise if ( !BG_ClassHasAbility( ps->stats[ STAT_CLASS ], SCA_WALLJUMPER ) ) { if ( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) { VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f ); } } // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } //shut off the poison cloud effect if it's still on the go if ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) { cg.wasDeadLastFrame = qfalse; } if ( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView(); } else { float speed; // offset for local bobbing and kicks CG_OffsetFirstPersonView(); // Compute motion blur vector speed = VectorNormalize2( cg.snap->ps.velocity, cg.refdef.blurVec ); speed = (speed - cg_motionblurMinSpeed.value); if( speed < 0.0f ) speed = 0.0f; VectorScale( cg.refdef.blurVec, speed * cg_motionblur.value, cg.refdef.blurVec ); } // position eye relative to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } //draw the surface normal looking at if ( cg_drawSurfNormal.integer ) { CG_DrawSurfNormal(); } // field of view return CG_CalcFov(); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; if ( cg.cameraMode ) { vec3_t origin, angles; float fov = 90; float x; if ( trap_getCameraInfo( CAM_PRIMARY, cg.time, &origin, &angles, &fov ) ) { VectorCopy( origin, cg.refdef.vieworg ); angles[ROLL] = 0; angles[PITCH] = -angles[PITCH]; // (SA) compensate for reversed pitch (this makes the game match the editor, however I'm guessing the real fix is to be done there) VectorCopy( angles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); x = cg.refdef.width / tan( fov / 360 * M_PI ); cg.refdef.fov_y = atan2( cg.refdef.height, x ); cg.refdef.fov_y = cg.refdef.fov_y * 360 / M_PI; cg.refdef.fov_x = fov; trap_SendClientCommand( va( "setCameraOrigin %f %f %f", origin[0], origin[1], origin[2] ) ); return 0; } else { cg.cameraMode = qfalse; // camera off in cgame trap_Cvar_Set( "cg_letterbox", "0" ); trap_SendClientCommand( "stopCamera" ); // camera off in game trap_stopCamera( CAM_PRIMARY ); // camera off in client CG_Fade( 0, 0, 0, 255, 0, 0 ); // go black CG_Fade( 0, 0, 0, 0, cg.time + 200, 1500 ); // then fadeup } } // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } // Ridah, lock the viewangles if the game has told us to if ( ps->viewlocked ) { /* if (ps->viewlocked == 4) { centity_t *tent; tent = &cg_entities[ps->viewlocked_entNum]; VectorCopy (tent->currentState.apos.trBase, cg.refdefViewAngles); } else */ BG_EvaluateTrajectory( &cg_entities[ps->viewlocked_entNum].currentState.apos, cg.time, cg.refdefViewAngles ); if ( ps->viewlocked == 2 ) { cg.refdefViewAngles[0] += crandom(); cg.refdefViewAngles[1] += crandom(); } } // done. if ( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView(); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); // Ridah, lock the viewangles if the game has told us to if ( ps->viewlocked == 4 ) { vec3_t fwd; AngleVectors( cg.refdefViewAngles, fwd, NULL, NULL ); VectorMA( cg_entities[ps->viewlocked_entNum].currentState.pos.trBase, 16, fwd, cg.refdef.vieworg ); } else if ( ps->viewlocked ) { vec3_t fwd; float oldZ; // set our position to be behind it oldZ = cg.refdef.vieworg[2]; AngleVectors( cg.refdefViewAngles, fwd, NULL, NULL ); VectorMA( cg_entities[ps->viewlocked_entNum].currentState.pos.trBase, -34, fwd, cg.refdef.vieworg ); cg.refdef.vieworg[2] = oldZ; } // done. } // position eye relative to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } // field of view return CG_CalcFov(); }
/* ------------------------- CGCam_RenderScene ------------------------- */ void CGCam_RenderScene( void ) { CGCam_Update(); CG_CalcVrect(); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // strings for in game rendering // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) ); // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.bobfraccos = fabs( cos( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.bobfracsin2 = fabs( sin( ( ps->bobCycle & 127) / 127.0 * (M_PI) )); cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); if (cg_cameraOrbit.integer) { if (cg.time > cg.nextOrbitTime) { cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer; cg_thirdPersonAngle.value += cg_cameraOrbit.value; } } // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } if ( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView(); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); } // leilei - View-from-the-model-eyes feature, aka "fullbody awareness" lol if (cg_cameraEyes.integer && !cg.renderingThirdPerson){ vec3_t forward, right, up; cg.refdefViewAngles[ROLL] = headang[ROLL]; cg.refdefViewAngles[PITCH] = headang[PITCH]; cg.refdefViewAngles[YAW] = headang[YAW]; AngleVectors( headang, forward, NULL, up ); if (cg_cameraEyes.integer == 2){ VectorMA( headpos, 0, forward, headpos ); VectorMA( headpos, 4, up, headpos ); } else { VectorMA( headpos, cg_cameraEyes_Fwd.value, forward, headpos ); VectorMA( headpos, cg_cameraEyes_Up.value, up, headpos ); } cg.refdef.vieworg[0] = ps->origin[0] + headpos[0]; cg.refdef.vieworg[1] = ps->origin[1] + headpos[1]; cg.refdef.vieworg[2] = ps->origin[2] + headpos[2]; } // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } // field of view return CG_CalcFov(); }
/* ================= CG_DrawActiveFrame Generates and draws a game scene and status information at the given time. ================= */ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) { int inwater; qboolean renderClientViewport[MAX_SPLITVIEW]; int i; cg.time = serverTime; cg.demoPlayback = demoPlayback; // update cvars CG_UpdateCvars(); // if we are only updating the screen as a loading // pacifier, don't even try to read snapshots if ( cg.infoScreenText[0] != 0 ) { CG_DrawInformation(); return; } // any looped sounds will be respecified as entities // are added to the render list trap_S_ClearLoopingSounds(qfalse); // clear all the render lists trap_R_ClearScene(); // set up cg.snap and possibly cg.nextSnap CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { CG_DrawInformation(); return; } // this counter will be bumped for every valid scene we generate cg.clientFrame++; // Use single camera/viewport at intermission for (i = 0; i < CG_MaxSplitView(); i++) { if (cg.snap->lcIndex[i] != -1 && cg.snap->pss[i].pm_type != PM_INTERMISSION) { // client present and not at intermission, keep viewports separate. break; } } cg.singleCamera = (cg.snap->numPSs > 1) && (i == CG_MaxSplitView()); cg.numViewports = 0; for (i = 0; i < CG_MaxSplitView(); i++) { if (cg.snap->lcIndex[i] == -1) { renderClientViewport[i] = qfalse; continue; } cg.cur_localClientNum = i; cg.cur_lc = &cg.localClients[i]; cg.cur_ps = &cg.snap->pss[cg.snap->lcIndex[i]]; // Check if viewport should be drawn. if ( cg.singleCamera && cg.numViewports >= 1 ) { renderClientViewport[i] = qfalse; } else { cg.numViewports++; renderClientViewport[i] = qtrue; } // let the client system know what our weapon and zoom settings are trap_SetUserCmdValue( cg.cur_lc->weaponSelect, cg.cur_lc->zoomSensitivity, cg.cur_localClientNum ); // update cg.predictedPlayerState CG_PredictPlayerState(); // Remove expired console lines if( cg.cur_lc->consoleLines[ 0 ].time + cg_consoleLatency.integer < cg.time && cg_consoleLatency.integer > 0 ) { CG_RemoveNotifyLine( cg.cur_lc ); } } // If all local clients dropped out from playing still draw main local client. if (cg.numViewports == 0) { cg.numViewports = 1; renderClientViewport[0] = qtrue; } // play lead change annoucement and time/frag limit warnings CG_CheckGameSounds(); // add buffered sounds CG_PlayBufferedSounds(); #ifdef MISSIONPACK // play buffered voice chats CG_PlayBufferedVoiceChats(); #endif for (i = 0, cg.viewport = -1; i < CG_MaxSplitView(); i++) { if (!renderClientViewport[i]) { continue; } cg.viewport++; cg.cur_localClientNum = i; cg.cur_lc = &cg.localClients[i]; cg.cur_ps = &cg.snap->pss[cg.snap->lcIndex[i]]; // decide on third person view cg.cur_lc->renderingThirdPerson = cg_thirdPerson[cg.cur_localClientNum].integer || (cg.cur_ps->stats[STAT_HEALTH] <= 0); CG_PB_ClearPolyBuffers(); // build cg.refdef inwater = CG_CalcViewValues(); CG_SetupFrustum(); // first person blend blobs, done after AnglesToAxis if ( !cg.cur_lc->renderingThirdPerson ) { CG_DamageBlendBlob(); } // build the render lists if ( !cg.cur_lc->hyperspace ) { CG_AddPacketEntities(); // adter calcViewValues, so predicted player state is correct CG_AddMarks(); CG_AddParticles (); CG_AddLocalEntities(); CG_AddAtmosphericEffects(); } CG_AddViewWeapon( &cg.cur_lc->predictedPlayerState ); // finish up the rest of the refdef if ( cg.testModelEntity.hModel ) { CG_AddTestModel(); } cg.refdef.time = cg.time; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // warning sounds when powerup is wearing off CG_PowerupTimerSounds(); // update audio positions trap_S_Respatialize( cg.cur_ps->clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater, !cg.cur_lc->renderingThirdPerson ); // make sure the lagometerSample and frame timing isn't done twice when in stereo if ( stereoView != STEREO_RIGHT && cg.viewport == 0 ) { cg.frametime = cg.time - cg.oldTime; if ( cg.frametime < 0 ) { cg.frametime = 0; } cg.oldTime = cg.time; CG_AddLagometerFrameInfo(); } if (cg_timescale.value != cg_timescaleFadeEnd.value) { if (cg_timescale.value < cg_timescaleFadeEnd.value) { cg_timescale.value += cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value > cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } else { cg_timescale.value -= cg_timescaleFadeSpeed.value * ((float)cg.frametime) / 1000; if (cg_timescale.value < cg_timescaleFadeEnd.value) cg_timescale.value = cg_timescaleFadeEnd.value; } if (cg_timescaleFadeSpeed.value) { trap_Cvar_Set("timescale", va("%f", cg_timescale.value)); } } // actually issue the rendering calls CG_DrawActive( stereoView ); } // load any models that have been deferred if a scoreboard is shown if ( !CG_AnyScoreboardShowing() ) { cg.deferredPlayerLoading = 0; } else if ( ++cg.deferredPlayerLoading > 10 ) { CG_LoadDeferredPlayers(); } if (cg.numViewports != 1) { // Setup single viewport cg.numViewports = 1; cg.viewport = 0; // calculate size of viewport CG_CalcVrect(); } // Not drawing single client view. cg.cur_lc = NULL; cg.cur_ps = NULL; cg.cur_localClientNum = -1; // Draw over all viewports CG_DrawScreen2D( stereoView ); if ( cg_stats.integer ) { CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); } }
/* ------------------------- CGCam_RenderScene ------------------------- */ void CGCam_RenderScene( void ) { memset( &cg.refdef, 0, sizeof( cg.refdef ) ); CGCam_Update(); CG_CalcVrect(); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // strings for in game rendering // Q_strncpyz( cg.refdef.text[0], "Park Ranger", sizeof(cg.refdef.text[0]) ); // Q_strncpyz( cg.refdef.text[1], "19", sizeof(cg.refdef.text[1]) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predictedPlayerState; /* if (cg.cameraMode) { vec3_t origin, angles; if (trap_getCameraInfo(cg.time, &origin, &angles)) { VectorCopy(origin, cg.refdef.vieworg); angles[ROLL] = 0; VectorCopy(angles, cg.refdefViewAngles); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } else { cg.cameraMode = qfalse; } } */ // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); //link to view to head of ppm if dying - edited, only do this if the player killed himself //or specting someone else if ((((ps->pm_flags & PMF_SUICIDE) || !cgs.deathcam || cgs.gametype == GT_DUEL) && (ps->pm_type == PM_DEAD) && (!cg.renderingThirdPerson)) || ((cg.snap->ps.pm_flags & PMF_FOLLOW) && (cg.snap->ps.pm_type != PM_CHASECAM) && (ps->stats[STAT_HEALTH] <= 0))) { VectorCopy(cg.anim_viewangles, cg.refdefViewAngles); VectorCopy(cg.anim_vieworigin, cg.refdef.vieworg); } if (cg_cameraOrbit.integer) { if (cg.time > cg.nextOrbitTime) { cg.nextOrbitTime = cg.time + cg_cameraOrbitDelay.integer; cg_thirdPersonAngle.value += cg_cameraOrbit.value; } } // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } // this is a special camera movement around the players if(cg.introend - DU_INTRO_DRAW >= cg.time && cgs.gametype == GT_DUEL && cg.predictedPlayerState.persistant[PERS_TEAM] == TEAM_FREE && !(cg.snap->ps.pm_flags & PMF_FOLLOW)) { CG_OffsetFirstPersonView(); CG_DuelIntroView(); } else if ((cg.renderingThirdPerson ||(cg.snap->ps.pm_flags & PMF_FOLLOW && cg.snap->ps.pm_type == PM_CHASECAM)) && !cg.introstart) { // back away from character CG_OffsetThirdPersonView(); cg.introstart = 0; } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); cg.introstart = 0; } // position eye relative to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } // field of view return CG_CalcFov(); }
/* =============== Wolfcam_OffsetFirstPersonView Sets cg.refdef view values if following other players =============== */ int Wolfcam_OffsetFirstPersonView (void) { int clientNum; const clientInfo_t *ci; centity_t *cent; const entityState_t *es; wclient_t *wc; float ratio; float v_dmg_pitch; //qboolean wasBinocZooming; int timeDelta; //qboolean notDrawing; float bob; float speed; float delta; qboolean useLastValidBob = qfalse; int anim; int t; memset(&cg.refdef, 0, sizeof(cg.refdef)); CG_CalcVrect(); if (cg.hyperspace) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } clientNum = wcg.clientNum; if (wcg.followMode == WOLFCAM_FOLLOW_KILLER) { const centity_t *c; c = &cg_entities[cg.wcKillerClientNum]; t = wcg.nextKillerServerTime - cg.snap->serverTime; if (t < 0 && t > -wolfcam_hoverTime.integer) { if (!c->currentValid) { // handled at end of function } else { clientNum = cg.wcKillerClientNum; } } } ci = &cgs.clientinfo[clientNum]; cent = &cg_entities[clientNum]; es = ¢->currentState; wc = &wclients[wcg.clientNum]; anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; if (wcg.clientNum == cg.snap->ps.clientNum) { //cg.renderingThirdPerson = 0; //trap_Cvar_Set ("cg_thirdPerson", "0"); } else { //cg.renderingThirdPerson = 1; //trap_Cvar_Set ("cg_thirdPerson", "1"); } //notDrawing = cent->currentState.eFlags & EF_NODRAW; cent->currentState.eFlags |= EF_NODRAW; cent->nextState.eFlags |= EF_NODRAW; VectorCopy (cent->lerpOrigin, cg.refdef.vieworg); VectorCopy (cent->lerpAngles, cg.refdefViewAngles); // CG_TransitionPlayerState for wcg.clientNum //FIXME wolfcam don't know #if 0 if (cent->currentState.eFlags & EF_DEAD) { trap_SendConsoleCommand ("-zoom\n"); } #endif #if 0 wasBinocZooming = qfalse; if (wolfcam_esPrev.eFlags & EF_ZOOMING && wolfcam_esPrev.weapon == WP_BINOCULARS) { wasBinocZooming = qtrue; } if (wasBinocZooming == qfalse && cent->currentState.weapon == WP_BINOCULARS && cent->currentState.eFlags & EF_ZOOMING) { wolfcam_binocZoomTime = cg.time; Com_Printf ("ent zooming with binocs\n"); } #endif #if 1 // add view height //if (es->eFlags & EF_CROUCHING) { if (anim == LEGS_WALKCR || anim == LEGS_IDLECR) { cg.refdef.vieworg[2] += CROUCH_VIEWHEIGHT; //cg.refdef.vieworg[2] += CROUCH_VIEWHEIGHT; //Com_Printf ("test.....\n"); } else { cg.refdef.vieworg[2] += DEFAULT_VIEWHEIGHT; //cg.refdef.vieworg[2] += DEFAULT_VIEWHEIGHT; //Com_Printf ("test.....\n"); } #endif timeDelta = cg.time - wc->duckTime; //FIXME cg.ioverf { if (timeDelta < 0) wc->duckTime = cg.time - DUCK_TIME; if (timeDelta < DUCK_TIME) { cg.refdef.vieworg[2] -= wc->duckChange * (DUCK_TIME - timeDelta) / DUCK_TIME; } } #if 0 //if (es->eFlags & EF_DEAD && ci->infoValid && !notDrawing) { if (!cent->currentValid || es->eFlags & EF_DEAD) { return qfalse; } #endif //FIXME fall, stepOffset? // add angles based on bob // if (cent->currentValid) { if (wclients[wcg.clientNum].currentValid) { // make sure the bob is visible even at low speeds speed = wc->xyspeed > 200 ? wc->xyspeed : 200; ///////////////////// if( !wc->bobfracsin && wc->lastvalidBobfracsin > 0 ) { // 200 msec to get back to center from 1 // that's 1/200 per msec = 0.005 per msec wc->lastvalidBobfracsin -= 0.005 * cg.frametime; useLastValidBob = qtrue; } // delta = useLastValidBob ? wolfcam_lastvalidBobfracsin * cg_bobpitch.value * speed : cg.bobfracsin * cg_bobpitch.value * speed; delta = useLastValidBob ? wc->lastvalidBobfracsin * cg_bobpitch.value * speed : wc->bobfracsin * cg_bobpitch.value * speed; //if (es->eFlags & EF_CROUCHING) if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) delta *= 3; // crouching cg.refdefViewAngles[PITCH] += delta; delta = useLastValidBob ? wc->lastvalidBobfracsin * cg_bobroll.value * speed : wc->bobfracsin * cg_bobroll.value * speed; // if (es->eFlags & EF_CROUCHING) if ( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) delta *= 3; // crouching accentuates roll if( useLastValidBob ) { if( wc->lastvalidBobcycle & 1 ) delta = -delta; } else if (wc->bobcycle & 1) delta = -delta; cg.refdefViewAngles[ROLL] += delta; //FIXME wolfcam ok for weapons, sucks for regular walking //FIXME wolfcam using v_dmg_pitch == kick == -5 v_dmg_pitch = -5; ratio = cg.time - wc->bulletDamageTime; if (ratio < DAMAGE_TIME && !(es->eFlags & EF_DEAD) && ci->infoValid) { if (ratio < DAMAGE_DEFLECT_TIME) { ratio /= DAMAGE_DEFLECT_TIME; cg.refdefViewAngles[PITCH] += ratio * v_dmg_pitch; //FIXME wolfcam ROLL } else { ratio = 1.0 - (ratio - DAMAGE_DEFLECT_TIME) / DAMAGE_RETURN_TIME; if (ratio > 0) { cg.refdefViewAngles[PITCH] += ratio * v_dmg_pitch; //FIXME wolfcam ROLL } } } bob = wc->bobfracsin * wc->xyspeed * cg_bobup.value; if (bob > 6) { bob = 6; } cg.refdef.vieworg[2] += bob; //FIXME wolfcam ok for weapons, not player movement } #if 0 // ZoomSway if (wc->zoomval) { float spreadfrac, phase; if (es->eFlags & EF_MG42_ACTIVE) { // || es->eFlags & EF_AAGUN_ACTIVE) { } else { //spreadfrac = (float)cg.snap->ps.aimSpreadScale / 255.0; spreadfrac = 0.25; //FIXME wolfcam phase = cg.time / 1000.0 * ZOOM_PITCH_FREQUENCY * M_PI * 2; cg.refdefViewAngles[PITCH] += ZOOM_PITCH_AMPLITUDE * sin( phase ) * (spreadfrac+ZOOM_PITCH_MIN_AMPLITUDE); phase = cg.time / 1000.0 * ZOOM_YAW_FREQUENCY * M_PI * 2; cg.refdefViewAngles[YAW] += ZOOM_YAW_AMPLITUDE * sin( phase ) * (spreadfrac+ZOOM_YAW_MIN_AMPLITUDE); } } #endif if (wcg.followMode == WOLFCAM_FOLLOW_VICTIM) { t = wcg.nextVictimServerTime - cg.snap->serverTime; if (t < 0 && t > -wolfcam_hoverTime.integer) { VectorCopy(cg.victimOrigin, cg.refdef.vieworg); VectorCopy(cg.victimAngles, cg.refdefViewAngles); } } else if (wcg.followMode == WOLFCAM_FOLLOW_KILLER) { const centity_t *c; c = &cg_entities[cg.wcKillerClientNum]; t = wcg.nextKillerServerTime - cg.snap->serverTime; if (t < 0 && t > -wolfcam_hoverTime.integer) { if (!c->currentValid) { VectorCopy(cg.wcKillerOrigin, cg.refdef.vieworg); VectorCopy(cg.wcKillerAngles, cg.refdefViewAngles); } } } AnglesToAxis (cg.refdefViewAngles, cg.refdef.viewaxis ); //VectorCopy (cg.refdef.vieworg, cg.refdef_current->vieworg); //AnglesToAxis (cg.refdefViewAngles, cg.refdef_current->viewaxis); return 0; }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static qboolean CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // calculate size of 3D view CG_CalcVrect(); ps = &cg.predicted_player_state; // intermission view if ( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov(); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); // add error decay if ( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if ( f > 0 && f < 1 ) { VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); } else { cg.predictedErrorTime = 0; } } if ( cg.renderingThirdPerson ) { // back away from character if ( cg_thirdPerson.integer == CG_CAM_ABOVE) { CG_OffsetThirdPersonOverheadView(); } else { CG_OffsetThirdPersonView(); } } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView(); } // shake the camera if necessary CGCam_UpdateShake( cg.refdef.vieworg, cg.refdefViewAngles ); // Doing this when the camera is directly above will look bad if ( cg_thirdPerson.integer != CG_CAM_ABOVE ) { // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); } if ( cg.hyperspace ) { cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; } // field of view return CG_CalcFov(); }
void CG_RenderView( float frameTime, float realFrameTime, int realTime, unsigned int serverTime, float stereo_separation, unsigned int extrapolationTime, bool flipped ) { refdef_t *rd = &cg.view.refdef; // update time cg.realTime = realTime; cg.frameTime = frameTime; cg.realFrameTime = realFrameTime; cg.frameCount++; cg.time = serverTime; if( !cgs.precacheDone || !cg.frame.valid ) { CG_Precache(); CG_DrawLoading(); return; } { float snapTime = ( cg.frame.serverTime - cg.oldFrame.serverTime ); if( !snapTime ) snapTime = cgs.snapFrameTime; // moved this from CG_Init here cgs.extrapolationTime = extrapolationTime; if( cg.oldFrame.serverTime == cg.frame.serverTime ) cg.lerpfrac = 1.0f; else cg.lerpfrac = ( (double)( cg.time - cgs.extrapolationTime ) - (double)cg.oldFrame.serverTime ) / (double)snapTime; if( cgs.extrapolationTime ) { cg.xerpTime = 0.001f * ( (double)cg.time - (double)cg.frame.serverTime ); cg.oldXerpTime = 0.001f * ( (double)cg.time - (double)cg.oldFrame.serverTime ); if( cg.time >= cg.frame.serverTime ) { cg.xerpSmoothFrac = (double)( cg.time - cg.frame.serverTime ) / (double)( cgs.extrapolationTime ); clamp( cg.xerpSmoothFrac, 0.0f, 1.0f ); } else { cg.xerpSmoothFrac = (double)( cg.frame.serverTime - cg.time ) / (double)( cgs.extrapolationTime ); clamp( cg.xerpSmoothFrac, -1.0f, 0.0f ); cg.xerpSmoothFrac = 1.0f - cg.xerpSmoothFrac; } clamp_low( cg.xerpTime, -( cgs.extrapolationTime * 0.001f ) ); //clamp( cg.xerpTime, -( cgs.extrapolationTime * 0.001f ), ( cgs.extrapolationTime * 0.001f ) ); //clamp( cg.oldXerpTime, 0, ( ( snapTime + cgs.extrapolationTime ) * 0.001f ) ); } else { cg.xerpTime = 0.0f; cg.xerpSmoothFrac = 0.0f; } } if( cg_showClamp->integer ) { if( cg.lerpfrac > 1.0f ) CG_Printf( "high clamp %f\n", cg.lerpfrac ); else if( cg.lerpfrac < 0.0f ) CG_Printf( "low clamp %f\n", cg.lerpfrac ); } clamp( cg.lerpfrac, 0.0f, 1.0f ); if( !cgs.configStrings[CS_WORLDMODEL][0] ) { CG_AddLocalSounds(); trap_R_DrawStretchPic( 0, 0, cgs.vidWidth, cgs.vidHeight, 0, 0, 1, 1, colorBlack, cgs.shaderWhite ); trap_S_Update( vec3_origin, vec3_origin, axis_identity, cgs.clientInfo[cgs.playerNum].name ); return; } // bring up the game menu after reconnecting if( !cgs.tv && !cgs.demoPlaying ) { if( ISREALSPECTATOR() && !cg.firstFrame ) { if( !cgs.gameMenuRequested ) { trap_Cmd_ExecuteText( EXEC_NOW, "gamemenu\n" ); } cgs.gameMenuRequested = true; } } if( !cg.viewFrameCount ) cg.firstViewRealTime = cg.realTime; CG_FlashGameWindow(); // notify player of important game events CG_CalcVrect(); // find sizes of the 3d drawing screen CG_TileClear(); // clear any dirty part of the background CG_ChaseCamButtons(); CG_RunLightStyles(); CG_ClearFragmentedDecals(); trap_R_ClearScene(); if( CG_DemoCam_Update() ) CG_SetupViewDef( &cg.view, CG_DemoCam_GetViewType(), flipped ); else CG_SetupViewDef( &cg.view, VIEWDEF_PLAYERVIEW, flipped ); CG_LerpEntities(); // interpolate packet entities positions CG_CalcViewWeapon( &cg.weapon ); CG_FireEvents( false ); CG_AddEntities(); CG_AddViewWeapon( &cg.weapon ); CG_AddLocalEntities(); CG_AddParticles(); CG_AddDlights(); CG_AddShadeBoxes(); CG_AddDecals(); CG_AddPolys(); CG_AddLightStyles(); #ifndef PUBLIC_BUILD CG_AddTest(); #endif // offset vieworg appropriately if we're doing stereo separation VectorMA( cg.view.origin, stereo_separation, &cg.view.axis[AXIS_RIGHT], rd->vieworg ); // never let it sit exactly on a node line, because a water plane can // disappear when viewed with the eye exactly on it. // the server protocol only specifies to 1/16 pixel, so add 1/16 in each axis rd->vieworg[0] += 1.0/PM_VECTOR_SNAP; rd->vieworg[1] += 1.0/PM_VECTOR_SNAP; rd->vieworg[2] += 1.0/PM_VECTOR_SNAP; AnglesToAxis( cg.view.angles, rd->viewaxis ); rd->rdflags = CG_RenderFlags(); // warp if underwater if( rd->rdflags & RDF_UNDERWATER ) { float phase = rd->time * 0.001 * WAVE_FREQUENCY * M_TWOPI; float v = WAVE_AMPLITUDE * ( sin( phase ) - 1.0 ) + 1; rd->fov_x *= v; rd->fov_y *= v; } CG_AddLocalSounds(); CG_SetSceneTeamColors(); // update the team colors in the renderer trap_R_RenderScene( &cg.view.refdef ); cg.oldAreabits = true; trap_S_Update( cg.view.origin, cg.view.velocity, cg.view.axis, cgs.clientInfo[cgs.playerNum].name ); CG_Draw2D(); CG_ResetTemporaryBoneposesCache(); // clear for next frame cg.viewFrameCount++; }