浏览代码

chore: update to use better practices for inclusion/deployment

Sam Jaffe 1 年之前
父节点
当前提交
b6072c3bce
共有 49 个文件被更改,包括 565 次插入337 次删除
  1. 3 3
      .gitmodules
  2. 6 4
      engine/engine.xcodeproj/project.pbxproj
  3. 0 63
      engine/engine.xcodeproj/xcshareddata/xcschemes/engine-test.xcscheme
  4. 3 3
      engine/include/game/engine/events.hpp
  5. 6 6
      engine/include/game/engine/game_dispatch.hpp
  6. 5 5
      engine/include/game/engine/scene.hpp
  7. 3 3
      engine/include/game/engine/text_engine.hpp
  8. 2 1
      engine/src/KeyBindingView.mm
  9. 5 4
      engine/src/game_dispatch.cpp
  10. 5 5
      engine/src/serial.cxx
  11. 2 2
      engine/test/entity_test.cxx
  12. 6 6
      engine/test/fps_counter_test.cxx
  13. 5 5
      engine/test/game_dispatch_test.cxx
  14. 6 6
      engine/test/mock_renderer.h
  15. 4 6
      engine/test/scene_test.cxx
  16. 4 4
      engine/test/serial_test.cxx
  17. 6 6
      engine/test/text_engine_test.cxx
  18. 1 1
      external/matrix
  19. 1 0
      external/stb
  20. 1 1
      external/vector
  21. 60 2
      graphics/graphics.xcodeproj/project.pbxproj
  22. 0 63
      graphics/graphics.xcodeproj/xcshareddata/xcschemes/graphics-test.xcscheme
  23. 5 4
      graphics/include/game/graphics/material.hpp
  24. 4 3
      graphics/include/game/graphics/object.hpp
  25. 5 4
      graphics/include/game/graphics/renderer.hpp
  26. 3 3
      graphics/include/game/graphics/texture.hpp
  27. 2 2
      graphics/include/game/graphics/vertex.h
  28. 3 2
      graphics/src/helper.hpp
  29. 2 2
      graphics/src/matrix.cxx
  30. 1 1
      graphics/src/matrix.hpp
  31. 6 6
      graphics/src/openGL/opengl_manager.cxx
  32. 5 4
      graphics/src/openGL/opengl_renderer.cxx
  33. 5 4
      graphics/src/openGL/opengl_renderer.h
  34. 5 2
      graphics/src/renderer.cxx
  35. 3 3
      graphics/src/renderer_impl.hpp
  36. 1 1
      graphics/src/texture.cpp
  37. 4 4
      graphics/test/manager_test.cxx
  38. 6 4
      graphics/test/renderer_test.cxx
  39. 1 1
      math/include/game/math/common.hpp
  40. 2 2
      math/include/game/math/shape.hpp
  41. 99 18
      math/math.xcodeproj/project.pbxproj
  42. 0 63
      math/math.xcodeproj/xcshareddata/xcschemes/math-test.xcscheme
  43. 175 2
      util/gameutils.xcodeproj/project.pbxproj
  44. 1 1
      util/include/game/util/env.hpp
  45. 1 1
      util/src/files.cxx
  46. 1 1
      util/src/osx_env.mm
  47. 9 0
      util/src/smart_map.hpp
  48. 9 0
      util/src/state_machine.cxx
  49. 73 0
      util/src/state_machine.h

+ 3 - 3
.gitmodules

@@ -1,6 +1,3 @@
-[submodule "include/stb"]
-	path = include/stb
-	url = https://github.com/nothings/stb.git
 [submodule "include/expect"]
 	path = external/expect
 	url = freenas:utility/expect
@@ -17,3 +14,6 @@
 [submodule "include/resource_factory"]
 	path = external/resource_factory
 	url = freenas:utility/resource_factory.git
+[submodule "external/stb"]
+	path = external/stb
+	url = https://github.com/nothings/stb.git

+ 6 - 4
engine/engine.xcodeproj/project.pbxproj

@@ -28,6 +28,7 @@
 		CD9F1BA42B74428E0035EDF5 /* KeyBindingView.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD9F1BA32B74428E0035EDF5 /* KeyBindingView.mm */; };
 		CD9F1BAA2B7446A80035EDF5 /* libjsoncpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9F1BA92B7446A80035EDF5 /* libjsoncpp.a */; };
 		CD9F1BB02B7447080035EDF5 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9F1BAF2B7447080035EDF5 /* Cocoa.framework */; };
+		CDAE63252B77C52F00551FB8 /* libjsoncpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CD9F1BA92B7446A80035EDF5 /* libjsoncpp.a */; };
 		CDB1F8C81D7A312B00700C6B /* game_dispatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB1F8C61D7A312B00700C6B /* game_dispatch.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CDB1F8CC1D7A319A00700C6B /* scene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB1F8CA1D7A319A00700C6B /* scene.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CDB1F8D21D7A32A300700C6B /* events.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CDB1F8D01D7A32A300700C6B /* events.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
@@ -195,6 +196,7 @@
 				CD8064EF22D21EB500B9B4E4 /* libgraphics.dylib in Frameworks */,
 				CD62FCD622904A9B00376440 /* GoogleMock.framework in Frameworks */,
 				CD62FCCE22904A8900376440 /* libengine.dylib in Frameworks */,
+				CDAE63252B77C52F00551FB8 /* libjsoncpp.a in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -747,8 +749,8 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
-				SYSTEM_HEADER_SEARCH_PATHS = /opt/local/include/;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include $(PROJECT_DIR)/../ $(PROJECT_DIR)/../graphics/include/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../util/include/ $(PROJECT_DIR)/../math/";
+				SYSTEM_HEADER_SEARCH_PATHS = "/opt/local/include $(TARGET_BUILD_DIR)/usr/local/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Debug;
 		};
@@ -795,8 +797,8 @@
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-				SYSTEM_HEADER_SEARCH_PATHS = /opt/local/include/;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include $(PROJECT_DIR)/../ $(PROJECT_DIR)/../graphics/include/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../util/include/ $(PROJECT_DIR)/../math/";
+				SYSTEM_HEADER_SEARCH_PATHS = "/opt/local/include $(TARGET_BUILD_DIR)/usr/local/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Release;
 		};

+ 0 - 63
engine/engine.xcodeproj/xcshareddata/xcschemes/engine-test.xcscheme

@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1240"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES"
-      onlyGenerateCoverageForSpecifiedTargets = "YES">
-      <CodeCoverageTargets>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "CDB1F8AD1D7A30CD00700C6B"
-            BuildableName = "libengine.dylib"
-            BlueprintName = "engine"
-            ReferencedContainer = "container:engine.xcodeproj">
-         </BuildableReference>
-      </CodeCoverageTargets>
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "CD62FCC822904A8900376440"
-               BuildableName = "engine-test.xctest"
-               BlueprintName = "engine-test"
-               ReferencedContainer = "container:engine.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 3 - 3
engine/include/game/engine/events.hpp

@@ -7,10 +7,10 @@
 
 #pragma once
 
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
+#include <game/math/math_fwd.hpp>
+#include <math/vector/vector.hpp>
 
-#include "engine_fwd.hpp"
+#include "game/engine/engine_fwd.hpp"
 
 namespace engine::keys {
 enum default_keys : key_enum_t { QUIT = 'q' };

+ 6 - 6
engine/include/game/engine/game_dispatch.hpp

@@ -11,13 +11,13 @@
 #include <memory>
 #include <unordered_map>
 
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
+#include <game/graphics/graphics_fwd.h>
+#include <game/math/math_fwd.hpp>
+#include <game/util/time.hpp>
+#include <math/vector/vector.hpp>
 
-#include "engine_fwd.hpp"
-#include "events.hpp"
-#include "game/graphics/graphics_fwd.h"
-#include "game/util/time.hpp"
+#include "game/engine/engine_fwd.hpp"
+#include "game/engine/events.hpp"
 
 namespace engine {
 class game_dispatch {

+ 5 - 5
engine/include/game/engine/scene.hpp

@@ -11,12 +11,12 @@
 #include <unordered_map>
 #include <vector>
 
-#include "game/graphics/graphics_fwd.h"
-#include "game/math/math_fwd.hpp"
-#include "game/util/identity.hpp"
-#include "vector/vector.hpp"
+#include <game/graphics/graphics_fwd.h>
+#include <game/math/math_fwd.hpp>
+#include <game/util/identity.hpp>
+#include <math/vector/vector.hpp>
 
-#include "engine_fwd.hpp"
+#include "game/engine/engine_fwd.hpp"
 
 namespace engine {
 class scene : public identity<scene, std::string> {

+ 3 - 3
engine/include/game/engine/text_engine.hpp

@@ -12,9 +12,9 @@
 #include <string>
 #include <unordered_map>
 
-#include "game/graphics/object.hpp"
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
+#include <game/graphics/object.hpp>
+#include <game/math/math_fwd.hpp>
+#include <math/vector/vector.hpp>
 
 namespace engine {
 class text_engine {

+ 2 - 1
engine/src/KeyBindingView.mm

@@ -10,9 +10,10 @@
 
 #include <array>
 
+#include <math/vector/vector.hpp>
+
 #include "game/engine/events.hpp"
 #include "game/engine/game_dispatch.hpp"
-#include "vector/vector.hpp"
 
 static math::vec2 cast(NSPoint point) {
   return {{static_cast<float>(point.x), static_cast<float>(point.y)}};

+ 5 - 4
engine/src/game_dispatch.cpp

@@ -9,14 +9,15 @@
 
 #include "game/engine/game_dispatch.hpp"
 
+#include <game/graphics/object.hpp>
+#include <game/graphics/renderer.hpp>
+#include <game/util/env.hpp>
+#include <math/matrix/matrix_helpers.hpp>
+
 #include "game/engine/events.hpp"
 #include "game/engine/fps_counter.hpp"
 #include "game/engine/scene.hpp"
 #include "game/engine/text_engine.hpp"
-#include "game/graphics/object.hpp"
-#include "game/graphics/renderer.hpp"
-#include "game/util/env.hpp"
-#include "matrix/matrix_helpers.hpp"
 
 namespace engine {
 namespace {

+ 5 - 5
engine/src/serial.cxx

@@ -12,11 +12,11 @@
 #include <json/json.h>
 #include <json/reader.h>
 
-#include "game/graphics/manager.hpp"
-#include "game/graphics/material.hpp"
-#include "game/graphics/object.hpp"
-#include "game/util/identity.hpp"
-#include "vector/vector.hpp"
+#include <game/graphics/manager.hpp>
+#include <game/graphics/material.hpp>
+#include <game/graphics/object.hpp>
+#include <game/util/identity.hpp>
+#include <math/vector/vector.hpp>
 
 namespace engine {
 Json::Value read_file(std::string const & abs_path) {

+ 2 - 2
engine/test/entity_test.cxx

@@ -6,13 +6,13 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
+#include "game/engine/entity.hpp"
+
 #include <sstream>
 
 #include <gmock/gmock.h>
 #include <json/json.h>
 
-#include "game/engine/entity.hpp"
-
 #include "mock_renderer.h"
 
 using namespace engine;

+ 6 - 6
engine/test/fps_counter_test.cxx

@@ -6,17 +6,17 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
+#include "game/engine/fps_counter.hpp"
+
 #include <gmock/gmock.h>
 
-#include "game/engine/fps_counter.hpp"
 #include "game/engine/text_engine.hpp"
-
 #include "mock_renderer.h"
 
 #ifdef __APPLE__
-namespace env { namespace detail {
-  extern void bundle(std::string const &);
-}}
+namespace env::osx {
+extern void bundle(std::string const &);
+}
 #endif
 
 using testing::IsEmpty;
@@ -31,7 +31,7 @@ struct FpsCounterTest : testing::Test {
 
 void FpsCounterTest::SetUp() {
 #ifdef __APPLE__
-  env::detail::bundle("leumasjaffe.engine-test");
+  env::osx::bundle("leumasjaffe.engine-test");
 #endif
   manager.reset(new stub_manager_impl);
   engine.reset(new engine::text_engine("font", manager));

+ 5 - 5
engine/test/game_dispatch_test.cxx

@@ -6,18 +6,18 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
+#include "game/engine/game_dispatch.hpp"
+
 #include <memory>
 
 #include <gmock/gmock.h>
 
-#include "math/vector/vector.hpp"
+#include <game/graphics/renderer.hpp>
+#include <game/util/env.hpp>
+#include <math/vector/vector.hpp>
 
 #include "game/engine/events.hpp"
-#include "game/engine/game_dispatch.hpp"
 #include "game/engine/scene.hpp"
-#include "game/graphics/renderer.hpp"
-#include "game/util/env.hpp"
-
 #include "mock_renderer.h"
 
 struct mock_scene : engine::scene {

+ 6 - 6
engine/test/mock_renderer.h

@@ -8,12 +8,12 @@
 
 #pragma once
 
-#include "game/graphics/manager.hpp"
-#include "game/graphics/renderer.hpp"
-#include "game/graphics/shader.hpp"
-#include "game/graphics/shader_program.hpp"
-#include "game/graphics/texture.hpp"
-#include "game/util/identity.hpp"
+#include <game/graphics/manager.hpp>
+#include <game/graphics/renderer.hpp>
+#include <game/graphics/shader.hpp>
+#include <game/graphics/shader_program.hpp>
+#include <game/graphics/texture.hpp>
+#include <game/util/identity.hpp>
 
 template <typename T> inline identity<T> cast(unsigned int id) {
   return *reinterpret_cast<identity<T> *>(&id);

+ 4 - 6
engine/test/scene_test.cxx

@@ -6,18 +6,16 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
+#include "game/engine/scene.hpp"
+
 #include <gmock/gmock.h>
 
+#include <game/util/env.hpp>
+
 #include "game/engine/entity.hpp"
 #include "game/engine/game_dispatch.hpp"
-#include "game/engine/scene.hpp"
-
 #include "mock_renderer.h"
 
-namespace env {
-void resize_screen(math::vec2i const & size);
-}
-
 struct test_scene : engine::scene {
   using engine::scene::scene;
 

+ 4 - 4
engine/test/serial_test.cxx

@@ -5,17 +5,17 @@
 //  Created by Sam Jaffe on 6/2/19.
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
+#include "game/engine/serial.hpp"
 
 #include <sstream>
 
-#include "mock_renderer.h"
 #include <gmock/gmock.h>
-
 #include <json/json.h>
 #include <json/reader.h>
 
-#include "game/engine/serial.hpp"
-#include "game/graphics/object.hpp"
+#include <game/graphics/object.hpp>
+
+#include "mock_renderer.h"
 
 Json::Value to_json(std::string const & str) {
   Json::Value json;

+ 6 - 6
engine/test/text_engine_test.cxx

@@ -6,16 +6,16 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
-#include <gmock/gmock.h>
-
 #include "game/engine/text_engine.hpp"
 
+#include <gmock/gmock.h>
+
 #include "mock_renderer.h"
 
 #ifdef __APPLE__
-namespace env { namespace detail {
-  extern void bundle(std::string const &);
-}}
+namespace env::osx {
+extern void bundle(std::string const &);
+}
 #endif
 
 using testing::Eq;
@@ -30,7 +30,7 @@ struct TextEngineTest : testing::Test {
 
 void TextEngineTest::SetUp() {
 #ifdef __APPLE__
-  env::detail::bundle("leumasjaffe.engine-test");
+  env::osx::bundle("leumasjaffe.engine-test");
 #endif
   manager.reset(new stub_manager_impl);
 }

+ 1 - 1
external/matrix

@@ -1 +1 @@
-Subproject commit f3514497bf996324beebe0571a0178618d743241
+Subproject commit a41327180c0e3aeffc40f2a8d969c42ff219f6af

+ 1 - 0
external/stb

@@ -0,0 +1 @@
+Subproject commit b7cf1246284b49dfe7f1288e6f739b7a3a9d966b

+ 1 - 1
external/vector

@@ -1 +1 @@
-Subproject commit 919be447d9bcb0c08d2460e5b04950e55de9d1b3
+Subproject commit 232f64be05a0584b5888d60f5628254ff6bb5b80

+ 60 - 2
graphics/graphics.xcodeproj/project.pbxproj

@@ -110,6 +110,27 @@
 			remoteGlobalIDString = CD3786171CF9F61100BE89B2;
 			remoteInfo = math;
 		};
+		CDAE630D2B77C13E00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CD0C59D120C412AD00454F82;
+			remoteInfo = "matrix-test";
+		};
+		CDAE630F2B77C13E00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDAE62392B77B88A00551FB8;
+			remoteInfo = matrix;
+		};
+		CDAE63112B77C14500551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CDAE62382B77B88A00551FB8;
+			remoteInfo = matrix;
+		};
 		CDED9C1A22A2D6CE00AE5CE5 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = CD3AC6DA1D2C0364002B4BB0 /* Project object */;
@@ -166,6 +187,7 @@
 		CD9F1BD72B7469600035EDF5 /* math.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = math.xcodeproj; path = ../math/math.xcodeproj; sourceTree = "<group>"; };
 		CDA34D86225171AA008036A7 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = include/game; sourceTree = "<group>"; };
 		CDA34D9922517A3D008036A7 /* libmath.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libmath.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+		CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = matrix.xcodeproj; path = ../external/matrix/matrix.xcodeproj; sourceTree = "<group>"; };
 		CDED9C1422A2D6CD00AE5CE5 /* graphics-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "graphics-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
 		CDED9C1822A2D6CE00AE5CE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		CDED9C4222A2FACB00AE5CE5 /* renderer_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = renderer_test.cxx; sourceTree = "<group>"; };
@@ -225,6 +247,7 @@
 			children = (
 				CD9F1BCC2B7469540035EDF5 /* gameutils.xcodeproj */,
 				CD9F1BD72B7469600035EDF5 /* math.xcodeproj */,
+				CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */,
 				CD62FCD722904AD100376440 /* GoogleMock.xcodeproj */,
 				CDA34D86225171AA008036A7 /* game */,
 				CD3AC6E41D2C0364002B4BB0 /* src */,
@@ -318,6 +341,15 @@
 			name = Frameworks;
 			sourceTree = "<group>";
 		};
+		CDAE63052B77C13E00551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE630E2B77C13E00551FB8 /* matrix-test.xctest */,
+				CDAE63102B77C13E00551FB8 /* libmatrix.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
 		CDED9C1522A2D6CE00AE5CE5 /* graphics-test */ = {
 			isa = PBXGroup;
 			children = (
@@ -371,6 +403,7 @@
 			buildRules = (
 			);
 			dependencies = (
+				CDAE63122B77C14500551FB8 /* PBXTargetDependency */,
 				CD9F1BE12B7469640035EDF5 /* PBXTargetDependency */,
 				CD9F1BD62B74695C0035EDF5 /* PBXTargetDependency */,
 			);
@@ -463,6 +496,10 @@
 					ProductGroup = CD9F1BD82B7469600035EDF5 /* Products */;
 					ProjectRef = CD9F1BD72B7469600035EDF5 /* math.xcodeproj */;
 				},
+				{
+					ProductGroup = CDAE63052B77C13E00551FB8 /* Products */;
+					ProjectRef = CDAE63042B77C13E00551FB8 /* matrix.xcodeproj */;
+				},
 			);
 			projectRoot = "";
 			targets = (
@@ -523,6 +560,20 @@
 			remoteRef = CD9F1BDE2B7469600035EDF5 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
+		CDAE630E2B77C13E00551FB8 /* matrix-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "matrix-test.xctest";
+			remoteRef = CDAE630D2B77C13E00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE63102B77C13E00551FB8 /* libmatrix.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libmatrix.a;
+			remoteRef = CDAE630F2B77C13E00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 /* End PBXReferenceProxy section */
 
 /* Begin PBXResourcesBuildPhase section */
@@ -609,6 +660,11 @@
 			name = math;
 			targetProxy = CD9F1BE02B7469640035EDF5 /* PBXContainerItemProxy */;
 		};
+		CDAE63122B77C14500551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = matrix;
+			targetProxy = CDAE63112B77C14500551FB8 /* PBXContainerItemProxy */;
+		};
 		CDED9C1B22A2D6CE00AE5CE5 /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = CD3AC6E11D2C0364002B4BB0 /* graphics */;
@@ -669,10 +725,11 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include/ $(PROJECT_DIR)/../math/ $(PROJECT_DIR)/../include/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../include/resource_factory/include/ $(PROJECT_DIR)/../util/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include $(PROJECT_DIR)/..";
 			};
 			name = Debug;
 		};
@@ -717,9 +774,10 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include/ $(PROJECT_DIR)/../math/ $(PROJECT_DIR)/../include/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../include/resource_factory/include/ $(PROJECT_DIR)/../util/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include $(PROJECT_DIR)/..";
 			};
 			name = Release;
 		};

+ 0 - 63
graphics/graphics.xcodeproj/xcshareddata/xcschemes/graphics-test.xcscheme

@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1240"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES"
-      onlyGenerateCoverageForSpecifiedTargets = "YES">
-      <CodeCoverageTargets>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "CD3AC6E11D2C0364002B4BB0"
-            BuildableName = "libgraphics.dylib"
-            BlueprintName = "graphics"
-            ReferencedContainer = "container:graphics.xcodeproj">
-         </BuildableReference>
-      </CodeCoverageTargets>
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "CDED9C1322A2D6CD00AE5CE5"
-               BuildableName = "graphics-test.xctest"
-               BlueprintName = "graphics-test"
-               ReferencedContainer = "container:graphics.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 5 - 4
graphics/include/game/graphics/material.hpp

@@ -9,15 +9,16 @@
 
 #include <vector>
 
+#include <game/math/math_fwd.hpp>
+#include <math/vector/vector.hpp>
+
 #include "game/graphics/graphics_fwd.h"
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
 
 namespace graphics {
 struct uniform {
   identity<texture> texture;
-  materials::uniform
-      uniform_id; // TODO (sjaffe): use an enum and hide remapping?
+  // TODO (sjaffe): use an enum and hide remapping?
+  materials::uniform uniform_id;
 };
 
 struct material : public identity<material> {

+ 4 - 3
graphics/include/game/graphics/object.hpp

@@ -9,10 +9,11 @@
 
 #include <vector>
 
+#include <game/math/math_fwd.hpp>
+#include <game/math/shape.hpp>
+#include <math/vector/vector.hpp>
+
 #include "game/graphics/graphics_fwd.h"
-#include "game/math/math_fwd.hpp"
-#include "game/math/shape.hpp"
-#include "vector/vector.hpp"
 
 namespace graphics {
 struct object {

+ 5 - 4
graphics/include/game/graphics/renderer.hpp

@@ -10,11 +10,12 @@
 
 #include <unordered_map>
 
+#include <game/math/math_fwd.hpp>
+#include <game/util/hash.hpp>
+#include <math/matrix/matrix.hpp>
+#include <math/vector/vector.hpp>
+
 #include "game/graphics/graphics_fwd.h"
-#include "game/math/math_fwd.hpp"
-#include "game/util/hash.hpp"
-#include "matrix/matrix.hpp"
-#include "vector/vector.hpp"
 
 namespace graphics {
 struct renderer {

+ 3 - 3
graphics/include/game/graphics/texture.hpp

@@ -7,9 +7,9 @@
 
 #pragma once
 
-#include "game/math/math_fwd.hpp"
-#include "game/util/identity.hpp"
-#include "vector/vector.hpp"
+#include <game/math/math_fwd.hpp>
+#include <game/util/identity.hpp>
+#include <math/vector/vector.hpp>
 
 namespace graphics {
 struct texture : public identity<texture> {

+ 2 - 2
graphics/include/game/graphics/vertex.h

@@ -8,8 +8,8 @@
 
 #pragma once
 
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
+#include <game/math/math_fwd.hpp>
+#include <math/vector/vector.hpp>
 
 namespace graphics {
 struct vertex {

+ 3 - 2
graphics/src/helper.hpp

@@ -11,9 +11,10 @@
 #include <string>
 #include <utility>
 
+#include <game/math/math_fwd.hpp>
+#include <math/vector/vector.hpp>
+
 #include "game/graphics/graphics_fwd.h"
-#include "game/math/math_fwd.hpp"
-#include "vector/vector.hpp"
 
 namespace graphics {
 namespace textures {

+ 2 - 2
graphics/src/matrix.cxx

@@ -8,8 +8,8 @@
 
 #include "matrix.hpp"
 
-#include "game/math/angle.hpp"
-#include "matrix/matrix.hpp"
+#include <game/math/angle.hpp>
+#include <math/matrix/matrix.hpp>
 
 namespace graphics {
 math::matr4 orthogonal_view(float left, float right, float bottom, float top,

+ 1 - 1
graphics/src/matrix.hpp

@@ -8,7 +8,7 @@
 
 #pragma once
 
-#include "game/math/math_fwd.hpp"
+#include <game/math/math_fwd.hpp>
 
 namespace graphics {
 math::matr4 orthogonal_view(float left, float right, float bottom, float top,

+ 6 - 6
graphics/src/openGL/opengl_manager.cxx

@@ -6,7 +6,6 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
-#include "helper.hpp"
 #include "opengl_renderer.h"
 
 #include <iostream>
@@ -16,17 +15,18 @@
 #include <OpenGL/gl3.h>
 #endif
 
-#include "scope_guard/scope_guard.hpp"
-#include "vector/vector.hpp"
+#include <game/util/env.hpp>
+#include <game/util/files.hpp>
+#include <game/util/time.hpp>
+#include <math/vector/vector.hpp>
+#include <scope_guard/scope_guard.hpp>
 
 #include "game/graphics/exception.h"
 #include "game/graphics/material.hpp"
 #include "game/graphics/shader.hpp"
 #include "game/graphics/shader_program.hpp"
 #include "game/graphics/texture.hpp"
-#include "game/util/env.hpp"
-#include "game/util/files.hpp"
-#include "game/util/time.hpp"
+#include "helper.hpp"
 
 namespace graphics {
 extern void print_shader_error(GLuint, std::string const &);

+ 5 - 4
graphics/src/openGL/opengl_renderer.cxx

@@ -12,14 +12,15 @@
 #include <OpenGL/gl3.h>
 #endif
 
+#include <game/util/env.hpp>
+#include <game/util/time.hpp>
+#include <math/matrix/matrix.hpp>
+#include <math/matrix/matrix_helpers.hpp>
+
 #include "game/graphics/manager.hpp"
 #include "game/graphics/material.hpp"
 #include "game/graphics/vertex.h"
-#include "game/util/env.hpp"
-#include "game/util/time.hpp"
 #include "matrix.hpp"
-#include "matrix/matrix.hpp"
-#include "matrix/matrix_helpers.hpp"
 
 using namespace graphics;
 

+ 5 - 4
graphics/src/openGL/opengl_renderer.h

@@ -8,13 +8,14 @@
 
 #pragma once
 
+#include <game/util/identity.hpp>
+
+#include <math/matrix/matrix.hpp>
+#include <math/matrix/matrix_helpers.hpp>
+
 #include "../helper.hpp"
 #include "../renderer_impl.hpp"
 #include "game/graphics/manager.hpp"
-#include "game/util/identity.hpp"
-
-#include "matrix/matrix.hpp"
-#include "matrix/matrix_helpers.hpp"
 
 namespace graphics {
 struct opengl_uniform_data {

+ 5 - 2
graphics/src/renderer.cxx

@@ -7,13 +7,16 @@
 //
 
 #include "game/graphics/renderer.hpp"
+
 #include <vector>
 
+#include <math/matrix/matrix.hpp>
+#include <math/matrix/matrix_helpers.hpp>
+
 #include "game/graphics/exception.h"
 #include "game/graphics/object.hpp"
 #include "game/graphics/vertex.h"
-#include "matrix/matrix.hpp"
-#include "matrix/matrix_helpers.hpp"
+
 #include "renderer_impl.hpp"
 
 using namespace graphics;

+ 3 - 3
graphics/src/renderer_impl.hpp

@@ -8,11 +8,11 @@
 
 #pragma once
 
+#include <game/math/math_fwd.hpp>
+#include <resource_factory/prototype_factory.hpp>
+
 #include "game/graphics/graphics_fwd.h"
 #include "game/graphics/renderer.hpp"
-#include "game/math/math_fwd.hpp"
-
-#include "resource_factory/prototype_factory.hpp"
 
 namespace graphics {
 using renderer_impl_factory = objects::prototype::factory<renderer_impl *>;

+ 1 - 1
graphics/src/texture.cpp

@@ -14,7 +14,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wcomma"
 #define STB_IMAGE_IMPLEMENTATION
-#include "stb/stb_image.h"
+#include "external/stb/stb_image.h"
 #pragma clang diagnostic pop
 
 #include "game/graphics/exception.h"

+ 4 - 4
graphics/test/manager_test.cxx

@@ -17,9 +17,9 @@
 #include "game/graphics/texture.hpp"
 
 #ifdef __APPLE__
-namespace env { namespace detail {
-  extern void bundle(std::string const &);
-}}
+namespace env::osx {
+extern void bundle(std::string const &);
+}
 #endif
 
 using testing::_;
@@ -86,7 +86,7 @@ private:
 
 void ManagerTest::SetUp() {
 #ifdef __APPLE__
-  env::detail::bundle("leumasjaffe.graphics-test");
+  env::osx::bundle("leumasjaffe.graphics-test");
 #endif
   using testing::Invoke;
   using testing::WithArg;

+ 6 - 4
graphics/test/renderer_test.cxx

@@ -6,16 +6,18 @@
 //  Copyright © 2019 Sam Jaffe. All rights reserved.
 //
 
+#include "game/graphics/renderer.hpp"
+
 #include <gmock/gmock.h>
 
+#include <game/math/shape.hpp>
+#include <math/matrix/matrix.hpp>
+#include <math/matrix/matrix_helpers.hpp>
+
 #include "../src/renderer_impl.hpp"
 #include "game/graphics/exception.h"
 #include "game/graphics/object.hpp"
-#include "game/graphics/renderer.hpp"
 #include "game/graphics/vertex.h"
-#include "game/math/shape.hpp"
-#include "matrix/matrix.hpp"
-#include "matrix/matrix_helpers.hpp"
 
 using testing::_;
 using testing::AnyNumber;

+ 1 - 1
math/include/game/math/common.hpp

@@ -7,7 +7,7 @@
 
 #pragma once
 
-#include "math_fwd.hpp"
+#include "game/math/math_fwd.hpp"
 
 namespace math {
 vec2 rotate(vec2 const & point, radian r);

+ 2 - 2
math/include/game/math/shape.hpp

@@ -7,9 +7,9 @@
 
 #pragma once
 
-#include "vector/vector.hpp"
+#include <math/vector/vector.hpp>
 
-#include "math_fwd.hpp"
+#include <game/math/math_fwd.hpp>
 
 namespace math { namespace dim2 {
   using point = vec2;

+ 99 - 18
math/math.xcodeproj/project.pbxproj

@@ -13,9 +13,6 @@
 		CD1FCFEC227E4C2E00F9BF93 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C80BA1D68902300ACC795 /* common.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CD3AC71E1D2C0AF8002B4BB0 /* shape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC71C1D2C0AF8002B4BB0 /* shape.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
 		CD3C809F1D675AB100ACC795 /* angle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C809D1D675AB100ACC795 /* angle.cpp */; settings = {COMPILER_FLAGS = "-fvisibility=default"; }; };
-		CDA34D9522517967008036A7 /* matrix_helpers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D8C22517680008036A7 /* matrix_helpers.hpp */; };
-		CDA34D9622517969008036A7 /* matrix.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D8D22517680008036A7 /* matrix.hpp */; };
-		CDA34D972251796B008036A7 /* vector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D9022517689008036A7 /* vector.hpp */; };
 		CDED9C2422A2D71600AE5CE5 /* angle_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDED9C2322A2D71600AE5CE5 /* angle_test.cxx */; };
 		CDEDC5B9227F2D38003A2E45 /* common_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CDEDC5B8227F2D38003A2E45 /* common_test.cxx */; };
 /* End PBXBuildFile section */
@@ -63,6 +60,41 @@
 			remoteGlobalIDString = 05818F851A685AEA0072A469;
 			remoteInfo = GoogleMock;
 		};
+		CDAE622C2B77B86700551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62272B77B86700551FB8 /* matrix.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CD0C59D120C412AD00454F82;
+			remoteInfo = "matrix-test";
+		};
+		CDAE62332B77B86D00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CD10425824E837FB00C0DF2A;
+			remoteInfo = "vector-test";
+		};
+		CDAE62E22B77BC0D00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62272B77B86700551FB8 /* matrix.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDAE62392B77B88A00551FB8;
+			remoteInfo = matrix;
+		};
+		CDAE62E52B77BC0D00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDAE62452B77B8A800551FB8;
+			remoteInfo = vector;
+		};
+		CDAE62E72B77BC2200551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CDAE62442B77B8A800551FB8;
+			remoteInfo = vector;
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
@@ -75,9 +107,8 @@
 		CD3C809D1D675AB100ACC795 /* angle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = angle.cpp; sourceTree = "<group>"; };
 		CD3C80BA1D68902300ACC795 /* common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = common.cpp; sourceTree = "<group>"; };
 		CDA34D89225175CB008036A7 /* game */ = {isa = PBXFileReference; lastKnownFileType = folder; name = game; path = include/game; sourceTree = "<group>"; };
-		CDA34D8C22517680008036A7 /* matrix_helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = matrix_helpers.hpp; path = matrix/matrix_helpers.hpp; sourceTree = SOURCE_ROOT; };
-		CDA34D8D22517680008036A7 /* matrix.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = matrix.hpp; path = matrix/matrix.hpp; sourceTree = SOURCE_ROOT; };
-		CDA34D9022517689008036A7 /* vector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = vector.hpp; path = vector/vector.hpp; sourceTree = SOURCE_ROOT; };
+		CDAE62272B77B86700551FB8 /* matrix.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = matrix.xcodeproj; path = ../external/matrix/matrix.xcodeproj; sourceTree = "<group>"; };
+		CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = vector.xcodeproj; path = ../external/vector/vector.xcodeproj; sourceTree = "<group>"; };
 		CDED9C2322A2D71600AE5CE5 /* angle_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = angle_test.cxx; sourceTree = "<group>"; };
 		CDEDC5B8227F2D38003A2E45 /* common_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = common_test.cxx; sourceTree = "<group>"; };
 		CDEDC5BD227F2DB2003A2E45 /* test_printers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = test_printers.h; sourceTree = "<group>"; };
@@ -132,9 +163,10 @@
 		CD37860F1CF9F61100BE89B2 = {
 			isa = PBXGroup;
 			children = (
+				CDAE62272B77B86700551FB8 /* matrix.xcodeproj */,
+				CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */,
 				CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */,
 				CDA34D89225175CB008036A7 /* game */,
-				CDA34D8A22517670008036A7 /* include */,
 				CD3786321CFA304800BE89B2 /* src */,
 				CD3C80791D66440200ACC795 /* test */,
 				CD1FCFCE227E194D00F9BF93 /* math-test */,
@@ -173,14 +205,22 @@
 			path = test;
 			sourceTree = "<group>";
 		};
-		CDA34D8A22517670008036A7 /* include */ = {
+		CDAE62282B77B86700551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE622D2B77B86700551FB8 /* matrix-test.xctest */,
+				CDAE62E32B77BC0D00551FB8 /* libmatrix.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CDAE622F2B77B86D00551FB8 /* Products */ = {
 			isa = PBXGroup;
 			children = (
-				CDA34D8C22517680008036A7 /* matrix_helpers.hpp */,
-				CDA34D8D22517680008036A7 /* matrix.hpp */,
-				CDA34D9022517689008036A7 /* vector.hpp */,
+				CDAE62342B77B86D00551FB8 /* vector-test.xctest */,
+				CDAE62E62B77BC0D00551FB8 /* libvector.a */,
 			);
-			name = include;
+			name = Products;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -190,9 +230,6 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				CDA34D9522517967008036A7 /* matrix_helpers.hpp in Headers */,
-				CDA34D9622517969008036A7 /* matrix.hpp in Headers */,
-				CDA34D972251796B008036A7 /* vector.hpp in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -230,6 +267,7 @@
 			buildRules = (
 			);
 			dependencies = (
+				CDAE62E82B77BC2200551FB8 /* PBXTargetDependency */,
 			);
 			name = math;
 			productName = math;
@@ -271,6 +309,14 @@
 					ProductGroup = CD1FCFDA227E197800F9BF93 /* Products */;
 					ProjectRef = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
 				},
+				{
+					ProductGroup = CDAE62282B77B86700551FB8 /* Products */;
+					ProjectRef = CDAE62272B77B86700551FB8 /* matrix.xcodeproj */;
+				},
+				{
+					ProductGroup = CDAE622F2B77B86D00551FB8 /* Products */;
+					ProjectRef = CDAE622E2B77B86D00551FB8 /* vector.xcodeproj */;
+				},
 			);
 			projectRoot = "";
 			targets = (
@@ -309,6 +355,34 @@
 			remoteRef = CD1FCFE6227E197800F9BF93 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
+		CDAE622D2B77B86700551FB8 /* matrix-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "matrix-test.xctest";
+			remoteRef = CDAE622C2B77B86700551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62342B77B86D00551FB8 /* vector-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "vector-test.xctest";
+			remoteRef = CDAE62332B77B86D00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62E32B77BC0D00551FB8 /* libmatrix.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libmatrix.a;
+			remoteRef = CDAE62E22B77BC0D00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62E62B77BC0D00551FB8 /* libvector.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libvector.a;
+			remoteRef = CDAE62E52B77BC0D00551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 /* End PBXReferenceProxy section */
 
 /* Begin PBXResourcesBuildPhase section */
@@ -337,7 +411,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "mkdir -p ${BUILT_PRODUCTS_DIR}/usr/local/include/\nmkdir -p ${BUILT_PRODUCTS_DIR}/usr/local/include/vector/\nmkdir -p ${BUILT_PRODUCTS_DIR}/usr/local/include/matrix/\ncp -r ${PROJECT_DIR}/include/* ${BUILT_PRODUCTS_DIR}/usr/local/include/\ncp -r ${PROJECT_DIR}/vector/*.h* ${BUILT_PRODUCTS_DIR}/usr/local/include/vector/\ncp -r ${PROJECT_DIR}/matrix/*.h* ${BUILT_PRODUCTS_DIR}/usr/local/include/matrix/\n";
+			shellScript = "mkdir -p ${BUILT_PRODUCTS_DIR}/usr/local/include/\ncp -r ${PROJECT_DIR}/include/* ${BUILT_PRODUCTS_DIR}/usr/local/include/\n";
 		};
 /* End PBXShellScriptBuildPhase section */
 
@@ -375,6 +449,11 @@
 			name = GoogleMock;
 			targetProxy = CD1FCFEA227E198400F9BF93 /* PBXContainerItemProxy */;
 		};
+		CDAE62E82B77BC2200551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = vector;
+			targetProxy = CDAE62E72B77BC2200551FB8 /* PBXContainerItemProxy */;
+		};
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
@@ -473,10 +552,11 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/ $(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include/";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Debug;
 		};
@@ -521,9 +601,10 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/ $(PROJECT_DIR)/include/ $(PROJECT_DIR)/../include/expect/include/";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Release;
 		};

+ 0 - 63
math/math.xcodeproj/xcshareddata/xcschemes/math-test.xcscheme

@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1240"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      codeCoverageEnabled = "YES"
-      onlyGenerateCoverageForSpecifiedTargets = "YES">
-      <CodeCoverageTargets>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "CD3786171CF9F61100BE89B2"
-            BuildableName = "libmath.dylib"
-            BlueprintName = "math"
-            ReferencedContainer = "container:math.xcodeproj">
-         </BuildableReference>
-      </CodeCoverageTargets>
-      <Testables>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "CD1FCFCC227E194D00F9BF93"
-               BuildableName = "math-test.xctest"
-               BlueprintName = "math-test"
-               ReferencedContainer = "container:math.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
-      </Testables>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Debug"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      launchStyle = "0"
-      useCustomWorkingDirectory = "NO"
-      ignoresPersistentStateOnLaunch = "NO"
-      debugDocumentVersioning = "YES"
-      debugServiceExtension = "internal"
-      allowLocationSimulation = "YES">
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Debug">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 175 - 2
util/gameutils.xcodeproj/project.pbxproj

@@ -42,6 +42,69 @@
 			remoteGlobalIDString = 05818F901A685AEA0072A469;
 			remoteInfo = GoogleMockTests;
 		};
+		CDAE62F32B77C05300551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDD215D129CCFA1E00A4582C;
+			remoteInfo = scope_guard;
+		};
+		CDAE62F52B77C05300551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDD215EA29CCFA5000A4582C;
+			remoteInfo = "scope_guard-test";
+		};
+		CDAE62FC2B77C05800551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62F72B77C05800551FB8 /* vector.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CD10425824E837FB00C0DF2A;
+			remoteInfo = "vector-test";
+		};
+		CDAE62FE2B77C05800551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62F72B77C05800551FB8 /* vector.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDAE62452B77B8A800551FB8;
+			remoteInfo = vector;
+		};
+		CDAE63002B77C06100551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CDD215D029CCFA1E00A4582C;
+			remoteInfo = scope_guard;
+		};
+		CDAE63022B77C06100551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE62F72B77C05800551FB8 /* vector.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CDAE62442B77B8A800551FB8;
+			remoteInfo = vector;
+		};
+		CDAE63192B77C2E700551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CD35DCDD1D612CCD00BE3686;
+			remoteInfo = resource_factory;
+		};
+		CDAE631B2B77C2E700551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = CDB23F5E230B69A300AC1138;
+			remoteInfo = "resource_factory-test";
+		};
+		CDAE631D2B77C2EE00551FB8 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = CD35DCDC1D612CCD00BE3686;
+			remoteInfo = resource_factory;
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
@@ -60,6 +123,9 @@
 		CD9F1B902B743DC20035EDF5 /* files.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = files.hpp; sourceTree = "<group>"; };
 		CD9F1B912B743DC20035EDF5 /* identity.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = identity.hpp; sourceTree = "<group>"; };
 		CDA31AB32725C6190071CDC2 /* smart_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = smart_map.hpp; sourceTree = "<group>"; };
+		CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = scope_guard.xcodeproj; path = ../external/scope_guard/scope_guard.xcodeproj; sourceTree = "<group>"; };
+		CDAE62F72B77C05800551FB8 /* vector.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = vector.xcodeproj; path = ../external/vector/vector.xcodeproj; sourceTree = "<group>"; };
+		CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = resource_factory.xcodeproj; path = ../external/resource_factory/resource_factory.xcodeproj; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -77,6 +143,9 @@
 		CD3AC6FF1D2C0726002B4BB0 = {
 			isa = PBXGroup;
 			children = (
+				CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */,
+				CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */,
+				CDAE62F72B77C05800551FB8 /* vector.xcodeproj */,
 				CD62FCE622904AD500376440 /* GoogleMock.xcodeproj */,
 				CD62FCFF2291953700376440 /* game */,
 				CD9F1B8A2B743DC20035EDF5 /* include */,
@@ -154,6 +223,33 @@
 			path = util;
 			sourceTree = "<group>";
 		};
+		CDAE62EA2B77C05200551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE62F42B77C05300551FB8 /* libscope_guard.a */,
+				CDAE62F62B77C05300551FB8 /* scope_guard-test.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CDAE62F82B77C05800551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE62FD2B77C05800551FB8 /* vector-test.xctest */,
+				CDAE62FF2B77C05800551FB8 /* libvector.a */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CDAE63142B77C2E700551FB8 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CDAE631A2B77C2E700551FB8 /* libresource_factory.dylib */,
+				CDAE631C2B77C2E700551FB8 /* resource_factory-test.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -179,6 +275,9 @@
 			buildRules = (
 			);
 			dependencies = (
+				CDAE631E2B77C2EE00551FB8 /* PBXTargetDependency */,
+				CDAE63012B77C06100551FB8 /* PBXTargetDependency */,
+				CDAE63032B77C06100551FB8 /* PBXTargetDependency */,
 			);
 			name = gameutils;
 			productName = gameutils;
@@ -215,6 +314,18 @@
 					ProductGroup = CD62FCE722904AD500376440 /* Products */;
 					ProjectRef = CD62FCE622904AD500376440 /* GoogleMock.xcodeproj */;
 				},
+				{
+					ProductGroup = CDAE63142B77C2E700551FB8 /* Products */;
+					ProjectRef = CDAE63132B77C2E700551FB8 /* resource_factory.xcodeproj */;
+				},
+				{
+					ProductGroup = CDAE62EA2B77C05200551FB8 /* Products */;
+					ProjectRef = CDAE62E92B77C05200551FB8 /* scope_guard.xcodeproj */;
+				},
+				{
+					ProductGroup = CDAE62F82B77C05800551FB8 /* Products */;
+					ProjectRef = CDAE62F72B77C05800551FB8 /* vector.xcodeproj */;
+				},
 			);
 			projectRoot = "";
 			targets = (
@@ -252,6 +363,48 @@
 			remoteRef = CD62FCF322904AD500376440 /* PBXContainerItemProxy */;
 			sourceTree = BUILT_PRODUCTS_DIR;
 		};
+		CDAE62F42B77C05300551FB8 /* libscope_guard.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libscope_guard.a;
+			remoteRef = CDAE62F32B77C05300551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62F62B77C05300551FB8 /* scope_guard-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "scope_guard-test.xctest";
+			remoteRef = CDAE62F52B77C05300551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62FD2B77C05800551FB8 /* vector-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "vector-test.xctest";
+			remoteRef = CDAE62FC2B77C05800551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE62FF2B77C05800551FB8 /* libvector.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libvector.a;
+			remoteRef = CDAE62FE2B77C05800551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE631A2B77C2E700551FB8 /* libresource_factory.dylib */ = {
+			isa = PBXReferenceProxy;
+			fileType = "compiled.mach-o.dylib";
+			path = libresource_factory.dylib;
+			remoteRef = CDAE63192B77C2E700551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CDAE631C2B77C2E700551FB8 /* resource_factory-test.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = "resource_factory-test.xctest";
+			remoteRef = CDAE631B2B77C2E700551FB8 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 /* End PBXReferenceProxy section */
 
 /* Begin PBXShellScriptBuildPhase section */
@@ -287,6 +440,24 @@
 		};
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+		CDAE63012B77C06100551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = scope_guard;
+			targetProxy = CDAE63002B77C06100551FB8 /* PBXContainerItemProxy */;
+		};
+		CDAE63032B77C06100551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = vector;
+			targetProxy = CDAE63022B77C06100551FB8 /* PBXContainerItemProxy */;
+		};
+		CDAE631E2B77C2EE00551FB8 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = resource_factory;
+			targetProxy = CDAE631D2B77C2EE00551FB8 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
 		CD3AC7111D2C0726002B4BB0 /* Debug */ = {
 			isa = XCBuildConfiguration;
@@ -336,10 +507,11 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include $(PROJECT_DIR)/../include/ $(PROJECT_DIR)/../math/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../include/expect/include/";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Debug;
 		};
@@ -385,9 +557,10 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = "$(TARGET_BUILD_DIR)/usr/local/include";
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include $(PROJECT_DIR)/../include/ $(PROJECT_DIR)/../math/ $(PROJECT_DIR)/../math/include/ $(PROJECT_DIR)/../include/expect/include/";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Release;
 		};

+ 1 - 1
util/include/game/util/env.hpp

@@ -10,7 +10,7 @@
 
 #include <string>
 
-#include "game/math/math_fwd.hpp"
+#include <game/math/math_fwd.hpp>
 
 #define ENVIRONMENT_FREE_FUNCTION_ALIAS(function)                              \
   template <typename... Args> auto function(Args &&... args) {                 \

+ 1 - 1
util/src/files.cxx

@@ -8,7 +8,7 @@
 
 #include "game/util/files.hpp"
 
-#include "scope_guard/scope_guard.hpp"
+#include <scope_guard/scope_guard.hpp>
 
 namespace files {
 std::unique_ptr<char[]> load(std::string const & absolute_path) {

+ 1 - 1
util/src/osx_env.mm

@@ -10,7 +10,7 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "vector/vector.hpp"
+#include <math/vector/vector.hpp>
 
 namespace {
 

+ 9 - 0
util/src/smart_map.hpp

@@ -0,0 +1,9 @@
+//
+//  smart_map.hpp
+//  gameutils
+//
+//  Created by Sam Jaffe on 10/24/21.
+//  Copyright © 2021 Sam Jaffe. All rights reserved.
+//
+
+#pragma once

+ 9 - 0
util/src/state_machine.cxx

@@ -0,0 +1,9 @@
+//
+//  state_machine.cxx
+//  gameutils
+//
+//  Created by Sam Jaffe on 10/23/21.
+//  Copyright © 2021 Sam Jaffe. All rights reserved.
+//
+
+#include "state_machine.h"

+ 73 - 0
util/src/state_machine.h

@@ -0,0 +1,73 @@
+//
+//  state_machine.hpp
+//  gameutils
+//
+//  Created by Sam Jaffe on 10/23/21.
+//  Copyright © 2021 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "game/util/identity.hpp"
+
+namespace state {
+struct State : identity<State> {
+  using identity::identity;
+};
+struct Symbol : identity<Symbol> {
+  using identity::identity;
+};
+
+class Machine {
+private:
+  std::vector<State> states_;
+  std::vector<Symbol> alphabet_;
+  std::vector<std::vector<identity<State>>> transitions_;
+
+public:
+  template <typename Q, typename E, typename C>
+  Machine(std::vector<Q> states, std::vector<E> alphabet,
+          C const & transitions) {
+    // TODO: Smarter mapping
+    std::map<Q, identity<State>> state_ids;
+    std::map<E, identity<Symbol>> symbol_ids;
+    for (size_t i = 0; i < states.size(); ++i) {
+      states_.emplace_back(i);
+      state_ids.emplace(states[i], states_.back());
+    }
+    for (size_t i = 0; i < alphabet.size(); ++i) {
+      alphabet_.emplace_back(i);
+      symbol_ids.emplace(alphabet[i], alphabet_.back());
+    }
+    transitions_ =
+        std::vector(states.size(), std::vector(alphabet.size(), states_[0]));
+    for (auto & [state, more] : transitions) {
+      for (auto & [sym, to] : more) {
+        transitions_[state_ids[state].id][symbol_ids[sym].id] = state_ids[to];
+      }
+    }
+  }
+};
+
+#if 0
+template <typename Content = void>
+class DFA {
+public:
+  using super = detail::dfa_impl;
+  
+private:
+  std::shared_ptr<super::node> current_;
+
+public:
+  auto content() const {
+    return std::shared_ptr_cast<Content const>(super::content(current_));
+  }
+};
+#endif
+
+}