Просмотр исходного кода

Chapter 2 code, I think (need to test Mac still)?

Sanjay Madhav 8 лет назад
Родитель
Сommit
d220bd5e9b
42 измененных файлов с 2960 добавлено и 0 удалено
  1. 83 0
      Chapter02/Actor.cpp
  2. 60 0
      Chapter02/Actor.h
  3. 49 0
      Chapter02/AnimSpriteComponent.cpp
  4. 30 0
      Chapter02/AnimSpriteComponent.h
  5. BIN
      Chapter02/Assets/Enemy01.png
  6. BIN
      Chapter02/Assets/Enemy02.png
  7. BIN
      Chapter02/Assets/Enemy03.png
  8. BIN
      Chapter02/Assets/Enemy04.png
  9. BIN
      Chapter02/Assets/Enemy05.png
  10. BIN
      Chapter02/Assets/Enemy06.png
  11. BIN
      Chapter02/Assets/Farback01.png
  12. BIN
      Chapter02/Assets/Farback02.png
  13. 5 0
      Chapter02/Assets/LICENSE.txt
  14. BIN
      Chapter02/Assets/Laser.png
  15. 24 0
      Chapter02/Assets/MapLayer1.csv
  16. 24 0
      Chapter02/Assets/MapLayer2.csv
  17. 24 0
      Chapter02/Assets/MapLayer3.csv
  18. BIN
      Chapter02/Assets/Ship01.png
  19. BIN
      Chapter02/Assets/Ship02.png
  20. BIN
      Chapter02/Assets/Ship03.png
  21. BIN
      Chapter02/Assets/Ship04.png
  22. BIN
      Chapter02/Assets/Stars.png
  23. BIN
      Chapter02/Assets/Tiles.png
  24. 69 0
      Chapter02/BGSpriteComponent.cpp
  25. 37 0
      Chapter02/BGSpriteComponent.h
  26. 22 0
      Chapter02/Chapter02-windows.sln
  27. 342 0
      Chapter02/Chapter3-mac.xcodeproj/project.pbxproj
  28. 7 0
      Chapter02/Chapter3-mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  29. 92 0
      Chapter02/Chapter3-mac.xcodeproj/xcshareddata/xcschemes/Game-mac.xcscheme
  30. 27 0
      Chapter02/Component.cpp
  31. 27 0
      Chapter02/Component.h
  32. 312 0
      Chapter02/Game.cpp
  33. 58 0
      Chapter02/Game.h
  34. 124 0
      Chapter02/Game.vcxproj
  35. 64 0
      Chapter02/Game.vcxproj.filters
  36. 21 0
      Chapter02/Main.cpp
  37. 240 0
      Chapter02/Math.cpp
  38. 1033 0
      Chapter02/Math.h
  39. 78 0
      Chapter02/Ship.cpp
  40. 22 0
      Chapter02/Ship.h
  41. 56 0
      Chapter02/SpriteComponent.cpp
  42. 30 0
      Chapter02/SpriteComponent.h

+ 83 - 0
Chapter02/Actor.cpp

@@ -0,0 +1,83 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Actor.h"
+#include "Game.h"
+#include "Component.h"
+#include <algorithm>
+
+Actor::Actor(Game* game)
+	:mState(EActive)
+	, mPosition(Vector2::Zero)
+	, mScale(1.0f)
+	, mRotation(0.0f)
+	, mGame(game)
+{
+	mGame->AddActor(this);
+}
+
+Actor::~Actor()
+{
+	mGame->RemoveActor(this);
+	// Need to delete components
+	// Because ~Component calls RemoveComponent, need a different style loop
+	while (!mComponents.empty())
+	{
+		delete mComponents.back();
+	}
+}
+
+void Actor::Update(float deltaTime)
+{
+	if (mState == EActive)
+	{
+		UpdateComponents(deltaTime);
+		UpdateActor(deltaTime);
+	}
+}
+
+void Actor::UpdateComponents(float deltaTime)
+{
+	for (auto comp : mComponents)
+	{
+		comp->Update(deltaTime);
+	}
+}
+
+void Actor::UpdateActor(float deltaTime)
+{
+}
+
+void Actor::AddComponent(Component* component)
+{
+	// Find the insertion point in the sorted vector
+	// (The first element with a order higher than me)
+	int myOrder = component->GetUpdateOrder();
+	auto iter = mComponents.begin();
+	for (;
+		iter != mComponents.end();
+		++iter)
+	{
+		if (myOrder < (*iter)->GetUpdateOrder())
+		{
+			break;
+		}
+	}
+
+	// Inserts element before position of iterator
+	mComponents.insert(iter, component);
+}
+
+void Actor::RemoveComponent(Component* component)
+{
+	auto iter = std::find(mComponents.begin(), mComponents.end(), component);
+	if (iter != mComponents.end())
+	{
+		mComponents.erase(iter);
+	}
+}

+ 60 - 0
Chapter02/Actor.h

@@ -0,0 +1,60 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include <vector>
+#include "Math.h"
+class Actor
+{
+public:
+	enum State
+	{
+		EActive,
+		EPaused,
+		EDead
+	};
+
+	Actor(class Game* game);
+	virtual ~Actor();
+
+	// Update function called from Game (not overridable)
+	void Update(float deltaTime);
+	// Updates all the components attached to the actor (not overridable)
+	void UpdateComponents(float deltaTime);
+	// Any actor-specific update code (overridable)
+	virtual void UpdateActor(float deltaTime);
+
+	// Getters/setters
+	const Vector2& GetPosition() const { return mPosition; }
+	void SetPosition(const Vector2& pos) { mPosition = pos; }
+	float GetScale() const { return mScale; }
+	void SetScale(float scale) { mScale = scale; }
+	float GetRotation() const { return mRotation; }
+	void SetRotation(float rotation) { mRotation = rotation; }
+
+	State GetState() const { return mState; }
+	void SetState(State state) { mState = state; }
+
+	class Game* GetGame() { return mGame; }
+
+
+	// Add/remove components
+	void AddComponent(class Component* component);
+	void RemoveComponent(class Component* component);
+private:
+	// Actor's state
+	State mState;
+
+	// Transform
+	Vector2 mPosition;
+	float mScale;
+	float mRotation;
+
+	std::vector<class Component*> mComponents;
+	class Game* mGame;
+};

+ 49 - 0
Chapter02/AnimSpriteComponent.cpp

@@ -0,0 +1,49 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "AnimSpriteComponent.h"
+#include "Math.h"
+
+AnimSpriteComponent::AnimSpriteComponent(Actor* owner, int drawOrder)
+	:SpriteComponent(owner, drawOrder)
+	, mCurrFrame(0.0f)
+	, mAnimFPS(24.0f)
+{
+}
+
+void AnimSpriteComponent::Update(float deltaTime)
+{
+	SpriteComponent::Update(deltaTime);
+
+	if (mAnimTextures.size() > 0)
+	{
+		// Update the current frame based on frame rate
+		// and delta time
+		mCurrFrame += mAnimFPS * deltaTime;
+		
+		// Wrap current frame if needed
+		while (mCurrFrame >= mAnimTextures.size())
+		{
+			mCurrFrame -= mAnimTextures.size();
+		}
+
+		// Set the current texture
+		SetTexture(mAnimTextures[static_cast<int>(mCurrFrame)]);
+	}
+}
+
+void AnimSpriteComponent::SetAnimTextures(const std::vector<SDL_Texture*>& textures)
+{
+	mAnimTextures = textures;
+	if (mAnimTextures.size() > 0)
+	{
+		// Set the active texture to first frame
+		mCurrFrame = 0.0f;
+		SetTexture(mAnimTextures[0]);
+	}
+}

+ 30 - 0
Chapter02/AnimSpriteComponent.h

@@ -0,0 +1,30 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include "SpriteComponent.h"
+#include <vector>
+class AnimSpriteComponent : public SpriteComponent
+{
+public:
+	AnimSpriteComponent(class Actor* owner, int drawOrder = 100);
+	// Update animation every frame (overriden from component)
+	void Update(float deltaTime) override;
+	// Set the textures used for animation
+	void SetAnimTextures(const std::vector<SDL_Texture*>& textures);
+	// Set/get the animation FPS
+	float GetAnimFPS() const { return mAnimFPS; }
+	void SetAnimFPS(float fps) { mAnimFPS = fps; }
+private:
+	// All textures in the animation
+	std::vector<SDL_Texture*> mAnimTextures;
+	// Current frame displayed
+	float mCurrFrame;
+	// Animation frame rate
+	float mAnimFPS;
+};

BIN
Chapter02/Assets/Enemy01.png


BIN
Chapter02/Assets/Enemy02.png


BIN
Chapter02/Assets/Enemy03.png


BIN
Chapter02/Assets/Enemy04.png


BIN
Chapter02/Assets/Enemy05.png


BIN
Chapter02/Assets/Enemy06.png


BIN
Chapter02/Assets/Farback01.png


BIN
Chapter02/Assets/Farback02.png


+ 5 - 0
Chapter02/Assets/LICENSE.txt

@@ -0,0 +1,5 @@
+These sprites were designed by Jacob Zinman-Jeanes (http://jeanes.co) for Gamedevtuts+ (http://gamedev.tutsplus.com/).
+
+To find out more about what's in this mini sprite pack, check out this post: http://gamedev.tutsplus.com/articles/news/enjoy-these-totally-free-space-based-shoot-em-up-sprites/
+
+These sprites are licensed under the CC BY 3.0 license: http://creativecommons.org/licenses/by/3.0/

BIN
Chapter02/Assets/Laser.png


+ 24 - 0
Chapter02/Assets/MapLayer1.csv

@@ -0,0 +1,24 @@
+27,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42,43,44,42
+21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+29,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+37,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+29,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,48,49,52,53,54,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+27,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+27,43,44,45,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+29,-1,-1,-1,-1,-1,48,49,52,53,54,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+37,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,48,49,52,53,54,-1,-1,-1,48,49,50,51,52,50
+21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+27,10,11,12,11,12,10,11,12,10,11,12,10,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+27,43,44,42,43,44,42,43,44,42,43,44,42,43,44,45,-1,-1,-1,-1,-1,-1,48,49,53,54,-1,-1,-1,-1,-1,-1
+21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+29,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,56,57,58,59,57
+37,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,9,10,11,12,10,11,12,11,13,65,66,67,65
+21,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,41,42,42,43,44,42,43,44,45,-1,-1,-1,-1
+27,10,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,48,49,53,54,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+20,26,27,28,18,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+28,34,35,36,34,35,36,27,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+36,42,43,44,44,42,43,44,42,43,44,52,50,51,52,50,51,52,50,51,52,53,54,-1,-1,-1,-1,-1,-1,-1,-1,-1
+37,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,48,49,52,53,54,-1,8,9,10
+29,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,26

+ 24 - 0
Chapter02/Assets/MapLayer2.csv

@@ -0,0 +1,24 @@
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,61,62,63,70,70,70,70,70,70,70,70,70,61,63,61,62,62,63,70,61,62
+70,70,70,70,70,70,70,70,70,70,70,69,0,71,70,70,70,70,70,70,61,62,63,69,71,69,0,0,71,70,69,0
+70,70,70,70,70,70,70,70,70,70,70,69,0,75,62,63,70,70,70,70,69,0,71,69,71,69,0,0,71,70,69,0
+70,70,70,70,70,61,62,62,62,62,62,76,0,0,0,71,70,70,70,61,76,0,71,69,75,76,0,0,71,70,69,0
+70,70,70,70,70,69,0,0,0,0,0,0,0,0,0,71,70,70,70,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,70,70,70,69,0,0,0,0,0,0,0,0,0,75,63,61,63,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,70,70,70,69,0,0,0,0,0,0,0,0,0,0,75,76,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,70,61,62,76,0,0,0,0,0,0,0,0,0,0,0,0,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,61,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,71,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,79,69,0,0,71,69,0,0,0,0,71,70,69,0
+70,70,77,78,78,74,0,0,0,0,0,0,0,0,0,0,0,71,70,77,78,78,79,69,0,0,0,0,71,70,77,78
+70,70,70,70,70,77,78,78,78,74,0,0,0,0,73,78,78,79,70,70,70,70,70,69,0,0,0,0,71,70,70,70
+70,70,70,70,70,70,70,70,70,69,73,78,74,0,71,70,70,70,70,70,70,70,70,77,78,78,78,78,79,70,70,70
+70,70,70,70,70,70,70,70,70,77,79,70,77,78,79,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,70,61,63,61,62,62,63,61,63,70,70,70,70,70,70,70,70,70,70
+70,70,70,70,70,70,70,70,70,70,70,70,70,61,76,71,69,0,0,75,76,71,70,70,70,70,70,70,70,70,70,70

+ 24 - 0
Chapter02/Assets/MapLayer3.csv

@@ -0,0 +1,24 @@
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113
+96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97,98,96,97
+104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105,106,104,105
+112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113,114,112,113

BIN
Chapter02/Assets/Ship01.png


BIN
Chapter02/Assets/Ship02.png


BIN
Chapter02/Assets/Ship03.png


BIN
Chapter02/Assets/Ship04.png


BIN
Chapter02/Assets/Stars.png


BIN
Chapter02/Assets/Tiles.png


+ 69 - 0
Chapter02/BGSpriteComponent.cpp

@@ -0,0 +1,69 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "BGSpriteComponent.h"
+#include "Actor.h"
+
+BGSpriteComponent::BGSpriteComponent(class Actor* owner, int drawOrder)
+	:SpriteComponent(owner, drawOrder)
+	,mScrollSpeed(0.0f)
+{
+}
+
+void BGSpriteComponent::Update(float deltaTime)
+{
+	SpriteComponent::Update(deltaTime);
+	for (auto& bg : mBGTextures)
+	{
+		// Update the x offset
+		bg.mOffset.x += mScrollSpeed * deltaTime;
+		// If this is completely off the screen, reset offset to
+		// the right of the last bg texture
+		if (bg.mOffset.x < -mScreenSize.x)
+		{
+			bg.mOffset.x = (mBGTextures.size() - 1) * mScreenSize.x - 1;
+		}
+	}
+}
+
+void BGSpriteComponent::Draw(SDL_Renderer* renderer)
+{
+	// Draw each background texture
+	for (auto& bg : mBGTextures)
+	{
+		SDL_Rect r;
+		// Assume screen size dimensions
+		r.w = static_cast<int>(mScreenSize.x);
+		r.h = static_cast<int>(mScreenSize.y);
+		// Center the rectangle around the position of the owner
+		r.x = static_cast<int>(mOwner->GetPosition().x - r.w / 2 + bg.mOffset.x);
+		r.y = static_cast<int>(mOwner->GetPosition().y - r.h / 2 + bg.mOffset.y);
+
+		// Draw this background
+		SDL_RenderCopy(renderer,
+			bg.mTexture,
+			nullptr,
+			&r
+		);
+	}
+}
+
+void BGSpriteComponent::SetBGTextures(const std::vector<SDL_Texture*>& textures)
+{
+	int count = 0;
+	for (auto tex : textures)
+	{
+		BGTexture temp;
+		temp.mTexture = tex;
+		// Each texture is screen width in offset
+		temp.mOffset.x = count * mScreenSize.x;
+		temp.mOffset.y = 0;
+		mBGTextures.emplace_back(temp);
+		count++;
+	}
+}

+ 37 - 0
Chapter02/BGSpriteComponent.h

@@ -0,0 +1,37 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include "SpriteComponent.h"
+#include <vector>
+#include "Math.h"
+class BGSpriteComponent : public SpriteComponent
+{
+public:
+	// Set draw order to default to lower (so it's in the background)
+	BGSpriteComponent(class Actor* owner, int drawOrder = 10);
+	// Update/draw overriden from parent
+	void Update(float deltaTime) override;
+	void Draw(SDL_Renderer* renderer) override;
+	// Set the textures used for the background
+	void SetBGTextures(const std::vector<SDL_Texture*>& textures);
+	// Get/set screen size and scroll speed
+	void SetScreenSize(const Vector2& size) { mScreenSize = size; }
+	void SetScrollSpeed(float speed) { mScrollSpeed = speed; }
+	float GetScrollSpeed() const { return mScrollSpeed; }
+private:
+	// Struct to encapsulate each bg image and its offset
+	struct BGTexture
+	{
+		SDL_Texture* mTexture;
+		Vector2 mOffset;
+	};
+	std::vector<BGTexture> mBGTextures;
+	Vector2 mScreenSize;
+	float mScrollSpeed;
+};

+ 22 - 0
Chapter02/Chapter02-windows.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "Game.vcxproj", "{BC508D87-495F-4554-932D-DD68388B63CC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BC508D87-495F-4554-932D-DD68388B63CC}.Debug|Win32.ActiveCfg = Debug|Win32
+		{BC508D87-495F-4554-932D-DD68388B63CC}.Debug|Win32.Build.0 = Debug|Win32
+		{BC508D87-495F-4554-932D-DD68388B63CC}.Release|Win32.ActiveCfg = Release|Win32
+		{BC508D87-495F-4554-932D-DD68388B63CC}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 342 - 0
Chapter02/Chapter3-mac.xcodeproj/project.pbxproj

@@ -0,0 +1,342 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		9223C4781F009428009A94D7 /* Game.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4671F009428009A94D7 /* Game.cpp */; };
+		9223C4791F009428009A94D7 /* Actor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4681F009428009A94D7 /* Actor.cpp */; };
+		9223C47A1F009428009A94D7 /* AnimSpriteComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C46A1F009428009A94D7 /* AnimSpriteComponent.cpp */; };
+		9223C47B1F009428009A94D7 /* BGSpriteComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C46C1F009428009A94D7 /* BGSpriteComponent.cpp */; };
+		9223C47C1F009428009A94D7 /* Component.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C46E1F009428009A94D7 /* Component.cpp */; };
+		9223C47D1F009428009A94D7 /* Main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4711F009428009A94D7 /* Main.cpp */; };
+		9223C47E1F009428009A94D7 /* Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4721F009428009A94D7 /* Math.cpp */; };
+		9223C47F1F009428009A94D7 /* Ship.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4741F009428009A94D7 /* Ship.cpp */; };
+		9223C4801F009428009A94D7 /* SpriteComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9223C4761F009428009A94D7 /* SpriteComponent.cpp */; };
+		92D324FB1B697389005A86C7 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92D324FA1B697389005A86C7 /* CoreFoundation.framework */; };
+		92E46E941B6353E50035CD21 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92E46E931B6353E50035CD21 /* OpenGL.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		9223C4671F009428009A94D7 /* Game.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Game.cpp; sourceTree = "<group>"; };
+		9223C4681F009428009A94D7 /* Actor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Actor.cpp; sourceTree = "<group>"; };
+		9223C4691F009428009A94D7 /* Actor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Actor.h; sourceTree = "<group>"; };
+		9223C46A1F009428009A94D7 /* AnimSpriteComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimSpriteComponent.cpp; sourceTree = "<group>"; };
+		9223C46B1F009428009A94D7 /* AnimSpriteComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimSpriteComponent.h; sourceTree = "<group>"; };
+		9223C46C1F009428009A94D7 /* BGSpriteComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BGSpriteComponent.cpp; sourceTree = "<group>"; };
+		9223C46D1F009428009A94D7 /* BGSpriteComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BGSpriteComponent.h; sourceTree = "<group>"; };
+		9223C46E1F009428009A94D7 /* Component.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Component.cpp; sourceTree = "<group>"; };
+		9223C46F1F009428009A94D7 /* Component.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Component.h; sourceTree = "<group>"; };
+		9223C4701F009428009A94D7 /* Game.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Game.h; sourceTree = "<group>"; };
+		9223C4711F009428009A94D7 /* Main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Main.cpp; sourceTree = "<group>"; };
+		9223C4721F009428009A94D7 /* Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Math.cpp; sourceTree = "<group>"; };
+		9223C4731F009428009A94D7 /* Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Math.h; sourceTree = "<group>"; };
+		9223C4741F009428009A94D7 /* Ship.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ship.cpp; sourceTree = "<group>"; };
+		9223C4751F009428009A94D7 /* Ship.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ship.h; sourceTree = "<group>"; };
+		9223C4761F009428009A94D7 /* SpriteComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteComponent.cpp; sourceTree = "<group>"; };
+		9223C4771F009428009A94D7 /* SpriteComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpriteComponent.h; sourceTree = "<group>"; };
+		92D324FA1B697389005A86C7 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+		92E46DF71B634EA30035CD21 /* Game-mac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Game-mac"; sourceTree = BUILT_PRODUCTS_DIR; };
+		92E46E931B6353E50035CD21 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		92E46DF41B634EA30035CD21 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				92D324FB1B697389005A86C7 /* CoreFoundation.framework in Frameworks */,
+				92E46E941B6353E50035CD21 /* OpenGL.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		92E46DEE1B634EA30035CD21 = {
+			isa = PBXGroup;
+			children = (
+				9223C4681F009428009A94D7 /* Actor.cpp */,
+				9223C4691F009428009A94D7 /* Actor.h */,
+				9223C46A1F009428009A94D7 /* AnimSpriteComponent.cpp */,
+				9223C46B1F009428009A94D7 /* AnimSpriteComponent.h */,
+				9223C46C1F009428009A94D7 /* BGSpriteComponent.cpp */,
+				9223C46D1F009428009A94D7 /* BGSpriteComponent.h */,
+				9223C46E1F009428009A94D7 /* Component.cpp */,
+				9223C46F1F009428009A94D7 /* Component.h */,
+				9223C4671F009428009A94D7 /* Game.cpp */,
+				9223C4701F009428009A94D7 /* Game.h */,
+				9223C4711F009428009A94D7 /* Main.cpp */,
+				9223C4721F009428009A94D7 /* Math.cpp */,
+				9223C4731F009428009A94D7 /* Math.h */,
+				9223C4741F009428009A94D7 /* Ship.cpp */,
+				9223C4751F009428009A94D7 /* Ship.h */,
+				9223C4761F009428009A94D7 /* SpriteComponent.cpp */,
+				9223C4771F009428009A94D7 /* SpriteComponent.h */,
+				92E46DF81B634EA30035CD21 /* Products */,
+				92D324FA1B697389005A86C7 /* CoreFoundation.framework */,
+				92E46E931B6353E50035CD21 /* OpenGL.framework */,
+			);
+			sourceTree = "<group>";
+		};
+		92E46DF81B634EA30035CD21 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				92E46DF71B634EA30035CD21 /* Game-mac */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		92E46DF61B634EA30035CD21 /* Game-mac */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 92E46DFE1B634EA40035CD21 /* Build configuration list for PBXNativeTarget "Game-mac" */;
+			buildPhases = (
+				92E46DF31B634EA30035CD21 /* Sources */,
+				92E46DF41B634EA30035CD21 /* Frameworks */,
+				92E46EA11B63615B0035CD21 /* ShellScript */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "Game-mac";
+			productName = "Game-mac";
+			productReference = 92E46DF71B634EA30035CD21 /* Game-mac */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		92E46DEF1B634EA30035CD21 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0720;
+				ORGANIZATIONNAME = "Sanjay Madhav";
+				TargetAttributes = {
+					92E46DF61B634EA30035CD21 = {
+						CreatedOnToolsVersion = 6.4;
+					};
+				};
+			};
+			buildConfigurationList = 92E46DF21B634EA30035CD21 /* Build configuration list for PBXProject "Chapter3-mac" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 92E46DEE1B634EA30035CD21;
+			productRefGroup = 92E46DF81B634EA30035CD21 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				92E46DF61B634EA30035CD21 /* Game-mac */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		92E46EA11B63615B0035CD21 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "if [ -d \"$BUILD_DIR/Debug\" ]; then\n    cp \"$SRCROOT\"/../external/GLEW/lib/mac/*.dylib $BUILD_DIR/Debug\n    cp \"$SRCROOT\"/../external/SDL/lib/mac/*.dylib $BUILD_DIR/Debug\nfi\n\nif [ -d \"$BUILD_DIR/Release\" ]; then\n    cp \"$SRCROOT\"/../external/GLEW/lib/mac/*.dylib $BUILD_DIR/Release\n    cp \"$SRCROOT\"/../external/SDL/lib/mac/*.dylib $BUILD_DIR/Release\nfi";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		92E46DF31B634EA30035CD21 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				9223C47D1F009428009A94D7 /* Main.cpp in Sources */,
+				9223C47E1F009428009A94D7 /* Math.cpp in Sources */,
+				9223C47A1F009428009A94D7 /* AnimSpriteComponent.cpp in Sources */,
+				9223C47B1F009428009A94D7 /* BGSpriteComponent.cpp in Sources */,
+				9223C4781F009428009A94D7 /* Game.cpp in Sources */,
+				9223C4801F009428009A94D7 /* SpriteComponent.cpp in Sources */,
+				9223C47F1F009428009A94D7 /* Ship.cpp in Sources */,
+				9223C4791F009428009A94D7 /* Actor.cpp in Sources */,
+				9223C47C1F009428009A94D7 /* Component.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		92E46DFC1B634EA40035CD21 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		92E46DFD1B634EA40035CD21 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		92E46DFF1B634EA40035CD21 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_ENABLE_CPP_RTTI = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)/../external/SDL/include",
+					"$(SRCROOT)/../external/GLEW/include",
+					"$(SRCROOT)/../external/SOIL/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(SRCROOT)/../external/GLEW/lib/mac",
+					"$(SRCROOT)/../external/SDL/lib/mac",
+					"$(SRCROOT)/../external/SOIL/lib/mac",
+				);
+				OTHER_LDFLAGS = (
+					"-lGLEW.2.1.0",
+					"-lSDL2-2.0.0",
+					"-lSDL2_mixer-2.0.0",
+					"-lSDL2_ttf-2.0.0",
+					"-lSOIL",
+					"-lSDL2_image-2.0.0",
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		92E46E001B634EA40035CD21 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_CXX_LANGUAGE_STANDARD = "c++14";
+				FRAMEWORK_SEARCH_PATHS = "";
+				GCC_ENABLE_CPP_RTTI = YES;
+				HEADER_SEARCH_PATHS = (
+					"$(inherited)",
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+					"$(SRCROOT)/../external/SDL/include",
+					"$(SRCROOT)/../external/GLEW/include",
+					"$(SRCROOT)/../external/SOIL/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(SRCROOT)/../external/GLEW/lib/mac",
+					"$(SRCROOT)/../external/SDL/lib/mac",
+					"$(SRCROOT)/../external/SOIL/lib/mac",
+				);
+				OTHER_LDFLAGS = (
+					"-lGLEW.2.1.0",
+					"-lSDL2-2.0.0",
+					"-lSDL2_mixer-2.0.0",
+					"-lSDL2_ttf-2.0.0",
+					"-lSOIL",
+					"-lSDL2_image-2.0.0",
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		92E46DF21B634EA30035CD21 /* Build configuration list for PBXProject "Chapter3-mac" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				92E46DFC1B634EA40035CD21 /* Debug */,
+				92E46DFD1B634EA40035CD21 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		92E46DFE1B634EA40035CD21 /* Build configuration list for PBXNativeTarget "Game-mac" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				92E46DFF1B634EA40035CD21 /* Debug */,
+				92E46E001B634EA40035CD21 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 92E46DEF1B634EA30035CD21 /* Project object */;
+}

+ 7 - 0
Chapter02/Chapter3-mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:Game-mac.xcodeproj">
+   </FileRef>
+</Workspace>

+ 92 - 0
Chapter02/Chapter3-mac.xcodeproj/xcshareddata/xcschemes/Game-mac.xcscheme

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0830"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "92E46DF61B634EA30035CD21"
+               BuildableName = "Game-mac"
+               BlueprintName = "Game-mac"
+               ReferencedContainer = "container:Chapter3-mac.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "92E46DF61B634EA30035CD21"
+            BuildableName = "Game-mac"
+            BlueprintName = "Game-mac"
+            ReferencedContainer = "container:Chapter3-mac.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "YES"
+      customWorkingDirectory = "$(SRCROOT)"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "92E46DF61B634EA30035CD21"
+            BuildableName = "Game-mac"
+            BlueprintName = "Game-mac"
+            ReferencedContainer = "container:Chapter3-mac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "92E46DF61B634EA30035CD21"
+            BuildableName = "Game-mac"
+            BlueprintName = "Game-mac"
+            ReferencedContainer = "container:Chapter3-mac.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 27 - 0
Chapter02/Component.cpp

@@ -0,0 +1,27 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Component.h"
+#include "Actor.h"
+
+Component::Component(Actor* owner, int updateOrder)
+	:mOwner(owner)
+	,mUpdateOrder(updateOrder)
+{
+	// Add to actor's vector of components
+	mOwner->AddComponent(this);
+}
+
+Component::~Component()
+{
+	mOwner->RemoveComponent(this);
+}
+
+void Component::Update(float deltaTime)
+{
+}

+ 27 - 0
Chapter02/Component.h

@@ -0,0 +1,27 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+class Component
+{
+public:
+	// Constructor
+	// (the lower the update order, the earlier the component updates)
+	Component(class Actor* owner, int updateOrder = 100);
+	// Destructor
+	virtual ~Component();
+	// Update this component by delta time
+	virtual void Update(float deltaTime);
+
+	int GetUpdateOrder() const { return mUpdateOrder; }
+protected:
+	// Owning actor
+	class Actor* mOwner;
+	// Update order of component
+	int mUpdateOrder;
+};

+ 312 - 0
Chapter02/Game.cpp

@@ -0,0 +1,312 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Game.h"
+#include "SDL/SDL_image.h"
+#include <algorithm>
+#include "Actor.h"
+#include "SpriteComponent.h"
+#include "Ship.h"
+#include "BGSpriteComponent.h"
+
+Game::Game()
+:mWindow(nullptr)
+,mRenderer(nullptr)
+,mIsRunning(true)
+,mUpdatingActors(false)
+{
+	
+}
+
+bool Game::Initialize()
+{
+	if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0)
+	{
+		SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
+		return false;
+	}
+	
+	mWindow = SDL_CreateWindow("Game Programming in C++ (Chapter 3)", 100, 100, 1024, 768, 0);
+	if (!mWindow)
+	{
+		SDL_Log("Failed to create window: %s", SDL_GetError());
+		return false;
+	}
+	
+	mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+	if (!mRenderer)
+	{
+		SDL_Log("Failed to create renderer: %s", SDL_GetError());
+		return false;
+	}
+	
+	if (IMG_Init(IMG_INIT_PNG) == 0)
+	{
+		SDL_Log("Unable to initialize SDL_image: %s", SDL_GetError());
+		return false;
+	}
+
+	LoadData();
+
+	mTicksCount = SDL_GetTicks();
+	
+	return true;
+}
+
+void Game::RunLoop()
+{
+	while (mIsRunning)
+	{
+		ProcessInput();
+		UpdateGame();
+		GenerateOutput();
+	}
+}
+
+void Game::ProcessInput()
+{
+	SDL_Event event;
+	while (SDL_PollEvent(&event))
+	{
+		switch (event.type)
+		{
+			case SDL_QUIT:
+				mIsRunning = false;
+				break;
+		}
+	}
+	
+	const Uint8* state = SDL_GetKeyboardState(NULL);
+	if (state[SDL_SCANCODE_ESCAPE])
+	{
+		mIsRunning = false;
+	}
+
+	// Process ship input
+	mShip->ProcessKeyboard(state);
+}
+
+void Game::UpdateGame()
+{
+	// Compute delta time
+	// Wait until 16ms has elapsed since last frame
+	while (!SDL_TICKS_PASSED(SDL_GetTicks(), mTicksCount + 16))
+		;
+
+	float deltaTime = (SDL_GetTicks() - mTicksCount) / 1000.0f;
+	if (deltaTime > 0.05f)
+	{
+		deltaTime = 0.05f;
+	}
+	mTicksCount = SDL_GetTicks();
+
+	// Update all actors
+	mUpdatingActors = true;
+	for (auto actor : mActors)
+	{
+		actor->Update(deltaTime);
+	}
+	mUpdatingActors = false;
+
+	// Move any pending actors to mActors
+	for (auto pending : mPendingActors)
+	{
+		mActors.emplace_back(pending);
+	}
+	mPendingActors.clear();
+
+	// Add any dead actors to a temp vector
+	std::vector<Actor*> deadActors;
+	for (auto actor : mActors)
+	{
+		if (actor->GetState() == Actor::EDead)
+		{
+			deadActors.emplace_back(actor);
+		}
+	}
+
+	// Delete dead actors (which removes them from mActors)
+	for (auto actor : deadActors)
+	{
+		delete actor;
+	}
+}
+
+void Game::GenerateOutput()
+{
+	SDL_SetRenderDrawColor(mRenderer, 0, 0, 0, 255);
+	SDL_RenderClear(mRenderer);
+	
+	// Draw all sprite components
+	for (auto sprite : mSprites)
+	{
+		sprite->Draw(mRenderer);
+	}
+
+	SDL_RenderPresent(mRenderer);
+}
+
+void Game::LoadData()
+{
+	// Load textures
+	LoadTexture("Assets/Laser.png");
+	LoadTexture("Assets/Ship01.png");
+	LoadTexture("Assets/Ship02.png");
+	LoadTexture("Assets/Ship03.png");
+	LoadTexture("Assets/Ship04.png");
+	LoadTexture("Assets/Farback01.png");
+	LoadTexture("Assets/Farback02.png");
+	LoadTexture("Assets/Stars.png");
+
+	// Create player's ship
+	mShip = new Ship(this);
+	mShip->SetPosition(Vector2(100.0f, 384.0f));
+	mShip->SetScale(1.5f);
+
+	// Create actor for the background (this doesn't need a subclass)
+	Actor* temp = new Actor(this);
+	temp->SetPosition(Vector2(512.0f, 384.0f));
+	// Create the "far back" background
+	BGSpriteComponent* bg = new BGSpriteComponent(temp);
+	bg->SetScreenSize(Vector2(1024.0f, 768.0f));
+	std::vector<SDL_Texture*> bgtexs = {
+		GetTexture("Assets/Farback01.png"),
+		GetTexture("Assets/Farback02.png")
+	};
+	bg->SetBGTextures(bgtexs);
+	bg->SetScrollSpeed(-100.0f);
+	// Create the closer background
+	bg = new BGSpriteComponent(temp, 50);
+	bg->SetScreenSize(Vector2(1024.0f, 768.0f));
+	bgtexs = {
+		GetTexture("Assets/Stars.png"),
+		GetTexture("Assets/Stars.png")
+	};
+	bg->SetBGTextures(bgtexs);
+	bg->SetScrollSpeed(-200.0f);
+}
+
+void Game::UnloadData()
+{
+	// Delete actors
+	// Because ~Actor calls RemoveActor, have to use a different style loop
+	while (!mActors.empty())
+	{
+		delete mActors.back();
+	}
+
+	// Destroy textures
+	for (auto i : mTextures)
+	{
+		SDL_DestroyTexture(i.second);
+	}
+	mTextures.clear();
+}
+
+void Game::LoadTexture(const char* fileName)
+{
+	// Load from file
+	SDL_Surface* surf = IMG_Load(fileName);
+	if (!surf)
+	{
+		SDL_Log("Failed to load texture file %s", fileName);
+		return;
+	}
+
+	// Create texture from surface
+	SDL_Texture* text = SDL_CreateTextureFromSurface(mRenderer, surf);
+	SDL_FreeSurface(surf);
+	if (!text)
+	{
+		SDL_Log("Failed to convert surface to texture for %s", fileName);
+		return;
+	}
+	
+	mTextures.emplace(fileName, text);
+}
+
+SDL_Texture * Game::GetTexture(const char * fileName)
+{
+	SDL_Texture* tex = nullptr;
+	auto iter = mTextures.find(fileName);
+	if (iter != mTextures.end())
+	{
+		tex = iter->second;
+	}
+	return tex;
+}
+
+void Game::Shutdown()
+{
+	UnloadData();
+	IMG_Quit();
+	SDL_DestroyRenderer(mRenderer);
+	SDL_DestroyWindow(mWindow);
+	SDL_Quit();
+}
+
+void Game::AddActor(Actor* actor)
+{
+	// If we're updating actors, need to add to pending
+	if (mUpdatingActors)
+	{
+		mPendingActors.emplace_back(actor);
+	}
+	else
+	{
+		mActors.emplace_back(actor);
+	}
+}
+
+void Game::RemoveActor(Actor* actor)
+{
+	// Is it in pending actors?
+	auto iter = std::find(mPendingActors.begin(), mPendingActors.end(), actor);
+	if (iter != mPendingActors.end())
+	{
+		// Swap to end of vector and pop off (avoid erase copies)
+		std::iter_swap(iter, mPendingActors.end() - 1);
+		mPendingActors.pop_back();
+	}
+
+	// Is it in actors?
+	iter = std::find(mActors.begin(), mActors.end(), actor);
+	if (iter != mActors.end())
+	{
+		// Swap to end of vector and pop off (avoid erase copies)
+		std::iter_swap(iter, mActors.end() - 1);
+		mActors.pop_back();
+	}
+}
+
+void Game::AddSprite(SpriteComponent* sprite)
+{
+	// Find the insertion point in the sorted vector
+	// (The first element with a higher draw order than me)
+	int myDrawOrder = sprite->GetDrawOrder();
+	auto iter = mSprites.begin();
+	for ( ;
+		iter != mSprites.end();
+		++iter)
+	{
+		if (myDrawOrder < (*iter)->GetDrawOrder())
+		{
+			break;
+		}
+	}
+
+	// Inserts element before position of iterator
+	mSprites.insert(iter, sprite);
+}
+
+void Game::RemoveSprite(SpriteComponent* sprite)
+{
+	// (We can't swap because it ruins ordering)
+	auto iter = std::find(mSprites.begin(), mSprites.end(), sprite);
+	mSprites.erase(iter);
+}

+ 58 - 0
Chapter02/Game.h

@@ -0,0 +1,58 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include "SDL/SDL.h"
+#include <unordered_map>
+#include <string>
+#include <vector>
+
+class Game
+{
+public:
+	Game();
+	bool Initialize();
+	void RunLoop();
+	void Shutdown();
+
+	void AddActor(class Actor* actor);
+	void RemoveActor(class Actor* actor);
+
+	void AddSprite(class SpriteComponent* sprite);
+	void RemoveSprite(class SpriteComponent* sprite);
+	
+	void LoadTexture(const char* fileName);
+	SDL_Texture* GetTexture(const char* fileName);
+private:
+	void ProcessInput();
+	void UpdateGame();
+	void GenerateOutput();
+	void LoadData();
+	void UnloadData();
+	
+	// Map of textures loaded
+	std::unordered_map<std::string, SDL_Texture*> mTextures;
+
+	// All the actors in the game
+	std::vector<class Actor*> mActors;
+	// Any pending actors
+	std::vector<class Actor*> mPendingActors;
+
+	// All the sprite components drawn
+	std::vector<class SpriteComponent*> mSprites;
+
+	SDL_Window* mWindow;
+	SDL_Renderer* mRenderer;
+	Uint32 mTicksCount;
+	bool mIsRunning;
+	// Track if we're updating actors right now
+	bool mUpdatingActors;
+
+	// Game-specific
+	class Ship* mShip; // Player's ship
+};

+ 124 - 0
Chapter02/Game.vcxproj

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Actor.cpp" />
+    <ClCompile Include="AnimSpriteComponent.cpp" />
+    <ClCompile Include="BGSpriteComponent.cpp" />
+    <ClCompile Include="Component.cpp" />
+    <ClCompile Include="Game.cpp" />
+    <ClCompile Include="Main.cpp" />
+    <ClCompile Include="Math.cpp" />
+    <ClCompile Include="Ship.cpp" />
+    <ClCompile Include="SpriteComponent.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Actor.h" />
+    <ClInclude Include="AnimSpriteComponent.h" />
+    <ClInclude Include="BGSpriteComponent.h" />
+    <ClInclude Include="Component.h" />
+    <ClInclude Include="Game.h" />
+    <ClInclude Include="Math.h" />
+    <ClInclude Include="Ship.h" />
+    <ClInclude Include="SpriteComponent.h" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{BC508D87-495F-4554-932D-DD68388B63CC}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>Game</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v141</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>..\external\SDL\include;..\external\GLEW\include;..\external\SOIL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <ExceptionHandling>Sync</ExceptionHandling>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>..\external\SDL\lib\win\x86;..\external\GLEW\lib\win\x86;..\external\SOIL\lib\win\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;SDL2_ttf.lib;SDL2_mixer.lib;SDL2_image.lib;glew32.lib;SOIL.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalOptions>/NODEFAULTLIB:msvcrt.lib %(AdditionalOptions)</AdditionalOptions>
+    </Link>
+    <PostBuildEvent>
+      <Command>xcopy "$(ProjectDir)\..\external\SDL\lib\win\x86\*.dll" "$(OutDir)" /i /s /y
+xcopy "$(ProjectDir)\..\external\GLEW\lib\win\x86\*.dll" "$(OutDir)" /i /s /y</Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <AdditionalIncludeDirectories>..\external\SDL\include;..\external\GLEW\include;..\external\SOIL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeTypeInfo>false</RuntimeTypeInfo>
+      <ExceptionHandling>Sync</ExceptionHandling>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalLibraryDirectories>..\external\SDL\lib\win\x86;..\external\GLEW\lib\win\x86;..\external\SOIL\lib\win\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>opengl32.lib;SDL2.lib;SDL2main.lib;SDL2_ttf.lib;SDL2_mixer.lib;SDL2_image.lib;glew32.lib;SOIL.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <PostBuildEvent>
+      <Command>xcopy "$(ProjectDir)\..\external\SDL\lib\win\x86\*.dll" "$(OutDir)" /i /s /y
+xcopy "$(ProjectDir)\..\external\GLEW\lib\win\x86\*.dll" "$(OutDir)" /i /s /y</Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 64 - 0
Chapter02/Game.vcxproj.filters

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Actor.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Component.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Game.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Main.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Math.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="SpriteComponent.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="AnimSpriteComponent.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Ship.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="BGSpriteComponent.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="Actor.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Component.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Game.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Math.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="SpriteComponent.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="AnimSpriteComponent.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Ship.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="BGSpriteComponent.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 21 - 0
Chapter02/Main.cpp

@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Game.h"
+
+int main(int argc, char** argv)
+{
+	Game game;
+	bool success = game.Initialize();
+	if (success)
+	{
+		game.RunLoop();
+	}
+	game.Shutdown();
+	return 0;
+}

+ 240 - 0
Chapter02/Math.cpp

@@ -0,0 +1,240 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Math.h"
+
+const Vector2 Vector2::Zero(0.0f, 0.0f);
+const Vector2 Vector2::UnitX(1.0f, 0.0f);
+const Vector2 Vector2::UnitY(0.0f, 1.0f);
+const Vector2 Vector2::NegUnitX(-1.0f, 0.0f);
+const Vector2 Vector2::NegUnitY(0.0f, -1.0f);
+
+const Vector3 Vector3::Zero(0.0f, 0.0f, 0.f);
+const Vector3 Vector3::UnitX(1.0f, 0.0f, 0.0f);
+const Vector3 Vector3::UnitY(0.0f, 1.0f, 0.0f);
+const Vector3 Vector3::UnitZ(0.0f, 0.0f, 1.0f);
+const Vector3 Vector3::NegUnitX(-1.0f, 0.0f, 0.0f);
+const Vector3 Vector3::NegUnitY(0.0f, -1.0f, 0.0f);
+const Vector3 Vector3::NegUnitZ(0.0f, 0.0f, -1.0f);
+const Vector3 Vector3::Infinity(Math::Infinity, Math::Infinity, Math::Infinity);
+const Vector3 Vector3::NegInfinity(Math::NegInfinity, Math::NegInfinity, Math::NegInfinity);
+
+static float m3Ident[3][3] =
+{
+	{ 1.0f, 0.0f, 0.0f },
+	{ 0.0f, 1.0f, 0.0f },
+	{ 0.0f, 0.0f, 1.0f }
+};
+const Matrix3 Matrix3::Identity(m3Ident);
+
+static float m4Ident[4][4] =
+{
+	{ 1.0f, 0.0f, 0.0f, 0.0f },
+	{ 0.0f, 1.0f, 0.0f, 0.0f },
+	{ 0.0f, 0.0f, 1.0f, 0.0f },
+	{ 0.0f, 0.0f, 0.0f, 1.0f }
+};
+
+const Matrix4 Matrix4::Identity(m4Ident);
+
+const Quaternion Quaternion::Identity(0.0f, 0.0f, 0.0f, 1.0f);
+
+Vector2 Vector2::Transform(const Vector2& vec, const Matrix3& mat, float w /*= 1.0f*/)
+{
+	Vector2 retVal;
+	retVal.x = vec.x * mat.mat[0][0] + vec.y * mat.mat[1][0] + w * mat.mat[2][0];
+	retVal.y = vec.x * mat.mat[0][1] + vec.y * mat.mat[1][1] + w * mat.mat[2][1];
+	//ignore w since we aren't returning a new value for it...
+	return retVal;
+}
+
+Vector3 Vector3::Transform(const Vector3& vec, const Matrix4& mat, float w /*= 1.0f*/)
+{
+	Vector3 retVal;
+	retVal.x = vec.x * mat.mat[0][0] + vec.y * mat.mat[1][0] +
+		vec.z * mat.mat[2][0] + w * mat.mat[3][0];
+	retVal.y = vec.x * mat.mat[0][1] + vec.y * mat.mat[1][1] +
+		vec.z * mat.mat[2][1] + w * mat.mat[3][1];
+	retVal.z = vec.x * mat.mat[0][2] + vec.y * mat.mat[1][2] +
+		vec.z * mat.mat[2][2] + w * mat.mat[3][2];
+	//ignore w since we aren't returning a new value for it...
+	return retVal;
+}
+
+// This will transform the vector and renormalize the w component
+Vector3 Vector3::TransformWithPerspDiv(const Vector3& vec, const Matrix4& mat, float w /*= 1.0f*/)
+{
+	Vector3 retVal;
+	retVal.x = vec.x * mat.mat[0][0] + vec.y * mat.mat[1][0] +
+		vec.z * mat.mat[2][0] + w * mat.mat[3][0];
+	retVal.y = vec.x * mat.mat[0][1] + vec.y * mat.mat[1][1] +
+		vec.z * mat.mat[2][1] + w * mat.mat[3][1];
+	retVal.z = vec.x * mat.mat[0][2] + vec.y * mat.mat[1][2] +
+		vec.z * mat.mat[2][2] + w * mat.mat[3][2];
+	float transformedW = vec.x * mat.mat[0][3] + vec.y * mat.mat[1][3] +
+		vec.z * mat.mat[2][3] + w * mat.mat[3][3];
+	if (!Math::NearZero(Math::Abs(transformedW)))
+	{
+		transformedW = 1.0f / transformedW;
+		retVal *= transformedW;
+	}
+	return retVal;
+}
+
+// Transform a Vector3 by a quaternion
+Vector3 Vector3::Transform(const Vector3& v, const Quaternion& q)
+{
+	// v + 2.0*cross(q.xyz, cross(q.xyz,v) + q.w*v);
+	Vector3 qv(q.x, q.y, q.z);
+	Vector3 retVal = v;
+	retVal += 2.0f * Vector3::Cross(qv, Vector3::Cross(qv, v) + q.w * v);
+	return retVal;
+}
+
+void Matrix4::Invert()
+{
+	// Thanks slow math
+	float tmp[12]; /* temp array for pairs */
+	float src[16]; /* array of transpose source matrix */
+	float dst[16]; /* storage */
+	float det; /* determinant */
+	/* transpose matrix */
+
+	// row 1 to col 1
+	src[0] = mat[0][0];
+	src[4] = mat[0][1];
+	src[8] = mat[0][2];
+	src[12] = mat[0][3];
+
+	// row 2 to col 2
+	src[1] = mat[1][0];
+	src[5] = mat[1][1];
+	src[9] = mat[1][2];
+	src[13] = mat[1][3];
+
+	// row 3 to col 3
+	src[2] = mat[2][0];
+	src[6] = mat[2][1];
+	src[10] = mat[2][2];
+	src[14] = mat[2][3];
+
+	// row 4 to col 4
+	src[3] = mat[3][0];
+	src[7] = mat[3][1];
+	src[11] = mat[3][2];
+	src[15] = mat[3][3];
+
+	// 	for (int i = 0; i < 4; i++) {
+	// 		src[i] = mat[i*4];
+	// 		src[i + 4] = mat[i*4 + 1];
+	// 		src[i + 8] = mat[i*4 + 2];
+	// 		src[i + 12] = mat[i*4 + 3];
+	// 	}
+	/* calculate pairs for first 8 elements (cofactors) */
+	tmp[0] = src[10] * src[15];
+	tmp[1] = src[11] * src[14];
+	tmp[2] = src[9] * src[15];
+	tmp[3] = src[11] * src[13];
+	tmp[4] = src[9] * src[14];
+	tmp[5] = src[10] * src[13];
+	tmp[6] = src[8] * src[15];
+	tmp[7] = src[11] * src[12];
+	tmp[8] = src[8] * src[14];
+	tmp[9] = src[10] * src[12];
+	tmp[10] = src[8] * src[13];
+	tmp[11] = src[9] * src[12];
+	/* calculate first 8 elements (cofactors) */
+	dst[0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7];
+	dst[0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7];
+	dst[1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7];
+	dst[1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7];
+	dst[2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7];
+	dst[2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7];
+	dst[3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6];
+	dst[3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6];
+	dst[4] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3];
+	dst[4] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3];
+	dst[5] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3];
+	dst[5] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3];
+	dst[6] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3];
+	dst[6] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3];
+	dst[7] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2];
+	dst[7] -= tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2];
+	/* calculate pairs for second 8 elements (cofactors) */
+	tmp[0] = src[2] * src[7];
+	tmp[1] = src[3] * src[6];
+	tmp[2] = src[1] * src[7];
+	tmp[3] = src[3] * src[5];
+	tmp[4] = src[1] * src[6];
+	tmp[5] = src[2] * src[5];
+	tmp[6] = src[0] * src[7];
+	tmp[7] = src[3] * src[4];
+	tmp[8] = src[0] * src[6];
+	tmp[9] = src[2] * src[4];
+	tmp[10] = src[0] * src[5];
+	tmp[11] = src[1] * src[4];
+	/* calculate second 8 elements (cofactors) */
+	dst[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15];
+	dst[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15];
+	dst[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15];
+	dst[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15];
+	dst[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15];
+	dst[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15];
+	dst[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14];
+	dst[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14];
+	dst[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9];
+	dst[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10];
+	dst[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10];
+	dst[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8];
+	dst[14] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8];
+	dst[14] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9];
+	dst[15] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9];
+	dst[15] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8];
+	/* calculate determinant */
+	det = src[0] * dst[0] + src[1] * dst[1] + src[2] * dst[2] + src[3] * dst[3];
+	/* calculate matrix inverse */
+	det = 1 / det;
+	for (int j = 0; j < 16; j++)
+		dst[j] *= det;
+
+	// Set it back
+	for (int i = 0; i < 4; i++)
+	{
+		for (int j = 0; j < 4; j++)
+		{
+			mat[i][j] = dst[i * 4 + j];
+		}
+	}
+}
+
+Matrix4 Matrix4::CreateFromQuaternion(const class Quaternion& q)
+{
+	float mat[4][4];
+	
+	mat[0][0] = 1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z;
+	mat[0][1] = 2.0f * q.x * q.y + 2.0f * q.w * q.z;
+	mat[0][2] = 2.0f * q.x * q.z - 2.0f * q.w * q.y;
+	mat[0][3] = 0.0f;
+
+	mat[1][0] = 2.0f * q.x * q.y - 2.0f * q.w * q.z;
+	mat[1][1] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z;
+	mat[1][2] = 2.0f * q.y * q.z + 2.0f * q.w * q.x;
+	mat[1][3] = 0.0f;
+
+	mat[2][0] = 2.0f * q.x * q.z + 2.0f * q.w * q.y;
+	mat[2][1] = 2.0f * q.y * q.z - 2.0f * q.w * q.x;
+	mat[2][2] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y;
+	mat[2][3] = 0.0f;
+
+	mat[3][0] = 0.0f;
+	mat[3][1] = 0.0f;
+	mat[3][2] = 0.0f;
+	mat[3][3] = 1.0f;
+
+	return Matrix4(mat);
+}

+ 1033 - 0
Chapter02/Math.h

@@ -0,0 +1,1033 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+
+#include <cmath>
+#include <memory.h>
+#include <limits>
+
+namespace Math
+{
+	const float Pi = 3.1415926535f;
+	const float TwoPi = Pi * 2.0f;
+	const float PiOver2 = Pi / 2.0f;
+	const float Infinity = std::numeric_limits<float>::infinity();
+	const float NegInfinity = -std::numeric_limits<float>::infinity();
+
+	inline float ToRadians(float degrees)
+	{
+		return degrees * Pi / 180.0f;
+	}
+
+	inline float ToDegrees(float radians)
+	{
+		return radians * 180.0f / Pi;
+	}
+
+	inline bool NearZero(float val, float epsilon = 0.001f)
+	{
+		if (fabs(val) <= epsilon)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	template <typename T>
+	T Max(const T& a, const T& b)
+	{
+		return (a < b ? b : a);
+	}
+
+	template <typename T>
+	T Min(const T& a, const T& b)
+	{
+		return (a < b ? a : b);
+	}
+
+	template <typename T>
+	T Clamp(const T& value, const T& lower, const T& upper)
+	{
+		return Min(upper, Max(lower, value));
+	}
+
+	inline float Abs(float value)
+	{
+		return fabs(value);
+	}
+
+	inline float Cos(float angle)
+	{
+		return cosf(angle);
+	}
+
+	inline float Sin(float angle)
+	{
+		return sinf(angle);
+	}
+
+	inline float Tan(float angle)
+	{
+		return tanf(angle);
+	}
+
+	inline float Acos(float value)
+	{
+		return acosf(value);
+	}
+	
+	inline float Atan2(float y, float x)
+	{
+		return atan2f(y, x);
+	}
+
+	inline float Cot(float angle)
+	{
+		return 1.0f / Tan(angle);
+	}
+
+	inline float Lerp(float a, float b, float f)
+	{
+		return a + f * (b - a);
+	}
+
+	inline float Sqrt(float value)
+	{
+		return sqrtf(value);
+	}
+	
+	inline float Fmod(float numer, float denom)
+	{
+		return fmod(numer, denom);
+	}
+}
+
+// 2D Vector
+class Vector2
+{
+public:
+	float x;
+	float y;
+
+	Vector2()
+		:x(0.0f)
+		,y(0.0f)
+	{}
+
+	explicit Vector2(float inX, float inY)
+		:x(inX)
+		,y(inY)
+	{}
+
+	// Set both components in one line
+	void Set(float inX, float inY)
+	{
+		x = inX;
+		y = inY;
+	}
+
+	// Vector addition (a + b)
+	friend Vector2 operator+(const Vector2& a, const Vector2& b)
+	{
+		return Vector2(a.x + b.x, a.y + b.y);
+	}
+
+	// Vector subtraction (a - b)
+	friend Vector2 operator-(const Vector2& a, const Vector2& b)
+	{
+		return Vector2(a.x - b.x, a.y - b.y);
+	}
+
+	// Component-wise multiplication
+	// (a.x * b.x, ...)
+	friend Vector2 operator*(const Vector2& a, const Vector2& b)
+	{
+		return Vector2(a.x * b.x, a.y * b.y);
+	}
+
+	// Scalar multiplication
+	friend Vector2 operator*(const Vector2& vec, float scalar)
+	{
+		return Vector2(vec.x * scalar, vec.y * scalar);
+	}
+
+	// Scalar multiplication
+	friend Vector2 operator*(float scalar, const Vector2& vec)
+	{
+		return Vector2(vec.x * scalar, vec.y * scalar);
+	}
+
+	// Scalar *=
+	Vector2& operator*=(float scalar)
+	{
+		x *= scalar;
+		y *= scalar;
+		return *this;
+	}
+
+	// Vector +=
+	Vector2& operator+=(const Vector2& right)
+	{
+		x += right.x;
+		y += right.y;
+		return *this;
+	}
+
+	// Vector -=
+	Vector2& operator-=(const Vector2& right)
+	{
+		x -= right.x;
+		y -= right.y;
+		return *this;
+	}
+
+	// Length squared of vector
+	float LengthSq() const
+	{
+		return (x*x + y*y);
+	}
+
+	// Length of vector
+	float Length() const
+	{
+		return (Math::Sqrt(LengthSq()));
+	}
+
+	// Normalize this vector
+	void Normalize()
+	{
+		float length = Length();
+		x /= length;
+		y /= length;
+	}
+
+	// Normalize the provided vector
+	static Vector2 Normalize(const Vector2& vec)
+	{
+		Vector2 temp = vec;
+		temp.Normalize();
+		return temp;
+	}
+
+	// Dot product between two vectors (a dot b)
+	static float Dot(const Vector2& a, const Vector2& b)
+	{
+		return (a.x * b.x + a.y * b.y);
+	}
+
+	// Lerp from A to B by f
+	static Vector2 Lerp(const Vector2& a, const Vector2& b, float f)
+	{
+		return Vector2(a + f * (b - a));
+	}
+	
+	// Reflect V about (normalized) N
+	static Vector2 Reflect(const Vector2& v, const Vector2& n)
+	{
+		return v - 2.0f * Vector2::Dot(v, n) * n;
+	}
+
+	// Transform vector by matrix
+	static Vector2 Transform(const Vector2& vec, const class Matrix3& mat, float w = 1.0f);
+
+	static const Vector2 Zero;
+	static const Vector2 UnitX;
+	static const Vector2 UnitY;
+	static const Vector2 NegUnitX;
+	static const Vector2 NegUnitY;
+};
+
+// 3D Vector
+class Vector3
+{
+public:
+	float x;
+	float y;
+	float z;
+
+	Vector3()
+		:x(0.0f)
+		,y(0.0f)
+		,z(0.0f)
+	{}
+
+	explicit Vector3(float inX, float inY, float inZ)
+		:x(inX)
+		,y(inY)
+		,z(inZ)
+	{}
+
+	// Cast to a const float pointer
+	const float* GetAsFloatPtr() const
+	{
+		return reinterpret_cast<const float*>(&x);
+	}
+
+	// Set all three components in one line
+	void Set(float inX, float inY, float inZ)
+	{
+		x = inX;
+		y = inY;
+		z = inZ;
+	}
+
+	// Vector addition (a + b)
+	friend Vector3 operator+(const Vector3& a, const Vector3& b)
+	{
+		return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
+	}
+
+	// Vector subtraction (a - b)
+	friend Vector3 operator-(const Vector3& a, const Vector3& b)
+	{
+		return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
+	}
+
+	// Component-wise multiplication
+	friend Vector3 operator*(const Vector3& left, const Vector3& right)
+	{
+		return Vector3(left.x * right.x, left.y * right.y, left.z * right.z);
+	}
+
+	// Scalar multiplication
+	friend Vector3 operator*(const Vector3& vec, float scalar)
+	{
+		return Vector3(vec.x * scalar, vec.y * scalar, vec.z * scalar);
+	}
+
+	// Scalar multiplication
+	friend Vector3 operator*(float scalar, const Vector3& vec)
+	{
+		return Vector3(vec.x * scalar, vec.y * scalar, vec.z * scalar);
+	}
+
+	// Scalar *=
+	Vector3& operator*=(float scalar)
+	{
+		x *= scalar;
+		y *= scalar;
+		z *= scalar;
+		return *this;
+	}
+
+	// Vector +=
+	Vector3& operator+=(const Vector3& right)
+	{
+		x += right.x;
+		y += right.y;
+		z += right.z;
+		return *this;
+	}
+
+	// Vector -=
+	Vector3& operator-=(const Vector3& right)
+	{
+		x -= right.x;
+		y -= right.y;
+		z -= right.z;
+		return *this;
+	}
+
+	// Length squared of vector
+	float LengthSq() const
+	{
+		return (x*x + y*y + z*z);
+	}
+
+	// Length of vector
+	float Length() const
+	{
+		return (Math::Sqrt(LengthSq()));
+	}
+
+	// Normalize this vector
+	void Normalize()
+	{
+		float length = Length();
+		x /= length;
+		y /= length;
+		z /= length;
+	}
+
+	// Normalize the provided vector
+	static Vector3 Normalize(const Vector3& vec)
+	{
+		Vector3 temp = vec;
+		temp.Normalize();
+		return temp;
+	}
+
+	// Dot product between two vectors (a dot b)
+	static float Dot(const Vector3& a, const Vector3& b)
+	{
+		return (a.x * b.x + a.y * b.y + a.z * b.z);
+	}
+
+	// Cross product between two vectors (a cross b)
+	static Vector3 Cross(const Vector3& a, const Vector3& b)
+	{
+		Vector3 temp;
+		temp.x = a.y * b.z - a.z * b.y;
+		temp.y = a.z * b.x - a.x * b.z;
+		temp.z = a.x * b.y - a.y * b.x;
+		return temp;
+	}
+
+	// Lerp from A to B by f
+	static Vector3 Lerp(const Vector3& a, const Vector3& b, float f)
+	{
+		return Vector3(a + f * (b - a));
+	}
+	
+	// Reflect V about (normalized) N
+	static Vector3 Reflect(const Vector3& v, const Vector3& n)
+	{
+		return v - 2.0f * Vector3::Dot(v, n) * n;
+	}
+
+	static Vector3 Transform(const Vector3& vec, const class Matrix4& mat, float w = 1.0f);
+	// This will transform the vector and renormalize the w component
+	static Vector3 TransformWithPerspDiv(const Vector3& vec, const class Matrix4& mat, float w = 1.0f);
+
+	// Transform a Vector3 by a quaternion
+	static Vector3 Transform(const Vector3& v, const class Quaternion& q);
+
+	static const Vector3 Zero;
+	static const Vector3 UnitX;
+	static const Vector3 UnitY;
+	static const Vector3 UnitZ;
+	static const Vector3 NegUnitX;
+	static const Vector3 NegUnitY;
+	static const Vector3 NegUnitZ;
+	static const Vector3 Infinity;
+	static const Vector3 NegInfinity;
+};
+
+// 3x3 Matrix
+class Matrix3
+{
+public:
+	float mat[3][3];
+
+	Matrix3()
+	{
+		*this = Matrix3::Identity;
+	}
+
+	explicit Matrix3(float inMat[3][3])
+	{
+		memcpy(mat, inMat, 9 * sizeof(float));
+	}
+
+	// Cast to a const float pointer
+	const float* GetAsFloatPtr() const
+	{
+		return reinterpret_cast<const float*>(&mat[0][0]);
+	}
+
+	// Matrix multiplication
+	friend Matrix3 operator*(const Matrix3& left, const Matrix3& right)
+	{
+		Matrix3 retVal;
+		// row 0
+		retVal.mat[0][0] = 
+			left.mat[0][0] * right.mat[0][0] +
+			left.mat[0][1] * right.mat[1][0] +
+			left.mat[0][2] * right.mat[2][0];
+
+		retVal.mat[0][1] = 
+			left.mat[0][0] * right.mat[0][1] +
+			left.mat[0][1] * right.mat[1][1] +
+			left.mat[0][2] * right.mat[2][1];
+
+		retVal.mat[0][2] = 
+			left.mat[0][0] * right.mat[0][2] +
+			left.mat[0][1] * right.mat[1][2] +
+			left.mat[0][2] * right.mat[2][2];
+		
+		// row 1
+		retVal.mat[1][0] = 
+			left.mat[1][0] * right.mat[0][0] +
+			left.mat[1][1] * right.mat[1][0] +
+			left.mat[1][2] * right.mat[2][0];
+
+		retVal.mat[1][1] = 
+			left.mat[1][0] * right.mat[0][1] +
+			left.mat[1][1] * right.mat[1][1] +
+			left.mat[1][2] * right.mat[2][1];
+
+		retVal.mat[1][2] = 
+			left.mat[1][0] * right.mat[0][2] +
+			left.mat[1][1] * right.mat[1][2] +
+			left.mat[1][2] * right.mat[2][2];
+		
+		// row 2
+		retVal.mat[2][0] = 
+			left.mat[2][0] * right.mat[0][0] +
+			left.mat[2][1] * right.mat[1][0] +
+			left.mat[2][2] * right.mat[2][0];
+
+		retVal.mat[2][1] =
+			left.mat[2][0] * right.mat[0][1] +
+			left.mat[2][1] * right.mat[1][1] +
+			left.mat[2][2] * right.mat[2][1];
+
+		retVal.mat[2][2] = 
+			left.mat[2][0] * right.mat[0][2] +
+			left.mat[2][1] * right.mat[1][2] +
+			left.mat[2][2] * right.mat[2][2];
+
+		return retVal;
+	}
+
+	Matrix3& operator*=(const Matrix3& right)
+	{
+		*this = *this * right;
+		return *this;
+	}
+
+	// Create a scale matrix with x and y scales
+	static Matrix3 CreateScale(float xScale, float yScale)
+	{
+		float temp[3][3] =
+		{
+			{ xScale, 0.0f, 0.0f },
+			{ 0.0f, yScale, 0.0f },
+			{ 0.0f, 0.0f, 1.0f },
+		};
+		return Matrix3(temp);
+	}
+
+	static Matrix3 CreateScale(const Vector2& scaleVector)
+	{
+		return CreateScale(scaleVector.x, scaleVector.y);
+	}
+
+	// Create a scale matrix with a uniform factor
+	static Matrix3 CreateScale(float scale)
+	{
+		return CreateScale(scale, scale);
+	}
+
+	// Create a rotation matrix about the Z axis
+	// theta is in radians
+	static Matrix3 CreateRotation(float theta)
+	{
+		float temp[3][3] =
+		{
+			{ Math::Cos(theta), Math::Sin(theta), 0.0f },
+			{ -Math::Sin(theta), Math::Cos(theta), 0.0f },
+			{ 0.0f, 0.0f, 1.0f },
+		};
+		return Matrix3(temp);
+	}
+
+	// Create a translation matrix (on the xy-plane)
+	static Matrix3 CreateTranslation(const Vector2& trans)
+	{
+		float temp[3][3] =
+		{
+			{ 1.0f, 0.0f, 0.0f },
+			{ 0.0f, 1.0f, 0.0f },
+			{ trans.x, trans.y, 1.0f },
+		};
+		return Matrix3(temp);
+	}
+
+	static const Matrix3 Identity;
+};
+
+// 4x4 Matrix
+class Matrix4
+{
+public:
+	float mat[4][4];
+
+	Matrix4()
+	{
+		*this = Matrix4::Identity;
+	}
+
+	explicit Matrix4(float inMat[4][4])
+	{
+		memcpy(mat, inMat, 16 * sizeof(float));
+	}
+
+	// Cast to a const float pointer
+	const float* GetAsFloatPtr() const
+	{
+		return reinterpret_cast<const float*>(&mat[0][0]);
+	}
+
+	// Matrix multiplication (a * b)
+	friend Matrix4 operator*(const Matrix4& a, const Matrix4& b)
+	{
+		Matrix4 retVal;
+		// row 0
+		retVal.mat[0][0] = 
+			a.mat[0][0] * b.mat[0][0] + 
+			a.mat[0][1] * b.mat[1][0] + 
+			a.mat[0][2] * b.mat[2][0] +
+			a.mat[0][3] * b.mat[3][0];
+
+		retVal.mat[0][1] = 
+			a.mat[0][0] * b.mat[0][1] + 
+			a.mat[0][1] * b.mat[1][1] + 
+			a.mat[0][2] * b.mat[2][1] + 
+			a.mat[0][3] * b.mat[3][1];
+
+		retVal.mat[0][2] = 
+			a.mat[0][0] * b.mat[0][2] + 
+			a.mat[0][1] * b.mat[1][2] + 
+			a.mat[0][2] * b.mat[2][2] + 
+			a.mat[0][3] * b.mat[3][2];
+		
+		retVal.mat[0][3] = 
+			a.mat[0][0] * b.mat[0][3] + 
+			a.mat[0][1] * b.mat[1][3] + 
+			a.mat[0][2] * b.mat[2][3] + 
+			a.mat[0][3] * b.mat[3][3];
+
+		// row 1
+		retVal.mat[1][0] = 
+			a.mat[1][0] * b.mat[0][0] + 
+			a.mat[1][1] * b.mat[1][0] + 
+			a.mat[1][2] * b.mat[2][0] + 
+			a.mat[1][3] * b.mat[3][0];
+
+		retVal.mat[1][1] = 
+			a.mat[1][0] * b.mat[0][1] + 
+			a.mat[1][1] * b.mat[1][1] + 
+			a.mat[1][2] * b.mat[2][1] + 
+			a.mat[1][3] * b.mat[3][1];
+
+		retVal.mat[1][2] = 
+			a.mat[1][0] * b.mat[0][2] + 
+			a.mat[1][1] * b.mat[1][2] + 
+			a.mat[1][2] * b.mat[2][2] + 
+			a.mat[1][3] * b.mat[3][2];
+
+		retVal.mat[1][3] = 
+			a.mat[1][0] * b.mat[0][3] +
+			a.mat[1][1] * b.mat[1][3] +
+			a.mat[1][2] * b.mat[2][3] +
+			a.mat[1][3] * b.mat[3][3];
+
+		// row 2
+		retVal.mat[2][0] = 
+			a.mat[2][0] * b.mat[0][0] +
+			a.mat[2][1] * b.mat[1][0] +
+			a.mat[2][2] * b.mat[2][0] +
+			a.mat[2][3] * b.mat[3][0];
+
+		retVal.mat[2][1] = 
+			a.mat[2][0] * b.mat[0][1] + 
+			a.mat[2][1] * b.mat[1][1] + 
+			a.mat[2][2] * b.mat[2][1] + 
+			a.mat[2][3] * b.mat[3][1];
+
+		retVal.mat[2][2] = 
+			a.mat[2][0] * b.mat[0][2] +
+			a.mat[2][1] * b.mat[1][2] + 
+			a.mat[2][2] * b.mat[2][2] + 
+			a.mat[2][3] * b.mat[3][2];
+
+		retVal.mat[2][3] = 
+			a.mat[2][0] * b.mat[0][3] + 
+			a.mat[2][1] * b.mat[1][3] + 
+			a.mat[2][2] * b.mat[2][3] + 
+			a.mat[2][3] * b.mat[3][3];
+
+		// row 3
+		retVal.mat[3][0] = 
+			a.mat[3][0] * b.mat[0][0] + 
+			a.mat[3][1] * b.mat[1][0] + 
+			a.mat[3][2] * b.mat[2][0] + 
+			a.mat[3][3] * b.mat[3][0];
+
+		retVal.mat[3][1] = 
+			a.mat[3][0] * b.mat[0][1] + 
+			a.mat[3][1] * b.mat[1][1] + 
+			a.mat[3][2] * b.mat[2][1] + 
+			a.mat[3][3] * b.mat[3][1];
+
+		retVal.mat[3][2] = 
+			a.mat[3][0] * b.mat[0][2] +
+			a.mat[3][1] * b.mat[1][2] +
+			a.mat[3][2] * b.mat[2][2] +
+			a.mat[3][3] * b.mat[3][2];
+
+		retVal.mat[3][3] = 
+			a.mat[3][0] * b.mat[0][3] +
+			a.mat[3][1] * b.mat[1][3] +
+			a.mat[3][2] * b.mat[2][3] +
+			a.mat[3][3] * b.mat[3][3];
+		
+		return retVal;
+	}
+
+	Matrix4& operator*=(const Matrix4& right)
+	{
+		*this = *this * right;
+		return *this;
+	}
+
+	// Invert the matrix - super slow
+	void Invert();
+
+	// Get the translation component of the matrix
+	Vector3 GetTranslation() const
+	{
+		return Vector3(mat[3][0], mat[3][1], mat[3][2]);
+	}
+	
+	// Get the X axis of the matrix (forward)
+	Vector3 GetXAxis() const
+	{
+		return Vector3::Normalize(Vector3(mat[0][0], mat[0][1], mat[0][2]));
+	}
+
+	// Get the Y axis of the matrix (left)
+	Vector3 GetYAxis() const
+	{
+		return Vector3::Normalize(Vector3(mat[1][0], mat[1][1], mat[1][2]));
+	}
+
+	// Get the Z axis of the matrix (up)
+	Vector3 GetZAxis() const
+	{
+		return Vector3::Normalize(Vector3(mat[2][0], mat[2][1], mat[2][2]));
+	}
+
+	// Extract the scale component from the matrix
+	Vector3 GetScale() const
+	{
+		Vector3 retVal;
+		retVal.x = Vector3(mat[0][0], mat[0][1], mat[0][2]).Length();
+		retVal.y = Vector3(mat[1][0], mat[1][1], mat[1][2]).Length();
+		retVal.z = Vector3(mat[2][0], mat[2][1], mat[2][2]).Length();
+		return retVal;
+	}
+
+	// Create a scale matrix with x, y, and z scales
+	static Matrix4 CreateScale(float xScale, float yScale, float zScale)
+	{
+		float temp[4][4] =
+		{
+			{ xScale, 0.0f, 0.0f, 0.0f },
+			{ 0.0f, yScale, 0.0f, 0.0f },
+			{ 0.0f, 0.0f, zScale, 0.0f },
+			{ 0.0f, 0.0f, 0.0f, 1.0f }
+		};
+		return Matrix4(temp);
+	}
+
+	static Matrix4 CreateScale(const Vector3& scaleVector)
+	{
+		return CreateScale(scaleVector.x, scaleVector.y, scaleVector.z);
+	}
+
+	// Create a scale matrix with a uniform factor
+	static Matrix4 CreateScale(float scale)
+	{
+		return CreateScale(scale, scale, scale);
+	}
+
+	// Rotation about x-axis
+	static Matrix4 CreateRotationX(float theta)
+	{
+		float temp[4][4] =
+		{
+			{ 1.0f, 0.0f, 0.0f , 0.0f },
+			{ 0.0f, Math::Cos(theta), Math::Sin(theta), 0.0f },
+			{ 0.0f, -Math::Sin(theta), Math::Cos(theta), 0.0f },
+			{ 0.0f, 0.0f, 0.0f, 1.0f },
+		};
+		return Matrix4(temp);
+	}
+
+	// Rotation about y-axis
+	static Matrix4 CreateRotationY(float theta)
+	{
+		float temp[4][4] =
+		{
+			{ Math::Cos(theta), 0.0f, -Math::Sin(theta), 0.0f },
+			{ 0.0f, 1.0f, 0.0f, 0.0f },
+			{ Math::Sin(theta), 0.0f, Math::Cos(theta), 0.0f },
+			{ 0.0f, 0.0f, 0.0f, 1.0f },
+		};
+		return Matrix4(temp);
+	}
+
+	// Rotation about z-axis
+	static Matrix4 CreateRotationZ(float theta)
+	{
+		float temp[4][4] =
+		{
+			{ Math::Cos(theta), Math::Sin(theta), 0.0f, 0.0f },
+			{ -Math::Sin(theta), Math::Cos(theta), 0.0f, 0.0f },
+			{ 0.0f, 0.0f, 1.0f, 0.0f },
+			{ 0.0f, 0.0f, 0.0f, 1.0f },
+		};
+		return Matrix4(temp);
+	}
+
+	// Create a rotation matrix from a quaternion
+	static Matrix4 CreateFromQuaternion(const class Quaternion& q);
+
+	static Matrix4 CreateTranslation(const Vector3& trans)
+	{
+		float temp[4][4] =
+		{
+			{ 1.0f, 0.0f, 0.0f, 0.0f },
+			{ 0.0f, 1.0f, 0.0f, 0.0f },
+			{ 0.0f, 0.0f, 1.0f, 0.0f },
+			{ trans.x, trans.y, trans.z, 1.0f }
+		};
+		return Matrix4(temp);
+	}
+
+	static Matrix4 CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up)
+	{
+		Vector3 zaxis = Vector3::Normalize(target - eye);
+		Vector3 xaxis = Vector3::Normalize(Vector3::Cross(up, zaxis));
+		Vector3 yaxis = Vector3::Normalize(Vector3::Cross(zaxis, xaxis));
+		Vector3 trans;
+		trans.x = -Vector3::Dot(xaxis, eye);
+		trans.y = -Vector3::Dot(yaxis, eye);
+		trans.z = -Vector3::Dot(zaxis, eye);
+
+		float temp[4][4] =
+		{
+			{ xaxis.x, yaxis.x, zaxis.x, 0.0f },
+			{ xaxis.y, yaxis.y, zaxis.y, 0.0f },
+			{ xaxis.z, yaxis.z, zaxis.z, 0.0f },
+			{ trans.x, trans.y, trans.z, 1.0f }
+		};
+		return Matrix4(temp);
+	}
+
+	static Matrix4 CreateOrtho(float width, float height, float near, float far)
+	{
+		float temp[4][4] =
+		{
+			{ 2.0f / width, 0.0f, 0.0f, 0.0f },
+			{ 0.0f, 2.0f / height, 0.0f, 0.0f },
+			{ 0.0f, 0.0f, 1.0f / (far - near), 0.0f },
+			{ 0.0f, 0.0f, near / (near - far), 1.0f }
+		};
+		return Matrix4(temp);
+	}
+
+	static Matrix4 CreatePerspectiveFOV(float fovY, float width, float height, float near, float far)
+	{
+		float yScale = Math::Cot(fovY / 2.0f);
+		float xScale = yScale * height / width;
+		float temp[4][4] =
+		{
+			{ xScale, 0.0f, 0.0f, 0.0f },
+			{ 0.0f, yScale, 0.0f, 0.0f },
+			{ 0.0f, 0.0f, far / (far - near), 1.0f },
+			{ 0.0f, 0.0f, -near * far / (far - near), 0.0f }
+		};
+		return Matrix4(temp);
+	}
+
+	// Create "Simple" View-Projection Matrix from Chapter 6
+	static Matrix4 CreateSimpleViewProj(float width, float height)
+	{
+		float temp[4][4] =
+		{
+			{ 2.0f/width, 0.0f, 0.0f, 0.0f },
+			{ 0.0f, 2.0f/height, 0.0f, 0.0f },
+			{ 0.0f, 0.0f, 1.0f, 0.0f },
+			{ 0.0f, 0.0f, 1.0f, 1.0f }
+		};
+		return Matrix4(temp);
+	}
+	
+	static const Matrix4 Identity;
+};
+
+// (Unit) Quaternion
+class Quaternion
+{
+public:
+	float x;
+	float y;
+	float z;
+	float w;
+
+	Quaternion()
+	{
+		*this = Quaternion::Identity;
+	}
+
+	// This directly sets the quaternion components --
+	// don't use for axis/angle
+	explicit Quaternion(float inX, float inY, float inZ, float inW)
+	{
+		Set(inX, inY, inZ, inW);
+	}
+
+	// Construct the quaternion from an axis and angle
+	// It is assumed that axis is already normalized,
+	// and the angle is in radians
+	explicit Quaternion(const Vector3& axis, float angle)
+	{
+		float scalar = Math::Sin(angle / 2.0f);
+		x = axis.x * scalar;
+		y = axis.y * scalar;
+		z = axis.z * scalar;
+		w = Math::Cos(angle / 2.0f);
+	}
+
+	// Directly set the internal components
+	void Set(float inX, float inY, float inZ, float inW)
+	{
+		x = inX;
+		y = inY;
+		z = inZ;
+		w = inW;
+	}
+
+	void Conjugate()
+	{
+		x *= -1.0f;
+		y *= -1.0f;
+		z *= -1.0f;
+	}
+
+	float LengthSq() const
+	{
+		return (x*x + y*y + z*z + w*w);
+	}
+
+	float Length() const
+	{
+		return Math::Sqrt(LengthSq());
+	}
+
+	void Normalize()
+	{
+		float length = Length();
+		x /= length;
+		y /= length;
+		z /= length;
+		w /= length;
+	}
+
+	// Normalize the provided quaternion
+	static Quaternion Normalize(const Quaternion& q)
+	{
+		Quaternion retVal = q;
+		retVal.Normalize();
+		return retVal;
+	}
+
+	// Linear interpolation
+	static Quaternion Lerp(const Quaternion& a, const Quaternion& b, float f)
+	{
+		Quaternion retVal;
+		retVal.x = Math::Lerp(a.x, b.x, f);
+		retVal.y = Math::Lerp(a.y, b.y, f);
+		retVal.z = Math::Lerp(a.z, b.z, f);
+		retVal.w = Math::Lerp(a.w, b.w, f);
+		retVal.Normalize();
+		return retVal;
+	}
+
+	static float Dot(const Quaternion& a, const Quaternion& b)
+	{
+		return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
+	}
+
+	// Spherical Linear Interpolation
+	static Quaternion Slerp(const Quaternion& a, const Quaternion& b, float f)
+	{
+		float rawCosm = Quaternion::Dot(a, b);
+
+		float cosom = -rawCosm;
+		if (rawCosm >= 0.0f)
+		{
+			cosom = rawCosm;
+		}
+
+		float scale0, scale1;
+
+		if (cosom < 0.9999f)
+		{
+			const float omega = Math::Acos(cosom);
+			const float invSin = 1.f / Math::Sin(omega);
+			scale0 = Math::Sin((1.f - f) * omega) * invSin;
+			scale1 = Math::Sin(f * omega) * invSin;
+		}
+		else
+		{
+			// Use linear interpolation if the quaternions
+			// are collinear
+			scale0 = 1.0f - f;
+			scale1 = f;
+		}
+
+		if (rawCosm < 0.0f)
+		{
+			scale1 = -scale1;
+		}
+
+		Quaternion retVal;
+		retVal.x = scale0 * a.x + scale1 * b.x;
+		retVal.y = scale0 * a.y + scale1 * b.y;
+		retVal.z = scale0 * a.z + scale1 * b.z;
+		retVal.w = scale0 * a.w + scale1 * b.w;
+		retVal.Normalize();
+		return retVal;
+	}
+
+	// Concatenate
+	// Rotate by q FOLLOWED BY p
+	static Quaternion Concatenate(const Quaternion& q, const Quaternion& p)
+	{
+		Quaternion retVal;
+
+		// Vector component is:
+		// ps * qv + qs * pv + pv x qv
+		Vector3 qv(q.x, q.y, q.z);
+		Vector3 pv(p.x, p.y, p.z);
+		Vector3 newVec = p.w * qv + q.w * pv + Vector3::Cross(pv, qv);
+		retVal.x = newVec.x;
+		retVal.y = newVec.y;
+		retVal.z = newVec.z;
+
+		// Scalar component is:
+		// ps * qs - pv . qv
+		retVal.w = p.w * q.w - Vector3::Dot(pv, qv);
+
+		return retVal;
+	}
+
+	static const Quaternion Identity;
+};
+
+namespace Color
+{
+	static const Vector3 Black(0.0f, 0.0f, 0.0f);
+	static const Vector3 White(1.0f, 1.0f, 1.0f);
+	static const Vector3 Red(1.0f, 0.0f, 0.0f);
+	static const Vector3 Green(0.0f, 1.0f, 0.0f);
+	static const Vector3 Blue(0.0f, 0.0f, 1.0f);
+	static const Vector3 Yellow(1.0f, 1.0f, 0.0f);
+	static const Vector3 LightYellow(1.0f, 1.0f, 0.88f);
+	static const Vector3 LightBlue(0.68f, 0.85f, 0.9f);
+	static const Vector3 LightPink(1.0f, 0.71f, 0.76f);
+	static const Vector3 LightGreen(0.56f, 0.93f, 0.56f);
+}

+ 78 - 0
Chapter02/Ship.cpp

@@ -0,0 +1,78 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "Ship.h"
+#include "AnimSpriteComponent.h"
+#include "Game.h"
+
+Ship::Ship(Game* game)
+	:Actor(game)
+	,mRightSpeed(0.0f)
+	,mDownSpeed(0.0f)
+{
+	// Create an animated sprite component
+	AnimSpriteComponent* asc = new AnimSpriteComponent(this);
+	std::vector<SDL_Texture*> anims = {
+		game->GetTexture("Assets/Ship01.png"),
+		game->GetTexture("Assets/Ship02.png"),
+		game->GetTexture("Assets/Ship03.png"),
+		game->GetTexture("Assets/Ship04.png"),
+	};
+	asc->SetAnimTextures(anims);
+}
+
+void Ship::UpdateActor(float deltaTime)
+{
+	Actor::UpdateActor(deltaTime);
+	// Update position based on speeds and delta time
+	Vector2 pos = GetPosition();
+	pos.x += mRightSpeed * deltaTime;
+	pos.y += mDownSpeed * deltaTime;
+	// Restrict position to left half of screen
+	if (pos.x < 25.0f)
+	{
+		pos.x = 25.0f;
+	}
+	else if (pos.x > 500.0f)
+	{
+		pos.x = 500.0f;
+	}
+	if (pos.y < 25.0f)
+	{
+		pos.y = 25.0f;
+	}
+	else if (pos.y > 743.0f)
+	{
+		pos.y = 743.0f;
+	}
+	SetPosition(pos);
+}
+
+void Ship::ProcessKeyboard(const uint8_t* state)
+{
+	mRightSpeed = 0.0f;
+	mDownSpeed = 0.0f;
+	// right/left
+	if (state[SDL_SCANCODE_D])
+	{
+		mRightSpeed += 250.0f;
+	}
+	if (state[SDL_SCANCODE_A])
+	{
+		mRightSpeed -= 250.0f;
+	}
+	// up/down
+	if (state[SDL_SCANCODE_S])
+	{
+		mDownSpeed += 300.0f;
+	}
+	if (state[SDL_SCANCODE_W])
+	{
+		mDownSpeed -= 300.0f;
+	}
+}

+ 22 - 0
Chapter02/Ship.h

@@ -0,0 +1,22 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include "Actor.h"
+class Ship : public Actor
+{
+public:
+	Ship(class Game* game);
+	void UpdateActor(float deltaTime) override;
+	void ProcessKeyboard(const uint8_t* state);
+	float GetRightSpeed() const { return mRightSpeed; }
+	float GetDownSpeed() const { return mDownSpeed; }
+private:
+	float mRightSpeed;
+	float mDownSpeed;
+};

+ 56 - 0
Chapter02/SpriteComponent.cpp

@@ -0,0 +1,56 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#include "SpriteComponent.h"
+#include "Actor.h"
+#include "Game.h"
+
+SpriteComponent::SpriteComponent(Actor* owner, int drawOrder)
+	:Component(owner)
+	,mTexture(nullptr)
+	,mDrawOrder(drawOrder)
+	,mTexWidth(0)
+	,mTexHeight(0)
+{
+	mOwner->GetGame()->AddSprite(this);
+}
+
+SpriteComponent::~SpriteComponent()
+{
+	mOwner->GetGame()->RemoveSprite(this);
+}
+
+void SpriteComponent::Draw(SDL_Renderer* renderer)
+{
+	if (mTexture)
+	{
+		SDL_Rect r;
+		// Scale the width/height by owner's scale
+		r.w = static_cast<int>(mTexWidth * mOwner->GetScale());
+		r.h = static_cast<int>(mTexHeight * mOwner->GetScale());
+		// Center the rectangle around the position of the owner
+		r.x = static_cast<int>(mOwner->GetPosition().x - r.w / 2);
+		r.y = static_cast<int>(mOwner->GetPosition().y - r.h / 2);
+
+		// Draw (have to convert angle from radians to degrees, and clockwise to counter)
+		SDL_RenderCopyEx(renderer,
+			mTexture,
+			nullptr,
+			&r,
+			-Math::ToDegrees(mOwner->GetRotation()),
+			nullptr,
+			SDL_FLIP_NONE);
+	}
+}
+
+void SpriteComponent::SetTexture(SDL_Texture* texture)
+{
+	mTexture = texture;
+	// Set width/height
+	SDL_QueryTexture(texture, nullptr, nullptr, &mTexWidth, &mTexHeight);
+}

+ 30 - 0
Chapter02/SpriteComponent.h

@@ -0,0 +1,30 @@
+// ----------------------------------------------------------------
+// From Game Programming in C++ by Sanjay Madhav
+// Copyright (C) 2017 Sanjay Madhav. All rights reserved.
+// 
+// Released under the BSD License
+// See LICENSE.txt for full details.
+// ----------------------------------------------------------------
+
+#pragma once
+#include "Component.h"
+#include "SDL/SDL.h"
+class SpriteComponent : public Component
+{
+public:
+	// (Lower draw order corresponds with further back)
+	SpriteComponent(class Actor* owner, int drawOrder = 100);
+	~SpriteComponent();
+
+	virtual void Draw(SDL_Renderer* renderer);
+	virtual void SetTexture(SDL_Texture* texture);
+
+	int GetDrawOrder() const { return mDrawOrder; }
+	int GetTexHeight() const { return mTexHeight; }
+	int GetTexWidth() const { return mTexWidth; }
+protected:
+	SDL_Texture* mTexture;
+	int mDrawOrder;
+	int mTexWidth;
+	int mTexHeight;
+};