Full Code of jeff-1amstudios/OpenNFS1 for AI

master 357fe6c3314a cached
126 files
472.1 KB
127.1k tokens
584 symbols
1 requests
Download .txt
Showing preview only (506K chars total). Download the full file or copy to clipboard to get everything.
Repository: jeff-1amstudios/OpenNFS1
Branch: master
Commit: 357fe6c3314a
Files: 126
Total size: 472.1 KB

Directory structure:
gitextract_3ncehpj2/

├── .editorconfig
├── .gitignore
├── Engine/
│   ├── AverageValueVector3.cs
│   ├── ChaseCamera.cs
│   ├── Engine.cs
│   ├── FPSCamera.cs
│   ├── FPSCounter.cs
│   ├── FixedChaseCamera.cs
│   ├── GameConsole.cs
│   ├── GameEngine.csproj
│   ├── GameObject.cs
│   ├── GraphicsUtilities.cs
│   ├── ICamera.cs
│   ├── IDrawableObject.cs
│   ├── IGameScreen.cs
│   ├── IWorld.cs
│   ├── InputProvider.cs
│   ├── ParticleSystem/
│   │   ├── ParticleEmitter.cs
│   │   ├── ParticleSettings.cs
│   │   ├── ParticleSystem.cs
│   │   └── ParticleVertex.cs
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── ScreenEffects.cs
│   ├── SimpleCamera.cs
│   ├── SkyBox.cs
│   ├── SoundEngine2.cs
│   └── Utility.cs
├── Installer/
│   ├── OpenNFS1.nsi
│   ├── build-installer.bat
│   └── readme.txt
├── NFSSpecs.txt
├── OpenNFS1/
│   ├── Audio/
│   │   ├── BnkVehicleAudioProvider.cs
│   │   ├── EnvironmentAudioProvider.cs
│   │   └── VehicleAudioProvider.cs
│   ├── AverageValue.cs
│   ├── Content/
│   │   ├── ArialBlack-Italic.spritefont
│   │   ├── ArialBlack.spritefont
│   │   ├── ParticleEffect.fx
│   │   ├── common.fxh
│   │   ├── macros.fxh
│   │   └── structures.fxh
│   ├── Dashboards/
│   │   ├── Dashboard.cs
│   │   ├── DashboardDescription.cs
│   │   └── GearboxAnimation.cs
│   ├── Game1.cs
│   ├── GameConfig.cs
│   ├── Mesh.cs
│   ├── ObjectShadow.cs
│   ├── OpenNFS1.csproj
│   ├── Parsers/
│   │   ├── Audio/
│   │   │   ├── BnkFile.cs
│   │   │   └── WavWriter.cs
│   │   ├── BaseChunk.cs
│   │   ├── BitmapChunk.cs
│   │   ├── BitmapLoader.cs
│   │   ├── CfmFile.cs
│   │   ├── FshFile.cs
│   │   ├── HeaderChunk.cs
│   │   ├── MeshChunk.cs
│   │   ├── OpenRoadTrackfamFile.cs
│   │   ├── QfsFile.cs
│   │   ├── TrackfamFile.cs
│   │   └── TriFile.cs
│   ├── Physics/
│   │   ├── AutoGearbox.cs
│   │   ├── BaseGearbox.cs
│   │   ├── DrivableVehicle.cs
│   │   ├── ManualGearbox.cs
│   │   ├── Motor.cs
│   │   ├── Spring.cs
│   │   ├── Vector3Helper.cs
│   │   ├── VehicleFenceCollision.cs
│   │   └── VehicleWheel.cs
│   ├── PlayerUI.cs
│   ├── Polygon.cs
│   ├── Program.cs
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── Race/
│   │   ├── PlayerRaceStats.cs
│   │   ├── Race.cs
│   │   └── RaceUI.cs
│   ├── Tracks/
│   │   ├── SceneryObject.cs
│   │   ├── TerrainRow.cs
│   │   ├── TerrainSegment.cs
│   │   ├── Track.cs
│   │   ├── TrackAssembler.cs
│   │   ├── TrackBillboardModel.cs
│   │   ├── TrackDescription.cs
│   │   ├── TrackNode.cs
│   │   ├── TrackObjectDescriptor.cs
│   │   └── TrackSkybox.cs
│   ├── UI/
│   │   └── Screens/
│   │       ├── BaseUIScreen.cs
│   │       ├── ChooseDataDownloadScreen.cs
│   │       ├── DataDownloadScreen.cs
│   │       ├── DoRaceScreen.cs
│   │       ├── HomeScreen.cs
│   │       ├── LoadRaceScreen.cs
│   │       ├── OpenNFS1SplashScreen.cs
│   │       ├── RaceFinishedScreen.cs
│   │       ├── RaceOptionsScreen.cs
│   │       └── RacePausedScreen.cs
│   ├── UIController.cs
│   ├── VehicleController.cs
│   ├── Vehicles/
│   │   ├── AI/
│   │   │   ├── AIDriver.cs
│   │   │   ├── IDriver.cs
│   │   │   └── TrafficDriver.cs
│   │   ├── CarMesh.cs
│   │   ├── CarModelCache.cs
│   │   ├── PlayerDriver.cs
│   │   ├── Traffic/
│   │   │   └── TrafficController.cs
│   │   ├── TyreSmokeParticleSystem.cs
│   │   ├── Vehicle.cs
│   │   ├── VehicleDescription.cs
│   │   └── WheelModel.cs
│   ├── Views/
│   │   ├── BaseExternalView.cs
│   │   ├── BumperView.cs
│   │   ├── ChaseView.cs
│   │   ├── DashboardView.cs
│   │   ├── DebugView.cs
│   │   ├── DropCameraView.cs
│   │   └── IView.cs
│   └── gameconfig.json
├── OpenNFS1.sln
├── PreBuilt_Content/
│   ├── ArialBlack-Italic.xnb
│   ├── ArialBlack.xnb
│   └── ParticleEffect.xnb
├── TnfsSeSpex.txt
├── readme.md
└── reverse_engineering.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
indent_size = 4
tab_width = 4
indent_style = tab

================================================
FILE: .gitignore
================================================
*.suo
*.user
_ReSharper.*
bin
obj
deploy


================================================
FILE: Engine/AverageValueVector3.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace GameEngine
{
	public class AverageValueVector3
	{
		int _nbrValues;
		List<Vector3> _values = new List<Vector3>();

		public AverageValueVector3(int nbrVaues)
		{
			_nbrValues = nbrVaues;
		}

        public void Reset(int nbrValues)
        {
            _nbrValues = nbrValues;
            _values.Clear();
        }

		public void AddValue(Vector3 value)
		{
			_values.Add(value);
			if (_values.Count > _nbrValues)
				_values.RemoveAt(0);
		}

		public Vector3 GetAveragedValue()
		{
			Vector3 average = new Vector3();
			foreach (Vector3 value in _values)
			{
				average += value;
			}
			return average / _values.Count;
		}
	}
}


================================================
FILE: Engine/ChaseCamera.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GameEngine;
using System.Diagnostics;

namespace GameEngine
{
    
    public class ChaseCamera : ICamera
    {
		private Vector3 _chasePosition;
		private Vector3 _chaseDirection = new Vector3(0, 0, -1);
		private Vector3 _up = Vector3.Up;
		private Vector3 _desiredPositionOffset = new Vector3(0, 2.0f, 2.0f);
		private Vector3 _desiredPosition;
		private Vector3 _lookAtOffset = new Vector3(0, 2.8f, 0);
		private Vector3 _lookAt;
		private float _stiffness = 1800.0f;
		private float _zstiffness = 2.0f;
		private float _damping = 600.0f;
		private float _mass = 50.0f;
		private Vector3 _position;
		private Vector3 _velocity;
		private float _fieldOfView = MathHelper.ToRadians(45.0f);
		private float _nearPlaneDistance = 1.0f;
		private float _farPlaneDistance = 15000.0f;
		private Matrix _view;
		private Matrix _projection;

        
        /// <summary>
        /// Position of object being chased.
        /// </summary>
        public Vector3 ChasePosition
        {
            get { return _chasePosition; }
            set { _chasePosition = value; }
        }        

        public void FollowObject(GameObject obj)
        {
            _chasePosition = obj.Position;
            _chaseDirection = obj.Orientation;
        }

        /// <summary>
        /// Direction the chased object is facing.
        /// </summary>
        public Vector3 ChaseDirection
        {
            get { return _chaseDirection; }
            set { _chaseDirection = value; }
        }        

        /// <summary>
        /// Chased object's Up vector.
        /// </summary>
        public Vector3 Up
        {
            get { return _up; }
            set { _up = value; }
        }

        /// <summary>
        /// Desired camera position in the chased object's coordinate system.
        /// </summary>
        public Vector3 DesiredPositionOffset
        {
            get { return _desiredPositionOffset; }
            set { _desiredPositionOffset = value; }
        }
        
        /// <summary>
        /// Desired camera position in world space.
        /// </summary>
        public Vector3 DesiredPosition
        {
            get
            {
                // Ensure correct value even if update has not been called this frame
                UpdateWorldPositions();

                return _desiredPosition;
            }
        }
		
        /// <summary>
        /// Look at point in the chased object's coordinate system.
        /// </summary>
        public Vector3 LookAtOffset
        {
            get { return _lookAtOffset; }
            set { _lookAtOffset = value; }
        }
		
        /// <summary>
        /// Look at point in world space.
        /// </summary>
        public Vector3 LookAt
        {
            get
            {
                // Ensure correct value even if update has not been called this frame
                UpdateWorldPositions();

                return _lookAt;
            }
        }
		
        /// <summary>
        /// Physics coefficient which controls the influence of the camera's position
        /// over the spring force. The stiffer the spring, the closer it will stay
        /// the chased object.
        /// </summary>
        public float Stiffness
        {
            get { return _stiffness; }
            set { _stiffness = value; }
        }
		
		/// <summary>
		/// Controls how hard the camera tries to keep up with the chased object 
		/// </summary>
        public float ZStiffness
        {
            get { return _zstiffness; }
            set { _zstiffness = value; }
        }
		
        /// <summary>
        /// Physics coefficient which approximates internal friction of the spring.
        /// Sufficient damping will prevent the spring from oscillating infinitely.
        /// </summary>
        public float Damping
        {
            get { return _damping; }
            set { _damping = value; }
        }
		
        /// <summary>
        /// Mass of the camera body. Heaver objects require stiffer springs with less
        /// damping to move at the same rate as lighter objects.
        /// </summary>
        public float Mass
        {
            get { return _mass; }
            set { _mass = value; }
        }
		

        /// <summary>
        /// Position of camera in world space.
        /// </summary>
        public Vector3 Position
        {
            get { return _position; }
        }
		
        /// <summary>
        /// Velocity of camera.
        /// </summary>
        public Vector3 Velocity
        {
            get { return _velocity; }
        }
		

        #region Perspective properties

		
        /// <summary>
        /// Perspective field of view.
        /// </summary>
        public float FieldOfView
        {
            get { return _fieldOfView; }
            set { _fieldOfView = value; }
        }
		
        /// <summary>
        /// Distance to the near clipping plane.
        /// </summary>
        public float NearPlaneDistance
        {
            get { return _nearPlaneDistance; }
            set { _nearPlaneDistance = value; }
        }
		
        /// <summary>
        /// Distance to the far clipping plane.
        /// </summary>
        public float FarPlaneDistance
        {
            get { return _farPlaneDistance; }
            set { _farPlaneDistance = value; }
        }
		
        #endregion


        /// <summary>
        /// View transform matrix.
        /// </summary>
        public Matrix View
        {
            get { return _view; }
        }
		
        /// <summary>
        /// Projecton transform matrix.
        /// </summary>
        public Matrix Projection
        {
            get { return _projection; }
        }


        /// <summary>
        /// Rebuilds object space values in world space. Invoke before publicly
        /// returning or privately accessing world space values.
        /// </summary>
        private void UpdateWorldPositions()
        {
            Matrix transform = Matrix.Identity;
            transform.Forward = ChaseDirection;
            transform.Up = Up;
            transform.Right = Vector3.Cross(Up, ChaseDirection);

            // Calculate desired camera properties in world space
            _desiredPosition = ChasePosition + Vector3.TransformNormal(DesiredPositionOffset, transform);
            _lookAt = ChasePosition + Vector3.TransformNormal(LookAtOffset, transform);
        }

        /// <summary>
        /// Rebuilds camera's view and projection matricies.
        /// </summary> 
        private void UpdateMatrices()
        {
            _view = Matrix.CreateLookAt(this.Position, this.LookAt, this.Up);
            _projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView,
                Engine.Instance.AspectRatio, NearPlaneDistance, FarPlaneDistance);
        }

        /// <summary>
        /// Forces camera to be at desired position and to stop moving. The is useful
        /// when the chased object is first created or after it has been teleported.
        /// Failing to call this after a large change to the chased object's position
        /// will result in the camera quickly flying across the world.
        /// </summary>
        public void Reset()
        {
            UpdateWorldPositions();

            // Stop motion
            _velocity = Vector3.Zero;

            // Force desired position
            _position = _desiredPosition;

            UpdateMatrices();
        }

        /// <summary>
        /// Animates the camera from its current position towards the desired offset
        /// behind the chased object. The camera's animation is controlled by a simple
        /// physical spring attached to the camera and anchored to the desired position.
        /// </summary>
        public void Update(GameTime gameTime)
        {
            
            UpdateWorldPositions();

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // Calculate spring force
            Vector3 stretch = (_position - _desiredPosition);
            
            Vector3 force = -_stiffness * stretch - _damping * _velocity;

            // Apply acceleration
            Vector3 acceleration = force / _mass;
            _velocity += acceleration * elapsed;

            // Apply velocity
            _position += _velocity * elapsed;

			// Keep up with chased object
            //if (Vector3.Distance(_chasePosition, _position) > 50)
            //{

            //_position += _chaseDirection * elapsed * (Vector3.Distance(_chasePosition, _position)) * _zstiffness;
            
            //}

            UpdateMatrices();
        }

        public void SetPosition(Vector3 position)
        {
            _position = position;
        }
    }
}


================================================
FILE: Engine/Engine.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using System.Diagnostics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using GameEngine;

namespace GameEngine
{
    public class Engine : DrawableGameComponent
    {
                
        private static Engine _instance;
        private ContentManager _contentManager;
        private ICamera _camera;
        private InputProvider _inputProvider;
        private GraphicsUtilities _graphicsUtils;
        private IWorld _world;
        public GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;
        public Vector2 ScreenSize;
		public float FrameTime;
                
        public static Engine Instance
        {
            get
            {
                return _instance;
            }
        }

        public static void Create(Game game, GraphicsDeviceManager graphics)
        {
            Debug.Assert(_instance == null);
            _instance = new Engine(game);            
            _instance.EngineStartup(graphics);
        }

        
        private Engine(Game game)
            : base(game)
        {
             
        }

        private void EngineStartup(GraphicsDeviceManager graphics)
        {
            _graphics = graphics;

            _contentManager = new ContentManager(base.Game.Services);

            //Game bits
            _inputProvider = new InputProvider(base.Game);
			var defaultFont = Engine.Instance.ContentManager.Load<SpriteFont>("Content\\ArialBlack");
            _graphicsUtils = new GraphicsUtilities(defaultFont);
            _spriteBatch = new SpriteBatch(Device);
            base.Game.Components.Add(this);
        }

        public float AspectRatio
        {
			get
			{

				return (float)Device.Viewport.Width / (float)Device.Viewport.Height;
			}
        }
        

        public override void Update(GameTime gameTime)
        {
			
            base.Update(gameTime);

			FrameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
			GameConsole.Clear();
            
            _inputProvider.Update(gameTime);
            SoundEngine2.Instance.Update(gameTime);
            Screen.Update(gameTime);

            ScreenEffects.Instance.Update(gameTime);

            _graphicsUtils.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            Screen.Draw();
            _graphicsUtils.Draw();
            ScreenEffects.Instance.Draw();
            _graphicsUtils.DrawText();
        }

        public ContentManager ContentManager
        {
            get { return _contentManager; }
        }

        public GraphicsDevice Device
        {
            get { return _graphics.GraphicsDevice; }
        }
        
				//public BasicEffect CurrentEffect
				//{
				//		get { return _currentEffect; }
				//		set { _currentEffect = value; }
				//}

        public GraphicsUtilities GraphicsUtils
        {
            get { return _graphicsUtils; }
        }

        public IWorld World
        {
            get { return _world; }
            set { _world = value; }
        }

        public ICamera Camera
        {
            get { return _camera; }
            set { _camera = value; }
        }

        public InputProvider Input
        {
            get { return _inputProvider; }
            set { _inputProvider = value; }
        }

        public IGameScreen Screen {get; set; }
        

        public SpriteBatch SpriteBatch
        {
            get { return _spriteBatch; }
        }

		Random _random = new Random();

		public Random Random
		{
			get
			{
				return _random;
			}
		}

        

        //public bool EnableBloom
        //{
        //    set
        //    {
        //        if (value)
        //        {
        //            _game.Components.Add(new BloomComponent(_game));
        //        }
        //        else
        //        {
        //            foreach (IGameComponent component in _game.Components)
        //            {
        //                if (component is BloomComponent)
        //                {
        //                    _game.Components.Remove(component);
        //                    break;
        //                }
        //            }
        //        }
        //    }
        //}
    }
}


================================================
FILE: Engine/FPSCamera.cs
================================================
//-----------------------------------------------------------------------------
// Copyright (c) 2007 dhpoware. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GameEngine;


namespace OneAmEngine
{
	/// <summary>
	/// The FirstPersonCamera class implements the logic for a first person
	/// style 3D camera. This class also handles player input that is used
	/// to control the camera. To use this class, create an instance of the
	/// FirstPersonCamera class and then call the Update() method once a
	/// frame from your game's main loop. The FirstPersonCamera's Update()
	/// method will process mouse and keyboard input used to manipulate the
	/// camera. To change the default movement key bindings call the
	/// MapActionToKey() method. Most of the code in this class is used to
	/// simulate camera view bobbing, crouching, and jumping.
	/// </summary>
	public class FPSCamera : ICamera
	{

		public const float DEFAULT_FOVX = 60.0f;
		public const float DEFAULT_ROTATION_SPEED = 0.25f;

		public const float DEFAULT_ZNEAR = 0.1f;

		private const float GRAVITY = -9.8f;
		private const float DECELERATION = -0.5f;
		private const float STRAFE_SPEED_MULTIPLIER = 15.5f;

		private const float VelocityInversionMultiplier = 20.0f;
		private const float Acceleration = 5.0f;
		private const float Deceleration = -5.0f;
		private const float JumpVelocity = 0.23f;
		private const float MaxSpeed = 1.5f;
		
		private float _strafeDelta, _forwardDelta, _velocity;

		private Vector3 _orientation, _position;

		public Vector3 Position
		{
			get { return _position; }
			set { _position = value; }
		}
		public Vector3 Orientation
		{
			get { return _orientation; }
			set { _orientation = value; }
		}

		public float DrawDistance { get; set; }

		public Matrix View { get; private set; }
		public Matrix Projection { get; private set; }

		public FPSCamera()
		{
			Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(DEFAULT_FOVX), Engine.Instance.AspectRatio, DEFAULT_ZNEAR, 15000);
			View = Matrix.Identity;
		}


		public void Update(GameTime gt)
		{
			InputProvider input = Engine.Instance.Input;
			float elapsedTime = Engine.Instance.FrameTime;

			_forwardDelta = input.MoveForward * elapsedTime * Acceleration;

			_strafeDelta = input.Strafe * elapsedTime * Acceleration;

			float speed = 0.5f;

			if (input.IsKeyDown(Keys.Home))
			{
				_orientation.Y -= speed * elapsedTime;
			}
			if (input.IsKeyDown(Keys.End))
			{
				_orientation.Y += speed * elapsedTime;
			}
			if (input.IsKeyDown(Keys.Delete))
			{
				_orientation.X += speed * elapsedTime;
			}
			if (input.IsKeyDown(Keys.PageDown))
			{
				_orientation.X -= speed * elapsedTime;
			}

			UpdateVelocity();
			MoveForward();

			_position.X += (float)(Math.Cos(_orientation.X) * input.Strafe);
			_position.Z -= (float)(Math.Sin(_orientation.X) * input.Strafe);
			
			Matrix view = Matrix.CreateTranslation(-Position);
			view *= Matrix.CreateRotationY(-_orientation.X);
			view *= Matrix.CreateRotationX(_orientation.Y);
			view *= Matrix.CreateRotationZ(_orientation.Z);

			View = view;
			Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(DEFAULT_FOVX), Engine.Instance.AspectRatio, DEFAULT_ZNEAR, 15000);
		}

		private void UpdateVelocity()
		{
			float elapsedTimeSec = Engine.Instance.FrameTime;

			// Accelerate or decelerate as camera is moved forward or backward.
			float acceleration = Acceleration;

			if (_forwardDelta != 0.0f)
			{
				// Speed up the transition from moving backwards to moving
				// forwards and vice versa. Otherwise there will be too much
				// of a delay as the camera slows down and then accelerates.
				if ((_forwardDelta > 0.0f && _velocity < 0.0f) ||
					(_forwardDelta < 0.0f && _velocity > 0.0f))
				{
					acceleration *= VelocityInversionMultiplier;
				}

				_velocity += _forwardDelta * acceleration;
			}
			else
			{

				if (_velocity > 0.0f)
				{
					_velocity += Deceleration * elapsedTimeSec;

					if (_velocity < 0.0f)
						_velocity = 0.0f;
				}
				else if (_velocity < 0.0f)
				{
					_velocity -= Deceleration * elapsedTimeSec;

					if (_velocity > 0.0f)
						_velocity = 0.0f;
				}

			}

			if (_velocity > MaxSpeed)
			{
				_velocity = MaxSpeed;
				acceleration = 0;
			}

			if (_velocity < -MaxSpeed)
			{
				_velocity = -MaxSpeed;
				acceleration = 0;
			}
		}

		public void MoveForward()
		{
			_position.X -= (float)((Math.Sin(_orientation.X) * Math.Cos(_orientation.Y)) * _velocity);
			_position.Z -= (float)((Math.Cos(_orientation.X) * Math.Cos(_orientation.Y)) * _velocity);
			_position.Y -= _orientation.Y * _velocity;
		}

		public void SetPosition(Vector3 pos)
		{

		}

		public void FollowObject(GameObject obj)
		{

		}
	}
}

================================================
FILE: Engine/FPSCounter.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GameEngine;

namespace GameEngine
{
    public class FrameRateCounter : DrawableGameComponent
    {
        
        int frameRate = 0;
        int frameCounter = 0;
        TimeSpan elapsedTime = TimeSpan.Zero;
        
        public FrameRateCounter()
            : base(Engine.Instance.Game)
        {
        }

        public override void Update(GameTime gameTime)
        {
            elapsedTime += gameTime.ElapsedGameTime;

            if (elapsedTime > TimeSpan.FromSeconds(1))
            {
                elapsedTime -= TimeSpan.FromSeconds(1);
                frameRate = frameCounter;
                frameCounter = 0;
            }
        }

        public override void Draw(GameTime gameTime)
        {
            frameCounter++;

            string fps = string.Format("fps: {0}", frameRate);
            GameConsole.WriteLine(fps);
        }
    }
}


================================================
FILE: Engine/FixedChaseCamera.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GameEngine;

namespace GameEngine
{
    /// <summary>
    /// Camera that stays a fixed distance behind an object but swings freely
    /// </summary>
    public class FixedChaseCamera : ICamera
    {
        public FixedChaseCamera()
		{
		}

        public Vector3 RightVec = Vector3.Right;
        public Vector3 UpVector = Vector3.Up;
        AverageValueVector3 _lookAt = new AverageValueVector3(40);

		
		/// <summary>
		/// Position of camera in world space.
		/// </summary>
		public Vector3 Position
		{
			get { return _position; }
			set { _position = value; }
		}

		private Vector3 _position;

        public Vector3 ChaseDirection
        {
            set {
                
                //_lookAt.AddValue(value);
                _chaseDirection = value;
            }
        }
        private Vector3 _chaseDirection;

        public float ChaseOffset { get; set; }

		
		/// <summary>
		/// Perspective field of view.
		/// </summary>
		public float FieldOfView
		{
			get { return fieldOfView; }
			set { fieldOfView = value; }
		}
		private float fieldOfView = MathHelper.ToRadians(45.0f);

		/// <summary>
		/// Distance to the near clipping plane.
		/// </summary>
		public float NearPlaneDistance
		{
			get { return nearPlaneDistance; }
			set { nearPlaneDistance = value; }
		}
		private float nearPlaneDistance = 1.0f;

		/// <summary>
		/// Distance to the far clipping plane.
		/// </summary>
		public float FarPlaneDistance
		{
			get { return farPlaneDistance; }
			set { farPlaneDistance = value; }
		}
		private float farPlaneDistance = 15000.0f;


		/// <summary>
		/// View transform matrix.
		/// </summary>
		public Matrix View
		{
			get { return _view; }
		}
		private Matrix _view;

		/// <summary>
		/// Projecton transform matrix.
		/// </summary>
		public Matrix Projection
		{
			get { return _projection; }
		}
		private Matrix _projection;


		public void Update(GameTime gameTime)
		{
            _lookAt.AddValue(new Vector3(ChaseOffset, ChaseHeight, 0) + (-_chaseDirection * new Vector3(ChaseDistance, ChaseDistance, ChaseDistance)));
            Vector3 avgLookAt = _lookAt.GetAveragedValue();
            Vector3 cameraPosition = _position +avgLookAt;
            _view = Matrix.CreateLookAt(cameraPosition, cameraPosition - avgLookAt + new Vector3(0,13,0), Vector3.Up);
            _projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView, Engine.Instance.AspectRatio, NearPlaneDistance, FarPlaneDistance);
		}

		public void SetPosition(Vector3 position)
		{
			_position = position;
		}

		public void FollowObject(GameObject obj)
		{
		}

        public float ChaseDistance { get; set; }
        public float ChaseHeight { get; set; }

        
    }
}


================================================
FILE: Engine/GameConsole.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using GameEngine;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace GameEngine
{
    public static class GameConsole
    {
		static int _row = 0;
		public static void Clear()
		{
			_row = 0;
		}

        public static void WriteLine(object o)
        {
			Engine.Instance.GraphicsUtils.AddText(new Vector2(21, _row * 18 + 101), o.ToString(), Justify.MIDDLE_LEFT, Color.Black);
			Engine.Instance.GraphicsUtils.AddText(new Vector2(20, _row * 18 + 100), o.ToString(), Justify.MIDDLE_LEFT, Color.White);
			_row++;
        }

		public static void WriteLine(Vector3 vec)
		{
			vec.X = (float)Math.Round(vec.X, 3);
			vec.Y = (float)Math.Round(vec.Y, 3);
			vec.Z = (float)Math.Round(vec.Z, 3);
			WriteLine(vec.ToString());
		}
	}
}


================================================
FILE: Engine/GameEngine.csproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProductVersion>8.0.30703</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{F66B2F9A-AF38-40F9-A094-522C823D04EE}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>GameEngine</RootNamespace>
    <AssemblyName>GameEngine</AssemblyName>
    <FileAlignment>512</FileAlignment>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <PlatformTarget>x86</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\WindowsGL\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <PlatformTarget>x86</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\WindowsGL\Release\</OutputPath>
    <DefineConstants>TRACE;WINDOWS</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup>
    <ApplicationIcon>Icon.ico</ApplicationIcon>
  </PropertyGroup>
  <PropertyGroup>
    <StartupObject />
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="AverageValueVector3.cs" />
    <Compile Include="ChaseCamera.cs" />
    <Compile Include="Engine.cs" />
    <Compile Include="FixedChaseCamera.cs" />
    <Compile Include="FPSCamera.cs" />
    <Compile Include="FPSCounter.cs" />
    <Compile Include="GameConsole.cs" />
    <Compile Include="GameObject.cs" />
    <Compile Include="GraphicsUtilities.cs" />
    <Compile Include="ICamera.cs" />
    <Compile Include="IDrawableObject.cs" />
    <Compile Include="IGameScreen.cs" />
    <Compile Include="InputProvider.cs" />
    <Compile Include="IWorld.cs" />
    <Compile Include="ParticleSystem\ParticleEmitter.cs" />
    <Compile Include="ParticleSystem\ParticleSettings.cs" />
    <Compile Include="ParticleSystem\ParticleSystem.cs" />
    <Compile Include="ParticleSystem\ParticleVertex.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="ScreenEffects.cs" />
    <Compile Include="SimpleCamera.cs" />
    <Compile Include="SkyBox.cs" />
    <Compile Include="SoundEngine2.cs" />
    <Compile Include="Utility.cs" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="MonoGame.Framework, Version=3.1.2.0, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\lib\MonoGame.Framework.dll</HintPath>
    </Reference>
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="Icon.ico" />
  </ItemGroup>
  <ItemGroup />
  <ItemGroup>
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="..\packages\MonoGame.Binaries.3.2.0\build\net40\MonoGame.Binaries.targets" Condition="Exists('..\packages\MonoGame.Binaries.3.2.0\build\net40\MonoGame.Binaries.targets')" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

================================================
FILE: Engine/GameObject.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace GameEngine
{
    public abstract class GameObject
    {

        protected Vector3 _position, _lastPosition, _size, _orientation;
        protected float _velocity;
        protected bool _visible;
        protected bool _lockToGround;
        
        public GameObject()
        {
            _visible = true;
        }

        public Vector3 Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public Vector3 Orientation
        {
            get { return _orientation; }
            set { _orientation = value; }
        }

        public Vector3 Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public float Velocity
        {
            get { return _velocity; }
            set { _velocity = value; }
        }

        public bool Visible
        {
            get { return _visible; }
            set { _visible = value; }
        }

        public bool LockToGround
        {
            get { return _lockToGround; }
            set { _lockToGround = value; }
        }

        public void SetRotation(float rotation)
        {
            _orientation.X = rotation;
        }

        public void MoveForward()
        {
            _lastPosition = _position;
            _position.X -= (float)((Math.Sin(_orientation.X) * Math.Cos(_orientation.Y)) * _velocity);
            _position.Z -= (float)((Math.Cos(_orientation.X) * Math.Cos(_orientation.Y)) * _velocity);
            if (!_lockToGround)
                _position.Y -= _orientation.Y * _velocity;
        }

        public Vector3 GetLookAt(float distance)
        {
            Vector3 lookAt = _position;
            lookAt.X -= (float)((Math.Sin(_orientation.X) * Math.Cos(_orientation.Y)) * distance);
            lookAt.Z -= (float)((Math.Cos(_orientation.X) * Math.Cos(_orientation.Y)) * distance);
            lookAt.Y -= _orientation.Y * distance;
            return lookAt;
        }

        public Vector3 GetLookAt(Vector3 orientation, float distance)
        {
            Vector3 lookAt = _position;
            lookAt.X -= (float)((Math.Sin(orientation.X) * Math.Cos(orientation.Y)) * distance);
            lookAt.Z -= (float)((Math.Cos(orientation.X) * Math.Cos(orientation.Y)) * distance);
            lookAt.Y -= orientation.Y * distance;
            return lookAt;
        }

        public void Strafe(float amount)
        {
            _position.X += (float)(Math.Cos(_orientation.X) * amount);
            _position.Z -= (float)(Math.Sin(_orientation.X) * amount);
        }

        public Matrix WorldTransform
        {
            get
            {
                Matrix world = Matrix.CreateFromYawPitchRoll(_orientation.X, -_orientation.Y, _orientation.Z);
                world *= Matrix.CreateScale(_size);
                world *= Matrix.CreateTranslation(_position);
                return world;
            }
        }
      
        
        /// <summary>
        /// Moves the camera. The dx, dy, and dz parameters determine how
        /// far to move the camera forwards, upwards, and sideways.
        /// </summary>
        /// <param name="dx">Sideways movement amount.</param>
        /// <param name="dy">Upwards movement amount.</param>
        /// <param name="dz">Forwads movement amount.</param>
        public void Move(float dx, float dy, float dz)
        {
            _position.X += dx;
            _position.Y += dy;
            _position.Z += dz;
        }

        /// <summary>
        /// Moves the camera along the given direction.
        /// </summary>
        /// <param name="direction">The direction to move.</param>
        /// <param name="velocity">How far to move along direction.</param>
        public void Move(Vector3 direction, float amount)
        {
            _position += direction * amount;
        }

        public void Rotate(float amount)
        {
            _orientation.X += amount;
        }

        public void Pitch(float amount)
        {
            _orientation.Y += amount;
        }
        

        public virtual Vector3 GetCameraPosition()
        {
            return _position;
        }

        public BoundingSphere BoundingSphere
        {
            get
            {
                return new BoundingSphere(_position, _size.X);
            }
        }

        public abstract void Update(GameTime gameTime);
        public abstract void Render();

        public virtual void OnPlayerSelect() { }

    }
}


================================================
FILE: Engine/GraphicsUtilities.cs
================================================
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace GameEngine
{
    /// <summary>
    /// Used for text justification.
    /// </summary>
    public enum Justify
    {
        TOP_LEFT,
        TOP_CENTER,
        TOP_RIGHT,
        MIDDLE_LEFT,
        MIDDLE_CENTER,
        MIDDLE_RIGHT,
        BOTTOM_LEFT,
        BOTTOM_CENTER,
        BOTTOM_RIGHT
    }


    /// <summary>
    /// Type of shape to draw.
    /// </summary>
    public enum ShapeType
    {
        Cube
    }

    /// <summary>
    /// GraphicsUtilities
    ///   DrawableGameComponent for debug-graphics functionality.
    ///   Currently supports 3D lines, text, and basic solid shapes.
    ///   Registers self as service provider - IGraphicsUtilitiesService.
    ///   
    /// To use:
    ///   Create an instance of GraphicsUtilities
    ///   Add it to the list of components
    ///   Set its view/projection matrices every frame
    ///   Add lines/text/shapes every frame
    /// 
    /// </summary>
    public class GraphicsUtilities : IDrawableObject
    {
        #region Creation / Initialization
        public GraphicsUtilities(SpriteFont font)
        {
            CreateLineEffect();
            CreateShapeEffect();
            CreateCube();

			mFont1 = font;
            mSpriteBatch = new SpriteBatch(Engine.Instance.Device);

        }

        public void Update(GameTime gameTime)
        {
			if (Engine.Instance.Camera == null) return;
            SetViewMatrix(Engine.Instance.Camera.View);
            SetProjectionMatrix(Engine.Instance.Camera.Projection);
        }
       
        /// <summary>
        /// Draw utility graphics waiting to be rendered this pass.
        /// </summary>
        public void Draw()
        {
					Engine.Instance.Device.DepthStencilState = DepthStencilState.Default;
            // Draw shapes
            if (sShapeList.Count > 0)
            {
                int nbrPrimitives = 0;
                foreach (ShapeData shapeData in sShapeList)
                {

                    switch (shapeData.mType)
                    {
                        case ShapeType.Cube:
							Engine.Instance.Device.SetVertexBuffer(mCubeVertexBuffer);
                            nbrPrimitives = 12;
							Engine.Instance.Device.RasterizerState = RasterizerState.CullClockwise;
                            break;
                    }

                    
                    mBasicShapeEffect.DiffuseColor = shapeData.mColor.ToVector3() * 0.5f;
                    mBasicShapeEffect.SpecularColor = shapeData.mColor.ToVector3();

                    mBasicShapeEffect.TextureEnabled = false;

                    mBasicShapeEffect.World = shapeData.mWorldMatrix;
                    mBasicShapeEffect.View = mViewMatrix;
                    mBasicShapeEffect.Projection = mProjectionMatrix;
                    
                    foreach (EffectPass pass in mBasicShapeEffect.CurrentTechnique.Passes)
                    {
						pass.Apply();
                        Engine.Instance.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, nbrPrimitives);
                    }
                }
            }
            ClearShapes();
            

            // Draw lines
            if (sLinesList.Count > 0)
            {
				mLineVertexBuffer = new VertexBuffer(Engine.Instance.Device, typeof(VertexPositionColor), sLinesList.Count, BufferUsage.WriteOnly);

                mLineVertexBuffer.SetData<VertexPositionColor>(sLinesList.ToArray());
                Engine.Instance.Device.SetVertexBuffer(mLineVertexBuffer);

                mBasicLineEffect.View = mViewMatrix;
                mBasicLineEffect.Projection = mProjectionMatrix;

                foreach (EffectPass pass in mBasicLineEffect.CurrentTechnique.Passes)
                {
                    pass.Apply();
                    Engine.Instance.Device.DrawPrimitives(PrimitiveType.LineList, 0, sLinesList.Count / 2);
                }
            }
            ClearLines();
        }

        public void DrawText()
        {
            // Draw text
            if (sTextList.Count > 0)
            {
                mSpriteBatch.Begin();
                foreach (TextData textData in sTextList)
                {
                    Vector2 screenPos = new Vector2(textData.mPos.X, textData.mPos.Y);
                    if (!textData.mIsTransformed)
                    {
                        // If text was specified in 3D, transform it to 2D coordinates
                        Vector3 transformed = Engine.Instance.Device.Viewport.Project(textData.mPos,
                                                                              mProjectionMatrix,
                                                                              mViewMatrix,
                                                                              Matrix.Identity);

                        // Don't draw text for positions behind the camera
                        if (transformed.Z < 0.0f)
                        {
                            continue;
                        }

                        screenPos.X = transformed.X;
                        screenPos.Y = transformed.Y;
                    }

                    // Draw each string
                    JustifyText(mFont1, textData.mText, textData.mJustify, screenPos, out screenPos);
                    mSpriteBatch.DrawString(mFont1, textData.mText, screenPos, textData.mColor);
                }
                mSpriteBatch.End();
            }
            ClearText();
        }

        #endregion


        #region Utilities (Line/Text/Object drawing)

        public void AddCube(Matrix worldTransform, Color color)
        {
            if (sShapeList.Count >= MAX_SHAPES)
            {
                return;
            }
            ShapeData shapeData = new ShapeData();
            shapeData.mType = ShapeType.Cube;
            shapeData.mWorldMatrix = worldTransform;
            shapeData.mColor = color;
            shapeData.mTexture = null;
            sShapeList.Add(shapeData);
        }


        /// <summary>
        /// Add 3D line.
        /// </summary>
        /// <param name="startPos">3D world-space start position</param>
        /// <param name="endPos">3D world-space end position</param>
        /// <param name="color">Color of line</param>
        public void AddLine(Vector3 startPos, Vector3 endPos, Color color)
        {
            if (sLinesList.Count >= MAX_LINES * 2)
            {
                return;
            }
            VertexPositionColor lineVert = new VertexPositionColor();
            lineVert.Position = startPos;
            lineVert.Color = color;
            sLinesList.Add(lineVert);
            lineVert.Position = endPos;
            lineVert.Color = color;
            sLinesList.Add(lineVert);
        }


        /// <summary>
        /// Add text at 2D position.
        /// </summary>
        /// <param name="pos">XY screen coordinates (pixels)</param>
        /// <param name="text">Text to draw</param>
        /// <param name="color">Color of text</param>
        public void AddText(Vector2 pos, String text, Justify justify, Color color)
        {
            if (sTextList.Count >= MAX_TEXT_LINES)
            {
                return;
            }

            TextData textData = new TextData();
            textData.mPos.X = pos.X;
            textData.mPos.Y = pos.Y;
            textData.mPos.Z = 0.0f;
            textData.mText = text;
            textData.mColor = color;
            textData.mJustify = justify;
            textData.mIsTransformed = true;
            sTextList.Add(textData);
        }


        /// <summary>
        /// Add text at 3D position.
        /// </summary>
        /// <param name="worldPos">3D world-space position for text</param>
        /// <param name="text">Text to draw</param>
        /// <param name="color">Color of text</param>
        public void AddText(Vector3 worldPos, String text, Justify justify, Color color)
        {
            if (sTextList.Count >= MAX_TEXT_LINES)
            {
                return;
            }

            TextData textData = new TextData();
            textData.mPos = worldPos;
            textData.mText = text;
            textData.mColor = color;
            textData.mJustify = justify;
            textData.mIsTransformed = false;
            sTextList.Add(textData);
        }


        /// <summary>
        /// Add coordinate axis using the specified transformation.
        /// </summary>
        /// <param name="worldTransform">World transformation matrix</param>
        /// <param name="scale">Scale on drawn lines (1.0 units by default).</param>
        public void AddAxis(Matrix worldTransform, float scale)
        {
            AddLine(worldTransform.Translation, worldTransform.Translation + worldTransform.Forward, Color.Red);
            AddLine(worldTransform.Translation, worldTransform.Translation + worldTransform.Left, Color.Green);
            AddLine(worldTransform.Translation, worldTransform.Translation + worldTransform.Up, Color.Blue);
        }


        /// <summary>
        /// Add a cube using lines.
        /// </summary>
        /// <param name="worldTransform">World transformation matrix, specifies the center of the cube.</param>
        /// <param name="color">Color</param>
        public void AddWireframeCube(Matrix worldTransform, Color color)
        {
            Vector3 forwardVector = worldTransform.Forward / 2.0f;
            Vector3 leftVector = worldTransform.Left / 2.0f;
            Vector3 upVector = worldTransform.Up / 2.0f;

            Vector3 centerPosition = worldTransform.Translation;
            Vector3 forwardLeftUp = centerPosition + forwardVector + leftVector + upVector;
            Vector3 forwardRightUp = centerPosition + forwardVector - leftVector + upVector;
            Vector3 backwardLeftUp = centerPosition - forwardVector + leftVector + upVector;
            Vector3 backwardRightUp = centerPosition - forwardVector - leftVector + upVector;

            Vector3 forwardLeftDown = centerPosition + forwardVector + leftVector - upVector;
            Vector3 forwardRightDown = centerPosition + forwardVector - leftVector - upVector;
            Vector3 backwardLeftDown = centerPosition - forwardVector + leftVector - upVector;
            Vector3 backwardRightDown = centerPosition - forwardVector - leftVector - upVector;

            // Draw top
            AddLine(forwardLeftUp, forwardRightUp, color);
            AddLine(forwardRightUp, backwardRightUp, color);
            AddLine(backwardRightUp, backwardLeftUp, color);
            AddLine(backwardLeftUp, forwardLeftUp, color);

            // Draw bottom
            AddLine(forwardLeftDown, forwardRightDown, color);
            AddLine(forwardRightDown, backwardRightDown, color);
            AddLine(backwardRightDown, backwardLeftDown, color);
            AddLine(backwardLeftDown, forwardLeftDown, color);

            // Draw sides
            AddLine(forwardLeftUp, forwardLeftDown, color);
            AddLine(forwardRightUp, forwardRightDown, color);
            AddLine(backwardRightUp, backwardRightDown, color);
            AddLine(backwardLeftUp, backwardLeftDown, color);
        }


        /// <summary>
        /// Add a square grid using lines.
        /// </summary>
        /// <param name="worldTransform">World transformation matrix, specifies the center of the grid.</param>
        /// <param name="numRows">Number of rows (and columns).</param>
        /// <param name="color">Color.</param>
        public void AddSquareGrid(Matrix worldTransform, int numRows, Color color)
        {
            if (0 < numRows)
            {
                float scale = worldTransform.Forward.Length();
                Vector3 forwardVector = worldTransform.Forward / 2.0f;
                Vector3 leftVector = worldTransform.Left / 2.0f;
                Vector3 backwardsNormalizedVector = -forwardVector / forwardVector.Length();
                Vector3 rightNormalizedVector = -leftVector / leftVector.Length();

                Vector3 centerPosition = worldTransform.Translation;
                Vector3 forwardLeft = centerPosition + forwardVector + leftVector;
                Vector3 forwardRight = centerPosition + forwardVector - leftVector;
                Vector3 backwardLeft = centerPosition - forwardVector + leftVector;
                Vector3 backwardRight = centerPosition - forwardVector - leftVector;

                // Draw outline of the grid
                AddLine(forwardLeft, forwardRight, color);
                AddLine(forwardRight, backwardRight, color);
                AddLine(backwardRight, backwardLeft, color);
                AddLine(backwardLeft, forwardLeft, color);

                // Draw interior grid lines
                float stepSize = 1.0f / (float)(numRows);
                for (int ii = 1; ii < numRows; ++ii)
                {
                    float percentageAcross = (float)(ii) * stepSize;
                    // Front-to-back line
                    AddLine(forwardLeft + (rightNormalizedVector * percentageAcross * scale),
                              backwardLeft + (rightNormalizedVector * percentageAcross * scale),
                              color);

                    // Left-to-right line
                    AddLine(forwardLeft + (backwardsNormalizedVector * percentageAcross * scale),
                              forwardRight + (backwardsNormalizedVector * percentageAcross * scale),
                              color);
                }
            }
        }
        #endregion


        #region Data Access (used to set view/projection matrices)

        public void SetViewMatrix(Matrix view)
        {
            mViewMatrix = view;
        }

        public void SetProjectionMatrix(Matrix proj)
        {
            mProjectionMatrix = proj;
        }

        /// <summary>
        /// Clear list of shapes waiting to be rendered.
        /// </summary>
        public void ClearShapes()
        {
            sShapeList.Clear();
        }

        /// <summary>
        /// Clear list of lines waiting to be rendered.
        /// </summary>
        public void ClearLines()
        {
            sLinesList.Clear();
        }


        /// <summary>
        /// Clear list of text waiting to be rendered.
        /// </summary>
        public void ClearText()
        {
            sTextList.Clear();
        }
        #endregion


        #region Private Data & Methods

        /// <summary>
        /// Justify text based on enumerated value.
        /// </summary>
        private void JustifyText(SpriteFont font, String text, Justify justify, Vector2 inputPos, out Vector2 resultPos)
        {
            Vector2 textSize = font.MeasureString(text);

            // Default text to upper-left
            resultPos = inputPos;

            switch (justify)
            {
                case Justify.TOP_LEFT:
                    break;

                case Justify.TOP_CENTER:
                    resultPos.X -= (textSize.X / 2);
                    break;

                case Justify.TOP_RIGHT:
                    resultPos.X -= textSize.X;
                    break;

                case Justify.MIDDLE_LEFT:
                    resultPos.Y -= (textSize.Y / 2);
                    break;

                case Justify.MIDDLE_CENTER:
                    resultPos.X -= (textSize.X / 2);
                    resultPos.Y -= (textSize.Y / 2);
                    break;

                case Justify.MIDDLE_RIGHT:
                    resultPos.X -= textSize.X;
                    resultPos.Y -= (textSize.Y / 2);
                    break;

                case Justify.BOTTOM_LEFT:
                    resultPos.Y -= textSize.Y;
                    break;

                case Justify.BOTTOM_CENTER:
                    resultPos.X -= (textSize.X / 2);
                    resultPos.Y -= textSize.Y;
                    break;

                case Justify.BOTTOM_RIGHT:
                    resultPos.X -= textSize.X;
                    resultPos.Y -= textSize.Y;
                    break;
            }
        }


        /// <summary>
        /// Create the BasicEffect to be used by Lines.
        /// </summary>
        private void CreateLineEffect()
        {
            mBasicLineEffect = new BasicEffect(Engine.Instance.Device);
            mBasicLineEffect.VertexColorEnabled = true;
        }


        /// <summary>
        /// Create the BasicEffect to be used by shapes.
        /// </summary>
        private void CreateShapeEffect()
        {
            mBasicShapeEffect = new BasicEffect(Engine.Instance.Device);
            mBasicShapeEffect.Alpha = 1.0f;
            mBasicShapeEffect.DiffuseColor = new Vector3(0.5f, 0.5f, 0.5f);
            mBasicShapeEffect.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
            mBasicShapeEffect.SpecularPower = 3.0f;
            mBasicShapeEffect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);

            mBasicShapeEffect.DirectionalLight0.Enabled = true;
            mBasicShapeEffect.DirectionalLight0.DiffuseColor = Vector3.One;
            mBasicShapeEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f));
            mBasicShapeEffect.DirectionalLight0.SpecularColor = Vector3.One;

            mBasicShapeEffect.DirectionalLight1.Enabled = true;
            mBasicShapeEffect.DirectionalLight1.DiffuseColor = new Vector3(0.5f, 0.5f, 0.5f);
            mBasicShapeEffect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f));
            mBasicShapeEffect.DirectionalLight1.SpecularColor = new Vector3(0.5f, 0.5f, 0.5f);

            mBasicShapeEffect.LightingEnabled = true;

            
        }


        /// <summary>
        /// Create vertices and vertex buffer for drawing a solid cube.
        /// </summary>
        private void CreateCube()
        {
            mCubeVertices = new VertexPositionNormalTexture[36];

            Vector3 topLeftFront = new Vector3(-0.5f, 0.5f, 0.5f);
            Vector3 bottomLeftFront = new Vector3(-0.5f, -0.5f, 0.5f);
            Vector3 topRightFront = new Vector3(0.5f, 0.5f, 0.5f);
            Vector3 bottomRightFront = new Vector3(0.5f, -0.5f, 0.5f);
            Vector3 topLeftBack = new Vector3(-0.5f, 0.5f, -0.5f);
            Vector3 topRightBack = new Vector3(0.5f, 0.5f, -0.5f);
            Vector3 bottomLeftBack = new Vector3(-0.5f, -0.5f, -0.5f);
            Vector3 bottomRightBack = new Vector3(0.5f, -0.5f, -0.5f);

            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
            Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

            Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f);
            Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);
            Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f);
            Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f);


            // Front face.
            mCubeVertices[0] = new VertexPositionNormalTexture(topLeftFront, frontNormal, textureTopLeft);
            mCubeVertices[1] = new VertexPositionNormalTexture(bottomLeftFront, frontNormal, textureBottomLeft);
            mCubeVertices[2] = new VertexPositionNormalTexture(topRightFront, frontNormal, textureTopRight);
            mCubeVertices[3] = new VertexPositionNormalTexture(bottomLeftFront, frontNormal, textureBottomLeft);
            mCubeVertices[4] = new VertexPositionNormalTexture(bottomRightFront, frontNormal, textureBottomRight);
            mCubeVertices[5] = new VertexPositionNormalTexture(topRightFront, frontNormal, textureTopRight);

            // Back face.
            mCubeVertices[6] = new VertexPositionNormalTexture(topLeftBack, backNormal, textureTopRight);
            mCubeVertices[7] = new VertexPositionNormalTexture(topRightBack, backNormal, textureTopLeft);
            mCubeVertices[8] = new VertexPositionNormalTexture(bottomLeftBack, backNormal, textureBottomRight);
            mCubeVertices[9] = new VertexPositionNormalTexture(bottomLeftBack, backNormal, textureBottomRight);
            mCubeVertices[10] = new VertexPositionNormalTexture(topRightBack, backNormal, textureTopLeft);
            mCubeVertices[11] = new VertexPositionNormalTexture(bottomRightBack, backNormal, textureBottomLeft);

            // Top face.
            mCubeVertices[12] = new VertexPositionNormalTexture(topLeftFront, topNormal, textureBottomLeft);
            mCubeVertices[13] = new VertexPositionNormalTexture(topRightBack, topNormal, textureTopRight);
            mCubeVertices[14] = new VertexPositionNormalTexture(topLeftBack, topNormal, textureTopLeft);
            mCubeVertices[15] = new VertexPositionNormalTexture(topLeftFront, topNormal, textureBottomLeft);
            mCubeVertices[16] = new VertexPositionNormalTexture(topRightFront, topNormal, textureBottomRight);
            mCubeVertices[17] = new VertexPositionNormalTexture(topRightBack, topNormal, textureTopRight);

            // Bottom face. 
            mCubeVertices[18] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
            mCubeVertices[19] = new VertexPositionNormalTexture(bottomLeftBack, bottomNormal, textureBottomLeft);
            mCubeVertices[20] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
            mCubeVertices[21] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
            mCubeVertices[22] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
            mCubeVertices[23] = new VertexPositionNormalTexture(bottomRightFront, bottomNormal, textureTopRight);

            // Left face.
            mCubeVertices[24] = new VertexPositionNormalTexture(topLeftFront, leftNormal, textureTopRight);
            mCubeVertices[25] = new VertexPositionNormalTexture(bottomLeftBack, leftNormal, textureBottomLeft);
            mCubeVertices[26] = new VertexPositionNormalTexture(bottomLeftFront, leftNormal, textureBottomRight);
            mCubeVertices[27] = new VertexPositionNormalTexture(topLeftBack, leftNormal, textureTopLeft);
            mCubeVertices[28] = new VertexPositionNormalTexture(bottomLeftBack, leftNormal, textureBottomLeft);
            mCubeVertices[29] = new VertexPositionNormalTexture(topLeftFront, leftNormal, textureTopRight);

            // Right face. 
            mCubeVertices[30] = new VertexPositionNormalTexture(topRightFront, rightNormal, textureTopLeft);
            mCubeVertices[31] = new VertexPositionNormalTexture(bottomRightFront, rightNormal, textureBottomLeft);
            mCubeVertices[32] = new VertexPositionNormalTexture(bottomRightBack, rightNormal, textureBottomRight);
            mCubeVertices[33] = new VertexPositionNormalTexture(topRightBack, rightNormal, textureTopRight);
            mCubeVertices[34] = new VertexPositionNormalTexture(topRightFront, rightNormal, textureTopLeft);
            mCubeVertices[35] = new VertexPositionNormalTexture(bottomRightBack, rightNormal, textureBottomRight);

			mCubeVertexBuffer = new VertexBuffer(Engine.Instance.Device, typeof(VertexPositionNormalTexture), mCubeVertices.Length,
												 BufferUsage.WriteOnly);

            mCubeVertexBuffer.SetData<VertexPositionNormalTexture>(mCubeVertices);
        }

        

        // Internal data types
        struct TextData
        {
            public Vector3 mPos;
            public String mText;
            public Color mColor;
            public Justify mJustify;
            public bool mIsTransformed;
        }

        struct ShapeData
        {
            public ShapeType mType;
            public Matrix mWorldMatrix;
            public Color mColor;
            public Texture2D mTexture;
        }

        Matrix mViewMatrix = Matrix.Identity;
        Matrix mProjectionMatrix = Matrix.CreateLookAt(Vector3.One, Vector3.Zero, Vector3.Up);

        // Lists of data
        private List<VertexPositionColor> sLinesList = new List<VertexPositionColor>();
        private List<TextData> sTextList = new List<TextData>();
        private List<ShapeData> sShapeList = new List<ShapeData>();

        // Shape-drawing data
        BasicEffect mBasicShapeEffect;
        VertexPositionNormalTexture[] mCubeVertices;
        VertexBuffer mCubeVertexBuffer;
        const int MAX_SHAPES = 200;

        // Line-drawing data
        VertexBuffer mLineVertexBuffer;
        BasicEffect mBasicLineEffect;
        const int MAX_LINES = 1024;

        // Text-drawing data
        SpriteBatch mSpriteBatch;
        SpriteFont mFont1;
        const int MAX_TEXT_LINES = 50;
        #endregion

    }
}


================================================
FILE: Engine/ICamera.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GameEngine;

namespace GameEngine
{
    public interface ICamera
    {
        /// <summary>
        /// Returns the camera's current view matrix.
        /// </summary>
        Matrix View { get; }

        /// <summary>
        /// Returns the camera's current perspective projection matrix.
        /// </summary>
        Matrix Projection { get; }

        void FollowObject(GameObject obj);

        void Update(GameTime time);

        Vector3 Position { get;}

        void SetPosition(Vector3 position);
    }
}


================================================
FILE: Engine/IDrawableObject.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace GameEngine
{
    public interface IDrawableObject
    {
        void Update(GameTime gameTime);
        void Draw();        
    }
}


================================================
FILE: Engine/IGameScreen.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;

namespace GameEngine
{
    public interface IGameScreen : IDrawableObject
    {
    }
}


================================================
FILE: Engine/IWorld.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace GameEngine
{
    public interface IWorld : IDrawableObject
    {
        float GetHeightAtPoint(Vector3 position);
        void Reset();
    }
}


================================================
FILE: Engine/InputProvider.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Diagnostics;

namespace GameEngine
{
    public enum Actions
    {
        MoveForwardsPrimary,
        MoveForwardsAlternate,
        MoveBackwardsPrimary,
        MoveBackwardsAlternate,
        StrafeRightPrimary,
        StrafeRightAlternate,
        StrafeLeftPrimary,
        StrafeLeftAlternate,
        RunPrimary,
        RunAlternate,
        CrouchPrimary,
        CrouchAlternate,
        JumpPrimary,
        JumpAlternate
    };

    public enum MouseInputMode
    {
        FPS,
        FreeMouse
    }

    public class InputProvider : GameComponent
    {
        private GamePadState _gamePadState, _previousGamePadState;

        private KeyboardState _keyboardState, _previousKeyboardState;
        
        private const float SENSITIVITY = 1.0f;
        
        private float _perFrameMultiplier;
        

        public InputProvider(Game game)
            : base(game)
        {
            
        }

        public GamePadState GamePadState
        {
            get { return _gamePadState; }
        }


        public override void Update(GameTime gameTime)
        {
            float frameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            _perFrameMultiplier = frameTime * SENSITIVITY;
            
            _previousKeyboardState = _keyboardState;
            _previousGamePadState = _gamePadState;
            _keyboardState = Keyboard.GetState();
            _gamePadState = GamePad.GetState(PlayerIndex.One);

            if (_previousKeyboardState == null)
                _previousKeyboardState = _keyboardState;
            
            base.Update(gameTime);
        }

        private Vector2 GetScreenCenter()
        {
            GameWindow window = Engine.Instance.Game.Window;
            return new Vector2(window.ClientBounds.Width / 2, window.ClientBounds.Height / 2);
        }

        public float MoveForward
        {
            get
            {
                if (_gamePadState.ThumbSticks.Left.Y != 0)
                    return _gamePadState.ThumbSticks.Left.Y * _perFrameMultiplier;
                else if (_keyboardState.IsKeyDown(Keys.W))
                    return 1.0f * _perFrameMultiplier;
                else if (_keyboardState.IsKeyDown(Keys.S))
                    return -1.0f * _perFrameMultiplier;
                else
                    return 0.0f;
            }
        }
        public float Strafe
        {
            get
            {
                if (_gamePadState.ThumbSticks.Left.X != 0)
                    return _gamePadState.ThumbSticks.Left.X * _perFrameMultiplier;
                else if (_keyboardState.IsKeyDown(Keys.A))
                    return -1.0f * _perFrameMultiplier;
                else if (_keyboardState.IsKeyDown(Keys.D))
                    return 1.0f * _perFrameMultiplier;
                else
                    return 0.0f;
            }
        }

        public bool WasPressed(Keys key)
        {
            return _previousKeyboardState.IsKeyDown(key) && !_keyboardState.IsKeyDown(key);
        }

        public bool WasPressed(Buttons button)
        {
            return _previousGamePadState.IsButtonDown(button) && !_gamePadState.IsButtonDown(button);
        }

        public bool IsKeyDown(Keys key)
        {
            return _keyboardState.IsKeyDown(key);
        }
    }
}


================================================
FILE: Engine/ParticleSystem/ParticleEmitter.cs
================================================
#region File Description
//-----------------------------------------------------------------------------
// ParticleEmitter.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
#endregion

namespace GameEngine
{
    /// <summary>
    /// Helper for objects that want to leave particles behind them as they
    /// move around the world. This emitter implementation solves two related
    /// problems:
    /// 
    /// If an object wants to create particles very slowly, less than once per
    /// frame, it can be a pain to keep track of which updates ought to create
    /// a new particle versus which should not.
    /// 
    /// If an object is moving quickly and is creating many particles per frame,
    /// it will look ugly if these particles are all bunched up together. Much
    /// better if they can be spread out along a line between where the object
    /// is now and where it was on the previous frame. This is particularly
    /// important for leaving trails behind fast moving objects such as rockets.
    /// 
    /// This emitter class keeps track of a moving object, remembering its
    /// previous position so it can calculate the velocity of the object. It
    /// works out the perfect locations for creating particles at any frequency
    /// you specify, regardless of whether this is faster or slower than the
    /// game update rate.
    /// </summary>
    public class ParticleEmitter
    {
        #region Fields

        public ParticleSystem ParticleSystem { get; set; }
        float _timeBetweenParticles;
        Vector3 _previousPosition;
        float _timeLeftOver;
        public float ParticlesPerSecond;
        public float DumpsPerSecond = 0.2f;

        #endregion

        public float LastDumpTime;
        public bool Enabled = true;
        public List<ParticleSystem> ParticleSystems = new List<ParticleSystem>();

        public static List<ParticleEmitter> AllEmitters = new List<ParticleEmitter>();

        /// <summary>
        /// Constructs a new particle emitter object.
        /// </summary>
        public ParticleEmitter(ParticleSystem particleSystem, float particlesPerSecond, Vector3 initialPosition)
        {
            ParticleSystem = particleSystem;

            _timeBetweenParticles = 1.0f / particlesPerSecond;
            ParticlesPerSecond = particlesPerSecond;
            _previousPosition = initialPosition;
            
            AllEmitters.Add(this);
        }

        public void Update(Vector3 newPosition)
        {
            Update(newPosition, ParticleSystem);
        }

        /// <summary>
        /// Updates the emitter, creating the appropriate number of particles
        /// in the appropriate positions.
        /// </summary>
        public void Update(Vector3 newPosition, ParticleSystem particleSystem)
        {
			float elapsedSeconds = Engine.Instance.FrameTime;
            
            // Work out how much time has passed since the previous update.

            if (elapsedSeconds > 0 && Enabled)
            {
                // Work out how fast we are moving.
                Vector3 velocity = (newPosition - _previousPosition) / elapsedSeconds;

                // If we had any time left over that we didn't use during the
                // previous update, add that to the current elapsed time.
                float timeToSpend = _timeLeftOver + elapsedSeconds;
                
                // Counter for looping over the time interval.
                float currentTime = -_timeLeftOver;

                // Create particles as long as we have a big enough time interval.
                while (timeToSpend > _timeBetweenParticles)
                {
                    currentTime += _timeBetweenParticles;
                    timeToSpend -= _timeBetweenParticles;

                    // Work out the optimal position for this particle. This will produce
                    // evenly spaced particles regardless of the object speed, particle
                    // creation frequency, or game update rate.
                    float mu = currentTime / elapsedSeconds;

                    Vector3 position = Vector3.Lerp(_previousPosition, newPosition, mu);

                    // Create the particle.
                    particleSystem.AddParticle(position, velocity);
                }

                // Store any time we didn't use, so it can be part of the next update.
                _timeLeftOver = timeToSpend;
            }

            _previousPosition = newPosition;
        }

        
    }
}


================================================
FILE: Engine/ParticleSystem/ParticleSettings.cs
================================================
#region File Description
//-----------------------------------------------------------------------------
// ParticleSettings.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace GameEngine
{
    /// <summary>
    /// Settings class describes all the tweakable options used
    /// to control the appearance of a particle system.
    /// </summary>
    public class ParticleSettings
    {
        // Name of the texture used by this particle system.
        public Texture2D Texture = null;


        // Maximum number of particles that can be displayed at one time.
        public int MaxParticles = 100;


        // How long these particles will last.
        public TimeSpan Duration = TimeSpan.FromSeconds(1);


        // If greater than zero, some particles will last a shorter time than others.
        public float DurationRandomness = 0;


        // Controls how much particles are influenced by the velocity of the object
        // which created them. You can see this in action with the explosion effect,
        // where the flames continue to move in the same direction as the source
        // projectile. The projectile trail particles, on the other hand, set this
        // value very low so they are less affected by the velocity of the projectile.
        public float EmitterVelocitySensitivity = 1;


        // Range of values controlling how much X and Z axis velocity to give each
        // particle. Values for individual particles are randomly chosen from somewhere
        // between these limits.
        public float MinHorizontalVelocity = 0;
        public float MaxHorizontalVelocity = 0;


        // Range of values controlling how much Y axis velocity to give each particle.
        // Values for individual particles are randomly chosen from somewhere between
        // these limits.
        public float MinVerticalVelocity = 0;
        public float MaxVerticalVelocity = 0;


        // Direction and strength of the gravity effect. Note that this can point in any
        // direction, not just down! The fire effect points it upward to make the flames
        // rise, and the smoke plume points it sideways to simulate wind.
        public Vector3 Gravity = Vector3.Zero;


        // Controls how the particle velocity will change over their lifetime. If set
        // to 1, particles will keep going at the same speed as when they were created.
        // If set to 0, particles will come to a complete stop right before they die.
        // Values greater than 1 make the particles speed up over time.
        public float EndVelocity = 1;


        // Range of values controlling the particle color and alpha. Values for
        // individual particles are randomly chosen from somewhere between these limits.
        public Color MinColor = Color.White;
        public Color MaxColor = Color.White;


        // Range of values controlling how fast the particles rotate. Values for
        // individual particles are randomly chosen from somewhere between these
        // limits. If both these values are set to 0, the particle system will
        // automatically switch to an alternative shader technique that does not
        // support rotation, and thus requires significantly less GPU power. This
        // means if you don't need the rotation effect, you may get a performance
        // boost from leaving these values at 0.
        public float MinRotateSpeed = 0;
        public float MaxRotateSpeed = 0;


        // Range of values controlling how big the particles are when first created.
        // Values for individual particles are randomly chosen from somewhere between
        // these limits.
        public float MinStartSize = 100;
        public float MaxStartSize = 100;


        // Range of values controlling how big particles become at the end of their
        // life. Values for individual particles are randomly chosen from somewhere
        // between these limits.
        public float MinEndSize = 100;
        public float MaxEndSize = 100;


        // Alpha blending settings.
        public Blend SourceBlend = Blend.SourceAlpha;
        public Blend DestinationBlend = Blend.InverseSourceAlpha;
    }
}


================================================
FILE: Engine/ParticleSystem/ParticleSystem.cs
================================================
#region File Description
//-----------------------------------------------------------------------------
// ParticleSystem.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
#endregion

namespace GameEngine
{
	/// <summary>
	/// The main component in charge of displaying particles.
	/// </summary>
	public abstract class ParticleSystem
	{
		#region Fields


		// Settings class controls the appearance and animation of this particle system.
		ParticleSettings settings = new ParticleSettings();

		// Custom effect for drawing particles. This computes the particle
		// animation entirely in the vertex shader: no per-particle CPU work required!
		Effect particleEffect;


		// Shortcuts for accessing frequently changed effect parameters.
		EffectParameter effectViewParameter;
		EffectParameter effectProjectionParameter;
		EffectParameter effectViewportScaleParameter;
		EffectParameter effectTimeParameter;


		// An array of particles, treated as a circular queue.
		ParticleVertex[] particles;


		// A vertex buffer holding our particles. This contains the same data as
		// the particles array, but copied across to where the GPU can access it.
		DynamicVertexBuffer vertexBuffer;


		// Index buffer turns sets of four vertices into particle quads (pairs of triangles).
		IndexBuffer indexBuffer;


		// The particles array and vertex buffer are treated as a circular queue.
		// Initially, the entire contents of the array are free, because no particles
		// are in use. When a new particle is created, this is allocated from the
		// beginning of the array. If more than one particle is created, these will
		// always be stored in a consecutive block of array elements. Because all
		// particles last for the same amount of time, old particles will always be
		// removed in order from the start of this active particle region, so the
		// active and free regions will never be intermingled. Because the queue is
		// circular, there can be times when the active particle region wraps from the
		// end of the array back to the start. The queue uses modulo arithmetic to
		// handle these cases. For instance with a four entry queue we could have:
		//
		//      0
		//      1 - first active particle
		//      2 
		//      3 - first free particle
		//
		// In this case, particles 1 and 2 are active, while 3 and 4 are free.
		// Using modulo arithmetic we could also have:
		//
		//      0
		//      1 - first free particle
		//      2 
		//      3 - first active particle
		//
		// Here, 3 and 0 are active, while 1 and 2 are free.
		//
		// But wait! The full story is even more complex.
		//
		// When we create a new particle, we add them to our managed particles array.
		// We also need to copy this new data into the GPU vertex buffer, but we don't
		// want to do that straight away, because setting new data into a vertex buffer
		// can be an expensive operation. If we are going to be adding several particles
		// in a single frame, it is faster to initially just store them in our managed
		// array, and then later upload them all to the GPU in one single call. So our
		// queue also needs a region for storing new particles that have been added to
		// the managed array but not yet uploaded to the vertex buffer.
		//
		// Another issue occurs when old particles are retired. The CPU and GPU run
		// asynchronously, so the GPU will often still be busy drawing the previous
		// frame while the CPU is working on the next frame. This can cause a
		// synchronization problem if an old particle is retired, and then immediately
		// overwritten by a new one, because the CPU might try to change the contents
		// of the vertex buffer while the GPU is still busy drawing the old data from
		// it. Normally the graphics driver will take care of this by waiting until
		// the GPU has finished drawing inside the VertexBuffer.SetData call, but we
		// don't want to waste time waiting around every time we try to add a new
		// particle! To avoid this delay, we can specify the SetDataOptions.NoOverwrite
		// flag when we write to the vertex buffer. This basically means "I promise I
		// will never try to overwrite any data that the GPU might still be using, so
		// you can just go ahead and update the buffer straight away". To keep this
		// promise, we must avoid reusing vertices immediately after they are drawn.
		//
		// So in total, our queue contains four different regions:
		//
		// Vertices between firstActiveParticle and firstNewParticle are actively
		// being drawn, and exist in both the managed particles array and the GPU
		// vertex buffer.
		//
		// Vertices between firstNewParticle and firstFreeParticle are newly created,
		// and exist only in the managed particles array. These need to be uploaded
		// to the GPU at the start of the next draw call.
		//
		// Vertices between firstFreeParticle and firstRetiredParticle are free and
		// waiting to be allocated.
		//
		// Vertices between firstRetiredParticle and firstActiveParticle are no longer
		// being drawn, but were drawn recently enough that the GPU could still be
		// using them. These need to be kept around for a few more frames before they
		// can be reallocated.

		int firstActiveParticle;
		int firstNewParticle;
		int firstFreeParticle;
		int firstRetiredParticle;


		// Store the current time, in seconds.
		float currentTime;


		// Count how many times Draw has been called. This is used to know
		// when it is safe to retire old particles back into the free list.
		int drawCounter;


		// Shared random number generator.
		static Random random = new Random();


		#endregion

		public static List<ParticleSystem> AllParticleSystems = new List<ParticleSystem>();

		#region Initialization


		/// <summary>
		/// Initializes the component.
		/// </summary>
		public void InitializeSystem()
		{
			InitializeSettings(settings);

			// Allocate the particle array, and fill in the corner fields (which never change).
			particles = new ParticleVertex[settings.MaxParticles * 4];

			for (int i = 0; i < settings.MaxParticles; i++)
			{
				particles[i * 4 + 0].Corner = new Short2(-1, -1);
				particles[i * 4 + 1].Corner = new Short2(1, -1);
				particles[i * 4 + 2].Corner = new Short2(1, 1);
				particles[i * 4 + 3].Corner = new Short2(-1, 1);
			}

			LoadContent();

			AllParticleSystems.Add(this);
		}


		/// <summary>
		/// Derived particle system classes should override this method
		/// and use it to initalize their tweakable settings.
		/// </summary>
		protected abstract void InitializeSettings(ParticleSettings settings);


		/// <summary>
		/// Loads graphics for the particle system.
		/// </summary>
		protected void LoadContent()
		{
			LoadParticleEffect();

			vertexBuffer = new DynamicVertexBuffer(Engine.Instance.Device, ParticleVertex.VertexDeclaration, 
				settings.MaxParticles * 4, BufferUsage.WriteOnly);

			// Create and populate the index buffer.
			ushort[] indices = new ushort[settings.MaxParticles * 6];

			for (int i = 0; i < settings.MaxParticles; i++)
			{
				indices[i * 6 + 0] = (ushort)(i * 4 + 0);
				indices[i * 6 + 1] = (ushort)(i * 4 + 1);
				indices[i * 6 + 2] = (ushort)(i * 4 + 2);

				indices[i * 6 + 3] = (ushort)(i * 4 + 0);
				indices[i * 6 + 4] = (ushort)(i * 4 + 2);
				indices[i * 6 + 5] = (ushort)(i * 4 + 3);
			}

			indexBuffer = new IndexBuffer(Engine.Instance.Device, typeof(ushort), indices.Length, BufferUsage.WriteOnly);

			indexBuffer.SetData(indices);
		}


		/// <summary>
		/// Helper for loading and initializing the particle effect.
		/// </summary>
		void LoadParticleEffect()
		{
			//Effect effect = Engine.Instance.ContentManager.Load<Effect>("Content/ParticleEffect");

			// If we have several particle systems, the content manager will return
			// a single shared effect instance to them all. But we want to preconfigure
			// the effect with parameters that are specific to this particular
			// particle system. By cloning the effect, we prevent one particle system
			// from stomping over the parameter settings of another.

			//particleEffect = new Effect(Engine.Instance.Device, File.ReadAllBytes("Content\\ParticleEffect.mgfx"));
			particleEffect = Engine.Instance.ContentManager.Load<Effect>("Content/ParticleEffect");

			EffectParameterCollection parameters = particleEffect.Parameters;

			// Look up shortcuts for parameters that change every frame.
			effectViewParameter = parameters["View"];
			effectProjectionParameter = parameters["Projection"];
			effectViewportScaleParameter = parameters["ViewportScale"];
			effectTimeParameter = parameters["CurrentTime"];

			// Set the values of parameters that do not change.
			parameters["Duration"].SetValue((float)settings.Duration.TotalSeconds);
			parameters["DurationRandomness"].SetValue(settings.DurationRandomness);
			parameters["Gravity"].SetValue(settings.Gravity);
			parameters["EndVelocity"].SetValue(settings.EndVelocity);
			parameters["MinColor"].SetValue(settings.MinColor.ToVector4());
			parameters["MaxColor"].SetValue(settings.MaxColor.ToVector4());

			parameters["RotateSpeed"].SetValue(
				new Vector2(settings.MinRotateSpeed, settings.MaxRotateSpeed));

			parameters["StartSize"].SetValue(
				new Vector2(settings.MinStartSize, settings.MaxStartSize));

			parameters["EndSize"].SetValue(
				new Vector2(settings.MinEndSize, settings.MaxEndSize));

			parameters["Texture"].SetValue(settings.Texture);
		}


		#endregion

		#region Update and Draw


		/// <summary>
		/// Updates the particle system.
		/// </summary>
		public void Update()
		{
			currentTime += Engine.Instance.FrameTime;

			RetireActiveParticles();
			FreeRetiredParticles();

			// If we let our timer go on increasing for ever, it would eventually
			// run out of floating point precision, at which point the particles
			// would render incorrectly. An easy way to prevent this is to notice
			// that the time value doesn't matter when no particles are being drawn,
			// so we can reset it back to zero any time the active queue is empty.

			if (firstActiveParticle == firstFreeParticle)
				currentTime = 0;

			if (firstRetiredParticle == firstActiveParticle)
				drawCounter = 0;
		}


		/// <summary>
		/// Helper for checking when active particles have reached the end of
		/// their life. It moves old particles from the active area of the queue
		/// to the retired section.
		/// </summary>
		void RetireActiveParticles()
		{
			float particleDuration = (float)settings.Duration.TotalSeconds;

			while (firstActiveParticle != firstNewParticle)
			{
				// Is this particle old enough to retire?
				// We multiply the active particle index by four, because each
				// particle consists of a quad that is made up of four vertices.
				float particleAge = currentTime - particles[firstActiveParticle * 4].Time;

				if (particleAge < particleDuration)
					break;

				// Remember the time at which we retired this particle.
				particles[firstActiveParticle * 4].Time = drawCounter;

				// Move the particle from the active to the retired queue.
				firstActiveParticle++;

				if (firstActiveParticle >= settings.MaxParticles)
					firstActiveParticle = 0;
			}
		}


		/// <summary>
		/// Helper for checking when retired particles have been kept around long
		/// enough that we can be sure the GPU is no longer using them. It moves
		/// old particles from the retired area of the queue to the free section.
		/// </summary>
		void FreeRetiredParticles()
		{
			while (firstRetiredParticle != firstActiveParticle)
			{
				// Has this particle been unused long enough that
				// the GPU is sure to be finished with it?
				// We multiply the retired particle index by four, because each
				// particle consists of a quad that is made up of four vertices.
				int age = drawCounter - (int)particles[firstRetiredParticle * 4].Time;

				// The GPU is never supposed to get more than 2 frames behind the CPU.
				// We add 1 to that, just to be safe in case of buggy drivers that
				// might bend the rules and let the GPU get further behind.
				if (age < 3)
					break;

				// Move the particle from the retired to the free queue.
				firstRetiredParticle++;

				if (firstRetiredParticle >= settings.MaxParticles)
					firstRetiredParticle = 0;
			}
		}


		/// <summary>
		/// Draws the particle system.
		/// </summary>
		public void Render()
		{
			GraphicsDevice device = Engine.Instance.Device;
			
			ICamera camera = Engine.Instance.Camera;
			effectViewParameter.SetValue(camera.View);
			effectProjectionParameter.SetValue(camera.Projection);

			// Restore the vertex buffer contents if the graphics device was lost.
			if (vertexBuffer.IsContentLost)
			{
				vertexBuffer.SetData(particles);
			}

			// If there are any particles waiting in the newly added queue,
			// we'd better upload them to the GPU ready for drawing.
			if (firstNewParticle != firstFreeParticle)
			{
				AddNewParticlesToVertexBuffer();
			}

			// If there are any active particles, draw them now!
			if (firstActiveParticle != firstFreeParticle)
			{
				SetParticleRenderStates();

				// Set an effect parameter describing the viewport size. This is
				// needed to convert particle sizes into screen space point sizes.
				effectViewportScaleParameter.SetValue(new Vector2(0.5f / device.Viewport.AspectRatio, -0.5f));

				// Set an effect parameter describing the current time. All the vertex
				// shader particle animation is keyed off this value.
				effectTimeParameter.SetValue(currentTime);

				// Set the particle vertex and index buffer.
				device.SetVertexBuffer(vertexBuffer);
				device.Indices = indexBuffer;

				// Activate the particle effect.
				foreach (EffectPass pass in particleEffect.CurrentTechnique.Passes)
				{
					pass.Apply();

					if (firstActiveParticle < firstFreeParticle)
					{
						// If the active particles are all in one consecutive range,
						// we can draw them all in a single call.
						device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0,
													 /*firstActiveParticle * 4*/ 0, (firstFreeParticle),
													 firstActiveParticle * 6, (firstFreeParticle - firstActiveParticle) * 2);
					}
					else
					{
						// If the active particle range wraps past the end of the queue
						// back to the start, we must split them over two draw calls.
						device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0,
													 /*firstActiveParticle * 4*/ 0, (settings.MaxParticles),
													 firstActiveParticle * 6, (settings.MaxParticles - firstActiveParticle) * 2);

						if (firstFreeParticle > 0)
						{
							device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0,
														 0, firstFreeParticle * 4,
														 0, firstFreeParticle * 2);
						}
					}
				}

				// Reset some of the renderstates that we changed,
				// so as not to mess up any other subsequent drawing.
				device.DepthStencilState = DepthStencilState.Default;
				device.BlendState = BlendState.Opaque;
			}

			drawCounter++;
		}


		/// <summary>
		/// Helper for uploading new particles from our managed
		/// array to the GPU vertex buffer.
		/// </summary>
		void AddNewParticlesToVertexBuffer()
		{
			int stride = ParticleVertex.SizeInBytes;

			if (firstNewParticle < firstFreeParticle)
			{
				// If the new particles are all in one consecutive range,
				// we can upload them all in a single call.
				vertexBuffer.SetData(firstNewParticle * stride * 4, particles,
									 firstNewParticle * 4,
									 (firstFreeParticle - firstNewParticle) * 4,
									 stride, SetDataOptions.NoOverwrite);
			}
			else
			{
				// If the new particle range wraps past the end of the queue
				// back to the start, we must split them over two upload calls.
				vertexBuffer.SetData(firstNewParticle * stride * 4, particles,
									 firstNewParticle * 4,
									 (settings.MaxParticles - firstNewParticle) * 4,
									 stride, SetDataOptions.NoOverwrite);

				if (firstFreeParticle > 0)
				{
					vertexBuffer.SetData(0, particles,
										 0, firstFreeParticle * 4,
										 stride, SetDataOptions.NoOverwrite);
				}
			}

			// Move the particles we just uploaded from the new to the active queue.
			firstNewParticle = firstFreeParticle;
		}


		#endregion

		#region Public Methods


		


		/// <summary>
		/// Adds a new particle to the system.
		/// </summary>
		public void AddParticle(Vector3 position, Vector3 velocity)
		{
			// Figure out where in the circular queue to allocate the new particle.
			int nextFreeParticle = firstFreeParticle + 1;

			if (nextFreeParticle >= settings.MaxParticles)
				nextFreeParticle = 0;

			// If there are no free particles, we just have to give up.
			if (nextFreeParticle == firstRetiredParticle)
			{
				return;
			}

			// Adjust the input velocity based on how much
			// this particle system wants to be affected by it.
			velocity *= settings.EmitterVelocitySensitivity;

			// Add in some random amount of horizontal velocity.
			float horizontalVelocity = MathHelper.Lerp(settings.MinHorizontalVelocity,
													   settings.MaxHorizontalVelocity,
													   (float)random.NextDouble());

			double horizontalAngle = random.NextDouble() * MathHelper.TwoPi;

			velocity.X += horizontalVelocity * (float)Math.Cos(horizontalAngle);
			velocity.Z += horizontalVelocity * (float)Math.Sin(horizontalAngle);

			// Add in some random amount of vertical velocity.
			velocity.Y += MathHelper.Lerp(settings.MinVerticalVelocity,
										  settings.MaxVerticalVelocity,
										  (float)random.NextDouble());

			// Choose four random control values. These will be used by the vertex
			// shader to give each particle a different size, rotation, and color.
			Color randomValues = new Color((byte)random.Next(255),
										   (byte)random.Next(255),
										   (byte)random.Next(255),
										   (byte)random.Next(255));

			// Fill in the particle vertex structure.
			for (int i = 0; i < 4; i++)
			{
				particles[firstFreeParticle * 4 + i].Position = position;
				particles[firstFreeParticle * 4 + i].Velocity = velocity;
				particles[firstFreeParticle * 4 + i].Random = randomValues;
				particles[firstFreeParticle * 4 + i].Time = currentTime;
			}

			firstFreeParticle = nextFreeParticle;
		}


		#endregion

		void SetParticleRenderStates()
		{
			Engine.Instance.Device.BlendState = BlendState.NonPremultiplied;
			// Set the alpha blend mode.
			//renderState.AlphaBlendEnable = true;
			//renderState.AlphaBlendOperation = BlendFunction.Add;
			//renderState.SourceBlend = settings.SourceBlend;
			//renderState.DestinationBlend = settings.DestinationBlend;

			// Set the alpha test mode.
			//renderState.AlphaTestEnable = true;
			//renderState.AlphaFunction = CompareFunction.Greater;
			//renderState.ReferenceAlpha = 0;

			// Enable the depth buffer (so particles will not be visible through
			// solid objects like the ground plane), but disable depth writes
			// (so particles will not obscure other particles).
			Engine.Instance.Device.DepthStencilState = DepthStencilState.DepthRead;
		}

		public void Clear()
		{
			firstActiveParticle = 0;
			firstNewParticle = 0;
			firstFreeParticle = 0;
			firstRetiredParticle = 0;
		}

		/// <summary>
		/// Sets the camera view and projection matrices
		/// that will be used to draw this particle system.
		/// </summary>
		public void SetCamera(ICamera camera)
		{
			effectViewParameter.SetValue(camera.View);
			effectProjectionParameter.SetValue(camera.Projection);
		}


	}
}


================================================
FILE: Engine/ParticleSystem/ParticleVertex.cs
================================================
#region File Description
//-----------------------------------------------------------------------------
// ParticleVertex.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Graphics.PackedVector;
#endregion

namespace GameEngine
{
    /// <summary>
    /// Custom vertex structure for drawing point sprite particles.
    /// </summary>
    struct ParticleVertex
    {
		// Stores which corner of the particle quad this vertex represents.
		public Short2 Corner;

		// Stores the starting position of the particle.
		public Vector3 Position;

		// Stores the starting velocity of the particle.
		public Vector3 Velocity;

		// Four random values, used to make each particle look slightly different.
		public Color Random;

		// The time (in seconds) at which this particle was created.
		public float Time;


        // Describe the layout of this vertex structure.
		public static readonly VertexDeclaration VertexDeclaration = new VertexDeclaration
		(
			new VertexElement(0, VertexElementFormat.Short2,
								 VertexElementUsage.Position, 0),

			new VertexElement(4, VertexElementFormat.Vector3,
								 VertexElementUsage.Position, 1),

			new VertexElement(16, VertexElementFormat.Vector3,
								  VertexElementUsage.Normal, 0),

			new VertexElement(28, VertexElementFormat.Color,
								  VertexElementUsage.Color, 0),

			new VertexElement(32, VertexElementFormat.Single,
								  VertexElementUsage.TextureCoordinate, 0)
		);


        // Describe the size of this vertex structure.
        public const int SizeInBytes = 36;
    }
}


================================================
FILE: Engine/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Engine")]
[assembly: AssemblyProduct("Engine")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright ©  2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("45cbce85-4b7b-4ec4-b30b-8489311f3329")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]


================================================
FILE: Engine/ScreenEffects.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace GameEngine
{
    public class ScreenEffects : IDrawableObject
    {
        public event EventHandler FadeCompleted;

        private enum FadeDirection
        {
            None,
            FadeIn,
            FadeOut
        }

        private static ScreenEffects _instance;
        public static ScreenEffects Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new ScreenEffects();
                return _instance;
            }
        }

        private float _alpha;
        private FadeDirection _fadeDirection;
        private Texture2D _fadeTexture;
        public float FadeSpeed = 350;

        private ScreenEffects()
        {
            _fadeDirection = FadeDirection.None;

            _fadeTexture = new Texture2D(Engine.Instance.Device, 1, 1);
            _fadeTexture.SetData<Color>(new Color[] { Color.Black });
        }

        /// <summary>
        /// Helper draws a translucent black fullscreen sprite, used for fading
        /// screens in and out, and for darkening the background behind popups.
        /// </summary>
        public void FadeScreen()
        {
            _alpha = 0;
            _fadeDirection = FadeDirection.FadeOut;
        }

        public void UnFadeScreen()
        {
            _alpha = 255;
            _fadeDirection = FadeDirection.FadeIn;
        }

        #region IDrawableObject Members

        public void Update(GameTime gameTime)
        {
            if (_fadeDirection == FadeDirection.FadeOut)
            {
                _alpha += FadeSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (_alpha >= 255)
                    CompleteFade();
            }
            else if (_fadeDirection == FadeDirection.FadeIn)
            {
                _alpha -= FadeSpeed * 0.5f * (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (_alpha <= 0)
                    CompleteFade();
            }

        }

        public void Draw()
        {
            if (_fadeDirection != FadeDirection.None)
            {
                Viewport viewport = Engine.Instance.Device.Viewport;

                Engine.Instance.SpriteBatch.Begin();
					
                Engine.Instance.SpriteBatch.Draw(_fadeTexture,
                                 new Rectangle(0, 0, viewport.Width, viewport.Height),
                                 new Color(255, 255, 255, (byte)_alpha));

                Engine.Instance.SpriteBatch.End();
            }
        }

        private void CompleteFade()
        {
            _fadeDirection = FadeDirection.None;
            if (FadeCompleted != null)
            {
                FadeCompleted(this, null);
            }
        }

        #endregion

        public static Texture2D TakeScreenshot()
        {
            int w = Engine.Instance.Device.PresentationParameters.BackBufferWidth;
            int h = Engine.Instance.Device.PresentationParameters.BackBufferHeight;

			int[] backBuffer = new int[w * h];
			
			//copy into a texture 
			Texture2D texture = new Texture2D(Engine.Instance.Device, w, h, false, Engine.Instance.Device.PresentationParameters.BackBufferFormat);
			texture.SetData(backBuffer);

            return texture;
        }
    }
}


================================================
FILE: Engine/SimpleCamera.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using GameEngine;

namespace GameEngine
{

	public class SimpleCamera : ICamera
	{

		public SimpleCamera()
		{
		}

        public Vector3 RightVec = Vector3.Right;
        public Vector3 UpVector = Vector3.Up;

		/// <summary>
		/// Look at point in world space.
		/// </summary>
		public Vector3 LookAt
		{
			get
			{
				return lookAt;
			}
			set
			{
				lookAt = value;
			}
		}
		private Vector3 lookAt;


		/// <summary>
		/// Position of camera in world space.
		/// </summary>
		public Vector3 Position
		{
			get { return _position; }
			set { _position = value; }
		}
		private Vector3 _position;


		/// <summary>
		/// Perspective field of view.
		/// </summary>
		public float FieldOfView
		{
			get { return fieldOfView; }
			set { fieldOfView = value; }
		}
		private float fieldOfView = MathHelper.ToRadians(45.0f);

		/// <summary>
		/// Distance to the near clipping plane.
		/// </summary>
		public float NearPlaneDistance
		{
			get { return nearPlaneDistance; }
			set { nearPlaneDistance = value; }
		}
		private float nearPlaneDistance = 1.0f;

		/// <summary>
		/// Distance to the far clipping plane.
		/// </summary>
		public float FarPlaneDistance
		{
			get { return farPlaneDistance; }
			set { farPlaneDistance = value; }
		}
        private float farPlaneDistance = 15000.0f;


		/// <summary>
		/// View transform matrix.
		/// </summary>
		public Matrix View
		{
			get { return view; }
		}
		private Matrix view;

		/// <summary>
		/// Projecton transform matrix.
		/// </summary>
		public Matrix Projection
		{
			get { return projection; }
		}
		private Matrix projection;


		/// <summary>
		/// Animates the camera from its current position towards the desired offset
		/// behind the chased object. The camera's animation is controlled by a simple
		/// physical spring attached to the camera and anchored to the desired position.
		/// </summary>
		public void Update(GameTime gameTime)
		{
            view = Matrix.CreateLookAt(this.Position, this.LookAt, UpVector);
			projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView,
				Engine.Instance.AspectRatio, NearPlaneDistance, FarPlaneDistance);
		}

		public void SetPosition(Vector3 position)
		{
			_position = position;
		}

		public void FollowObject(GameObject obj)
		{
		} 
	}
}


================================================
FILE: Engine/SkyBox.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using GameEngine;
using System.IO;

namespace GameEngine
{
    public class SkyBox : IDrawableObject
    {

        Texture2D[] textures = new Texture2D[6];

        public Texture2D[] Textures
        {
            get { return textures; }
            set { textures = value; }
        }
		AlphaTestEffect _effect;

        VertexBuffer vertices;
        IndexBuffer indices;

		float YOffset = 15f;

        public SkyBox()
        {
            LoadResources();
        }

        
        public void LoadResources()
        {
			_effect = new AlphaTestEffect(Engine.Instance.Device);
           
            vertices = new VertexBuffer(Engine.Instance.Device,
                                typeof(VertexPositionTexture),
                                4 * 6,
                                BufferUsage.WriteOnly);

            VertexPositionTexture[] data = new VertexPositionTexture[4 * 6];

            float y = 0.3f;

            #region Define Vertexes
            Vector3 vExtents = new Vector3(1400, 450, 800);
            //back
            data[0].Position = new Vector3(vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[0].TextureCoordinate.X = 1.5f; data[0].TextureCoordinate.Y = 1.0f;
            data[1].Position = new Vector3(vExtents.X, vExtents.Y, -vExtents.Z);
            data[1].TextureCoordinate.X = 1.5f; data[1].TextureCoordinate.Y = 0.0f;
            data[2].Position = new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z);
            data[2].TextureCoordinate.X = 0.5f; data[2].TextureCoordinate.Y = 0.0f;
            data[3].Position = new Vector3(-vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[3].TextureCoordinate.X = 0.5f; data[3].TextureCoordinate.Y = 1.0f;

            //front
            data[4].Position = new Vector3(-vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[4].TextureCoordinate.X = 1.5f; data[4].TextureCoordinate.Y = 1.0f;
            data[5].Position = new Vector3(-vExtents.X, vExtents.Y, vExtents.Z);
            data[5].TextureCoordinate.X = 1.5f; data[5].TextureCoordinate.Y = 0.0f;
            data[6].Position = new Vector3(vExtents.X, vExtents.Y, vExtents.Z);
            data[6].TextureCoordinate.X = 0.5f; data[6].TextureCoordinate.Y = 0.0f;
            data[7].Position = new Vector3(vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[7].TextureCoordinate.X = 0.5f; data[7].TextureCoordinate.Y = 1.0f;

            //bottom
            data[8].Position = new Vector3(-vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[8].TextureCoordinate.X = 1.5f; data[8].TextureCoordinate.Y = 0.0f;
            data[9].Position = new Vector3(-vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[9].TextureCoordinate.X = 1.5f; data[9].TextureCoordinate.Y = 1.0f;
            data[10].Position = new Vector3(vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[10].TextureCoordinate.X = 0.5f; data[10].TextureCoordinate.Y = 1.0f;
            data[11].Position = new Vector3(vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[11].TextureCoordinate.X = 0.5f; data[11].TextureCoordinate.Y = 0.0f;

            //top
            data[12].Position = new Vector3(vExtents.X, vExtents.Y, -vExtents.Z);
            data[12].TextureCoordinate.X = 0.5f; data[12].TextureCoordinate.Y = 0.0f;
            data[13].Position = new Vector3(vExtents.X, vExtents.Y, vExtents.Z);
            data[13].TextureCoordinate.X = 0.5f; data[13].TextureCoordinate.Y = 1.0f;
            data[14].Position = new Vector3(-vExtents.X, vExtents.Y, vExtents.Z);
            data[14].TextureCoordinate.X = 1.5f; data[14].TextureCoordinate.Y = 1.0f;
            data[15].Position = new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z);
            data[15].TextureCoordinate.X = 1.5f; data[15].TextureCoordinate.Y = 0.0f;


            //left
            data[16].Position = new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z);
            data[16].TextureCoordinate.X = 1.5f; data[16].TextureCoordinate.Y = 0.0f;
            data[17].Position = new Vector3(-vExtents.X, vExtents.Y, vExtents.Z);
            data[17].TextureCoordinate.X = 0.5f; data[17].TextureCoordinate.Y = 0.0f;
            data[18].Position = new Vector3(-vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[18].TextureCoordinate.X = 0.5f; data[18].TextureCoordinate.Y = 1.0f;
            data[19].Position = new Vector3(-vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[19].TextureCoordinate.X = 1.5f; data[19].TextureCoordinate.Y = 1.0f;

            //right
            data[20].Position = new Vector3(vExtents.X, -vExtents.Y * y, -vExtents.Z);
            data[20].TextureCoordinate.X = 0.5f; data[20].TextureCoordinate.Y = 1.0f;
            data[21].Position = new Vector3(vExtents.X, -vExtents.Y * y, vExtents.Z);
            data[21].TextureCoordinate.X = 1.5f; data[21].TextureCoordinate.Y = 1.0f;
            data[22].Position = new Vector3(vExtents.X, vExtents.Y, vExtents.Z);
            data[22].TextureCoordinate.X = 1.5f; data[22].TextureCoordinate.Y = 0.0f;
            data[23].Position = new Vector3(vExtents.X, vExtents.Y, -vExtents.Z);
            data[23].TextureCoordinate.X = 0.5f; data[23].TextureCoordinate.Y = 0.0f;

            vertices.SetData<VertexPositionTexture>(data);


            indices = new IndexBuffer(Engine.Instance.Device,
                                typeof(short), 6 * 6,
                                BufferUsage.WriteOnly);

            short[] ib = new short[6 * 6];

            for (int x = 0; x < 6; x++)
            {
                ib[x * 6 + 0] = (short)(x * 4 + 0);
                ib[x * 6 + 2] = (short)(x * 4 + 1);
                ib[x * 6 + 1] = (short)(x * 4 + 2);

                ib[x * 6 + 3] = (short)(x * 4 + 2);
                ib[x * 6 + 5] = (short)(x * 4 + 3);
                ib[x * 6 + 4] = (short)(x * 4 + 0);
            }

            indices.SetData<short>(ib);
            #endregion

        }

        public void Update(GameTime gameTime)
        {
			var pos = Engine.Instance.Camera.Position;
			pos.Y += YOffset;
			_effect.World = Matrix.CreateTranslation(pos);
            _effect.Projection = Engine.Instance.Camera.Projection;
            _effect.View = Engine.Instance.Camera.View;
        }


        public void Draw()
        {
            if (vertices == null)
                return;

			GraphicsDevice device = Engine.Instance.Device;

			var ds = DepthStencilState.None;
			
			device.DepthStencilState = ds;
			device.SamplerStates[0] = SamplerState.LinearWrap;
			device.RasterizerState = RasterizerState.CullCounterClockwise;
			device.SetVertexBuffer(vertices);
			device.Indices = indices;
			_effect.CurrentTechnique.Passes[0].Apply();

			for (int x = 0; x < 6; x++)
			{
				if (textures[x] == null) continue;

				_effect.Texture = textures[x];
				_effect.Techniques[0].Passes[0].Apply();
				device.DrawIndexedPrimitives(PrimitiveType.TriangleList,
					0, 0, vertices.VertexCount, x * 6, 2);
			}
			
			device.DepthStencilState = DepthStencilState.Default;
        }
    }
}


================================================
FILE: Engine/SoundEngine2.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework;

namespace GameEngine
{
    class SoundEffectDescriptor 
    {
        public SoundEffectInstance Effect;
        public float RemainingDuration;
    }

    public class SoundEngine2
    {
        private static SoundEngine2 _instance;

        public static SoundEngine2 Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new SoundEngine2();
                return _instance;
            }
        }

        private List<SoundEffectDescriptor> _effects = new List<SoundEffectDescriptor>(); 

        private SoundEngine2()
        {
        }

        public void PlayEffect(SoundEffectInstance effect, float duration)
        {
            SoundEffectDescriptor sd = new SoundEffectDescriptor();
            sd.Effect = effect;
            sd.RemainingDuration = duration;
            _effects.Add(sd);
        }

        public void Update(GameTime gameTime)
        {
            for (int i = _effects.Count - 1; i >= 0; i--)
            {
                _effects[i].RemainingDuration -= (float)gameTime.ElapsedGameTime.TotalSeconds;
                if (_effects[i].RemainingDuration <= 0)
                {
                    _effects[i].Effect.Stop();
                    _effects.RemoveAt(i);
                }
            }
        }
    }
}


================================================
FILE: Engine/Utility.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace GameEngine
{
    public class Triangle
    {
        public Vector3 V1, V2, V3;
        public Triangle(Vector3 v1, Vector3 v2, Vector3 v3)
        {
            V1 = v1;
            V2 = v2;
            V3 = v3;
        }

    }
    public class Utility
    {
        public static float Epsilon = 1E-5f; //for numerical imprecision
        public static Random RandomGenerator = new Random();

        public static bool FindRayTriangleIntersection(ref Vector3 rayOrigin, Vector3 rayDirection, float maximumLength, ref Vector3 a, ref Vector3 b, ref Vector3 c, out Vector3 hitLocation, out float t)
        {
            hitLocation = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
            
            t = float.NegativeInfinity;
            Vector3 vector = b - a;
            Vector3 vector2 = c - a;
            Vector3 vector4 = Vector3.Cross(rayDirection, vector2);
            float num = Vector3.Dot(vector, vector4);
            if ((num > -1E-07f) && (num < 1E-07f))
            {
                return false;
            }
            float num2 = 1f / num;
            Vector3 vector3 = rayOrigin - a;
            float num3 = Vector3.Dot(vector3, vector4) * num2;
            if ((num3 < -0.01f) || (num3 > 1.01f))
            {
                return false;
            }
            Vector3 vector5 = Vector3.Cross(vector3, vector);
            float num4 = Vector3.Dot(rayDirection, vector5) * num2;
            if ((num4 < -0.01f) || ((num3 + num4) > 1.01f))
            {
                return false;
            }
            t = Vector3.Dot(vector2, vector5) * num2;
            if ((t > maximumLength) || (t < 0f))
            {
                t = float.NegativeInfinity;
                return false;
            }
            hitLocation = rayOrigin + (t * rayDirection);
            return true;
        }
        

        public static Vector3 RotatePoint(Vector2 point, float degrees)
        {
            float cDegrees = ((float)Math.PI * degrees) / 180.0f; //Radians
            float cosDegrees = (float)Math.Cos(cDegrees);
            float sinDegrees = (float)Math.Sin(cDegrees);

            float x = (point.X * cosDegrees) + (point.Y * sinDegrees);
            float z = (point.X * -sinDegrees) + (point.Y * cosDegrees);
            return new Vector3(x, 0, -z);
        }

		public static bool IsLeftOfLine(Vector3 line1, Vector3 line2, Vector3 pos)
		{
			return ((line2.X - line1.X) * (pos.Z - line1.Z) - (line2.Z - line1.Z) * (pos.X - line1.X)) > 0;
		}

		public static Vector3 GetClosestPointOnLine(Vector3 line1, Vector3 line2, Vector3 pos)
		{
			Vector3 lineDir = line2 - line1;
			lineDir.Normalize();

			float d = Vector3.Distance(line1, line2);

			Vector3 v1 = pos - line1;
			float t = Vector3.Dot(lineDir, v1);

			if (t <= 0)
				return line1;
			if (t >= d)
				return line2;

			return line1 + lineDir * t;
		}

		public static float GetSignedAngleBetweenVectors(Vector3 from, Vector3 to, bool ignoreY)
		{
			if (ignoreY) from.Y = to.Y = 0;
			from.Normalize();
			to.Normalize();
			Vector3 toRight = Vector3.Cross(to, Vector3.Up);
			toRight.Normalize();

			float forwardDot = Vector3.Dot(from, to);
			float rightDot = Vector3.Dot(from, toRight);

			// Keep dot in range to prevent rounding errors
			forwardDot = MathHelper.Clamp(forwardDot, -1.0f, 1.0f);

			double angleBetween = Math.Acos(forwardDot);

			if (rightDot < 0.0f)
				angleBetween *= -1.0f;

			return (float)angleBetween;
		}
    }
}

================================================
FILE: Installer/OpenNFS1.nsi
================================================
!include LogicLib.nsh

; The name of the installer
Name "OpenNFS1"

; The file to write
OutFile "OpenNFS1_Install-v1.2.exe"

; The default installation directory
InstallDir $PROGRAMFILES\OpenNFS1

; Registry key to check for directory (so if you install again, it will 
; overwrite the old one automatically)
InstallDirRegKey HKLM "Software\OpenNFS1" "Install_Dir"

; Request application privileges for Windows Vista
RequestExecutionLevel admin

;--------------------------------

; Pages

Page components
Page directory
Page instfiles

UninstPage uninstConfirm
UninstPage instfiles

;--------------------------------

; The stuff to install
Section "OpenNFS1 (required)"

  SectionIn RO
    
  ; Set output path to the installation directory.
  SetOutPath $INSTDIR
  
  ; Include all files in the deploy folder
  File /r "deploy\*.*"
  File /r "3rdparty"
  File "readme.txt"
  
  Call CheckAndInstallDotNet
  Call InstallOAL
  
  ; Write the installation path into the registry
  WriteRegStr HKLM SOFTWARE\OpenNFS1 "Install_Dir" "$INSTDIR"
  
  ; Write the uninstall keys for Windows
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenNFS1" "DisplayName" "OpenNFS1"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenNFS1" "UninstallString" '"$INSTDIR\uninstall.exe"'
  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenNFS1" "NoModify" 1
  WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenNFS1" "NoRepair" 1
  WriteUninstaller "uninstall.exe"
  
SectionEnd

; Optional section (can be disabled by the user)
Section "Start Menu Shortcuts"

  CreateDirectory "$SMPROGRAMS\OpenNFS1"
  CreateShortcut "$SMPROGRAMS\OpenNFS1\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
  CreateShortcut "$SMPROGRAMS\OpenNFS1\OpenNFS1.lnk" "$INSTDIR\OpenNFS1.exe" "" "$INSTDIR\OpenNFS1.exe" 0
  
SectionEnd

;--------------------------------

; Uninstaller

Section "Uninstall"
  
  ; Remove registry keys
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenNFS1"
  DeleteRegKey HKLM SOFTWARE\OpenNFS1
  
  ; Remove shortcuts
  Delete "$SMPROGRAMS\OpenNFS1\*.*"

  ; Remove directories used
  RMDir "$SMPROGRAMS\OpenNFS1"
  RMDir /R "$INSTDIR"

SectionEnd

Function CheckAndInstallDotNet
    ; Installer dotNetFx45_Full_setup.exe avalible from http://msdn.microsoft.com/en-us/library/5a4x27ek.aspx
    ; Magic numbers from http://msdn.microsoft.com/en-us/library/ee942965.aspx
    ClearErrors
    ReadRegDWORD $0 HKLM "SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" "Release"
    IfErrors NotDetected
    ${If} $0 >= 978389
        DetailPrint "Microsoft .NET Framework 4.5 is installed ($0)"
    ${Else}
    NotDetected:
        MessageBox MB_YESNO|MB_ICONQUESTION ".NET Framework 4.5+ is required, \
            do you want to launch the web installer? This requires a valid internet connection." IDYES InstallDotNet IDNO Cancel 
        Cancel:
            MessageBox MB_ICONEXCLAMATION "To install, Microsoft's .NET Framework v4.5 \
                (or higher) must be installed. Cannot proceed with the installation!"
            # ${OpenURL} "${WWW_MS_DOTNET4_5}"
            RMDir /r "$INSTDIR" 
            SetOutPath "$PROGRAMFILES"
            RMDir "$INSTDIR" 
            Abort

        ; Install .NET4.5.
        InstallDotNet:
            DetailPrint "Installing Microsoft .NET Framework 4.5"
            SetDetailsPrint listonly
            ExecWait '"$INSTDIR\3rdparty\dotNetFx45_Full_setup.exe" /passive /norestart' $0
            ${If} $0 == 3010 
            ${OrIf} $0 == 1641
                DetailPrint "Microsoft .NET Framework 4.5 installer requested reboot."
                SetRebootFlag true 
            ${EndIf}
            SetDetailsPrint lastused
            DetailPrint "Microsoft .NET Framework 4.5 installer returned $0"
    ${EndIf}

FunctionEnd


Function InstallOAL
	ExecWait '"$INSTDIR\3rdparty\oalinst.exe" /s' $0
FunctionEnd

================================================
FILE: Installer/build-installer.bat
================================================
rmdir /S /Q deploy
mkdir deploy
set src=..\OpenNFS1\bin\WindowsGL\Debug
set dest=.\deploy
xcopy %src%\Content %dest%\Content\ /s /e
copy %src%\gameconfig.json %dest%
copy %src%\OpenNFS1.exe %dest%
copy %src%\*.dll %dest%
copy %src%\*.pdb %dest%
del %dest%\IgnoreMe.dll

"C:\Program Files (x86)\NSIS\makensis" /V1 OpenNFS1.nsi

================================================
FILE: Installer/readme.txt
================================================
OpenNFS1 v1.2
----------------
Web: http://www.1amstudios.com/projects/opennfs1
Src: https://github.com/jeff-1amstudios/OpenNFS1
Email: jeff@1amstudios.com


OpenNFS1 is a ground-up remake of the original EA Need for Speed 1. The code is all written from scratch without reverse engineering executables, and it uses the original data files that were on the CD back in 1995! The format of the various binary data files was worked out by Ian Brown, Denis Auroux and myself.


Main features:

Written in C# and XNA. (Now converted to Monogame)
16 tracks with scenery, animations, tunnels
9 drivable cars with animated dashboards
Can drive tracks backwards (not allowed in the original)
Can drive past the finish signs on open road stages to see the real end of the track (probably never seen by anyone except by the original developers!)


Keys:

C - Change camera
Up - Accelerate
Down - Brake
Left / Right - Steer
Space - Handbrake
A / Z - Gear up down in manual gearbox mode
F1 - Toggle debug mode.  This enables an FPS camera which can be moved independantly of the car



Models, textures, tracks, cars by Pioneer Productions / EA Seattle (C) 1995. OpenNFS1 is not affiated in any way with EA or Pioneer Productions

================================================
FILE: NFSSpecs.txt
================================================
======================================================================
THE UNOFFICIAL NEED FOR SPEED FILE FORMAT SPECIFICATIONS - Version 0.2
  Copyright (c) 1995-96, Denis AUROUX (MXK) - auroux@clipper.ens.fr
======================================================================

Last updated : February 13, 1996

This file is available from the following URL :

     http://www.eleves.ens.fr:8080/home/auroux/nfsspecs.txt

Disclaimer : NO WARRANTY of any kind comes with this file.


Added in version 0.2 :
- TRI files (section B.6) : all you need to write a track editor.

A - GAMEDATA directory
    ==================

A.1 GAMEDATA\CONFIG\PATHS.DAT
    -------------------------

This file contains 18 null-terminated strings of 80 characters each
(total 1440 bytes), describing the paths where NFS looks for its files.
For minimum install, here are the contents (with hex offset):

000 gamedata/config/              2D0 F:\simdata\misc\
050 gamedata/savegame/            320 F:\simdata\trackfam\
0A0 F:\frontend\speech\           370 F:\simdata\slides\
0F0 F:\simdata\soundbnk\          3C0 F:\simdata\carFams\
140 F:\frontend\music\            410 F:\simdata\soundbnk\
190 F:\frontend\art\              460 F:\simdata\carspecs\
1E0 gamedata/modem/               4B0 F:\simdata\dash\
230 F:\frontend\movielow\         500 F:\simdata\misc\
280 gamedata/replay/              550 F:\frontend\show\

Note that simdata\soundbnk and simdata\misc are present twice.
Also note that in the CD-ROM, directories whose name starts with a 'G'
correspond to the German version of the game. Don't know why the car
dashboards had to be translated, though :)

Modify these entries if you want to copy some of the CD files to your hard
disk, for example if you want to modify them. Remember that modifying the
files can be hazardous, and that because the file formats are not fully
known it is better to modify an existing file than to create one from scratch.

A.2 GAMEDATA\SAVEGAME\*.SAV
    -----------------------

These are the tournament save files (840 bytes each).

- Offset 0 : your name (null-terminated string followed by zeros)
- Offset 28 : 'Opponent'               (")
- Offset EC : 'Player 2'               (")
- Offset 114 : 'Opponent 2'            (")
- Offset 1D8 : name of the tournament  (")
- Offset 20A : 'REPLAY.RPL'            (")
- Offsets 23C-26F : ???
- Offset 270 : name of the tournament  (")
- Offsets 30E-337 : ???
- Offsets 338, 33A, 33C, 33E, 340, 342, 344 : these contain 01 if the
  corresponding race has been won, otherwise 00. The first three bytes
  are for open-road races, while the other correspond to closed tracks.
  For instance, in order to access the bonus track, save a tournament,
  then set all these bytes to 01 except 33E to 00 (Rusty Springs), then
  reload the tournament and win Rusty Springs. The odd offsets 339 to 345
  are zeros.
- Offsets 346-347 : ???

The other offsets contains zeros.

A.3 GAMEDATA\CONFIG\CONFIG.DAT
    --------------------------

This file (25552 bytes) contains all the relevant configuration data
(current car, track, display & sound options, ...), as well as the current
scores (best times, top speeds, laps, ...). It also describes whether you
have access to the bonus track and the bonus car, etc...
Anybody got anything more detailed to put here ?


B - SIMDATA directory
    =================

B.1 SIMDATA\CARSPECS\*.PBS
    ----------------------

These files (one per player car) describe the car performance.
Usually, installing these files to the hard disk (by editing PATHS.DAT)
makes Need for Speed inoperable (no acceleration is possible) because the
game modifies SIMDATA\CARSPECS\BY_R&T. However this can be prevented by
making the check file read-only (run ATTRIB +R BY_R&T).

Note that copying one of these files on top of another one will affect the
car performance and handling, but not the engine sound. So if the max rpm's
of the two engines are not the same, the sound can get badly altered because
the correct sound sample is not available.

These files are somehow compressed, because by modifying a single byte in
the file one can reach various results such as : an instant system crash ;
a car that materializes under the road and cannot move, with 11 gears (!) ;
a car without front wheels, that keeps spinning at its initial position...

B.2 SIMDATA\DASH\*.FMM
    ------------------

These small files (two per player car, corresponding to the hi-res and
low-res dashboards) describe the shape of the car's windshield in each
display resolution. The files are slightly different for 320x200 and 640x480.

a) Low-res .FMMs (*DL.FMM) :

The file structure is the following : first a 24-byte header, then four
chunks.

The header format is the following :

offset len data
------ --- ----
00      4  'wwww'
04      4   4     (number of chunks)
08      4  18h    (offset of the first chunk)
0C      4  offset of the second chunk
10      4  offset of the third chunk
14      4  offset of the fourth chunk

The chunks in low-res .FMMs have the following header (22 bytes) :

offset len data
------ --- ----
00      4  'BAMF'
04      2  length of the chunk in bytes, minus two
06      4  ? (usually equals 10000h or 8000h : maybe an image size)
0A      2  maximum "length" value in the chunk's records
0C      4  ? (usually equals 10000h or 8000h : maybe an image size)
10      4  ? (usually equals 10000h or 8000h : maybe an image size)
14      2  number of records in the chunk (length minus 18h, div 8)

This header is in each chunk immediately followed by the 8-byte records.
Each record has the following structure :

offset len data
------ --- ----
00      4  baddr
04      2  vaddr
06      2  length

The last record is followed by a 16-bit value (purpose unknown).

The vaddr and length values are interpreted as follows : starting from
address "vaddr" in video memory (i.e. of the form 320y+x for pixel (x,y)),
"length" pixels do not belong to the dashboard, and must instead be drawn
because they correspond to screen portions where the player must see the
road through the windshield.
The baddr field corresponds to an internal buffer offset, describing
where the data to be displayed at "vaddr" are to be found in the buffer
where NFS draws the view.

- The first chunk corresponds to high detail : vaddr and baddr are equal,
and each line corresponds to 320 bytes in the buffer (every pixel is stored).

- The second chunk corresponds to medium detail : each line corresponds to
320 bytes in the buffer, but only half of the pixels are stored, thus only
the first 160 bytes contain relevant data, the following 160 being unused.
To vaddr=320y+x corresponds baddr=320y+(x>>1) : the horizontal resolution
is decreased.

- The third chunk corresponds to low detail : two consecutive lines have the
same baddr values, and these two lines correspond to 320 bytes in the buffer.
As before, only half of these 320 bytes are used. Only a quarter of the
pixels are stored. vaddr=320y+x corresponds to baddr=320.(y>>1)+(x>>1) :
both horizontal and vertical resolutions are decreased.

- The fourth chunk corresponds to the interlaced mode : only half of the
screen lines are referenced ; as in low detail, two screen lines correspond
to 320 bytes, half of which are unused. vaddr=320y+x still corresponds to
baddr=320.(y>>1)+(x>>1), but only the even-numbered lines are present.

b) Hi-res .FMMs (*DH.FMM) :

The chunk format is slightly different because the video memory is now
segmented in several 64K pages. (Note that the values at offsets 06, 0C and
10 in the chunk header are now larger, e.g. 40000h and 10000h)

Offset 14h in the chunk now contains, instead of the total number of records
in the chunk, only the number of records that correspond to the first page
of video memory (i.e. the first 64K). It is followed by the corresponding
records.
After these records, another 16-bit value describes the number of records
that are located in the second page of video memory (the following 64K);
the records for the second page follow (note that the 32-bit baddr values
at last become useful ; only the 16 last bits of the vaddr are stored,
since it is known to be located in the second page).
The chunk continues with the following pages, until the number of records
for a given page is zero. This zero value is followed by a 16-bit value
(purpose unknown) as in the low-res files.

The four chunks correspond respectively to high, medium, low and interlaced
detail levels, as described above (but the lines are now each 640 pixels
long ; when not in high resolution, only 320 of the 640 bytes are used).

B.3 SIMDATA\DASH\*.FSH
    ------------------

These store the different bitmaps that make up the dashboard.
The 16-byte header format is the following :

offset len data
------ --- ----
00      4  'SHPI'
04      4  length of the file in bytes
08      4  number of objects in the directory
0C      4  directory identifier string

The directory identifier is 'GIMX' in .FSH dashboard files.

This header is followed by the directory entries, each consisting of a
4-byte identifier string, and a 4-byte offset inside the file pointing to
the beginning of the corresponding data.

Each entry in the directory represents a piece of the dashboard.
There are gaps between the directory and the first bitmap, and between
consecutive bitmaps (significance unknown).

Each directory entry points to a bitmap block with the following structure :

offset len data
------ --- ----
00      1  7Bh
01      3  size of the block (= width x length + 10h)
04      2  width of the bitmap in pixels
06      2  heigth of the bitmap in pixels
08      4  ?
0C      2  x position to display the bitmap
0E      2  y position to display the bitmap
10     w.h bitmap data : 1 byte per pixel

Note that the object called 'dash' in the directory takes the whole screen
(320x200 or 640x480, at position x=0, y=0)."

The various objects, depending on their 4-letter identifier, represent :
the dashboard itself, the steering wheel in various positions, the radar
detector lights, the gauges, and also pieces of the steering wheel to redraw
over the gauges when necessary. Note that value FF in the bitmaps stands for
the background : this is useful when a bitmap is drawn on top of another one.

Also note that some SHPI bitmap directories contain entries that actually
describe the palette to be used with the bitmaps. Typically, entries with
names like '!PAL', and with bitmap dimension 256x3, correspond to palettes.
The palette data consists of 256 3-byte records, each record containing the
red, green and blue components of the corresponding color (1 byte each).

B.4 SIMDATA\CARFAMS\*.CFM
    ---------------------

These files describe the exterior look of the cars during the race. There
seem to be two different kinds of files :
- full CFMs that can be used to describe any car
- restricted CFMs that can only describe traffic or opponents - note that
  yourself and your head-to-head opponent must have full CFMs, whereas
  "single race" opponents can be either full or restricted CFMs.

a) Full CFMs on the CD :
  Standard cars : ANSX.CFM, CZR1.CFM, DVIPER.CFM, F512TR.CFM, LDIABL.CFM,
                  MRX7.CFM, P911.CFM, TSUPRA.CFM, TRAFFC.CFM (Warrior)
  More or less bugged previous versions of these cars :
    F512M.CFM, P911T.CFM, WARIOR.CFM, WARRIOR.CFM

b) Restricted CFMs on the CD :
  Vans/jeeps/pickups : JEEP.CFM, PICKUP.CFM, RODEO.CFM, VANDURA.CFM
  Station-wagons : AXXESS.CFM, WAGON.CFM
  Usual cars : BMW.CFM, JETTA.CFM, LEMANS.CFM, SUNBIRD.CFM
  Sports cars : CRX.CFM, PROBE.CFM
  The cop's car : COPMUST.CFM
  Restricted versions of the player cars (loaded for single race opponents):
      MANSX.CFM, MCZR1.CFM, MDVIPER.CFM, MF512TR.CFM, MLDIABL.CFM,
      MMRX7.CFM, MP911.CFM, MTSUPRA.CFM, MTRAFFC.CFM
  Bugged versions of the player cars :
      LDIABLO.CFM, MF512M.CFM, MP911T.CFM, TESTA.CFM

These files are 'wwww' files containing four chunks. The header is as in
.FMM files (see B.2). The first and second chunk correspond to high-detail
car structure, while the third and fourth chunk correspond to low-detail.

The first and third chunks have header 'ORIP', and describe how the car is
to be drawn (position and orientation of each car element). The second
and fourth chunks are 'SHPI' bitmap directories (see B.3), with directory
identifier 'WRAP'. They provide the bitmaps referenced by the ORIP chunks.
Note that the offsets specified in the bitmap directories are relative to the
'SHPI' header.

An 'ORIP' chunk consists of a header followed by nine blocks.
The header has length 112 (70h) and the following structure :

offset len data
------ --- ----
00      4  'ORIP'
04      4  chunk length in bytes
08      4  2BCh (=700)
0C      4  0
10      4  size of block 8 in 12-byte records
14      4  ? the previous minus 10h
18      4  offset of block 8 in the ORIP (in bytes)
1C      4  size of block 2 in 8-byte records
20      4  offset of block 2
24      4  size of block 1 in 12-byte records
28      4  offset of block 1 (=70h)
2C     12  identifier string
38      4  size of block 3 in 20-byte records
3C      4  offset of block 3
40      4  size of block 4 in 20-byte records
44      4  offset of block 4
48      4  size of block 5 in 28-byte records
4C      4  offset of block 5
50      4  offset of block 9
54      4  size of block 6 in 12-byte records
58      4  offset of block 6
5C      4  size of block 7 in 12-byte records
60      4  offset of block 7
64      4  0
68      4  70h
6C      4  0

The first block consists of 12-byte records and describes the polygons that
are used to draw the car:

offset len data
------ --- ----
00      1  83h for triangle, 84h for quadrangle, 8Ch when quadrangle/null
01      1  ?
02      1  texture number
03      1  ?
04      4  polygon offset for pol1
08      4  polygon offset for pol2

The texture number corresponds to a record position in block 3, which is
converted to one of the textures in the SHPI chunk that follows the ORIP.
The polygon offsets correspond to positions in the last block, where the
polygons are listed consecutively (first pol2 and then pol1, for each record).
The first polygon has pol2 starting at 0. (The polygon offsets are given
in 4-byte units). In the last block, vertices belonging to a pol1 are
expanded to 3D points by lookup in block 8, while vertices belonging to a
pol2 are expanded to 2D points by lookup in block 2. The portion of the
relevant texture corresponding to pol2 is mapped onto the 3D polygon pol1.

When the first byte is 83h, pol1=pol2+3 and next polygon's pol2 equals pol1+3.
When it is 84h, pol1=pol2+4 and next pol2 equals pol1+4. When it is 8Ch,
pol1=pol2 and next pol2 equals pol1+4.

The second block is made of 8-byte records, which describe the (x,y)
coordinates inside the textures referenced by pol2.

offset len data
------ --- ----
00      4  x coordinate
04      4  y coordinate

Third block (20-byte records):

offset len data
------ --- ----
00      8  identifier string 1
08      4  identifier string 2
0C      8  ? 00 00 00 81 F5 00 00 00

This block describes the link between the texture numbers of block 1 and
the textures stored in the SHPI chunk. Identifier string 2, when non-void,
corresponds to one of the SHPI directory entries.

Fourth block (20-byte records):

offset len data
------ --- ----
00      8  identifier string ('left_tur', 'right_tu')
08      4  number of vertices
0C      4  polygon offset (in block 9)
10      4  ?

Fifth block (28-byte records):

offset len data
------ --- ----
00     12  identifier string ('NON-SORT', 'inside', 'surface', 'outside')
0C      4  ?
10      4  polygon offset (in block 9)
14      4  number of vertices
18      4  0

Sixth and seventh blocks (12-byte records):

offset len data
------ --- ----
00      8  identifier string
08      4  ?

The eighth block consists of 12-byte records which describe the position in
space of each vertex (using signed long ints, centered at (0,0,0)).

offset len data
------ --- ----
00      4  x coord. (x axis is lateral)
04      4  z coord. (z axis is vertical, z increases when going up)
08      4  y coord. (y axis is longitudinal, increases when going forward)

The last block is a succession of long integers, each representing a vertex
number. This block describes the vertices each polygon consists of, and is
referenced by the index tables of the first, fourth and fifth blocks. Each
vertex number referenced in a pol1 polygon is converted to a point in space
using block 8, while each vertex number referenced in a pol2 polygon is
converted to a position in a texture bitmap using block 2.

B.5 SIMDATA\MISC\*.QFS, SIMDATA\SLIDES\*.QFS, ...
    ---------------------------------------------

This seems to be EAC's favorite bitmap format... Basically, it is similar
to the .FSH files described in B.3, however the data are now compressed
using some kind of Huffman algorithm. Outside of this compression thing,
the file still contains a 'SHPI' header, and a directory. The directory
itself is much shorter than in the dashboard FSH's : usually one entry
(the bitmap itself), sometimes two (when a palette is specified).
The big trouble is in finding the details of the decompression algorithm.

The directory header is 'LN32', indicating 32768-color mode. (see C.2).

B.6 SIMDATA\MISC\*.TRI
    ------------------

Don't know why these are in the MISC directory... they are quite important
indeed ! They describe the track itself, including the shape of the road
and the position of the scenery items. The objects are referenced by numbers
which correspond to entries in the corresponding file in SIMDATA\TRACKFAM.

Their structure is fairly complex, so I recommend you play with the files
in order to get acquainted with their subtleties. The information contained
in this section was used to develop the first NFS track editor, called
TRACKED, and available at the following URL :

         http://www.eleves.ens.fr:8080/home/auroux/nfs/tracked.zip

In order to understand the structure of TRI files you have to know that a
track is the superposition of three structures :

- first, a 'virtual road' : this is a sequence of points in space,
  which will be called 'nodes'. These points correspond to successive
  positions along the track, and all the cars have to pass near each of
  these positions. During the game, the virtual road is invisible, but
  you have to stay close to it.

- second, the scenery : this is a collection of points in space, which
  will be called 'vertices', together with textures which are mapped onto
  the polygons defined by consecutive vertices. These textures are used
  to draw the road, the roadside and part of the landscape. Thus it is
  of course preferable that the scenery remain close to the virtual road !

- and last, the objects : points in space together with bitmaps, which
  are used for road signs, buildings, trees, etc... Some of them are
  plain 2D bitmaps, but others have a more sophisticated polygonal 3D
  structure.

The 3D coordinates x,y,z will always be used with the following meaning :

- x is an axis which is transversal to the starting line. Positive x values
  correspond to points which are on the right of the starting position.
  (i.e. if you start looking to the north, x points to the east)

- y is an axis which is parallel to the starting line. Positive y values
  correspond to points which are ahead of the starting position.
  (i.e. y points to the north)

- z is a vertical axis. Positive z values correspond to points higher than
  the starting position.

a) TRI files begin with 12F8h bytes of headers and index tables. These are
as follows :

offset len data
------ --- ----
00      4   ?
04      8   ?
0C      4   x coordinate of the first node
10      4   z coordinate of the first node
14      4   y coordinate of the first node
18      4   ?
1C      4   ?
20      4   ?
24      4   length of the scenery data (in bytes : 554h per record)
28      4   ?
2C    960h  first index table
98C   960h  second index table

The first index table is a succession of 32-bit offsets. It follows an
arithmetic progression by 548h as a general rule. This means the first
value is 0, followed by 548h, A90h, etc... On closed tracks, when the
end is reached, the offsets start again with 0, 548h, A90h, etc...
(so that the end of a lap is connected with the beginning of the following
one !). The table is filled to 960h bytes (600 entries) with zero values.
This table is probably only used as a lookup table in memory during the
game, since there are no 548h-byte structures in the file.

The second index table is also a succession of 32-bit offsets, but these
offsets are inside the TRI file. This one follows an arithmetic progression
by 554h. It corresponds to the offsets of the successive records for
scenery data, which starts at offset 1B000h in the scenery file. So this
table starts with 1B000h, 1B554h, 1BAA8h, etc... until the end of the
TRI file is reached. It is filled to 600 entries with zero values.

b) The virtual road data follows, and is constituted of 36-byte records
(one for each node). The first record is at offset 12F8h, and the last
allowed record is at offset 16468h (this leaves room for 2400 records, and
since a scenery block corresponds to four nodes, both capacities are equal).
The unused records (after the last node) are filled with zero values.
The structure of each record is the following :

offset len data
------ --- ----
00      1  a0
01      1  a1
02      1  a2
03      1  a3
04      1  b0
05      1  b1
06      1  b2
07      1  b3
08      4  x coordinate
0C      4  z coordinate
10      4  y coordinate
14      2  slope
16      2  slant-A
18      2  orientation
1A      2  0
1C      2  y-orientation
1E      2  slant-B
20      2  x-orientation
22      2  0

- a0,a1,a2,a3 are 8-bit values whose purpose is unknown : possibly the
  width of the road on each side ?

- b0,b1,b2,b3 are 8-bit values of unknown purpose.

- x, z and y coordinates are signed long values.

- slope is a value indicating the slope at the current node, i.e. the
  difference between the z coordinates of two consecutive nodes.
  A good approximation is : slope(i) = (z(i+1) - z(i))/152.
  However, to complicate things, it is stored as a signed 14-bit value,
  complemented to 4000h. This means -1 is stored as 3FFFh, -2 as 3FFEh, ...
  So in fact you must perform a logical and with 3FFFh before storing !

- slant-A is a value indicating how the road is slanted to the left or
  to the right (as in the turns in Autumn Valley or Lost Vegas). It is
  a signed 14-bit value, like slope. The value is positive if the road
  is slanted to the right, negative if it is slanted to the left.

- slant-B has the same purpose, but is a standard signed 16-bit value.
  Its value is positive for the left, negative for the right.
  The approximative relation between slant-A and slant-B is
  slant-B = -12.3 slant-A (remember that slant-A is 14-bit, though)

- orientation is a 14-bit value, and is equal to 0 for north (increasing y),
  1000h for east (increasing x), 2000h for south (decreasing y), 3000h for
  west (decreasing x), and back to 3FFFh for north.

- y-orientation is a signed 16-bit value, which is proportional to the
  y coordinate variation. Meanwhile, x-orientation is proportional to the
  *opposite* of the x coordinate variation. This means that the couple
  (-xorientation,yorientation) gives the orientation of the track.
  The norm (square root of xorient^2+yorient^2) is usually around 32000
  (a little less than 8000h, to avoid numeric overflows), but can fluctuate
  with the only condition that (-xor,yor) gives the correct orientation.

c) The objects data comes next. There are first several distinct zones,
many of which seem to be unused (?) :

offset len  data
------ ---  ----
16478  708h  3-byte records (there are 600... as many as scenery blocks ?)
16B80   4    40h (?)
16B84   4    3E8h = 1000 (size of the main block in records)
16B88   4    'OBJS'
16B8C   4    428Ch (total length of the remaining blocks)
16B90  400h  16-byte records (unknown purpose)
16F90   4    ?
16F94 3E80h  object data : 1000 records of 16 bytes (one per object)
1AE14  1ECh  0

The object data itself consists of a 16-byte record per object. The record
structure is the following :

offset len data
------ --- ----
00      4  reference node
04      1  bitmap number
05      1  flip
06      4  flags (unknown purpose)
0A      2  relative x coordinate
0C      2  relative z coordinate
0E      2  relative y coordinate

Each object is related to a reference node in the virtual road. The x,z,y
coordinates are then expressed as signed 16-bit values relative to the
coordinates of the reference node. Beware that the axes are simply translated
but not rotated ! (i.e. the x and y axes are still pointing east and north)
The objects are sorted in the order of increasing reference nodes.
A reference node value of -1 indicates that the record is unused (i.e. after
the end of the used records). Also note that the coordinates are not
expressed in the same unit as the 32-bit absolute coordinates seen above
(the units are much larger, so that the value fits in 16 bits).

The 8-bit flip value is equal to 0 for an object that is perfectly perpendi-
cular to the track (e.g. a road sign), larger values for objects that are
slightly turned, until 64 for an object that is mapped along the track
(e.g. an ad on the side of the road), then up to 128 which is the perfectly
reversed position (since the objects have no "back", this is the common
way of reversing a road sign for a turn in the other direction), then
up to 192 which is again longitudinal mapping (the other way) and until
255 which is back to the normal position.

The bitmap number corresponds to a texture in the corresponding .FAM file
(see B.8). The relevant bitmaps are in the second chunk of the .FAM file.
Two cases can occur :

- closed tracks : the second chunk is a 'wwww' structure containing a
single subchunk which is in turn a SHPI directory where the entry corres-
ponding to bitmap #n is called "nn00" where nn is n written in decimal.
(e.g. bitmap #18 is "1800"). Furthermore the object called "!pal" or "!PAL",
when it exists, is the corresponding palette (256 3-byte entries) ; FFh is
transparent.

- open roads : the second chunk contains a subchunk per bitmap, and each
subchunk is a SHPI containing at least the object "0000" (the bitmap), and
possibly a palette ("!pal" or "!PAL"). Object #n is then the bitmap "0000"
in the subchunk #n (the first subchunk is #0).

One must add to these 2D objects (plain bitmaps) the 3D objects described
in the fourth chunk of the .FAM file. They usually correspond to numbers
above the last 2D object ; however it happens, in closed tracks, that some
of the 3D objects are given numbers inside the range used by 2D objects.
In that case, the numbers describing 2D objects are shifted upwards.
(i.e. the bitmap "4400" corresponds to object #45 or #46). This phenomenon
apparently does not occur for open roads, where the 3D objects always follow
the 2D objects.

Furthermore, certain consecutive bitmaps represent successive states of an
animated object. In that case, the game will display successively the
relevant bitmaps. Note that if the second bitmap is given instead of the
first, the animation does not occur.

d) The scenery data starts at offset 1B000h. It is made up of records of
size 554h, each corresponding to four nodes in the virtual road. The
records are consecutive and the last record ends the .TRI file.
Each record has the following structure :

offset len data
------ --- ----
000     4   'TRKD'
004     4   548h = length of the record contents
008     4   number of this record (0 for the first, then 1, etc...)
00C     2   ?
00E    10   textures
018    12   reference point
024    12   ?
030    12   point A0
03C    12   point A1
...    ..   ........
09C    12   point A9
0A8    12   point A10
0B4    12   ?
0C0    12   point B0
0CC    12   point B1
...    ..   ........
12C    12   point B9
138    12   point B10
144    12   ?
150    12   point C0
15C    12   point C1
...    ..   ........
1BC    12   point C9
1C8    12   point C10
1D4    12   ?
1E0    12   point D0
1EC    12   point D1
...    ..   ........
24C    12   point D9
258    12   point D10
264    12   ?
270    12   ?
27C    12   point E0
288    12   point E1
...    ..   ........
2E8    12   point E9
2F4    12   point E10
300   516   ? unused (room for 43 points)
504    80   ? unused

Each point is given by three signed 32-bit absolute coordinates (x,z,y as
usual). The coordinates are the same as in the virtual road data.
The reference point is unused in the game and usually equal to point A0.

The points A0,...,A10 in record #n (starting with 0) correspond to the node
#4n (starting with 0) in the virtual road data. B0,...,B10 correspond to
node #4n+1, C0...C10 to node #4n+2, D0...D10 to node #4n+3 and E0...E10 to
node #4n+4. Thus the points E0...E10 are identical to the points A0...A10
of the following record.

The eleven point series (0 to 10) are arranged as follows : A0-E0 are near
the middle of the road, and thus close to the corresponding nodes.
A1-E1 are a little to the right, A2-E2 further right, ... until A5-E5.
A6-E6 are a little to the left, A7-E7 further left, ... until A10-E10.
(In tunnels, the points A5-E5 and A10-E10 get back to the center, consti-
tuting the ceiling).

To each record correspond ten textures (coded at the beginning), each given
by a 8-bit value, T1,T2,...,T10. T1 is used between A0-E0 and A1-E1,
T2 between A1-E1 and A2-E2, ..., T5 between A4-E4 and A5-E5 ; meanwhile,
T6 is used between A0-E0 and A6-E6, T7 between A6-E6 and A7-E7, ...,
T10 between A9-E9 and A10-E10. This is summarized on the following diagram :

E10---E9---E8---E7---E6---E0---E1---E2---E3---E4---E5  node 4n+4
 |    |    |    |    |    ||    |    |    |    |    |
 |    |    |    |    |    ||    |    |    |    |    |
D10   D9   D8   D7   D6   D0   D1   D2   D3   D4   D5  node 4n+3
 |  T |  T |  T |  T |  T || T  | T  | T  | T  | T  |
 |    |    |    |    |    ||    |    |    |    |    |
C10   C9   C8   C7   C6   C0   C1   C2   C3   C4   C5  node 4n+2
 | 10 |  9 |  8 |  7 |  6 || 1  | 2  | 3  | 4  | 5  |
 |    |    |    |    |    ||    |    |    |    |    |
B10   B9   B8   B7   B6   B0   B1   B2   B3   B4   B5  node 4n+1
 |    |    |    |    |    ||    |    |    |    |    |
 |    |    |    |    |    ||    |    |    |    |    |
A10---A9---A8---A7---A6---A0---A1---A2---A3---A4---A5  node 4n
                          ^
       the nodes are here |

The texture numbers are converted to bitmaps in the first chunk of the
.FAM file (see B.8). There are two different cases :

- closed tracks : the first chunk is a 'wwww' structure which contains a 
single subchunk which is in turn a SHPI bitmap directory, possibly with a 
palette '!PAL' or '!pal'. There is also often a bitmap called 'ga00' or 
'GA00' (unknown interpretation). The names have the structure "xxls", where 
xx is a decimal value indicating the texture group, l is 'A', 'B' or 'C', 
and s indicates a scale ('0' is the largest, while '3'&'4' are very small). 
The various scales are here to speed up the texture-mapping algorithm,
anyway the only texture that is always present is with s=0.
The xx and l values correspond to a texture number n in the following way :
n=3xx if l='A', 3xx+1 if l='B' and 3xx+2 if l='C'. Note that there are holes
in the numbering : many numbers do not have a bitmap.
Examples : bitmap "03C0" corresponds to texture #11 (3x3+2) at the largest
scale; bitmap "14A1" corresponds to texture #42 (3x14) at the second scale
available.

- open roads : the first chunk contains a subchunk per texture group (i.e.
the xx value is now the number of the subchunk, starting with 0). Each
subchunk is a SHPI directory containing potentially a palette, and bitmaps
labelled "l00s", where l is 'A','B' or 'C' and s is the scale.
As before, n=3xx if l='A', 3xx+1 if l='B', 3xx+2 if l='C', and there are
holes in the numbering.
Examples : texture #11 at scale '0' is now the bitmap "C000" in subchunk #3.
Texture #42 at scale '1' is now the bitmap called "A001" in subchunk #14.

B.7 SIMDATA\SOUNDBNK\*.BNK
    ----------------------

These file store the sound samples for the engines, the crashes, etc...
The filenames ending with 'W' correspond to 16-bit sound, while 'B' stands
for 8-bit sound. Logically, 'S' should stand for stereo and 'M' for mono,
but it seems that, at least for cars, the file that gets loaded in 8-bit
mono mode is the one whose name ends with 'SB'. I don't know why. I'm
beginning to think that EAC recruited Microsoft programmers ;-)

Also remember that the 8 bit sound samples are signed data. If you plan to
use WAV files as samples, don't forget to change this.

The file format is the following :

- the first 512 bytes contain 128 long integers, which are either zero if
the corresponding sample is not present, or the offset of a sample header.
Car files contain four samples with header offsets 200h, 248h, 290h and 2D8h,
declared at offsets 04, 08, 0C and 80h respectively. The two first samples
are the engine sound, the third is the car horn, the fourth is the sound
that gets produced when you change gears.

- each sample header consists of 72 bytes (48h). The format is the following:

offset len data
------ --- ----
00      4  ? flags (for 8-bit car sounds, these are 1, 2, 4000h and 10h)
04      4  header's offset + 28h (i.e. offset of the 'EACS' marker)
08      4  ? (0 for cars)
0C      4  ? (0 for cars except gear change)
10      4  ? (0 for cars)
14      1  ?
15      1  ? (80h for cars)
16      1  ? (0 for cars)
17      1  ?
18      4  ? (7F40h for cars)
1C      4  ? (0 for cars)
20      4  ? (0 for cars)
24      4  ? (0 for cars)
28      4  'EACS'
2C      4  3E80h (sampling rate : 16 kHz)
30      1  8/16 bit flag : 1 for 8-bit, 2 for 16-bit
31      1  mono/stereo flag : 1 for mono, 2 for stereo
32      1  ? (0 for cars)
33      1  ? (FFh for cars)
34      4  beginning of the repeat loop (in samples : 1, 2 or 4 bytes)
38      4  length of the repeat loop (in samples)
3C      4  length of the sound (in samples)
40      4  offset of the raw sound data in the .BNK file
44      4  ? (0 for cars)

B.8 SIMDATA\TRACKFAM\*.FAM
    ----------------------

These files contain the bitmaps that are used for displaying the correspon-
ding track or track segment. They make use of the 'wwww' file format, using
the usual header (see B.2) : first 'wwww', then the number of chunks (as a
long integer), then the offsets of each chunk header (long integers).

The .FAM file itself is a 'wwww' file containing four chunks. The first chunk
corresponds to the background bitmaps, making up the terrain and the road,
while the second chunk is devoted to foreground bitmaps (road signs, etc...)
Each of these two chunks is itself in 'wwww' format, containing sub-chunks.
Note that the offsets of the sub-chunks listed in the headers are relative
to the beginning of the chunks. In the open road .FAM's, the chunks are very
subdivided and contain many small subchunks, while in the closed tracks,
there is only one big subchunk.

Now the subchunks in each of the first two chunks are themselves 'SHPI'
bitmap directories (see B.3), whose elements are a palette and several
bitmaps. Keep in mind that the offsets in the directories are relative to
the beginning of the subchunk (i.e. the 'SHPI' header).

The third chunk of the .FAM file is a SHPI file describing the horizon :
the SHPI directory contains two entries, one for the palette and one for
the bitmap itself.

The fourth chunk describes the three-dimensional objects in the scenery.
It is a 'wwww' structure, containing a subchunk per object. Now each of
these subchunks is quite similar to a .CFM file (see B.4) : it is itself a
'wwww' structure containing two subsubchunks ! The first subsubchunk is an
'ORIP' structure describing the shape of the object, while the second is
a 'SHPI' structure containing the bitmaps referenced by the 'ORIP' part.

If you didn't catch everything, don't worry... look at NFSVIEW.PAS (see D.1)


C - FRONTEND directory
    ==================

C.1 FRONTEND\ART\*.QFS, FRONTEND\SHOW\*.QFS : see B.5
    ---------------------------------------

C.2 FRONTEND\ART\*.INV
    ------------------

These files describe how to reduce the palette from hi-color mode to 256
colors. The corresponding .QFS files (compressed SHPI bitmaps) have directory
identifier 'LN32', indicating the bitmaps are in 32768-color mode (each
red, blue and green component is coded on 5 bits (0 to 31), and the 15 bits
describing the color are stored in a 16-bit word). Since many video cards do
not support these modes, information is provided for palette reduction to
256-color modes. This information is partly stored as a palette object in the
QFS file, describing the RGB components of the 256 colors. In order to help
Need for Speed with the palette conversion, the .INV file (length 32768 bytes)
stores, for each 15-bit value, which palette entry is relevant.

Displaying the 'LN32' bitmaps in 256-color is thus done by first expanding
the .QFS file, then setting the specified palette, and converting each
15-bit pixel in the bitmap to the 8-bit value located at the corresponding
offset in the .INV file.

C.3 FRONTEND\MUSIC\*.ASF
    --------------------

These files contain the music for the front end. The 40-byte header is as
follows (note a consistency with the EACS structures described in B.7) :

offset len data
------ --- ----
00      4  '1SNh'
04      4  ?
08      4  'EACS'
0C      4  3E80h (sampling rate 16 kHz)
10      1  2 (16-bit mode flag)
11      1  2 (stereo mode flag)
12      1  ? (0 usually)
13      1  ? (0 usually)
14      4  length of the wave data (expressed in 4-byte samples)
18      4  beginning of the repeat loop (in samples)
1C      4  length of the repeat loop (in samples)
20      4  0 (the start offset is not specified : should be 28h)
24      4  ?

Signed 16-bit stereo wave data follows.

C.4 FRONTEND\SPEECH\*.EAS
    ---------------------

These file contain the speeches, as an EACS structure (see B.7 and C.3).
The 32-byte header is now as follows :

offset len data
------ --- ----
00      4  'EACS'
04      4  3E80h (sampling rate 16 kHz)
08      1  1 (8-bit mode flag)
09      1  1 (mono mode flag)
0A      1  ? (0 usually)
0B      1  ? (FFh usually)
0C      4  length of wave data (expressed in 1-byte units)
10      4  FFFFFFFFh (no repeat loop)
14      4  0 (no repeat length)
18      4  20h (offset of the wave data)
1C      4  ?

Signed 8-bit mono wave data follows.


D - Appendix
    ========

D.1 NFSVIEW.PAS
    -----------

{NFS file viewer : recurse into 'wwww' structures and view 'SHPI' bitmaps}

uses crt;
var f:file;
    scr:array[0..199,0..319] of byte absolute $A000:0;
    pal:array[0..767] of byte;
    s:string[5];

procedure setpalette; assembler;
asm
   mov dx,3c8h
   xor cl,cl
   mov si,offset pal
   cld
@bcl:
   mov al,cl
   out dx,al
   inc dx
   lodsb
   out dx,al
   lodsb
   out dx,al
   lodsb
   out dx,al
   dec dx
   inc cl
   jnz @bcl
end;

function st(x:longint):string;
var s:string[20];
begin
     str(x,s);
     st:=s;
end;

procedure viewshpi(pre:string;off:longint); {process a SHPI}
var ni,i:integer;
    w,h,xp,yp,y:word;
    l:longint;
    foundpal:boolean;
begin
     seek(f,off+8);
     blockread(f,ni,2);
     writeln(pre,'SHPI ',ni,' bitmaps'#10#13'Looking for a palette...');
     foundpal:=false;
     for i:=0 to ni-1 do begin {look for a palette}
       seek(f,off+20+8*i);
       blockread(f,l,4);
       seek(f,off+l+4);
       blockread(f,w,2);
       blockread(f,h,2);
       if (w=256) and (h=3) then begin
        blockread(f,pal,8);
        blockread(f,pal,768);
        foundpal:=true;
       end;
     end;
     if foundpal then writeln('Found !') else writeln('No palette.');
     readkey;
     asm
      mov ax,13h
      int 10h
     end;
     if foundpal then setpalette;
     for i:=0 to ni-1 do begin    {display the bitmaps}
       fillchar(scr,64000,0);
       seek(f,off+20+8*i);
       blockread(f,l,4);
       seek(f,off+l+4);
       blockread(f,w,2);
       blockread(f,h,2);
       blockread(f,l,4);
       blockread(f,xp,2);
       blockread(f,yp,2);
       if (w<>256) or (h<>3) then begin
        if (xp+w>320) or (yp+h>200) then begin yp:=0; xp:=0; end;
        for y:=yp to yp+h-1 do
         blockread(f,scr[y,xp],w);
        readkey; end;
     end;
     asm
      mov ax,3
      int 10h
     end;
end;

procedure viewwwww(pre:string;off:longint); {process a wwww block}
var n,i:integer;
    l:longint;
    s:string[5];
begin
     seek(f,off+4);
     blockread(f,n,2);
     for i:=1 to n do begin {process each chunk}
      seek(f,off+4+4*i);
      blockread(f,l,4);
      s[0]:=#4;
      seek(f,off+l);
      blockread(f,s[1],4);  {read 4-char id}
      if s='wwww' then
        viewwwww(pre+'chunk '+st(i)+'/'+st(n)+' sub',off+l)
      else if s='SHPI' then
        viewshpi(pre+'chunk '+st(i)+'/'+st(n)+' ',off+l)
      else begin
       writeln(pre,'chunk ',i,'/',n,' unrecognized header ',s);
       readkey;
      end;
     end;
end;

begin
     if paramcount=0 then begin
       writeln('Need For Speed wwww/SHPI Viewer 1.0 (c) Denis Auroux 1995');
       writeln('Syntax : NFSVIEW filename'#10#13);
       exit;
     end;
     clrscr;
     assign(f,paramstr(1));
     reset(f,1);
     s[0]:=#4;
     blockread(f,s[1],4); {read 4-char id}
     if s='wwww' then viewwwww('',0)
     else if s='SHPI' then viewshpi('',0)
     else writeln('Unrecognized header ',s,#10#13);
     close(f);
end.

============================================================================
For any comments and additions to this file, mail to auroux@clipper.ens.fr.
============================================================================


================================================
FILE: OpenNFS1/Audio/BnkVehicleAudioProvider.cs
================================================
using System;
using System.Collections.Generic;

using System.Text;
using Microsoft.Xna.Framework.Audio;
using GameEngine;
using Microsoft.Xna.Framework;
using OpenNFS1.Physics;
using System.Diagnostics;
using OpenNFS1.Audio;
using OpenNFS1.Parsers.Audio;

namespace OpenNFS1
{
	class VehicleAudioProvider2
	{
		const int GRASS_SLIDE_INDEX = 5;
		DrivableVehicle _car;

		SoundEffect _engineOnEffect, _engineOffEffect, _grassSlide;
		SoundEffectInstance _engineOn, _engineOff, _skidInstance, _grassSlideInstance;
		SoundEffect _gearChange;
		List<SoundEffect> _skids = new List<SoundEffect>();
		bool _isActive = false;

		public VehicleAudioProvider2(DrivableVehicle car)
		{
			_car = car;
		}


		public void Initialize()
		{
			if (_engineOn != null)
			{
				return;
			}

			_isActive = true;

			BnkFile bnk = new BnkFile(_car.Descriptor.SoundBnkFile);
			var sample = bnk.Samples[0];
			_engineOnEffect = new SoundEffect(sample.PCMData, sample.SampleRate, sample.NbrChannels == 2 ? AudioChannels.Stereo : AudioChannels.Mono);
			_engineOn = _engineOnEffect.CreateInstance();
			sample = bnk.Samples[1];
			_engineOffEffect = new SoundEffect(sample.PCMData, sample.SampleRate, sample.NbrChannels == 2 ? AudioChannels.Stereo : AudioChannels.Mono);
			_engineOff = _engineOffEffect.CreateInstance();
			sample = bnk.Samples[3];
			_gearChange = new SoundEffect(sample.PCMData, sample.SampleRate, sample.NbrChannels == 2 ? AudioChannels.Stereo : AudioChannels.Mono);
			

			//temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format("Content/Audio/Vehicles/{0}/engine-on-low", _car.Descriptor.Name));
			//_engineOnLow = temp.CreateInstance();
			////.Play(0.3f, 0, 0);
			//temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format("Content/Audio/Vehicles/{0}/engine-on-high", _car.Descriptor.Name));
			//_engineOn = temp.CreateInstance(); // temp.Play(0.3f, 0, 0);
			//temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format("Content/Audio/Vehicles/{0}/engine-off-low", _car.Descriptor.Name));
			//_engineOffLow = temp.CreateInstance(); //temp.Play(0.3f, 0, 0);
			//temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format("Content/Audio/Vehicles/{0}/engine-off-high", _car.Descriptor.Name));
			//_engineOff = temp.CreateInstance(); //temp.Play(0.3f, 0, 0);

			BnkFile envBnk = new BnkFile("COLL_SW.BNK");
			sample = envBnk.Samples[GRASS_SLIDE_INDEX];
			_grassSlide = new SoundEffect(sample.PCMData, sample.SampleRate, sample.NbrChannels == 2 ? AudioChannels.Stereo : AudioChannels.Mono);
			_grassSlideInstance = _grassSlide.CreateInstance();

			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>("Content/Audio/Vehicles/common/skid1"));
			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>("Content/Audio/Vehicles/common/skid2"));
			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>("Content/Audio/Vehicles/common/skid3"));
		}

		public void UpdateEngine()
		{
			if (!_isActive) return;
			float engineRpmFactor = ((_car.Motor.Rpm - 0.8f) / _car.Motor.RedlineRpm) - 0.5f;
			if (_car.Motor.Throttle == 0 && !_car.Motor.AtRedline)
			{
				_engineOn.Pause();
				_engineOff.Resume();
				_engineOff.Pitch = engineRpmFactor;
			}
			else
			{
				_engineOn.Resume();
				_engineOff.Pause();
				_engineOn.Pitch = engineRpmFactor;
			}
		}

		public void PlaySkid(bool play)
		{
			if (!_isActive) return;
			if (play)
			{
				if (_skidInstance != null && _skidInstance.State == SoundState.Playing)
					return;
				if (_skidInstance != null && _skidInstance.State != SoundState.Playing)
				{
					_skidInstance.Resume();
				}
				else
				{
					_skidInstance = _skids[Engine.Instance.Random.Next(_skids.Count)].CreateInstance(); //.Play(0.3f, 0, 0);
				}
			}
			else
			{
				if (_skidInstance != null && _skidInstance.State == SoundState.Playing)
				{
					_skidInstance.Stop();
					_skidInstance = null;
				}
			}
		}

		public void ChangeGear()
		{
			if (!_isActive) return;
			_gearChange.Play();
		}

		public void HitGround()
		{
			if (!_isActive) return;
			EnvironmentAudioProvider.Instance.PlayCollision(2);
			SoundEngine2.Instance.PlayEffect(_skids[2].CreateInstance(), 0.2f);
		}


		public void PlayOffRoad(bool play)
		{
			if (!_isActive) return;
			if (play)
			{
				_grassSlideInstance.Volume = 0.4f;
				if (_grassSlideInstance.State == SoundState.Playing)
					return;
				else
					_grassSlideInstance.Resume();
			}
			else
			{
				_grassSlideInstance.Pause();
			}
		}

		public void StopAll()
		{
			if (!_isActive) return;
			if (_skidInstance != null)
				_skidInstance.Stop();
			_engineOff.Stop();
			_engineOn.Stop();
		}
	}
}


================================================
FILE: OpenNFS1/Audio/EnvironmentAudioProvider.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Audio;
using GameEngine;

namespace OpenNFS1.Audio
{
    class EnvironmentAudioProvider
    {
        private static EnvironmentAudioProvider _instance;

        public static EnvironmentAudioProvider Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new EnvironmentAudioProvider();
                }
                return _instance;
            }
        }

        List<SoundEffect> _collisions;
        SoundEffectInstance _collisionInstance;

		public string BasePath { get { return GameConfig.CdDataPath + "/ConvertedAudio"; } }
        
        private EnvironmentAudioProvider()
        {
            _collisions = new List<SoundEffect>();
            _collisions.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Environment/collision1"));
			_collisions.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Environment/collision2"));
			_collisions.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Environment/collision3"));
        }

        public void PlayVehicleFenceCollision()
        {
            if (_collisionInstance != null && _collisionInstance.State == SoundState.Playing)
            {
                return;
            }
            _collisionInstance = _collisions[Utility.RandomGenerator.Next(_collisions.Count)].CreateInstance();
			_collisionInstance.Play();
        }

        public void PlayCollision(int index)
        {
            _collisions[index].Play(0.5f, 0, 0);
        }

        
    }
}


================================================
FILE: OpenNFS1/Audio/VehicleAudioProvider.cs
================================================
using System;
using System.Collections.Generic;

using System.Text;
using Microsoft.Xna.Framework.Audio;
using GameEngine;
using Microsoft.Xna.Framework;
using OpenNFS1.Physics;
using System.Diagnostics;
using OpenNFS1.Audio;

namespace OpenNFS1
{
    class VehicleAudioProvider
    {
        DrivableVehicle _car;

        SoundEffectInstance _engineOnLow, _engineOnHigh, _engineOffLow, _engineOffHigh, _skidInstance, _offRoadInstance;
        SoundEffect _gearChange;
        List<SoundEffect> _skids = new List<SoundEffect>();
		bool _isActive = false;
                
        public VehicleAudioProvider(DrivableVehicle car)
        {
            _car = car;
        }

		public string BasePath { get { return GameConfig.CdDataPath + "/ConvertedAudio"; } }


        public void Initialize()
        {
			if (_engineOnLow != null)
            {
                return;
            }

			_isActive = true;
            
            SoundEffect temp;
			temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format(BasePath + "/Vehicles/{0}/engine-on-low", _car.Descriptor.Name));
            _engineOnLow = temp.CreateInstance();
			//.Play(0.3f, 0, 0);
			temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format(BasePath + "/Vehicles/{0}/engine-on-high", _car.Descriptor.Name));
			_engineOnHigh = temp.CreateInstance(); // temp.Play(0.3f, 0, 0);
			temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format(BasePath + "/Vehicles/{0}/engine-off-low", _car.Descriptor.Name));
			_engineOffLow = temp.CreateInstance(); //temp.Play(0.3f, 0, 0);
			temp = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format(BasePath + "/Vehicles/{0}/engine-off-high", _car.Descriptor.Name));
			_engineOffHigh = temp.CreateInstance(); //temp.Play(0.3f, 0, 0);

			temp = Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Vehicles/common/grass_slide");
			_offRoadInstance = temp.CreateInstance(); //temp.Play(0.3f, 0, 0, true);
            _offRoadInstance.Pause();

			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Vehicles/common/skid1"));
			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Vehicles/common/skid2"));
			_skids.Add(Engine.Instance.ContentManager.Load<SoundEffect>(BasePath + "/Vehicles/common/skid3"));

            _engineOnLow.Pause();
            _engineOnHigh.Pause();
            _engineOffLow.Pause();
            _engineOffHigh.Pause();

			_gearChange = Engine.Instance.ContentManager.Load<SoundEffect>(String.Format(BasePath + "/Vehicles/{0}/gear-change", _car.Descriptor.Name));

        }

        public void UpdateEngine()
        {
			if (!_isActive) return;
            float engineRpmFactor = (_car.Motor.Rpm - 0.8f) / _car.Motor.RedlineRpm;
            SoundEffectInstance low, high;

            if (_car.Motor.Throttle == 0 && !_car.Motor.AtRedline)
            {
                _engineOnHigh.Pause();
                _engineOnLow.Pause();
                _engineOffHigh.Resume();
                _engineOffLow.Resume();
                low = _engineOffLow;
                high = _engineOffHigh;
            }
            else
            {
                _engineOnHigh.Resume();
                _engineOnLow.Resume();
                _engineOffHigh.Pause();
                _engineOffLow.Pause();
                low = _engineOnLow;
                high = _engineOnHigh;
            }

            low.Volume = engineRpmFactor > 0.55f ? 0 : 0.3f;
            high.Volume = engineRpmFactor < 0.45f ? 0 : 0.3f;

            if (engineRpmFactor < 0.1f)
            {
                low.Volume = MathHelper.Lerp(0.1f, 0.3f, (engineRpmFactor) * 10);
            }
            
            if (engineRpmFactor > 0.45f && engineRpmFactor < 0.55f)
            {
                low.Volume = MathHelper.Lerp(0.3f, 0f, (engineRpmFactor - 0.45f) * 10);
                high.Volume = MathHelper.Lerp(0, 0.3f, (engineRpmFactor - 0.45f) * 10);
            }

            low.Pitch = engineRpmFactor - 0.1f;
            high.Pitch = engineRpmFactor - 0.5f;
        }

        public void PlaySkid(bool play)
        {
			if (!_isActive) return;
            if (play)
            {
                if (_skidInstance != null && _skidInstance.State == SoundState.Playing)
                    return;
                if (_skidInstance != null && _skidInstance.State != SoundState.Playing)
                {
                    _skidInstance.Resume();
                }
                else
                {
                    _skidInstance = _skids[Engine.Instance.Random.Next(_skids.Count)].CreateInstance(); //.Play(0.3f, 0, 0);
                }
            }
            else
            {
                if (_skidInstance != null && _skidInstance.State == SoundState.Playing)
                {
                    _skidInstance.Stop();
                    _skidInstance = null;
                }
            }                
        }

        public void ChangeGear()
        {
			if (!_isActive) return;
            _gearChange.Play();
        }

        public void HitGround()
        {
			if (!_isActive) return;
            EnvironmentAudioProvider.Instance.PlayCollision(2);
            SoundEngine2.Instance.PlayEffect(_skids[2].CreateInstance(), 0.2f);
        }


        public void PlayOffRoad(bool play)
        {
			if (!_isActive) return;
            if (play)
            {
                _offRoadInstance.Volume = 0.4f;
                if (_offRoadInstance.State == SoundState.Playing)
                    return;
                else
                    _offRoadInstance.Resume();
            }
            else
            {
                _offRoadInstance.Pause();
            }
        }

        public void StopAll()
        {
			if (!_isActive) return;
            if (_skidInstance != null)
                _skidInstance.Stop();
            _engineOffHigh.Stop();
            _engineOffLow.Stop();
            _engineOnHigh.Stop();
            _engineOnLow.Stop();
            
        }
    }
}


================================================
FILE: OpenNFS1/AverageValue.cs
================================================
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace OpenNFS1
{
    class AverageValue
    {
        int _nbrValues;
        List<float> _values = new List<float>();

        public AverageValue(int nbrVaues)
        {
            _nbrValues = nbrVaues;
        }

        public void AddValue(float value)
        {
            _values.Add(value);
            if (_values.Count > _nbrValues)
                _values.RemoveAt(0);
        }

        public float GetAveragedValue()
        {
            float average = 0;
            foreach (float value in _values)
            {
                average += value;
            }
            return average / _values.Count;
        }

        public void Clear()
        {
            _values.Clear();
        }
    }

    
}


================================================
FILE: OpenNFS1/Content/ArialBlack-Italic.spritefont
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>Arial Black</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>26</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Italic</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>


================================================
FILE: OpenNFS1/Content/ArialBlack.spritefont
================================================
<?xml version="1.0" encoding="utf-8"?>
<!--
This file contains an xml description of a font, and will be read by the XNA
Framework Content Pipeline. Follow the comments to customize the appearance
of the font in your game, and to change the characters which are available to draw
with.
-->
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
  <Asset Type="Graphics:FontDescription">

    <!--
    Modify this string to change the font that will be imported.
    -->
    <FontName>Arial Black</FontName>

    <!--
    Size is a float value, measured in points. Modify this value to change
    the size of the font.
    -->
    <Size>26</Size>

    <!--
    Spacing is a float value, measured in pixels. Modify this value to change
    the amount of spacing in between characters.
    -->
    <Spacing>0</Spacing>

    <!--
    UseKerning controls the layout of the font. If this value is true, kerning information
    will be used when placing characters.
    -->
    <UseKerning>true</UseKerning>

    <!--
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
    and "Bold, Italic", and are case sensitive.
    -->
    <Style>Regular</Style>

    <!--
    If you uncomment this line, the default character will be substituted if you draw
    or measure text that contains characters which were not included in the font.
    -->
    <!-- <DefaultCharacter>*</DefaultCharacter> -->

    <!--
    CharacterRegions control what letters are available in the font. Every
    character from Start to End will be built and made available for drawing. The
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
    character set. The characters are ordered according to the Unicode standard.
    See the documentation for more information.
    -->
    <CharacterRegions>
      <CharacterRegion>
        <Start>&#32;</Start>
        <End>&#126;</End>
      </CharacterRegion>
    </CharacterRegions>
  </Asset>
</XnaContent>


================================================
FILE: OpenNFS1/Content/ParticleEffect.fx
================================================
//-----------------------------------------------------------------------------
// ParticleEffect.fx
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


// Camera parameters.
float4x4 View;
float4x4 Projection;
float2 ViewportScale;


// The current time, in seconds.
float CurrentTime;


// Parameters describing how the particles animate.
float Duration;
float DurationRandomness;
float3 Gravity;
float EndVelocity;
float4 MinColor;
float4 MaxColor;


// These float2 parameters describe the min and max of a range.
// The actual value is chosen differently for each particle,
// interpolating between x and y by some random amount.
float2 RotateSpeed;
float2 StartSize;
float2 EndSize;


// Particle texture and sampler.
texture Texture;

sampler Sampler2 = sampler_state
{
	Texture = <Texture>;

	MinFilter = Linear;
	MagFilter = Linear;
	MipFilter = Point;

	AddressU = Clamp;
	AddressV = Clamp;
};


// Vertex shader input structure describes the start position and
// velocity of the particle, and the time at which it was created,
// along with some random values that affect its size and rotation.
struct VertexShaderInput
{
	float2 Corner : POSITION0;
	float3 Position : POSITION1;
	float3 Velocity : NORMAL0;
	float4 Random : COLOR0;
	float Time : TEXCOORD0;
};


// Vertex shader output structure specifies the position and color of the particle.
struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float4 Color : COLOR0;
	float2 TextureCoordinate : COLOR1;
};


// Vertex shader helper for computing the position of a particle.
float4 ComputeParticlePosition(float3 position, float3 velocity,
	float age, float normalizedAge)
{
	float startVelocity = length(velocity);

	// Work out how fast the particle should be moving at the end of its life,
	// by applying a constant scaling factor to its starting velocity.
	float endVelocity = startVelocity * EndVelocity;

	// Our particles have constant acceleration, so given a starting velocity
	// S and ending velocity E, at time T their velocity should be S + (E-S)*T.
	// The particle position is the sum of this velocity over the range 0 to T.
	// To compute the position directly, we must integrate the velocity
	// equation. Integrating S + (E-S)*T for T produces S*T + (E-S)*T*T/2.

	float velocityIntegral = startVelocity * normalizedAge +
		(endVelocity - startVelocity) * normalizedAge *
		normalizedAge / 2;

	position += normalize(velocity) * velocityIntegral * Duration;

	// Apply the gravitational force.
	position += Gravity * age * normalizedAge;

	// Apply the camera view and projection transforms.
	return mul(mul(float4(position, 1), View), Projection);
}


// Vertex shader helper for computing the size of a particle.
float ComputeParticleSize(float randomValue, float normalizedAge)
{
	// Apply a random factor to make each particle a slightly different size.
	float startSize = lerp(StartSize.x, StartSize.y, randomValue);
	float endSize = lerp(EndSize.x, EndSize.y, randomValue);

	// Compute the actual size based on the age of the particle.
	float size = lerp(startSize, endSize, normalizedAge);

	// Project the size into screen coordinates.
	return size * Projection._m11;
}


// Vertex shader helper for computing the color of a particle.
float4 ComputeParticleColor(float4 projectedPosition,
	float randomValue, float normalizedAge)
{
	// Apply a random factor to make each particle a slightly different color.
	float4 color = lerp(MinColor, MaxColor, randomValue);

		// Fade the alpha based on the age of the particle. This curve is hard coded
		// to make the particle fade in fairly quickly, then fade out more slowly:
		// plot x*(1-x)*(1-x) for x=0:1 in a graphing program if you want to see what
		// this looks like. The 6.7 scaling factor normalizes the curve so the alpha
		// will reach all the way up to fully solid.

		color.a *= normalizedAge * (1 - normalizedAge) * (1 - normalizedAge) * 6.7;

	return color;
}


// Vertex shader helper for computing the rotation of a particle.
float2x2 ComputeParticleRotation(float randomValue, float age)
{
	// Apply a random factor to make each particle rotate at a different speed.
	float rotateSpeed = lerp(RotateSpeed.x, RotateSpeed.y, randomValue);

	float rotation = rotateSpeed * age;

	// Compute a 2x2 rotation matrix.
	float c = cos(rotation);
	float s = sin(rotation);

	return float2x2(c, -s, s, c);
}


// Custom vertex shader animates particles entirely on the GPU.
VertexShaderOutput ParticleVertexShader(VertexShaderInput input)
{
	VertexShaderOutput output;

	// Compute the age of the particle.
	float age = CurrentTime - input.Time;

	// Apply a random factor to make different particles age at different rates.
	age *= 1 + input.Random.x * DurationRandomness;

	// Normalize the age into the range zero to one.
	float normalizedAge = saturate(age / Duration);

	// Compute the particle position, size, color, and rotation.
	output.Position = ComputeParticlePosition(input.Position, input.Velocity,
		age, normalizedAge);

	float size = ComputeParticleSize(input.Random.y, normalizedAge);
	float2x2 rotation = ComputeParticleRotation(input.Random.w, age);

		output.Position.xy += mul(input.Corner, rotation) * size * ViewportScale;

	output.Color = ComputeParticleColor(output.Position, input.Random.z, normalizedAge);
	output.TextureCoordinate = (input.Corner + 1) / 2;

	return output;
}


// Pixel shader for drawing particles.
float4 ParticlePixelShader(VertexShaderOutput input) : COLOR0
{
	float2 tex = input.TextureCoordinate;

	float4 v = tex2D(Sampler2, tex);

	return v * input.Color;
}


// Effect technique for drawing particles.
technique Particles
{
	pass P0
	{
		VertexShader = compile vs_2_0 ParticleVertexShader();
		PixelShader = compile ps_2_0 ParticlePixelShader();
	}
}


================================================
FILE: OpenNFS1/Content/common.fxh
================================================
//-----------------------------------------------------------------------------
// Common.fxh
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


float ComputeFogFactor(float4 position)
{
    return saturate(dot(position, FogVector));
}


void ApplyFog(inout float4 color, float fogFactor)
{
    color.rgb = lerp(color.rgb, FogColor * color.a, fogFactor);
}


void AddSpecular(inout float4 color, float3 specular)
{
    color.rgb += specular * color.a;
}


struct CommonVSOutput
{
    float4 Pos_ps;
    float4 Diffuse;
    float3 Specular;
    float  FogFactor;
};


CommonVSOutput ComputeCommonVSOutput(float4 position)
{
    CommonVSOutput vout;
    
    vout.Pos_ps = mul(position, WorldViewProj);
    vout.Diffuse = DiffuseColor;
    vout.Specular = 0;
    vout.FogFactor = ComputeFogFactor(position);
    
    return vout;
}


#define SetCommonVSOutputParams \
    vout.PositionPS = cout.Pos_ps; \
    vout.Diffuse = cout.Diffuse; \
    vout.Specular = float4(cout.Specular, cout.FogFactor);


#define SetCommonVSOutputParamsNoFog \
    vout.PositionPS = cout.Pos_ps; \
    vout.Diffuse = cout.Diffuse;

================================================
FILE: OpenNFS1/Content/macros.fxh
================================================
//-----------------------------------------------------------------------------
// Macros.fxh
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------

#ifdef SM4

// Macros for targetting shader model 4.0 (DX11)

#define TECHNIQUE(name, vsname, psname ) \
	technique name { pass { VertexShader = compile vs_4_0_level_9_1 vsname (); PixelShader = compile ps_4_0_level_9_1 psname(); } }

#define BEGIN_CONSTANTS     cbuffer Parameters : register(b0) {
#define MATRIX_CONSTANTS
#define END_CONSTANTS       };

#define _vs(r)
#define _ps(r)
#define _cb(r)

#define DECLARE_TEXTURE(Name, index) \
    Texture2D<float4> Name : register(t##index); \
    sampler Name##Sampler : register(s##index)

#define DECLARE_CUBEMAP(Name, index) \
    TextureCube<float4> Name : register(t##index); \
    sampler Name##Sampler : register(s##index)

#define SAMPLE_TEXTURE(Name, texCoord)  Name.Sample(Name##Sampler, texCoord)
#define SAMPLE_CUBEMAP(Name, texCoord)  Name.Sample(Name##Sampler, texCoord)


#else


// Macros for targetting shader model 2.0 (DX9)

#define TECHNIQUE(name, vsname, psname ) \
	technique name { pass { VertexShader = compile vs_2_0 vsname (); PixelShader = compile ps_2_0 psname(); } }

#define BEGIN_CONSTANTS
#define MATRIX_CONSTANTS
#define END_CONSTANTS

#define _vs(r)  : register(vs, r)
#define _ps(r)  : register(ps, r)
#define _cb(r)

#define DECLARE_TEXTURE(Name, index) \
    sampler2D Name : register(s##index);

#define DECLARE_CUBEMAP(Name, index) \
    samplerCUBE Name : register(s##index);

#define SAMPLE_TEXTURE(Name, texCoord)  tex2D(Name, texCoord)
#define SAMPLE_CUBEMAP(Name, texCoord)  texCUBE(Name, texCoord)


#endif

================================================
FILE: OpenNFS1/Content/structures.fxh
================================================
//-----------------------------------------------------------------------------
// Structurs.fxh
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


// Vertex shader input structures.

struct VSInput
{
    float4 Position : SV_Position;
};

struct VSInputVc
{
    float4 Position : SV_Position;
    float4 Color    : COLOR;
};

struct VSInputTx
{
    float4 Position : SV_Position;
    float2 TexCoord : TEXCOORD0;
};

struct VSInputTxVc
{
    float4 Position : SV_Position;
    float2 TexCoord : TEXCOORD0;
    float4 Color    : COLOR;
};

struct VSInputNm
{
    float4 Position : SV_Position;
    float3 Normal   : NORMAL;
};

struct VSInputNmVc
{
    float4 Position : SV_Position;
    float3 Normal   : NORMAL;
    float4 Color    : COLOR;
};

struct VSInputNmTx
{
    float4 Position : SV_Position;
    float3 Normal   : NORMAL;
    float2 TexCoord : TEXCOORD0;
};

struct VSInputNmTxVc
{
    float4 Position : SV_Position;
    float3 Normal   : NORMAL;
    float2 TexCoord : TEXCOORD0;
    float4 Color    : COLOR;
};

struct VSInputTx2
{
    float4 Position  : SV_Position;
    float2 TexCoord  : TEXCOORD0;
    float2 TexCoord2 : TEXCOORD1;
};

struct VSInputTx2Vc
{
    float4 Position  : SV_Position;
    float2 TexCoord  : TEXCOORD0;
    float2 TexCoord2 : TEXCOORD1;
    float4 Color     : COLOR;
};

struct VSInputNmTxWeights
{
    float4 Position : SV_Position;
    float3 Normal   : NORMAL;
    float2 TexCoord : TEXCOORD0;
    int4   Indices  : BLENDINDICES0;
    float4 Weights  : BLENDWEIGHT0;
};



// Vertex shader output structures.

struct VSOutput
{
    float4 PositionPS : SV_Position;
    float4 Diffuse    : COLOR0;
    float4 Specular   : COLOR1;
};

struct VSOutputNoFog
{
    float4 PositionPS : SV_Position;
    float4 Diffuse    : COLOR0;
};

struct VSOutputTx
{
    float4 PositionPS : SV_Position;
    float4 Diffuse    : COLOR0;
    float4 Specular   : COLOR1;
    float2 TexCoord   : TEXCOORD0;
};

struct VSOutputTxNoFog
{
    float4 PositionPS : SV_Position;
    float4 Diffuse    : COLOR0;
    float2 TexCoord   : TEXCOORD0;
};

struct VSOutputPixelLighting
{
    float4 PositionPS : SV_Position;
    float4 PositionWS : TEXCOORD0;
    
Download .txt
gitextract_3ncehpj2/

├── .editorconfig
├── .gitignore
├── Engine/
│   ├── AverageValueVector3.cs
│   ├── ChaseCamera.cs
│   ├── Engine.cs
│   ├── FPSCamera.cs
│   ├── FPSCounter.cs
│   ├── FixedChaseCamera.cs
│   ├── GameConsole.cs
│   ├── GameEngine.csproj
│   ├── GameObject.cs
│   ├── GraphicsUtilities.cs
│   ├── ICamera.cs
│   ├── IDrawableObject.cs
│   ├── IGameScreen.cs
│   ├── IWorld.cs
│   ├── InputProvider.cs
│   ├── ParticleSystem/
│   │   ├── ParticleEmitter.cs
│   │   ├── ParticleSettings.cs
│   │   ├── ParticleSystem.cs
│   │   └── ParticleVertex.cs
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── ScreenEffects.cs
│   ├── SimpleCamera.cs
│   ├── SkyBox.cs
│   ├── SoundEngine2.cs
│   └── Utility.cs
├── Installer/
│   ├── OpenNFS1.nsi
│   ├── build-installer.bat
│   └── readme.txt
├── NFSSpecs.txt
├── OpenNFS1/
│   ├── Audio/
│   │   ├── BnkVehicleAudioProvider.cs
│   │   ├── EnvironmentAudioProvider.cs
│   │   └── VehicleAudioProvider.cs
│   ├── AverageValue.cs
│   ├── Content/
│   │   ├── ArialBlack-Italic.spritefont
│   │   ├── ArialBlack.spritefont
│   │   ├── ParticleEffect.fx
│   │   ├── common.fxh
│   │   ├── macros.fxh
│   │   └── structures.fxh
│   ├── Dashboards/
│   │   ├── Dashboard.cs
│   │   ├── DashboardDescription.cs
│   │   └── GearboxAnimation.cs
│   ├── Game1.cs
│   ├── GameConfig.cs
│   ├── Mesh.cs
│   ├── ObjectShadow.cs
│   ├── OpenNFS1.csproj
│   ├── Parsers/
│   │   ├── Audio/
│   │   │   ├── BnkFile.cs
│   │   │   └── WavWriter.cs
│   │   ├── BaseChunk.cs
│   │   ├── BitmapChunk.cs
│   │   ├── BitmapLoader.cs
│   │   ├── CfmFile.cs
│   │   ├── FshFile.cs
│   │   ├── HeaderChunk.cs
│   │   ├── MeshChunk.cs
│   │   ├── OpenRoadTrackfamFile.cs
│   │   ├── QfsFile.cs
│   │   ├── TrackfamFile.cs
│   │   └── TriFile.cs
│   ├── Physics/
│   │   ├── AutoGearbox.cs
│   │   ├── BaseGearbox.cs
│   │   ├── DrivableVehicle.cs
│   │   ├── ManualGearbox.cs
│   │   ├── Motor.cs
│   │   ├── Spring.cs
│   │   ├── Vector3Helper.cs
│   │   ├── VehicleFenceCollision.cs
│   │   └── VehicleWheel.cs
│   ├── PlayerUI.cs
│   ├── Polygon.cs
│   ├── Program.cs
│   ├── Properties/
│   │   └── AssemblyInfo.cs
│   ├── Race/
│   │   ├── PlayerRaceStats.cs
│   │   ├── Race.cs
│   │   └── RaceUI.cs
│   ├── Tracks/
│   │   ├── SceneryObject.cs
│   │   ├── TerrainRow.cs
│   │   ├── TerrainSegment.cs
│   │   ├── Track.cs
│   │   ├── TrackAssembler.cs
│   │   ├── TrackBillboardModel.cs
│   │   ├── TrackDescription.cs
│   │   ├── TrackNode.cs
│   │   ├── TrackObjectDescriptor.cs
│   │   └── TrackSkybox.cs
│   ├── UI/
│   │   └── Screens/
│   │       ├── BaseUIScreen.cs
│   │       ├── ChooseDataDownloadScreen.cs
│   │       ├── DataDownloadScreen.cs
│   │       ├── DoRaceScreen.cs
│   │       ├── HomeScreen.cs
│   │       ├── LoadRaceScreen.cs
│   │       ├── OpenNFS1SplashScreen.cs
│   │       ├── RaceFinishedScreen.cs
│   │       ├── RaceOptionsScreen.cs
│   │       └── RacePausedScreen.cs
│   ├── UIController.cs
│   ├── VehicleController.cs
│   ├── Vehicles/
│   │   ├── AI/
│   │   │   ├── AIDriver.cs
│   │   │   ├── IDriver.cs
│   │   │   └── TrafficDriver.cs
│   │   ├── CarMesh.cs
│   │   ├── CarModelCache.cs
│   │   ├── PlayerDriver.cs
│   │   ├── Traffic/
│   │   │   └── TrafficController.cs
│   │   ├── TyreSmokeParticleSystem.cs
│   │   ├── Vehicle.cs
│   │   ├── VehicleDescription.cs
│   │   └── WheelModel.cs
│   ├── Views/
│   │   ├── BaseExternalView.cs
│   │   ├── BumperView.cs
│   │   ├── ChaseView.cs
│   │   ├── DashboardView.cs
│   │   ├── DebugView.cs
│   │   ├── DropCameraView.cs
│   │   └── IView.cs
│   └── gameconfig.json
├── OpenNFS1.sln
├── PreBuilt_Content/
│   ├── ArialBlack-Italic.xnb
│   ├── ArialBlack.xnb
│   └── ParticleEffect.xnb
├── TnfsSeSpex.txt
├── readme.md
└── reverse_engineering.txt
Download .txt
SYMBOL INDEX (584 symbols across 102 files)

FILE: Engine/AverageValueVector3.cs
  class AverageValueVector3 (line 8) | public class AverageValueVector3
    method AverageValueVector3 (line 13) | public AverageValueVector3(int nbrVaues)
    method Reset (line 18) | public void Reset(int nbrValues)
    method AddValue (line 24) | public void AddValue(Vector3 value)
    method GetAveragedValue (line 31) | public Vector3 GetAveragedValue()

FILE: Engine/ChaseCamera.cs
  class ChaseCamera (line 11) | public class ChaseCamera : ICamera
    method FollowObject (line 42) | public void FollowObject(GameObject obj)
    method UpdateWorldPositions (line 224) | private void UpdateWorldPositions()
    method UpdateMatrices (line 239) | private void UpdateMatrices()
    method Reset (line 252) | public void Reset()
    method Update (line 270) | public void Update(GameTime gameTime)
    method SetPosition (line 300) | public void SetPosition(Vector3 position)

FILE: Engine/Engine.cs
  class Engine (line 12) | public class Engine : DrawableGameComponent
    method Create (line 34) | public static void Create(Game game, GraphicsDeviceManager graphics)
    method Engine (line 42) | private Engine(Game game)
    method EngineStartup (line 48) | private void EngineStartup(GraphicsDeviceManager graphics)
    method Update (line 72) | public override void Update(GameTime gameTime)
    method Draw (line 89) | public override void Draw(GameTime gameTime)

FILE: Engine/FPSCamera.cs
  class FPSCamera (line 43) | public class FPSCamera : ICamera
    method FPSCamera (line 81) | public FPSCamera()
    method Update (line 88) | public void Update(GameTime gt)
    method UpdateVelocity (line 131) | private void UpdateVelocity()
    method MoveForward (line 184) | public void MoveForward()
    method SetPosition (line 191) | public void SetPosition(Vector3 pos)
    method FollowObject (line 196) | public void FollowObject(GameObject obj)

FILE: Engine/FPSCounter.cs
  class FrameRateCounter (line 9) | public class FrameRateCounter : DrawableGameComponent
    method FrameRateCounter (line 16) | public FrameRateCounter()
    method Update (line 21) | public override void Update(GameTime gameTime)
    method Draw (line 33) | public override void Draw(GameTime gameTime)

FILE: Engine/FixedChaseCamera.cs
  class FixedChaseCamera (line 12) | public class FixedChaseCamera : ICamera
    method FixedChaseCamera (line 14) | public FixedChaseCamera()
    method Update (line 97) | public void Update(GameTime gameTime)
    method SetPosition (line 106) | public void SetPosition(Vector3 position)
    method FollowObject (line 111) | public void FollowObject(GameObject obj)

FILE: Engine/GameConsole.cs
  class GameConsole (line 10) | public static class GameConsole
    method Clear (line 13) | public static void Clear()
    method WriteLine (line 18) | public static void WriteLine(object o)
    method WriteLine (line 25) | public static void WriteLine(Vector3 vec)

FILE: Engine/GameObject.cs
  class GameObject (line 8) | public abstract class GameObject
    method GameObject (line 16) | public GameObject()
    method SetRotation (line 57) | public void SetRotation(float rotation)
    method MoveForward (line 62) | public void MoveForward()
    method GetLookAt (line 71) | public Vector3 GetLookAt(float distance)
    method GetLookAt (line 80) | public Vector3 GetLookAt(Vector3 orientation, float distance)
    method Strafe (line 89) | public void Strafe(float amount)
    method Move (line 114) | public void Move(float dx, float dy, float dz)
    method Move (line 126) | public void Move(Vector3 direction, float amount)
    method Rotate (line 131) | public void Rotate(float amount)
    method Pitch (line 136) | public void Pitch(float amount)
    method GetCameraPosition (line 142) | public virtual Vector3 GetCameraPosition()
    method Update (line 155) | public abstract void Update(GameTime gameTime);
    method Render (line 156) | public abstract void Render();
    method OnPlayerSelect (line 158) | public virtual void OnPlayerSelect() { }

FILE: Engine/GraphicsUtilities.cs
  type Justify (line 14) | public enum Justify
  type ShapeType (line 31) | public enum ShapeType
  class GraphicsUtilities (line 49) | public class GraphicsUtilities : IDrawableObject
    method GraphicsUtilities (line 52) | public GraphicsUtilities(SpriteFont font)
    method Update (line 63) | public void Update(GameTime gameTime)
    method Draw (line 73) | public void Draw()
    method DrawText (line 132) | public void DrawText()
    method AddCube (line 173) | public void AddCube(Matrix worldTransform, Color color)
    method AddLine (line 194) | public void AddLine(Vector3 startPos, Vector3 endPos, Color color)
    method AddText (line 216) | public void AddText(Vector2 pos, String text, Justify justify, Color c...
    method AddText (line 241) | public void AddText(Vector3 worldPos, String text, Justify justify, Co...
    method AddAxis (line 263) | public void AddAxis(Matrix worldTransform, float scale)
    method AddWireframeCube (line 276) | public void AddWireframeCube(Matrix worldTransform, Color color)
    method AddSquareGrid (line 319) | public void AddSquareGrid(Matrix worldTransform, int numRows, Color co...
    method SetViewMatrix (line 363) | public void SetViewMatrix(Matrix view)
    method SetProjectionMatrix (line 368) | public void SetProjectionMatrix(Matrix proj)
    method ClearShapes (line 376) | public void ClearShapes()
    method ClearLines (line 384) | public void ClearLines()
    method ClearText (line 393) | public void ClearText()
    method JustifyText (line 405) | private void JustifyText(SpriteFont font, String text, Justify justify...
    method CreateLineEffect (line 459) | private void CreateLineEffect()
    method CreateShapeEffect (line 469) | private void CreateShapeEffect()
    method CreateCube (line 497) | private void CreateCube()
    type TextData (line 580) | struct TextData
    type ShapeData (line 589) | struct ShapeData

FILE: Engine/ICamera.cs
  type ICamera (line 9) | public interface ICamera
    method FollowObject (line 21) | void FollowObject(GameObject obj);
    method Update (line 23) | void Update(GameTime time);
    method SetPosition (line 27) | void SetPosition(Vector3 position);

FILE: Engine/IDrawableObject.cs
  type IDrawableObject (line 8) | public interface IDrawableObject
    method Update (line 10) | void Update(GameTime gameTime);
    method Draw (line 11) | void Draw();

FILE: Engine/IGameScreen.cs
  type IGameScreen (line 7) | public interface IGameScreen : IDrawableObject

FILE: Engine/IWorld.cs
  type IWorld (line 8) | public interface IWorld : IDrawableObject
    method GetHeightAtPoint (line 10) | float GetHeightAtPoint(Vector3 position);
    method Reset (line 11) | void Reset();

FILE: Engine/InputProvider.cs
  type Actions (line 10) | public enum Actions
  type MouseInputMode (line 28) | public enum MouseInputMode
  class InputProvider (line 34) | public class InputProvider : GameComponent
    method InputProvider (line 45) | public InputProvider(Game game)
    method Update (line 57) | public override void Update(GameTime gameTime)
    method GetScreenCenter (line 73) | private Vector2 GetScreenCenter()
    method WasPressed (line 108) | public bool WasPressed(Keys key)
    method WasPressed (line 113) | public bool WasPressed(Buttons button)
    method IsKeyDown (line 118) | public bool IsKeyDown(Keys key)

FILE: Engine/ParticleSystem/ParticleEmitter.cs
  class ParticleEmitter (line 39) | public class ParticleEmitter
    method ParticleEmitter (line 61) | public ParticleEmitter(ParticleSystem particleSystem, float particlesP...
    method Update (line 72) | public void Update(Vector3 newPosition)
    method Update (line 81) | public void Update(Vector3 newPosition, ParticleSystem particleSystem)

FILE: Engine/ParticleSystem/ParticleSettings.cs
  class ParticleSettings (line 22) | public class ParticleSettings

FILE: Engine/ParticleSystem/ParticleSystem.cs
  class ParticleSystem (line 26) | public abstract class ParticleSystem
    method InitializeSystem (line 159) | public void InitializeSystem()
    method InitializeSettings (line 184) | protected abstract void InitializeSettings(ParticleSettings settings);
    method LoadContent (line 190) | protected void LoadContent()
    method LoadParticleEffect (line 220) | void LoadParticleEffect()
    method Update (line 270) | public void Update()
    method RetireActiveParticles (line 296) | void RetireActiveParticles()
    method FreeRetiredParticles (line 327) | void FreeRetiredParticles()
    method Render (line 355) | public void Render()
    method AddNewParticlesToVertexBuffer (line 437) | void AddNewParticlesToVertexBuffer()
    method AddParticle (line 483) | public void AddParticle(Vector3 position, Vector3 velocity)
    method SetParticleRenderStates (line 538) | void SetParticleRenderStates()
    method Clear (line 558) | public void Clear()
    method SetCamera (line 570) | public void SetCamera(ICamera camera)

FILE: Engine/ParticleSystem/ParticleVertex.cs
  type ParticleVertex (line 21) | struct ParticleVertex

FILE: Engine/ScreenEffects.cs
  class ScreenEffects (line 9) | public class ScreenEffects : IDrawableObject
    type FadeDirection (line 13) | private enum FadeDirection
    method ScreenEffects (line 36) | private ScreenEffects()
    method FadeScreen (line 48) | public void FadeScreen()
    method UnFadeScreen (line 54) | public void UnFadeScreen()
    method Update (line 62) | public void Update(GameTime gameTime)
    method Draw (line 79) | public void Draw()
    method CompleteFade (line 95) | private void CompleteFade()
    method TakeScreenshot (line 106) | public static Texture2D TakeScreenshot()

FILE: Engine/SimpleCamera.cs
  class SimpleCamera (line 10) | public class SimpleCamera : ICamera
    method SimpleCamera (line 13) | public SimpleCamera()
    method Update (line 103) | public void Update(GameTime gameTime)
    method SetPosition (line 110) | public void SetPosition(Vector3 position)
    method FollowObject (line 115) | public void FollowObject(GameObject obj)

FILE: Engine/SkyBox.cs
  class SkyBox (line 12) | public class SkyBox : IDrawableObject
    method SkyBox (line 29) | public SkyBox()
    method LoadResources (line 35) | public void LoadResources()
    method Update (line 136) | public void Update(GameTime gameTime)
    method Draw (line 146) | public void Draw()

FILE: Engine/SoundEngine2.cs
  class SoundEffectDescriptor (line 9) | class SoundEffectDescriptor
  class SoundEngine2 (line 15) | public class SoundEngine2
    method SoundEngine2 (line 31) | private SoundEngine2()
    method PlayEffect (line 35) | public void PlayEffect(SoundEffectInstance effect, float duration)
    method Update (line 43) | public void Update(GameTime gameTime)

FILE: Engine/Utility.cs
  class Triangle (line 9) | public class Triangle
    method Triangle (line 12) | public Triangle(Vector3 v1, Vector3 v2, Vector3 v3)
  class Utility (line 20) | public class Utility
    method FindRayTriangleIntersection (line 25) | public static bool FindRayTriangleIntersection(ref Vector3 rayOrigin, ...
    method RotatePoint (line 62) | public static Vector3 RotatePoint(Vector2 point, float degrees)
    method IsLeftOfLine (line 73) | public static bool IsLeftOfLine(Vector3 line1, Vector3 line2, Vector3 ...
    method GetClosestPointOnLine (line 78) | public static Vector3 GetClosestPointOnLine(Vector3 line1, Vector3 lin...
    method GetSignedAngleBetweenVectors (line 96) | public static float GetSignedAngleBetweenVectors(Vector3 from, Vector3...

FILE: OpenNFS1/Audio/BnkVehicleAudioProvider.cs
  class VehicleAudioProvider2 (line 15) | class VehicleAudioProvider2
    method VehicleAudioProvider2 (line 26) | public VehicleAudioProvider2(DrivableVehicle car)
    method Initialize (line 32) | public void Initialize()
    method UpdateEngine (line 72) | public void UpdateEngine()
    method PlaySkid (line 90) | public void PlaySkid(bool play)
    method ChangeGear (line 116) | public void ChangeGear()
    method HitGround (line 122) | public void HitGround()
    method PlayOffRoad (line 130) | public void PlayOffRoad(bool play)
    method StopAll (line 147) | public void StopAll()

FILE: OpenNFS1/Audio/EnvironmentAudioProvider.cs
  class EnvironmentAudioProvider (line 9) | class EnvironmentAudioProvider
    method EnvironmentAudioProvider (line 30) | private EnvironmentAudioProvider()
    method PlayVehicleFenceCollision (line 38) | public void PlayVehicleFenceCollision()
    method PlayCollision (line 48) | public void PlayCollision(int index)

FILE: OpenNFS1/Audio/VehicleAudioProvider.cs
  class VehicleAudioProvider (line 14) | class VehicleAudioProvider
    method VehicleAudioProvider (line 23) | public VehicleAudioProvider(DrivableVehicle car)
    method Initialize (line 31) | public void Initialize()
    method UpdateEngine (line 68) | public void UpdateEngine()
    method PlaySkid (line 111) | public void PlaySkid(bool play)
    method ChangeGear (line 137) | public void ChangeGear()
    method HitGround (line 143) | public void HitGround()
    method PlayOffRoad (line 151) | public void PlayOffRoad(bool play)
    method StopAll (line 168) | public void StopAll()

FILE: OpenNFS1/AverageValue.cs
  class AverageValue (line 8) | class AverageValue
    method AverageValue (line 13) | public AverageValue(int nbrVaues)
    method AddValue (line 18) | public void AddValue(float value)
    method GetAveragedValue (line 25) | public float GetAveragedValue()
    method Clear (line 35) | public void Clear()

FILE: OpenNFS1/Dashboards/Dashboard.cs
  class Dashboard (line 17) | class Dashboard
    method Dashboard (line 30) | public Dashboard(DrivableVehicle car, DashboardDescription descriptor)
    method Gearbox_GearChangeStarted (line 81) | void Gearbox_GearChangeStarted(object sender, EventArgs e)
    method Update (line 90) | public void Update(GameTime gameTime)
    method Render (line 107) | public void Render()
    method RenderGearstick (line 126) | public void RenderGearstick()
    method RenderSteeringWheel (line 150) | public void RenderSteeringWheel()

FILE: OpenNFS1/Dashboards/DashboardDescription.cs
  class DashboardDescription (line 9) | class DashboardDescription
    method DashboardDescription (line 19) | static DashboardDescription()

FILE: OpenNFS1/Dashboards/GearboxAnimation.cs
  type AnimationStatus (line 9) | enum AnimationStatus
  class GearboxAnimation (line 16) | class GearboxAnimation
    method GearboxAnimation (line 25) | public GearboxAnimation()
    method Update (line 53) | public void Update(GameTime gameTime)

FILE: OpenNFS1/Game1.cs
  class Game1 (line 14) | class Game1 : Microsoft.Xna.Framework.Game
    method SetWindowPos (line 19) | [DllImport("user32.dll")]
    method Game1 (line 23) | public Game1()
    method Initialize (line 51) | protected override void Initialize()
    method LoadContent (line 72) | protected override void LoadContent()
    method UnloadContent (line 87) | protected override void UnloadContent()
    method Update (line 97) | protected override void Update(GameTime gameTime)
    method Draw (line 106) | protected override void Draw(GameTime gameTime)

FILE: OpenNFS1/GameConfig.cs
  class GameConfig (line 16) | static class GameConfig
    method GameConfig (line 43) | static GameConfig()
    method Load (line 48) | public static void Load()

FILE: OpenNFS1/Mesh.cs
  class MeshCache (line 12) | public static class MeshCache
  class Mesh (line 17) | class Mesh
    method Mesh (line 25) | public Mesh(MeshChunk meshChunk, BitmapChunk bmpChunk)
    method Resolve (line 33) | public void Resolve(BitmapChunk bitmapChunk)
    method Render (line 57) | public virtual void Render(Effect effect)
    method GetBoundingBox (line 73) | private BoundingBox GetBoundingBox()
    method Dispose (line 94) | public void Dispose()

FILE: OpenNFS1/ObjectShadow.cs
  class ObjectShadow (line 10) | class ObjectShadow
    method ObjectShadow (line 14) | static ObjectShadow()
    method Render (line 27) | public static void Render(Vector3[] points, bool ignoreDepthBuffer)

FILE: OpenNFS1/Parsers/Audio/BnkFile.cs
  class BnkSample (line 9) | class BnkSample
  class BnkFile (line 19) | class BnkFile
    method BnkFile (line 25) | public BnkFile(string filename)
    method Parse (line 35) | private void Parse(BinaryReader reader)
    method ReadSample (line 53) | private void ReadSample(BinaryReader reader, int sampleIndex)

FILE: OpenNFS1/Parsers/Audio/WavWriter.cs
  class WavWriter (line 8) | class WavWriter
    method WavWriter (line 10) | public WavWriter()
    method Write (line 14) | public static void Write(string filename, int samples, short channels,...

FILE: OpenNFS1/Parsers/BaseChunk.cs
  class BaseChunk (line 8) | class BaseChunk
    method Load (line 20) | public void Load(BinaryReader reader)
    method Read (line 26) | public virtual void Read(BinaryReader reader)
    method SkipHeader (line 32) | public void SkipHeader(BinaryReader reader)

FILE: OpenNFS1/Parsers/BitmapChunk.cs
  type BitmapEntryType (line 13) | enum BitmapEntryType
  class BitmapEntry (line 22) | class BitmapEntry
    method ToString (line 31) | public override string ToString()
    method GetDisplayAt (line 37) | public Vector2 GetDisplayAt()
  class BitmapChunk (line 43) | class BitmapChunk : BaseChunk
    method Read (line 64) | public override void Read(BinaryReader reader)
    method ReadEntry (line 106) | private void ReadEntry(BinaryReader reader, BitmapEntry entry)
    method ReadTexture (line 138) | private void ReadTexture(BinaryReader reader, BitmapEntry entry, int w...
    method LoadPalette (line 168) | byte[] LoadPalette(BinaryReader reader, BitmapEntryType type)
    method FindByName (line 193) | public BitmapEntry FindByName(string name)

FILE: OpenNFS1/Parsers/BitmapLoader.cs
  class TextureGenerator (line 11) | class TextureGenerator
    method TextureGenerator (line 15) | public TextureGenerator(byte[] palette)
    method Generate (line 20) | public Texture2D Generate(byte[] pixelData, int width, int height)
    method GenerateImageData (line 27) | private byte[] GenerateImageData(byte[] pixelData, int width, int height)
    method GetMostUsedColour (line 66) | private Vector3 GetMostUsedColour(string id, byte[] pixels)
    method GetRGBForPixel (line 95) | private byte[] GetRGBForPixel(int pixel)

FILE: OpenNFS1/Parsers/CfmFile.cs
  class CfmFile (line 14) | class CfmFile
    method CfmFile (line 22) | public CfmFile(string filename)
    method Parse (line 27) | private void Parse(string filename)
    method CfmFile_TextureGenerated (line 46) | void CfmFile_TextureGenerated(BitmapEntry entry, byte[] palette, byte[...

FILE: OpenNFS1/Parsers/FshFile.cs
  class FshFile (line 13) | class FshFile
    method FshFile (line 17) | public FshFile(string filename)
    method FshFile (line 23) | public FshFile(byte[] contents)
    method Parse (line 28) | private void Parse(Stream contents)

FILE: OpenNFS1/Parsers/HeaderChunk.cs
  class HeaderChunk (line 10) | class HeaderChunk : BaseChunk
    method Read (line 18) | public override void Read(BinaryReader reader)
    method Read (line 22) | public void Read(BinaryReader reader, bool readHeadersOnly)
    method Read (line 27) | public void Read(BinaryReader reader, bool readIdentifier, bool readHe...
    method ReadChunk (line 51) | private void ReadChunk(BinaryReader reader, bool readHeaderOnly)

FILE: OpenNFS1/Parsers/MeshChunk.cs
  class MeshChunk (line 13) | class MeshChunk : BaseChunk
    method Read (line 26) | public override void Read(BinaryReader reader)
    method ReadVertexBlock (line 78) | private void ReadVertexBlock(BinaryReader reader, int vertexCount)
    method ReadTextureMapBlock (line 90) | private void ReadTextureMapBlock(BinaryReader reader, int texturePoint...
    method ReadTextureNameBlock (line 100) | private void ReadTextureNameBlock(BinaryReader reader, int textureName...
    method ReadPolygonBlock (line 113) | private void ReadPolygonBlock(BinaryReader reader, int polygonCount, B...
    method ReadPolygonLabelBlock (line 200) | private void ReadPolygonLabelBlock(BinaryReader reader, int labelCount)

FILE: OpenNFS1/Parsers/OpenRoadTrackfamFile.cs
  class OpenRoadTrackfamFile (line 9) | class OpenRoadTrackfamFile : TrackfamFile
    method OpenRoadTrackfamFile (line 11) | public OpenRoadTrackfamFile(string trackFile, bool alternateTimeOfDay)
    method GetGroundTexture (line 16) | public override Texture2D GetGroundTexture(int textureNbr)
    method GetSceneryTexture (line 44) | public override Texture2D GetSceneryTexture(int textureNbr)
    method GetFenceTexture (line 60) | public override Texture2D GetFenceTexture(int textureNbr)

FILE: OpenNFS1/Parsers/QfsFile.cs
  class QfsFile (line 12) | class QfsFile
    method QfsFile (line 16) | public QfsFile(string filename)
    method Decompress (line 26) | private byte[] Decompress(string filename)
    method mmemcpy (line 105) | void mmemcpy(byte[] dest, int pDest, byte[] src, int pSrc, int len) /*...

FILE: OpenNFS1/Parsers/TrackfamFile.cs
  class TrackfamFile (line 13) | class TrackfamFile
    method TrackfamFile (line 22) | public TrackfamFile(string trackFile, bool alternateTimeOfDay)
    method ReadFamFile (line 34) | private void ReadFamFile(string filename)
    method GetGroundTexture (line 44) | public virtual Texture2D GetGroundTexture(int textureNbr)
    method GetSceneryTexture (line 70) | public virtual Texture2D GetSceneryTexture(int textureNbr)
    method GetFenceTexture (line 95) | public virtual Texture2D GetFenceTexture(int textureNbr)
    method GetMesh (line 101) | public Mesh GetMesh(int index)
    method Dispose (line 112) | public void Dispose()

FILE: OpenNFS1/Parsers/TriFile.cs
  type SceneryType (line 15) | enum SceneryType
  type SceneryFlags (line 22) | [Flags]
  class SceneryObjectDescriptor (line 30) | class SceneryObjectDescriptor
  class SceneryObject (line 40) | class SceneryObject
  class TriFile (line 51) | class TriFile
    method TriFile (line 64) | public TriFile(string filename)
    method ParseTrackNodesBlock (line 89) | void ParseTrackNodesBlock(BinaryReader reader)
    method ParseSceneryObjectsBlock (line 192) | private void ParseSceneryObjectsBlock(BinaryReader reader)
    method ParseTerrainBlock (line 253) | private void ParseTerrainBlock(BinaryReader reader)
    method ReadTerrainRow (line 327) | private TerrainRow ReadTerrainRow(BinaryReader reader)
    method ComputeAbsoluteTerrainPoints (line 366) | private void ComputeAbsoluteTerrainPoints()

FILE: OpenNFS1/Physics/AutoGearbox.cs
  class AutoGearbox (line 10) | class AutoGearbox : BaseGearbox
    method AutoGearbox (line 15) | public AutoGearbox(List<float> ratios, float changeTime)
    method Update (line 20) | public override void Update(float motorRpmPercent, GearboxAction action)

FILE: OpenNFS1/Physics/BaseGearbox.cs
  class GearboxGearChange (line 10) | class GearboxGearChange
  type GearboxAction (line 16) | enum GearboxAction
  class BaseGearbox (line 23) | abstract class BaseGearbox
    method BaseGearbox (line 82) | public BaseGearbox(List<float> ratios, float changeTime)
    method GearUp (line 92) | public void GearUp()
    method GearDown (line 104) | public void GearDown()
    method Update (line 121) | public virtual void Update(float motorRpmPercent, GearboxAction action)
    method Create (line 150) | public static BaseGearbox Create(bool manual, List<float> ratios, floa...

FILE: OpenNFS1/Physics/DrivableVehicle.cs
  class DrivableVehicle (line 16) | class DrivableVehicle : Vehicle
    method DrivableVehicle (line 59) | public DrivableVehicle(VehicleDescription desc)
    method UpdateWheels (line 99) | private void UpdateWheels()
    method UpdateDrag (line 146) | private void UpdateDrag()
    method UpdateEngineForce (line 190) | private void UpdateEngineForce()
    method Update (line 233) | public override void Update()
    method HandleExtraSteeringPhysics (line 266) | public override void HandleExtraSteeringPhysics()
    method UpdateRearSlip (line 303) | void UpdateRearSlip()
    method CheckForCollisions (line 334) | void CheckForCollisions()
    method RenderShadow (line 350) | public void RenderShadow(bool isPlayer)
    method Render (line 371) | public override void Render()
    method GetRenderMatrix (line 386) | public override Matrix GetRenderMatrix()
    method Gearbox_GearChanged (line 399) | protected void Gearbox_GearChanged(object sender, EventArgs e)
    method OnGroundHit (line 404) | public override void OnGroundHit()

FILE: OpenNFS1/Physics/ManualGearbox.cs
  class ManualGearbox (line 10) | class ManualGearbox : BaseGearbox
    method ManualGearbox (line 12) | public ManualGearbox(List<float> ratios, float changeTime)
    method Update (line 17) | public override void Update(float motorRpmPercent, GearboxAction action)

FILE: OpenNFS1/Physics/Motor.cs
  class Motor (line 10) | class Motor
    method Motor (line 83) | public Motor(List<float> powerCurve, float maxPower, float redline, Ba...
    method Update (line 93) | public void Update(float carSpeed, GearboxAction action)
    method GetPowerAtRpmForGear (line 144) | public float GetPowerAtRpmForGear(float rpm, int gear)
    method Idle (line 151) | public void Idle()
    method GetRpmForGear (line 157) | public float GetRpmForGear(int gear)
    method HandleRpmNoLoad (line 162) | private void HandleRpmNoLoad()

FILE: OpenNFS1/Physics/Spring.cs
  class Spring (line 11) | class Spring
    method Spring (line 29) | public Spring(float mass, float friction, float springConstant, float ...
    method Simulate (line 41) | public void Simulate(float timeChange)
    method ChangePosition (line 53) | public void ChangePosition(float change)

FILE: OpenNFS1/Physics/Vector3Helper.cs
  class Vector3Helper (line 21) | class Vector3Helper
    method Vector3Helper (line 27) | private Vector3Helper()
    method GetAngleBetweenVectors (line 40) | public static float GetAngleBetweenVectors(Vector3 vec1, Vector3 vec2)
    method DistanceToLine (line 58) | public static float DistanceToLine(Vector3 point, Vector3 linePos1, Ve...
    method SignedDistanceToPlane (line 76) | public static float SignedDistanceToPlane(Vector3 point, Vector3 plane...

FILE: OpenNFS1/Physics/VehicleFenceCollision.cs
  class VehicleFenceCollision (line 10) | class VehicleFenceCollision
    method Handle (line 12) | public static void Handle(DrivableVehicle car)
    method GetWheelsOutsideRoadVerge (line 71) | public static int GetWheelsOutsideRoadVerge(DrivableVehicle car)
    method SlideAlongFence (line 99) | private static void SlideAlongFence(DrivableVehicle car, int wheel, fl...
    method HandleHeadOnCrash (line 120) | private static void HandleHeadOnCrash(DrivableVehicle car, int wheel, ...

FILE: OpenNFS1/Physics/VehicleWheel.cs
  class VehicleWheel (line 12) | class VehicleWheel
    method VehicleWheel (line 34) | public VehicleWheel(DrivableVehicle car, Vector3 axlePoint, float size...
    method GetOffsetPosition (line 68) | public Vector3 GetOffsetPosition(Vector3 offset)
    method Steer (line 84) | public void Steer(float angle)
    method Update (line 89) | public void Update()
    method Render (line 96) | public void Render()

FILE: OpenNFS1/PlayerUI.cs
  class PlayerUI (line 13) | class PlayerUI
    method PlayerUI (line 21) | public PlayerUI(DrivableVehicle vehicle)
    method Update (line 37) | public void Update(GameTime gameTime)
    method Render (line 65) | public void Render()

FILE: OpenNFS1/Polygon.cs
  type PolygonShape (line 9) | enum PolygonShape
  class Polygon (line 16) | class Polygon
    method Polygon (line 40) | public Polygon(PolygonShape type, bool computeUVs)
    method ResolveTexture (line 58) | public void ResolveTexture(BitmapEntry bmpEntry)
    method GetVertices (line 79) | public VertexPositionTexture[] GetVertices()

FILE: OpenNFS1/Program.cs
  class Program (line 13) | public static class Program
    method Main (line 18) | [STAThread]
    method CurrentDomain_UnhandledException (line 26) | static void CurrentDomain_UnhandledException(object sender, UnhandledE...

FILE: OpenNFS1/Race/PlayerRaceStats.cs
  class PlayerRaceStats (line 8) | class PlayerRaceStats
    method OnLapStarted (line 16) | public void OnLapStarted()

FILE: OpenNFS1/Race/Race.cs
  class Race (line 18) | class Race
    method Race (line 30) | public Race(int nbrLaps, Track track, PlayerDriver player)
    method StartCountdown (line 61) | public void StartCountdown()
    method AddDriver (line 67) | public void AddDriver(IDriver d)
    method AddDriver (line 73) | public void AddDriver(IDriver d, TrackNode startNode)
    method Update (line 95) | public void Update()
    method Render (line 141) | public void Render(bool renderPlayerVehicle)

FILE: OpenNFS1/Race/RaceUI.cs
  class RaceUI (line 14) | class RaceUI
    method RaceUI (line 22) | public RaceUI(Race race)
    method Render (line 36) | public void Render()
    method GearToString (line 73) | private string GearToString(int gear)

FILE: OpenNFS1/Tracks/SceneryObject.cs
  class SceneryItem (line 14) | abstract class SceneryItem
    method Initialize (line 21) | public abstract void Initialize();
    method Update (line 22) | public virtual void Update() { }
    method Render (line 23) | public abstract void Render(AlphaTestEffect effect);
  class BillboardSceneryItem (line 26) | class BillboardSceneryItem : SceneryItem
    method BillboardSceneryItem (line 31) | public BillboardSceneryItem() { }
    method BillboardSceneryItem (line 32) | public BillboardSceneryItem(Texture2D texture)
    method Initialize (line 37) | public override void Initialize()
    method Render (line 50) | public override void Render(AlphaTestEffect effect)
  class AnimatedBillboardSceneryItem (line 59) | class AnimatedBillboardSceneryItem : BillboardSceneryItem
    method AnimatedBillboardSceneryItem (line 65) | public AnimatedBillboardSceneryItem(List<Texture2D> textures)
    method Initialize (line 71) | public override void Initialize()
    method Update (line 83) | public override void Update()
  class TwoSidedBillboardSceneryItem (line 96) | class TwoSidedBillboardSceneryItem : SceneryItem
    method TwoSidedBillboardSceneryItem (line 101) | public TwoSidedBillboardSceneryItem(Texture2D texture1, Texture2D text...
    method Initialize (line 107) | public override void Initialize()
    method Render (line 119) | public override void Render(AlphaTestEffect effect)
  class ModelSceneryItem (line 135) | class ModelSceneryItem : SceneryItem
    method ModelSceneryItem (line 140) | public ModelSceneryItem(Mesh mesh)
    method Initialize (line 145) | public override void Initialize()
    method Render (line 152) | public override void Render(AlphaTestEffect effect)

FILE: OpenNFS1/Tracks/TerrainRow.cs
  class TerrainRow (line 12) | class TerrainRow
    method GetPoint (line 20) | public Vector3 GetPoint(int pointIndex)
    method RelativizeTo (line 28) | public void RelativizeTo(Vector3 position)

FILE: OpenNFS1/Tracks/TerrainSegment.cs
  class TerrainSegment (line 13) | class TerrainSegment

FILE: OpenNFS1/Tracks/Track.cs
  class Track (line 19) | class Track
    method Track (line 36) | public Track()
    method Initialize (line 46) | public void Initialize()
    method Update (line 51) | public void Update()
    method Render (line 60) | public void Render(Vector3 cameraPosition, TrackNode currentNode)
    method RenderSegment (line 148) | private void RenderSegment(TerrainSegment segment)
    method DrawTerrainStrip (line 164) | private void DrawTerrainStrip(ref int vertexIndex, int stripNumber, Te...
    method DrawFenceStrips (line 174) | private void DrawFenceStrips(TerrainSegment segment)
    method DrawScenery (line 190) | private void DrawScenery(List<TerrainSegment> renderedSegments)
    method GetHeightAtPoint (line 225) | public float GetHeightAtPoint(TrackNode node, Vector3 point)
    method Dispose (line 249) | public void Dispose()

FILE: OpenNFS1/Tracks/TrackAssembler.cs
  class TrackAssembler (line 16) | class TrackAssembler
    method AddProgress (line 31) | private void AddProgress(string progress)
    method Assemble (line 36) | public Track Assemble(TriFile tri)
    method AssembleSceneryItems (line 74) | private List<SceneryItem> AssembleSceneryItems()
    method AssembleTerrainVertices (line 136) | private VertexBuffer AssembleTerrainVertices()
    method GetPointIndicesForRightSide (line 208) | void GetPointIndicesForRightSide(TerrainSegment segment, int terrainPo...
    method GetPointIndicesForLeftSide (line 226) | void GetPointIndicesForLeftSide(TerrainSegment segment, int terrainPoi...
    method AssembleFenceVertices (line 253) | VertexBuffer AssembleFenceVertices()
    method AssembleTrackSegments (line 298) | void AssembleTrackSegments()
    method GeneratePhysicalVertices (line 336) | public List<Triangle> GeneratePhysicalVertices(List<TrackNode> nodes)
    method GetRoadOffsetPosition (line 392) | public static Vector3 GetRoadOffsetPosition(TrackNode roadNode, float ...

FILE: OpenNFS1/Tracks/TrackBillboardModel.cs
  class TrackBillboardModel (line 10) | static class TrackBillboardModel
    method TrackBillboardModel (line 15) | static TrackBillboardModel()
    method BeginBatch (line 24) | public static void BeginBatch()
    method CreateGeometry (line 42) | private static void CreateGeometry()

FILE: OpenNFS1/Tracks/TrackDescription.cs
  class TrackDescription (line 9) | class TrackDescription
    method TrackDescription (line 25) | static TrackDescription()
    method GetNextOpenRoadStage (line 168) | public static TrackDescription GetNextOpenRoadStage(TrackDescription o...

FILE: OpenNFS1/Tracks/TrackNode.cs
  class TrackNodeProperty (line 11) | class TrackNodeProperty
  class TrackNode (line 32) | class TrackNode
    method GetLeftBoundary (line 52) | public Vector3 GetLeftBoundary()
    method GetLeftVerge (line 56) | public Vector3 GetLeftVerge()
    method GetRightBoundary (line 60) | public Vector3 GetRightBoundary()
    method GetRightVerge (line 64) | public Vector3 GetRightVerge()
    method GetLeftVerge2 (line 69) | public Vector3 GetLeftVerge2()
    method GetRightVerge2 (line 74) | public Vector3 GetRightVerge2()
    method GetMiddlePoint (line 79) | public Vector3 GetMiddlePoint()
    method GetLeftOffset (line 85) | private Vector3 GetLeftOffset(float offset)
    method GetRightOffset (line 95) | private Vector3 GetRightOffset(float offset)

FILE: OpenNFS1/Tracks/TrackObjectDescriptor.cs
  class TrackObjectDescriptor (line 8) | class TrackObjectDescriptor

FILE: OpenNFS1/Tracks/TrackSkybox.cs
  class TrackSkyBox (line 12) | public class TrackSkyBox
    method TrackSkyBox (line 30) | public TrackSkyBox(Texture2D horizon)
    method Update (line 144) | public void Update()
    method Render (line 175) | public void Render()

FILE: OpenNFS1/UI/Screens/BaseUIScreen.cs
  class BaseUIScreen (line 13) | class BaseUIScreen
    method BaseUIScreen (line 23) | public BaseUIScreen()
    method Draw (line 29) | public virtual void Draw()
    method WriteLine (line 39) | public void WriteLine(string text)
    method WriteLine (line 44) | public void WriteLine(string text, Color c)
    method WriteLine (line 49) | public void WriteLine(string text, bool selected, int lineOffset, int ...
    method WriteLine (line 54) | public void WriteLine(string text, Color c, int lineOffset, int column...

FILE: OpenNFS1/UI/Screens/ChooseDataDownloadScreen.cs
  class ChooseDataDownloadScreen (line 12) | class ChooseDataDownloadScreen : BaseUIScreen, IGameScreen
    method ChooseDataDownloadScreen (line 16) | public ChooseDataDownloadScreen() : base()
    method Update (line 21) | public void Update(GameTime gameTime)
    method Draw (line 45) | public override void Draw()

FILE: OpenNFS1/UI/Screens/DataDownloadScreen.cs
  class DataDownloadScreen (line 15) | class DataDownloadScreen : BaseUIScreen, IGameScreen
    method DataDownloadScreen (line 23) | public DataDownloadScreen() : base()
    method Update (line 30) | public void Update(Microsoft.Xna.Framework.GameTime gameTime)
    method Draw (line 41) | public override void Draw()
    method DownloadDataThreadProc (line 75) | private void DownloadDataThreadProc()

FILE: OpenNFS1/UI/Screens/DoRaceScreen.cs
  class DoRaceScreen (line 15) | class DoRaceScreen : IGameScreen
    method DoRaceScreen (line 25) | public DoRaceScreen(Track track)
    method Update (line 74) | public void Update(GameTime gameTime)
    method Pause (line 105) | public void Pause()
    method Resume (line 111) | public void Resume()
    method Draw (line 116) | public void Draw()

FILE: OpenNFS1/UI/Screens/HomeScreen.cs
  class VehicleUIControl (line 13) | class VehicleUIControl
    method VehicleUIControl (line 18) | public VehicleUIControl(VehicleDescription desc)
  class TrackUIControl (line 26) | class TrackUIControl
    method TrackUIControl (line 31) | public TrackUIControl(TrackDescription desc)
  type SelectedControlType (line 39) | enum SelectedControlType
  class HomeScreen (line 45) | class HomeScreen : IGameScreen
    method HomeScreen (line 59) | public HomeScreen()
    method Update (line 89) | public void Update(GameTime gameTime)
    method Draw (line 128) | public void Draw()

FILE: OpenNFS1/UI/Screens/LoadRaceScreen.cs
  class LoadRaceScreen (line 14) | class LoadRaceScreen : BaseUIScreen, IGameScreen
    method LoadRaceScreen (line 21) | public LoadRaceScreen() : base()
    method Update (line 33) | public void Update(GameTime gameTime)
    method Draw (line 47) | public override void Draw()
    method LoadTrack (line 62) | private void LoadTrack()

FILE: OpenNFS1/UI/Screens/OpenNFS1SplashScreen.cs
  class OpenNFS1SplashScreen (line 13) | class OpenNFS1SplashScreen : BaseUIScreen, IGameScreen
    method Update (line 16) | public void Update(GameTime gameTime)
    method Draw (line 30) | public override void Draw()

FILE: OpenNFS1/UI/Screens/RaceFinishedScreen.cs
  class RaceFinishedScreen (line 11) | class RaceFinishedScreen : BaseUIScreen, IGameScreen
    method RaceFinishedScreen (line 19) | public RaceFinishedScreen(Race race, Track raceTrack)
    method Update (line 31) | public void Update(GameTime gameTime)
    method Draw (line 63) | public override void Draw()
    method DrawCircuitResult (line 79) | private void DrawCircuitResult()
    method DrawOpenRoadResult (line 96) | private void DrawOpenRoadResult()

FILE: OpenNFS1/UI/Screens/RaceOptionsScreen.cs
  class RaceOptionsScreen (line 13) | class RaceOptionsScreen: BaseUIScreen, IGameScreen
    method RaceOptionsScreen (line 17) | public RaceOptionsScreen() : base()
    method Update (line 24) | public void Update(GameTime gameTime)
    method Draw (line 59) | public override void Draw()

FILE: OpenNFS1/UI/Screens/RacePausedScreen.cs
  class RacePausedScreen (line 11) | class RacePausedScreen : BaseUIScreen, IGameScreen
    method RacePausedScreen (line 16) | public RacePausedScreen(DoRaceScreen currentRace)
    method Update (line 24) | public void Update(GameTime gameTime)
    method Draw (line 53) | public override void Draw()

FILE: OpenNFS1/UIController.cs
  class UIController (line 9) | static class UIController

FILE: OpenNFS1/VehicleController.cs
  class VehicleController (line 9) | static class VehicleController

FILE: OpenNFS1/Vehicles/AI/AIDriver.cs
  class AIDriver (line 15) | abstract class AIDriver : IDriver
    method GetNextTarget (line 23) | public virtual Vector3 GetNextTarget()
    method FollowTrack (line 28) | protected virtual void FollowTrack()
    method Update (line 50) | public abstract void Update(List<IDriver> otherDrivers);
  class RacingAIDriver (line 54) | class RacingAIDriver : AIDriver
    method RacingAIDriver (line 60) | public RacingAIDriver(VehicleDescription vehicleDescriptor)
    method Update (line 69) | public override void Update(List<IDriver> otherDrivers)
    method Render (line 120) | public void Render()

FILE: OpenNFS1/Vehicles/AI/IDriver.cs
  type IDriver (line 9) | interface IDriver
    method Update (line 12) | void Update(List<IDriver> otherDrivers);

FILE: OpenNFS1/Vehicles/AI/TrafficDriver.cs
  type TrafficDriverDirection (line 14) | enum TrafficDriverDirection
  class TrafficDriver (line 20) | class TrafficDriver : AIDriver
    method TrafficDriver (line 24) | public TrafficDriver(string cfmFile, TrafficDriverDirection direction)
    method GetNextTarget (line 39) | public override Vector3 GetNextTarget()
    method FollowTrack (line 47) | protected override void FollowTrack()
    method Update (line 63) | public override void Update(List<IDriver> otherDrivers)

FILE: OpenNFS1/Vehicles/CarMesh.cs
  class CarMesh (line 12) | class CarMesh : Mesh
    method CarMesh (line 21) | public CarMesh(MeshChunk meshChunk, BitmapChunk bmpChunk, Color brakeC...
    method GetWheelAxlePoint (line 87) | private Vector3 GetWheelAxlePoint(Polygon wheelPoly)
    method Render (line 114) | public void Render(Effect effect, bool enableBrakeLights)

FILE: OpenNFS1/Vehicles/CarModelCache.cs
  class CarModelCache (line 8) | static class CarModelCache
    method GetCfm (line 12) | public static CarMesh GetCfm(string filename)

FILE: OpenNFS1/Vehicles/PlayerDriver.cs
  class PlayerDriver (line 9) | class PlayerDriver : IDriver
    method PlayerDriver (line 14) | public PlayerDriver(DrivableVehicle vehicle)
    method Update (line 19) | public void Update(List<IDriver> otherDrivers)
    method Render (line 30) | public void Render()

FILE: OpenNFS1/Vehicles/Traffic/TrafficController.cs
  class TrafficController (line 14) | class TrafficController
    method TrafficController (line 19) | static TrafficController()
    method TrafficController (line 38) | public TrafficController(Race race)
    method Update (line 44) | public void Update()

FILE: OpenNFS1/Vehicles/TyreSmokeParticleSystem.cs
  class TyreSmokeParticleSystem (line 11) | class TyreSmokeParticleSystem : ParticleSystem
    method InitializeSettings (line 28) | protected override void InitializeSettings(ParticleSettings settings)

FILE: OpenNFS1/Vehicles/Vehicle.cs
  class Vehicle (line 19) | class Vehicle
    method Vehicle (line 63) | public Vehicle(string cfmFile)
    method PlaceOnTrack (line 71) | public void PlaceOnTrack(Track t, TrackNode startNode)
    method Update (line 78) | public virtual void Update()
    method UpdateTrackNode (line 105) | private void UpdateTrackNode()
    method FollowTrackOrientation (line 121) | private void FollowTrackOrientation(TrackNode node, TrackNode nextNode)
    method UpdateSteering (line 161) | private void UpdateSteering()
    method HandleExtraSteeringPhysics (line 197) | public virtual void HandleExtraSteeringPhysics() { }
    method ApplyGravity (line 200) | private void ApplyGravity()
    method OnGroundHit (line 239) | public virtual void OnGroundHit() { }
    method Reset (line 241) | public void Reset()
    method Render (line 248) | public virtual void Render()
    method GetRenderMatrix (line 262) | public virtual Matrix GetRenderMatrix()
    method Distance2d (line 271) | public static float Distance2d(Vector3 pos1, Vector3 pos2)

FILE: OpenNFS1/Vehicles/VehicleDescription.cs
  class VehicleDescription (line 8) | class VehicleDescription
    method VehicleDescription (line 20) | static VehicleDescription()

FILE: OpenNFS1/Vehicles/WheelModel.cs
  class WheelModel (line 11) | static class WheelModel
    method WheelModel (line 18) | static WheelModel()
    method BeginBatch (line 28) | public static void BeginBatch()
    method Render (line 36) | public static void Render(Matrix world, Texture2D texture)
    method CreateGeometry (line 52) | private static void CreateGeometry()

FILE: OpenNFS1/Views/BaseExternalView.cs
  class BaseExternalView (line 13) | class BaseExternalView
    method BaseExternalView (line 21) | public BaseExternalView()
    method RenderBackground (line 38) | public void RenderBackground(DrivableVehicle car)

FILE: OpenNFS1/Views/BumperView.cs
  class BumperView (line 7) | class BumperView : BaseExternalView, IView
    method BumperView (line 12) | public BumperView(DrivableVehicle car)
    method Activate (line 29) | public void Activate()
    method Deactivate (line 34) | public void Deactivate()
    method Update (line 38) | public void Update(GameTime gameTime)
    method Render (line 48) | public void Render()

FILE: OpenNFS1/Views/ChaseView.cs
  class ChaseView (line 9) | class ChaseView : BaseExternalView, IView
    method ChaseView (line 16) | public ChaseView(DrivableVehicle car, int distance, int height, int of...
    method Activate (line 34) | public void Activate()
    method Deactivate (line 41) | public void Deactivate()
    method Update (line 45) | public void Update(GameTime gameTime)
    method Render (line 52) | public void Render()

FILE: OpenNFS1/Views/DashboardView.cs
  class DashboardView (line 12) | class DashboardView : IView
    method DashboardView (line 18) | public DashboardView(DrivableVehicle car)
    method Update (line 39) | public void Update(GameTime gameTime)
    method Render (line 48) | public void Render()
    method Activate (line 57) | public void Activate()
    method Deactivate (line 63) | public void Deactivate()

FILE: OpenNFS1/Views/DebugView.cs
  class DebugView (line 9) | class DebugView : IView
    method DebugView (line 14) | public DebugView(DrivableVehicle car)
    method Update (line 29) | public void Update(GameTime gameTime)
    method Render (line 34) | public void Render()
    method Activate (line 38) | public void Activate()
    method Deactivate (line 44) | public void Deactivate()

FILE: OpenNFS1/Views/DropCameraView.cs
  class DropCameraView (line 9) | class DropCameraView : BaseExternalView, IView
    method DropCameraView (line 16) | public DropCameraView(DrivableVehicle car)
    method Activate (line 34) | public void Activate()
    method Deactivate (line 39) | public void Deactivate()
    method Update (line 43) | public void Update(GameTime gameTime)
    method PositionCameraAtNode (line 53) | private void PositionCameraAtNode(TrackNode node)
    method Render (line 60) | public void Render()

FILE: OpenNFS1/Views/IView.cs
  type IView (line 8) | interface IView
    method Update (line 12) | void Update(GameTime gameTime);
    method Render (line 13) | void Render();
    method Activate (line 14) | void Activate();
    method Deactivate (line 15) | void Deactivate();
Condensed preview — 126 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (540K chars).
[
  {
    "path": ".editorconfig",
    "chars": 70,
    "preview": "root = true\r\n\r\n[*]\r\nindent_size = 4\r\ntab_width = 4\r\nindent_style = tab"
  },
  {
    "path": ".gitignore",
    "chars": 47,
    "preview": "*.suo\r\n*.user\r\n_ReSharper.*\r\nbin\r\nobj\r\ndeploy\r\n"
  },
  {
    "path": "Engine/AverageValueVector3.cs",
    "chars": 792,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace GameE"
  },
  {
    "path": "Engine/ChaseCamera.cs",
    "chars": 9188,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "Engine/Engine.cs",
    "chars": 4541,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing System.Diagn"
  },
  {
    "path": "Engine/FPSCamera.cs",
    "chars": 6198,
    "preview": "//-----------------------------------------------------------------------------\r\n// Copyright (c) 2007 dhpoware. All Rig"
  },
  {
    "path": "Engine/FPSCounter.cs",
    "chars": 1020,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "Engine/FixedChaseCamera.cs",
    "chars": 2942,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;"
  },
  {
    "path": "Engine/GameConsole.cs",
    "chars": 863,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework;\r"
  },
  {
    "path": "Engine/GameEngine.csproj",
    "chars": 3823,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "Engine/GameObject.cs",
    "chars": 4782,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace GameEn"
  },
  {
    "path": "Engine/GraphicsUtilities.cs",
    "chars": 25796,
    "preview": "#region Using Statements\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing Microsoft.Xna.Framework;\r\nusing Micros"
  },
  {
    "path": "Engine/ICamera.cs",
    "chars": 653,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "Engine/IDrawableObject.cs",
    "chars": 255,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace GameEn"
  },
  {
    "path": "Engine/IGameScreen.cs",
    "chars": 166,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\n\r\nnamespace GameEngine\r\n{\r\n    public interface IG"
  },
  {
    "path": "Engine/IWorld.cs",
    "chars": 267,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace GameEn"
  },
  {
    "path": "Engine/InputProvider.cs",
    "chars": 3600,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xn"
  },
  {
    "path": "Engine/ParticleSystem/ParticleEmitter.cs",
    "chars": 4916,
    "preview": "#region File Description\r\n//-----------------------------------------------------------------------------\r\n// ParticleEm"
  },
  {
    "path": "Engine/ParticleSystem/ParticleSettings.cs",
    "chars": 4585,
    "preview": "#region File Description\r\n//-----------------------------------------------------------------------------\r\n// ParticleSe"
  },
  {
    "path": "Engine/ParticleSystem/ParticleSystem.cs",
    "chars": 20517,
    "preview": "#region File Description\r\n//-----------------------------------------------------------------------------\r\n// ParticleSy"
  },
  {
    "path": "Engine/ParticleSystem/ParticleVertex.cs",
    "chars": 1889,
    "preview": "#region File Description\r\n//-----------------------------------------------------------------------------\r\n// ParticleVe"
  },
  {
    "path": "Engine/Properties/AssemblyInfo.cs",
    "chars": 1421,
    "preview": "using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General I"
  },
  {
    "path": "Engine/ScreenEffects.cs",
    "chars": 3535,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "Engine/SimpleCamera.cs",
    "chars": 2506,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "Engine/SkyBox.cs",
    "chars": 7410,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "Engine/SoundEngine2.cs",
    "chars": 1514,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Audio;\r\nusing Micro"
  },
  {
    "path": "Engine/Utility.cs",
    "chars": 3776,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.X"
  },
  {
    "path": "Installer/OpenNFS1.nsi",
    "chars": 4001,
    "preview": "!include LogicLib.nsh\n\n; The name of the installer\nName \"OpenNFS1\"\n\n; The file to write\nOutFile \"OpenNFS1_Install-v1.2.e"
  },
  {
    "path": "Installer/build-installer.bat",
    "chars": 336,
    "preview": "rmdir /S /Q deploy\r\nmkdir deploy\r\nset src=..\\OpenNFS1\\bin\\WindowsGL\\Debug\r\nset dest=.\\deploy\r\nxcopy %src%\\Content %dest%"
  },
  {
    "path": "Installer/readme.txt",
    "chars": 1247,
    "preview": "OpenNFS1 v1.2\r\n----------------\r\nWeb: http://www.1amstudios.com/projects/opennfs1\r\nSrc: https://github.com/jeff-1amstudi"
  },
  {
    "path": "NFSSpecs.txt",
    "chars": 42988,
    "preview": "======================================================================\r\nTHE UNOFFICIAL NEED FOR SPEED FILE FORMAT SPECIF"
  },
  {
    "path": "OpenNFS1/Audio/BnkVehicleAudioProvider.cs",
    "chars": 4825,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Audio;\r\nusing Gam"
  },
  {
    "path": "OpenNFS1/Audio/EnvironmentAudioProvider.cs",
    "chars": 1722,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Audio;\r\nusing GameE"
  },
  {
    "path": "OpenNFS1/Audio/VehicleAudioProvider.cs",
    "chars": 6230,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Audio;\r\nusing Gam"
  },
  {
    "path": "OpenNFS1/AverageValue.cs",
    "chars": 873,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace OpenNF"
  },
  {
    "path": "OpenNFS1/Content/ArialBlack-Italic.spritefont",
    "chars": 2011,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nThis file contains an xml description of a font, and will be read by the XN"
  },
  {
    "path": "OpenNFS1/Content/ArialBlack.spritefont",
    "chars": 2012,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\nThis file contains an xml description of a font, and will be read by the XN"
  },
  {
    "path": "OpenNFS1/Content/ParticleEffect.fx",
    "chars": 5896,
    "preview": "//-----------------------------------------------------------------------------\n// ParticleEffect.fx\n//\n// Microsoft XNA"
  },
  {
    "path": "OpenNFS1/Content/common.fxh",
    "chars": 1243,
    "preview": "//-----------------------------------------------------------------------------\n// Common.fxh\n//\n// Microsoft XNA Commun"
  },
  {
    "path": "OpenNFS1/Content/macros.fxh",
    "chars": 1780,
    "preview": "//-----------------------------------------------------------------------------\n// Macros.fxh\n//\n// Microsoft XNA Commun"
  },
  {
    "path": "OpenNFS1/Content/structures.fxh",
    "chars": 3152,
    "preview": "//-----------------------------------------------------------------------------\n// Structurs.fxh\n//\n// Microsoft XNA Com"
  },
  {
    "path": "OpenNFS1/Dashboards/Dashboard.cs",
    "chars": 7672,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing System.IO;\r\nusing OpenNFS1.Parsers;\r\nusin"
  },
  {
    "path": "OpenNFS1/Dashboards/DashboardDescription.cs",
    "chars": 2629,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/Dashboards/GearboxAnimation.cs",
    "chars": 3640,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace Ope"
  },
  {
    "path": "OpenNFS1/Game1.cs",
    "chars": 4229,
    "preview": "using System;\r\nusing System.IO;\r\nusing System.Runtime.InteropServices;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft."
  },
  {
    "path": "OpenNFS1/GameConfig.cs",
    "chars": 1894,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing OpenNFS1.Physics;\r\nusing Newtonsoft.Json;"
  },
  {
    "path": "OpenNFS1/Mesh.cs",
    "chars": 2558,
    "preview": "using Microsoft.Xna.Framework.Graphics;\r\nusing OpenNFS1.Parsers;\r\nusing GameEngine;\r\nusing System;\r\nusing System.Collec"
  },
  {
    "path": "OpenNFS1/ObjectShadow.cs",
    "chars": 1591,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework.G"
  },
  {
    "path": "OpenNFS1/OpenNFS1.csproj",
    "chars": 8176,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "OpenNFS1/Parsers/Audio/BnkFile.cs",
    "chars": 4509,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing System.Diagnostics;\r\n\r\nna"
  },
  {
    "path": "OpenNFS1/Parsers/Audio/WavWriter.cs",
    "chars": 1406,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\n\r\nnamespace OpenNFS1.Parsers.Au"
  },
  {
    "path": "OpenNFS1/Parsers/BaseChunk.cs",
    "chars": 800,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\n\r\nnamespace OpenNFS1.Parsers\r\n{\r"
  },
  {
    "path": "OpenNFS1/Parsers/BitmapChunk.cs",
    "chars": 5118,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework.Gr"
  },
  {
    "path": "OpenNFS1/Parsers/BitmapLoader.cs",
    "chars": 3420,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework.G"
  },
  {
    "path": "OpenNFS1/Parsers/CfmFile.cs",
    "chars": 1711,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework.Gr"
  },
  {
    "path": "OpenNFS1/Parsers/FshFile.cs",
    "chars": 794,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing OpenN"
  },
  {
    "path": "OpenNFS1/Parsers/HeaderChunk.cs",
    "chars": 3339,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework.Gr"
  },
  {
    "path": "OpenNFS1/Parsers/MeshChunk.cs",
    "chars": 6865,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework;\r\n"
  },
  {
    "path": "OpenNFS1/Parsers/OpenRoadTrackfamFile.cs",
    "chars": 1885,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Text;\r\nusing Microsoft.Xna.Fr"
  },
  {
    "path": "OpenNFS1/Parsers/QfsFile.cs",
    "chars": 2976,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.IO;\r\nusing System.Linq;\r\nusin"
  },
  {
    "path": "OpenNFS1/Parsers/TrackfamFile.cs",
    "chars": 4065,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework.Gr"
  },
  {
    "path": "OpenNFS1/Parsers/TriFile.cs",
    "chars": 12165,
    "preview": "using Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing OpenNFS1;\r\nusing OpenNFS1.Parsers.Track;"
  },
  {
    "path": "OpenNFS1/Physics/AutoGearbox.cs",
    "chars": 1518,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "OpenNFS1/Physics/BaseGearbox.cs",
    "chars": 4323,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.Diagnostics;\r\nusing Microsoft.Xna.Fr"
  },
  {
    "path": "OpenNFS1/Physics/DrivableVehicle.cs",
    "chars": 11823,
    "preview": "\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing Microsoft.Xna.Framework;\r\nusing Mic"
  },
  {
    "path": "OpenNFS1/Physics/ManualGearbox.cs",
    "chars": 765,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework.I"
  },
  {
    "path": "OpenNFS1/Physics/Motor.cs",
    "chars": 5044,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing System.Diag"
  },
  {
    "path": "OpenNFS1/Physics/Spring.cs",
    "chars": 1787,
    "preview": "using System;\r\nusing System.Collections;\r\nusing System.Text;\r\n\r\n\r\nnamespace OpenNFS1.Physics\r\n{\r\n    /// <summary>\r\n    "
  },
  {
    "path": "OpenNFS1/Physics/Vector3Helper.cs",
    "chars": 3090,
    "preview": "// Project: RacingGame, File: Vector3Helper.cs\r\n// Namespace: RacingGame.Helpers, Class: Vector3Helper\r\n// Path: C:\\code"
  },
  {
    "path": "OpenNFS1/Physics/VehicleFenceCollision.cs",
    "chars": 4544,
    "preview": "using System;\r\nusing System.Diagnostics;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r\nusing OpenNFS1.Audio;\r\n\r\nna"
  },
  {
    "path": "OpenNFS1/Physics/VehicleWheel.cs",
    "chars": 2897,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r"
  },
  {
    "path": "OpenNFS1/PlayerUI.cs",
    "chars": 1608,
    "preview": "using System.Collections.Generic;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing GameEngin"
  },
  {
    "path": "OpenNFS1/Polygon.cs",
    "chars": 2366,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "OpenNFS1/Program.cs",
    "chars": 771,
    "preview": "#region Using Statements\r\nusing System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\n#endre"
  },
  {
    "path": "OpenNFS1/Properties/AssemblyInfo.cs",
    "chars": 1425,
    "preview": "using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General I"
  },
  {
    "path": "OpenNFS1/Race/PlayerRaceStats.cs",
    "chars": 806,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\n\r\nnamespace OpenNFS1\r\n{\r\n\tcla"
  },
  {
    "path": "OpenNFS1/Race/Race.cs",
    "chars": 4682,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing OpenNFS1.Physics;\r\nusin"
  },
  {
    "path": "OpenNFS1/Race/RaceUI.cs",
    "chars": 3657,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Micr"
  },
  {
    "path": "OpenNFS1/Tracks/SceneryObject.cs",
    "chars": 3979,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "OpenNFS1/Tracks/TerrainRow.cs",
    "chars": 1264,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/Tracks/TerrainSegment.cs",
    "chars": 849,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/Tracks/Track.cs",
    "chars": 8165,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing System.IO;\r\nusing Microsoft.Xna.Framework;\r\n"
  },
  {
    "path": "OpenNFS1/Tracks/TrackAssembler.cs",
    "chars": 15063,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing OpenNFS1.Parsers.Track;\r\nusing System.IO;\r\nu"
  },
  {
    "path": "OpenNFS1/Tracks/TrackBillboardModel.cs",
    "chars": 2281,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "OpenNFS1/Tracks/TrackDescription.cs",
    "chars": 5142,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\n\r\nusing System.Text;\r\nusing System.IO;\r\n\r\nnamespace OpenNFS1\r\n{\r\n    "
  },
  {
    "path": "OpenNFS1/Tracks/TrackNode.cs",
    "chars": 3465,
    "preview": "using Microsoft.Xna.Framework;\r\nusing OpenNFS1;\r\nusing GameEngine;\r\nusing System;\r\nusing System.Collections.Generic;\r\nu"
  },
  {
    "path": "OpenNFS1/Tracks/TrackObjectDescriptor.cs",
    "chars": 164,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\n\r\nnamespace OpenNFS1.Tracks\r\n"
  },
  {
    "path": "OpenNFS1/Tracks/TrackSkybox.cs",
    "chars": 7590,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mi"
  },
  {
    "path": "OpenNFS1/UI/Screens/BaseUIScreen.cs",
    "chars": 2268,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Media;\r\nusing GameE"
  },
  {
    "path": "OpenNFS1/UI/Screens/ChooseDataDownloadScreen.cs",
    "chars": 1538,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/UI/Screens/DataDownloadScreen.cs",
    "chars": 3157,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Net;\r\nusing System"
  },
  {
    "path": "OpenNFS1/UI/Screens/DoRaceScreen.cs",
    "chars": 3632,
    "preview": "using Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Microsoft.Xna.Framework.Input;\r\nusing Gam"
  },
  {
    "path": "OpenNFS1/UI/Screens/HomeScreen.cs",
    "chars": 4996,
    "preview": "using System.Collections.Generic;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Audio;\r\nusing Microsof"
  },
  {
    "path": "OpenNFS1/UI/Screens/LoadRaceScreen.cs",
    "chars": 1910,
    "preview": "using System;\r\nusing System.Threading;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing "
  },
  {
    "path": "OpenNFS1/UI/Screens/OpenNFS1SplashScreen.cs",
    "chars": 1665,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.IO;\r\nusing System.Linq;\r\nusing System.Reflection;\r\nusing"
  },
  {
    "path": "OpenNFS1/UI/Screens/RaceFinishedScreen.cs",
    "chars": 3655,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework;"
  },
  {
    "path": "OpenNFS1/UI/Screens/RaceOptionsScreen.cs",
    "chars": 2295,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/UI/Screens/RacePausedScreen.cs",
    "chars": 1731,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework;"
  },
  {
    "path": "OpenNFS1/UIController.cs",
    "chars": 2623,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework."
  },
  {
    "path": "OpenNFS1/VehicleController.cs",
    "chars": 2524,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing GameEngine;\r\nusing Microsoft.Xna.Framework.I"
  },
  {
    "path": "OpenNFS1/Vehicles/AI/AIDriver.cs",
    "chars": 3509,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Linq;\r\nusing System.Text;\r\nus"
  },
  {
    "path": "OpenNFS1/Vehicles/AI/IDriver.cs",
    "chars": 256,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing OpenNFS1.Physics;\r\n\r\nna"
  },
  {
    "path": "OpenNFS1/Vehicles/AI/TrafficDriver.cs",
    "chars": 2944,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Diagnostics;\r\nusing System.Linq;\r\nusing System.Text;\r\nus"
  },
  {
    "path": "OpenNFS1/Vehicles/CarMesh.cs",
    "chars": 4354,
    "preview": "using Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing OpenNFS1.Parsers;\r\nusing GameEngine;\r\nus"
  },
  {
    "path": "OpenNFS1/Vehicles/CarModelCache.cs",
    "chars": 627,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing OpenNFS1.Parsers;\r\n\r\nnamespace OpenNFS1.Veh"
  },
  {
    "path": "OpenNFS1/Vehicles/PlayerDriver.cs",
    "chars": 829,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing OpenNFS1.Physics;\r\n\r\nna"
  },
  {
    "path": "OpenNFS1/Vehicles/Traffic/TrafficController.cs",
    "chars": 3177,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing OpenNFS1.Parsers.Track;\r\nusing Microsoft.Xn"
  },
  {
    "path": "OpenNFS1/Vehicles/TyreSmokeParticleSystem.cs",
    "chars": 1544,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\nusing OpenNFS1.Ph"
  },
  {
    "path": "OpenNFS1/Vehicles/Vehicle.cs",
    "chars": 7647,
    "preview": "using Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing OpenNFS1;\r\nusing OpenNFS1.Dashboards;\r\nu"
  },
  {
    "path": "OpenNFS1/Vehicles/VehicleDescription.cs",
    "chars": 2797,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\n\r\nnamespace OpenNFS1.Vehicles"
  },
  {
    "path": "OpenNFS1/Vehicles/WheelModel.cs",
    "chars": 5357,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing Mic"
  },
  {
    "path": "OpenNFS1/Views/BaseExternalView.cs",
    "chars": 2433,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework"
  },
  {
    "path": "OpenNFS1/Views/BumperView.cs",
    "chars": 1410,
    "preview": "using Microsoft.Xna.Framework;\r\nusing GameEngine;\r\nusing OpenNFS1.Physics;\r\n\r\nnamespace OpenNFS1.Views\r\n{\r\n\tclass Bumpe"
  },
  {
    "path": "OpenNFS1/Views/ChaseView.cs",
    "chars": 1405,
    "preview": "using Microsoft.Xna.Framework;\r\nusing GameEngine;\r\nusing OpenNFS1.Physics;\r\n\r\nnamespace OpenNFS1.Views\r\n{\r\n\t\r\n\r\n    clas"
  },
  {
    "path": "OpenNFS1/Views/DashboardView.cs",
    "chars": 1924,
    "preview": "using System.IO;\r\nusing Microsoft.Xna.Framework;\r\nusing Microsoft.Xna.Framework.Graphics;\r\nusing GameEngine;\r\nusing Open"
  },
  {
    "path": "OpenNFS1/Views/DebugView.cs",
    "chars": 770,
    "preview": "using Microsoft.Xna.Framework;\r\nusing GameEngine;\r\nusing OneAmEngine;\r\nusing OpenNFS1.Physics;\r\nusing OpenNFS1.Views;\r\n"
  },
  {
    "path": "OpenNFS1/Views/DropCameraView.cs",
    "chars": 1579,
    "preview": "using System;\r\nusing Microsoft.Xna.Framework;\r\nusing GameEngine;\r\nusing OpenNFS1.Physics;\r\nusing OpenNFS1.Tracks;\r\n\r\nna"
  },
  {
    "path": "OpenNFS1/Views/IView.cs",
    "chars": 364,
    "preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\nusing Microsoft.Xna.Framework;\r\n\r\nnamespace OpenNF"
  },
  {
    "path": "OpenNFS1/gameconfig.json",
    "chars": 142,
    "preview": "{\r\n\t\"fullScreen\": false,\r\n\t\"cdDataPath\": \"CD_Data\",\r\n\t\"drawDistance\": 5000,\r\n\t\"respectOpenRoadCheckpoints\": true,\r\n\t\"dr"
  },
  {
    "path": "OpenNFS1.sln",
    "chars": 8984,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2013\r\nVisualStudioVersion = 12.0.31101.0"
  },
  {
    "path": "TnfsSeSpex.txt",
    "chars": 20718,
    "preview": "\r\n============================================================================\r\nTHE UNOFFICIAL NEED FOR SPEED - SE FILE "
  },
  {
    "path": "readme.md",
    "chars": 1210,
    "preview": "## OpenNFS1\r\nOpenNFS1 is a ground-up remake of the original EA Need for Speed 1. The code is all written from scratch wi"
  },
  {
    "path": "reverse_engineering.txt",
    "chars": 1591,
    "preview": "2  left lane /\r\n1 nothing\r\n0 left lane \\\r\n3 nothing (default)\r\n\r\nLost Vegas:\r\nInside (ambient noise): 17,17,0,4\r\nNormal:"
  }
]

// ... and 3 more files (download for full content)

About this extraction

This page contains the full source code of the jeff-1amstudios/OpenNFS1 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 126 files (472.1 KB), approximately 127.1k tokens, and a symbol index with 584 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!