void PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs
(const PxVehiclePadSmoothingData& padSmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
 const PxVehicleDrive4WRawInputData& rawInputData, 
 const PxF32 timestep, 
 PxVehicleDrive4W& focusVehicle)
{
	//gearup/geardown
	const bool gearup=rawInputData.getGearUp();
	const bool geardown=rawInputData.getGearDown();
	focusVehicle.mDriveDynData.setGearUp(gearup);
	focusVehicle.mDriveDynData.setGearDown(geardown);

	//Update analog inputs for focus vehicle.

	//Process the accel.
	{
		const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4W::eANALOG_INPUT_ACCEL];
		const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4W::eANALOG_INPUT_ACCEL];
		const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_ACCEL);
		const PxF32 targetVal=rawInputData.getAnalogAccel();
		const PxF32 accel=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
		focusVehicle.mDriveDynData.setAnalogInput(accel,PxVehicleDrive4W::eANALOG_INPUT_ACCEL);
	}

	//Process the brake
	{
		const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4W::eANALOG_INPUT_BRAKE];
		const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4W::eANALOG_INPUT_BRAKE];
		const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_BRAKE);
		const PxF32 targetVal=rawInputData.getAnalogBrake();
		const PxF32 brake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
		focusVehicle.mDriveDynData.setAnalogInput(brake,PxVehicleDrive4W::eANALOG_INPUT_BRAKE);
	}

	//Process the handbrake.
	{
		const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE];
		const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE];
		const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE);
		const PxF32 targetVal=rawInputData.getAnalogHandbrake();
		const PxF32 handbrake=processPositiveAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
		focusVehicle.mDriveDynData.setAnalogInput(handbrake,PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE);
	}

	//Process the steer
	{
		const PxF32 vz=focusVehicle.computeForwardSpeed();
		const PxF32 vzAbs=PxAbs(vz);
		const bool isInAir=focusVehicle.isInAir();
		const PxF32 riseRate=padSmoothing.mRiseRates[PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT];
		const PxF32 fallRate=padSmoothing.mFallRates[PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT];
		const PxF32 currentVal=focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT)-focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_STEER_LEFT);
		const PxF32 targetVal=rawInputData.getAnalogSteer()*(isInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs));
		const PxF32 steer=processAnalogValue(riseRate,fallRate,currentVal,targetVal,timestep);
		focusVehicle.mDriveDynData.setAnalogInput(0.0f, PxVehicleDrive4W::eANALOG_INPUT_STEER_LEFT);
		focusVehicle.mDriveDynData.setAnalogInput(steer, PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT);
	}
}
void PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs
(const PxVehicleKeySmoothingData& keySmoothing, const PxFixedSizeLookupTable<8>& steerVsForwardSpeedTable,
 const PxVehicleDrive4WRawInputData& rawInputData, 
 const PxF32 timestep, 
 PxVehicleDrive4W& focusVehicle)
{
	const bool gearup=rawInputData.getGearUp();
	const bool geardown=rawInputData.getGearDown();
	focusVehicle.mDriveDynData.setGearDown(geardown);
	focusVehicle.mDriveDynData.setGearUp(gearup);

	const PxF32 accel=processDigitalValue(PxVehicleDrive4W::eANALOG_INPUT_ACCEL,keySmoothing,rawInputData.getDigitalAccel(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_ACCEL));
	focusVehicle.mDriveDynData.setAnalogInput(accel,PxVehicleDrive4W::eANALOG_INPUT_ACCEL);

	const PxF32 brake=processDigitalValue(PxVehicleDrive4W::eANALOG_INPUT_BRAKE,keySmoothing,rawInputData.getDigitalBrake(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_BRAKE));
	focusVehicle.mDriveDynData.setAnalogInput(brake,PxVehicleDrive4W::eANALOG_INPUT_BRAKE);

	const PxF32 handbrake=processDigitalValue(PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE,keySmoothing,rawInputData.getDigitalHandbrake(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE));
	focusVehicle.mDriveDynData.setAnalogInput(handbrake,PxVehicleDrive4W::eANALOG_INPUT_HANDBRAKE);

	PxF32 steerLeft=processDigitalValue(PxVehicleDrive4W::eANALOG_INPUT_STEER_LEFT,keySmoothing,rawInputData.getDigitalSteerLeft(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_STEER_LEFT));
	PxF32 steerRight=processDigitalValue(PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT,keySmoothing,rawInputData.getDigitalSteerRight(),timestep,focusVehicle.mDriveDynData.getAnalogInput(PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT));
	const PxF32 vz=focusVehicle.computeForwardSpeed();
	const PxF32 vzAbs=PxAbs(vz);
	const bool isInAir=focusVehicle.isInAir();
	const PxF32 maxSteer=(isInAir ? 1.0f :steerVsForwardSpeedTable.getYVal(vzAbs));
	const PxF32 steer=PxAbs(steerRight-steerLeft);
	if(steer>maxSteer)
	{
		const PxF32 k=maxSteer/steer;
		steerLeft*=k;
		steerRight*=k;
	}
	focusVehicle.mDriveDynData.setAnalogInput(steerLeft, PxVehicleDrive4W::eANALOG_INPUT_STEER_LEFT);
	focusVehicle.mDriveDynData.setAnalogInput(steerRight, PxVehicleDrive4W::eANALOG_INPUT_STEER_RIGHT);
}
void SampleVehicle_VehicleController::processRawInputs
(const PxF32 dtime, const bool useAutoGears, PxVehicleDrive4WRawInputData& rawInputData)
{
	// Keyboard
	{
		if(mRecord)
		{
			if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
			{
				mKeyboardAccelValues[mNumSamples]		= mKeyPressedAccel;
				mKeyboardBrakeValues[mNumSamples]		= mKeyPressedBrake;
				mKeyboardHandbrakeValues[mNumSamples]	= mKeyPressedHandbrake;
				mKeyboardSteerLeftValues[mNumSamples]	= mKeyPressedSteerLeft;
				mKeyboardSteerRightValues[mNumSamples]	= mKeyPressedSteerRight;
				mKeyboardGearupValues[mNumSamples]		= mKeyPressedGearUp;
				mKeyboardGeardownValues[mNumSamples]	= mKeyPressedGearDown;
			}
		}
		else if(mReplay)
		{
			if(mNumSamples<mNumRecordedSamples)
			{
				mKeyPressedAccel		= mKeyboardAccelValues[mNumSamples];		
				mKeyPressedBrake		= mKeyboardBrakeValues[mNumSamples];		
				mKeyPressedHandbrake	= mKeyboardHandbrakeValues[mNumSamples];	
				mKeyPressedSteerLeft	= mKeyboardSteerLeftValues[mNumSamples];
				mKeyPressedSteerRight	= mKeyboardSteerRightValues[mNumSamples];	
				mKeyPressedGearUp		= mKeyboardGearupValues[mNumSamples];	
				mKeyPressedGearDown		= mKeyboardGeardownValues[mNumSamples];
			}
		}

		rawInputData.setDigitalAccel(mKeyPressedAccel);
		rawInputData.setDigitalBrake(mKeyPressedBrake);
		rawInputData.setDigitalHandbrake(mKeyPressedHandbrake);
		rawInputData.setDigitalSteerLeft(mKeyPressedSteerLeft);
		rawInputData.setDigitalSteerRight(mKeyPressedSteerRight);
		rawInputData.setGearUp(mKeyPressedGearUp);
		rawInputData.setGearDown(mKeyPressedGearDown);

		mUseKeyInputs=
			(mKeyPressedAccel || mKeyPressedBrake  || mKeyPressedHandbrake || 
			 mKeyPressedSteerLeft || mKeyPressedSteerRight || 
			 mKeyPressedGearUp || mKeyPressedGearDown);
	}

	// Gamepad
	{
		if(mRecord)
		{
			if(mNumSamples<MAX_NUM_RECORD_REPLAY_SAMPLES)
			{
				mGamepadAccelValues[mNumSamples]		= mGamepadAccel;
				mGamepadCarBrakeValues[mNumSamples]		= mGamepadCarBrake;
				mGamepadCarSteerValues[mNumSamples]		= mGamepadCarSteer;
				mGamepadGearupValues[mNumSamples]		= mGamepadGearup;
				mGamepadGeardownValues[mNumSamples]		= mGamepadGeardown;
				mGamepadCarHandbrakeValues[mNumSamples]	= mGamepadCarHandbrake;
			}
		}
		else if(mReplay)
		{
			if(mNumSamples<mNumRecordedSamples)
			{
				mGamepadAccel		= mGamepadAccelValues[mNumSamples];		
				mGamepadCarBrake		= mGamepadCarBrakeValues[mNumSamples];		
				mGamepadCarSteer		= mGamepadCarSteerValues[mNumSamples];		
				mGamepadGearup		= mGamepadGearupValues[mNumSamples];	
				mGamepadGeardown	= mGamepadGeardownValues[mNumSamples];	
				mGamepadCarHandbrake	= mGamepadCarHandbrakeValues[mNumSamples];	
			}
		}

		if(mGamepadAccel<0.0f || mGamepadAccel>1.01f)
			getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal accel value from gamepad", __FILE__, __LINE__);

		if(mGamepadCarBrake<0.0f || mGamepadCarBrake>1.01f)
			getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal brake value from gamepad", __FILE__, __LINE__);

		if(PxAbs(mGamepadCarSteer)>1.01f)
			getSampleErrorCallback().reportError(PxErrorCode::eINTERNAL_ERROR, "Illegal steer value from gamepad", __FILE__, __LINE__);

		if(mUseKeyInputs && ((mGamepadAccel+mGamepadCarBrake+mGamepadCarSteer)!=0.0f ||  mGamepadGearup || mGamepadGeardown || mGamepadCarHandbrake))
		{
			mUseKeyInputs=false;
		}

		if(!mUseKeyInputs)
		{
			rawInputData.setAnalogAccel(mGamepadAccel);
			rawInputData.setAnalogBrake(mGamepadCarBrake);
			rawInputData.setAnalogHandbrake(mGamepadCarHandbrake ? 1.0f : 0.0f);
			rawInputData.setAnalogSteer(mGamepadCarSteer);
			rawInputData.setGearUp(mGamepadGearup);
			rawInputData.setGearDown(mGamepadGeardown);
		}
	}

	if(useAutoGears && (rawInputData.getGearDown() || rawInputData.getGearUp()))
	{
		rawInputData.setGearDown(false);
		rawInputData.setGearUp(false);
	}

	mNumSamples++;
}