Josh Engebretson 9 年之前
父节点
当前提交
5e86020fd9
共有 100 个文件被更改,包括 13876 次插入844 次删除
  1. 6 0
      Build/CIScripts/BuildMac.js
  2. 3 1
      Build/CMake/Modules/AtomicLinux.cmake
  3. 二进制
      Build/Managed/nuget/nuget.exe
  4. 25 0
      Build/Scripts/BuildCommon.js
  5. 37 10
      Build/Scripts/HostCommon.js
  6. 84 0
      Script/AtomicEditor/ui/frames/inspector/AssemblyInspector.ts
  7. 1 1
      Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts
  8. 101 0
      Script/AtomicEditor/ui/frames/inspector/CSComponentClassSelector.ts
  9. 9 0
      Script/AtomicEditor/ui/frames/inspector/InspectorFrame.ts
  10. 6 0
      Script/AtomicNET/.gitignore
  11. 28 0
      Script/AtomicNET/AtomicNET/Application/NETIPCPlayerApp.cs
  12. 27 0
      Script/AtomicNET/AtomicNET/Application/NETServiceApplication.cs
  13. 42 0
      Script/AtomicNET/AtomicNET/Core/AObject.cs
  14. 101 0
      Script/AtomicNET/AtomicNET/Core/AtomicNET.cs
  15. 13 0
      Script/AtomicNET/AtomicNET/Core/Constants.cs
  16. 252 0
      Script/AtomicNET/AtomicNET/Core/NativeCore.cs
  17. 33 0
      Script/AtomicNET/AtomicNET/Core/NativeEvents.cs
  18. 28 0
      Script/AtomicNET/AtomicNET/Core/RefCounted.cs
  19. 635 0
      Script/AtomicNET/AtomicNET/Core/SDLConsts.cs
  20. 20 0
      Script/AtomicNET/AtomicNET/IPC/IPC.cs
  21. 13 0
      Script/AtomicNET/AtomicNET/Math/BoundingBox.cs
  22. 24 0
      Script/AtomicNET/AtomicNET/Math/Color.cs
  23. 22 0
      Script/AtomicNET/AtomicNET/Math/IntRect.cs
  24. 943 0
      Script/AtomicNET/AtomicNET/Math/IntVector2.cs
  25. 313 0
      Script/AtomicNET/AtomicNET/Math/MathHelper.cs
  26. 796 0
      Script/AtomicNET/AtomicNET/Math/Matrix3.cs
  27. 1222 0
      Script/AtomicNET/AtomicNET/Math/Matrix4.cs
  28. 44 0
      Script/AtomicNET/AtomicNET/Math/Plane.cs
  29. 819 0
      Script/AtomicNET/AtomicNET/Math/Quaternion.cs
  30. 10 0
      Script/AtomicNET/AtomicNET/Math/README.md
  31. 13 0
      Script/AtomicNET/AtomicNET/Math/Rect.cs
  32. 1056 0
      Script/AtomicNET/AtomicNET/Math/Vector2.cs
  33. 1358 0
      Script/AtomicNET/AtomicNET/Math/Vector3.cs
  34. 1186 0
      Script/AtomicNET/AtomicNET/Math/Vector4.cs
  35. 14 0
      Script/AtomicNET/AtomicNET/Scene/CSComponent.cs
  36. 206 0
      Script/AtomicNET/AtomicNET/Scene/CSComponentCore.cs
  37. 17 0
      Script/AtomicNET/AtomicNET/Scene/InspectorAttribute.cs
  38. 33 0
      Script/AtomicNET/AtomicNET/Script/ScriptVariantMap.cs
  39. 549 0
      Script/AtomicNET/AtomicNET/ThirdParty/MiniJSON.cs
  40. 84 0
      Script/AtomicNET/AtomicNETProject.json
  41. 226 0
      Script/AtomicNET/AtomicNETService/AssemblyInspector.cs
  42. 41 0
      Script/AtomicNET/AtomicNETService/AtomicTools.cs
  43. 808 0
      Script/AtomicNET/AtomicNETService/CSComponentInspector.cs
  44. 72 0
      Script/AtomicNET/AtomicNETService/Program.cs
  45. 22 0
      Script/AtomicNET/AtomicPlayer/Program.cs
  46. 27 0
      Script/AtomicNET/AtomicPlayer/project.json
  47. 18 0
      Script/AtomicNET/ComponentTest/Spinner.cs
  48. 47 0
      Script/AtomicNET/ComponentTest/TestComponent.cs
  49. 30 0
      Script/AtomicNET/Docs/Notes.txt
  50. 1 1
      Script/Packages/Atomic/Engine.json
  51. 6 0
      Script/Packages/Atomic/IPC.json
  52. 7 6
      Script/Packages/Atomic/Package.json
  53. 1 1
      Script/Packages/Atomic/Script.json
  54. 5 0
      Script/Packages/AtomicApp/AtomicApp.json
  55. 8 0
      Script/Packages/AtomicApp/Package.json
  56. 5 0
      Script/Packages/AtomicNETNative/AtomicNETNative.json
  57. 9 0
      Script/Packages/AtomicNETNative/Package.json
  58. 5 0
      Script/Packages/AtomicNETScript/AtomicNETScript.json
  59. 8 0
      Script/Packages/AtomicNETScript/Package.json
  60. 1 1
      Script/Packages/ToolCore/ToolCore.json
  61. 3 0
      Script/tsconfig.json
  62. 2 1
      Source/Atomic/CMakeLists.txt
  63. 3 0
      Source/Atomic/Graphics/Direct3D9/D3D9Texture.h
  64. 3 0
      Source/Atomic/Graphics/OpenGL/OGLTexture.h
  65. 72 5
      Source/Atomic/IPC/IPC.cpp
  66. 3 0
      Source/Atomic/IPC/IPC.h
  67. 219 0
      Source/Atomic/IPC/IPCServer.cpp
  68. 110 0
      Source/Atomic/IPC/IPCServer.h
  69. 4 0
      Source/Atomic/Resource/JSONValue.h
  70. 4 1
      Source/Atomic/Script/ScriptSystem.cpp
  71. 18 9
      Source/Atomic/Script/ScriptSystem.h
  72. 9 0
      Source/Atomic/Script/ScriptVariantMap.cpp
  73. 188 0
      Source/Atomic/Script/ScriptVariantMap.h
  74. 3 1
      Source/Atomic/UI/UI.cpp
  75. 182 0
      Source/AtomicApp/AppBase.cpp
  76. 70 0
      Source/AtomicApp/AppBase.h
  77. 11 0
      Source/AtomicApp/CMakeLists.txt
  78. 98 0
      Source/AtomicApp/IPCClientApp.cpp
  79. 57 0
      Source/AtomicApp/IPCClientApp.h
  80. 282 0
      Source/AtomicApp/Player/IPCPlayerApp.cpp
  81. 72 0
      Source/AtomicApp/Player/IPCPlayerApp.h
  82. 65 0
      Source/AtomicApp/Player/IPCPlayerAppEvents.h
  83. 176 0
      Source/AtomicApp/Player/PlayerApp.cpp
  84. 56 0
      Source/AtomicApp/Player/PlayerApp.h
  85. 116 77
      Source/AtomicEditor/Application/AEEditorApp.cpp
  86. 18 23
      Source/AtomicEditor/Application/AEEditorApp.h
  87. 0 307
      Source/AtomicEditor/Application/AEEditorCommon.cpp
  88. 210 0
      Source/AtomicEditor/Application/AEEditorPrefs.cpp
  89. 19 35
      Source/AtomicEditor/Application/AEEditorPrefs.h
  90. 22 292
      Source/AtomicEditor/Application/AEPlayerApp.cpp
  91. 18 34
      Source/AtomicEditor/Application/AEPlayerApp.h
  92. 1 1
      Source/AtomicEditor/CMakeLists.txt
  93. 21 7
      Source/AtomicEditor/EditorMode/AEEditorMode.cpp
  94. 1 1
      Source/AtomicEditor/EditorMode/AEEditorMode.h
  95. 66 0
      Source/AtomicEditor/EditorMode/AEEditorNETService.cpp
  96. 19 28
      Source/AtomicEditor/EditorMode/AEEditorNETService.h
  97. 1 1
      Source/AtomicEditor/PlayerMode/AEPlayerMode.cpp
  98. 3 0
      Source/AtomicNET/CMakeLists.txt
  99. 36 0
      Source/AtomicNET/NETNative/CMakeLists.txt
  100. 95 0
      Source/AtomicNET/NETNative/NETCInterop.cpp

+ 6 - 0
Build/CIScripts/BuildMac.js

@@ -22,6 +22,9 @@ namespace('build', function() {
     var cmds = [
       atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/Atomic/ MACOSX",
       atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicPlayer/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicApp/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicNETNative/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicNETScript/ MACOSX",
       "cmake -DATOMIC_DEV_BUILD=0 -G Xcode ../../../../",
       "xcodebuild -target AtomicPlayer -configuration Release -parallelizeTargets -jobs 4"
     ];
@@ -56,6 +59,9 @@ namespace('build', function() {
       atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/ToolCore/ MACOSX",
       atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/Editor/ MACOSX",
       atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/WebView/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicApp/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicNETNative/ MACOSX",
+      atomicTool + " bind " + bcommon.atomicRoot + " Script/Packages/AtomicNETScript/ MACOSX",      
       "cmake -DATOMIC_DEV_BUILD=0 -G Xcode ../../../../",
       "xcodebuild -target AtomicEditor -configuration Release -parallelizeTargets -jobs 4",
       "cd " + editorBuildDir + "Source/AtomicEditor/Release && zip -r -X " + buildDir + "Bin/AtomicEditor.zip ./AtomicEditor.app"

+ 3 - 1
Build/CMake/Modules/AtomicLinux.cmake

@@ -5,7 +5,9 @@ include(AtomicDesktop)
 
 add_definitions(-DATOMIC_PLATFORM_LINUX -DATOMIC_OPENGL -DKNET_UNIX -DHAVE_INT64_T)
 
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -std=gnu++0x")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -std=gnu++0x -fPIC")
+
 
 find_package(PkgConfig REQUIRED)
 

二进制
Build/Managed/nuget/nuget.exe


+ 25 - 0
Build/Scripts/BuildCommon.js

@@ -79,6 +79,31 @@ namespace('build', function() {
         }
     }
 
+    task('genAtomicNET', {
+      async:true
+    }, function(platform, configuration) {
+
+      if (configuration != "Debug" && configuration != "Release")
+        configuration = "Release";
+
+      // Compile AtomicNET assemblies
+      var cmds = [];
+
+      if (os.platform() == "win32") {
+        cmds.push(host.atomicTool + " net genproject " + atomicRoot + "/Script/AtomicNET/AtomicNETProject.json " + platform);
+        cmds.push(host.atomicTool + " net compile " + atomicRoot + "Artifacts\\AtomicNET\\Build\\AtomicNET.sln " + configuration);
+      }
+
+      jake.exec(cmds, function() {
+
+          complete();
+
+      }, {
+          printStdout: true
+      });
+
+    })
+
     task('genscripts', {
         async: true
     }, function(platform, force) {

+ 37 - 10
Build/Scripts/HostCommon.js

@@ -39,13 +39,17 @@ function getScriptModules(platform) {
       var moduleName = pkg.modules[j];
 
       if (pkg.moduleExclude && pkg.moduleExclude[platform])
-        if (pkg.moduleExclude[platform].indexOf(moduleName) != -1)
-          continue;
+      if (pkg.moduleExclude[platform].indexOf(moduleName) != -1)
+        continue;
 
-      if (!modules[pkg.name])
-        modules[pkg.name] = [];
+      if (!modules[pkg.name]) {
+        modules[pkg.name] = {
+          moduleNames: [],
+          bindings: pkg.bindings
+        };
+      }
 
-      modules[pkg.name].push(moduleName);
+      modules[pkg.name].moduleNames.push(moduleName);
     }
 
   }
@@ -71,13 +75,36 @@ function getGenScriptFilenames(platform) {
 
   for (var pkgName in modules) {
 
-    var jsPackageFolder = scriptGenRoot + "Javascript/Packages/" + pkgName + "/";
+    var module = modules[pkgName];
 
-    // the JS package sources
-    filenames.push(jsPackageFolder + "JSPackage" + pkgName + ".cpp");
+    // handle JS bindings
+    if (!module.bindings || module.bindings.indexOf("JavaScript") != -1) {
+
+      var jsPackageFolder = scriptGenRoot + "Javascript/Packages/" + pkgName + "/";
+
+      // the JS package sources
+      filenames.push(jsPackageFolder + "JSPackage" + pkgName + ".cpp");
+
+      for (var i in module.moduleNames) {
+        filenames.push(jsPackageFolder + "JSModule" + module.moduleNames[i] + ".cpp");
+      }
+    }
+
+    // C#
+    if (!module.bindings || module.bindings.indexOf("CSharp") != -1) {
+
+      var csPackageFolder = scriptGenRoot + "CSharp/Packages/" + pkgName + "/";
+      var csPackageNativeFolder = csPackageFolder + "Native/";
+      var csPackageManagedFolder = csPackageFolder + "Managed/";
+
+      // Native Package sources
+      filenames.push(csPackageNativeFolder + "CSPackage" + pkgName + ".cpp");
+      filenames.push(csPackageNativeFolder + "CSPackage" + pkgName + ".h");
+
+      for (var i in module.moduleNames) {
+        filenames.push(csPackageNativeFolder + "CSModule" + module.moduleNames[i] + ".cpp");
+      }
 
-    for (var i in modules[pkgName]) {
-      filenames.push(jsPackageFolder + "JSModule" + modules[pkgName][i] + ".cpp");
     }
 
   }

+ 84 - 0
Script/AtomicEditor/ui/frames/inspector/AssemblyInspector.ts

@@ -0,0 +1,84 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import InspectorWidget = require("./InspectorWidget");
+import ArrayEditWidget = require("./ArrayEditWidget");
+import InspectorUtils = require("./InspectorUtils");
+
+class AssemblyInspector extends InspectorWidget {
+
+    constructor() {
+
+        super();
+
+        this.subscribeToEvent(this, "WidgetEvent", (data) => this.handleWidgetEvent(data));
+
+    }
+
+    handleWidgetEvent(ev: Atomic.UIWidgetEvent):boolean {
+
+      return false;
+
+    }
+
+    inspect(asset: ToolCore.Asset) {
+
+        this.asset = asset;
+        this.importer = <ToolCore.NETAssemblyImporter> asset.importer;
+
+        // node attr layout
+        var rootLayout = this.rootLayout;
+
+        // Assembly Section
+        var assemblyLayout = this.createSection(rootLayout, "NETAssembly", 1);
+
+        var assemblyFile = <AtomicNETScript.CSComponentAssembly> asset.importer.getResource();
+
+        var container = InspectorUtils.createContainer();
+        container.gravity = Atomic.UI_GRAVITY_ALL;
+        assemblyLayout.addChild(container);
+
+        var panel = new Atomic.UILayout();
+        panel.axis = Atomic.UI_AXIS_Y;
+        panel.layoutSize = Atomic.UI_LAYOUT_SIZE_PREFERRED;
+        panel.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP;
+        container.addChild(panel);
+
+        var label = InspectorUtils.createAttrName("CSComponents:");
+        panel.addChild(label);
+
+        for (var index in assemblyFile.classNames) {
+            var classname = assemblyFile.classNames[index];
+
+            label = InspectorUtils.createAttrName(classname);
+            panel.addChild(label);
+        }
+
+    }
+
+
+    asset: ToolCore.Asset;
+    importer:ToolCore.NETAssemblyImporter;
+
+}
+
+export = AssemblyInspector;

+ 1 - 1
Script/AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts

@@ -675,7 +675,7 @@ class ResourceRefAttributeEdit extends AttributeInfoEdit {
             this.nameOverride = attrInfo.resourceTypeName + " " + this.refListIndex;
 
         var importerName = ToolCore.assetDatabase.getResourceImporterName(attrInfo.resourceTypeName);
-
+        
         if (!importerName)
             return false;
 

+ 101 - 0
Script/AtomicEditor/ui/frames/inspector/CSComponentClassSelector.ts

@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import EditorUI = require("ui/EditorUI");
+
+class CSComponentClassSelector extends Atomic.UIWindow {
+
+    constructor(editField: Atomic.UIEditField, component: AtomicNETScript.CSComponent) {
+
+        super();
+
+        var assemblyFile = component.assemblyFile;
+
+        this.text = "Select Class: " + assemblyFile.name;
+
+        this.rect = [0, 0, 400, 512];
+
+        var mainLayout = new Atomic.UILayout();
+        mainLayout.gravity = Atomic.UI_GRAVITY_ALL;
+        mainLayout.layoutDistribution = Atomic.UI_LAYOUT_DISTRIBUTION_AVAILABLE;
+        mainLayout.axis = Atomic.UI_AXIS_Y;
+        this.contentRoot.addChild(mainLayout);
+
+        // really want a grid container
+        var scrollContainer = new Atomic.UIScrollContainer();
+        scrollContainer.gravity = Atomic.UI_GRAVITY_ALL;
+        scrollContainer.scrollMode = Atomic.UI_SCROLL_MODE_Y_AUTO;
+        scrollContainer.adaptContentSize = true;
+
+        var scrollLayout = new Atomic.UILayout();
+        scrollLayout.layoutPosition = Atomic.UI_LAYOUT_POSITION_LEFT_TOP;
+        scrollLayout.layoutDistributionPosition = Atomic.UI_LAYOUT_DISTRIBUTION_POSITION_LEFT_TOP;
+        scrollLayout.axis = Atomic.UI_AXIS_Y;
+
+        scrollContainer.contentRoot.addChild(scrollLayout);
+
+        var window = this;
+
+        for (var i in assemblyFile.classNames) {
+
+            var classname = assemblyFile.classNames[i];
+            var button = new Atomic.UIButton();
+            button.text = classname;
+
+            button.onClick = function() {
+                editField.text = this.text;
+                component.componentClassName = this.text;
+                window.close();
+            }.bind(button);
+
+            scrollLayout.addChild(button);
+        }
+
+        mainLayout.addChild(scrollContainer);
+
+        EditorUI.getMainFrame().addChild(this);
+
+        this.center();
+
+        this.subscribeToEvent("WidgetEvent", (data) => this.handleWidgetEvent(data));
+
+    }
+
+    handleWidgetEvent(ev: Atomic.UIWidgetEvent) {
+
+        if (ev.type == Atomic.UI_EVENT_TYPE_CLICK) {
+
+            if (ev.target != this && !this.isAncestorOf(ev.target)) {
+
+                //this.close();
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+}
+
+export = CSComponentClassSelector;

+ 9 - 0
Script/AtomicEditor/ui/frames/inspector/InspectorFrame.ts

@@ -29,6 +29,7 @@ import MaterialInspector = require("./MaterialInspector");
 import ModelInspector = require("./ModelInspector");
 import PrefabInspector = require("./PrefabInspector");
 import TextureInspector = require("./TextureInspector");
+import AssemblyInspector = require("./AssemblyInspector");
 
 import SelectionInspector = require("./SelectionInspector");
 // make sure these are hooked in
@@ -220,6 +221,14 @@ class InspectorFrame extends ScriptWidget {
             textureInspector.inspect(texture, asset);
         }
 
+        if (asset.importerTypeName == "NETAssemblyImporter") {
+
+          var assemblyInspector = new AssemblyInspector();
+          container.addChild(assemblyInspector);
+          assemblyInspector.inspect(asset);
+
+        }
+
     }
 
 }

+ 6 - 0
Script/AtomicNET/.gitignore

@@ -0,0 +1,6 @@
+**/bin/*
+**/obj/*
+**/project.lock.json
+**/.vscode/*
+**/Generated
+

+ 28 - 0
Script/AtomicNET/AtomicNET/Application/NETIPCPlayerApp.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class NETIPCPlayerApp : IPCPlayerApp
+    {
+
+        public static NETIPCPlayerApp Create(bool headless = false)
+        {
+            // Initialize AtomicNET
+            AtomicNET.Initialize();
+
+            var app = CreateInternal();
+
+            app.Initialize();
+
+            AtomicNET.RegisterSubsystem("Graphics");
+            AtomicNET.RegisterSubsystem("Player");
+
+            return app;
+        }
+
+    }
+
+}

+ 27 - 0
Script/AtomicNET/AtomicNET/Application/NETServiceApplication.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class NETServiceApplication : IPCClientApp
+    {
+
+        public static NETServiceApplication Create()
+        {
+            // Initialize AtomicNET
+            AtomicNET.Initialize();
+
+            var app = CreateInternal();
+
+            app.Initialize();
+
+            AtomicNET.RegisterSubsystem("IPC");
+
+            return app;
+        }
+
+    }
+
+}

+ 42 - 0
Script/AtomicNET/AtomicNET/Core/AObject.cs

@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class AObject : RefCounted
+    {
+        internal Dictionary<uint, EventDelegate> eventHandlers = new Dictionary<uint, EventDelegate>();
+
+        internal void HandleEvent(uint eventType, ScriptVariantMap eventData)
+        {
+            eventHandlers[eventType](eventType, eventData);
+        }
+
+        public void SubscribeToEvent(uint eventType, EventDelegate eventDelegate)
+        {
+            NETCore.RegisterNETEventType(eventType);
+            eventHandlers[eventType] = eventDelegate;
+            NativeCore.SubscribeToEvent(this, eventType);
+        }
+
+        public void SubscribeToEvent(string eventType, EventDelegate eventDelegate)
+        {
+            SubscribeToEvent(AtomicNET.StringToStringHash(eventType), eventDelegate);
+        }
+
+        public void SendEvent(string eventType, ScriptVariantMap eventData = null)
+        {
+
+            csb_Atomic_AObject_SendEvent(this.nativeInstance, eventType, eventData == null ? IntPtr.Zero : eventData.nativeInstance);
+
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern void csb_Atomic_AObject_SendEvent(IntPtr self, string eventType, IntPtr variantMap);
+
+
+    }
+
+}

+ 101 - 0
Script/AtomicNET/AtomicNET/Core/AtomicNET.cs

@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using AtomicPlayer;
+
+namespace AtomicEngine
+{
+
+    public static class AtomicNET
+    {
+
+        public static Context Context => context;
+
+        public static T GetSubsystem<T>() where T : AObject
+        {
+            AObject subSystem = null;
+            subSystems.TryGetValue(typeof(T), out subSystem);
+            return (T)subSystem;
+        }
+
+        public static void RegisterSubsystem(String name, AObject instance = null)
+        {
+            if (instance != null)
+            {
+                subSystems[instance.GetType()] = instance;
+                return;
+            }
+
+            var subsystem = AtomicNET.Context.GetSubsystem(name);
+
+            if (subsystem == null)
+            {
+                throw new System.InvalidOperationException("AtomicNET.RegisterSubsystem - Attempting to register null subsystem");
+            }
+
+            subSystems[subsystem.GetType()] = subsystem;
+        }
+
+        public static uint StringToStringHash(string value)
+        {
+            return csb_Atomic_AtomicNET_StringToStringHash(value);
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern uint csb_Atomic_AtomicNET_StringToStringHash(string name);
+
+        public static void Initialize()
+        {
+            // Atomic Modules
+            CoreModule.Initialize();
+            MathModule.Initialize();
+            EngineModule.Initialize();
+            InputModule.Initialize();
+            IOModule.Initialize();
+            ResourceModule.Initialize();
+            AudioModule.Initialize();
+            GraphicsModule.Initialize();
+            SceneModule.Initialize();
+            Atomic2DModule.Initialize();
+            Atomic3DModule.Initialize();
+            NavigationModule.Initialize();
+            NetworkModule.Initialize();
+            PhysicsModule.Initialize();
+            EnvironmentModule.Initialize();
+            UIModule.Initialize();
+            IPCModule.Initialize();
+            AtomicAppModule.Initialize();
+
+            AtomicNETScriptModule.Initialize();
+            AtomicNETNativeModule.Initialize();
+
+            PlayerModule.Initialize();            
+
+            CoreDelegates delegates = new CoreDelegates();
+            delegates.eventDispatch = NativeCore.EventDispatch;
+
+            IntPtr coreptr = csb_Atomic_NETCore_Initialize(ref delegates);
+
+            NETCore core = (coreptr == IntPtr.Zero ? null : NativeCore.WrapNative<NETCore>(coreptr));
+
+            if (core != null)
+                AtomicNET.RegisterSubsystem("NETCore", core);
+
+            context = core.Context;
+
+            NativeCore.Initialize();
+
+            CSComponentCore.Initialize();
+
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern IntPtr csb_Atomic_NETCore_Initialize(ref CoreDelegates delegates);
+
+        private static Context context;
+        private static Dictionary<Type, AObject> subSystems = new Dictionary<Type, AObject>();
+
+    }
+
+}

+ 13 - 0
Script/AtomicNET/AtomicNET/Core/Constants.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public static partial class Constants
+    {
+        public const string LIBNAME = "AtomicNETNative.dll";
+    }
+
+}

+ 252 - 0
Script/AtomicNET/AtomicNET/Core/NativeCore.cs

@@ -0,0 +1,252 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public class NativeType
+    {
+
+        public Type Type => type;
+
+        public NativeType(IntPtr nativeClassID, Type type, Func<IntPtr, RefCounted> managedConstructor)
+        {
+            this.nativeClassID = nativeClassID;
+            this.type = type;
+            this.managedConstructor = managedConstructor;
+
+            NativeCore.RegisterNativeType(this);
+        }
+
+        internal Type type;
+        internal IntPtr nativeClassID;
+        internal Func<IntPtr, RefCounted> managedConstructor;
+
+    }
+
+    public static class NativeCore
+    {
+
+        static internal void SubscribeToEvent(AObject receiver, uint eventType)
+        {
+            List<WeakReference> eventReceivers;
+
+            if (!eventReceiverLookup.TryGetValue(eventType, out eventReceivers))
+            {
+                eventReceivers = eventReceiverLookup[eventType] = new List<WeakReference>();
+            }
+
+            foreach (WeakReference wr in eventReceivers)
+            {
+                // GC'd?
+                if (!wr.IsAlive)
+                    continue;
+
+                // already on list?
+                if (((AObject)wr.Target) == receiver)
+                    return;
+            }
+
+            WeakReference w = null;
+
+            if (!nativeLookup.TryGetValue(receiver.nativeInstance, out w))
+            {
+                throw new System.InvalidOperationException("NativeCore.SubscribeToEvent - unable to find native instance");
+            }
+
+            if (!w.IsAlive)
+            {
+                throw new System.InvalidOperationException("NativeCore.SubscribeToEvent - attempting to subscribe a GC'd AObject");
+            }
+
+            eventReceivers.Add(w);
+        }
+
+        static ScriptVariantMap[] svm;
+        static int svmDepth = 0;
+        const int svmMax = 256;
+
+        internal static void Initialize()
+        {
+            // preallocate script variant maps
+            svm = new ScriptVariantMap[svmMax];
+            for (int i = 0; i < svmMax; i++)
+                svm[i] = new ScriptVariantMap();
+        }
+
+        public static void EventDispatch(uint eventType, IntPtr eventData)
+        {
+            List<WeakReference> eventReceivers;
+
+            if (!eventReceiverLookup.TryGetValue(eventType, out eventReceivers))
+            {
+
+                // This should not happen, as event NET objects are subscribed to are filtered 
+                throw new System.InvalidOperationException("NativeCore.EventDispatch - received unregistered event type");
+
+            }
+
+            ScriptVariantMap scriptMap = null;
+
+            foreach (var w in eventReceivers)
+            {
+                // GC'd?
+                if (!w.IsAlive)
+                    continue;
+
+                if (scriptMap == null)
+                {
+                    if (svmDepth == svmMax)
+                    {
+                        throw new System.InvalidOperationException("NativeCore.EventDispatch - exceeded max svm");
+                    }
+
+                    scriptMap = svm[svmDepth++];
+                    scriptMap.CopyVariantMap(eventData);
+                }
+
+                ((AObject)w.Target).HandleEvent(eventType, scriptMap);
+            }
+
+            if (scriptMap != null)
+                svmDepth--;
+
+        }
+
+        // register a newly created native
+        public static IntPtr RegisterNative(IntPtr native, RefCounted r)
+        {
+            if (nativeLookup.ContainsKey(native))
+            {
+                throw new System.InvalidOperationException("NativeCore.RegisterNative - Duplicate IntPtr key");
+            }
+
+            r.nativeInstance = native;
+
+            var w = new WeakReference(r);
+            nativeLookup[native] = w;
+
+            // keep native side alive
+            r.AddRef();
+
+            return native;
+        }
+
+
+        // wraps an existing native instance, with downcast support
+        public static T WrapNative<T>(IntPtr native) where T : RefCounted
+        {
+            if (native == IntPtr.Zero)
+                return null;
+
+            WeakReference w;
+
+            // first see if we're already available
+            if (nativeLookup.TryGetValue(native, out w))
+            {
+
+                if (w.IsAlive)
+                {
+
+                    // we're alive!
+                    return (T)w.Target;
+
+                }
+                else
+                {
+
+                    // we were seen before, but have since been GC'd, remove!
+                    nativeLookup.Remove(native);
+                    csb_AtomicEngine_ReleaseRef(native);
+                }
+            }
+
+            IntPtr classID = RefCounted.csb_Atomic_RefCounted_GetClassID(native);
+
+            // and store, with downcast support for instance Component -> StaticModel
+            // we never want to hit this path for script inherited natives
+
+            NativeType nativeType;
+
+            if (!nativeClassIDToNativeType.TryGetValue(classID, out nativeType))
+            {
+                throw new System.InvalidOperationException("NativeCore.WrapNative - Attempting to wrap unknown native class id");
+            }
+
+            RefCounted r = nativeType.managedConstructor(native);
+            w = new WeakReference(r);
+            NativeCore.nativeLookup[native] = w;
+
+            // store a ref, so native side will not be released while we still have a reference in managed code
+            r.AddRef();
+
+            return (T)r;
+        }
+
+        public static void RegisterNativeType(NativeType nativeType)
+        {
+            if (nativeClassIDToNativeType.ContainsKey(nativeType.nativeClassID))
+            {
+                throw new System.InvalidOperationException("NativeCore.RegisterNativeType - Duplicate NativeType class id registered");
+            }
+            if (typeToNativeType.ContainsKey(nativeType.type))
+            {
+                throw new System.InvalidOperationException("NativeCore.RegisterNativeType - Duplicate NativeType type registered");
+            }
+
+            nativeClassIDToNativeType[nativeType.nativeClassID] = nativeType;
+            typeToNativeType[nativeType.type] = nativeType;
+
+        }
+
+        static public IntPtr NativeContructorOverride
+        {
+            get
+            {
+                IntPtr value = nativeContructorOverride;
+                nativeContructorOverride = IntPtr.Zero;
+                return value;                
+            }
+
+            set
+            {
+                if (nativeContructorOverride != IntPtr.Zero)
+                {
+                    throw new System.InvalidOperationException("NativeCore.NativeContructorOverride - Previous nativeContructorOverride not consumed");
+                }
+
+                nativeContructorOverride = value;
+            }
+        }
+
+        static public void VerifyNativeContructorOverrideConsumed()
+        {
+            if (nativeContructorOverride != IntPtr.Zero)
+            {
+                throw new System.InvalidOperationException("NativeCore.VerifyNativeContructorOverrideConsumed -  NativeContructorOverride not consumed");
+            }
+        }
+
+
+        private static IntPtr nativeContructorOverride = IntPtr.Zero;
+
+        // weak references here, hold a ref native side
+        internal static Dictionary<IntPtr, WeakReference> nativeLookup = new Dictionary<IntPtr, WeakReference>();
+
+        // Native ClassID to NativeType lookup
+        internal static Dictionary<IntPtr, NativeType> nativeClassIDToNativeType = new Dictionary<IntPtr, NativeType>();
+
+        // weak references here, hold a ref native side
+        internal static Dictionary<uint, List<WeakReference>> eventReceiverLookup = new Dictionary<uint, List<WeakReference>>();
+
+        // Managed Type to NativeType lookup
+        internal static Dictionary<Type, NativeType> typeToNativeType = new Dictionary<Type, NativeType>();
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern void csb_AtomicEngine_ReleaseRef(IntPtr refCounted);
+
+    }
+
+
+}

+ 33 - 0
Script/AtomicNET/AtomicNET/Core/NativeEvents.cs

@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    [StructLayout(LayoutKind.Sequential)]
+    public struct CoreDelegates
+    {
+        [MarshalAs(UnmanagedType.FunctionPtr)]
+        public EventDispatchDelegate eventDispatch;
+    }
+
+
+    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+    public delegate void EventDispatchDelegate(uint eventType, IntPtr eventData);
+
+    public delegate void EventDelegate(uint eventType, ScriptVariantMap eventData);
+
+    public partial class ScriptVariantMap
+    {
+        public void CopyVariantMap(IntPtr vm)
+        {
+            csb_Atomic_AtomicNET_ScriptVariantMapCopyVariantMap(nativeInstance, vm);
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern IntPtr csb_Atomic_AtomicNET_ScriptVariantMapCopyVariantMap(IntPtr svm, IntPtr vm);
+
+    }
+
+}

+ 28 - 0
Script/AtomicNET/AtomicNET/Core/RefCounted.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class RefCounted
+    {
+
+        public RefCounted()
+        {
+        }
+
+        protected RefCounted(IntPtr native)
+        {
+            nativeInstance = native;
+        }
+
+        public IntPtr nativeInstance = IntPtr.Zero;
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        public static extern IntPtr csb_Atomic_RefCounted_GetClassID(IntPtr self);
+
+    }
+
+
+}

+ 635 - 0
Script/AtomicNET/AtomicNET/Core/SDLConsts.cs

@@ -0,0 +1,635 @@
+#region License
+/* SDL2# - C# Wrapper for SDL2
+ *
+ * Copyright (c) 2013-2015 Ethan Lee.
+ *
+ * This software is provided 'as-is', without any express or implied warranty.
+ * In no event will the authors be held liable for any damages arising from
+ * the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software in a
+ * product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * Ethan "flibitijibibo" Lee <[email protected]>
+ *
+ */
+#endregion
+
+namespace AtomicEngine
+{
+
+	public static class SDL
+	{
+
+
+		public const int SDL_BUTTON_LEFT =	1;
+		public const int SDL_BUTTON_MIDDLE =	2;
+		public const int SDL_BUTTON_RIGHT =	3;
+		public const int SDL_BUTTON_X1 =	4;
+		public const int SDL_BUTTON_X2 =	5;
+		public const int SDL_BUTTON_LMASK =	(1 << ((int)SDL_BUTTON_LEFT - 1));
+		public const int SDL_BUTTON_MMASK =	(1 << ((int)SDL_BUTTON_MIDDLE - 1));
+		public const int SDL_BUTTON_RMASK =	(1 << ((int)SDL_BUTTON_RIGHT - 1));
+		public const int SDL_BUTTON_X1MASK = (1 << ((int)SDL_BUTTON_X1 - 1));
+		public const int SDL_BUTTON_X2MASK = (1 << ((int)SDL_BUTTON_X2 - 1));
+
+		public const byte SDL_HAT_CENTERED =	0x00;
+		public const byte SDL_HAT_UP =		0x01;
+		public const byte SDL_HAT_RIGHT =	0x02;
+		public const byte SDL_HAT_DOWN =	0x04;
+		public const byte SDL_HAT_LEFT =	0x08;
+		public const byte SDL_HAT_RIGHTUP =	SDL_HAT_RIGHT | SDL_HAT_UP;
+		public const byte SDL_HAT_RIGHTDOWN =	SDL_HAT_RIGHT | SDL_HAT_DOWN;
+		public const byte SDL_HAT_LEFTUP =	SDL_HAT_LEFT | SDL_HAT_UP;
+		public const byte SDL_HAT_LEFTDOWN =	SDL_HAT_LEFT | SDL_HAT_DOWN;
+
+		public enum SDL_GameControllerButton
+		{
+			SDL_CONTROLLER_BUTTON_INVALID = -1,
+			SDL_CONTROLLER_BUTTON_A,
+			SDL_CONTROLLER_BUTTON_B,
+			SDL_CONTROLLER_BUTTON_X,
+			SDL_CONTROLLER_BUTTON_Y,
+			SDL_CONTROLLER_BUTTON_BACK,
+			SDL_CONTROLLER_BUTTON_GUIDE,
+			SDL_CONTROLLER_BUTTON_START,
+			SDL_CONTROLLER_BUTTON_LEFTSTICK,
+			SDL_CONTROLLER_BUTTON_RIGHTSTICK,
+			SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
+			SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
+			SDL_CONTROLLER_BUTTON_DPAD_UP,
+			SDL_CONTROLLER_BUTTON_DPAD_DOWN,
+			SDL_CONTROLLER_BUTTON_DPAD_LEFT,
+			SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
+			SDL_CONTROLLER_BUTTON_MAX,
+		}
+
+		public enum SDL_GameControllerAxis
+		{
+			SDL_CONTROLLER_AXIS_INVALID = -1,
+			SDL_CONTROLLER_AXIS_LEFTX,
+			SDL_CONTROLLER_AXIS_LEFTY,
+			SDL_CONTROLLER_AXIS_RIGHTX,
+			SDL_CONTROLLER_AXIS_RIGHTY,
+			SDL_CONTROLLER_AXIS_TRIGGERLEFT,
+			SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
+			SDL_CONTROLLER_AXIS_MAX
+		}
+
+
+		/* Scancodes based off USB keyboard page (0x07) */
+		public enum SDL_Scancode
+		{
+			SDL_SCANCODE_UNKNOWN = 0,
+
+			SDL_SCANCODE_A = 4,
+			SDL_SCANCODE_B = 5,
+			SDL_SCANCODE_C = 6,
+			SDL_SCANCODE_D = 7,
+			SDL_SCANCODE_E = 8,
+			SDL_SCANCODE_F = 9,
+			SDL_SCANCODE_G = 10,
+			SDL_SCANCODE_H = 11,
+			SDL_SCANCODE_I = 12,
+			SDL_SCANCODE_J = 13,
+			SDL_SCANCODE_K = 14,
+			SDL_SCANCODE_L = 15,
+			SDL_SCANCODE_M = 16,
+			SDL_SCANCODE_N = 17,
+			SDL_SCANCODE_O = 18,
+			SDL_SCANCODE_P = 19,
+			SDL_SCANCODE_Q = 20,
+			SDL_SCANCODE_R = 21,
+			SDL_SCANCODE_S = 22,
+			SDL_SCANCODE_T = 23,
+			SDL_SCANCODE_U = 24,
+			SDL_SCANCODE_V = 25,
+			SDL_SCANCODE_W = 26,
+			SDL_SCANCODE_X = 27,
+			SDL_SCANCODE_Y = 28,
+			SDL_SCANCODE_Z = 29,
+
+			SDL_SCANCODE_1 = 30,
+			SDL_SCANCODE_2 = 31,
+			SDL_SCANCODE_3 = 32,
+			SDL_SCANCODE_4 = 33,
+			SDL_SCANCODE_5 = 34,
+			SDL_SCANCODE_6 = 35,
+			SDL_SCANCODE_7 = 36,
+			SDL_SCANCODE_8 = 37,
+			SDL_SCANCODE_9 = 38,
+			SDL_SCANCODE_0 = 39,
+
+			SDL_SCANCODE_RETURN = 40,
+			SDL_SCANCODE_ESCAPE = 41,
+			SDL_SCANCODE_BACKSPACE = 42,
+			SDL_SCANCODE_TAB = 43,
+			SDL_SCANCODE_SPACE = 44,
+
+			SDL_SCANCODE_MINUS = 45,
+			SDL_SCANCODE_EQUALS = 46,
+			SDL_SCANCODE_LEFTBRACKET = 47,
+			SDL_SCANCODE_RIGHTBRACKET = 48,
+			SDL_SCANCODE_BACKSLASH = 49,
+			SDL_SCANCODE_NONUSHASH = 50,
+			SDL_SCANCODE_SEMICOLON = 51,
+			SDL_SCANCODE_APOSTROPHE = 52,
+			SDL_SCANCODE_GRAVE = 53,
+			SDL_SCANCODE_COMMA = 54,
+			SDL_SCANCODE_PERIOD = 55,
+			SDL_SCANCODE_SLASH = 56,
+
+			SDL_SCANCODE_CAPSLOCK = 57,
+
+			SDL_SCANCODE_F1 = 58,
+			SDL_SCANCODE_F2 = 59,
+			SDL_SCANCODE_F3 = 60,
+			SDL_SCANCODE_F4 = 61,
+			SDL_SCANCODE_F5 = 62,
+			SDL_SCANCODE_F6 = 63,
+			SDL_SCANCODE_F7 = 64,
+			SDL_SCANCODE_F8 = 65,
+			SDL_SCANCODE_F9 = 66,
+			SDL_SCANCODE_F10 = 67,
+			SDL_SCANCODE_F11 = 68,
+			SDL_SCANCODE_F12 = 69,
+
+			SDL_SCANCODE_PRINTSCREEN = 70,
+			SDL_SCANCODE_SCROLLLOCK = 71,
+			SDL_SCANCODE_PAUSE = 72,
+			SDL_SCANCODE_INSERT = 73,
+			SDL_SCANCODE_HOME = 74,
+			SDL_SCANCODE_PAGEUP = 75,
+			SDL_SCANCODE_DELETE = 76,
+			SDL_SCANCODE_END = 77,
+			SDL_SCANCODE_PAGEDOWN = 78,
+			SDL_SCANCODE_RIGHT = 79,
+			SDL_SCANCODE_LEFT = 80,
+			SDL_SCANCODE_DOWN = 81,
+			SDL_SCANCODE_UP = 82,
+
+			SDL_SCANCODE_NUMLOCKCLEAR = 83,
+			SDL_SCANCODE_KP_DIVIDE = 84,
+			SDL_SCANCODE_KP_MULTIPLY = 85,
+			SDL_SCANCODE_KP_MINUS = 86,
+			SDL_SCANCODE_KP_PLUS = 87,
+			SDL_SCANCODE_KP_ENTER = 88,
+			SDL_SCANCODE_KP_1 = 89,
+			SDL_SCANCODE_KP_2 = 90,
+			SDL_SCANCODE_KP_3 = 91,
+			SDL_SCANCODE_KP_4 = 92,
+			SDL_SCANCODE_KP_5 = 93,
+			SDL_SCANCODE_KP_6 = 94,
+			SDL_SCANCODE_KP_7 = 95,
+			SDL_SCANCODE_KP_8 = 96,
+			SDL_SCANCODE_KP_9 = 97,
+			SDL_SCANCODE_KP_0 = 98,
+			SDL_SCANCODE_KP_PERIOD = 99,
+
+			SDL_SCANCODE_NONUSBACKSLASH = 100,
+			SDL_SCANCODE_APPLICATION = 101,
+			SDL_SCANCODE_POWER = 102,
+			SDL_SCANCODE_KP_EQUALS = 103,
+			SDL_SCANCODE_F13 = 104,
+			SDL_SCANCODE_F14 = 105,
+			SDL_SCANCODE_F15 = 106,
+			SDL_SCANCODE_F16 = 107,
+			SDL_SCANCODE_F17 = 108,
+			SDL_SCANCODE_F18 = 109,
+			SDL_SCANCODE_F19 = 110,
+			SDL_SCANCODE_F20 = 111,
+			SDL_SCANCODE_F21 = 112,
+			SDL_SCANCODE_F22 = 113,
+			SDL_SCANCODE_F23 = 114,
+			SDL_SCANCODE_F24 = 115,
+			SDL_SCANCODE_EXECUTE = 116,
+			SDL_SCANCODE_HELP = 117,
+			SDL_SCANCODE_MENU = 118,
+			SDL_SCANCODE_SELECT = 119,
+			SDL_SCANCODE_STOP = 120,
+			SDL_SCANCODE_AGAIN = 121,
+			SDL_SCANCODE_UNDO = 122,
+			SDL_SCANCODE_CUT = 123,
+			SDL_SCANCODE_COPY = 124,
+			SDL_SCANCODE_PASTE = 125,
+			SDL_SCANCODE_FIND = 126,
+			SDL_SCANCODE_MUTE = 127,
+			SDL_SCANCODE_VOLUMEUP = 128,
+			SDL_SCANCODE_VOLUMEDOWN = 129,
+			/* not sure whether there's a reason to enable these */
+			/*	SDL_SCANCODE_LOCKINGCAPSLOCK = 130,  */
+			/*	SDL_SCANCODE_LOCKINGNUMLOCK = 131, */
+			/*	SDL_SCANCODE_LOCKINGSCROLLLOCK = 132, */
+			SDL_SCANCODE_KP_COMMA = 133,
+			SDL_SCANCODE_KP_EQUALSAS400 = 134,
+
+			SDL_SCANCODE_INTERNATIONAL1 = 135,
+			SDL_SCANCODE_INTERNATIONAL2 = 136,
+			SDL_SCANCODE_INTERNATIONAL3 = 137,
+			SDL_SCANCODE_INTERNATIONAL4 = 138,
+			SDL_SCANCODE_INTERNATIONAL5 = 139,
+			SDL_SCANCODE_INTERNATIONAL6 = 140,
+			SDL_SCANCODE_INTERNATIONAL7 = 141,
+			SDL_SCANCODE_INTERNATIONAL8 = 142,
+			SDL_SCANCODE_INTERNATIONAL9 = 143,
+			SDL_SCANCODE_LANG1 = 144,
+			SDL_SCANCODE_LANG2 = 145,
+			SDL_SCANCODE_LANG3 = 146,
+			SDL_SCANCODE_LANG4 = 147,
+			SDL_SCANCODE_LANG5 = 148,
+			SDL_SCANCODE_LANG6 = 149,
+			SDL_SCANCODE_LANG7 = 150,
+			SDL_SCANCODE_LANG8 = 151,
+			SDL_SCANCODE_LANG9 = 152,
+
+			SDL_SCANCODE_ALTERASE = 153,
+			SDL_SCANCODE_SYSREQ = 154,
+			SDL_SCANCODE_CANCEL = 155,
+			SDL_SCANCODE_CLEAR = 156,
+			SDL_SCANCODE_PRIOR = 157,
+			SDL_SCANCODE_RETURN2 = 158,
+			SDL_SCANCODE_SEPARATOR = 159,
+			SDL_SCANCODE_OUT = 160,
+			SDL_SCANCODE_OPER = 161,
+			SDL_SCANCODE_CLEARAGAIN = 162,
+			SDL_SCANCODE_CRSEL = 163,
+			SDL_SCANCODE_EXSEL = 164,
+
+			SDL_SCANCODE_KP_00 = 176,
+			SDL_SCANCODE_KP_000 = 177,
+			SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
+			SDL_SCANCODE_DECIMALSEPARATOR = 179,
+			SDL_SCANCODE_CURRENCYUNIT = 180,
+			SDL_SCANCODE_CURRENCYSUBUNIT = 181,
+			SDL_SCANCODE_KP_LEFTPAREN = 182,
+			SDL_SCANCODE_KP_RIGHTPAREN = 183,
+			SDL_SCANCODE_KP_LEFTBRACE = 184,
+			SDL_SCANCODE_KP_RIGHTBRACE = 185,
+			SDL_SCANCODE_KP_TAB = 186,
+			SDL_SCANCODE_KP_BACKSPACE = 187,
+			SDL_SCANCODE_KP_A = 188,
+			SDL_SCANCODE_KP_B = 189,
+			SDL_SCANCODE_KP_C = 190,
+			SDL_SCANCODE_KP_D = 191,
+			SDL_SCANCODE_KP_E = 192,
+			SDL_SCANCODE_KP_F = 193,
+			SDL_SCANCODE_KP_XOR = 194,
+			SDL_SCANCODE_KP_POWER = 195,
+			SDL_SCANCODE_KP_PERCENT = 196,
+			SDL_SCANCODE_KP_LESS = 197,
+			SDL_SCANCODE_KP_GREATER = 198,
+			SDL_SCANCODE_KP_AMPERSAND = 199,
+			SDL_SCANCODE_KP_DBLAMPERSAND = 200,
+			SDL_SCANCODE_KP_VERTICALBAR = 201,
+			SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
+			SDL_SCANCODE_KP_COLON = 203,
+			SDL_SCANCODE_KP_HASH = 204,
+			SDL_SCANCODE_KP_SPACE = 205,
+			SDL_SCANCODE_KP_AT = 206,
+			SDL_SCANCODE_KP_EXCLAM = 207,
+			SDL_SCANCODE_KP_MEMSTORE = 208,
+			SDL_SCANCODE_KP_MEMRECALL = 209,
+			SDL_SCANCODE_KP_MEMCLEAR = 210,
+			SDL_SCANCODE_KP_MEMADD = 211,
+			SDL_SCANCODE_KP_MEMSUBTRACT = 212,
+			SDL_SCANCODE_KP_MEMMULTIPLY = 213,
+			SDL_SCANCODE_KP_MEMDIVIDE = 214,
+			SDL_SCANCODE_KP_PLUSMINUS = 215,
+			SDL_SCANCODE_KP_CLEAR = 216,
+			SDL_SCANCODE_KP_CLEARENTRY = 217,
+			SDL_SCANCODE_KP_BINARY = 218,
+			SDL_SCANCODE_KP_OCTAL = 219,
+			SDL_SCANCODE_KP_DECIMAL = 220,
+			SDL_SCANCODE_KP_HEXADECIMAL = 221,
+
+			SDL_SCANCODE_LCTRL = 224,
+			SDL_SCANCODE_LSHIFT = 225,
+			SDL_SCANCODE_LALT = 226,
+			SDL_SCANCODE_LGUI = 227,
+			SDL_SCANCODE_RCTRL = 228,
+			SDL_SCANCODE_RSHIFT = 229,
+			SDL_SCANCODE_RALT = 230,
+			SDL_SCANCODE_RGUI = 231,
+
+			SDL_SCANCODE_MODE = 257,
+
+			/* These come from the USB consumer page (0x0C) */
+			SDL_SCANCODE_AUDIONEXT = 258,
+			SDL_SCANCODE_AUDIOPREV = 259,
+			SDL_SCANCODE_AUDIOSTOP = 260,
+			SDL_SCANCODE_AUDIOPLAY = 261,
+			SDL_SCANCODE_AUDIOMUTE = 262,
+			SDL_SCANCODE_MEDIASELECT = 263,
+			SDL_SCANCODE_WWW = 264,
+			SDL_SCANCODE_MAIL = 265,
+			SDL_SCANCODE_CALCULATOR = 266,
+			SDL_SCANCODE_COMPUTER = 267,
+			SDL_SCANCODE_AC_SEARCH = 268,
+			SDL_SCANCODE_AC_HOME = 269,
+			SDL_SCANCODE_AC_BACK = 270,
+			SDL_SCANCODE_AC_FORWARD = 271,
+			SDL_SCANCODE_AC_STOP = 272,
+			SDL_SCANCODE_AC_REFRESH = 273,
+			SDL_SCANCODE_AC_BOOKMARKS = 274,
+
+			/* These come from other sources, and are mostly mac related */
+			SDL_SCANCODE_BRIGHTNESSDOWN = 275,
+			SDL_SCANCODE_BRIGHTNESSUP = 276,
+			SDL_SCANCODE_DISPLAYSWITCH = 277,
+			SDL_SCANCODE_KBDILLUMTOGGLE = 278,
+			SDL_SCANCODE_KBDILLUMDOWN = 279,
+			SDL_SCANCODE_KBDILLUMUP = 280,
+			SDL_SCANCODE_EJECT = 281,
+			SDL_SCANCODE_SLEEP = 282,
+
+			SDL_SCANCODE_APP1 = 283,
+			SDL_SCANCODE_APP2 = 284,
+
+			/* This is not a key, simply marks the number of scancodes
+			 * so that you know how big to make your arrays. */
+			SDL_NUM_SCANCODES = 512
+		}
+
+		public const int SDLK_SCANCODE_MASK = (1 << 30);
+
+		public enum SDL_Keycode
+		{
+			SDLK_UNKNOWN = 0,
+
+			SDLK_RETURN = '\r',
+			SDLK_ESCAPE = 27,
+			// '\033'
+			SDLK_BACKSPACE = '\b',
+			SDLK_TAB = '\t',
+			SDLK_SPACE = ' ',
+			SDLK_EXCLAIM = '!',
+			SDLK_QUOTEDBL = '"',
+			SDLK_HASH = '#',
+			SDLK_PERCENT = '%',
+			SDLK_DOLLAR = '$',
+			SDLK_AMPERSAND = '&',
+			SDLK_QUOTE = '\'',
+			SDLK_LEFTPAREN = '(',
+			SDLK_RIGHTPAREN = ')',
+			SDLK_ASTERISK = '*',
+			SDLK_PLUS = '+',
+			SDLK_COMMA = ',',
+			SDLK_MINUS = '-',
+			SDLK_PERIOD = '.',
+			SDLK_SLASH = '/',
+			SDLK_0 = '0',
+			SDLK_1 = '1',
+			SDLK_2 = '2',
+			SDLK_3 = '3',
+			SDLK_4 = '4',
+			SDLK_5 = '5',
+			SDLK_6 = '6',
+			SDLK_7 = '7',
+			SDLK_8 = '8',
+			SDLK_9 = '9',
+			SDLK_COLON = ':',
+			SDLK_SEMICOLON = ';',
+			SDLK_LESS = '<',
+			SDLK_EQUALS = '=',
+			SDLK_GREATER = '>',
+			SDLK_QUESTION = '?',
+			SDLK_AT = '@',
+			/*
+			Skip uppercase letters
+			*/
+			SDLK_LEFTBRACKET = '[',
+			SDLK_BACKSLASH = '\\',
+			SDLK_RIGHTBRACKET = ']',
+			SDLK_CARET = '^',
+			SDLK_UNDERSCORE = '_',
+			SDLK_BACKQUOTE = '`',
+			SDLK_a = 'a',
+			SDLK_b = 'b',
+			SDLK_c = 'c',
+			SDLK_d = 'd',
+			SDLK_e = 'e',
+			SDLK_f = 'f',
+			SDLK_g = 'g',
+			SDLK_h = 'h',
+			SDLK_i = 'i',
+			SDLK_j = 'j',
+			SDLK_k = 'k',
+			SDLK_l = 'l',
+			SDLK_m = 'm',
+			SDLK_n = 'n',
+			SDLK_o = 'o',
+			SDLK_p = 'p',
+			SDLK_q = 'q',
+			SDLK_r = 'r',
+			SDLK_s = 's',
+			SDLK_t = 't',
+			SDLK_u = 'u',
+			SDLK_v = 'v',
+			SDLK_w = 'w',
+			SDLK_x = 'x',
+			SDLK_y = 'y',
+			SDLK_z = 'z',
+
+			SDLK_CAPSLOCK = (int)SDL_Scancode.SDL_SCANCODE_CAPSLOCK | SDLK_SCANCODE_MASK,
+
+			SDLK_F1 = (int)SDL_Scancode.SDL_SCANCODE_F1 | SDLK_SCANCODE_MASK,
+			SDLK_F2 = (int)SDL_Scancode.SDL_SCANCODE_F2 | SDLK_SCANCODE_MASK,
+			SDLK_F3 = (int)SDL_Scancode.SDL_SCANCODE_F3 | SDLK_SCANCODE_MASK,
+			SDLK_F4 = (int)SDL_Scancode.SDL_SCANCODE_F4 | SDLK_SCANCODE_MASK,
+			SDLK_F5 = (int)SDL_Scancode.SDL_SCANCODE_F5 | SDLK_SCANCODE_MASK,
+			SDLK_F6 = (int)SDL_Scancode.SDL_SCANCODE_F6 | SDLK_SCANCODE_MASK,
+			SDLK_F7 = (int)SDL_Scancode.SDL_SCANCODE_F7 | SDLK_SCANCODE_MASK,
+			SDLK_F8 = (int)SDL_Scancode.SDL_SCANCODE_F8 | SDLK_SCANCODE_MASK,
+			SDLK_F9 = (int)SDL_Scancode.SDL_SCANCODE_F9 | SDLK_SCANCODE_MASK,
+			SDLK_F10 = (int)SDL_Scancode.SDL_SCANCODE_F10 | SDLK_SCANCODE_MASK,
+			SDLK_F11 = (int)SDL_Scancode.SDL_SCANCODE_F11 | SDLK_SCANCODE_MASK,
+			SDLK_F12 = (int)SDL_Scancode.SDL_SCANCODE_F12 | SDLK_SCANCODE_MASK,
+
+			SDLK_PRINTSCREEN = (int)SDL_Scancode.SDL_SCANCODE_PRINTSCREEN | SDLK_SCANCODE_MASK,
+			SDLK_SCROLLLOCK = (int)SDL_Scancode.SDL_SCANCODE_SCROLLLOCK | SDLK_SCANCODE_MASK,
+			SDLK_PAUSE = (int)SDL_Scancode.SDL_SCANCODE_PAUSE | SDLK_SCANCODE_MASK,
+			SDLK_INSERT = (int)SDL_Scancode.SDL_SCANCODE_INSERT | SDLK_SCANCODE_MASK,
+			SDLK_HOME = (int)SDL_Scancode.SDL_SCANCODE_HOME | SDLK_SCANCODE_MASK,
+			SDLK_PAGEUP = (int)SDL_Scancode.SDL_SCANCODE_PAGEUP | SDLK_SCANCODE_MASK,
+			SDLK_DELETE = 127,
+			SDLK_END = (int)SDL_Scancode.SDL_SCANCODE_END | SDLK_SCANCODE_MASK,
+			SDLK_PAGEDOWN = (int)SDL_Scancode.SDL_SCANCODE_PAGEDOWN | SDLK_SCANCODE_MASK,
+			SDLK_RIGHT = (int)SDL_Scancode.SDL_SCANCODE_RIGHT | SDLK_SCANCODE_MASK,
+			SDLK_LEFT = (int)SDL_Scancode.SDL_SCANCODE_LEFT | SDLK_SCANCODE_MASK,
+			SDLK_DOWN = (int)SDL_Scancode.SDL_SCANCODE_DOWN | SDLK_SCANCODE_MASK,
+			SDLK_UP = (int)SDL_Scancode.SDL_SCANCODE_UP | SDLK_SCANCODE_MASK,
+
+			SDLK_NUMLOCKCLEAR = (int)SDL_Scancode.SDL_SCANCODE_NUMLOCKCLEAR | SDLK_SCANCODE_MASK,
+			SDLK_KP_DIVIDE = (int)SDL_Scancode.SDL_SCANCODE_KP_DIVIDE | SDLK_SCANCODE_MASK,
+			SDLK_KP_MULTIPLY = (int)SDL_Scancode.SDL_SCANCODE_KP_MULTIPLY | SDLK_SCANCODE_MASK,
+			SDLK_KP_MINUS = (int)SDL_Scancode.SDL_SCANCODE_KP_MINUS | SDLK_SCANCODE_MASK,
+			SDLK_KP_PLUS = (int)SDL_Scancode.SDL_SCANCODE_KP_PLUS | SDLK_SCANCODE_MASK,
+			SDLK_KP_ENTER = (int)SDL_Scancode.SDL_SCANCODE_KP_ENTER | SDLK_SCANCODE_MASK,
+			SDLK_KP_1 = (int)SDL_Scancode.SDL_SCANCODE_KP_1 | SDLK_SCANCODE_MASK,
+			SDLK_KP_2 = (int)SDL_Scancode.SDL_SCANCODE_KP_2 | SDLK_SCANCODE_MASK,
+			SDLK_KP_3 = (int)SDL_Scancode.SDL_SCANCODE_KP_3 | SDLK_SCANCODE_MASK,
+			SDLK_KP_4 = (int)SDL_Scancode.SDL_SCANCODE_KP_4 | SDLK_SCANCODE_MASK,
+			SDLK_KP_5 = (int)SDL_Scancode.SDL_SCANCODE_KP_5 | SDLK_SCANCODE_MASK,
+			SDLK_KP_6 = (int)SDL_Scancode.SDL_SCANCODE_KP_6 | SDLK_SCANCODE_MASK,
+			SDLK_KP_7 = (int)SDL_Scancode.SDL_SCANCODE_KP_7 | SDLK_SCANCODE_MASK,
+			SDLK_KP_8 = (int)SDL_Scancode.SDL_SCANCODE_KP_8 | SDLK_SCANCODE_MASK,
+			SDLK_KP_9 = (int)SDL_Scancode.SDL_SCANCODE_KP_9 | SDLK_SCANCODE_MASK,
+			SDLK_KP_0 = (int)SDL_Scancode.SDL_SCANCODE_KP_0 | SDLK_SCANCODE_MASK,
+			SDLK_KP_PERIOD = (int)SDL_Scancode.SDL_SCANCODE_KP_PERIOD | SDLK_SCANCODE_MASK,
+
+			SDLK_APPLICATION = (int)SDL_Scancode.SDL_SCANCODE_APPLICATION | SDLK_SCANCODE_MASK,
+			SDLK_POWER = (int)SDL_Scancode.SDL_SCANCODE_POWER | SDLK_SCANCODE_MASK,
+			SDLK_KP_EQUALS = (int)SDL_Scancode.SDL_SCANCODE_KP_EQUALS | SDLK_SCANCODE_MASK,
+			SDLK_F13 = (int)SDL_Scancode.SDL_SCANCODE_F13 | SDLK_SCANCODE_MASK,
+			SDLK_F14 = (int)SDL_Scancode.SDL_SCANCODE_F14 | SDLK_SCANCODE_MASK,
+			SDLK_F15 = (int)SDL_Scancode.SDL_SCANCODE_F15 | SDLK_SCANCODE_MASK,
+			SDLK_F16 = (int)SDL_Scancode.SDL_SCANCODE_F16 | SDLK_SCANCODE_MASK,
+			SDLK_F17 = (int)SDL_Scancode.SDL_SCANCODE_F17 | SDLK_SCANCODE_MASK,
+			SDLK_F18 = (int)SDL_Scancode.SDL_SCANCODE_F18 | SDLK_SCANCODE_MASK,
+			SDLK_F19 = (int)SDL_Scancode.SDL_SCANCODE_F19 | SDLK_SCANCODE_MASK,
+			SDLK_F20 = (int)SDL_Scancode.SDL_SCANCODE_F20 | SDLK_SCANCODE_MASK,
+			SDLK_F21 = (int)SDL_Scancode.SDL_SCANCODE_F21 | SDLK_SCANCODE_MASK,
+			SDLK_F22 = (int)SDL_Scancode.SDL_SCANCODE_F22 | SDLK_SCANCODE_MASK,
+			SDLK_F23 = (int)SDL_Scancode.SDL_SCANCODE_F23 | SDLK_SCANCODE_MASK,
+			SDLK_F24 = (int)SDL_Scancode.SDL_SCANCODE_F24 | SDLK_SCANCODE_MASK,
+			SDLK_EXECUTE = (int)SDL_Scancode.SDL_SCANCODE_EXECUTE | SDLK_SCANCODE_MASK,
+			SDLK_HELP = (int)SDL_Scancode.SDL_SCANCODE_HELP | SDLK_SCANCODE_MASK,
+			SDLK_MENU = (int)SDL_Scancode.SDL_SCANCODE_MENU | SDLK_SCANCODE_MASK,
+			SDLK_SELECT = (int)SDL_Scancode.SDL_SCANCODE_SELECT | SDLK_SCANCODE_MASK,
+			SDLK_STOP = (int)SDL_Scancode.SDL_SCANCODE_STOP | SDLK_SCANCODE_MASK,
+			SDLK_AGAIN = (int)SDL_Scancode.SDL_SCANCODE_AGAIN | SDLK_SCANCODE_MASK,
+			SDLK_UNDO = (int)SDL_Scancode.SDL_SCANCODE_UNDO | SDLK_SCANCODE_MASK,
+			SDLK_CUT = (int)SDL_Scancode.SDL_SCANCODE_CUT | SDLK_SCANCODE_MASK,
+			SDLK_COPY = (int)SDL_Scancode.SDL_SCANCODE_COPY | SDLK_SCANCODE_MASK,
+			SDLK_PASTE = (int)SDL_Scancode.SDL_SCANCODE_PASTE | SDLK_SCANCODE_MASK,
+			SDLK_FIND = (int)SDL_Scancode.SDL_SCANCODE_FIND | SDLK_SCANCODE_MASK,
+			SDLK_MUTE = (int)SDL_Scancode.SDL_SCANCODE_MUTE | SDLK_SCANCODE_MASK,
+			SDLK_VOLUMEUP = (int)SDL_Scancode.SDL_SCANCODE_VOLUMEUP | SDLK_SCANCODE_MASK,
+			SDLK_VOLUMEDOWN = (int)SDL_Scancode.SDL_SCANCODE_VOLUMEDOWN | SDLK_SCANCODE_MASK,
+			SDLK_KP_COMMA = (int)SDL_Scancode.SDL_SCANCODE_KP_COMMA | SDLK_SCANCODE_MASK,
+			SDLK_KP_EQUALSAS400 =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_EQUALSAS400 | SDLK_SCANCODE_MASK,
+
+			SDLK_ALTERASE = (int)SDL_Scancode.SDL_SCANCODE_ALTERASE | SDLK_SCANCODE_MASK,
+			SDLK_SYSREQ = (int)SDL_Scancode.SDL_SCANCODE_SYSREQ | SDLK_SCANCODE_MASK,
+			SDLK_CANCEL = (int)SDL_Scancode.SDL_SCANCODE_CANCEL | SDLK_SCANCODE_MASK,
+			SDLK_CLEAR = (int)SDL_Scancode.SDL_SCANCODE_CLEAR | SDLK_SCANCODE_MASK,
+			SDLK_PRIOR = (int)SDL_Scancode.SDL_SCANCODE_PRIOR | SDLK_SCANCODE_MASK,
+			SDLK_RETURN2 = (int)SDL_Scancode.SDL_SCANCODE_RETURN2 | SDLK_SCANCODE_MASK,
+			SDLK_SEPARATOR = (int)SDL_Scancode.SDL_SCANCODE_SEPARATOR | SDLK_SCANCODE_MASK,
+			SDLK_OUT = (int)SDL_Scancode.SDL_SCANCODE_OUT | SDLK_SCANCODE_MASK,
+			SDLK_OPER = (int)SDL_Scancode.SDL_SCANCODE_OPER | SDLK_SCANCODE_MASK,
+			SDLK_CLEARAGAIN = (int)SDL_Scancode.SDL_SCANCODE_CLEARAGAIN | SDLK_SCANCODE_MASK,
+			SDLK_CRSEL = (int)SDL_Scancode.SDL_SCANCODE_CRSEL | SDLK_SCANCODE_MASK,
+			SDLK_EXSEL = (int)SDL_Scancode.SDL_SCANCODE_EXSEL | SDLK_SCANCODE_MASK,
+
+			SDLK_KP_00 = (int)SDL_Scancode.SDL_SCANCODE_KP_00 | SDLK_SCANCODE_MASK,
+			SDLK_KP_000 = (int)SDL_Scancode.SDL_SCANCODE_KP_000 | SDLK_SCANCODE_MASK,
+			SDLK_THOUSANDSSEPARATOR =
+			(int)SDL_Scancode.SDL_SCANCODE_THOUSANDSSEPARATOR | SDLK_SCANCODE_MASK,
+			SDLK_DECIMALSEPARATOR =
+			(int)SDL_Scancode.SDL_SCANCODE_DECIMALSEPARATOR | SDLK_SCANCODE_MASK,
+			SDLK_CURRENCYUNIT = (int)SDL_Scancode.SDL_SCANCODE_CURRENCYUNIT | SDLK_SCANCODE_MASK,
+			SDLK_CURRENCYSUBUNIT =
+			(int)SDL_Scancode.SDL_SCANCODE_CURRENCYSUBUNIT | SDLK_SCANCODE_MASK,
+			SDLK_KP_LEFTPAREN = (int)SDL_Scancode.SDL_SCANCODE_KP_LEFTPAREN | SDLK_SCANCODE_MASK,
+			SDLK_KP_RIGHTPAREN = (int)SDL_Scancode.SDL_SCANCODE_KP_RIGHTPAREN | SDLK_SCANCODE_MASK,
+			SDLK_KP_LEFTBRACE = (int)SDL_Scancode.SDL_SCANCODE_KP_LEFTBRACE | SDLK_SCANCODE_MASK,
+			SDLK_KP_RIGHTBRACE = (int)SDL_Scancode.SDL_SCANCODE_KP_RIGHTBRACE | SDLK_SCANCODE_MASK,
+			SDLK_KP_TAB = (int)SDL_Scancode.SDL_SCANCODE_KP_TAB | SDLK_SCANCODE_MASK,
+			SDLK_KP_BACKSPACE = (int)SDL_Scancode.SDL_SCANCODE_KP_BACKSPACE | SDLK_SCANCODE_MASK,
+			SDLK_KP_A = (int)SDL_Scancode.SDL_SCANCODE_KP_A | SDLK_SCANCODE_MASK,
+			SDLK_KP_B = (int)SDL_Scancode.SDL_SCANCODE_KP_B | SDLK_SCANCODE_MASK,
+			SDLK_KP_C = (int)SDL_Scancode.SDL_SCANCODE_KP_C | SDLK_SCANCODE_MASK,
+			SDLK_KP_D = (int)SDL_Scancode.SDL_SCANCODE_KP_D | SDLK_SCANCODE_MASK,
+			SDLK_KP_E = (int)SDL_Scancode.SDL_SCANCODE_KP_E | SDLK_SCANCODE_MASK,
+			SDLK_KP_F = (int)SDL_Scancode.SDL_SCANCODE_KP_F | SDLK_SCANCODE_MASK,
+			SDLK_KP_XOR = (int)SDL_Scancode.SDL_SCANCODE_KP_XOR | SDLK_SCANCODE_MASK,
+			SDLK_KP_POWER = (int)SDL_Scancode.SDL_SCANCODE_KP_POWER | SDLK_SCANCODE_MASK,
+			SDLK_KP_PERCENT = (int)SDL_Scancode.SDL_SCANCODE_KP_PERCENT | SDLK_SCANCODE_MASK,
+			SDLK_KP_LESS = (int)SDL_Scancode.SDL_SCANCODE_KP_LESS | SDLK_SCANCODE_MASK,
+			SDLK_KP_GREATER = (int)SDL_Scancode.SDL_SCANCODE_KP_GREATER | SDLK_SCANCODE_MASK,
+			SDLK_KP_AMPERSAND = (int)SDL_Scancode.SDL_SCANCODE_KP_AMPERSAND | SDLK_SCANCODE_MASK,
+			SDLK_KP_DBLAMPERSAND =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_DBLAMPERSAND | SDLK_SCANCODE_MASK,
+			SDLK_KP_VERTICALBAR =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_VERTICALBAR | SDLK_SCANCODE_MASK,
+			SDLK_KP_DBLVERTICALBAR =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_DBLVERTICALBAR | SDLK_SCANCODE_MASK,
+			SDLK_KP_COLON = (int)SDL_Scancode.SDL_SCANCODE_KP_COLON | SDLK_SCANCODE_MASK,
+			SDLK_KP_HASH = (int)SDL_Scancode.SDL_SCANCODE_KP_HASH | SDLK_SCANCODE_MASK,
+			SDLK_KP_SPACE = (int)SDL_Scancode.SDL_SCANCODE_KP_SPACE | SDLK_SCANCODE_MASK,
+			SDLK_KP_AT = (int)SDL_Scancode.SDL_SCANCODE_KP_AT | SDLK_SCANCODE_MASK,
+			SDLK_KP_EXCLAM = (int)SDL_Scancode.SDL_SCANCODE_KP_EXCLAM | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMSTORE = (int)SDL_Scancode.SDL_SCANCODE_KP_MEMSTORE | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMRECALL = (int)SDL_Scancode.SDL_SCANCODE_KP_MEMRECALL | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMCLEAR = (int)SDL_Scancode.SDL_SCANCODE_KP_MEMCLEAR | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMADD = (int)SDL_Scancode.SDL_SCANCODE_KP_MEMADD | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMSUBTRACT =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_MEMSUBTRACT | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMMULTIPLY =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_MEMMULTIPLY | SDLK_SCANCODE_MASK,
+			SDLK_KP_MEMDIVIDE = (int)SDL_Scancode.SDL_SCANCODE_KP_MEMDIVIDE | SDLK_SCANCODE_MASK,
+			SDLK_KP_PLUSMINUS = (int)SDL_Scancode.SDL_SCANCODE_KP_PLUSMINUS | SDLK_SCANCODE_MASK,
+			SDLK_KP_CLEAR = (int)SDL_Scancode.SDL_SCANCODE_KP_CLEAR | SDLK_SCANCODE_MASK,
+			SDLK_KP_CLEARENTRY = (int)SDL_Scancode.SDL_SCANCODE_KP_CLEARENTRY | SDLK_SCANCODE_MASK,
+			SDLK_KP_BINARY = (int)SDL_Scancode.SDL_SCANCODE_KP_BINARY | SDLK_SCANCODE_MASK,
+			SDLK_KP_OCTAL = (int)SDL_Scancode.SDL_SCANCODE_KP_OCTAL | SDLK_SCANCODE_MASK,
+			SDLK_KP_DECIMAL = (int)SDL_Scancode.SDL_SCANCODE_KP_DECIMAL | SDLK_SCANCODE_MASK,
+			SDLK_KP_HEXADECIMAL =
+			(int)SDL_Scancode.SDL_SCANCODE_KP_HEXADECIMAL | SDLK_SCANCODE_MASK,
+
+			SDLK_LCTRL = (int)SDL_Scancode.SDL_SCANCODE_LCTRL | SDLK_SCANCODE_MASK,
+			SDLK_LSHIFT = (int)SDL_Scancode.SDL_SCANCODE_LSHIFT | SDLK_SCANCODE_MASK,
+			SDLK_LALT = (int)SDL_Scancode.SDL_SCANCODE_LALT | SDLK_SCANCODE_MASK,
+			SDLK_LGUI = (int)SDL_Scancode.SDL_SCANCODE_LGUI | SDLK_SCANCODE_MASK,
+			SDLK_RCTRL = (int)SDL_Scancode.SDL_SCANCODE_RCTRL | SDLK_SCANCODE_MASK,
+			SDLK_RSHIFT = (int)SDL_Scancode.SDL_SCANCODE_RSHIFT | SDLK_SCANCODE_MASK,
+			SDLK_RALT = (int)SDL_Scancode.SDL_SCANCODE_RALT | SDLK_SCANCODE_MASK,
+			SDLK_RGUI = (int)SDL_Scancode.SDL_SCANCODE_RGUI | SDLK_SCANCODE_MASK,
+
+			SDLK_MODE = (int)SDL_Scancode.SDL_SCANCODE_MODE | SDLK_SCANCODE_MASK,
+
+			SDLK_AUDIONEXT = (int)SDL_Scancode.SDL_SCANCODE_AUDIONEXT | SDLK_SCANCODE_MASK,
+			SDLK_AUDIOPREV = (int)SDL_Scancode.SDL_SCANCODE_AUDIOPREV | SDLK_SCANCODE_MASK,
+			SDLK_AUDIOSTOP = (int)SDL_Scancode.SDL_SCANCODE_AUDIOSTOP | SDLK_SCANCODE_MASK,
+			SDLK_AUDIOPLAY = (int)SDL_Scancode.SDL_SCANCODE_AUDIOPLAY | SDLK_SCANCODE_MASK,
+			SDLK_AUDIOMUTE = (int)SDL_Scancode.SDL_SCANCODE_AUDIOMUTE | SDLK_SCANCODE_MASK,
+			SDLK_MEDIASELECT = (int)SDL_Scancode.SDL_SCANCODE_MEDIASELECT | SDLK_SCANCODE_MASK,
+			SDLK_WWW = (int)SDL_Scancode.SDL_SCANCODE_WWW | SDLK_SCANCODE_MASK,
+			SDLK_MAIL = (int)SDL_Scancode.SDL_SCANCODE_MAIL | SDLK_SCANCODE_MASK,
+			SDLK_CALCULATOR = (int)SDL_Scancode.SDL_SCANCODE_CALCULATOR | SDLK_SCANCODE_MASK,
+			SDLK_COMPUTER = (int)SDL_Scancode.SDL_SCANCODE_COMPUTER | SDLK_SCANCODE_MASK,
+			SDLK_AC_SEARCH = (int)SDL_Scancode.SDL_SCANCODE_AC_SEARCH | SDLK_SCANCODE_MASK,
+			SDLK_AC_HOME = (int)SDL_Scancode.SDL_SCANCODE_AC_HOME | SDLK_SCANCODE_MASK,
+			SDLK_AC_BACK = (int)SDL_Scancode.SDL_SCANCODE_AC_BACK | SDLK_SCANCODE_MASK,
+			SDLK_AC_FORWARD = (int)SDL_Scancode.SDL_SCANCODE_AC_FORWARD | SDLK_SCANCODE_MASK,
+			SDLK_AC_STOP = (int)SDL_Scancode.SDL_SCANCODE_AC_STOP | SDLK_SCANCODE_MASK,
+			SDLK_AC_REFRESH = (int)SDL_Scancode.SDL_SCANCODE_AC_REFRESH | SDLK_SCANCODE_MASK,
+			SDLK_AC_BOOKMARKS = (int)SDL_Scancode.SDL_SCANCODE_AC_BOOKMARKS | SDLK_SCANCODE_MASK,
+
+			SDLK_BRIGHTNESSDOWN =
+			(int)SDL_Scancode.SDL_SCANCODE_BRIGHTNESSDOWN | SDLK_SCANCODE_MASK,
+			SDLK_BRIGHTNESSUP = (int)SDL_Scancode.SDL_SCANCODE_BRIGHTNESSUP | SDLK_SCANCODE_MASK,
+			SDLK_DISPLAYSWITCH = (int)SDL_Scancode.SDL_SCANCODE_DISPLAYSWITCH | SDLK_SCANCODE_MASK,
+			SDLK_KBDILLUMTOGGLE =
+			(int)SDL_Scancode.SDL_SCANCODE_KBDILLUMTOGGLE | SDLK_SCANCODE_MASK,
+			SDLK_KBDILLUMDOWN = (int)SDL_Scancode.SDL_SCANCODE_KBDILLUMDOWN | SDLK_SCANCODE_MASK,
+			SDLK_KBDILLUMUP = (int)SDL_Scancode.SDL_SCANCODE_KBDILLUMUP | SDLK_SCANCODE_MASK,
+			SDLK_EJECT = (int)SDL_Scancode.SDL_SCANCODE_EJECT | SDLK_SCANCODE_MASK,
+			SDLK_SLEEP = (int)SDL_Scancode.SDL_SCANCODE_SLEEP | SDLK_SCANCODE_MASK
+		}
+	}
+
+}

+ 20 - 0
Script/AtomicNET/AtomicNET/IPC/IPC.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class IPC : AObject
+    {
+        public void SendEventToBroker(string eventType, ScriptVariantMap eventData)
+        {
+            csb_Atomic_IPC_SendEventToBrokerWithEventData(nativeInstance, eventType, eventData == null ? IntPtr.Zero : eventData.nativeInstance);
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern void csb_Atomic_IPC_SendEventToBrokerWithEventData(IntPtr self, string eventType, IntPtr variantMap);
+
+    }
+
+}

+ 13 - 0
Script/AtomicNET/AtomicNET/Math/BoundingBox.cs

@@ -0,0 +1,13 @@
+
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+
+[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct BoundingBox
+{
+}
+
+}

+ 24 - 0
Script/AtomicNET/AtomicNET/Math/Color.cs

@@ -0,0 +1,24 @@
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+
+[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct Color
+	{
+		public Color (float r, float g, float b, float a = 1.0f)
+		{
+			this.r = r;
+			this.g = g;
+			this.b = b;
+			this.a = a;
+		}
+
+		public float r;
+		public float g;
+		public float b;
+		public float a;
+
+	}
+}

+ 22 - 0
Script/AtomicNET/AtomicNET/Math/IntRect.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+
+	[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+	public struct IntRect
+	{
+		/// Left coordinate.
+    int left;
+    /// Top coordinate.
+    int top;
+    /// Right coordinate.
+    int right;
+    /// Bottom coordinate.
+    int bottom;
+
+	}
+
+}

+ 943 - 0
Script/AtomicNET/AtomicNET/Math/IntVector2.cs

@@ -0,0 +1,943 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+namespace AtomicEngine
+{
+	/// <summary>Represents a 2D vector using two single-precision inting-point numbers.</summary>
+	/// <remarks>
+	/// The IntVector2 structure is suitable for interoperation with unmanaged code requiring two consecutive ints.
+	/// </remarks>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct IntVector2 : IEquatable<IntVector2>
+	{
+		#region Fields
+
+		/// <summary>
+		/// The X component of the IntVector2.
+		/// </summary>
+		public int X;
+
+		/// <summary>
+		/// The Y component of the IntVector2.
+		/// </summary>
+		public int Y;
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs a new IntVector2.
+		/// </summary>
+		/// <param name="x">The x coordinate of the net IntVector2.</param>
+		/// <param name="y">The y coordinate of the net IntVector2.</param>
+		public IntVector2(int x, int y)
+		{
+			X = x;
+			Y = y;
+		}
+
+		/// <summary>
+		/// Constructs a new IntVector2 from the given IntVector2.
+		/// </summary>
+		/// <param name="v">The IntVector2 to copy components from.</param>
+		[Obsolete]
+		public IntVector2(IntVector2 v)
+		{
+			X = v.X;
+			Y = v.Y;
+		}
+
+		/// <summary>
+		/// Constructs a new IntVector2 from the given Vector2.
+		/// </summary>
+		/// <param name="v">The IntVector2 to copy components from.</param>
+		[Obsolete]
+		public IntVector2(Vector2 v)
+		{
+			X = (int) v.X;
+			Y = (int) v.Y;
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Instance
+
+		#region public void Add()
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(IntVector2 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+		}
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(ref IntVector2 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+		}
+
+		#endregion public void Add()
+
+		#region public void Sub()
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(IntVector2 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+		}
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(ref IntVector2 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+		}
+
+		#endregion public void Sub()
+
+		#region public void Mult()
+
+		/// <summary>Multiply this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Mult(int f)
+		{
+			this.X *= f;
+			this.Y *= f;
+		}
+
+		#endregion public void Mult()
+
+		#region public void Div()
+
+		/// <summary>Divide this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public void Div(int f)
+		{
+			this.X =  X / f;
+			this.Y = Y / f;
+		}
+
+		#endregion public void Div()
+
+		#region public int Length
+
+		/// <summary>
+		/// Gets the length (magnitude) of the vector.
+		/// </summary>
+		/// <see cref="LengthFast"/>
+		/// <seealso cref="LengthSquared"/>
+		public int Length
+		{
+			get
+			{
+				return (int)System.Math.Sqrt(X * X + Y * Y);
+			}
+		}
+
+		#endregion
+
+		#region public int LengthFast
+
+		/// <summary>
+		/// Gets an approximation of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property uses an approximation of the square root function to calculate vector magnitude, with
+		/// an upper error bound of 0.001.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthSquared"/>
+		public int LengthFast
+		{
+			get
+			{
+				return (int) (1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y));
+			}
+		}
+
+		#endregion
+
+		#region public int LengthSquared
+
+		/// <summary>
+		/// Gets the square of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property avoids the costly square root operation required by the Length property. This makes it more suitable
+		/// for comparisons.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthFast"/>
+		public int LengthSquared
+		{
+			get
+			{
+				return X * X + Y * Y;
+			}
+		}
+
+		#endregion
+
+		#region public IntVector2 PerpendicularRight
+
+		/// <summary>
+		/// Gets the perpendicular vector on the right side of this vector.
+		/// </summary>
+		public IntVector2 PerpendicularRight
+		{
+			get
+			{
+				return new IntVector2(Y, -X);
+			}
+		}
+
+		#endregion
+
+		#region public IntVector2 PerpendicularLeft
+
+		/// <summary>
+		/// Gets the perpendicular vector on the left side of this vector.
+		/// </summary>
+		public IntVector2 PerpendicularLeft
+		{
+			get
+			{
+				return new IntVector2(-Y, X);
+			}
+		}
+
+		#endregion
+
+		#region public void Normalize()
+
+		/// <summary>
+		/// Scales the IntVector2 to unit length.
+		/// </summary>
+		public void Normalize()
+		{
+			X =  X / this.Length;
+			Y *= Y / this.Length;
+		}
+
+		#endregion
+
+		#region public void NormalizeFast()
+
+		/// <summary>
+		/// Scales the IntVector2 to approximately unit length.
+		/// </summary>
+		public void NormalizeFast()
+		{
+			int scale = (int) MathHelper.InverseSqrtFast(X * X + Y * Y);
+			X *= scale;
+			Y *= scale;
+		}
+
+		#endregion
+
+		#region public void Scale()
+
+		/// <summary>
+		/// Scales the current IntVector2 by the given amounts.
+		/// </summary>
+		/// <param name="sx">The scale of the X component.</param>
+		/// <param name="sy">The scale of the Y component.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(int sx, int sy)
+		{
+			this.X = X * sx;
+			this.Y = Y * sy;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(IntVector2 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(ref IntVector2 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+		}
+
+		#endregion public void Scale()
+
+		#endregion
+
+		#region Static
+
+		#region Fields
+
+		/// <summary>
+		/// Defines a unit-length IntVector2 that points towards the X-axis.
+		/// </summary>
+		public static readonly IntVector2 UnitX = new IntVector2(1, 0);
+
+		/// <summary>
+		/// Defines a unit-length IntVector2 that points towards the Y-axis.
+		/// </summary>
+		public static readonly IntVector2 UnitY = new IntVector2(0, 1);
+
+		/// <summary>
+		/// Defines a zero-length IntVector2.
+		/// </summary>
+		public static readonly IntVector2 Zero = new IntVector2(0, 0);
+
+		/// <summary>
+		/// Defines an instance with all components set to 1.
+		/// </summary>
+		public static readonly IntVector2 One = new IntVector2(1, 1);
+
+		/// <summary>
+		/// Defines the size of the IntVector2 struct in bytes.
+		/// </summary>
+		public static readonly int SizeInBytes = Marshal.SizeOf(new IntVector2());
+
+		#endregion
+
+		#region Add
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <returns>Result of operation.</returns>
+		public static IntVector2 Add(IntVector2 a, IntVector2 b)
+		{
+			Add(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <param name="result">Result of operation.</param>
+		public static void Add(ref IntVector2 a, ref IntVector2 b, out IntVector2 result)
+		{
+			result = new IntVector2(a.X + b.X, a.Y + b.Y);
+		}
+
+		#endregion
+
+		#region Subtract
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		public static IntVector2 Subtract(IntVector2 a, IntVector2 b)
+		{
+			Subtract(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		public static void Subtract(ref IntVector2 a, ref IntVector2 b, out IntVector2 result)
+		{
+			result = new IntVector2(a.X - b.X, a.Y - b.Y);
+		}
+
+		#endregion
+
+		#region Multiply
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static IntVector2 Multiply(IntVector2 vector, int scale)
+		{
+			Multiply(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref IntVector2 vector, int scale, out IntVector2 result)
+		{
+			result = new IntVector2(vector.X * scale, vector.Y * scale);
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static IntVector2 Multiply(IntVector2 vector, IntVector2 scale)
+		{
+			Multiply(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref IntVector2 vector, ref IntVector2 scale, out IntVector2 result)
+		{
+			result = new IntVector2(vector.X * scale.X, vector.Y * scale.Y);
+		}
+
+		#endregion
+
+		#region Divide
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static IntVector2 Divide(IntVector2 vector, int scale)
+		{
+			Divide(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref IntVector2 vector, int scale, out IntVector2 result)
+		{
+			Multiply(ref vector, 1 / scale, out result);
+		}
+
+		/// <summary>
+		/// Divides a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static IntVector2 Divide(IntVector2 vector, IntVector2 scale)
+		{
+			Divide(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divide a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref IntVector2 vector, ref IntVector2 scale, out IntVector2 result)
+		{
+			result = new IntVector2(vector.X / scale.X, vector.Y / scale.Y);
+		}
+
+		#endregion
+
+		#region ComponentMin
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise minimum</returns>
+		public static IntVector2 ComponentMin(IntVector2 a, IntVector2 b)
+		{
+			a.X = a.X < b.X ? a.X : b.X;
+			a.Y = a.Y < b.Y ? a.Y : b.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise minimum</param>
+		public static void ComponentMin(ref IntVector2 a, ref IntVector2 b, out IntVector2 result)
+		{
+			result.X = a.X < b.X ? a.X : b.X;
+			result.Y = a.Y < b.Y ? a.Y : b.Y;
+		}
+
+		#endregion
+
+		#region ComponentMax
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise maximum</returns>
+		public static IntVector2 ComponentMax(IntVector2 a, IntVector2 b)
+		{
+			a.X = a.X > b.X ? a.X : b.X;
+			a.Y = a.Y > b.Y ? a.Y : b.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise maximum</param>
+		public static void ComponentMax(ref IntVector2 a, ref IntVector2 b, out IntVector2 result)
+		{
+			result.X = a.X > b.X ? a.X : b.X;
+			result.Y = a.Y > b.Y ? a.Y : b.Y;
+		}
+
+		#endregion
+
+		#region Min
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static IntVector2 Min(IntVector2 left, IntVector2 right)
+		{
+			return left.LengthSquared < right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Max
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static IntVector2 Max(IntVector2 left, IntVector2 right)
+		{
+			return left.LengthSquared >= right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Clamp
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <returns>The clamped vector</returns>
+		public static IntVector2 Clamp(IntVector2 vec, IntVector2 min, IntVector2 max)
+		{
+			vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			return vec;
+		}
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <param name="result">The clamped vector</param>
+		public static void Clamp(ref IntVector2 vec, ref IntVector2 min, ref IntVector2 max, out IntVector2 result)
+		{
+			result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+		}
+
+		#endregion
+
+		#region Normalize
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static IntVector2 Normalize(IntVector2 vec)
+		{
+			vec.X = vec.X / vec.Length;
+			vec.Y = vec.Y / vec.Length;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void Normalize(ref IntVector2 vec, out IntVector2 result)
+		{
+			result.X = vec.X / vec.Length;
+			result.Y = vec.Y / vec.Length;
+		}
+
+		#endregion
+
+		#region NormalizeFast
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static IntVector2 NormalizeFast(IntVector2 vec)
+		{
+			int scale = (int) MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y);
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void NormalizeFast(ref IntVector2 vec, out IntVector2 result)
+		{
+			int scale = (int) MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y);
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+		}
+
+		#endregion
+
+		#region Dot
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The dot product of the two inputs</returns>
+		public static int Dot(IntVector2 left, IntVector2 right)
+		{
+			return left.X * right.X + left.Y * right.Y;
+		}
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <param name="result">The dot product of the two inputs</param>
+		public static void Dot(ref IntVector2 left, ref IntVector2 right, out int result)
+		{
+			result = left.X * right.X + left.Y * right.Y;
+		}
+
+		#endregion
+
+		#region Lerp
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <returns>a when blend=0, b when blend=1, and a linear combination otherwise</returns>
+		public static IntVector2 Lerp(IntVector2 a, IntVector2 b, int blend)
+		{
+			a.X = blend * (b.X - a.X) + a.X;
+			a.Y = blend * (b.Y - a.Y) + a.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <param name="result">a when blend=0, b when blend=1, and a linear combination otherwise</param>
+		public static void Lerp(ref IntVector2 a, ref IntVector2 b, int blend, out IntVector2 result)
+		{
+			result.X = blend * (b.X - a.X) + a.X;
+			result.Y = blend * (b.Y - a.Y) + a.Y;
+		}
+
+		#endregion
+
+		#region Barycentric
+
+		/// <summary>
+		/// Interpolate 3 Vectors using Barycentric coordinates
+		/// </summary>
+		/// <param name="a">First input Vector</param>
+		/// <param name="b">Second input Vector</param>
+		/// <param name="c">Third input Vector</param>
+		/// <param name="u">First Barycentric Coordinate</param>
+		/// <param name="v">Second Barycentric Coordinate</param>
+		/// <returns>a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</returns>
+		public static IntVector2 BaryCentric(IntVector2 a, IntVector2 b, IntVector2 c, int u, int v)
+		{
+			return a + u * (b - a) + v * (c - a);
+		}
+
+		/// <summary>Interpolate 3 Vectors using Barycentric coordinates</summary>
+		/// <param name="a">First input Vector.</param>
+		/// <param name="b">Second input Vector.</param>
+		/// <param name="c">Third input Vector.</param>
+		/// <param name="u">First Barycentric Coordinate.</param>
+		/// <param name="v">Second Barycentric Coordinate.</param>
+		/// <param name="result">Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</param>
+		public static void BaryCentric(ref IntVector2 a, ref IntVector2 b, ref IntVector2 c, int u, int v, out IntVector2 result)
+		{
+			result = a; // copy
+
+			IntVector2 temp = b; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, u, out temp);
+			Add(ref result, ref temp, out result);
+
+			temp = c; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, v, out temp);
+			Add(ref result, ref temp, out result);
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Adds the specified instances.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>Result of addition.</returns>
+		public static IntVector2 operator +(IntVector2 left, IntVector2 right)
+		{
+			left.X += right.X;
+			left.Y += right.Y;
+			return left;
+		}
+
+		/// <summary>
+		/// Subtracts the specified instances.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>Result of subtraction.</returns>
+		public static IntVector2 operator -(IntVector2 left, IntVector2 right)
+		{
+			left.X -= right.X;
+			left.Y -= right.Y;
+			return left;
+		}
+
+		/// <summary>
+		/// Negates the specified instance.
+		/// </summary>
+		/// <param name="vec">Operand.</param>
+		/// <returns>Result of negation.</returns>
+		public static IntVector2 operator -(IntVector2 vec)
+		{
+			vec.X = -vec.X;
+			vec.Y = -vec.Y;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies the specified instance by a scalar.
+		/// </summary>
+		/// <param name="vec">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of multiplication.</returns>
+		public static IntVector2 operator *(IntVector2 vec, int scale)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies the specified instance by a scalar.
+		/// </summary>
+		/// <param name="scale">Left operand.</param>
+		/// <param name="vec">Right operand.</param>
+		/// <returns>Result of multiplication.</returns>
+		public static IntVector2 operator *(int scale, IntVector2 vec)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Divides the specified instance by a scalar.
+		/// </summary>
+		/// <param name="vec">Left operand</param>
+		/// <param name="scale">Right operand</param>
+		/// <returns>Result of the division.</returns>
+		public static IntVector2 operator /(IntVector2 vec, int scale)
+		{
+			vec.X = vec.X / scale;
+			vec.Y = vec.Y / scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Compares the specified instances for equality.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>True if both instances are equal; false otherwise.</returns>
+		public static bool operator ==(IntVector2 left, IntVector2 right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares the specified instances for inequality.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>True if both instances are not equal; false otherwise.</returns>
+		public static bool operator !=(IntVector2 left, IntVector2 right)
+		{
+			return !left.Equals(right);
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current IntVector2.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("({0}, {1})", X, Y);
+		}
+
+		#endregion
+
+		#region public override int GetHashCode()
+
+		/// <summary>
+		/// Returns the hashcode for this instance.
+		/// </summary>
+		/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return X.GetHashCode() ^ Y.GetHashCode();
+		}
+
+		#endregion
+
+		#region public override bool Equals(object obj)
+
+		/// <summary>
+		/// Indicates whether this instance and a specified object are equal.
+		/// </summary>
+		/// <param name="obj">The object to compare to.</param>
+		/// <returns>True if the instances are equal; false otherwise.</returns>
+		public override bool Equals(object obj)
+		{
+			if (!(obj is IntVector2))
+				return false;
+
+			return this.Equals((IntVector2)obj);
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<IntVector2> Members
+
+		/// <summary>Indicates whether the current vector is equal to another vector.</summary>
+		/// <param name="other">A vector to compare with this vector.</param>
+		/// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
+		public bool Equals(IntVector2 other)
+		{
+			return
+				X == other.X &&
+				Y == other.Y;
+		}
+
+		#endregion
+
+		public bool IsEmpty => X == 0 && Y == 0;
+	}
+}

+ 313 - 0
Script/AtomicNET/AtomicNET/Math/MathHelper.cs

@@ -0,0 +1,313 @@
+#region --- License ---
+/* Licensed under the MIT/X11 license.
+ * Copyright (c) 2006-2008 the OpenTK Team.
+ * This notice may not be removed from any source distribution.
+ * See license.txt for licensing detailed licensing details.
+ * 
+ * Contributions by Andy Gill, James Talton and Georg Wächter.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AtomicEngine
+{
+	/// <summary>
+	/// Contains common mathematical functions and constants.
+	/// </summary>
+	public static class MathHelper
+	{
+		#region Fields
+
+		/// <summary>
+		/// Defines the value of Pi as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float Pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930382f;
+
+		/// <summary>
+		/// Defines the value of Pi divided by two as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float PiOver2 = Pi / 2;
+
+		/// <summary>
+		/// Defines the value of Pi divided by three as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float PiOver3 = Pi / 3;
+
+		/// <summary>
+		/// Definesthe value of  Pi divided by four as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float PiOver4 = Pi / 4;
+
+		/// <summary>
+		/// Defines the value of Pi divided by six as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float PiOver6 = Pi / 6;
+
+		/// <summary>
+		/// Defines the value of Pi multiplied by two as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float TwoPi = 2 * Pi;
+
+		/// <summary>
+		/// Defines the value of Pi multiplied by 3 and divided by two as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float ThreePiOver2 = 3 * Pi / 2;
+
+		/// <summary>
+		/// Defines the value of E as a <see cref="System.Single"/>.
+		/// </summary>
+		public const float E = 2.71828182845904523536f;
+
+		/// <summary>
+		/// Defines the base-10 logarithm of E.
+		/// </summary>
+		public const float Log10E = 0.434294482f;
+
+		/// <summary>
+		/// Defines the base-2 logarithm of E.
+		/// </summary>
+		public const float Log2E = 1.442695041f;
+
+		public static readonly float DTORF = Pi / 180.0f;
+
+		#endregion
+
+		#region Public Members
+
+		#region NextPowerOfTwo
+
+		/// <summary>
+		/// Returns the next power of two that is larger than the specified number.
+		/// </summary>
+		/// <param name="n">The specified number.</param>
+		/// <returns>The next power of two.</returns>
+		public static long NextPowerOfTwo(long n)
+		{
+			if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
+			return (long)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
+		}
+
+		/// <summary>
+		/// Returns the next power of two that is larger than the specified number.
+		/// </summary>
+		/// <param name="n">The specified number.</param>
+		/// <returns>The next power of two.</returns>
+		public static int NextPowerOfTwo(int n)
+		{
+			if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
+			return (int)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
+		}
+
+		/// <summary>
+		/// Returns the next power of two that is larger than the specified number.
+		/// </summary>
+		/// <param name="n">The specified number.</param>
+		/// <returns>The next power of two.</returns>
+		public static float NextPowerOfTwo(float n)
+		{
+			if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
+			return (float)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
+		}
+
+		/// <summary>
+		/// Returns the next power of two that is larger than the specified number.
+		/// </summary>
+		/// <param name="n">The specified number.</param>
+		/// <returns>The next power of two.</returns>
+		public static double NextPowerOfTwo(double n)
+		{
+			if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
+			return System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
+		}
+
+		#endregion
+
+		#region Factorial
+
+		/// <summary>Calculates the factorial of a given natural number.
+		/// </summary>
+		/// <param name="n">The number.</param>
+		/// <returns>n!</returns>
+		public static long Factorial(int n)
+		{
+			long result = 1;
+
+			for (; n > 1; n--)
+				result *= n;
+
+			return result;
+		}
+
+		#endregion
+
+		#region BinomialCoefficient
+
+		/// <summary>
+		/// Calculates the binomial coefficient <paramref name="n"/> above <paramref name="k"/>.
+		/// </summary>
+		/// <param name="n">The n.</param>
+		/// <param name="k">The k.</param>
+		/// <returns>n! / (k! * (n - k)!)</returns>
+		public static long BinomialCoefficient(int n, int k)
+		{
+			return Factorial(n) / (Factorial(k) * Factorial(n - k));
+		}
+
+		#endregion
+
+		#region InverseSqrtFast
+
+		/// <summary>
+		/// Returns an approximation of the inverse square root of left number.
+		/// </summary>
+		/// <param name="x">A number.</param>
+		/// <returns>An approximation of the inverse square root of the specified number, with an upper error bound of 0.001</returns>
+		/// <remarks>
+		/// This is an improved implementation of the the method known as Carmack's inverse square root
+		/// which is found in the Quake III source code. This implementation comes from
+		/// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see
+		/// http://www.beyond3d.com/content/articles/8/
+		/// </remarks>
+		public static float InverseSqrtFast(float x)
+		{
+			unsafe
+			{
+				float xhalf = 0.5f * x;
+				int i = *(int*)&x;              // Read bits as integer.
+				i = 0x5f375a86 - (i >> 1);      // Make an initial guess for Newton-Raphson approximation
+				x = *(float*)&i;                // Convert bits back to float
+				x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step.
+				return x;
+			}
+		}
+
+		/// <summary>
+		/// Returns an approximation of the inverse square root of left number.
+		/// </summary>
+		/// <param name="x">A number.</param>
+		/// <returns>An approximation of the inverse square root of the specified number, with an upper error bound of 0.001</returns>
+		/// <remarks>
+		/// This is an improved implementation of the the method known as Carmack's inverse square root
+		/// which is found in the Quake III source code. This implementation comes from
+		/// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see
+		/// http://www.beyond3d.com/content/articles/8/
+		/// </remarks>
+		public static double InverseSqrtFast(double x)
+		{
+			return InverseSqrtFast((float)x);
+			// TODO: The following code is wrong. Fix it, to improve precision.
+#if false
+			unsafe
+			{
+				double xhalf = 0.5f * x;
+				int i = *(int*)&x;              // Read bits as integer.
+				i = 0x5f375a86 - (i >> 1);      // Make an initial guess for Newton-Raphson approximation
+				x = *(float*)&i;                // Convert bits back to float
+				x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step.
+				return x;
+			}
+#endif
+		}
+
+		#endregion
+
+		#region DegreesToRadians
+
+		/// <summary>
+		/// Convert degrees to radians
+		/// </summary>
+		/// <param name="degrees">An angle in degrees</param>
+		/// <returns>The angle expressed in radians</returns>
+		public static float DegreesToRadians(float degrees)
+		{
+			const float degToRad = (float)System.Math.PI / 180.0f;
+			return degrees * degToRad;
+		}
+
+		/// <summary>
+		/// Convert radians to degrees
+		/// </summary>
+		/// <param name="radians">An angle in radians</param>
+		/// <returns>The angle expressed in degrees</returns>
+		public static float RadiansToDegrees(float radians)
+		{
+			const float radToDeg = 180.0f / (float)System.Math.PI;
+			return radians * radToDeg;
+		}
+
+		/// <summary>
+		/// Convert degrees to radians
+		/// </summary>
+		/// <param name="degrees">An angle in degrees</param>
+		/// <returns>The angle expressed in radians</returns>
+		public static double DegreesToRadians(double degrees)
+		{
+			const double degToRad = System.Math.PI / 180.0;
+			return degrees * degToRad;
+		}
+
+		/// <summary>
+		/// Convert radians to degrees
+		/// </summary>
+		/// <param name="radians">An angle in radians</param>
+		/// <returns>The angle expressed in degrees</returns>
+		public static double RadiansToDegrees(double radians)
+		{
+			const double radToDeg = 180.0 / System.Math.PI;
+			return radians * radToDeg;
+		}
+
+		#endregion
+
+		#region Swap
+
+		/// <summary>
+		/// Swaps two double values.
+		/// </summary>
+		/// <param name="a">The first value.</param>
+		/// <param name="b">The second value.</param>
+		public static void Swap(ref double a, ref double b)
+		{
+			double temp = a;
+			a = b;
+			b = temp;
+		}
+
+		/// <summary>
+		/// Swaps two float values.
+		/// </summary>
+		/// <param name="a">The first value.</param>
+		/// <param name="b">The second value.</param>
+		public static void Swap(ref float a, ref float b)
+		{
+			float temp = a;
+			a = b;
+			b = temp;
+		}
+
+		#endregion
+
+		#endregion
+
+		/// <summary>
+		/// Clamp a float to a range.
+		/// </summary>
+		public static float Clamp(float value, float min, float max)
+		{
+			if (value < min)
+				return min;
+			else if (value > max)
+				return max;
+			else
+				return value;
+		}
+
+		public static float Lerp(float lhs, float rhs, float t)
+		{
+			return lhs * (1.0f - t) + rhs * t;
+		}
+	}
+}

+ 796 - 0
Script/AtomicNET/AtomicNET/Math/Matrix3.cs

@@ -0,0 +1,796 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+	// Todo: Remove this warning when the code goes public.
+	#pragma warning disable 3019
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Matrix3 : IEquatable<Matrix3>
+	{
+		#region Fields & Access
+
+		/// <summary>Row 0, Column 0</summary>
+		public float R0C0;
+
+		/// <summary>Row 0, Column 1</summary>
+		public float R0C1;
+
+		/// <summary>Row 0, Column 2</summary>
+		public float R0C2;
+
+		/// <summary>Row 1, Column 0</summary>
+		public float R1C0;
+
+		/// <summary>Row 1, Column 1</summary>
+		public float R1C1;
+
+		/// <summary>Row 1, Column 2</summary>
+		public float R1C2;
+
+		/// <summary>Row 2, Column 0</summary>
+		public float R2C0;
+
+		/// <summary>Row 2, Column 1</summary>
+		public float R2C1;
+
+		/// <summary>Row 2, Column 2</summary>
+		public float R2C2;
+
+		/// <summary>Gets the component at the given row and column in the matrix.</summary>
+		/// <param name="row">The row of the matrix.</param>
+		/// <param name="column">The column of the matrix.</param>
+		/// <returns>The component at the given row and column in the matrix.</returns>
+		public float this[int row, int column]
+		{
+			get
+			{
+				switch( row )
+				{
+					case 0:
+						switch (column)
+						{
+							case 0: return R0C0;
+							case 1: return R0C1;
+							case 2: return R0C2;
+						}
+						break;
+
+					case 1:
+						switch (column)
+						{
+							case 0: return R1C0;
+							case 1: return R1C1;
+							case 2: return R1C2;
+						}
+						break;
+
+					case 2:
+						switch (column)
+						{
+							case 0: return R2C0;
+							case 1: return R2C1;
+							case 2: return R2C2;
+						}
+						break;
+				}
+
+				throw new IndexOutOfRangeException();
+			}
+			set
+			{
+				switch( row )
+				{
+					case 0:
+						switch (column)
+						{
+							case 0: R0C0 = value; return;
+							case 1: R0C1 = value; return;
+							case 2: R0C2 = value; return;
+						}
+						break;
+
+					case 1:
+						switch (column)
+						{
+							case 0: R1C0 = value; return;
+							case 1: R1C1 = value; return;
+							case 2: R1C2 = value; return;
+						}
+						break;
+
+					case 2:
+						switch (column)
+						{
+							case 0: R2C0 = value; return;
+							case 1: R2C1 = value; return;
+							case 2: R2C2 = value; return;
+						}
+						break;
+				}
+
+				throw new IndexOutOfRangeException();
+			}
+		}
+
+		/// <summary>Gets the component at the index into the matrix.</summary>
+		/// <param name="index">The index into the components of the matrix.</param>
+		/// <returns>The component at the given index into the matrix.</returns>
+		public float this[int index]
+		{
+			get
+			{
+				switch (index)
+				{
+					case 0: return R0C0;
+					case 1: return R0C1;
+					case 2: return R0C2;
+					case 3: return R1C0;
+					case 4: return R1C1;
+					case 5: return R1C2;
+					case 6: return R2C0;
+					case 7: return R2C1;
+					case 8: return R2C2;
+					default: throw new IndexOutOfRangeException();
+				}
+			}
+			set
+			{
+				switch (index)
+				{
+					case 0: R0C0 = value; return;
+					case 1: R0C1 = value; return;
+					case 2: R0C2 = value; return;
+					case 3: R1C0 = value; return;
+					case 4: R1C1 = value; return;
+					case 5: R1C2 = value; return;
+					case 6: R2C0 = value; return;
+					case 7: R2C1 = value; return;
+					case 8: R2C2 = value; return;
+					default: throw new IndexOutOfRangeException();
+				}
+			}
+		}
+
+		/// <summary>Converts the matrix into an IntPtr.</summary>
+		/// <param name="matrix">The matrix to convert.</param>
+		/// <returns>An IntPtr for the matrix.</returns>
+		public static explicit operator IntPtr(Matrix3 matrix)
+		{
+			unsafe
+			{
+				return (IntPtr)(&matrix.R0C0);
+			}
+		}
+
+		/// <summary>Converts the matrix into left float*.</summary>
+		/// <param name="matrix">The matrix to convert.</param>
+		/// <returns>A float* for the matrix.</returns>
+		[CLSCompliant(false)]
+		unsafe public static explicit operator float*(Matrix3 matrix)
+		{
+			return &matrix.R0C0;
+		}
+
+		/// <summary>Converts the matrix into an array of floats.</summary>
+		/// <param name="matrix">The matrix to convert.</param>
+		/// <returns>An array of floats for the matrix.</returns>
+		public static explicit operator float[](Matrix3 matrix)
+		{
+			return new float[9]
+			{
+				matrix.R0C0,
+				matrix.R0C1,
+				matrix.R0C2,
+				matrix.R1C0,
+				matrix.R1C1,
+				matrix.R1C2,
+				matrix.R2C0,
+				matrix.R2C1,
+				matrix.R2C2
+			};
+		}
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>Constructs left matrix with the same components as the given matrix.</summary>
+		/// <param name="vector">The matrix whose components to copy.</param>
+		public Matrix3(ref Matrix3 matrix)
+		{
+			this.R0C0 = matrix.R0C0;
+			this.R0C1 = matrix.R0C1;
+			this.R0C2 = matrix.R0C2;
+			this.R1C0 = matrix.R1C0;
+			this.R1C1 = matrix.R1C1;
+			this.R1C2 = matrix.R1C2;
+			this.R2C0 = matrix.R2C0;
+			this.R2C1 = matrix.R2C1;
+			this.R2C2 = matrix.R2C2;
+		}
+
+		/// <summary>Constructs left matrix with the given values.</summary>
+		/// <param name="r0c0">The value for row 0 column 0.</param>
+		/// <param name="r0c1">The value for row 0 column 1.</param>
+		/// <param name="r0c2">The value for row 0 column 2.</param>
+		/// <param name="r1c0">The value for row 1 column 0.</param>
+		/// <param name="r1c1">The value for row 1 column 1.</param>
+		/// <param name="r1c2">The value for row 1 column 2.</param>
+		/// <param name="r2c0">The value for row 2 column 0.</param>
+		/// <param name="r2c1">The value for row 2 column 1.</param>
+		/// <param name="r2c2">The value for row 2 column 2.</param>
+		public Matrix3
+		(
+			float r0c0,
+			float r0c1,
+			float r0c2,
+			float r1c0,
+			float r1c1,
+			float r1c2,
+			float r2c0,
+			float r2c1,
+			float r2c2
+		)
+		{
+			this.R0C0 = r0c0;
+			this.R0C1 = r0c1;
+			this.R0C2 = r0c2;
+			this.R1C0 = r1c0;
+			this.R1C1 = r1c1;
+			this.R1C2 = r1c2;
+			this.R2C0 = r2c0;
+			this.R2C1 = r2c1;
+			this.R2C2 = r2c2;
+		}
+
+		/// <summary>Constructs left matrix from the given array of float-precision floating-point numbers.</summary>
+		/// <param name="floatArray">The array of floats for the components of the matrix.</param>
+		public Matrix3(float[] floatArray)
+		{
+			if (floatArray == null || floatArray.GetLength(0) < 9) throw new InvalidOperationException();
+
+			this.R0C0 = floatArray[0];
+			this.R0C1 = floatArray[1];
+			this.R0C2 = floatArray[2];
+			this.R1C0 = floatArray[3];
+			this.R1C1 = floatArray[4];
+			this.R1C2 = floatArray[5];
+			this.R2C0 = floatArray[6];
+			this.R2C1 = floatArray[7];
+			this.R2C2 = floatArray[8];
+		}
+
+		#endregion
+
+		#region Equality
+
+		/// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
+		/// <param name="matrix">The OpenTK.Matrix3 structure to compare with.</param>
+		/// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
+		[CLSCompliant(false)]
+		public bool Equals(Matrix3 matrix)
+		{
+			return
+				R0C0 == matrix.R0C0 &&
+				R0C1 == matrix.R0C1 &&
+				R0C2 == matrix.R0C2 &&
+				R1C0 == matrix.R1C0 &&
+				R1C1 == matrix.R1C1 &&
+				R1C2 == matrix.R1C2 &&
+				R2C0 == matrix.R2C0 &&
+				R2C1 == matrix.R2C1 &&
+				R2C2 == matrix.R2C2;
+		}
+
+		/// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
+		/// <param name="matrix">The OpenTK.Matrix3 structure to compare to.</param>
+		/// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
+		public bool Equals(ref Matrix3 matrix)
+		{
+			return
+				R0C0 == matrix.R0C0 &&
+				R0C1 == matrix.R0C1 &&
+				R0C2 == matrix.R0C2 &&
+				R1C0 == matrix.R1C0 &&
+				R1C1 == matrix.R1C1 &&
+				R1C2 == matrix.R1C2 &&
+				R2C0 == matrix.R2C0 &&
+				R2C1 == matrix.R2C1 &&
+				R2C2 == matrix.R2C2;
+		}
+
+		/// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
+		/// <param name="left">The left-hand operand.</param>
+		/// <param name="right">The right-hand operand.</param>
+		/// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
+		public static bool Equals(ref Matrix3 left, ref Matrix3 right)
+		{
+			return
+				left.R0C0 == right.R0C0 &&
+				left.R0C1 == right.R0C1 &&
+				left.R0C2 == right.R0C2 &&
+				left.R1C0 == right.R1C0 &&
+				left.R1C1 == right.R1C1 &&
+				left.R1C2 == right.R1C2 &&
+				left.R2C0 == right.R2C0 &&
+				left.R2C1 == right.R2C1 &&
+				left.R2C2 == right.R2C2;
+		}
+
+		/// <summary>Indicates whether the current matrix is approximately equal to another matrix.</summary>
+		/// <param name="matrix">The OpenTK.Matrix3 structure to compare with.</param>
+		/// <param name="tolerance">The limit below which the matrices are considered equal.</param>
+		/// <returns>true if the current matrix is approximately equal to the matrix parameter; otherwise, false.</returns>
+		public bool EqualsApprox(ref Matrix3 matrix, float tolerance)
+		{
+			return
+				System.Math.Abs(R0C0 - matrix.R0C0) <= tolerance &&
+				System.Math.Abs(R0C1 - matrix.R0C1) <= tolerance &&
+				System.Math.Abs(R0C2 - matrix.R0C2) <= tolerance &&
+				System.Math.Abs(R1C0 - matrix.R1C0) <= tolerance &&
+				System.Math.Abs(R1C1 - matrix.R1C1) <= tolerance &&
+				System.Math.Abs(R1C2 - matrix.R1C2) <= tolerance &&
+				System.Math.Abs(R2C0 - matrix.R2C0) <= tolerance &&
+				System.Math.Abs(R2C1 - matrix.R2C1) <= tolerance &&
+				System.Math.Abs(R2C2 - matrix.R2C2) <= tolerance;
+		}
+
+		/// <summary>Indicates whether the current matrix is approximately equal to another matrix.</summary>
+		/// <param name="left">The left-hand operand.</param>
+		/// <param name="right">The right-hand operand.</param>
+		/// <param name="tolerance">The limit below which the matrices are considered equal.</param>
+		/// <returns>true if the current matrix is approximately equal to the matrix parameter; otherwise, false.</returns>
+		public static bool EqualsApprox(ref Matrix3 left, ref Matrix3 right, float tolerance)
+		{
+			return
+				System.Math.Abs(left.R0C0 - right.R0C0) <= tolerance &&
+				System.Math.Abs(left.R0C1 - right.R0C1) <= tolerance &&
+				System.Math.Abs(left.R0C2 - right.R0C2) <= tolerance &&
+				System.Math.Abs(left.R1C0 - right.R1C0) <= tolerance &&
+				System.Math.Abs(left.R1C1 - right.R1C1) <= tolerance &&
+				System.Math.Abs(left.R1C2 - right.R1C2) <= tolerance &&
+				System.Math.Abs(left.R2C0 - right.R2C0) <= tolerance &&
+				System.Math.Abs(left.R2C1 - right.R2C1) <= tolerance &&
+				System.Math.Abs(left.R2C2 - right.R2C2) <= tolerance;
+		}
+
+		#endregion
+
+		#region Arithmetic Operators
+
+
+		/// <summary>Add left matrix to this matrix.</summary>
+		/// <param name="matrix">The matrix to add.</param>
+		public void Add(ref Matrix3 matrix)
+		{
+			R0C0 = R0C0 + matrix.R0C0;
+			R0C1 = R0C1 + matrix.R0C1;
+			R0C2 = R0C2 + matrix.R0C2;
+			R1C0 = R1C0 + matrix.R1C0;
+			R1C1 = R1C1 + matrix.R1C1;
+			R1C2 = R1C2 + matrix.R1C2;
+			R2C0 = R2C0 + matrix.R2C0;
+			R2C1 = R2C1 + matrix.R2C1;
+			R2C2 = R2C2 + matrix.R2C2;
+		}
+
+		/// <summary>Add left matrix to this matrix.</summary>
+		/// <param name="matrix">The matrix to add.</param>
+		/// <param name="result">The resulting matrix of the addition.</param>
+		public void Add(ref Matrix3 matrix, out Matrix3 result)
+		{
+			result.R0C0 = R0C0 + matrix.R0C0;
+			result.R0C1 = R0C1 + matrix.R0C1;
+			result.R0C2 = R0C2 + matrix.R0C2;
+			result.R1C0 = R1C0 + matrix.R1C0;
+			result.R1C1 = R1C1 + matrix.R1C1;
+			result.R1C2 = R1C2 + matrix.R1C2;
+			result.R2C0 = R2C0 + matrix.R2C0;
+			result.R2C1 = R2C1 + matrix.R2C1;
+			result.R2C2 = R2C2 + matrix.R2C2;
+		}
+
+		/// <summary>Add left matrix to left matrix.</summary>
+		/// <param name="matrix">The matrix on the matrix side of the equation.</param>
+		/// <param name="right">The matrix on the right side of the equation</param>
+		/// <param name="result">The resulting matrix of the addition.</param>
+		public static void Add(ref Matrix3 left, ref Matrix3 right, out Matrix3 result)
+		{
+			result.R0C0 = left.R0C0 + right.R0C0;
+			result.R0C1 = left.R0C1 + right.R0C1;
+			result.R0C2 = left.R0C2 + right.R0C2;
+			result.R1C0 = left.R1C0 + right.R1C0;
+			result.R1C1 = left.R1C1 + right.R1C1;
+			result.R1C2 = left.R1C2 + right.R1C2;
+			result.R2C0 = left.R2C0 + right.R2C0;
+			result.R2C1 = left.R2C1 + right.R2C1;
+			result.R2C2 = left.R2C2 + right.R2C2;
+		}
+
+
+		/// <summary>Subtract left matrix from this matrix.</summary>
+		/// <param name="matrix">The matrix to subtract.</param>
+		public void Subtract(ref Matrix3 matrix)
+		{
+			R0C0 = R0C0 + matrix.R0C0;
+			R0C1 = R0C1 + matrix.R0C1;
+			R0C2 = R0C2 + matrix.R0C2;
+			R1C0 = R1C0 + matrix.R1C0;
+			R1C1 = R1C1 + matrix.R1C1;
+			R1C2 = R1C2 + matrix.R1C2;
+			R2C0 = R2C0 + matrix.R2C0;
+			R2C1 = R2C1 + matrix.R2C1;
+			R2C2 = R2C2 + matrix.R2C2;
+		}
+
+		/// <summary>Subtract left matrix from this matrix.</summary>
+		/// <param name="matrix">The matrix to subtract.</param>
+		/// <param name="result">The resulting matrix of the subtraction.</param>
+		public void Subtract(ref Matrix3 matrix, out Matrix3 result)
+		{
+			result.R0C0 = R0C0 + matrix.R0C0;
+			result.R0C1 = R0C1 + matrix.R0C1;
+			result.R0C2 = R0C2 + matrix.R0C2;
+			result.R1C0 = R1C0 + matrix.R1C0;
+			result.R1C1 = R1C1 + matrix.R1C1;
+			result.R1C2 = R1C2 + matrix.R1C2;
+			result.R2C0 = R2C0 + matrix.R2C0;
+			result.R2C1 = R2C1 + matrix.R2C1;
+			result.R2C2 = R2C2 + matrix.R2C2;
+		}
+
+		/// <summary>Subtract left matrix from left matrix.</summary>
+		/// <param name="matrix">The matrix on the matrix side of the equation.</param>
+		/// <param name="right">The matrix on the right side of the equation</param>
+		/// <param name="result">The resulting matrix of the subtraction.</param>
+		public static void Subtract(ref Matrix3 left, ref Matrix3 right, out Matrix3 result)
+		{
+			result.R0C0 = left.R0C0 + right.R0C0;
+			result.R0C1 = left.R0C1 + right.R0C1;
+			result.R0C2 = left.R0C2 + right.R0C2;
+			result.R1C0 = left.R1C0 + right.R1C0;
+			result.R1C1 = left.R1C1 + right.R1C1;
+			result.R1C2 = left.R1C2 + right.R1C2;
+			result.R2C0 = left.R2C0 + right.R2C0;
+			result.R2C1 = left.R2C1 + right.R2C1;
+			result.R2C2 = left.R2C2 + right.R2C2;
+		}
+
+
+		/// <summary>Multiply left martix times this matrix.</summary>
+		/// <param name="matrix">The matrix to multiply.</param>
+		public void Multiply(ref Matrix3 matrix)
+		{
+			float r0c0 = matrix.R0C0 * R0C0 + matrix.R0C1 * R1C0 + matrix.R0C2 * R2C0;
+			float r0c1 = matrix.R0C0 * R0C1 + matrix.R0C1 * R1C1 + matrix.R0C2 * R2C1;
+			float r0c2 = matrix.R0C0 * R0C2 + matrix.R0C1 * R1C2 + matrix.R0C2 * R2C2;
+
+			float r1c0 = matrix.R1C0 * R0C0 + matrix.R1C1 * R1C0 + matrix.R1C2 * R2C0;
+			float r1c1 = matrix.R1C0 * R0C1 + matrix.R1C1 * R1C1 + matrix.R1C2 * R2C1;
+			float r1c2 = matrix.R1C0 * R0C2 + matrix.R1C1 * R1C2 + matrix.R1C2 * R2C2;
+
+			R2C0 = matrix.R2C0 * R0C0 + matrix.R2C1 * R1C0 + matrix.R2C2 * R2C0;
+			R2C1 = matrix.R2C0 * R0C1 + matrix.R2C1 * R1C1 + matrix.R2C2 * R2C1;
+			R2C2 = matrix.R2C0 * R0C2 + matrix.R2C1 * R1C2 + matrix.R2C2 * R2C2;
+
+
+			R0C0 = r0c0;
+			R0C1 = r0c1;
+			R0C2 = r0c2;
+
+			R1C0 = r1c0;
+			R1C1 = r1c1;
+			R1C2 = r1c2;
+		}
+
+		/// <summary>Multiply matrix times this matrix.</summary>
+		/// <param name="matrix">The matrix to multiply.</param>
+		/// <param name="result">The resulting matrix of the multiplication.</param>
+		public void Multiply(ref Matrix3 matrix, out Matrix3 result)
+		{
+			result.R0C0 = matrix.R0C0 * R0C0 + matrix.R0C1 * R1C0 + matrix.R0C2 * R2C0;
+			result.R0C1 = matrix.R0C0 * R0C1 + matrix.R0C1 * R1C1 + matrix.R0C2 * R2C1;
+			result.R0C2 = matrix.R0C0 * R0C2 + matrix.R0C1 * R1C2 + matrix.R0C2 * R2C2;
+			result.R1C0 = matrix.R1C0 * R0C0 + matrix.R1C1 * R1C0 + matrix.R1C2 * R2C0;
+			result.R1C1 = matrix.R1C0 * R0C1 + matrix.R1C1 * R1C1 + matrix.R1C2 * R2C1;
+			result.R1C2 = matrix.R1C0 * R0C2 + matrix.R1C1 * R1C2 + matrix.R1C2 * R2C2;
+			result.R2C0 = matrix.R2C0 * R0C0 + matrix.R2C1 * R1C0 + matrix.R2C2 * R2C0;
+			result.R2C1 = matrix.R2C0 * R0C1 + matrix.R2C1 * R1C1 + matrix.R2C2 * R2C1;
+			result.R2C2 = matrix.R2C0 * R0C2 + matrix.R2C1 * R1C2 + matrix.R2C2 * R2C2;
+		}
+
+		/// <summary>Multiply left matrix times left matrix.</summary>
+		/// <param name="matrix">The matrix on the matrix side of the equation.</param>
+		/// <param name="right">The matrix on the right side of the equation</param>
+		/// <param name="result">The resulting matrix of the multiplication.</param>
+		public static void Multiply(ref Matrix3 left, ref Matrix3 right, out Matrix3 result)
+		{
+			result.R0C0 = right.R0C0 * left.R0C0 + right.R0C1 * left.R1C0 + right.R0C2 * left.R2C0;
+			result.R0C1 = right.R0C0 * left.R0C1 + right.R0C1 * left.R1C1 + right.R0C2 * left.R2C1;
+			result.R0C2 = right.R0C0 * left.R0C2 + right.R0C1 * left.R1C2 + right.R0C2 * left.R2C2;
+			result.R1C0 = right.R1C0 * left.R0C0 + right.R1C1 * left.R1C0 + right.R1C2 * left.R2C0;
+			result.R1C1 = right.R1C0 * left.R0C1 + right.R1C1 * left.R1C1 + right.R1C2 * left.R2C1;
+			result.R1C2 = right.R1C0 * left.R0C2 + right.R1C1 * left.R1C2 + right.R1C2 * left.R2C2;
+			result.R2C0 = right.R2C0 * left.R0C0 + right.R2C1 * left.R1C0 + right.R2C2 * left.R2C0;
+			result.R2C1 = right.R2C0 * left.R0C1 + right.R2C1 * left.R1C1 + right.R2C2 * left.R2C1;
+			result.R2C2 = right.R2C0 * left.R0C2 + right.R2C1 * left.R1C2 + right.R2C2 * left.R2C2;
+		}
+
+
+		/// <summary>Multiply matrix times this matrix.</summary>
+		/// <param name="matrix">The matrix to multiply.</param>
+		public void Multiply(float scalar)
+		{
+			R0C0 = scalar * R0C0;
+			R0C1 = scalar * R0C1;
+			R0C2 = scalar * R0C2;
+			R1C0 = scalar * R1C0;
+			R1C1 = scalar * R1C1;
+			R1C2 = scalar * R1C2;
+			R2C0 = scalar * R2C0;
+			R2C1 = scalar * R2C1;
+			R2C2 = scalar * R2C2;
+		}
+
+		/// <summary>Multiply matrix times this matrix.</summary>
+		/// <param name="matrix">The matrix to multiply.</param>
+		/// <param name="result">The resulting matrix of the multiplication.</param>
+		public void Multiply(float scalar, out Matrix3 result)
+		{
+			result.R0C0 = scalar * R0C0;
+			result.R0C1 = scalar * R0C1;
+			result.R0C2 = scalar * R0C2;
+			result.R1C0 = scalar * R1C0;
+			result.R1C1 = scalar * R1C1;
+			result.R1C2 = scalar * R1C2;
+			result.R2C0 = scalar * R2C0;
+			result.R2C1 = scalar * R2C1;
+			result.R2C2 = scalar * R2C2;
+		}
+
+		/// <summary>Multiply left matrix times left matrix.</summary>
+		/// <param name="matrix">The matrix on the matrix side of the equation.</param>
+		/// <param name="right">The matrix on the right side of the equation</param>
+		/// <param name="result">The resulting matrix of the multiplication.</param>
+		public static void Multiply(ref Matrix3 matrix, float scalar, out Matrix3 result)
+		{
+			result.R0C0 = scalar * matrix.R0C0;
+			result.R0C1 = scalar * matrix.R0C1;
+			result.R0C2 = scalar * matrix.R0C2;
+			result.R1C0 = scalar * matrix.R1C0;
+			result.R1C1 = scalar * matrix.R1C1;
+			result.R1C2 = scalar * matrix.R1C2;
+			result.R2C0 = scalar * matrix.R2C0;
+			result.R2C1 = scalar * matrix.R2C1;
+			result.R2C2 = scalar * matrix.R2C2;
+		}
+
+
+		#endregion
+
+		#region Functions
+
+		public float Determinant
+		{
+			get
+			{
+				return R0C0 * R1C1 * R2C2 - R0C0 * R1C2 * R2C1 - R0C1 * R1C0 * R2C2 + R0C2 * R1C0 * R2C1 + R0C1 * R1C2 * R2C0 - R0C2 * R1C1 * R2C0;
+			}
+		}
+
+		public void Transpose()
+		{
+			MathHelper.Swap(ref R0C1, ref R1C0);
+			MathHelper.Swap(ref R0C2, ref R2C0);
+			MathHelper.Swap(ref R1C2, ref R2C1);
+		}
+		public void Transpose(out Matrix3 result)
+		{
+			result.R0C0 = R0C0;
+			result.R0C1 = R1C0;
+			result.R0C2 = R2C0;
+			result.R1C0 = R0C1;
+			result.R1C1 = R1C1;
+			result.R1C2 = R2C1;
+			result.R2C0 = R0C2;
+			result.R2C1 = R1C2;
+			result.R2C2 = R2C2;
+		}
+		public static void Transpose(ref Matrix3 matrix, out Matrix3 result)
+		{
+			result.R0C0 = matrix.R0C0;
+			result.R0C1 = matrix.R1C0;
+			result.R0C2 = matrix.R2C0;
+			result.R1C0 = matrix.R0C1;
+			result.R1C1 = matrix.R1C1;
+			result.R1C2 = matrix.R2C1;
+			result.R2C0 = matrix.R0C2;
+			result.R2C1 = matrix.R1C2;
+			result.R2C2 = matrix.R2C2;
+		}
+
+		#endregion
+
+		#region Transformation Functions
+
+		public void Transform(ref Vector3 vector)
+		{
+			float x = R0C0 * vector.X + R0C1 * vector.Y + R0C2 * vector.Z;
+			float y = R1C0 * vector.X + R1C1 * vector.Y + R1C2 * vector.Z;
+			vector.Z = R2C0 * vector.X + R2C1 * vector.Y + R2C2 * vector.Z;
+			vector.X = x;
+			vector.Y = y;
+		}
+		public static void Transform(ref Matrix3 matrix, ref Vector3 vector)
+		{
+			float x = matrix.R0C0 * vector.X + matrix.R0C1 * vector.Y + matrix.R0C2 * vector.Z;
+			float y = matrix.R1C0 * vector.X + matrix.R1C1 * vector.Y + matrix.R1C2 * vector.Z;
+			vector.Z = matrix.R2C0 * vector.X + matrix.R2C1 * vector.Y + matrix.R2C2 * vector.Z;
+			vector.X = x;
+			vector.Y = y;
+		}
+		public void Transform(ref Vector3 vector, out Vector3 result)
+		{
+			result.X = R0C0 * vector.X + R0C1 * vector.Y + R0C2 * vector.Z;
+			result.Y = R1C0 * vector.X + R1C1 * vector.Y + R1C2 * vector.Z;
+			result.Z = R2C0 * vector.X + R2C1 * vector.Y + R2C2 * vector.Z;
+		}
+		public static void Transform(ref Matrix3 matrix, ref Vector3 vector, out Vector3 result)
+		{
+			result.X = matrix.R0C0 * vector.X + matrix.R0C1 * vector.Y + matrix.R0C2 * vector.Z;
+			result.Y = matrix.R1C0 * vector.X + matrix.R1C1 * vector.Y + matrix.R1C2 * vector.Z;
+			result.Z = matrix.R2C0 * vector.X + matrix.R2C1 * vector.Y + matrix.R2C2 * vector.Z;
+		}
+
+		public void Rotate(float angle)
+		{
+		float angleRadians = MathHelper.DegreesToRadians (angle);
+			float sin = (float)System.Math.Sin(angleRadians);
+			float cos = (float)System.Math.Cos(angleRadians);
+
+			float r0c0 = cos * R0C0 + sin * R1C0;
+			float r0c1 = cos * R0C1 + sin * R1C1;
+			float r0c2 = cos * R0C2 + sin * R1C2;
+
+			R1C0 = cos * R1C0 - sin * R0C0;
+			R1C1 = cos * R1C1 - sin * R0C1;
+			R1C2 = cos * R1C2 - sin * R0C2;
+
+			R0C0 = r0c0;
+			R0C1 = r0c1;
+			R0C2 = r0c2;
+		}
+		public void Rotate(float angle, out Matrix3 result)
+		{
+		float angleRadians = MathHelper.DegreesToRadians (angle);
+			float sin = (float)System.Math.Sin(angleRadians);
+			float cos = (float)System.Math.Cos(angleRadians);
+
+			result.R0C0 = cos * R0C0 + sin * R1C0;
+			result.R0C1 = cos * R0C1 + sin * R1C1;
+			result.R0C2 = cos * R0C2 + sin * R1C2;
+			result.R1C0 = cos * R1C0 - sin * R0C0;
+			result.R1C1 = cos * R1C1 - sin * R0C1;
+			result.R1C2 = cos * R1C2 - sin * R0C2;
+			result.R2C0 = R2C0;
+			result.R2C1 = R2C1;
+			result.R2C2 = R2C2;
+		}
+		public static void Rotate(ref Matrix3 matrix, float angle, out Matrix3 result)
+		{
+		float angleRadians = MathHelper.DegreesToRadians (angle);
+			float sin = (float)System.Math.Sin(angleRadians);
+			float cos = (float)System.Math.Cos(angleRadians);
+
+			result.R0C0 = cos * matrix.R0C0 + sin * matrix.R1C0;
+			result.R0C1 = cos * matrix.R0C1 + sin * matrix.R1C1;
+			result.R0C2 = cos * matrix.R0C2 + sin * matrix.R1C2;
+			result.R1C0 = cos * matrix.R1C0 - sin * matrix.R0C0;
+			result.R1C1 = cos * matrix.R1C1 - sin * matrix.R0C1;
+			result.R1C2 = cos * matrix.R1C2 - sin * matrix.R0C2;
+			result.R2C0 = matrix.R2C0;
+			result.R2C1 = matrix.R2C1;
+			result.R2C2 = matrix.R2C2;
+		}
+		public static void RotateMatrix(float angle, out Matrix3 result)
+		{
+		float angleRadians = MathHelper.DegreesToRadians(angle);
+			float sin = (float)System.Math.Sin(angleRadians);
+			float cos = (float)System.Math.Cos(angleRadians);
+
+			result.R0C0 = cos;
+			result.R0C1 = sin;
+			result.R0C2 = 0;
+			result.R1C0 = -sin;
+			result.R1C1 = cos;
+			result.R1C2 = 0;
+			result.R2C0 = 0;
+			result.R2C1 = 0;
+			result.R2C2 = 1;
+		}
+
+		public Quaternion ToQuaternion ()
+		{
+		return new Quaternion (ref this);
+		}
+
+		#endregion
+
+		#region Constants
+
+		/// <summary>The identity matrix.</summary>
+		public static readonly Matrix3 Identity = new Matrix3
+		(
+			1, 0, 0,
+			0, 1, 0,
+			0, 0, 1
+		);
+
+		/// <summary>A matrix of all zeros.</summary>
+		public static readonly Matrix3 Zero = new Matrix3
+		(
+			0, 0, 0,
+			0, 0, 0,
+			0, 0, 0
+		);
+
+		#endregion
+
+		#region HashCode
+
+		/// <summary>Returns the hash code for this instance.</summary>
+		/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return
+				R0C0.GetHashCode() ^ R0C1.GetHashCode() ^ R0C2.GetHashCode() ^
+				R1C0.GetHashCode() ^ R1C1.GetHashCode() ^ R1C2.GetHashCode() ^
+				R2C0.GetHashCode() ^ R2C1.GetHashCode() ^ R2C2.GetHashCode();
+		}
+
+		#endregion
+
+		#region String
+
+		/// <summary>Returns the fully qualified type name of this instance.</summary>
+		/// <returns>A System.String containing left fully qualified type name.</returns>
+		public override string ToString()
+		{
+			return String.Format(
+				"|{00}, {01}, {02}|\n" +
+				"|{03}, {04}, {05}|\n" +
+				"|{06}, {07}, {08}|\n",
+				R0C0, R0C1, R0C2,
+				R1C0, R1C1, R1C2,
+				R2C0, R2C1, R2C2);
+		}
+
+		#endregion
+	}
+	#pragma warning restore 3019
+}

+ 1222 - 0
Script/AtomicNET/AtomicNET/Math/Matrix4.cs

@@ -0,0 +1,1222 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+	/// <summary>
+	/// Represents a 4x4 Matrix
+	/// </summary>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Matrix4 : IEquatable<Matrix4>
+	{
+		#region Fields
+
+		/// <summary>
+		/// Top row of the matrix
+		/// </summary>
+		public Vector4 Row0;
+		/// <summary>
+		/// 2nd row of the matrix
+		/// </summary>
+		public Vector4 Row1;
+		/// <summary>
+		/// 3rd row of the matrix
+		/// </summary>
+		public Vector4 Row2;
+		/// <summary>
+		/// Bottom row of the matrix
+		/// </summary>
+		public Vector4 Row3;
+ 
+		/// <summary>
+		/// The identity matrix
+		/// </summary>
+		public static Matrix4 Identity = new Matrix4(Vector4.UnitX, Vector4.UnitY, Vector4.UnitZ, Vector4.UnitW);
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs a new instance.
+		/// </summary>
+		/// <param name="row0">Top row of the matrix</param>
+		/// <param name="row1">Second row of the matrix</param>
+		/// <param name="row2">Third row of the matrix</param>
+		/// <param name="row3">Bottom row of the matrix</param>
+		public Matrix4(Vector4 row0, Vector4 row1, Vector4 row2, Vector4 row3)
+		{
+			Row0 = row0;
+			Row1 = row1;
+			Row2 = row2;
+			Row3 = row3;
+		}
+
+		/// <summary>
+		/// Constructs a new instance.
+		/// </summary>
+		/// <param name="m00">First item of the first row of the matrix.</param>
+		/// <param name="m01">Second item of the first row of the matrix.</param>
+		/// <param name="m02">Third item of the first row of the matrix.</param>
+		/// <param name="m03">Fourth item of the first row of the matrix.</param>
+		/// <param name="m10">First item of the second row of the matrix.</param>
+		/// <param name="m11">Second item of the second row of the matrix.</param>
+		/// <param name="m12">Third item of the second row of the matrix.</param>
+		/// <param name="m13">Fourth item of the second row of the matrix.</param>
+		/// <param name="m20">First item of the third row of the matrix.</param>
+		/// <param name="m21">Second item of the third row of the matrix.</param>
+		/// <param name="m22">Third item of the third row of the matrix.</param>
+		/// <param name="m23">First item of the third row of the matrix.</param>
+		/// <param name="m30">Fourth item of the fourth row of the matrix.</param>
+		/// <param name="m31">Second item of the fourth row of the matrix.</param>
+		/// <param name="m32">Third item of the fourth row of the matrix.</param>
+		/// <param name="m33">Fourth item of the fourth row of the matrix.</param>
+		public Matrix4(
+			float m00, float m01, float m02, float m03,
+			float m10, float m11, float m12, float m13,
+			float m20, float m21, float m22, float m23,
+			float m30, float m31, float m32, float m33)
+		{
+			Row0 = new Vector4(m00, m01, m02, m03);
+			Row1 = new Vector4(m10, m11, m12, m13);
+			Row2 = new Vector4(m20, m21, m22, m23);
+			Row3 = new Vector4(m30, m31, m32, m33);
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Properties
+
+		/// <summary>
+		/// The determinant of this matrix
+		/// </summary>
+		public float Determinant
+		{
+			get
+			{
+				return
+					Row0.X * Row1.Y * Row2.Z * Row3.W - Row0.X * Row1.Y * Row2.W * Row3.Z + Row0.X * Row1.Z * Row2.W * Row3.Y - Row0.X * Row1.Z * Row2.Y * Row3.W
+				  + Row0.X * Row1.W * Row2.Y * Row3.Z - Row0.X * Row1.W * Row2.Z * Row3.Y - Row0.Y * Row1.Z * Row2.W * Row3.X + Row0.Y * Row1.Z * Row2.X * Row3.W
+				  - Row0.Y * Row1.W * Row2.X * Row3.Z + Row0.Y * Row1.W * Row2.Z * Row3.X - Row0.Y * Row1.X * Row2.Z * Row3.W + Row0.Y * Row1.X * Row2.W * Row3.Z
+				  + Row0.Z * Row1.W * Row2.X * Row3.Y - Row0.Z * Row1.W * Row2.Y * Row3.X + Row0.Z * Row1.X * Row2.Y * Row3.W - Row0.Z * Row1.X * Row2.W * Row3.Y
+				  + Row0.Z * Row1.Y * Row2.W * Row3.X - Row0.Z * Row1.Y * Row2.X * Row3.W - Row0.W * Row1.X * Row2.Y * Row3.Z + Row0.W * Row1.X * Row2.Z * Row3.Y
+				  - Row0.W * Row1.Y * Row2.Z * Row3.X + Row0.W * Row1.Y * Row2.X * Row3.Z - Row0.W * Row1.Z * Row2.X * Row3.Y + Row0.W * Row1.Z * Row2.Y * Row3.X;
+			}
+		}
+
+		/// <summary>
+		/// The first column of this matrix
+		/// </summary>
+		public Vector4 Column0
+		{
+			get { return new Vector4(Row0.X, Row1.X, Row2.X, Row3.X); }
+		}
+
+		/// <summary>
+		/// The second column of this matrix
+		/// </summary>
+		public Vector4 Column1
+		{
+			get { return new Vector4(Row0.Y, Row1.Y, Row2.Y, Row3.Y); }
+		}
+
+		/// <summary>
+		/// The third column of this matrix
+		/// </summary>
+		public Vector4 Column2
+		{
+			get { return new Vector4(Row0.Z, Row1.Z, Row2.Z, Row3.Z); }
+		}
+
+		/// <summary>
+		/// The fourth column of this matrix
+		/// </summary>
+		public Vector4 Column3
+		{
+			get { return new Vector4(Row0.W, Row1.W, Row2.W, Row3.W); }
+		}
+
+		/// <summary>
+		/// Gets or sets the value at row 1, column 1 of this instance.
+		/// </summary>
+		public float M11 { get { return Row0.X; } set { Row0.X = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 1, column 2 of this instance.
+		/// </summary>
+		public float M12 { get { return Row0.Y; } set { Row0.Y = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 1, column 3 of this instance.
+		/// </summary>
+		public float M13 { get { return Row0.Z; } set { Row0.Z = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 1, column 4 of this instance.
+		/// </summary>
+		public float M14 { get { return Row0.W; } set { Row0.W = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 2, column 1 of this instance.
+		/// </summary>
+		public float M21 { get { return Row1.X; } set { Row1.X = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 2, column 2 of this instance.
+		/// </summary>
+		public float M22 { get { return Row1.Y; } set { Row1.Y = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 2, column 3 of this instance.
+		/// </summary>
+		public float M23 { get { return Row1.Z; } set { Row1.Z = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 2, column 4 of this instance.
+		/// </summary>
+		public float M24 { get { return Row1.W; } set { Row1.W = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 3, column 1 of this instance.
+		/// </summary>
+		public float M31 { get { return Row2.X; } set { Row2.X = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 3, column 2 of this instance.
+		/// </summary>
+		public float M32 { get { return Row2.Y; } set { Row2.Y = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 3, column 3 of this instance.
+		/// </summary>
+		public float M33 { get { return Row2.Z; } set { Row2.Z = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 3, column 4 of this instance.
+		/// </summary>
+		public float M34 { get { return Row2.W; } set { Row2.W = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 4, column 1 of this instance.
+		/// </summary>
+		public float M41 { get { return Row3.X; } set { Row3.X = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 4, column 2 of this instance.
+		/// </summary>
+		public float M42 { get { return Row3.Y; } set { Row3.Y = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 4, column 3 of this instance.
+		/// </summary>
+		public float M43 { get { return Row3.Z; } set { Row3.Z = value; } }
+
+		/// <summary>
+		/// Gets or sets the value at row 4, column 4 of this instance.
+		/// </summary>
+		public float M44 { get { return Row3.W; } set { Row3.W = value; } }
+
+		#endregion
+
+		#region Instance
+
+		#region public void Invert()
+
+		/// <summary>
+		/// Converts this instance into its inverse.
+		/// </summary>
+		public void Invert()
+		{
+			this = Matrix4.Invert(this);
+		}
+
+		#endregion
+
+		#region public void Transpose()
+
+		/// <summary>
+		/// Converts this instance into its transpose.
+		/// </summary>
+		public void Transpose()
+		{
+			this = Matrix4.Transpose(this);
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Static
+		
+		#region CreateFromAxisAngle
+		
+		/// <summary>
+		/// Build a rotation matrix from the specified axis/angle rotation.
+		/// </summary>
+		/// <param name="axis">The axis to rotate about.</param>
+		/// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
+		/// <param name="result">A matrix instance.</param>
+		public static void CreateFromAxisAngle(Vector3 axis, float angle, out Matrix4 result)
+		{
+			float cos = (float)System.Math.Cos(-angle);
+			float sin = (float)System.Math.Sin(-angle);
+			float t = 1.0f - cos;
+
+			axis.Normalize();
+
+			result = new Matrix4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f,
+								 t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f,
+								 t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f,
+								 0, 0, 0, 1);
+		}
+		
+		/// <summary>
+		/// Build a rotation matrix from the specified axis/angle rotation.
+		/// </summary>
+		/// <param name="axis">The axis to rotate about.</param>
+		/// <param name="angle">Angle in radians to rotate counter-clockwise (looking in the direction of the given axis).</param>
+		/// <returns>A matrix instance.</returns>
+		public static Matrix4 CreateFromAxisAngle(Vector3 axis, float angle)
+		{
+			Matrix4 result;
+			CreateFromAxisAngle(axis, angle, out result);
+			return result;
+		}
+		
+		#endregion
+
+		#region CreateRotation[XYZ]
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the x-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateRotationX(float angle, out Matrix4 result)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			result.Row0 = Vector4.UnitX;
+			result.Row1 = new Vector4(0.0f, cos, sin, 0.0f);
+			result.Row2 = new Vector4(0.0f, -sin, cos, 0.0f);
+			result.Row3 = Vector4.UnitW;
+		}
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the x-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateRotationX(float angle)
+		{
+			Matrix4 result;
+			CreateRotationX(angle, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the y-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateRotationY(float angle, out Matrix4 result)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			result.Row0 = new Vector4(cos, 0.0f, -sin, 0.0f);
+			result.Row1 = Vector4.UnitY;
+			result.Row2 = new Vector4(sin, 0.0f, cos, 0.0f);
+			result.Row3 = Vector4.UnitW;
+		}
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the y-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateRotationY(float angle)
+		{
+			Matrix4 result;
+			CreateRotationY(angle, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the z-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateRotationZ(float angle, out Matrix4 result)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			result.Row0 = new Vector4(cos, sin, 0.0f, 0.0f);
+			result.Row1 = new Vector4(-sin, cos, 0.0f, 0.0f);
+			result.Row2 = Vector4.UnitZ;
+			result.Row3 = Vector4.UnitW;
+		}
+
+		/// <summary>
+		/// Builds a rotation matrix for a rotation around the z-axis.
+		/// </summary>
+		/// <param name="angle">The counter-clockwise angle in radians.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateRotationZ(float angle)
+		{
+			Matrix4 result;
+			CreateRotationZ(angle, out result);
+			return result;
+		}
+
+		#endregion
+
+		#region CreateTranslation
+
+		/// <summary>
+		/// Creates a translation matrix.
+		/// </summary>
+		/// <param name="x">X translation.</param>
+		/// <param name="y">Y translation.</param>
+		/// <param name="z">Z translation.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateTranslation(float x, float y, float z, out Matrix4 result)
+		{
+			result = Identity;
+			result.Row3 = new Vector4(x, y, z, 1);
+		}
+
+		/// <summary>
+		/// Creates a translation matrix.
+		/// </summary>
+		/// <param name="vector">The translation vector.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateTranslation(ref Vector3 vector, out Matrix4 result)
+		{
+			result = Identity;
+			result.Row3 = new Vector4(vector.X, vector.Y, vector.Z, 1);
+		}
+
+		/// <summary>
+		/// Creates a translation matrix.
+		/// </summary>
+		/// <param name="x">X translation.</param>
+		/// <param name="y">Y translation.</param>
+		/// <param name="z">Z translation.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateTranslation(float x, float y, float z)
+		{
+			Matrix4 result;
+			CreateTranslation(x, y, z, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Creates a translation matrix.
+		/// </summary>
+		/// <param name="vector">The translation vector.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateTranslation(Vector3 vector)
+		{
+			Matrix4 result;
+			CreateTranslation(vector.X, vector.Y, vector.Z, out result);
+			return result;
+		}
+
+		#endregion
+
+		#region CreateOrthographic
+
+		/// <summary>
+		/// Creates an orthographic projection matrix.
+		/// </summary>
+		/// <param name="width">The width of the projection volume.</param>
+		/// <param name="height">The height of the projection volume.</param>
+		/// <param name="zNear">The near edge of the projection volume.</param>
+		/// <param name="zFar">The far edge of the projection volume.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateOrthographic(float width, float height, float zNear, float zFar, out Matrix4 result)
+		{
+			CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
+		}
+
+		/// <summary>
+		/// Creates an orthographic projection matrix.
+		/// </summary>
+		/// <param name="width">The width of the projection volume.</param>
+		/// <param name="height">The height of the projection volume.</param>
+		/// <param name="zNear">The near edge of the projection volume.</param>
+		/// <param name="zFar">The far edge of the projection volume.</param>
+		/// <rereturns>The resulting Matrix4 instance.</rereturns>
+		public static Matrix4 CreateOrthographic(float width, float height, float zNear, float zFar)
+		{
+			Matrix4 result;
+			CreateOrthographicOffCenter(-width / 2, width / 2, -height / 2, height / 2, zNear, zFar, out result);
+			return result;
+		}
+
+		#endregion
+
+		#region CreateOrthographicOffCenter
+
+		/// <summary>
+		/// Creates an orthographic projection matrix.
+		/// </summary>
+		/// <param name="left">The left edge of the projection volume.</param>
+		/// <param name="right">The right edge of the projection volume.</param>
+		/// <param name="bottom">The bottom edge of the projection volume.</param>
+		/// <param name="top">The top edge of the projection volume.</param>
+		/// <param name="zNear">The near edge of the projection volume.</param>
+		/// <param name="zFar">The far edge of the projection volume.</param>
+		/// <param name="result">The resulting Matrix4 instance.</param>
+		public static void CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result)
+		{
+			result = new Matrix4();
+
+			float invRL = 1 / (right - left);
+			float invTB = 1 / (top - bottom);
+			float invFN = 1 / (zFar - zNear);
+
+			result.M11 = 2 * invRL;
+			result.M22 = 2 * invTB;
+			result.M33 = -2 * invFN;
+
+			result.M41 = -(right + left) * invRL;
+			result.M42 = -(top + bottom) * invTB;
+			result.M43 = -(zFar + zNear) * invFN;
+			result.M44 = 1;
+		}
+
+		/// <summary>
+		/// Creates an orthographic projection matrix.
+		/// </summary>
+		/// <param name="left">The left edge of the projection volume.</param>
+		/// <param name="right">The right edge of the projection volume.</param>
+		/// <param name="bottom">The bottom edge of the projection volume.</param>
+		/// <param name="top">The top edge of the projection volume.</param>
+		/// <param name="zNear">The near edge of the projection volume.</param>
+		/// <param name="zFar">The far edge of the projection volume.</param>
+		/// <returns>The resulting Matrix4 instance.</returns>
+		public static Matrix4 CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNear, float zFar)
+		{
+			Matrix4 result;
+			CreateOrthographicOffCenter(left, right, bottom, top, zNear, zFar, out result);
+			return result;
+		}
+
+		#endregion
+		
+		#region CreatePerspectiveFieldOfView
+		
+		/// <summary>
+		/// Creates a perspective projection matrix.
+		/// </summary>
+		/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
+		/// <param name="aspect">Aspect ratio of the view (width / height)</param>
+		/// <param name="zNear">Distance to the near clip plane</param>
+		/// <param name="zFar">Distance to the far clip plane</param>
+		/// <param name="result">A projection matrix that transforms camera space to raster space</param>
+		/// <exception cref="System.ArgumentOutOfRangeException">
+		/// Thrown under the following conditions:
+		/// <list type="bullet">
+		/// <item>fovy is zero, less than zero or larger than Math.PI</item>
+		/// <item>aspect is negative or zero</item>
+		/// <item>zNear is negative or zero</item>
+		/// <item>zFar is negative or zero</item>
+		/// <item>zNear is larger than zFar</item>
+		/// </list>
+		/// </exception>
+		public static void CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar, out Matrix4 result)
+		{
+			if (fovy <= 0 || fovy > Math.PI)
+				throw new ArgumentOutOfRangeException("fovy");
+			if (aspect <= 0)
+				throw new ArgumentOutOfRangeException("aspect");
+			if (zNear <= 0)
+				throw new ArgumentOutOfRangeException("zNear");
+			if (zFar <= 0)
+				throw new ArgumentOutOfRangeException("zFar");
+			if (zNear >= zFar)
+				throw new ArgumentOutOfRangeException("zNear");
+			
+			float yMax = zNear * (float)System.Math.Tan(0.5f * fovy);
+			float yMin = -yMax;
+			float xMin = yMin * aspect;
+			float xMax = yMax * aspect;
+
+			CreatePerspectiveOffCenter(xMin, xMax, yMin, yMax, zNear, zFar, out result);
+		}
+		
+		/// <summary>
+		/// Creates a perspective projection matrix.
+		/// </summary>
+		/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
+		/// <param name="aspect">Aspect ratio of the view (width / height)</param>
+		/// <param name="zNear">Distance to the near clip plane</param>
+		/// <param name="zFar">Distance to the far clip plane</param>
+		/// <returns>A projection matrix that transforms camera space to raster space</returns>
+		/// <exception cref="System.ArgumentOutOfRangeException">
+		/// Thrown under the following conditions:
+		/// <list type="bullet">
+		/// <item>fovy is zero, less than zero or larger than Math.PI</item>
+		/// <item>aspect is negative or zero</item>
+		/// <item>zNear is negative or zero</item>
+		/// <item>zFar is negative or zero</item>
+		/// <item>zNear is larger than zFar</item>
+		/// </list>
+		/// </exception>
+		public static Matrix4 CreatePerspectiveFieldOfView(float fovy, float aspect, float zNear, float zFar)
+		{
+			Matrix4 result;
+			CreatePerspectiveFieldOfView(fovy, aspect, zNear, zFar, out result);
+			return result;
+		}
+		
+		#endregion
+		
+		#region CreatePerspectiveOffCenter
+		
+		/// <summary>
+		/// Creates an perspective projection matrix.
+		/// </summary>
+		/// <param name="left">Left edge of the view frustum</param>
+		/// <param name="right">Right edge of the view frustum</param>
+		/// <param name="bottom">Bottom edge of the view frustum</param>
+		/// <param name="top">Top edge of the view frustum</param>
+		/// <param name="zNear">Distance to the near clip plane</param>
+		/// <param name="zFar">Distance to the far clip plane</param>
+		/// <param name="result">A projection matrix that transforms camera space to raster space</param>
+		/// <exception cref="System.ArgumentOutOfRangeException">
+		/// Thrown under the following conditions:
+		/// <list type="bullet">
+		/// <item>zNear is negative or zero</item>
+		/// <item>zFar is negative or zero</item>
+		/// <item>zNear is larger than zFar</item>
+		/// </list>
+		/// </exception>
+		public static void CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, out Matrix4 result)
+		{
+			if (zNear <= 0)
+				throw new ArgumentOutOfRangeException("zNear");
+			if (zFar <= 0)
+				throw new ArgumentOutOfRangeException("zFar");
+			if (zNear >= zFar)
+				throw new ArgumentOutOfRangeException("zNear");
+			
+			float x = (2.0f * zNear) / (right - left);
+			float y = (2.0f * zNear) / (top - bottom);
+			float a = (right + left) / (right - left);
+			float b = (top + bottom) / (top - bottom);
+			float c = -(zFar + zNear) / (zFar - zNear);
+			float d = -(2.0f * zFar * zNear) / (zFar - zNear);
+			
+			result = new Matrix4(x, 0, 0,  0,
+								 0, y, 0,  0,
+								 a, b, c, -1,
+								 0, 0, d,  0);
+		}
+		
+		/// <summary>
+		/// Creates an perspective projection matrix.
+		/// </summary>
+		/// <param name="left">Left edge of the view frustum</param>
+		/// <param name="right">Right edge of the view frustum</param>
+		/// <param name="bottom">Bottom edge of the view frustum</param>
+		/// <param name="top">Top edge of the view frustum</param>
+		/// <param name="zNear">Distance to the near clip plane</param>
+		/// <param name="zFar">Distance to the far clip plane</param>
+		/// <returns>A projection matrix that transforms camera space to raster space</returns>
+		/// <exception cref="System.ArgumentOutOfRangeException">
+		/// Thrown under the following conditions:
+		/// <list type="bullet">
+		/// <item>zNear is negative or zero</item>
+		/// <item>zFar is negative or zero</item>
+		/// <item>zNear is larger than zFar</item>
+		/// </list>
+		/// </exception>
+		public static Matrix4 CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar)
+		{
+			Matrix4 result;
+			CreatePerspectiveOffCenter(left, right, bottom, top, zNear, zFar, out result);
+			return result;
+		}
+		
+		#endregion
+
+		#region Obsolete Functions
+
+		#region Translation Functions
+
+		/// <summary>
+		/// Builds a translation matrix.
+		/// </summary>
+		/// <param name="trans">The translation vector.</param>
+		/// <returns>A new Matrix4 instance.</returns>
+		[Obsolete("Use CreateTranslation instead.")]
+		public static Matrix4 Translation(Vector3 trans)
+		{
+			return Translation(trans.X, trans.Y, trans.Z);
+		}
+
+		/// <summary>
+		/// Build a translation matrix with the given translation
+		/// </summary>
+		/// <param name="x">X translation</param>
+		/// <param name="y">Y translation</param>
+		/// <param name="z">Z translation</param>
+		/// <returns>A Translation matrix</returns>
+		[Obsolete("Use CreateTranslation instead.")]
+		public static Matrix4 Translation(float x, float y, float z)
+		{
+			Matrix4 result = Identity;
+			result.Row3 = new Vector4(x, y, z, 1.0f);
+			return result;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Scale Functions
+
+		/// <summary>
+		/// Build a scaling matrix
+		/// </summary>
+		/// <param name="scale">Single scale factor for x,y and z axes</param>
+		/// <returns>A scaling matrix</returns>
+		public static Matrix4 Scale(float scale)
+		{
+			return Scale(scale, scale, scale);
+		}
+
+		/// <summary>
+		/// Build a scaling matrix
+		/// </summary>
+		/// <param name="scale">Scale factors for x,y and z axes</param>
+		/// <returns>A scaling matrix</returns>
+		public static Matrix4 Scale(Vector3 scale)
+		{
+			return Scale(scale.X, scale.Y, scale.Z);
+		}
+
+		/// <summary>
+		/// Build a scaling matrix
+		/// </summary>
+		/// <param name="x">Scale factor for x-axis</param>
+		/// <param name="y">Scale factor for y-axis</param>
+		/// <param name="z">Scale factor for z-axis</param>
+		/// <returns>A scaling matrix</returns>
+		public static Matrix4 Scale(float x, float y, float z)
+		{
+			Matrix4 result;
+			result.Row0 = Vector4.UnitX * x;
+			result.Row1 = Vector4.UnitY * y;
+			result.Row2 = Vector4.UnitZ * z;
+			result.Row3 = Vector4.UnitW;
+			return result;
+		}
+
+		#endregion
+
+		#region Rotation Functions
+
+		/// <summary>
+		/// Build a rotation matrix that rotates about the x-axis
+		/// </summary>
+		/// <param name="angle">angle in radians to rotate counter-clockwise around the x-axis</param>
+		/// <returns>A rotation matrix</returns>
+		[Obsolete("Use CreateRotationX instead.")]
+		public static Matrix4 RotateX(float angle)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			Matrix4 result;
+			result.Row0 = Vector4.UnitX;
+			result.Row1 = new Vector4(0.0f, cos, sin, 0.0f);
+			result.Row2 = new Vector4(0.0f, -sin, cos, 0.0f);
+			result.Row3 = Vector4.UnitW;
+			return result;
+		}
+
+		/// <summary>
+		/// Build a rotation matrix that rotates about the y-axis
+		/// </summary>
+		/// <param name="angle">angle in radians to rotate counter-clockwise around the y-axis</param>
+		/// <returns>A rotation matrix</returns>
+		[Obsolete("Use CreateRotationY instead.")]
+		public static Matrix4 RotateY(float angle)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			Matrix4 result;
+			result.Row0 = new Vector4(cos, 0.0f, -sin, 0.0f);
+			result.Row1 = Vector4.UnitY;
+			result.Row2 = new Vector4(sin, 0.0f, cos, 0.0f);
+			result.Row3 = Vector4.UnitW;
+			return result;
+		}
+
+		/// <summary>
+		/// Build a rotation matrix that rotates about the z-axis
+		/// </summary>
+		/// <param name="angle">angle in radians to rotate counter-clockwise around the z-axis</param>
+		/// <returns>A rotation matrix</returns>
+		[Obsolete("Use CreateRotationZ instead.")]
+		public static Matrix4 RotateZ(float angle)
+		{
+			float cos = (float)System.Math.Cos(angle);
+			float sin = (float)System.Math.Sin(angle);
+
+			Matrix4 result;
+			result.Row0 = new Vector4(cos, sin, 0.0f, 0.0f);
+			result.Row1 = new Vector4(-sin, cos, 0.0f, 0.0f);
+			result.Row2 = Vector4.UnitZ;
+			result.Row3 = Vector4.UnitW;
+			return result;
+		}
+
+		/// <summary>
+		/// Build a rotation matrix to rotate about the given axis
+		/// </summary>
+		/// <param name="axis">the axis to rotate about</param>
+		/// <param name="angle">angle in radians to rotate counter-clockwise (looking in the direction of the given axis)</param>
+		/// <returns>A rotation matrix</returns>
+		[Obsolete("Use CreateFromAxisAngle instead.")]
+		public static Matrix4 Rotate(Vector3 axis, float angle)
+		{
+			float cos = (float)System.Math.Cos(-angle);
+			float sin = (float)System.Math.Sin(-angle);
+			float t = 1.0f - cos;
+
+			axis.Normalize();
+
+			Matrix4 result;
+			result.Row0 = new Vector4(t * axis.X * axis.X + cos, t * axis.X * axis.Y - sin * axis.Z, t * axis.X * axis.Z + sin * axis.Y, 0.0f);
+			result.Row1 = new Vector4(t * axis.X * axis.Y + sin * axis.Z, t * axis.Y * axis.Y + cos, t * axis.Y * axis.Z - sin * axis.X, 0.0f);
+			result.Row2 = new Vector4(t * axis.X * axis.Z - sin * axis.Y, t * axis.Y * axis.Z + sin * axis.X, t * axis.Z * axis.Z + cos, 0.0f);
+			result.Row3 = Vector4.UnitW;
+			return result;
+		}
+
+		/// <summary>
+		/// Build a rotation matrix from a quaternion
+		/// </summary>
+		/// <param name="q">the quaternion</param>
+		/// <returns>A rotation matrix</returns>
+		public static Matrix4 Rotate(Quaternion q)
+		{
+			Vector3 axis;
+			float angle;
+			q.ToAxisAngle(out axis, out angle);
+			return CreateFromAxisAngle(axis, angle);
+		}
+
+		#endregion
+
+		#region Camera Helper Functions
+
+		/// <summary>
+		/// Build a world space to camera space matrix
+		/// </summary>
+		/// <param name="eye">Eye (camera) position in world space</param>
+		/// <param name="target">Target position in world space</param>
+		/// <param name="up">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
+		/// <returns>A Matrix4 that transforms world space to camera space</returns>
+		public static Matrix4 LookAt(Vector3 eye, Vector3 target, Vector3 up)
+		{
+			Vector3 z = Vector3.Normalize(eye - target);
+			Vector3 x = Vector3.Normalize(Vector3.Cross(up, z));
+			Vector3 y = Vector3.Normalize(Vector3.Cross(z, x));
+
+			Matrix4 rot = new Matrix4(new Vector4(x.X, y.X, z.X, 0.0f),
+										new Vector4(x.Y, y.Y, z.Y, 0.0f),
+										new Vector4(x.Z, y.Z, z.Z, 0.0f),
+										Vector4.UnitW);
+
+			Matrix4 trans = Matrix4.CreateTranslation(-eye);
+
+			return trans * rot;
+		}
+
+		/// <summary>
+		/// Build a world space to camera space matrix
+		/// </summary>
+		/// <param name="eyeX">Eye (camera) position in world space</param>
+		/// <param name="eyeY">Eye (camera) position in world space</param>
+		/// <param name="eyeZ">Eye (camera) position in world space</param>
+		/// <param name="targetX">Target position in world space</param>
+		/// <param name="targetY">Target position in world space</param>
+		/// <param name="targetZ">Target position in world space</param>
+		/// <param name="upX">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
+		/// <param name="upY">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
+		/// <param name="upZ">Up vector in world space (should not be parallel to the camera direction, that is target - eye)</param>
+		/// <returns>A Matrix4 that transforms world space to camera space</returns>
+		public static Matrix4 LookAt(float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ, float upX, float upY, float upZ)
+		{
+			return LookAt(new Vector3(eyeX, eyeY, eyeZ), new Vector3(targetX, targetY, targetZ), new Vector3(upX, upY, upZ));
+		}
+
+		/// <summary>
+		/// Build a projection matrix
+		/// </summary>
+		/// <param name="left">Left edge of the view frustum</param>
+		/// <param name="right">Right edge of the view frustum</param>
+		/// <param name="bottom">Bottom edge of the view frustum</param>
+		/// <param name="top">Top edge of the view frustum</param>
+		/// <param name="near">Distance to the near clip plane</param>
+		/// <param name="far">Distance to the far clip plane</param>
+		/// <returns>A projection matrix that transforms camera space to raster space</returns>
+		[Obsolete("Use CreatePerspectiveOffCenter instead.")]
+		public static Matrix4 Frustum(float left, float right, float bottom, float top, float near, float far)
+		{
+			float invRL = 1.0f / (right - left);
+			float invTB = 1.0f / (top - bottom);
+			float invFN = 1.0f / (far - near);
+			return new Matrix4(new Vector4(2.0f * near * invRL, 0.0f, 0.0f, 0.0f),
+							   new Vector4(0.0f, 2.0f * near * invTB, 0.0f, 0.0f),
+							   new Vector4((right + left) * invRL, (top + bottom) * invTB, -(far + near) * invFN, -1.0f),
+							   new Vector4(0.0f, 0.0f, -2.0f * far * near * invFN, 0.0f));
+		}
+
+		/// <summary>
+		/// Build a projection matrix
+		/// </summary>
+		/// <param name="fovy">Angle of the field of view in the y direction (in radians)</param>
+		/// <param name="aspect">Aspect ratio of the view (width / height)</param>
+		/// <param name="near">Distance to the near clip plane</param>
+		/// <param name="far">Distance to the far clip plane</param>
+		/// <returns>A projection matrix that transforms camera space to raster space</returns>
+		[Obsolete("Use CreatePerspectiveFieldOfView instead.")]
+		public static Matrix4 Perspective(float fovy, float aspect, float near, float far)
+		{
+			float yMax = near * (float)System.Math.Tan(0.5f * fovy);
+			float yMin = -yMax;
+			float xMin = yMin * aspect;
+			float xMax = yMax * aspect;
+
+			return Frustum(xMin, xMax, yMin, yMax, near, far);
+		}
+
+		#endregion
+
+		#region Multiply Functions
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The left operand of the multiplication.</param>
+		/// <param name="right">The right operand of the multiplication.</param>
+		/// <returns>A new instance that is the result of the multiplication</returns>
+		public static Matrix4 Mult(Matrix4 left, Matrix4 right)
+		{
+			Matrix4 result;
+			Mult(ref left, ref right, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The left operand of the multiplication.</param>
+		/// <param name="right">The right operand of the multiplication.</param>
+		/// <param name="result">A new instance that is the result of the multiplication</param>
+		public static void Mult(ref Matrix4 left, ref Matrix4 right, out Matrix4 result)
+		{
+			result = new Matrix4(
+				left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41,
+				left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42,
+				left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43,
+				left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44,
+				left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41,
+				left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42,
+				left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43,
+				left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44,
+				left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41,
+				left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42,
+				left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43,
+				left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44,
+				left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41,
+				left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42,
+				left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43,
+				left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44);
+		}
+
+		#endregion
+
+		#region Invert Functions
+
+		/// <summary>
+		/// Calculate the inverse of the given matrix
+		/// </summary>
+		/// <param name="mat">The matrix to invert</param>
+		/// <returns>The inverse of the given matrix if it has one, or the input if it is singular</returns>
+		/// <exception cref="InvalidOperationException">Thrown if the Matrix4 is singular.</exception>
+		public static Matrix4 Invert(Matrix4 mat)
+		{
+			int[] colIdx = { 0, 0, 0, 0 };
+			int[] rowIdx = { 0, 0, 0, 0 };
+			int[] pivotIdx = { -1, -1, -1, -1 };
+
+			// convert the matrix to an array for easy looping
+			float[,] inverse = {{mat.Row0.X, mat.Row0.Y, mat.Row0.Z, mat.Row0.W}, 
+								{mat.Row1.X, mat.Row1.Y, mat.Row1.Z, mat.Row1.W}, 
+								{mat.Row2.X, mat.Row2.Y, mat.Row2.Z, mat.Row2.W}, 
+								{mat.Row3.X, mat.Row3.Y, mat.Row3.Z, mat.Row3.W} };
+			int icol = 0;
+			int irow = 0;
+			for (int i = 0; i < 4; i++)
+			{
+				// Find the largest pivot value
+				float maxPivot = 0.0f;
+				for (int j = 0; j < 4; j++)
+				{
+					if (pivotIdx[j] != 0)
+					{
+						for (int k = 0; k < 4; ++k)
+						{
+							if (pivotIdx[k] == -1)
+							{
+								float absVal = System.Math.Abs(inverse[j, k]);
+								if (absVal > maxPivot)
+								{
+									maxPivot = absVal;
+									irow = j;
+									icol = k;
+								}
+							}
+							else if (pivotIdx[k] > 0)
+							{
+								return mat;
+							}
+						}
+					}
+				}
+
+				++(pivotIdx[icol]);
+
+				// Swap rows over so pivot is on diagonal
+				if (irow != icol)
+				{
+					for (int k = 0; k < 4; ++k)
+					{
+						float f = inverse[irow, k];
+						inverse[irow, k] = inverse[icol, k];
+						inverse[icol, k] = f;
+					}
+				}
+
+				rowIdx[i] = irow;
+				colIdx[i] = icol;
+
+				float pivot = inverse[icol, icol];
+				// check for singular matrix
+				if (pivot == 0.0f)
+				{
+					throw new InvalidOperationException("Matrix is singular and cannot be inverted.");
+					//return mat;
+				}
+
+				// Scale row so it has a unit diagonal
+				float oneOverPivot = 1.0f / pivot;
+				inverse[icol, icol] = 1.0f;
+				for (int k = 0; k < 4; ++k)
+					inverse[icol, k] *= oneOverPivot;
+
+				// Do elimination of non-diagonal elements
+				for (int j = 0; j < 4; ++j)
+				{
+					// check this isn't on the diagonal
+					if (icol != j)
+					{
+						float f = inverse[j, icol];
+						inverse[j, icol] = 0.0f;
+						for (int k = 0; k < 4; ++k)
+							inverse[j, k] -= inverse[icol, k] * f;
+					}
+				}
+			}
+
+			for (int j = 3; j >= 0; --j)
+			{
+				int ir = rowIdx[j];
+				int ic = colIdx[j];
+				for (int k = 0; k < 4; ++k)
+				{
+					float f = inverse[k, ir];
+					inverse[k, ir] = inverse[k, ic];
+					inverse[k, ic] = f;
+				}
+			}
+
+			mat.Row0 = new Vector4(inverse[0, 0], inverse[0, 1], inverse[0, 2], inverse[0, 3]);
+			mat.Row1 = new Vector4(inverse[1, 0], inverse[1, 1], inverse[1, 2], inverse[1, 3]);
+			mat.Row2 = new Vector4(inverse[2, 0], inverse[2, 1], inverse[2, 2], inverse[2, 3]);
+			mat.Row3 = new Vector4(inverse[3, 0], inverse[3, 1], inverse[3, 2], inverse[3, 3]);
+			return mat;
+		}
+
+		#endregion
+
+		#region Transpose
+
+		/// <summary>
+		/// Calculate the transpose of the given matrix
+		/// </summary>
+		/// <param name="mat">The matrix to transpose</param>
+		/// <returns>The transpose of the given matrix</returns>
+		public static Matrix4 Transpose(Matrix4 mat)
+		{
+			return new Matrix4(mat.Column0, mat.Column1, mat.Column2, mat.Column3);
+		}
+
+
+		/// <summary>
+		/// Calculate the transpose of the given matrix
+		/// </summary>
+		/// <param name="mat">The matrix to transpose</param>
+		/// <param name="result">The result of the calculation</param>
+		public static void Transpose(ref Matrix4 mat, out Matrix4 result)
+		{
+			result.Row0 = mat.Column0;
+			result.Row1 = mat.Column1;
+			result.Row2 = mat.Column2;
+			result.Row3 = mat.Column3;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Matrix multiplication
+		/// </summary>
+		/// <param name="left">left-hand operand</param>
+		/// <param name="right">right-hand operand</param>
+		/// <returns>A new Matrix44 which holds the result of the multiplication</returns>
+		public static Matrix4 operator *(Matrix4 left, Matrix4 right)
+		{
+			return Matrix4.Mult(left, right);
+		}
+
+		/// <summary>
+		/// Compares two instances for equality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left equals right; false otherwise.</returns>
+		public static bool operator ==(Matrix4 left, Matrix4 right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares two instances for inequality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left does not equal right; false otherwise.</returns>
+		public static bool operator !=(Matrix4 left, Matrix4 right)
+		{
+			return !left.Equals(right);
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current Matrix44.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("{0}\n{1}\n{2}\n{3}", Row0, Row1, Row2, Row3);
+		}
+
+		#endregion
+
+		#region public override int GetHashCode()
+
+		/// <summary>
+		/// Returns the hashcode for this instance.
+		/// </summary>
+		/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode() ^ Row3.GetHashCode();
+		}
+
+		#endregion
+
+		#region public override bool Equals(object obj)
+
+		/// <summary>
+		/// Indicates whether this instance and a specified object are equal.
+		/// </summary>
+		/// <param name="obj">The object to compare tresult.</param>
+		/// <returns>True if the instances are equal; false otherwise.</returns>
+		public override bool Equals(object obj)
+		{
+			if (!(obj is Matrix4))
+				return false;
+
+			return this.Equals((Matrix4)obj);
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<Matrix4> Members
+
+		/// <summary>Indicates whether the current matrix is equal to another matrix.</summary>
+		/// <param name="other">An matrix to compare with this matrix.</param>
+		/// <returns>true if the current matrix is equal to the matrix parameter; otherwise, false.</returns>
+		public bool Equals(Matrix4 other)
+		{
+			return
+				Row0 == other.Row0 &&
+				Row1 == other.Row1 &&
+				Row2 == other.Row2 &&
+				Row3 == other.Row3;
+		}
+
+		#endregion
+	}
+}

+ 44 - 0
Script/AtomicNET/AtomicNET/Math/Plane.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Plane
+	{
+		/// <summary>
+		/// Plane normal.
+		/// </summary>
+		public Vector3 Normal;
+
+		/// <summary>
+		/// Plane absolute normal.
+		/// </summary>
+		public Vector3 AbsNormal;
+
+		/// <summary>
+		/// Plane constant.
+		/// </summary>
+		public float D;
+
+		/// <summary>
+		/// Construct from a normal vector and a point on the plane.
+		/// </summary>
+		public Plane(Vector3 normal, Vector3 point)
+		{
+			Normal = Vector3.Normalize(normal);
+			AbsNormal = new Vector3(Math.Abs(Normal.X), Math.Abs(Normal.Y), Math.Abs(Normal.Z));
+			D = - Vector3.Dot(Normal, point);
+		}
+
+		/// <summary>
+		/// Construct from a 4-dimensional vector, where the w coordinate is the plane parameter.
+		/// </summary>
+		public Plane(Vector4 plane)
+		{
+			Normal = new Vector3(plane.X, plane.Y, plane.Z);
+			AbsNormal = new Vector3(Math.Abs(plane.X), Math.Abs(plane.Y), Math.Abs(plane.Z));
+			D = plane.W;
+		}
+	}
+}

+ 819 - 0
Script/AtomicNET/AtomicNET/Math/Quaternion.cs

@@ -0,0 +1,819 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.ComponentModel;
+using System.Xml.Serialization;
+
+namespace AtomicEngine
+{
+	/// <summary>
+	/// Represents a Quaternion.
+	/// </summary>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Quaternion : IEquatable<Quaternion>
+	{
+		#region Fields
+
+		float w;
+		Vector3 xyz;
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Construct a new Quaternion from vector and w components
+		/// </summary>
+		/// <param name="v">The vector part</param>
+		/// <param name="w">The w part</param>
+		public Quaternion(Vector3 v, float w)
+		{
+			this.xyz = v;
+			this.w = w;
+		}
+
+		/// <summary>
+		/// Construct a new Quaternion
+		/// </summary>
+		/// <param name="x">The x component</param>
+		/// <param name="y">The y component</param>
+		/// <param name="z">The z component</param>
+		/// <param name="w">The w component</param>
+		public Quaternion(float x, float y, float z, float w)
+			: this(new Vector3(x, y, z), w)
+		{ }
+
+		// From Euler angles
+		public Quaternion (float x, float y, float z)
+		{
+			const float M_DEGTORAD_2 = (float)Math.PI / 360.0f;
+			x *= M_DEGTORAD_2;
+			y *= M_DEGTORAD_2;
+			z *= M_DEGTORAD_2;
+			float sinX = (float)Math.Sin(x);
+			float cosX = (float)Math.Cos(x);
+			float sinY = (float)Math.Sin(y);
+			float cosY = (float)Math.Cos(y);
+			float sinZ = (float)Math.Sin(z);
+			float cosZ = (float)Math.Cos(z);
+
+			xyz = new Vector3(cosY * sinX * cosZ + sinY * cosX * sinZ,
+					  sinY * cosX * cosZ - cosY * sinX * sinZ,
+					  cosY * cosX * sinZ - sinY * sinX * cosZ);
+			w = cosY * cosX * cosZ + sinY * sinX * sinZ;
+		}
+	
+		public Quaternion (ref Matrix3 matrix)
+		{
+			double scale = System.Math.Pow(matrix.Determinant, 1.0d / 3.0d);
+			float x, y, z;
+		
+			w = (float) (System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2);
+			x = (float) (System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])) / 2);
+			y = (float) (System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] + matrix[1, 1] - matrix[2, 2])) / 2);
+			z = (float) (System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] - matrix[1, 1] + matrix[2, 2])) / 2);
+
+			xyz = new Vector3 (x, y, z);
+		
+			if (matrix[2, 1] - matrix[1, 2] < 0) X = -X;
+			if (matrix[0, 2] - matrix[2, 0] < 0) Y = -Y;
+			if (matrix[1, 0] - matrix[0, 1] < 0) Z = -Z;
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Properties
+
+		/// <summary>
+		/// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance.
+		/// </summary>
+		[Obsolete("Use Xyz property instead.")]
+		[CLSCompliant(false)]
+		[EditorBrowsable(EditorBrowsableState.Never)]
+		
+		public Vector3 XYZ { get { return Xyz; } set { Xyz = value; } }
+
+		/// <summary>
+		/// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance.
+		/// </summary>
+		public Vector3 Xyz { get { return xyz; } set { xyz = value; } }
+
+		/// <summary>
+		/// Gets or sets the X component of this instance.
+		/// </summary>
+		
+		public float X { get { return xyz.X; } set { xyz.X = value; } }
+
+		/// <summary>
+		/// Gets or sets the Y component of this instance.
+		/// </summary>
+		
+		public float Y { get { return xyz.Y; } set { xyz.Y = value; } }
+
+		/// <summary>
+		/// Gets or sets the Z component of this instance.
+		/// </summary>
+		
+		public float Z { get { return xyz.Z; } set { xyz.Z = value; } }
+
+		/// <summary>
+		/// Gets or sets the W component of this instance.
+		/// </summary>
+		public float W { get { return w; } set { w = value; } }
+
+		#endregion
+
+		#region Instance
+
+		#region ToAxisAngle
+
+		/// <summary>
+		/// Convert the current quaternion to axis angle representation
+		/// </summary>
+		/// <param name="axis">The resultant axis</param>
+		/// <param name="angle">The resultant angle</param>
+		public void ToAxisAngle(out Vector3 axis, out float angle)
+		{
+			Vector4 result = ToAxisAngle();
+			axis = result.Xyz;
+			angle = result.W;
+		}
+
+		/// <summary>
+		/// Convert this instance to an axis-angle representation.
+		/// </summary>
+		/// <returns>A Vector4 that is the axis-angle representation of this quaternion.</returns>
+		public Vector4 ToAxisAngle()
+		{
+			Quaternion q = this;
+			if (q.W > 1.0f)
+				q.Normalize();
+
+			Vector4 result = new Vector4();
+
+			result.W = 2.0f * (float)System.Math.Acos(q.W); // angle
+			float den = (float)System.Math.Sqrt(1.0 - q.W * q.W);
+			if (den > 0.0001f)
+			{
+				result.Xyz = q.Xyz / den;
+			}
+			else
+			{
+				// This occurs when the angle is zero. 
+				// Not a problem: just set an arbitrary normalized axis.
+				result.Xyz = Vector3.UnitX;
+			}
+
+			return result;
+		}
+
+		#endregion
+
+		#region public float Length
+
+		/// <summary>
+		/// Gets the length (magnitude) of the quaternion.
+		/// </summary>
+		/// <seealso cref="LengthSquared"/>
+		public float Length
+		{
+			get
+			{
+				return (float)System.Math.Sqrt(W * W + Xyz.LengthSquared);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthSquared
+
+		/// <summary>
+		/// Gets the square of the quaternion length (magnitude).
+		/// </summary>
+		public float LengthSquared
+		{
+			get
+			{
+				return W * W + Xyz.LengthSquared;
+			}
+		}
+
+		#endregion
+
+		#region public void Normalize()
+
+		/// <summary>
+		/// Scales the Quaternion to unit length.
+		/// </summary>
+		public void Normalize()
+		{
+			float scale = 1.0f / this.Length;
+			Xyz *= scale;
+			W *= scale;
+		}
+
+		#endregion
+
+		#region EulerAngles
+
+		public Vector3 ToEulerAngles()
+		{
+			// Derivation from http://www.geometrictools.com/Documentation/EulerAngles.pdf
+			// Order of rotations: Z first, then X, then Y
+			float check = 2.0f*(-Y*Z + W*X);
+			const float radToDeg = 180f/(float) Math.PI;
+
+			if (check < -0.995f)
+			{
+				return new Vector3(-90f, 0f, -(float)Math.Atan2(2.0f * (X * Z - W * Y), 1.0f - 2.0f * (Y * Y + Z * Z)) * radToDeg);
+			}
+			else if (check > 0.995f)
+			{
+				return new Vector3(90f, 0f, (float)Math.Atan2(2.0f * (X * Z - W * Y), 1.0f - 2.0f * (Y * Y + Z * Z)) * radToDeg);
+			}
+			else
+			{
+				return new Vector3(
+					(float)Math.Asin(check) * radToDeg,
+					(float)Math.Atan2(2.0f * (X * Z - W * Y), 1.0f - 2.0f * (X * X + Y * Y)) * radToDeg,
+					(float)Math.Atan2(2.0f * (X * Y - W * Z), 1.0f - 2.0f * (X * X + Z * Z)) * radToDeg);
+			}
+		}
+
+		public float YawAngle => ToEulerAngles().Y;
+
+		public float PitchAngle => ToEulerAngles().X;
+
+		public float RollAngle => ToEulerAngles().Z;
+
+		#endregion
+
+		#region public void Conjugate()
+
+		/// <summary>
+		/// Convert this quaternion to its conjugate
+		/// </summary>
+		public void Conjugate()
+		{
+			Xyz = -Xyz;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Static
+
+		#region Fields
+
+		/// <summary>
+		/// Defines the identity quaternion.
+		/// </summary>
+		public static Quaternion Identity = new Quaternion(0, 0, 0, 1);
+
+		#endregion
+
+		#region Add
+
+		/// <summary>
+		/// Add two quaternions
+		/// </summary>
+		/// <param name="left">The first operand</param>
+		/// <param name="right">The second operand</param>
+		/// <returns>The result of the addition</returns>
+		public static Quaternion Add(Quaternion left, Quaternion right)
+		{
+			return new Quaternion(
+				left.Xyz + right.Xyz,
+				left.W + right.W);
+		}
+
+		/// <summary>
+		/// Add two quaternions
+		/// </summary>
+		/// <param name="left">The first operand</param>
+		/// <param name="right">The second operand</param>
+		/// <param name="result">The result of the addition</param>
+		public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result)
+		{
+			result = new Quaternion(
+				left.Xyz + right.Xyz,
+				left.W + right.W);
+		}
+
+		#endregion
+
+		#region Sub
+
+		/// <summary>
+		/// Subtracts two instances.
+		/// </summary>
+		/// <param name="left">The left instance.</param>
+		/// <param name="right">The right instance.</param>
+		/// <returns>The result of the operation.</returns>
+		public static Quaternion Sub(Quaternion left, Quaternion right)
+		{
+			return  new Quaternion(
+				left.Xyz - right.Xyz,
+				left.W - right.W);
+		}
+
+		/// <summary>
+		/// Subtracts two instances.
+		/// </summary>
+		/// <param name="left">The left instance.</param>
+		/// <param name="right">The right instance.</param>
+		/// <param name="result">The result of the operation.</param>
+		public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result)
+		{
+			result = new Quaternion(
+				left.Xyz - right.Xyz,
+				left.W - right.W);
+		}
+
+		#endregion
+
+		#region Mult
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		[Obsolete("Use Multiply instead.")]
+		public static Quaternion Mult(Quaternion left, Quaternion right)
+		{
+			return new Quaternion(
+				right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
+				left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
+		}
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <param name="result">A new instance containing the result of the calculation.</param>
+		[Obsolete("Use Multiply instead.")]
+		public static void Mult(ref Quaternion left, ref Quaternion right, out Quaternion result)
+		{
+			result = new Quaternion(
+				right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
+				left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
+		}
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		public static Quaternion Multiply(Quaternion left, Quaternion right)
+		{
+			Quaternion result;
+			Multiply(ref left, ref right, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <param name="result">A new instance containing the result of the calculation.</param>
+		public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result)
+		{
+			result = new Quaternion(
+				right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
+				left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="quaternion">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <param name="result">A new instance containing the result of the calculation.</param>
+		public static void Multiply(ref Quaternion quaternion, float scale, out Quaternion result)
+		{
+			result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
+		}
+
+		[Obsolete ("Use the overload without the ref float scale")]
+		public static void Multiply(ref Quaternion quaternion, ref float scale, out Quaternion result)
+		{
+			result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);		
+		}
+	
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="quaternion">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		public static Quaternion Multiply(Quaternion quaternion, float scale)
+		{
+			return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
+		}
+
+		#endregion
+
+		#region Conjugate
+
+		/// <summary>
+		/// Get the conjugate of the given quaternion
+		/// </summary>
+		/// <param name="q">The quaternion</param>
+		/// <returns>The conjugate of the given quaternion</returns>
+		public static Quaternion Conjugate(Quaternion q)
+		{
+			return new Quaternion(-q.Xyz, q.W);
+		}
+
+		/// <summary>
+		/// Get the conjugate of the given quaternion
+		/// </summary>
+		/// <param name="q">The quaternion</param>
+		/// <param name="result">The conjugate of the given quaternion</param>
+		public static void Conjugate(ref Quaternion q, out Quaternion result)
+		{
+			result = new Quaternion(-q.Xyz, q.W);
+		}
+
+		#endregion
+
+		#region Invert
+
+		/// <summary>
+		/// Get the inverse of the given quaternion
+		/// </summary>
+		/// <param name="q">The quaternion to invert</param>
+		/// <returns>The inverse of the given quaternion</returns>
+		public static Quaternion Invert(Quaternion q)
+		{
+			Quaternion result;
+			Invert(ref q, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Get the inverse of the given quaternion
+		/// </summary>
+		/// <param name="q">The quaternion to invert</param>
+		/// <param name="result">The inverse of the given quaternion</param>
+		public static void Invert(ref Quaternion q, out Quaternion result)
+		{
+			float lengthSq = q.LengthSquared;
+			if (lengthSq != 0.0)
+			{
+				float i = 1.0f / lengthSq;
+				result = new Quaternion(q.Xyz * -i, q.W * i);
+			}
+			else
+			{
+				result = q;
+			}
+		}
+
+		#endregion
+
+		#region Normalize
+
+		/// <summary>
+		/// Scale the given quaternion to unit length
+		/// </summary>
+		/// <param name="q">The quaternion to normalize</param>
+		/// <returns>The normalized quaternion</returns>
+		public static Quaternion Normalize(Quaternion q)
+		{
+			Quaternion result;
+			Normalize(ref q, out result);
+			return result;
+		}
+
+		/// <summary>
+		/// Scale the given quaternion to unit length
+		/// </summary>
+		/// <param name="q">The quaternion to normalize</param>
+		/// <param name="result">The normalized quaternion</param>
+		public static void Normalize(ref Quaternion q, out Quaternion result)
+		{
+			float scale = 1.0f / q.Length;
+			result = new Quaternion(q.Xyz * scale, q.W * scale);
+		}
+
+		#endregion
+
+		#region FromAxisAngle
+
+		/// <summary>
+		/// Build a quaternion from the given axis and angle
+		/// </summary>
+		/// <param name="axis">The axis to rotate about</param>
+		/// <param name="angle">The rotation angle in radians</param>
+		/// <returns></returns>
+		public static Quaternion FromAxisAngle(Vector3 axis, float angle)
+		{
+			axis.Normalize();
+			angle *= (float)Math.PI /360f;
+			var sinAngle = (float)Math.Sin(angle);
+			var cosAngle = (float)Math.Cos(angle);
+
+			return new Quaternion(axis.X * sinAngle, axis.Y * sinAngle, axis.Z * sinAngle, cosAngle);
+		}
+
+		#endregion
+
+		#region FromRotationTo
+
+		public static Quaternion FromRotationTo(Vector3 start, Vector3 end)
+		{
+			Quaternion result = new Quaternion();
+			start.Normalize();
+			end.Normalize();
+
+			const float epsilon = 0.000001f;
+			float d = Vector3.Dot(start, end);
+
+			if (d > -1.0f + epsilon)
+			{
+				Vector3 c = Vector3.Cross(start, end);
+				float s = (float)Math.Sqrt((1.0f + d) * 2.0f);
+				float invS = 1.0f / s;
+
+				result.X = c.X * invS;
+				result.Y = c.Y * invS;
+				result.Z = c.Z * invS;
+				result.W = 0.5f * s;
+			}
+			else
+			{
+				Vector3 axis = Vector3.Cross(Vector3.UnitX, start);
+				if (axis.Length < epsilon)
+					axis = Vector3.Cross(Vector3.UnitY, start);
+
+				return FromAxisAngle(axis, 180.0f);
+			}
+			return result;
+		}
+
+		#endregion
+
+		#region Slerp
+
+		/// <summary>
+		/// Do Spherical linear interpolation between two quaternions 
+		/// </summary>
+		/// <param name="q1">The first quaternion</param>
+		/// <param name="q2">The second quaternion</param>
+		/// <param name="blend">The blend factor</param>
+		/// <returns>A smooth blend between the given quaternions</returns>
+		public static Quaternion Slerp(Quaternion q1, Quaternion q2, float blend)
+		{
+			// if either input is zero, return the other.
+			if (q1.LengthSquared == 0.0f)
+			{
+				if (q2.LengthSquared == 0.0f)
+				{
+					return Identity;
+				}
+				return q2;
+			}
+			else if (q2.LengthSquared == 0.0f)
+			{
+				return q1;
+			}
+
+
+			float cosHalfAngle = q1.W * q2.W + Vector3.Dot(q1.Xyz, q2.Xyz);
+
+			if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f)
+			{
+				// angle = 0.0f, so just return one input.
+				return q1;
+			}
+			else if (cosHalfAngle < 0.0f)
+			{
+				q2.Xyz = -q2.Xyz;
+				q2.W = -q2.W;
+				cosHalfAngle = -cosHalfAngle;
+			}
+
+			float blendA;
+			float blendB;
+			if (cosHalfAngle < 0.99f)
+			{
+				// do proper slerp for big angles
+				float halfAngle = (float)System.Math.Acos(cosHalfAngle);
+				float sinHalfAngle = (float)System.Math.Sin(halfAngle);
+				float oneOverSinHalfAngle = 1.0f / sinHalfAngle;
+				blendA = (float)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle;
+				blendB = (float)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle;
+			}
+			else
+			{
+				// do lerp if angle is really small.
+				blendA = 1.0f - blend;
+				blendB = blend;
+			}
+
+			Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W);
+			if (result.LengthSquared > 0.0f)
+				return Normalize(result);
+			else
+				return Identity;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Adds two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Quaternion operator +(Quaternion left, Quaternion right)
+		{
+			left.Xyz += right.Xyz;
+			left.W += right.W;
+			return left;
+		}
+
+		/// <summary>
+		/// Subtracts two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Quaternion operator -(Quaternion left, Quaternion right)
+		{
+			left.Xyz -= right.Xyz;
+			left.W -= right.W;
+			return left;
+		}
+
+		/// <summary>
+		/// Multiplies two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Quaternion operator *(Quaternion left, Quaternion right)
+		{
+			Multiply(ref left, ref right, out left);
+			return left;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="quaternion">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		public static Quaternion operator *(Quaternion quaternion, float scale)
+		{
+			Multiply(ref quaternion, scale, out quaternion);
+			return quaternion;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="quaternion">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		public static Quaternion operator *(float scale, Quaternion quaternion)
+		{
+			return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
+		}        
+		
+		/// <summary>
+		/// Multiplies an instance by a vector3.
+		/// </summary>
+		/// <param name="quaternion">The instance.</param>
+		/// <param name="vector">The vector.</param>
+		/// <returns>A new instance containing the result of the calculation.</returns>
+		public static Vector3 operator *(Quaternion quaternion, Vector3 vector)
+		{
+			var qVec = new Vector3(quaternion.X, quaternion.Y, quaternion.Z);
+			var cross1 = Vector3.Cross(qVec, vector);
+			var cross2 = Vector3.Cross(qVec, cross1);
+			return vector + 2.0f * (cross1 * quaternion.W + cross2);
+		}
+
+		/// <summary>
+		/// Compares two instances for equality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left equals right; false otherwise.</returns>
+		public static bool operator ==(Quaternion left, Quaternion right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares two instances for inequality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left does not equal right; false otherwise.</returns>
+		public static bool operator !=(Quaternion left, Quaternion right)
+		{
+			return !left.Equals(right);
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current Quaternion.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("V: {0}, W: {1}", Xyz, W);
+		}
+
+		#endregion
+
+		#region public override bool Equals (object o)
+
+		/// <summary>
+		/// Compares this object instance to another object for equality. 
+		/// </summary>
+		/// <param name="other">The other object to be used in the comparison.</param>
+		/// <returns>True if both objects are Quaternions of equal value. Otherwise it returns false.</returns>
+		public override bool Equals(object other)
+		{
+			if (other is Quaternion == false) return false;
+			   return this == (Quaternion)other;
+		}
+
+		#endregion
+
+		#region public override int GetHashCode ()
+
+		/// <summary>
+		/// Provides the hash code for this object. 
+		/// </summary>
+		/// <returns>A hash code formed from the bitwise XOR of this objects members.</returns>
+		public override int GetHashCode()
+		{
+			return Xyz.GetHashCode() ^ W.GetHashCode();
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<Quaternion> Members
+
+		/// <summary>
+		/// Compares this Quaternion instance to another Quaternion for equality. 
+		/// </summary>
+		/// <param name="other">The other Quaternion to be used in the comparison.</param>
+		/// <returns>True if both instances are equal; false otherwise.</returns>
+		public bool Equals(Quaternion other)
+		{
+			return Xyz == other.Xyz && W == other.W;
+		}
+
+		#endregion
+	}
+}

+ 10 - 0
Script/AtomicNET/AtomicNET/Math/README.md

@@ -0,0 +1,10 @@
+The classes in this directory are taken from OpenTK, and have the following changes:
+
+	* Quaternion: moved the field "w" from the end to the
+          beginning, to stay compatible with the C++ implementation.
+          Longer term, since we want to share Quaternion with the
+          implementation shipping in our libraries, we will have to change the C++ code to match this.
+
+	* Quaternion: Added a method to create a quaternion from euler x/y/z, without the w.
+	
+	* NAmespace: moved From "OpenTK" to "AtomicEngine"

+ 13 - 0
Script/AtomicNET/AtomicNET/Math/Rect.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+
+[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+public struct Rect
+{
+}
+
+}

+ 1056 - 0
Script/AtomicNET/AtomicNET/Math/Vector2.cs

@@ -0,0 +1,1056 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+namespace AtomicEngine
+{
+	/// <summary>Represents a 2D vector using two single-precision floating-point numbers.</summary>
+	/// <remarks>
+	/// The Vector2 structure is suitable for interoperation with unmanaged code requiring two consecutive floats.
+	/// </remarks>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Vector2 : IEquatable<Vector2>
+	{
+		#region Fields
+
+		/// <summary>
+		/// The X component of the Vector2.
+		/// </summary>
+		public float X;
+
+		/// <summary>
+		/// The Y component of the Vector2.
+		/// </summary>
+		public float Y;
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs a new Vector2.
+		/// </summary>
+		/// <param name="x">The x coordinate of the net Vector2.</param>
+		/// <param name="y">The y coordinate of the net Vector2.</param>
+		public Vector2(float x, float y)
+		{
+			X = x;
+			Y = y;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector2 from the given Vector2.
+		/// </summary>
+		/// <param name="v">The Vector2 to copy components from.</param>
+		[Obsolete]
+		public Vector2(Vector2 v)
+		{
+			X = v.X;
+			Y = v.Y;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector2 from the given Vector3.
+		/// </summary>
+		/// <param name="v">The Vector3 to copy components from. Z is discarded.</param>
+		[Obsolete]
+		public Vector2(Vector3 v)
+		{
+			X = v.X;
+			Y = v.Y;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector2 from the given Vector4.
+		/// </summary>
+		/// <param name="v">The Vector4 to copy components from. Z and W are discarded.</param>
+		[Obsolete]
+		public Vector2(Vector4 v)
+		{
+			X = v.X;
+			Y = v.Y;
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Instance
+
+		#region public void Add()
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(Vector2 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+		}
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(ref Vector2 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+		}
+
+		#endregion public void Add()
+
+		#region public void Sub()
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(Vector2 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+		}
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(ref Vector2 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+		}
+
+		#endregion public void Sub()
+
+		#region public void Mult()
+
+		/// <summary>Multiply this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Mult(float f)
+		{
+			this.X *= f;
+			this.Y *= f;
+		}
+
+		#endregion public void Mult()
+
+		#region public void Div()
+
+		/// <summary>Divide this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public void Div(float f)
+		{
+			float mult = 1.0f / f;
+			this.X *= mult;
+			this.Y *= mult;
+		}
+
+		#endregion public void Div()
+
+		#region public float Length
+
+		/// <summary>
+		/// Gets the length (magnitude) of the vector.
+		/// </summary>
+		/// <see cref="LengthFast"/>
+		/// <seealso cref="LengthSquared"/>
+		public float Length
+		{
+			get
+			{
+				return (float)System.Math.Sqrt(X * X + Y * Y);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthFast
+
+		/// <summary>
+		/// Gets an approximation of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property uses an approximation of the square root function to calculate vector magnitude, with
+		/// an upper error bound of 0.001.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthSquared"/>
+		public float LengthFast
+		{
+			get
+			{
+				return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthSquared
+
+		/// <summary>
+		/// Gets the square of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property avoids the costly square root operation required by the Length property. This makes it more suitable
+		/// for comparisons.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthFast"/>
+		public float LengthSquared
+		{
+			get
+			{
+				return X * X + Y * Y;
+			}
+		}
+
+		#endregion
+
+		#region public Vector2 PerpendicularRight
+
+		/// <summary>
+		/// Gets the perpendicular vector on the right side of this vector.
+		/// </summary>
+		public Vector2 PerpendicularRight
+		{
+			get
+			{
+				return new Vector2(Y, -X);
+			}
+		}
+
+		#endregion
+
+		#region public Vector2 PerpendicularLeft
+
+		/// <summary>
+		/// Gets the perpendicular vector on the left side of this vector.
+		/// </summary>
+		public Vector2 PerpendicularLeft
+		{
+			get
+			{
+				return new Vector2(-Y, X);
+			}
+		}
+
+		#endregion
+
+		#region public void Normalize()
+
+		/// <summary>
+		/// Scales the Vector2 to unit length.
+		/// </summary>
+		public void Normalize()
+		{
+			float scale = 1.0f / this.Length;
+			X *= scale;
+			Y *= scale;
+		}
+
+		#endregion
+
+		#region public void NormalizeFast()
+
+		/// <summary>
+		/// Scales the Vector2 to approximately unit length.
+		/// </summary>
+		public void NormalizeFast()
+		{
+			float scale = MathHelper.InverseSqrtFast(X * X + Y * Y);
+			X *= scale;
+			Y *= scale;
+		}
+
+		#endregion
+
+		#region public void Scale()
+
+		/// <summary>
+		/// Scales the current Vector2 by the given amounts.
+		/// </summary>
+		/// <param name="sx">The scale of the X component.</param>
+		/// <param name="sy">The scale of the Y component.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(float sx, float sy)
+		{
+			this.X = X * sx;
+			this.Y = Y * sy;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(Vector2 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(ref Vector2 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+		}
+
+		#endregion public void Scale()
+
+		#endregion
+
+		#region Static
+
+		#region Fields
+
+		/// <summary>
+		/// Defines a unit-length Vector2 that points towards the X-axis.
+		/// </summary>
+		public static readonly Vector2 UnitX = new Vector2(1, 0);
+
+		/// <summary>
+		/// Defines a unit-length Vector2 that points towards the Y-axis.
+		/// </summary>
+		public static readonly Vector2 UnitY = new Vector2(0, 1);
+
+		/// <summary>
+		/// Defines a zero-length Vector2.
+		/// </summary>
+		public static readonly Vector2 Zero = new Vector2(0, 0);
+
+		/// <summary>
+		/// Defines an instance with all components set to 1.
+		/// </summary>
+		public static readonly Vector2 One = new Vector2(1, 1);
+
+		/// <summary>
+		/// Defines the size of the Vector2 struct in bytes.
+		/// </summary>
+		public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2());
+
+		#endregion
+
+		#region Obsolete
+
+		#region Sub
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		[Obsolete("Use static Subtract() method instead.")]
+		public static Vector2 Sub(Vector2 a, Vector2 b)
+		{
+			a.X -= b.X;
+			a.Y -= b.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public static void Sub(ref Vector2 a, ref Vector2 b, out Vector2 result)
+		{
+			result.X = a.X - b.X;
+			result.Y = a.Y - b.Y;
+		}
+
+		#endregion
+
+		#region Mult
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the multiplication</returns>
+		[Obsolete("Use static Multiply() method instead.")]
+		public static Vector2 Mult(Vector2 a, float f)
+		{
+			a.X *= f;
+			a.Y *= f;
+			return a;
+		}
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the multiplication</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public static void Mult(ref Vector2 a, float f, out Vector2 result)
+		{
+			result.X = a.X * f;
+			result.Y = a.Y * f;
+		}
+
+		#endregion
+
+		#region Div
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the division</returns>
+		[Obsolete("Use static Divide() method instead.")]
+		public static Vector2 Div(Vector2 a, float f)
+		{
+			float mult = 1.0f / f;
+			a.X *= mult;
+			a.Y *= mult;
+			return a;
+		}
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the division</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public static void Div(ref Vector2 a, float f, out Vector2 result)
+		{
+			float mult = 1.0f / f;
+			result.X = a.X * mult;
+			result.Y = a.Y * mult;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Add
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <returns>Result of operation.</returns>
+		public static Vector2 Add(Vector2 a, Vector2 b)
+		{
+			Add(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <param name="result">Result of operation.</param>
+		public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result)
+		{
+			result = new Vector2(a.X + b.X, a.Y + b.Y);
+		}
+
+		#endregion
+
+		#region Subtract
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		public static Vector2 Subtract(Vector2 a, Vector2 b)
+		{
+			Subtract(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		public static void Subtract(ref Vector2 a, ref Vector2 b, out Vector2 result)
+		{
+			result = new Vector2(a.X - b.X, a.Y - b.Y);
+		}
+
+		#endregion
+
+		#region Multiply
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector2 Multiply(Vector2 vector, float scale)
+		{
+			Multiply(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector2 vector, float scale, out Vector2 result)
+		{
+			result = new Vector2(vector.X * scale, vector.Y * scale);
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector2 Multiply(Vector2 vector, Vector2 scale)
+		{
+			Multiply(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector2 vector, ref Vector2 scale, out Vector2 result)
+		{
+			result = new Vector2(vector.X * scale.X, vector.Y * scale.Y);
+		}
+
+		#endregion
+
+		#region Divide
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector2 Divide(Vector2 vector, float scale)
+		{
+			Divide(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector2 vector, float scale, out Vector2 result)
+		{
+			Multiply(ref vector, 1 / scale, out result);
+		}
+
+		/// <summary>
+		/// Divides a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector2 Divide(Vector2 vector, Vector2 scale)
+		{
+			Divide(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divide a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector2 vector, ref Vector2 scale, out Vector2 result)
+		{
+			result = new Vector2(vector.X / scale.X, vector.Y / scale.Y);
+		}
+
+		#endregion
+
+		#region ComponentMin
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise minimum</returns>
+		public static Vector2 ComponentMin(Vector2 a, Vector2 b)
+		{
+			a.X = a.X < b.X ? a.X : b.X;
+			a.Y = a.Y < b.Y ? a.Y : b.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise minimum</param>
+		public static void ComponentMin(ref Vector2 a, ref Vector2 b, out Vector2 result)
+		{
+			result.X = a.X < b.X ? a.X : b.X;
+			result.Y = a.Y < b.Y ? a.Y : b.Y;
+		}
+
+		#endregion
+
+		#region ComponentMax
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise maximum</returns>
+		public static Vector2 ComponentMax(Vector2 a, Vector2 b)
+		{
+			a.X = a.X > b.X ? a.X : b.X;
+			a.Y = a.Y > b.Y ? a.Y : b.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise maximum</param>
+		public static void ComponentMax(ref Vector2 a, ref Vector2 b, out Vector2 result)
+		{
+			result.X = a.X > b.X ? a.X : b.X;
+			result.Y = a.Y > b.Y ? a.Y : b.Y;
+		}
+
+		#endregion
+
+		#region Min
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static Vector2 Min(Vector2 left, Vector2 right)
+		{
+			return left.LengthSquared < right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Max
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static Vector2 Max(Vector2 left, Vector2 right)
+		{
+			return left.LengthSquared >= right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Clamp
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <returns>The clamped vector</returns>
+		public static Vector2 Clamp(Vector2 vec, Vector2 min, Vector2 max)
+		{
+			vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			return vec;
+		}
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <param name="result">The clamped vector</param>
+		public static void Clamp(ref Vector2 vec, ref Vector2 min, ref Vector2 max, out Vector2 result)
+		{
+			result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+		}
+
+		#endregion
+
+		#region Normalize
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector2 Normalize(Vector2 vec)
+		{
+			float scale = 1.0f / vec.Length;
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void Normalize(ref Vector2 vec, out Vector2 result)
+		{
+			float scale = 1.0f / vec.Length;
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+		}
+
+		#endregion
+
+		#region NormalizeFast
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector2 NormalizeFast(Vector2 vec)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y);
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void NormalizeFast(ref Vector2 vec, out Vector2 result)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y);
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+		}
+
+		#endregion
+
+		#region Dot
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The dot product of the two inputs</returns>
+		public static float Dot(Vector2 left, Vector2 right)
+		{
+			return left.X * right.X + left.Y * right.Y;
+		}
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <param name="result">The dot product of the two inputs</param>
+		public static void Dot(ref Vector2 left, ref Vector2 right, out float result)
+		{
+			result = left.X * right.X + left.Y * right.Y;
+		}
+
+		#endregion
+
+		#region Lerp
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <returns>a when blend=0, b when blend=1, and a linear combination otherwise</returns>
+		public static Vector2 Lerp(Vector2 a, Vector2 b, float blend)
+		{
+			a.X = blend * (b.X - a.X) + a.X;
+			a.Y = blend * (b.Y - a.Y) + a.Y;
+			return a;
+		}
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <param name="result">a when blend=0, b when blend=1, and a linear combination otherwise</param>
+		public static void Lerp(ref Vector2 a, ref Vector2 b, float blend, out Vector2 result)
+		{
+			result.X = blend * (b.X - a.X) + a.X;
+			result.Y = blend * (b.Y - a.Y) + a.Y;
+		}
+
+		#endregion
+
+		#region Barycentric
+
+		/// <summary>
+		/// Interpolate 3 Vectors using Barycentric coordinates
+		/// </summary>
+		/// <param name="a">First input Vector</param>
+		/// <param name="b">Second input Vector</param>
+		/// <param name="c">Third input Vector</param>
+		/// <param name="u">First Barycentric Coordinate</param>
+		/// <param name="v">Second Barycentric Coordinate</param>
+		/// <returns>a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</returns>
+		public static Vector2 BaryCentric(Vector2 a, Vector2 b, Vector2 c, float u, float v)
+		{
+			return a + u * (b - a) + v * (c - a);
+		}
+
+		/// <summary>Interpolate 3 Vectors using Barycentric coordinates</summary>
+		/// <param name="a">First input Vector.</param>
+		/// <param name="b">Second input Vector.</param>
+		/// <param name="c">Third input Vector.</param>
+		/// <param name="u">First Barycentric Coordinate.</param>
+		/// <param name="v">Second Barycentric Coordinate.</param>
+		/// <param name="result">Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</param>
+		public static void BaryCentric(ref Vector2 a, ref Vector2 b, ref Vector2 c, float u, float v, out Vector2 result)
+		{
+			result = a; // copy
+
+			Vector2 temp = b; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, u, out temp);
+			Add(ref result, ref temp, out result);
+
+			temp = c; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, v, out temp);
+			Add(ref result, ref temp, out result);
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Adds the specified instances.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>Result of addition.</returns>
+		public static Vector2 operator +(Vector2 left, Vector2 right)
+		{
+			left.X += right.X;
+			left.Y += right.Y;
+			return left;
+		}
+
+		/// <summary>
+		/// Subtracts the specified instances.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>Result of subtraction.</returns>
+		public static Vector2 operator -(Vector2 left, Vector2 right)
+		{
+			left.X -= right.X;
+			left.Y -= right.Y;
+			return left;
+		}
+
+		/// <summary>
+		/// Negates the specified instance.
+		/// </summary>
+		/// <param name="vec">Operand.</param>
+		/// <returns>Result of negation.</returns>
+		public static Vector2 operator -(Vector2 vec)
+		{
+			vec.X = -vec.X;
+			vec.Y = -vec.Y;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies the specified instance by a scalar.
+		/// </summary>
+		/// <param name="vec">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of multiplication.</returns>
+		public static Vector2 operator *(Vector2 vec, float scale)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies the specified instance by a scalar.
+		/// </summary>
+		/// <param name="scale">Left operand.</param>
+		/// <param name="vec">Right operand.</param>
+		/// <returns>Result of multiplication.</returns>
+		public static Vector2 operator *(float scale, Vector2 vec)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Divides the specified instance by a scalar.
+		/// </summary>
+		/// <param name="vec">Left operand</param>
+		/// <param name="scale">Right operand</param>
+		/// <returns>Result of the division.</returns>
+		public static Vector2 operator /(Vector2 vec, float scale)
+		{
+			float mult = 1.0f / scale;
+			vec.X *= mult;
+			vec.Y *= mult;
+			return vec;
+		}
+
+		/// <summary>
+		/// Compares the specified instances for equality.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>True if both instances are equal; false otherwise.</returns>
+		public static bool operator ==(Vector2 left, Vector2 right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares the specified instances for inequality.
+		/// </summary>
+		/// <param name="left">Left operand.</param>
+		/// <param name="right">Right operand.</param>
+		/// <returns>True if both instances are not equal; false otherwise.</returns>
+		public static bool operator !=(Vector2 left, Vector2 right)
+		{
+			return !left.Equals(right);
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current Vector2.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("({0}, {1})", X, Y);
+		}
+
+		#endregion
+
+		#region public override int GetHashCode()
+
+		/// <summary>
+		/// Returns the hashcode for this instance.
+		/// </summary>
+		/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return X.GetHashCode() ^ Y.GetHashCode();
+		}
+
+		#endregion
+
+		#region public override bool Equals(object obj)
+
+		/// <summary>
+		/// Indicates whether this instance and a specified object are equal.
+		/// </summary>
+		/// <param name="obj">The object to compare to.</param>
+		/// <returns>True if the instances are equal; false otherwise.</returns>
+		public override bool Equals(object obj)
+		{
+			if (!(obj is Vector2))
+				return false;
+
+			return this.Equals((Vector2)obj);
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<Vector2> Members
+
+		/// <summary>Indicates whether the current vector is equal to another vector.</summary>
+		/// <param name="other">A vector to compare with this vector.</param>
+		/// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
+		public bool Equals(Vector2 other)
+		{
+			return
+				X == other.X &&
+				Y == other.Y;
+		}
+
+		#endregion
+	}
+}

+ 1358 - 0
Script/AtomicNET/AtomicNET/Math/Vector3.cs

@@ -0,0 +1,1358 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+	/// <summary>
+	/// Represents a 3D vector using three single-precision floating-point numbers.
+	/// </summary>
+	/// <remarks>
+	/// The Vector3 structure is suitable for interoperation with unmanaged code requiring three consecutive floats.
+	/// </remarks>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Vector3 : IEquatable<Vector3>
+	{
+		#region Fields
+
+		/// <summary>
+		/// The X component of the Vector3.
+		/// </summary>
+		public float X;
+
+		/// <summary>
+		/// The Y component of the Vector3.
+		/// </summary>
+		public float Y;
+
+		/// <summary>
+		/// The Z component of the Vector3.
+		/// </summary>
+		public float Z;
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs a new Vector3.
+		/// </summary>
+		/// <param name="x">The x component of the Vector3.</param>
+		/// <param name="y">The y component of the Vector3.</param>
+		/// <param name="z">The z component of the Vector3.</param>
+		public Vector3(float x, float y, float z)
+		{
+			X = x;
+			Y = y;
+			Z = z;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector3 from the given Vector2.
+		/// </summary>
+		/// <param name="v">The Vector2 to copy components from.</param>
+		public Vector3(Vector2 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = 0.0f;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector3 from the given Vector3.
+		/// </summary>
+		/// <param name="v">The Vector3 to copy components from.</param>
+		public Vector3(Vector3 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = v.Z;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector3 from the given Vector4.
+		/// </summary>
+		/// <param name="v">The Vector4 to copy components from.</param>
+		public Vector3(Vector4 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = v.Z;
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Instance
+
+		#region public void Add()
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(Vector3 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+			this.Z += right.Z;
+		}
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(ref Vector3 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+			this.Z += right.Z;
+		}
+
+		#endregion public void Add()
+
+		#region public void Sub()
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(Vector3 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+			this.Z -= right.Z;
+		}
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(ref Vector3 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+			this.Z -= right.Z;
+		}
+
+		#endregion public void Sub()
+
+		#region public void Mult()
+
+		/// <summary>Multiply this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Mult(float f)
+		{
+			this.X *= f;
+			this.Y *= f;
+			this.Z *= f;
+		}
+
+		#endregion public void Mult()
+
+		#region public void Div()
+
+		/// <summary>Divide this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public void Div(float f)
+		{
+			float mult = 1.0f / f;
+			this.X *= mult;
+			this.Y *= mult;
+			this.Z *= mult;
+		}
+
+		#endregion public void Div()
+
+		#region public float Length
+
+		/// <summary>
+		/// Gets the length (magnitude) of the vector.
+		/// </summary>
+		/// <see cref="LengthFast"/>
+		/// <seealso cref="LengthSquared"/>
+		public float Length
+		{
+			get
+			{
+				return (float)System.Math.Sqrt(X * X + Y * Y + Z * Z);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthFast
+
+		/// <summary>
+		/// Gets an approximation of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property uses an approximation of the square root function to calculate vector magnitude, with
+		/// an upper error bound of 0.001.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthSquared"/>
+		public float LengthFast
+		{
+			get
+			{
+				return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthSquared
+
+		/// <summary>
+		/// Gets the square of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property avoids the costly square root operation required by the Length property. This makes it more suitable
+		/// for comparisons.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthFast"/>
+		public float LengthSquared
+		{
+			get
+			{
+				return X * X + Y * Y + Z * Z;
+			}
+		}
+
+		#endregion
+
+		#region public void Normalize()
+
+		/// <summary>
+		/// Scales the Vector3 to unit length.
+		/// </summary>
+		public void Normalize()
+		{
+			float scale = 1.0f / this.Length;
+			X *= scale;
+			Y *= scale;
+			Z *= scale;
+		}
+
+		#endregion
+
+		public void Abs()
+		{
+			X = Math.Abs(X);
+			Y = Math.Abs(Y);
+			Z = Math.Abs(Z);
+		}
+
+		#region public void NormalizeFast()
+
+		/// <summary>
+		/// Scales the Vector3 to approximately unit length.
+		/// </summary>
+		public void NormalizeFast()
+		{
+			float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z);
+			X *= scale;
+			Y *= scale;
+			Z *= scale;
+		}
+
+		#endregion
+
+		#region public void Scale()
+
+		/// <summary>
+		/// Scales the current Vector3 by the given amounts.
+		/// </summary>
+		/// <param name="sx">The scale of the X component.</param>
+		/// <param name="sy">The scale of the Y component.</param>
+		/// <param name="sz">The scale of the Z component.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(float sx, float sy, float sz)
+		{
+			this.X = X * sx;
+			this.Y = Y * sy;
+			this.Z = Z * sz;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(Vector3 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+			this.Z *= scale.Z;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(ref Vector3 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+			this.Z *= scale.Z;
+		}
+
+		#endregion public void Scale()
+
+		#endregion
+
+		#region Static
+
+		#region Fields
+
+		/// <summary>
+		/// Defines a unit-length Vector3 that points towards the X-axis.
+		/// </summary>
+		public static readonly Vector3 UnitX = new Vector3(1, 0, 0);
+
+		/// <summary>
+		/// Defines a unit-length Vector3 that points towards the Y-axis.
+		/// </summary>
+		public static readonly Vector3 UnitY = new Vector3(0, 1, 0);
+
+		/// <summary>
+		/// /// Defines a unit-length Vector3 that points towards the Z-axis.
+		/// </summary>
+		public static readonly Vector3 UnitZ = new Vector3(0, 0, 1);
+
+		/// <summary>
+		/// Defines a zero-length Vector3.
+		/// </summary>
+		public static readonly Vector3 Zero = new Vector3(0, 0, 0);
+
+		/// <summary>
+		/// Defines an instance with all components set to 1.
+		/// </summary>
+		public static readonly Vector3 One = new Vector3(1, 1, 1);
+
+		/// (-1,0,0) vector.
+		static public readonly Vector3 Left = new Vector3(-1, 0, 0);
+		/// (1,0,0) vector.
+		static public readonly Vector3 Right = new Vector3(1, 0, 0);
+		/// (0,1,0) vector.
+		static public readonly Vector3 Up = new Vector3(0, 1, 0);
+		/// (0,-1,0) vector.
+		static public readonly Vector3 Down = new Vector3(0, -1, 0);
+		/// (0,0,1) vector.
+		static public readonly Vector3 Forward = new Vector3(0, 0, 1);
+		/// (0,0,-1) vector.
+		static public readonly Vector3 Back = new Vector3(0, 0, -1);
+		
+		/// <summary>
+		/// Defines the size of the Vector3 struct in bytes.
+		/// </summary>
+		public static readonly int SizeInBytes = Marshal.SizeOf(new Vector3());
+
+		#endregion
+
+		#region Obsolete
+
+		#region Sub
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		[Obsolete("Use static Subtract() method instead.")]
+		public static Vector3 Sub(Vector3 a, Vector3 b)
+		{
+			a.X -= b.X;
+			a.Y -= b.Y;
+			a.Z -= b.Z;
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public static void Sub(ref Vector3 a, ref Vector3 b, out Vector3 result)
+		{
+			result.X = a.X - b.X;
+			result.Y = a.Y - b.Y;
+			result.Z = a.Z - b.Z;
+		}
+
+		#endregion
+
+		#region Mult
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the multiplication</returns>
+		[Obsolete("Use static Multiply() method instead.")]
+		public static Vector3 Mult(Vector3 a, float f)
+		{
+			a.X *= f;
+			a.Y *= f;
+			a.Z *= f;
+			return a;
+		}
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the multiplication</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public static void Mult(ref Vector3 a, float f, out Vector3 result)
+		{
+			result.X = a.X * f;
+			result.Y = a.Y * f;
+			result.Z = a.Z * f;
+		}
+
+		#endregion
+
+		#region Div
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the division</returns>
+		[Obsolete("Use static Divide() method instead.")]
+		public static Vector3 Div(Vector3 a, float f)
+		{
+			float mult = 1.0f / f;
+			a.X *= mult;
+			a.Y *= mult;
+			a.Z *= mult;
+			return a;
+		}
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the division</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public static void Div(ref Vector3 a, float f, out Vector3 result)
+		{
+			float mult = 1.0f / f;
+			result.X = a.X * mult;
+			result.Y = a.Y * mult;
+			result.Z = a.Z * mult;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Add
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <returns>Result of operation.</returns>
+		public static Vector3 Add(Vector3 a, Vector3 b)
+		{
+			Add(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <param name="result">Result of operation.</param>
+		public static void Add(ref Vector3 a, ref Vector3 b, out Vector3 result)
+		{
+			result = new Vector3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
+		}
+
+		#endregion
+
+		#region Subtract
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		public static Vector3 Subtract(Vector3 a, Vector3 b)
+		{
+			Subtract(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		public static void Subtract(ref Vector3 a, ref Vector3 b, out Vector3 result)
+		{
+			result = new Vector3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
+		}
+
+		#endregion
+
+		#region Multiply
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector3 Multiply(Vector3 vector, float scale)
+		{
+			Multiply(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector3 vector, float scale, out Vector3 result)
+		{
+			result = new Vector3(vector.X * scale, vector.Y * scale, vector.Z * scale);
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector3 Multiply(Vector3 vector, Vector3 scale)
+		{
+			Multiply(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector3 vector, ref Vector3 scale, out Vector3 result)
+		{
+			result = new Vector3(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z);
+		}
+
+		#endregion
+
+		#region Divide
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector3 Divide(Vector3 vector, float scale)
+		{
+			Divide(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector3 vector, float scale, out Vector3 result)
+		{
+			Multiply(ref vector, 1 / scale, out result);
+		}
+
+		/// <summary>
+		/// Divides a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector3 Divide(Vector3 vector, Vector3 scale)
+		{
+			Divide(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divide a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector3 vector, ref Vector3 scale, out Vector3 result)
+		{
+			result = new Vector3(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z);
+		}
+
+		#endregion
+
+		#region ComponentMin
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise minimum</returns>
+		public static Vector3 ComponentMin(Vector3 a, Vector3 b)
+		{
+			a.X = a.X < b.X ? a.X : b.X;
+			a.Y = a.Y < b.Y ? a.Y : b.Y;
+			a.Z = a.Z < b.Z ? a.Z : b.Z;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise minimum</param>
+		public static void ComponentMin(ref Vector3 a, ref Vector3 b, out Vector3 result)
+		{
+			result.X = a.X < b.X ? a.X : b.X;
+			result.Y = a.Y < b.Y ? a.Y : b.Y;
+			result.Z = a.Z < b.Z ? a.Z : b.Z;
+		}
+
+		#endregion
+
+		#region ComponentMax
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise maximum</returns>
+		public static Vector3 ComponentMax(Vector3 a, Vector3 b)
+		{
+			a.X = a.X > b.X ? a.X : b.X;
+			a.Y = a.Y > b.Y ? a.Y : b.Y;
+			a.Z = a.Z > b.Z ? a.Z : b.Z;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise maximum</param>
+		public static void ComponentMax(ref Vector3 a, ref Vector3 b, out Vector3 result)
+		{
+			result.X = a.X > b.X ? a.X : b.X;
+			result.Y = a.Y > b.Y ? a.Y : b.Y;
+			result.Z = a.Z > b.Z ? a.Z : b.Z;
+		}
+
+		#endregion
+
+		#region Min
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static Vector3 Min(Vector3 left, Vector3 right)
+		{
+			return left.LengthSquared < right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Max
+
+		/// <summary>
+		/// Returns the Vector3 with the minimum magnitude
+		/// </summary>
+		/// <param name="left">Left operand</param>
+		/// <param name="right">Right operand</param>
+		/// <returns>The minimum Vector3</returns>
+		public static Vector3 Max(Vector3 left, Vector3 right)
+		{
+			return left.LengthSquared >= right.LengthSquared ? left : right;
+		}
+
+		#endregion
+
+		#region Clamp
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <returns>The clamped vector</returns>
+		public static Vector3 Clamp(Vector3 vec, Vector3 min, Vector3 max)
+		{
+			vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			vec.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z;
+			return vec;
+		}
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <param name="result">The clamped vector</param>
+		public static void Clamp(ref Vector3 vec, ref Vector3 min, ref Vector3 max, out Vector3 result)
+		{
+			result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			result.Z = vec.Z < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z;
+		}
+
+		#endregion
+
+		#region Normalize
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector3 Normalize(Vector3 vec)
+		{
+			float scale = 1.0f / vec.Length;
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void Normalize(ref Vector3 vec, out Vector3 result)
+		{
+			float scale = 1.0f / vec.Length;
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+			result.Z = vec.Z * scale;
+		}
+
+		#endregion
+
+		#region NormalizeFast
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector3 NormalizeFast(Vector3 vec)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void NormalizeFast(ref Vector3 vec, out Vector3 result)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z);
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+			result.Z = vec.Z * scale;
+		}
+
+		#endregion
+
+		#region Dot
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The dot product of the two inputs</returns>
+		public static float Dot(Vector3 left, Vector3 right)
+		{
+			return left.X * right.X + left.Y * right.Y + left.Z * right.Z;
+		}
+
+		/// <summary>
+		/// Calculate the dot (scalar) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <param name="result">The dot product of the two inputs</param>
+		public static void Dot(ref Vector3 left, ref Vector3 right, out float result)
+		{
+			result = left.X * right.X + left.Y * right.Y + left.Z * right.Z;
+		}
+
+		#endregion
+
+		#region Cross
+
+		/// <summary>
+		/// Caclulate the cross (vector) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The cross product of the two inputs</returns>
+		public static Vector3 Cross(Vector3 left, Vector3 right)
+		{
+			return new Vector3(left.Y * right.Z - left.Z * right.Y,
+							   left.Z * right.X - left.X * right.Z,
+							   left.X * right.Y - left.Y * right.X);
+		}
+
+		/// <summary>
+		/// Caclulate the cross (vector) product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The cross product of the two inputs</returns>
+		/// <param name="result">The cross product of the two inputs</param>
+		public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result)
+		{
+			result.X = left.Y * right.Z - left.Z * right.Y;
+			result.Y = left.Z * right.X - left.X * right.Z;
+			result.Z = left.X * right.Y - left.Y * right.X;
+		}
+
+		#endregion
+
+		#region Lerp
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <returns>a when blend=0, b when blend=1, and a linear combination otherwise</returns>
+		public static Vector3 Lerp(Vector3 a, Vector3 b, float blend)
+		{
+			a.X = blend * (b.X - a.X) + a.X;
+			a.Y = blend * (b.Y - a.Y) + a.Y;
+			a.Z = blend * (b.Z - a.Z) + a.Z;
+			return a;
+		}
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <param name="result">a when blend=0, b when blend=1, and a linear combination otherwise</param>
+		public static void Lerp(ref Vector3 a, ref Vector3 b, float blend, out Vector3 result)
+		{
+			result.X = blend * (b.X - a.X) + a.X;
+			result.Y = blend * (b.Y - a.Y) + a.Y;
+			result.Z = blend * (b.Z - a.Z) + a.Z;
+		}
+
+		#endregion
+
+		#region Barycentric
+
+		/// <summary>
+		/// Interpolate 3 Vectors using Barycentric coordinates
+		/// </summary>
+		/// <param name="a">First input Vector</param>
+		/// <param name="b">Second input Vector</param>
+		/// <param name="c">Third input Vector</param>
+		/// <param name="u">First Barycentric Coordinate</param>
+		/// <param name="v">Second Barycentric Coordinate</param>
+		/// <returns>a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</returns>
+		public static Vector3 BaryCentric(Vector3 a, Vector3 b, Vector3 c, float u, float v)
+		{
+			return a + u * (b - a) + v * (c - a);
+		}
+
+		/// <summary>Interpolate 3 Vectors using Barycentric coordinates</summary>
+		/// <param name="a">First input Vector.</param>
+		/// <param name="b">Second input Vector.</param>
+		/// <param name="c">Third input Vector.</param>
+		/// <param name="u">First Barycentric Coordinate.</param>
+		/// <param name="v">Second Barycentric Coordinate.</param>
+		/// <param name="result">Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</param>
+		public static void BaryCentric(ref Vector3 a, ref Vector3 b, ref Vector3 c, float u, float v, out Vector3 result)
+		{
+			result = a; // copy
+
+			Vector3 temp = b; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, u, out temp);
+			Add(ref result, ref temp, out result);
+
+			temp = c; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, v, out temp);
+			Add(ref result, ref temp, out result);
+		}
+
+		#endregion
+
+		#region Transform
+
+		/// <summary>Transform a direction vector by the given Matrix
+		/// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored.
+		/// </summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed vector</returns>
+		public static Vector3 TransformVector(Vector3 vec, Matrix4 mat)
+		{
+			Vector3 v;
+			v.X = Vector3.Dot(vec, new Vector3(mat.Column0));
+			v.Y = Vector3.Dot(vec, new Vector3(mat.Column1));
+			v.Z = Vector3.Dot(vec, new Vector3(mat.Column2));
+			return v;
+		}
+
+		/// <summary>Transform a direction vector by the given Matrix
+		/// Assumes the matrix has a bottom row of (0,0,0,1), that is the translation part is ignored.
+		/// </summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed vector</param>
+		public static void TransformVector(ref Vector3 vec, ref Matrix4 mat, out Vector3 result)
+		{
+			result.X = vec.X * mat.Row0.X +
+					   vec.Y * mat.Row1.X +
+					   vec.Z * mat.Row2.X;
+
+			result.Y = vec.X * mat.Row0.Y +
+					   vec.Y * mat.Row1.Y +
+					   vec.Z * mat.Row2.Y;
+
+			result.Z = vec.X * mat.Row0.Z +
+					   vec.Y * mat.Row1.Z +
+					   vec.Z * mat.Row2.Z;
+		}
+
+		/// <summary>Transform a Normal by the given Matrix</summary>
+		/// <remarks>
+		/// This calculates the inverse of the given matrix, use TransformNormalInverse if you
+		/// already have the inverse to avoid this extra calculation
+		/// </remarks>
+		/// <param name="norm">The normal to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed normal</returns>
+		public static Vector3 TransformNormal(Vector3 norm, Matrix4 mat)
+		{
+			mat.Invert();
+			return TransformNormalInverse(norm, mat);
+		}
+
+		/// <summary>Transform a Normal by the given Matrix</summary>
+		/// <remarks>
+		/// This calculates the inverse of the given matrix, use TransformNormalInverse if you
+		/// already have the inverse to avoid this extra calculation
+		/// </remarks>
+		/// <param name="norm">The normal to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed normal</param>
+		public static void TransformNormal(ref Vector3 norm, ref Matrix4 mat, out Vector3 result)
+		{
+			Matrix4 Inverse = Matrix4.Invert(mat);
+			Vector3.TransformNormalInverse(ref norm, ref Inverse, out result);
+		}
+
+		/// <summary>Transform a Normal by the (transpose of the) given Matrix</summary>
+		/// <remarks>
+		/// This version doesn't calculate the inverse matrix.
+		/// Use this version if you already have the inverse of the desired transform to hand
+		/// </remarks>
+		/// <param name="norm">The normal to transform</param>
+		/// <param name="invMat">The inverse of the desired transformation</param>
+		/// <returns>The transformed normal</returns>
+		public static Vector3 TransformNormalInverse(Vector3 norm, Matrix4 invMat)
+		{
+			Vector3 n;
+			n.X = Vector3.Dot(norm, new Vector3(invMat.Row0));
+			n.Y = Vector3.Dot(norm, new Vector3(invMat.Row1));
+			n.Z = Vector3.Dot(norm, new Vector3(invMat.Row2));
+			return n;
+		}
+
+		/// <summary>Transform a Normal by the (transpose of the) given Matrix</summary>
+		/// <remarks>
+		/// This version doesn't calculate the inverse matrix.
+		/// Use this version if you already have the inverse of the desired transform to hand
+		/// </remarks>
+		/// <param name="norm">The normal to transform</param>
+		/// <param name="invMat">The inverse of the desired transformation</param>
+		/// <param name="result">The transformed normal</param>
+		public static void TransformNormalInverse(ref Vector3 norm, ref Matrix4 invMat, out Vector3 result)
+		{
+			result.X = norm.X * invMat.Row0.X +
+					   norm.Y * invMat.Row0.Y +
+					   norm.Z * invMat.Row0.Z;
+
+			result.Y = norm.X * invMat.Row1.X +
+					   norm.Y * invMat.Row1.Y +
+					   norm.Z * invMat.Row1.Z;
+
+			result.Z = norm.X * invMat.Row2.X +
+					   norm.Y * invMat.Row2.Y +
+					   norm.Z * invMat.Row2.Z;
+		}
+
+		/// <summary>Transform a Position by the given Matrix</summary>
+		/// <param name="pos">The position to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed position</returns>
+		public static Vector3 TransformPosition(Vector3 pos, Matrix4 mat)
+		{
+			Vector3 p;
+			p.X = Vector3.Dot(pos, new Vector3(mat.Column0)) + mat.Row3.X;
+			p.Y = Vector3.Dot(pos, new Vector3(mat.Column1)) + mat.Row3.Y;
+			p.Z = Vector3.Dot(pos, new Vector3(mat.Column2)) + mat.Row3.Z;
+			return p;
+		}
+
+		/// <summary>Transform a Position by the given Matrix</summary>
+		/// <param name="pos">The position to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed position</param>
+		public static void TransformPosition(ref Vector3 pos, ref Matrix4 mat, out Vector3 result)
+		{
+			result.X = pos.X * mat.Row0.X +
+					   pos.Y * mat.Row1.X +
+					   pos.Z * mat.Row2.X +
+					   mat.Row3.X;
+
+			result.Y = pos.X * mat.Row0.Y +
+					   pos.Y * mat.Row1.Y +
+					   pos.Z * mat.Row2.Y +
+					   mat.Row3.Y;
+
+			result.Z = pos.X * mat.Row0.Z +
+					   pos.Y * mat.Row1.Z +
+					   pos.Z * mat.Row2.Z +
+					   mat.Row3.Z;
+		}
+
+		/// <summary>Transform a Vector by the given Matrix</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed vector</returns>
+		public static Vector4 Transform(Vector3 vec, Matrix4 mat)
+		{
+			Vector4 v4 = new Vector4(vec.X, vec.Y, vec.Z, 1.0f);
+			Vector4 result;
+			result.X = Vector4.Dot(v4, mat.Column0);
+			result.Y = Vector4.Dot(v4, mat.Column1);
+			result.Z = Vector4.Dot(v4, mat.Column2);
+			result.W = Vector4.Dot(v4, mat.Column3);
+			return result;
+		}
+
+		/// <summary>Transform a Vector by the given Matrix</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed vector</param>
+		public static void Transform(ref Vector3 vec, ref Matrix4 mat, out Vector4 result)
+		{
+			Vector4 v4 = new Vector4(vec.X, vec.Y, vec.Z, 1.0f);
+			Vector4.Transform(ref v4, ref mat, out result);
+		}
+
+		/// <summary>Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed vector</returns>
+		public static Vector3 TransformPerspective(Vector3 vec, Matrix4 mat)
+		{
+			Vector4 h = Transform(vec, mat);
+			return new Vector3(h.X / h.W, h.Y / h.W, h.Z / h.W);
+		}
+
+		/// <summary>Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed vector</param>
+		public static void TransformPerspective(ref Vector3 vec, ref Matrix4 mat, out Vector3 result)
+		{
+			Vector4 h;
+			Vector3.Transform(ref vec, ref mat, out h);
+			result.X = h.X / h.W;
+			result.Y = h.Y / h.W;
+			result.Z = h.Z / h.W;
+		}
+
+		#endregion
+
+		#region CalculateAngle
+
+		/// <summary>
+		/// Calculates the angle (in radians) between two vectors.
+		/// </summary>
+		/// <param name="first">The first vector.</param>
+		/// <param name="second">The second vector.</param>
+		/// <returns>Angle (in radians) between the vectors.</returns>
+		/// <remarks>Note that the returned angle is never bigger than the constant Pi.</remarks>
+		public static float CalculateAngle(Vector3 first, Vector3 second)
+		{
+			return (float)System.Math.Acos((Vector3.Dot(first, second)) / (first.Length * second.Length));
+		}
+
+		/// <summary>Calculates the angle (in radians) between two vectors.</summary>
+		/// <param name="first">The first vector.</param>
+		/// <param name="second">The second vector.</param>
+		/// <param name="result">Angle (in radians) between the vectors.</param>
+		/// <remarks>Note that the returned angle is never bigger than the constant Pi.</remarks>
+		public static void CalculateAngle(ref Vector3 first, ref Vector3 second, out float result)
+		{
+			float temp;
+			Vector3.Dot(ref first, ref second, out temp);
+			result = (float)System.Math.Acos(temp / (first.Length * second.Length));
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Swizzle
+
+		/// <summary>
+		/// Gets or sets an OpenTK.Vector2 with the X and Y components of this instance.
+		/// </summary>
+		
+		public Vector2 Xy { get { return new Vector2(X, Y); } set { X = value.X; Y = value.Y; } }
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Adds two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator +(Vector3 left, Vector3 right)
+		{
+			left.X += right.X;
+			left.Y += right.Y;
+			left.Z += right.Z;
+			return left;
+		}
+
+		/// <summary>
+		/// Subtracts two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator -(Vector3 left, Vector3 right)
+		{
+			left.X -= right.X;
+			left.Y -= right.Y;
+			left.Z -= right.Z;
+			return left;
+		}
+
+		/// <summary>
+		/// Negates an instance.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator -(Vector3 vec)
+		{
+			vec.X = -vec.X;
+			vec.Y = -vec.Y;
+			vec.Z = -vec.Z;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator *(Vector3 vec, float scale)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="scale">The scalar.</param>
+		/// <param name="vec">The instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator *(float scale, Vector3 vec)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Divides an instance by a scalar.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector3 operator /(Vector3 vec, float scale)
+		{
+			float mult = 1.0f / scale;
+			vec.X *= mult;
+			vec.Y *= mult;
+			vec.Z *= mult;
+			return vec;
+		}
+
+		/// <summary>
+		/// Compares two instances for equality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left equals right; false otherwise.</returns>
+		public static bool operator ==(Vector3 left, Vector3 right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares two instances for inequality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left does not equa lright; false otherwise.</returns>
+		public static bool operator !=(Vector3 left, Vector3 right)
+		{
+			return !left.Equals(right);
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current Vector3.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("({0}, {1}, {2})", X, Y, Z);
+		}
+
+		#endregion
+
+		#region public override int GetHashCode()
+
+		/// <summary>
+		/// Returns the hashcode for this instance.
+		/// </summary>
+		/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();
+		}
+
+		#endregion
+
+		#region public override bool Equals(object obj)
+
+		/// <summary>
+		/// Indicates whether this instance and a specified object are equal.
+		/// </summary>
+		/// <param name="obj">The object to compare to.</param>
+		/// <returns>True if the instances are equal; false otherwise.</returns>
+		public override bool Equals(object obj)
+		{
+			if (!(obj is Vector3))
+				return false;
+
+			return this.Equals((Vector3)obj);
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<Vector3> Members
+
+		/// <summary>Indicates whether the current vector is equal to another vector.</summary>
+		/// <param name="other">A vector to compare with this vector.</param>
+		/// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
+		public bool Equals(Vector3 other)
+		{
+			return
+				X == other.X &&
+				Y == other.Y &&
+				Z == other.Z;
+		}
+
+		#endregion
+	}
+}

+ 1186 - 0
Script/AtomicNET/AtomicNET/Math/Vector4.cs

@@ -0,0 +1,1186 @@
+#region --- License ---
+/*
+Copyright (c) 2006 - 2008 The Open Toolkit library.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+	/// <summary>Represents a 4D vector using four single-precision floating-point numbers.</summary>
+	/// <remarks>
+	/// The Vector4 structure is suitable for interoperation with unmanaged code requiring four consecutive floats.
+	/// </remarks>
+	[StructLayout(LayoutKind.Sequential)]
+	public struct Vector4 : IEquatable<Vector4>
+	{
+		#region Fields
+
+		/// <summary>
+		/// The X component of the Vector4.
+		/// </summary>
+		public float X;
+
+		/// <summary>
+		/// The Y component of the Vector4.
+		/// </summary>
+		public float Y;
+
+		/// <summary>
+		/// The Z component of the Vector4.
+		/// </summary>
+		public float Z;
+
+		/// <summary>
+		/// The W component of the Vector4.
+		/// </summary>
+		public float W;
+
+		/// <summary>
+		/// Defines a unit-length Vector4 that points towards the X-axis.
+		/// </summary>
+		public static Vector4 UnitX = new Vector4(1, 0, 0, 0);
+
+		/// <summary>
+		/// Defines a unit-length Vector4 that points towards the Y-axis.
+		/// </summary>
+		public static Vector4 UnitY = new Vector4(0, 1, 0, 0);
+
+		/// <summary>
+		/// Defines a unit-length Vector4 that points towards the Z-axis.
+		/// </summary>
+		public static Vector4 UnitZ = new Vector4(0, 0, 1, 0);
+
+		/// <summary>
+		/// Defines a unit-length Vector4 that points towards the W-axis.
+		/// </summary>
+		public static Vector4 UnitW = new Vector4(0, 0, 0, 1);
+
+		/// <summary>
+		/// Defines a zero-length Vector4.
+		/// </summary>
+		public static Vector4 Zero = new Vector4(0, 0, 0, 0);
+
+		/// <summary>
+		/// Defines an instance with all components set to 1.
+		/// </summary>
+		public static readonly Vector4 One = new Vector4(1, 1, 1, 1);
+
+		/// <summary>
+		/// Defines the size of the Vector4 struct in bytes.
+		/// </summary>
+		public static readonly int SizeInBytes = Marshal.SizeOf(new Vector4());
+
+		#endregion
+
+		#region Constructors
+
+		/// <summary>
+		/// Constructs a new Vector4.
+		/// </summary>
+		/// <param name="x">The x component of the Vector4.</param>
+		/// <param name="y">The y component of the Vector4.</param>
+		/// <param name="z">The z component of the Vector4.</param>
+		/// <param name="w">The z component of the Vector4.</param>
+		public Vector4(float x, float y, float z, float w)
+		{
+			X = x;
+			Y = y;
+			Z = z;
+			W = w;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector4 from the given Vector2.
+		/// </summary>
+		/// <param name="v">The Vector2 to copy components from.</param>
+		public Vector4(Vector2 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = 0.0f;
+			W = 0.0f;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector4 from the given Vector3.
+		/// </summary>
+		/// <param name="v">The Vector3 to copy components from.</param>
+		public Vector4(Vector3 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = v.Z;
+			W = 0.0f;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector4 from the specified Vector3 and W component.
+		/// </summary>
+		/// <param name="v">The Vector3 to copy components from.</param>
+		/// <param name="w">The W component of the new Vector4.</param>
+		public Vector4(Vector3 v, float w)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = v.Z;
+			W = w;
+		}
+
+		/// <summary>
+		/// Constructs a new Vector4 from the given Vector4.
+		/// </summary>
+		/// <param name="v">The Vector4 to copy components from.</param>
+		public Vector4(Vector4 v)
+		{
+			X = v.X;
+			Y = v.Y;
+			Z = v.Z;
+			W = v.W;
+		}
+
+		#endregion
+
+		#region Public Members
+
+		#region Instance
+
+		#region public void Add()
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(Vector4 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+			this.Z += right.Z;
+			this.W += right.W;
+		}
+
+		/// <summary>Add the Vector passed as parameter to this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Add() method instead.")]
+		public void Add(ref Vector4 right)
+		{
+			this.X += right.X;
+			this.Y += right.Y;
+			this.Z += right.Z;
+			this.W += right.W;
+		}
+
+		#endregion public void Add()
+
+		#region public void Sub()
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(Vector4 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+			this.Z -= right.Z;
+			this.W -= right.W;
+		}
+
+		/// <summary>Subtract the Vector passed as parameter from this instance.</summary>
+		/// <param name="right">Right operand. This parameter is only read from.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Subtract() method instead.")]
+		public void Sub(ref Vector4 right)
+		{
+			this.X -= right.X;
+			this.Y -= right.Y;
+			this.Z -= right.Z;
+			this.W -= right.W;
+		}
+
+		#endregion public void Sub()
+
+		#region public void Mult()
+
+		/// <summary>Multiply this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Mult(float f)
+		{
+			this.X *= f;
+			this.Y *= f;
+			this.Z *= f;
+			this.W *= f;
+		}
+
+		#endregion public void Mult()
+
+		#region public void Div()
+
+		/// <summary>Divide this instance by a scalar.</summary>
+		/// <param name="f">Scalar operand.</param>
+		[Obsolete("Use static Divide() method instead.")]
+		public void Div(float f)
+		{
+			float mult = 1.0f / f;
+			this.X *= mult;
+			this.Y *= mult;
+			this.Z *= mult;
+			this.W *= mult;
+		}
+
+		#endregion public void Div()
+
+		#region public float Length
+
+		/// <summary>
+		/// Gets the length (magnitude) of the vector.
+		/// </summary>
+		/// <see cref="LengthFast"/>
+		/// <seealso cref="LengthSquared"/>
+		public float Length
+		{
+			get
+			{
+				return (float)System.Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthFast
+
+		/// <summary>
+		/// Gets an approximation of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property uses an approximation of the square root function to calculate vector magnitude, with
+		/// an upper error bound of 0.001.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthSquared"/>
+		public float LengthFast
+		{
+			get
+			{
+				return 1.0f / MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W);
+			}
+		}
+
+		#endregion
+
+		#region public float LengthSquared
+
+		/// <summary>
+		/// Gets the square of the vector length (magnitude).
+		/// </summary>
+		/// <remarks>
+		/// This property avoids the costly square root operation required by the Length property. This makes it more suitable
+		/// for comparisons.
+		/// </remarks>
+		/// <see cref="Length"/>
+		/// <seealso cref="LengthFast"/>
+		public float LengthSquared
+		{
+			get
+			{
+				return X * X + Y * Y + Z * Z + W * W;
+			}
+		}
+
+		#endregion
+
+		#region public void Normalize()
+
+		/// <summary>
+		/// Scales the Vector4 to unit length.
+		/// </summary>
+		public void Normalize()
+		{
+			float scale = 1.0f / this.Length;
+			X *= scale;
+			Y *= scale;
+			Z *= scale;
+			W *= scale;
+		}
+
+		#endregion
+
+		#region public void NormalizeFast()
+
+		/// <summary>
+		/// Scales the Vector4 to approximately unit length.
+		/// </summary>
+		public void NormalizeFast()
+		{
+			float scale = MathHelper.InverseSqrtFast(X * X + Y * Y + Z * Z + W * W);
+			X *= scale;
+			Y *= scale;
+			Z *= scale;
+			W *= scale;
+		}
+
+		#endregion
+
+		#region public void Scale()
+
+		/// <summary>
+		/// Scales the current Vector4 by the given amounts.
+		/// </summary>
+		/// <param name="sx">The scale of the X component.</param>
+		/// <param name="sy">The scale of the Y component.</param>
+		/// <param name="sz">The scale of the Z component.</param>
+		/// <param name="sw">The scale of the Z component.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(float sx, float sy, float sz, float sw)
+		{
+			this.X = X * sx;
+			this.Y = Y * sy;
+			this.Z = Z * sz;
+			this.W = W * sw;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(Vector4 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+			this.Z *= scale.Z;
+			this.W *= scale.W;
+		}
+
+		/// <summary>Scales this instance by the given parameter.</summary>
+		/// <param name="scale">The scaling of the individual components.</param>
+		[CLSCompliant(false)]
+		[Obsolete("Use static Multiply() method instead.")]
+		public void Scale(ref Vector4 scale)
+		{
+			this.X *= scale.X;
+			this.Y *= scale.Y;
+			this.Z *= scale.Z;
+			this.W *= scale.W;
+		}
+
+		#endregion public void Scale()
+
+		#endregion
+
+		#region Static
+
+		#region Obsolete
+
+		#region Sub
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		public static Vector4 Sub(Vector4 a, Vector4 b)
+		{
+			a.X -= b.X;
+			a.Y -= b.Y;
+			a.Z -= b.Z;
+			a.W -= b.W;
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		public static void Sub(ref Vector4 a, ref Vector4 b, out Vector4 result)
+		{
+			result.X = a.X - b.X;
+			result.Y = a.Y - b.Y;
+			result.Z = a.Z - b.Z;
+			result.W = a.W - b.W;
+		}
+
+		#endregion
+
+		#region Mult
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the multiplication</returns>
+		public static Vector4 Mult(Vector4 a, float f)
+		{
+			a.X *= f;
+			a.Y *= f;
+			a.Z *= f;
+			a.W *= f;
+			return a;
+		}
+
+		/// <summary>
+		/// Multiply a vector and a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the multiplication</param>
+		public static void Mult(ref Vector4 a, float f, out Vector4 result)
+		{
+			result.X = a.X * f;
+			result.Y = a.Y * f;
+			result.Z = a.Z * f;
+			result.W = a.W * f;
+		}
+
+		#endregion
+
+		#region Div
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <returns>Result of the division</returns>
+		public static Vector4 Div(Vector4 a, float f)
+		{
+			float mult = 1.0f / f;
+			a.X *= mult;
+			a.Y *= mult;
+			a.Z *= mult;
+			a.W *= mult;
+			return a;
+		}
+
+		/// <summary>
+		/// Divide a vector by a scalar
+		/// </summary>
+		/// <param name="a">Vector operand</param>
+		/// <param name="f">Scalar operand</param>
+		/// <param name="result">Result of the division</param>
+		public static void Div(ref Vector4 a, float f, out Vector4 result)
+		{
+			float mult = 1.0f / f;
+			result.X = a.X * mult;
+			result.Y = a.Y * mult;
+			result.Z = a.Z * mult;
+			result.W = a.W * mult;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Add
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <returns>Result of operation.</returns>
+		public static Vector4 Add(Vector4 a, Vector4 b)
+		{
+			Add(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Adds two vectors.
+		/// </summary>
+		/// <param name="a">Left operand.</param>
+		/// <param name="b">Right operand.</param>
+		/// <param name="result">Result of operation.</param>
+		public static void Add(ref Vector4 a, ref Vector4 b, out Vector4 result)
+		{
+			result = new Vector4(a.X + b.X, a.Y + b.Y, a.Z + b.Z, a.W + b.W);
+		}
+
+		#endregion
+
+		#region Subtract
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>Result of subtraction</returns>
+		public static Vector4 Subtract(Vector4 a, Vector4 b)
+		{
+			Subtract(ref a, ref b, out a);
+			return a;
+		}
+
+		/// <summary>
+		/// Subtract one Vector from another
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">Result of subtraction</param>
+		public static void Subtract(ref Vector4 a, ref Vector4 b, out Vector4 result)
+		{
+			result = new Vector4(a.X - b.X, a.Y - b.Y, a.Z - b.Z, a.W - b.W);
+		}
+
+		#endregion
+
+		#region Multiply
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector4 Multiply(Vector4 vector, float scale)
+		{
+			Multiply(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector4 vector, float scale, out Vector4 result)
+		{
+			result = new Vector4(vector.X * scale, vector.Y * scale, vector.Z * scale, vector.W * scale);
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector4 Multiply(Vector4 vector, Vector4 scale)
+		{
+			Multiply(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Multiplies a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Multiply(ref Vector4 vector, ref Vector4 scale, out Vector4 result)
+		{
+			result = new Vector4(vector.X * scale.X, vector.Y * scale.Y, vector.Z * scale.Z, vector.W * scale.W);
+		}
+
+		#endregion
+
+		#region Divide
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector4 Divide(Vector4 vector, float scale)
+		{
+			Divide(ref vector, scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divides a vector by a scalar.
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector4 vector, float scale, out Vector4 result)
+		{
+			Multiply(ref vector, 1 / scale, out result);
+		}
+
+		/// <summary>
+		/// Divides a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <returns>Result of the operation.</returns>
+		public static Vector4 Divide(Vector4 vector, Vector4 scale)
+		{
+			Divide(ref vector, ref scale, out vector);
+			return vector;
+		}
+
+		/// <summary>
+		/// Divide a vector by the components of a vector (scale).
+		/// </summary>
+		/// <param name="vector">Left operand.</param>
+		/// <param name="scale">Right operand.</param>
+		/// <param name="result">Result of the operation.</param>
+		public static void Divide(ref Vector4 vector, ref Vector4 scale, out Vector4 result)
+		{
+			result = new Vector4(vector.X / scale.X, vector.Y / scale.Y, vector.Z / scale.Z, vector.W / scale.W);
+		}
+
+		#endregion
+
+		#region Min
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise minimum</returns>
+		public static Vector4 Min(Vector4 a, Vector4 b)
+		{
+			a.X = a.X < b.X ? a.X : b.X;
+			a.Y = a.Y < b.Y ? a.Y : b.Y;
+			a.Z = a.Z < b.Z ? a.Z : b.Z;
+			a.W = a.W < b.W ? a.W : b.W;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise minimum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise minimum</param>
+		public static void Min(ref Vector4 a, ref Vector4 b, out Vector4 result)
+		{
+			result.X = a.X < b.X ? a.X : b.X;
+			result.Y = a.Y < b.Y ? a.Y : b.Y;
+			result.Z = a.Z < b.Z ? a.Z : b.Z;
+			result.W = a.W < b.W ? a.W : b.W;
+		}
+
+		#endregion
+
+		#region Max
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <returns>The component-wise maximum</returns>
+		public static Vector4 Max(Vector4 a, Vector4 b)
+		{
+			a.X = a.X > b.X ? a.X : b.X;
+			a.Y = a.Y > b.Y ? a.Y : b.Y;
+			a.Z = a.Z > b.Z ? a.Z : b.Z;
+			a.W = a.W > b.W ? a.W : b.W;
+			return a;
+		}
+
+		/// <summary>
+		/// Calculate the component-wise maximum of two vectors
+		/// </summary>
+		/// <param name="a">First operand</param>
+		/// <param name="b">Second operand</param>
+		/// <param name="result">The component-wise maximum</param>
+		public static void Max(ref Vector4 a, ref Vector4 b, out Vector4 result)
+		{
+			result.X = a.X > b.X ? a.X : b.X;
+			result.Y = a.Y > b.Y ? a.Y : b.Y;
+			result.Z = a.Z > b.Z ? a.Z : b.Z;
+			result.W = a.W > b.W ? a.W : b.W;
+		}
+
+		#endregion
+
+		#region Clamp
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <returns>The clamped vector</returns>
+		public static Vector4 Clamp(Vector4 vec, Vector4 min, Vector4 max)
+		{
+			vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			vec.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z;
+			vec.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W;
+			return vec;
+		}
+
+		/// <summary>
+		/// Clamp a vector to the given minimum and maximum vectors
+		/// </summary>
+		/// <param name="vec">Input vector</param>
+		/// <param name="min">Minimum vector</param>
+		/// <param name="max">Maximum vector</param>
+		/// <param name="result">The clamped vector</param>
+		public static void Clamp(ref Vector4 vec, ref Vector4 min, ref Vector4 max, out Vector4 result)
+		{
+			result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
+			result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
+			result.Z = vec.X < min.Z ? min.Z : vec.Z > max.Z ? max.Z : vec.Z;
+			result.W = vec.Y < min.W ? min.W : vec.W > max.W ? max.W : vec.W;
+		}
+
+		#endregion
+
+		#region Normalize
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector4 Normalize(Vector4 vec)
+		{
+			float scale = 1.0f / vec.Length;
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			vec.W *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void Normalize(ref Vector4 vec, out Vector4 result)
+		{
+			float scale = 1.0f / vec.Length;
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+			result.Z = vec.Z * scale;
+			result.W = vec.W * scale;
+		}
+
+		#endregion
+
+		#region NormalizeFast
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <returns>The normalized vector</returns>
+		public static Vector4 NormalizeFast(Vector4 vec)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W);
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			vec.W *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Scale a vector to approximately unit length
+		/// </summary>
+		/// <param name="vec">The input vector</param>
+		/// <param name="result">The normalized vector</param>
+		public static void NormalizeFast(ref Vector4 vec, out Vector4 result)
+		{
+			float scale = MathHelper.InverseSqrtFast(vec.X * vec.X + vec.Y * vec.Y + vec.Z * vec.Z + vec.W * vec.W);
+			result.X = vec.X * scale;
+			result.Y = vec.Y * scale;
+			result.Z = vec.Z * scale;
+			result.W = vec.W * scale;
+		}
+
+		#endregion
+
+		#region Dot
+
+		/// <summary>
+		/// Calculate the dot product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <returns>The dot product of the two inputs</returns>
+		public static float Dot(Vector4 left, Vector4 right)
+		{
+			return left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W;
+		}
+
+		/// <summary>
+		/// Calculate the dot product of two vectors
+		/// </summary>
+		/// <param name="left">First operand</param>
+		/// <param name="right">Second operand</param>
+		/// <param name="result">The dot product of the two inputs</param>
+		public static void Dot(ref Vector4 left, ref Vector4 right, out float result)
+		{
+			result = left.X * right.X + left.Y * right.Y + left.Z * right.Z + left.W * right.W;
+		}
+
+		#endregion
+
+		#region Lerp
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <returns>a when blend=0, b when blend=1, and a linear combination otherwise</returns>
+		public static Vector4 Lerp(Vector4 a, Vector4 b, float blend)
+		{
+			a.X = blend * (b.X - a.X) + a.X;
+			a.Y = blend * (b.Y - a.Y) + a.Y;
+			a.Z = blend * (b.Z - a.Z) + a.Z;
+			a.W = blend * (b.W - a.W) + a.W;
+			return a;
+		}
+
+		/// <summary>
+		/// Returns a new Vector that is the linear blend of the 2 given Vectors
+		/// </summary>
+		/// <param name="a">First input vector</param>
+		/// <param name="b">Second input vector</param>
+		/// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
+		/// <param name="result">a when blend=0, b when blend=1, and a linear combination otherwise</param>
+		public static void Lerp(ref Vector4 a, ref Vector4 b, float blend, out Vector4 result)
+		{
+			result.X = blend * (b.X - a.X) + a.X;
+			result.Y = blend * (b.Y - a.Y) + a.Y;
+			result.Z = blend * (b.Z - a.Z) + a.Z;
+			result.W = blend * (b.W - a.W) + a.W;
+		}
+
+		#endregion
+
+		#region Barycentric
+
+		/// <summary>
+		/// Interpolate 3 Vectors using Barycentric coordinates
+		/// </summary>
+		/// <param name="a">First input Vector</param>
+		/// <param name="b">Second input Vector</param>
+		/// <param name="c">Third input Vector</param>
+		/// <param name="u">First Barycentric Coordinate</param>
+		/// <param name="v">Second Barycentric Coordinate</param>
+		/// <returns>a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</returns>
+		public static Vector4 BaryCentric(Vector4 a, Vector4 b, Vector4 c, float u, float v)
+		{
+			return a + u * (b - a) + v * (c - a);
+		}
+
+		/// <summary>Interpolate 3 Vectors using Barycentric coordinates</summary>
+		/// <param name="a">First input Vector.</param>
+		/// <param name="b">Second input Vector.</param>
+		/// <param name="c">Third input Vector.</param>
+		/// <param name="u">First Barycentric Coordinate.</param>
+		/// <param name="v">Second Barycentric Coordinate.</param>
+		/// <param name="result">Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</param>
+		public static void BaryCentric(ref Vector4 a, ref Vector4 b, ref Vector4 c, float u, float v, out Vector4 result)
+		{
+			result = a; // copy
+
+			Vector4 temp = b; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, u, out temp);
+			Add(ref result, ref temp, out result);
+
+			temp = c; // copy
+			Subtract(ref temp, ref a, out temp);
+			Multiply(ref temp, v, out temp);
+			Add(ref result, ref temp, out result);
+		}
+
+		#endregion
+
+		#region Transform
+
+		/// <summary>Transform a Vector by the given Matrix</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <returns>The transformed vector</returns>
+		public static Vector4 Transform(Vector4 vec, Matrix4 mat)
+		{
+			Vector4 result;
+			result.X = Vector4.Dot(vec, mat.Column0);
+			result.Y = Vector4.Dot(vec, mat.Column1);
+			result.Z = Vector4.Dot(vec, mat.Column2);
+			result.W = Vector4.Dot(vec, mat.Column3);
+			return result;
+		}
+
+		/// <summary>Transform a Vector by the given Matrix</summary>
+		/// <param name="vec">The vector to transform</param>
+		/// <param name="mat">The desired transformation</param>
+		/// <param name="result">The transformed vector</param>
+		public static void Transform(ref Vector4 vec, ref Matrix4 mat, out Vector4 result)
+		{
+			result.X = vec.X * mat.Row0.X +
+					   vec.Y * mat.Row1.X +
+					   vec.Z * mat.Row2.X +
+					   vec.W * mat.Row3.X;
+
+			result.Y = vec.X * mat.Row0.Y +
+					   vec.Y * mat.Row1.Y +
+					   vec.Z * mat.Row2.Y +
+					   vec.W * mat.Row3.Y;
+
+			result.Z = vec.X * mat.Row0.Z +
+					   vec.Y * mat.Row1.Z +
+					   vec.Z * mat.Row2.Z +
+					   vec.W * mat.Row3.Z;
+
+			result.W = vec.X * mat.Row0.W +
+					   vec.Y * mat.Row1.W +
+					   vec.Z * mat.Row2.W +
+					   vec.W * mat.Row3.W;
+		}
+
+		#endregion
+
+		#endregion
+
+		#region Swizzle
+
+		/// <summary>
+		/// Gets or sets an OpenTK.Vector2 with the X and Y components of this instance.
+		/// </summary>
+		
+		public Vector2 Xy { get { return new Vector2(X, Y); } set { X = value.X; Y = value.Y; } }
+
+		/// <summary>
+		/// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance.
+		/// </summary>
+		
+		public Vector3 Xyz { get { return new Vector3(X, Y, Z); } set { X = value.X; Y = value.Y; Z = value.Z; } }
+
+		#endregion
+
+		#region Operators
+
+		/// <summary>
+		/// Adds two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator +(Vector4 left, Vector4 right)
+		{
+			left.X += right.X;
+			left.Y += right.Y;
+			left.Z += right.Z;
+			left.W += right.W;
+			return left;
+		}
+
+		/// <summary>
+		/// Subtracts two instances.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator -(Vector4 left, Vector4 right)
+		{
+			left.X -= right.X;
+			left.Y -= right.Y;
+			left.Z -= right.Z;
+			left.W -= right.W;
+			return left;
+		}
+
+		/// <summary>
+		/// Negates an instance.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator -(Vector4 vec)
+		{
+			vec.X = -vec.X;
+			vec.Y = -vec.Y;
+			vec.Z = -vec.Z;
+			vec.W = -vec.W;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator *(Vector4 vec, float scale)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			vec.W *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Multiplies an instance by a scalar.
+		/// </summary>
+		/// <param name="scale">The scalar.</param>
+		/// <param name="vec">The instance.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator *(float scale, Vector4 vec)
+		{
+			vec.X *= scale;
+			vec.Y *= scale;
+			vec.Z *= scale;
+			vec.W *= scale;
+			return vec;
+		}
+
+		/// <summary>
+		/// Divides an instance by a scalar.
+		/// </summary>
+		/// <param name="vec">The instance.</param>
+		/// <param name="scale">The scalar.</param>
+		/// <returns>The result of the calculation.</returns>
+		public static Vector4 operator /(Vector4 vec, float scale)
+		{
+			float mult = 1.0f / scale;
+			vec.X *= mult;
+			vec.Y *= mult;
+			vec.Z *= mult;
+			vec.W *= mult;
+			return vec;
+		}
+
+		/// <summary>
+		/// Compares two instances for equality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left equals right; false otherwise.</returns>
+		public static bool operator ==(Vector4 left, Vector4 right)
+		{
+			return left.Equals(right);
+		}
+
+		/// <summary>
+		/// Compares two instances for inequality.
+		/// </summary>
+		/// <param name="left">The first instance.</param>
+		/// <param name="right">The second instance.</param>
+		/// <returns>True, if left does not equa lright; false otherwise.</returns>
+		public static bool operator !=(Vector4 left, Vector4 right)
+		{
+			return !left.Equals(right);
+		}
+
+		/// <summary>
+		/// Returns a pointer to the first element of the specified instance.
+		/// </summary>
+		/// <param name="v">The instance.</param>
+		/// <returns>A pointer to the first element of v.</returns>
+		[CLSCompliant(false)]
+		unsafe public static explicit operator float*(Vector4 v)
+		{
+			return &v.X;
+		}
+
+		/// <summary>
+		/// Returns a pointer to the first element of the specified instance.
+		/// </summary>
+		/// <param name="v">The instance.</param>
+		/// <returns>A pointer to the first element of v.</returns>
+		public static explicit operator IntPtr(Vector4 v)
+		{
+			unsafe
+			{
+				return (IntPtr)(&v.X);
+			}
+		}
+
+		#endregion
+
+		#region Overrides
+
+		#region public override string ToString()
+
+		/// <summary>
+		/// Returns a System.String that represents the current Vector4.
+		/// </summary>
+		/// <returns></returns>
+		public override string ToString()
+		{
+			return String.Format("({0}, {1}, {2}, {3})", X, Y, Z, W);
+		}
+
+		#endregion
+
+		#region public override int GetHashCode()
+
+		/// <summary>
+		/// Returns the hashcode for this instance.
+		/// </summary>
+		/// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
+		public override int GetHashCode()
+		{
+			return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode() ^ W.GetHashCode();
+		}
+
+		#endregion
+
+		#region public override bool Equals(object obj)
+
+		/// <summary>
+		/// Indicates whether this instance and a specified object are equal.
+		/// </summary>
+		/// <param name="obj">The object to compare to.</param>
+		/// <returns>True if the instances are equal; false otherwise.</returns>
+		public override bool Equals(object obj)
+		{
+			if (!(obj is Vector4))
+				return false;
+
+			return this.Equals((Vector4)obj);
+		}
+
+		#endregion
+
+		#endregion
+
+		#endregion
+
+		#region IEquatable<Vector4> Members
+
+		/// <summary>Indicates whether the current vector is equal to another vector.</summary>
+		/// <param name="other">A vector to compare with this vector.</param>
+		/// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
+		public bool Equals(Vector4 other)
+		{
+			return
+				X == other.X &&
+				Y == other.Y &&
+				Z == other.Z &&
+				W == other.W;
+		}
+
+		#endregion
+	}
+}

+ 14 - 0
Script/AtomicNET/AtomicNET/Scene/CSComponent.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public partial class CSComponent : ScriptComponent
+    {
+
+
+    }
+
+}

+ 206 - 0
Script/AtomicNET/AtomicNET/Scene/CSComponentCore.cs

@@ -0,0 +1,206 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Linq;
+
+namespace AtomicEngine
+{
+    internal class CSComponentInfo
+    {
+        public CSComponentInfo(Type type)
+        {
+            this.Type = type;
+
+            // Fields
+
+            var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+            .Where(field => field.IsDefined(typeof(InspectorAttribute), true));
+
+            InspectorFields = fields.ToArray<FieldInfo>();
+
+            foreach (var field in InspectorFields)
+            {
+                fieldLookup[AtomicNET.StringToStringHash(field.Name)] = field;
+            }
+
+            // Methods
+            Type[] parms = new Type[1] { typeof(float) };
+            UpdateMethod = type.GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.DefaultBinder, parms, null);
+        }
+
+        public void ApplyFieldValues(CSComponent component, IntPtr fieldValuePtr)
+        {
+            // FIXME: This will need to be optimized, specifically to use uint key hashes for value lookup
+
+            fieldMap.CopyVariantMap(fieldValuePtr);
+
+            foreach (var field in InspectorFields)
+            {
+                if (fieldMap.Contains(field.Name))
+                {
+                    var fieldType = field.FieldType;
+
+                    if (fieldType.IsEnum)
+                    {
+                        field.SetValue(component, fieldMap.GetInt(field.Name));
+                        continue;
+                    }
+
+                    switch (Type.GetTypeCode(fieldType))
+                    {
+                        case TypeCode.Boolean:
+                            field.SetValue(component, fieldMap.GetBool(field.Name));
+                            break;
+
+                        case TypeCode.Int32:
+                            field.SetValue(component, fieldMap.GetInt(field.Name));
+                            break;
+
+                        case TypeCode.Single:
+                            field.SetValue(component, fieldMap.GetFloat(field.Name));
+                            break;
+
+                        case TypeCode.String:
+                            field.SetValue(component, fieldMap.GetString(field.Name));
+                            break;
+
+                        default:
+
+                            if (fieldType == typeof(Vector3))
+                            {
+                                field.SetValue(component, fieldMap.GetVector3(field.Name));
+                            }
+                            else if (fieldType == typeof(Quaternion))
+                            {
+                                field.SetValue(component, fieldMap.GetQuaternion(field.Name));
+                            }
+                            else if (fieldType.IsSubclassOf(typeof(Resource)))
+                            {
+                                field.SetValue(component, fieldMap.GetResourceFromRef(field.Name));
+                            }
+                            else if (fieldType.IsSubclassOf(typeof(RefCounted)))
+                            {
+                                field.SetValue(component, fieldMap.GetPtr(field.Name));
+                            }
+
+                            break;
+                    }
+                }
+            }
+
+        }
+
+        public void RegisterInstance(CSComponent component)
+        {
+            Instances.Add(component);
+        }
+
+
+        public List<CSComponent> Instances = new List<CSComponent>();
+        public FieldInfo[] InspectorFields;
+        public Type Type;
+        public MethodInfo UpdateMethod = null;
+
+        ScriptVariantMap fieldMap = new ScriptVariantMap();
+
+        public Dictionary<uint, FieldInfo> fieldLookup = new Dictionary<uint, FieldInfo>();
+    }
+
+    internal class CSComponentCore : NETScriptObject
+    {
+
+        void HandleUpdate(uint eventType, ScriptVariantMap eventData)
+        {
+            Object[] args = new Object[1] { eventData.GetFloat("timestep") };
+
+            foreach (var csinfo in csinfoLookup.Values)
+            {
+                var updateMethod = csinfo.UpdateMethod;
+
+                if (updateMethod != null)
+                {
+                    foreach (var instance in csinfo.Instances)
+                    {
+                        updateMethod.Invoke(instance, args);
+                    }
+                }
+            }
+        }
+
+        void HandleComponentLoad(uint eventType, ScriptVariantMap eventData)
+        {
+            var assemblyPath = eventData["AssemblyPath"];
+            var className = eventData["ClassName"];
+            IntPtr csnative = eventData.GetVoidPtr("NativeInstance");
+            IntPtr fieldValues = IntPtr.Zero;
+
+            if (eventData.Contains("FieldValues"))
+                fieldValues = eventData.GetVoidPtr("FieldValues");
+
+            Dictionary<string, CSComponentInfo> assemblyTypes = null;
+
+            if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
+            {
+                return;
+            }
+
+            CSComponentInfo csinfo;
+
+            if (!assemblyTypes.TryGetValue(className, out csinfo))
+            {
+                return;
+            }
+
+            NativeCore.NativeContructorOverride = csnative;
+            var component = (CSComponent)Activator.CreateInstance(csinfo.Type);
+            NativeCore.VerifyNativeContructorOverrideConsumed();
+
+            if (fieldValues != IntPtr.Zero)
+                csinfo.ApplyFieldValues(component, fieldValues);
+
+            csinfo.RegisterInstance(component);
+
+        }
+
+        void HandleComponentAssemblyReference(uint eventType, ScriptVariantMap eventData)
+        {
+            string assemblyPath = eventData["AssemblyPath"];
+
+            Dictionary<string, CSComponentInfo> assemblyTypes = null;
+
+            if (!componentCache.TryGetValue(assemblyPath, out assemblyTypes))
+            {
+                componentCache[assemblyPath] = assemblyTypes = new Dictionary<string, CSComponentInfo>();
+            }
+
+            Assembly assembly = Assembly.LoadFrom(assemblyPath);
+
+            Type[] types = assembly.GetTypes();
+
+            foreach (var type in types)
+            {
+                if (type.IsSubclassOf(typeof(CSComponent)))
+                {
+                    var csinfo = new CSComponentInfo(type);
+                    csinfoLookup[csinfo.Type] = csinfo;
+                    assemblyTypes[type.Name] = csinfo;
+                }
+            }
+        }
+
+        internal static void Initialize()
+        {
+            instance = new CSComponentCore();
+
+            instance.SubscribeToEvent("CSComponentAssemblyReference", instance.HandleComponentAssemblyReference);
+            instance.SubscribeToEvent("CSComponentLoad", instance.HandleComponentLoad);
+            instance.SubscribeToEvent("Update", instance.HandleUpdate);
+        }
+
+        Dictionary<string, Dictionary<string, CSComponentInfo>> componentCache = new Dictionary<string, Dictionary<string, CSComponentInfo>>();
+
+        Dictionary<Type, CSComponentInfo> csinfoLookup = new Dictionary<Type, CSComponentInfo>();
+
+        static CSComponentCore instance;
+    }
+}

+ 17 - 0
Script/AtomicNET/AtomicNET/Scene/InspectorAttribute.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+
+    public class InspectorAttribute : Attribute
+    {
+        public InspectorAttribute(string DefaultValue = "")
+        {
+        }
+
+        public string DefaultValue;
+    }
+
+}

+ 33 - 0
Script/AtomicNET/AtomicNET/Script/ScriptVariantMap.cs

@@ -0,0 +1,33 @@
+
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace AtomicEngine
+{
+    public partial class ScriptVariantMap : RefCounted
+    {
+        public string this[string key]
+        {
+            get
+            {
+                return GetString(key);
+            }
+            set
+            {
+                SetString(key, value);
+            }
+        }
+
+        public IntPtr GetVoidPtr(string key)
+        {
+            return csb_Atomic_AtomicNET_ScriptVariantMap_GetVoidPtr(nativeInstance, key);
+        }
+
+        [DllImport(Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
+        private static extern IntPtr csb_Atomic_AtomicNET_ScriptVariantMap_GetVoidPtr(IntPtr self, string key);
+
+    }
+}
+

+ 549 - 0
Script/AtomicNET/AtomicNET/ThirdParty/MiniJSON.cs

@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2012 Calvin Rien
+ *
+ * Based on the JSON parser by Patrick van Bergen
+ * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
+ *
+ * Simplified it so that it doesn't throw exceptions
+ * and can be used in Unity iPhone with maximum code stripping.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MiniJSON {
+    // Example usage:
+    //
+    //  using UnityEngine;
+    //  using System.Collections;
+    //  using System.Collections.Generic;
+    //  using MiniJSON;
+    //
+    //  public class MiniJSONTest : MonoBehaviour {
+    //      void Start () {
+    //          var jsonString = "{ \"array\": [1.44,2,3], " +
+    //                          "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
+    //                          "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
+    //                          "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
+    //                          "\"int\": 65536, " +
+    //                          "\"float\": 3.1415926, " +
+    //                          "\"bool\": true, " +
+    //                          "\"null\": null }";
+    //
+    //          var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
+    //
+    //          Debug.Log("deserialized: " + dict.GetType());
+    //          Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
+    //          Debug.Log("dict['string']: " + (string) dict["string"]);
+    //          Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
+    //          Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
+    //          Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
+    //
+    //          var str = Json.Serialize(dict);
+    //
+    //          Debug.Log("serialized: " + str);
+    //      }
+    //  }
+
+    /// <summary>
+    /// This class encodes and decodes JSON strings.
+    /// Spec. details, see http://www.json.org/
+    ///
+    /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
+    /// All numbers are parsed to doubles.
+    /// </summary>
+    public static class Json {
+        /// <summary>
+        /// Parses the string json into a value
+        /// </summary>
+        /// <param name="json">A JSON string.</param>
+        /// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
+        public static object Deserialize(string json) {
+            // save the string for debug information
+            if (json == null) {
+                return null;
+            }
+
+            return Parser.Parse(json);
+        }
+
+        sealed class Parser : IDisposable {
+            const string WHITE_SPACE = " \t\n\r";
+            const string WORD_BREAK = " \t\n\r{}[],:\"";
+
+            enum TOKEN {
+                NONE,
+                CURLY_OPEN,
+                CURLY_CLOSE,
+                SQUARED_OPEN,
+                SQUARED_CLOSE,
+                COLON,
+                COMMA,
+                STRING,
+                NUMBER,
+                TRUE,
+                FALSE,
+                NULL
+            };
+
+            StringReader json;
+
+            Parser(string jsonString) {
+                json = new StringReader(jsonString);
+            }
+
+            public static object Parse(string jsonString) {
+                using (var instance = new Parser(jsonString)) {
+                    return instance.ParseValue();
+                }
+            }
+
+            public void Dispose() {
+                json.Dispose();
+                json = null;
+            }
+
+            Dictionary<string, object> ParseObject() {
+                Dictionary<string, object> table = new Dictionary<string, object>();
+
+                // ditch opening brace
+                json.Read();
+
+                // {
+                while (true) {
+                    switch (NextToken) {
+                    case TOKEN.NONE:
+                        return null;
+                    case TOKEN.COMMA:
+                        continue;
+                    case TOKEN.CURLY_CLOSE:
+                        return table;
+                    default:
+                        // name
+                        string name = ParseString();
+                        if (name == null) {
+                            return null;
+                        }
+
+                        // :
+                        if (NextToken != TOKEN.COLON) {
+                            return null;
+                        }
+                        // ditch the colon
+                        json.Read();
+
+                        // value
+                        table[name] = ParseValue();
+                        break;
+                    }
+                }
+            }
+
+            List<object> ParseArray() {
+                List<object> array = new List<object>();
+
+                // ditch opening bracket
+                json.Read();
+
+                // [
+                var parsing = true;
+                while (parsing) {
+                    TOKEN nextToken = NextToken;
+
+                    switch (nextToken) {
+                    case TOKEN.NONE:
+                        return null;
+                    case TOKEN.COMMA:
+                        continue;
+                    case TOKEN.SQUARED_CLOSE:
+                        parsing = false;
+                        break;
+                    default:
+                        object value = ParseByToken(nextToken);
+
+                        array.Add(value);
+                        break;
+                    }
+                }
+
+                return array;
+            }
+
+            object ParseValue() {
+                TOKEN nextToken = NextToken;
+                return ParseByToken(nextToken);
+            }
+
+            object ParseByToken(TOKEN token) {
+                switch (token) {
+                case TOKEN.STRING:
+                    return ParseString();
+                case TOKEN.NUMBER:
+                    return ParseNumber();
+                case TOKEN.CURLY_OPEN:
+                    return ParseObject();
+                case TOKEN.SQUARED_OPEN:
+                    return ParseArray();
+                case TOKEN.TRUE:
+                    return true;
+                case TOKEN.FALSE:
+                    return false;
+                case TOKEN.NULL:
+                    return null;
+                default:
+                    return null;
+                }
+            }
+
+            string ParseString() {
+                StringBuilder s = new StringBuilder();
+                char c;
+
+                // ditch opening quote
+                json.Read();
+
+                bool parsing = true;
+                while (parsing) {
+
+                    if (json.Peek() == -1) {
+                        parsing = false;
+                        break;
+                    }
+
+                    c = NextChar;
+                    switch (c) {
+                    case '"':
+                        parsing = false;
+                        break;
+                    case '\\':
+                        if (json.Peek() == -1) {
+                            parsing = false;
+                            break;
+                        }
+
+                        c = NextChar;
+                        switch (c) {
+                        case '"':
+                        case '\\':
+                        case '/':
+                            s.Append(c);
+                            break;
+                        case 'b':
+                            s.Append('\b');
+                            break;
+                        case 'f':
+                            s.Append('\f');
+                            break;
+                        case 'n':
+                            s.Append('\n');
+                            break;
+                        case 'r':
+                            s.Append('\r');
+                            break;
+                        case 't':
+                            s.Append('\t');
+                            break;
+                        case 'u':
+                            var hex = new StringBuilder();
+
+                            for (int i=0; i< 4; i++) {
+                                hex.Append(NextChar);
+                            }
+
+                            s.Append((char) Convert.ToInt32(hex.ToString(), 16));
+                            break;
+                        }
+                        break;
+                    default:
+                        s.Append(c);
+                        break;
+                    }
+                }
+
+                return s.ToString();
+            }
+
+            object ParseNumber() {
+                string number = NextWord;
+
+                if (number.IndexOf('.') == -1) {
+                    long parsedInt;
+                    Int64.TryParse(number, out parsedInt);
+                    return parsedInt;
+                }
+
+                double parsedDouble;
+                Double.TryParse(number, out parsedDouble);
+                return parsedDouble;
+            }
+
+            void EatWhitespace() {
+                while (WHITE_SPACE.IndexOf(PeekChar) != -1) {
+                    json.Read();
+
+                    if (json.Peek() == -1) {
+                        break;
+                    }
+                }
+            }
+
+            char PeekChar {
+                get {
+                    return Convert.ToChar(json.Peek());
+                }
+            }
+
+            char NextChar {
+                get {
+                    return Convert.ToChar(json.Read());
+                }
+            }
+
+            string NextWord {
+                get {
+                    StringBuilder word = new StringBuilder();
+
+                    while (WORD_BREAK.IndexOf(PeekChar) == -1) {
+                        word.Append(NextChar);
+
+                        if (json.Peek() == -1) {
+                            break;
+                        }
+                    }
+
+                    return word.ToString();
+                }
+            }
+
+            TOKEN NextToken {
+                get {
+                    EatWhitespace();
+
+                    if (json.Peek() == -1) {
+                        return TOKEN.NONE;
+                    }
+
+                    char c = PeekChar;
+                    switch (c) {
+                    case '{':
+                        return TOKEN.CURLY_OPEN;
+                    case '}':
+                        json.Read();
+                        return TOKEN.CURLY_CLOSE;
+                    case '[':
+                        return TOKEN.SQUARED_OPEN;
+                    case ']':
+                        json.Read();
+                        return TOKEN.SQUARED_CLOSE;
+                    case ',':
+                        json.Read();
+                        return TOKEN.COMMA;
+                    case '"':
+                        return TOKEN.STRING;
+                    case ':':
+                        return TOKEN.COLON;
+                    case '0':
+                    case '1':
+                    case '2':
+                    case '3':
+                    case '4':
+                    case '5':
+                    case '6':
+                    case '7':
+                    case '8':
+                    case '9':
+                    case '-':
+                        return TOKEN.NUMBER;
+                    }
+
+                    string word = NextWord;
+
+                    switch (word) {
+                    case "false":
+                        return TOKEN.FALSE;
+                    case "true":
+                        return TOKEN.TRUE;
+                    case "null":
+                        return TOKEN.NULL;
+                    }
+
+                    return TOKEN.NONE;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
+        /// </summary>
+        /// <param name="json">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
+        /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
+        public static string Serialize(object obj) {
+            return Serializer.Serialize(obj);
+        }
+
+        sealed class Serializer {
+            StringBuilder builder;
+
+            Serializer() {
+                builder = new StringBuilder();
+            }
+
+            public static string Serialize(object obj) {
+                var instance = new Serializer();
+
+                instance.SerializeValue(obj);
+
+                return instance.builder.ToString();
+            }
+
+            void SerializeValue(object value) {
+                IList asList;
+                IDictionary asDict;
+                string asStr;
+
+                if (value == null) {
+                    builder.Append("null");
+                }
+                else if ((asStr = value as string) != null) {
+                    SerializeString(asStr);
+                }
+                else if (value is bool) {
+                    builder.Append(value.ToString().ToLower());
+                }
+                else if ((asList = value as IList) != null) {
+                    SerializeArray(asList);
+                }
+                else if ((asDict = value as IDictionary) != null) {
+                    SerializeObject(asDict);
+                }
+                else if (value is char) {
+                    SerializeString(value.ToString());
+                }
+                else {
+                    SerializeOther(value);
+                }
+            }
+
+            void SerializeObject(IDictionary obj) {
+                bool first = true;
+
+                builder.Append('{');
+
+                foreach (object e in obj.Keys) {
+                    if (!first) {
+                        builder.Append(',');
+                    }
+
+                    SerializeString(e.ToString());
+                    builder.Append(':');
+
+                    SerializeValue(obj[e]);
+
+                    first = false;
+                }
+
+                builder.Append('}');
+            }
+
+            void SerializeArray(IList anArray) {
+                builder.Append('[');
+
+                bool first = true;
+
+                foreach (object obj in anArray) {
+                    if (!first) {
+                        builder.Append(',');
+                    }
+
+                    SerializeValue(obj);
+
+                    first = false;
+                }
+
+                builder.Append(']');
+            }
+
+            void SerializeString(string str) {
+                builder.Append('\"');
+
+                char[] charArray = str.ToCharArray();
+                foreach (var c in charArray) {
+                    switch (c) {
+                    case '"':
+                        builder.Append("\\\"");
+                        break;
+                    case '\\':
+                        builder.Append("\\\\");
+                        break;
+                    case '\b':
+                        builder.Append("\\b");
+                        break;
+                    case '\f':
+                        builder.Append("\\f");
+                        break;
+                    case '\n':
+                        builder.Append("\\n");
+                        break;
+                    case '\r':
+                        builder.Append("\\r");
+                        break;
+                    case '\t':
+                        builder.Append("\\t");
+                        break;
+                    default:
+                        int codepoint = Convert.ToInt32(c);
+                        if ((codepoint >= 32) && (codepoint <= 126)) {
+                            builder.Append(c);
+                        }
+                        else {
+                            builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0'));
+                        }
+                        break;
+                    }
+                }
+
+                builder.Append('\"');
+            }
+
+            void SerializeOther(object value) {
+                if (value is float
+                    || value is int
+                    || value is uint
+                    || value is long
+                    || value is double
+                    || value is sbyte
+                    || value is byte
+                    || value is short
+                    || value is ushort
+                    || value is ulong
+                    || value is decimal) {
+                    builder.Append(value.ToString());
+                }
+                else {
+                    SerializeString(value.ToString());
+                }
+            }
+        }
+    }
+}

+ 84 - 0
Script/AtomicNET/AtomicNETProject.json

@@ -0,0 +1,84 @@
+{
+  "solution" : {
+    "name" : "AtomicNET",
+    "outputPath" : "$ATOMIC_ROOT$/Artifacts/AtomicNET/Build/"
+  },
+  "projects" : [
+    {
+      "name": "AtomicNET",
+      "outputType" : "Library",
+      "rootNamespace" : "AtomicEngine",
+      "assemblyName" : "AtomicNET",
+      "assemblyOutputPath" : "..\\..\\",
+      "references" : [
+        "System", "System.Core" , "System.Xml.Linq", "System.XML"
+      ],
+      "sources" : [
+        "$ATOMIC_ROOT$/Script/AtomicNET/AtomicNETCore/",
+        "$ATOMIC_ROOT$/Script/AtomicNET/AtomicNET/",
+        "$ATOMIC_ROOT$/Artifacts/Build/Source/Generated/$SCRIPT_PLATFORM$/CSharp/Packages/Atomic/Managed/",
+        "$ATOMIC_ROOT$/Artifacts/Build/Source/Generated/$SCRIPT_PLATFORM$/CSharp/Packages/AtomicNETScript/Managed/",
+        "$ATOMIC_ROOT$/Artifacts/Build/Source/Generated/$SCRIPT_PLATFORM$/CSharp/Packages/AtomicNETNative/Managed/",
+        "$ATOMIC_ROOT$/Artifacts/Build/Source/Generated/$SCRIPT_PLATFORM$/CSharp/Packages/AtomicApp/Managed/",
+        "$ATOMIC_ROOT$/Artifacts/Build/Source/Generated/$SCRIPT_PLATFORM$/CSharp/Packages/AtomicPlayer/Managed/"
+      ]
+    },
+    {
+      "name": "AtomicNETService",
+      "outputType" : "Exe",
+      "rootNamespace" : "AtomicTools",
+      "assemblyName" : "AtomicNETService",
+      "assemblyOutputPath" : "..\\..\\",
+      "references" : [
+        "System",
+        "<Reference Include=\"System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\"><HintPath>..\\packages\\System.Collections.Immutable.1.2.0\\lib\\portable-net45+win8+wp8+wpa81\\System.Collections.Immutable.dll</HintPath><Private>True</Private></Reference>",
+        "System.Core" ,
+        "<Reference Include=\"System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\"><HintPath>..\\packages\\System.Reflection.Metadata.1.3.0\\lib\\portable-net45+win8\\System.Reflection.Metadata.dll</HintPath><Private>True</Private></Reference>",
+        "System.Xml.Linq",
+        "System.XML",
+        "AtomicNET"
+      ],
+      "sources" : [
+        "$ATOMIC_ROOT$/Script/AtomicNET/AtomicNETService/"
+      ],
+      "packages" : [
+        "<package id=\"System.Collections.Immutable\" version=\"1.2.0\" targetFramework=\"net46\" />",
+        "<package id=\"System.Reflection.Metadata\" version=\"1.3.0\" targetFramework=\"net46\" />"
+      ]
+    },
+    {
+      "name": "ComponentTest",
+      "outputType" : "Library",
+      "rootNamespace" : "ComponentTest",
+      "assemblyName" : "ComponentTest",
+      "assemblyOutputPath" : "..\\..\\",
+      "references" : [
+        "System",
+        "System.Core" ,
+        "System.Xml.Linq",
+        "System.XML",
+        "AtomicNET"
+      ],
+      "sources" : [
+        "$ATOMIC_ROOT$/Script/AtomicNET/ComponentTest/"
+      ]
+    },
+    {
+      "name": "AtomicPlayer",
+      "outputType" : "Exe",
+      "rootNamespace" : "AtomicPlayer",
+      "assemblyName" : "AtomicPlayer",
+      "assemblyOutputPath" : "..\\..\\",
+      "references" : [
+        "System",
+        "System.Core" ,
+        "System.Xml.Linq",
+        "System.XML",
+        "AtomicNET"
+      ],
+      "sources" : [
+        "$ATOMIC_ROOT$/Script/AtomicNET/AtomicPlayer/"
+      ]
+    }
+  ]
+}

+ 226 - 0
Script/AtomicNET/AtomicNETService/AssemblyInspector.cs

@@ -0,0 +1,226 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
+using System.Reflection.Metadata.Ecma335;
+using System.Text;
+
+using AtomicEngine;
+
+using File = System.IO.File;
+
+namespace AtomicTools
+{
+
+	class AssemblyInspector
+	{
+
+		Dictionary<string, InspectorEnum> InspectorEnums = new Dictionary<string, InspectorEnum> ();
+		Dictionary<string, InspectorComponent> InspectorComponents = new Dictionary<string, InspectorComponent> ();
+
+		PEReader peFile;
+		MetadataReader metaReader;
+
+		public AssemblyInspector ()
+		{
+
+		}
+
+		public string DumpToJSON ()
+		{
+			var dict = new Dictionary<string, object> ();
+
+			var enumList = new List<object> ();
+			var componentList = new List<object> ();
+
+			foreach (var entry in InspectorEnums) {
+				enumList.Add (entry.Value.GetJSONDict ());
+			}
+
+			foreach (var entry in InspectorComponents) {
+				componentList.Add (entry.Value.GetJSONDict ());
+			}
+
+			dict ["enums"] = enumList;
+			dict ["components"] = componentList;
+
+			return MiniJSON.Json.Serialize (dict);
+
+		}
+
+		public void Inspect (String pathToAssembly)
+		{
+
+			using (var stream = File.OpenRead (pathToAssembly))
+			using (peFile = new PEReader (stream)) {
+
+				metaReader = peFile.GetMetadataReader ();
+
+				ParseEnums ();
+				ParseComponents ();
+			}
+
+		}
+
+		void ParseComponents ()
+		{
+
+			foreach (var handle in metaReader.TypeDefinitions) {
+
+				var typeDef = metaReader.GetTypeDefinition (handle);
+
+				var baseTypeHandle = typeDef.BaseType;
+
+				if (baseTypeHandle.Kind == HandleKind.TypeReference) {
+
+					var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle);
+
+                    var name = metaReader.GetString (typeRef.Name); 
+
+					if (name != "CSComponent")
+						continue;
+
+					var inspector = new CSComponentInspector (typeDef, peFile, metaReader);
+
+					var icomponent = inspector.Inspect ();
+
+					if (icomponent != null)
+						InspectorComponents [icomponent.Name] = icomponent;
+				}
+			}
+		}
+
+
+		void ParseEnums ()
+		{
+			foreach (var handle in metaReader.TypeDefinitions) {
+
+				var typeDef = metaReader.GetTypeDefinition (handle);
+
+				var baseTypeHandle = typeDef.BaseType;
+
+				if (baseTypeHandle.Kind == HandleKind.TypeReference) {
+					var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle);
+
+					if (metaReader.GetString (typeRef.Name) == "Enum") {
+						ParseEnum (typeDef);
+					}
+				}
+			}
+		}
+
+		void ParseEnum (TypeDefinition enumTypeDef)
+		{
+
+			// TODO: verify that int32 is the enums storage type for constant read below
+
+			InspectorEnum ienum = new InspectorEnum ();
+
+			ienum.Name = metaReader.GetString (enumTypeDef.Name);
+
+			InspectorEnums [ienum.Name] = ienum;
+
+			var fields = enumTypeDef.GetFields ();
+
+			foreach (var fieldHandle in fields) {
+
+				var inspectorField = new InspectorField ();
+
+				var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
+
+				if ((fieldDef.Attributes & FieldAttributes.HasDefault) != 0) {
+
+					var constantHandle = fieldDef.GetDefaultValue ();
+					var constant = metaReader.GetConstant (constantHandle);
+
+					BlobReader constantReader = metaReader.GetBlobReader (constant.Value);
+
+					ienum.Values [metaReader.GetString (fieldDef.Name)] = constantReader.ReadInt32 ();
+
+				}
+			}
+
+			return;
+
+		}
+	}
+
+	internal class InspectorEnum
+	{
+		public String Name;
+		public Dictionary<string, int> Values = new Dictionary<string, int> ();
+
+		public Dictionary<string, object> GetJSONDict ()
+		{
+			var dict = new Dictionary<string,object> ();
+			dict ["name"] = Name;
+			dict ["values"] = Values;
+			return dict;
+		}
+	}
+
+	internal class InspectorComponent
+	{
+		public String Name;
+		public String Namespace;
+		public Dictionary<string, InspectorField> Fields = new Dictionary<string, InspectorField> ();
+
+		public Dictionary<string, object> GetJSONDict ()
+		{
+			var dict = new Dictionary<string,object> ();
+
+			dict ["name"] = Name;
+			dict ["namespace"] = Namespace;
+
+			var fieldList = new List<object> ();
+
+			foreach (var entry in Fields) {
+				fieldList.Add (entry.Value.GetJSONDict ());
+			}
+
+			dict ["fields"] = fieldList;
+
+			return dict;
+		}
+	}
+
+	internal class InspectorField
+	{
+
+		public Dictionary<string, object> GetJSONDict ()
+		{
+
+			var dict = new Dictionary<string,object> ();
+
+			dict ["isEnum"] = IsEnum;
+			dict ["typeName"] = TypeName;
+			dict ["name"] = Name;
+			dict ["defaultValue"] = DefaultValue;
+
+			dict ["caPos"] = CustomAttrPositionalArgs;
+			dict ["caNamed"] = CustomAttrNamedArgs;
+
+			return dict;
+
+		}
+
+		public bool IsEnum = false;
+
+		public string TypeName;
+
+		// the Name of the InspectorField
+		public string Name;
+		// The DefaultValue if supplied
+		public string DefaultValue;
+
+		// custom attributes, positional and named
+		public List<string> CustomAttrPositionalArgs = new List<string> ();
+		public Dictionary<string, string> CustomAttrNamedArgs = new Dictionary<string, string> ();
+	}
+
+}

+ 41 - 0
Script/AtomicNET/AtomicNETService/AtomicTools.cs

@@ -0,0 +1,41 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.PortableExecutable;
+using System.Reflection.Metadata.Ecma335;
+using System.Text;
+
+using AtomicEngine;
+
+using File = System.IO.File;
+
+namespace AtomicTools
+{
+	public class AtomicTools
+	{
+
+		public static String InspectAssembly (String pathToAssembly)
+		{
+
+			try {
+
+				var inspector = new AssemblyInspector ();
+				inspector.Inspect (pathToAssembly);
+				return inspector.DumpToJSON();
+
+			} catch (Exception ex) {
+				Console.WriteLine (ex.Message);
+			}
+
+			return "";
+
+		}
+
+	}
+
+}

+ 808 - 0
Script/AtomicNET/AtomicNETService/CSComponentInspector.cs

@@ -0,0 +1,808 @@
+// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
+
+using System.Collections.Immutable;
+
+//using Roslyn.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
+
+// References
+
+//https://github.com/Microsoft/dotnetsamples/tree/master/System.Reflection.Metadata
+//https://github.com/dotnet/corefx/tree/master/src/System.Reflection.Metadata/tests
+//http://www.cnetion.com/getting-field-values-using-mono-cecil-qq-AUvBjRFgivICeoL1jxJy.php
+
+// https://github.com/Reactive-Extensions/IL2JS/blob/master/CCI2/PeReader/ILReader.cs
+
+// https://github.com/Reactive-Extensions/IL2JS
+
+// custom attr loading: https://github.com/Reactive-Extensions/IL2JS/blob/a4570f9c69b6c40d001e7539b952266d67609ca9/CST/PELoader.cs#L2352
+// custom attr: https://www.simple-talk.com/blogs/2011/06/03/anatomy-of-a-net-assembly-custom-attribute-encoding/
+// custom attr: https://github.com/jbevain/cecil/blob/67a2569688a13a6cb487f9af5c3418f7a8f43e3c/Mono.Cecil/AssemblyReader.cs
+
+// https://github.com/dotnet/roslyn/tree/master/src/Compilers/Core/Portable/MetadataReader
+
+
+namespace AtomicTools
+{
+
+	public class CSComponentInspector
+	{
+
+		InspectorComponent _inspectorComponent;
+
+		public CSComponentInspector (TypeDefinition typeDef, PEReader peFile, MetadataReader metaReader)
+		{
+			this.typeDef = typeDef;
+			this.peFile = peFile;
+			this.metaReader = metaReader;
+
+			this._inspectorComponent = new InspectorComponent ();
+			this._inspectorComponent.Name = metaReader.GetString (typeDef.Name);
+			this._inspectorComponent.Namespace = metaReader.GetString (typeDef.Namespace);
+		}
+
+		// Inspect a CSComponent derived class
+		internal InspectorComponent Inspect ()
+		{
+
+			var fields = typeDef.GetFields ();
+
+			foreach (var fieldHandle in fields) {
+
+				var inspectorField = new InspectorField ();
+
+				var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
+
+				var customAttr = fieldDef.GetCustomAttributes ();
+
+				foreach (var caHandle in customAttr) {
+
+					// Look for InspectorAttribute
+					if (DecodeCustomAttribute (caHandle, inspectorField)) {
+
+						BlobReader sigReader = metaReader.GetBlobReader (fieldDef.Signature);
+						SignatureHeader header = sigReader.ReadSignatureHeader ();
+
+						if (header.Kind != SignatureKind.Field)
+							continue;
+
+						var typeCode = sigReader.ReadSignatureTypeCode ();
+
+						string typeName = typeCode.ToString ();
+
+						if (typeCode == SignatureTypeCode.TypeHandle) {
+
+							EntityHandle token = sigReader.ReadTypeHandle ();
+							HandleKind tokenType = token.Kind;
+
+							if (tokenType == HandleKind.TypeDefinition) {
+
+								// can store local enum typedefs
+								// enum initializers are stored as constant value in the IL
+
+								var typeDef = metaReader.GetTypeDefinition ((TypeDefinitionHandle)token);
+
+								var baseTypeToken = typeDef.BaseType;
+
+								if (baseTypeToken.Kind != HandleKind.TypeReference)
+									continue;
+
+								var baseTypeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeToken);
+
+								if (metaReader.GetString (baseTypeRef.Name) != "Enum")
+									continue;
+
+								inspectorField.IsEnum = true;
+								typeName = metaReader.GetString (typeDef.Name);
+
+							} else if (tokenType == HandleKind.TypeReference) {
+
+								// TypeReference, ok
+								var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)token);
+
+								typeName = metaReader.GetString (typeRef.Name);
+
+							} else {
+								// ???
+								continue;
+							}
+
+						}
+
+						inspectorField.TypeName = typeName;
+						inspectorField.Name = metaReader.GetString (fieldDef.Name);
+						_inspectorComponent.Fields [inspectorField.Name] = inspectorField;
+
+						break;
+					}
+				}
+			}
+
+			// There is no way to get the initializer value of a field
+			// other than to inspect the IL code of the constructor
+			var methods = typeDef.GetMethods ();
+
+			foreach (var methodHandle in methods) {
+
+				var methodDef = metaReader.GetMethodDefinition (methodHandle);
+
+				if (metaReader.GetString (methodDef.Name) == ".ctor") {
+
+					var body = peFile.GetMethodBody (methodDef.RelativeVirtualAddress);
+					var ilBytes = body.GetILContent ();
+
+					InspectILBlock (ilBytes, ilBytes.Length);
+				}
+
+			}
+
+			//Dump ();
+
+			return _inspectorComponent;
+
+		}
+
+		private bool DecodeCustomAttribute (CustomAttributeHandle caHandle, InspectorField inspectorField)
+		{
+
+			// GetCustomAttribute: https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1370
+
+			// Custom Attribute
+			var ca = metaReader.GetCustomAttribute (caHandle);
+
+			// MethodDefinitionHandle or MemberReferenceHandle
+			if (ca.Constructor.Kind != HandleKind.MemberReference) {
+				Console.WriteLine ("ca.Constructor.Kind != HandleKind.MemberReference");
+				return false;
+			}
+
+			// constructor of the custom attr which contains the signature
+			var memberRef = metaReader.GetMemberReference ((MemberReferenceHandle)ca.Constructor);
+
+			// parent of the constructor is the TypeReference
+			var parent = memberRef.Parent;
+
+			if (parent.Kind != HandleKind.TypeReference) {
+				Console.WriteLine ("parent.Kind != HandleKind.TypeReference");
+				return false;
+			}
+
+			var parentTypeRef = metaReader.GetTypeReference ((TypeReferenceHandle)parent);
+
+			// check whether we have an InspectorAttribute
+			if (metaReader.GetString (parentTypeRef.Name) != "InspectorAttribute") {
+				Console.WriteLine ("parentTypeRef != InspectorAttribute");
+				return false;
+			}
+
+			// args
+			var argsReader = metaReader.GetBlobReader ((BlobHandle)ca.Value);
+
+			uint prolog = argsReader.ReadUInt16 ();
+
+			if (prolog != 1) {
+				Console.WriteLine ("prolog != 1");
+				return false;
+			}
+
+			// sig reader is on constructor
+			BlobReader sigReader = metaReader.GetBlobReader (memberRef.Signature);
+			SignatureHeader header = sigReader.ReadSignatureHeader ();
+
+			// Get the type parameter count.
+			if (header.IsGeneric && sigReader.ReadCompressedInteger () != 0) {
+				Console.WriteLine ("header.IsGeneric && sigReader.ReadCompressedInteger() != 0");
+				return false;
+			}
+
+			// Get the parameter count
+			int paramCount = sigReader.ReadCompressedInteger ();
+
+			// Get the type return type.
+			var returnTypeCode = sigReader.ReadSignatureTypeCode ();
+
+			if (returnTypeCode != SignatureTypeCode.Void) {
+				Console.WriteLine ("returnTypeCode != SignatureTypeCode.Void");
+				return false;
+			}
+
+			List<SignatureTypeCode> sigTypeCodes = new List<SignatureTypeCode> ();
+
+			// position args
+			for (int i = 0; i < paramCount; i++) {
+
+				SignatureTypeCode paramTypeCode = sigReader.ReadSignatureTypeCode ();
+
+				// support string custom attr for now to simplify things
+				if (paramTypeCode != SignatureTypeCode.String)
+					return false;
+
+				string value;
+
+				if (CrackStringInAttributeValue (out value, ref argsReader)) {
+					inspectorField.CustomAttrPositionalArgs.Add (value);
+				}
+
+				sigTypeCodes.Add (paramTypeCode);
+			}
+
+			// named args
+
+			short namedParamCount = argsReader.ReadInt16 ();
+
+			for (short i = 0; i < namedParamCount; i++) {
+
+				// Ecma-335 23.3 - A NamedArg is simply a FixedArg preceded by information to identify which field or
+				// property it represents. [Note: Recall that the CLI allows fields and properties to have the same name; so
+				// we require a means to disambiguate such situations. end note] FIELD is the single byte 0x53. PROPERTY is
+				// the single byte 0x54.
+
+				// https://github.com/dotnet/roslyn/blob/master/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs#L1305
+
+				var kind = (CustomAttributeNamedArgumentKind)argsReader.ReadCompressedInteger ();
+
+				if (kind != CustomAttributeNamedArgumentKind.Field && kind != CustomAttributeNamedArgumentKind.Property) {
+					return false;
+				}
+
+				var typeCode = argsReader.ReadSerializationTypeCode ();
+
+				// support string custom attr for now to simplify things
+				if (typeCode != SerializationTypeCode.String)
+					return false;
+
+				string name;
+
+				if (!CrackStringInAttributeValue (out name, ref argsReader))
+					return false;
+
+				string value;
+
+				if (!CrackStringInAttributeValue (out value, ref argsReader))
+					return false;
+
+				inspectorField.CustomAttrNamedArgs [name] = value;
+
+			}
+
+			return true;
+
+		}
+
+		internal static bool CrackStringInAttributeValue (out string value, ref BlobReader sig)
+		{
+			try {
+				int strLen;
+				if (sig.TryReadCompressedInteger (out strLen) && sig.RemainingBytes >= strLen) {
+					value = sig.ReadUTF8 (strLen);
+
+					// Trim null characters at the end to mimic native compiler behavior.
+					// There are libraries that have them and leaving them in breaks tests.
+					value = value.TrimEnd ('\0');
+
+					return true;
+				}
+
+				value = null;
+
+				// Strings are stored as UTF8, but 0xFF means NULL string.
+				return sig.RemainingBytes >= 1 && sig.ReadByte () == 0xFF;
+			} catch (BadImageFormatException) {
+				value = null;
+				return false;
+			}
+		}
+
+		public void InspectILBlock (
+			ImmutableArray<byte> ilBytes,
+			int length,
+			IReadOnlyList<HandlerSpan> spans = null,
+			int blockOffset = 0,
+			IReadOnlyDictionary<int, string> markers = null)
+		{
+			if (ilBytes == null) {
+				return;
+			}
+
+			int spanIndex = 0;
+			int curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, 0, spanIndex, markers, out spanIndex);
+		}
+
+		private int InspectILBlock (
+			ImmutableArray<byte> ilBytes,
+			int length,
+			IReadOnlyList<HandlerSpan> spans,
+			int blockOffset,
+			int curIndex,
+			int spanIndex,
+			IReadOnlyDictionary<int, string> markers,
+			out int nextSpanIndex)
+		{
+			int lastSpanIndex = spanIndex - 1;
+
+			List<string> loadedValues = new List<string> ();
+
+			while (curIndex < length) {
+
+				if (lastSpanIndex > 0 && StartsFilterHandler (spans, lastSpanIndex, curIndex + blockOffset)) {
+
+				}
+
+				if (StartsSpan (spans, spanIndex, curIndex + blockOffset)) {
+					curIndex = InspectILBlock (ilBytes, length, spans, blockOffset, curIndex, spanIndex + 1, markers, out spanIndex);
+				} else {
+
+					int ilOffset = curIndex + blockOffset;
+					string marker;
+					if (markers != null && markers.TryGetValue (ilOffset, out marker)) {
+					} else {
+					}
+
+					OpCode opCode;
+					int expectedSize;
+
+					byte op1 = ilBytes [curIndex++];
+					if (op1 == 0xfe && curIndex < length) {
+						byte op2 = ilBytes [curIndex++];
+						opCode = s_twoByteOpCodes [op2];
+						expectedSize = 2;
+					} else {
+						opCode = s_oneByteOpCodes [op1];
+						expectedSize = 1;
+					}
+
+					if (opCode.Size != expectedSize) {
+						//sb.AppendLine(string.Format("  <unknown 0x{0}{1:X2}>", expectedSize == 2 ? "fe" : "", op1));
+						continue;
+					}
+
+					//sb.Append("  ");
+
+					// Console.WriteLine (opCode.OperandType == OperandType.InlineNone ? "{0} {1}" : "{0,-10} {1}", opCode, opCode.OperandType);
+
+					switch (opCode.OperandType) {
+
+					case OperandType.InlineField:
+
+						// read token
+						uint fieldToken = ReadUInt32 (ilBytes, ref curIndex);
+						// get the kind
+						uint tokenKind = fieldToken & TokenTypeIds.TokenTypeMask;
+						// and the rowId
+						uint rowId = fieldToken & TokenTypeIds.RIDMask;
+
+						var fieldHandle = MetadataTokens.FieldDefinitionHandle ((int)rowId);
+
+						var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
+
+						var fieldName = metaReader.GetString (fieldDef.Name);
+
+						if (opCode.ToString () == "stfld") {
+
+							InspectorField inspectorField;
+
+							if (_inspectorComponent.Fields.TryGetValue (fieldName, out inspectorField)) {
+								inspectorField.DefaultValue = String.Join (" ", loadedValues.ToArray ());
+							}
+
+						}
+
+						loadedValues.Clear ();
+
+						break;
+					case OperandType.InlineMethod:
+
+						// new Vector3, etc
+						if (opCode.ToString () == "newobj") {
+
+						} else
+							loadedValues.Clear ();
+
+						break;
+					case OperandType.InlineTok:
+					case OperandType.InlineType:
+						ReadUInt32 (ilBytes, ref curIndex);
+						loadedValues.Clear ();
+						break;
+
+					case OperandType.InlineSig: // signature (calli), not emitted by C#/VB
+						ReadUInt32 (ilBytes, ref curIndex);
+						loadedValues.Clear ();
+						break;
+
+					case OperandType.InlineString:
+						//sb.Append(" 391 ");
+						//sb.Append(VisualizeUserString());
+
+						uint stringToken = ReadUInt32 (ilBytes, ref curIndex);
+
+						// get the kind
+						//uint tokenKind = stringToken & TokenTypeIds.TokenTypeMask;
+						// and the rowId
+						//uint rowId = stringToken & TokenTypeIds.RIDMask;
+
+
+						UserStringHandle handle = MetadataTokens.UserStringHandle ((int)stringToken);
+						loadedValues.Add (metaReader.GetUserString (handle));
+
+						break;
+
+					case OperandType.InlineNone:
+
+						if (opCode == OpCodes.Ldc_I4_0)
+							loadedValues.Add ("0");
+						else if (opCode == OpCodes.Ldc_I4_1)
+							loadedValues.Add ("1");
+						else if (opCode == OpCodes.Ldc_I4_2)
+							loadedValues.Add ("2");
+						else if (opCode == OpCodes.Ldc_I4_3)
+							loadedValues.Add ("3");
+						else if (opCode == OpCodes.Ldc_I4_4)
+							loadedValues.Add ("4");
+						else if (opCode == OpCodes.Ldc_I4_5)
+							loadedValues.Add ("5");
+						else if (opCode == OpCodes.Ldc_I4_6)
+							loadedValues.Add ("6");
+						else if (opCode == OpCodes.Ldc_I4_7)
+							loadedValues.Add ("7");
+						else if (opCode == OpCodes.Ldc_I4_8)
+							loadedValues.Add ("8");
+						else if (opCode == OpCodes.Ldc_I4_M1)
+							loadedValues.Add ("-1");
+
+						break;
+
+					case OperandType.ShortInlineI:
+						loadedValues.Add (ReadSByte (ilBytes, ref curIndex).ToString ());
+						break;
+
+					case OperandType.ShortInlineVar:
+						loadedValues.Add (ReadByte (ilBytes, ref curIndex).ToString ());
+						break;
+
+					case OperandType.InlineVar:
+						loadedValues.Add (ReadUInt16 (ilBytes, ref curIndex).ToString ());
+						break;
+
+					case OperandType.InlineI:
+						loadedValues.Add (ReadUInt32 (ilBytes, ref curIndex).ToString ());
+						break;
+
+					case OperandType.InlineI8:
+						loadedValues.Add (ReadUInt64 (ilBytes, ref curIndex).ToString ());
+						break;
+
+					case OperandType.ShortInlineR:
+						{
+							loadedValues.Add (ReadSingle (ilBytes, ref curIndex).ToString ());
+						}
+						break;
+
+					case OperandType.InlineR:
+						{
+							loadedValues.Add (ReadDouble (ilBytes, ref curIndex).ToString ());
+						}
+						break;
+
+					case OperandType.ShortInlineBrTarget:
+						loadedValues.Clear ();
+						var sbyteValue = ReadSByte (ilBytes, ref curIndex) + curIndex + blockOffset;
+						break;
+
+					case OperandType.InlineBrTarget:
+						loadedValues.Clear ();
+						var int32value = ReadInt32 (ilBytes, ref curIndex) + curIndex + blockOffset;
+						break;
+
+					case OperandType.InlineSwitch:
+						loadedValues.Clear ();
+						int labelCount = ReadInt32 (ilBytes, ref curIndex);
+						int instrEnd = curIndex + labelCount * 4;
+						for (int i = 0; i < labelCount; i++) {
+							var int32LabelValue = ReadInt32 (ilBytes, ref curIndex) + instrEnd + blockOffset;
+							//sb.AppendLine((i == labelCount - 1) ? ")" : ",");
+						}
+						break;
+
+					default:
+						throw new InvalidOperationException ();
+					//throw ExceptionUtilities.UnexpectedValue(opCode.OperandType);
+					}
+
+					//sb.AppendLine();
+				}
+
+				if (EndsSpan (spans, lastSpanIndex, curIndex + blockOffset)) {
+					break;
+				}
+			}
+
+			nextSpanIndex = spanIndex;
+			return curIndex;
+		}
+
+		TypeDefinition typeDef;
+		PEReader peFile;
+		MetadataReader metaReader;
+
+		private static readonly OpCode[] s_oneByteOpCodes;
+		private static readonly OpCode[] s_twoByteOpCodes;
+
+		static CSComponentInspector ()
+		{
+			s_oneByteOpCodes = new OpCode[0x100];
+			s_twoByteOpCodes = new OpCode[0x100];
+
+			var typeOfOpCode = typeof(OpCode);
+
+			foreach (FieldInfo fi in typeof(OpCodes).GetTypeInfo().DeclaredFields) {
+				if (fi.FieldType != typeOfOpCode) {
+					continue;
+				}
+
+				OpCode opCode = (OpCode)fi.GetValue (null);
+				var value = unchecked((ushort)opCode.Value);
+				if (value < 0x100) {
+					s_oneByteOpCodes [value] = opCode;
+				} else if ((value & 0xff00) == 0xfe00) {
+					s_twoByteOpCodes [value & 0xff] = opCode;
+				}
+			}
+		}
+
+		private static ulong ReadUInt64 (ImmutableArray<byte> buffer, ref int pos)
+		{
+			ulong result =
+				buffer [pos] |
+				(ulong)buffer [pos + 1] << 8 |
+				(ulong)buffer [pos + 2] << 16 |
+				(ulong)buffer [pos + 3] << 24 |
+				(ulong)buffer [pos + 4] << 32 |
+				(ulong)buffer [pos + 5] << 40 |
+				(ulong)buffer [pos + 6] << 48 |
+				(ulong)buffer [pos + 7] << 56;
+
+			pos += sizeof(ulong);
+			return result;
+		}
+
+		private static uint ReadUInt32 (ImmutableArray<byte> buffer, ref int pos)
+		{
+			uint result = buffer [pos] | (uint)buffer [pos + 1] << 8 | (uint)buffer [pos + 2] << 16 | (uint)buffer [pos + 3] << 24;
+			pos += sizeof(uint);
+			return result;
+		}
+
+		private static int ReadInt32 (ImmutableArray<byte> buffer, ref int pos)
+		{
+			return unchecked((int)ReadUInt32 (buffer, ref pos));
+		}
+
+		private static ushort ReadUInt16 (ImmutableArray<byte> buffer, ref int pos)
+		{
+			ushort result = (ushort)(buffer [pos] | buffer [pos + 1] << 8);
+			pos += sizeof(ushort);
+			return result;
+		}
+
+		private static byte ReadByte (ImmutableArray<byte> buffer, ref int pos)
+		{
+			byte result = buffer [pos];
+			pos += sizeof(byte);
+			return result;
+		}
+
+		private static sbyte ReadSByte (ImmutableArray<byte> buffer, ref int pos)
+		{
+			sbyte result = unchecked((sbyte)buffer [pos]);
+			pos += 1;
+			return result;
+		}
+
+		private unsafe static float ReadSingle (ImmutableArray<byte> buffer, ref int pos)
+		{
+			uint value = ReadUInt32 (buffer, ref pos);
+			return *(float*)&value;
+		}
+
+		private unsafe static double ReadDouble (ImmutableArray<byte> buffer, ref int pos)
+		{
+			ulong value = ReadUInt64 (buffer, ref pos);
+			return *(double*)&value;
+		}
+
+		public enum HandlerKind
+		{
+			Try,
+			Catch,
+			Filter,
+			Finally,
+			Fault
+		}
+
+		public struct HandlerSpan : IComparable<HandlerSpan>
+		{
+			public readonly HandlerKind Kind;
+			public readonly object ExceptionType;
+			public readonly int StartOffset;
+			public readonly int FilterHandlerStart;
+			public readonly int EndOffset;
+
+			public HandlerSpan (HandlerKind kind, object exceptionType, int startOffset, int endOffset, int filterHandlerStart = 0)
+			{
+				this.Kind = kind;
+				this.ExceptionType = exceptionType;
+				this.StartOffset = startOffset;
+				this.EndOffset = endOffset;
+				this.FilterHandlerStart = filterHandlerStart;
+			}
+
+			public int CompareTo (HandlerSpan other)
+			{
+				int result = this.StartOffset - other.StartOffset;
+				if (result == 0) {
+					// Both blocks have same start. Order larger (outer) before smaller (inner).
+					result = other.EndOffset - this.EndOffset;
+				}
+
+				return result;
+			}
+
+			public string ToString (CSComponentInspector visualizer)
+			{
+				switch (this.Kind) {
+				default:
+					return ".try";
+				case HandlerKind.Catch:
+					return "catch **exceptiontype**";// + visualizer.VisualizeLocalType(this.ExceptionType);
+				case HandlerKind.Filter:
+					return "filter";
+				case HandlerKind.Finally:
+					return "finally";
+				case HandlerKind.Fault:
+					return "fault";
+				}
+			}
+
+			public override string ToString ()
+			{
+				throw new NotSupportedException ("Use ToString(CSComponentInspector)");
+			}
+		}
+
+		private static bool StartsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
+		{
+			return spans != null && spanIndex < spans.Count && spans [spanIndex].StartOffset == (uint)curIndex;
+		}
+
+		private static bool EndsSpan (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
+		{
+			return spans != null && spanIndex >= 0 && spans [spanIndex].EndOffset == (uint)curIndex;
+		}
+
+		private static bool StartsFilterHandler (IReadOnlyList<HandlerSpan> spans, int spanIndex, int curIndex)
+		{
+			return spans != null &&
+			spanIndex < spans.Count &&
+			spans [spanIndex].Kind == HandlerKind.Filter &&
+			spans [spanIndex].FilterHandlerStart == (uint)curIndex;
+		}
+
+		public static IReadOnlyList<HandlerSpan> GetHandlerSpans (ImmutableArray<ExceptionRegion> entries)
+		{
+			if (entries.Length == 0) {
+				return new HandlerSpan[0];
+			}
+
+			var result = new List<HandlerSpan> ();
+			foreach (ExceptionRegion entry in entries) {
+				int tryStartOffset = entry.TryOffset;
+				int tryEndOffset = entry.TryOffset + entry.TryLength;
+				var span = new HandlerSpan (HandlerKind.Try, null, tryStartOffset, tryEndOffset);
+
+				if (result.Count == 0 || span.CompareTo (result [result.Count - 1]) != 0) {
+					result.Add (span);
+				}
+			}
+
+			foreach (ExceptionRegion entry in entries) {
+				int handlerStartOffset = entry.HandlerOffset;
+				int handlerEndOffset = entry.HandlerOffset + entry.HandlerLength;
+
+				HandlerSpan span;
+				switch (entry.Kind) {
+				case ExceptionRegionKind.Catch:
+					span = new HandlerSpan (HandlerKind.Catch, MetadataTokens.GetToken (entry.CatchType), handlerStartOffset, handlerEndOffset);
+					break;
+
+				case ExceptionRegionKind.Fault:
+					span = new HandlerSpan (HandlerKind.Fault, null, handlerStartOffset, handlerEndOffset);
+					break;
+
+				case ExceptionRegionKind.Filter:
+					span = new HandlerSpan (HandlerKind.Filter, null, handlerStartOffset, handlerEndOffset, entry.FilterOffset);
+					break;
+
+				case ExceptionRegionKind.Finally:
+					span = new HandlerSpan (HandlerKind.Finally, null, handlerStartOffset, handlerEndOffset);
+					break;
+
+				default:
+					throw new InvalidOperationException ();
+				}
+
+				result.Add (span);
+			}
+
+			return result;
+		}
+
+		public void Dump ()
+		{
+			/*
+				foreach (var entry in InspectorFields) {
+					var field = entry.Value;
+
+					Console.WriteLine ("Inspector Field: {0}", field.Name);
+
+					Console.WriteLine ("   Type Name: {0}", field.TypeName);
+					Console.WriteLine ("   Default Value: {0}", field.DefaultValue);
+
+					Console.WriteLine ("   Positional Custom Attr:");
+					foreach (var p in field.CustomAttrPositionalArgs)
+					if (p.Length != 0)
+					Console.WriteLine ("      {0}", p);
+					Console.WriteLine ("   Named Custom Attr:");
+					foreach (var nentry in field.CustomAttrNamedArgs)
+					Console.WriteLine ("      {0}:{1}", nentry.Key, nentry.Value);
+				}
+				*/
+		}
+
+	}
+
+	internal static class TokenTypeIds
+	{
+		internal const uint Module = 0x00000000;
+		internal const uint TypeRef = 0x01000000;
+		internal const uint TypeDef = 0x02000000;
+		internal const uint FieldDef = 0x04000000;
+		internal const uint MethodDef = 0x06000000;
+		internal const uint ParamDef = 0x08000000;
+		internal const uint InterfaceImpl = 0x09000000;
+		internal const uint MemberRef = 0x0a000000;
+		internal const uint CustomAttribute = 0x0c000000;
+		internal const uint Permission = 0x0e000000;
+		internal const uint Signature = 0x11000000;
+		internal const uint Event = 0x14000000;
+		internal const uint Property = 0x17000000;
+		internal const uint ModuleRef = 0x1a000000;
+		internal const uint TypeSpec = 0x1b000000;
+		internal const uint Assembly = 0x20000000;
+		internal const uint AssemblyRef = 0x23000000;
+		internal const uint File = 0x26000000;
+		internal const uint ExportedType = 0x27000000;
+		internal const uint ManifestResource = 0x28000000;
+		internal const uint GenericParam = 0x2a000000;
+		internal const uint MethodSpec = 0x2b000000;
+		internal const uint GenericParamConstraint = 0x2c000000;
+		internal const uint String = 0x70000000;
+		internal const uint Name = 0x71000000;
+		internal const uint BaseType = 0x72000000;
+		// Leave this on the high end value. This does not correspond to metadata table???
+
+		internal const uint RIDMask = 0x00FFFFFF;
+		internal const uint TokenTypeMask = 0xFF000000;
+	}
+
+
+}

+ 72 - 0
Script/AtomicNET/AtomicNETService/Program.cs

@@ -0,0 +1,72 @@
+using System;
+using AtomicEngine;
+
+// net genproject C:\Dev\atomic\AtomicGameEngine\Script\AtomicNET\AtomicNETProject.json WINDOWS
+// net parse C:\Dev\atomic\AtomicGameEngine\Artifacts\AtomicNET\Build\AtomicNETService\bin\Debug\AtomicNETService.exe
+// net compile C:\Dev\atomic\AtomicGameEngine\Artifacts\AtomicNET\Build\AtomicNET.sln
+
+
+namespace AtomicTools
+{
+
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            // create the service
+            var app = NETServiceApplication.Create();
+
+            // Subscribe to IPC NET commands
+            app.SubscribeToEvent("IPCCmd", (eventType, eventData) =>
+            {
+                // get the command
+                string command = eventData["command"];
+
+                switch (command)
+                {
+                    // parse assembly for component information
+                    case "parse":
+
+                        // Get the assembly to parse
+                        string assemblyPath = eventData["assemblyPath"];
+
+                        // Inspect the assembly for components
+                        var assemblyJSON = AtomicTools.InspectAssembly(assemblyPath);
+
+                        // Return result
+                        var vmap = new ScriptVariantMap();
+
+                        // FIXME: update index operator to a generic
+                        vmap.SetUInt("id", eventData.GetUInt("id"));
+
+                        vmap["command"] = command;
+                        vmap["result"] = assemblyJSON;
+
+                        AtomicNET.GetSubsystem<IPC>().SendEventToBroker("IPCCmdResult", vmap);
+
+                        break;
+
+                    // exit service
+                    case "exit":
+
+                        app.SendEvent("ExitRequested");
+                        break;
+
+                }
+
+            });
+
+            // Managed code in charge of main loop
+            while (app.RunFrame())
+            {
+
+            }
+
+            // Shut 'er down
+            app.Shutdown();
+
+        }
+    }
+}
+
+

+ 22 - 0
Script/AtomicNET/AtomicPlayer/Program.cs

@@ -0,0 +1,22 @@
+
+using AtomicEngine;
+
+public class Program
+{
+    public static void Main(string[] args)
+    {               
+        // Create the Application
+        var app = NETIPCPlayerApp.Create();
+
+        // Managed code in charge of main loop
+        while (app.RunFrame())
+        {
+
+        }
+
+        // Shut 'er down
+        app.Shutdown();
+    }
+}
+
+

+ 27 - 0
Script/AtomicNET/AtomicPlayer/project.json

@@ -0,0 +1,27 @@
+{
+  "version": "1.0.0-*",
+  "buildOptions": {
+    "emitEntryPoint": true, 
+    "allowUnsafe": true
+  },
+  "dependencies": {
+    "AtomicNETCore": {
+      "target": "project"
+    },
+    "AtomicNET": {
+      "target": "project"
+    },        
+    "Microsoft.NETCore.App": {      
+      "version": "1.0.0-rc2-3002702"
+    }
+  },
+  "runtimes": {                                                     
+      "osx.10.11-x64": {}                                               
+  },    
+  "frameworks": {
+    "netcoreapp1.0": {
+      "imports": "dnxcore50"
+    }
+  }
+}
+

+ 18 - 0
Script/AtomicNET/ComponentTest/Spinner.cs

@@ -0,0 +1,18 @@
+using System;
+using AtomicEngine;
+
+namespace ComponentTest
+{
+    public class Spinner : CSComponent
+    {
+        [Inspector()]
+        public float Speed = 1.0f;
+
+        void Update(float timeStep)
+        {
+            Node.Yaw(timeStep * Speed * 70);
+        }
+
+    }
+
+}

+ 47 - 0
Script/AtomicNET/ComponentTest/TestComponent.cs

@@ -0,0 +1,47 @@
+using System;
+using AtomicEngine;
+
+namespace ComponentTest
+{
+
+    public enum BehaviorState
+    {
+        Friendly,
+        Aggressive,
+        Neutral
+    }
+
+    public class TestComponent : CSComponent
+    {
+        [Inspector]
+        public bool MyBoolValue = true;
+
+        [Inspector]
+        public int MyIntValue = 5;
+
+        [Inspector]
+        public int MyOtherIntValue = 101;
+
+        [Inspector]
+        public Vector3 MyVector3Value = new Vector3(1, 1, 1);
+
+        [Inspector]
+        public Quaternion MyQuaternionValue = new Quaternion(1, 0, 0, 0);
+
+        [Inspector()]
+        public float MyFloatValue = 42.0f;
+
+        [Inspector]
+        public string MyStringValue = "Hey!";
+
+        [Inspector]
+        public BehaviorState State = BehaviorState.Neutral;
+
+        [Inspector("Textures/chest.png")]
+        public Sprite2D MySprite2DValue;
+
+        [Inspector(DefaultValue = "Textures/chest.png")]
+        public Sprite2D MyOtherSprite2DValue;
+    }
+
+}

+ 30 - 0
Script/AtomicNET/Docs/Notes.txt

@@ -0,0 +1,30 @@
+// Debugging Unmanaged Code, example invocation
+
+/usr/local/share/dotnet/dotnet exec --additionalprobingpath /Users/josh/.nuget/packages /Users/josh/Dev/atomic/AtomicGameEngine/Script/AtomicNET/AtomicNETCore/bin/Debug/netcoreapp1.0/AtomicNETCore.dll
+
+// Example launch.json
+
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": ".NET Core Launch (console)",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build",
+            "program": "${workspaceRoot}/AtomicTest/bin/Debug/netcoreapp1.0/AtomicTest.dll",
+            "args": [],
+            "cwd": "${workspaceRoot}",
+            "stopAtEntry": false,
+            "externalConsole": false
+        },
+        {
+            "name": ".NET Core Attach",
+            "type": "coreclr",
+            "request": "attach",
+            "processId": 0
+        }
+    ]
+}
+
+// Example tasks.json

+ 1 - 1
Script/Packages/Atomic/Engine.json

@@ -2,5 +2,5 @@
 	"name" : "Engine",
 	"sources" : ["Source/Atomic/Engine"],
 	"includes" : [],
-	"classes" : ["Engine"]
+	"classes" : ["Engine", "Application"]
 }

+ 6 - 0
Script/Packages/Atomic/IPC.json

@@ -0,0 +1,6 @@
+{
+	"name" : "IPC",
+	"includes" : ["Atomic/IPC/IPCMessage.h"],
+	"sources" : ["Source/Atomic/IPC"],
+	"classes" : ["IPC"]
+}

+ 7 - 6
Script/Packages/Atomic/Package.json

@@ -2,11 +2,12 @@
 {
 	"name" : "Atomic",
 	"namespace" : "Atomic",
-
 	"modules" : ["Container", "Math", "Core", "Scene", "Graphics", "Atomic3D", "Atomic2D", "Audio",
-	"Physics", "Navigation", "Input", "UI", "Resource", "Network", "IO",
-	"Engine", "Script", "Javascript", "Environment", "Web"],
-	"moduleExclude" : {
-		"WEB" : ["Network", "Navigation"]
+		"Physics", "Navigation", "Input", "UI", "Resource", "Network", "IO",
+		"Engine", "Script", "Javascript", "Environment", "Web", "IPC"],
+		"moduleExclude" : {
+			"WEB" : ["Network", "Navigation", "IPC"],
+			"ANDROID" : ["IPC"],
+			"IOS" : ["IPC"]
+		}
 	}
-}

+ 1 - 1
Script/Packages/Atomic/Script.json

@@ -1,5 +1,5 @@
 {
 	"name" : "Script",
 	"sources" : ["Source/Atomic/Script"],
-	"classes" : ["ScriptComponent", "ScriptComponentFile"]
+	"classes" : ["ScriptVariantMap", "ScriptComponent", "ScriptComponentFile"]
 }

+ 5 - 0
Script/Packages/AtomicApp/AtomicApp.json

@@ -0,0 +1,5 @@
+{
+	"name" : "AtomicApp",
+	"sources" : ["Source/AtomicApp", "Source/AtomicApp/Player"],
+	"classes" : ["AppBase", "IPCClientApp", "PlayerApp", "IPCPlayerApp"]
+}

+ 8 - 0
Script/Packages/AtomicApp/Package.json

@@ -0,0 +1,8 @@
+
+{
+  "name" : "AtomicApp",
+  "namespace" : "Atomic",
+  "dependencies" : ["Script/Packages/Atomic"],
+  "modules" : ["AtomicApp"],
+  "platforms" : ["WINDOWS", "MACOSX", "LINUX"]
+}

+ 5 - 0
Script/Packages/AtomicNETNative/AtomicNETNative.json

@@ -0,0 +1,5 @@
+{
+	"name" : "AtomicNETNative",
+	"sources" : ["Source/AtomicNET/NETNative"],
+	"classes" : ["NETCore", "NETIPCPlayerApp", "NETServiceApplication"]
+}

+ 9 - 0
Script/Packages/AtomicNETNative/Package.json

@@ -0,0 +1,9 @@
+
+{
+  "name" : "AtomicNETNative",
+  "namespace" : "Atomic",
+  "dependencies" : ["Script/Packages/AtomicApp"],
+  "modules" : ["AtomicNETNative"],
+  "platforms" : ["WINDOWS", "MACOSX","LINUX"],
+  "bindings" : ["CSharp"]
+}

+ 5 - 0
Script/Packages/AtomicNETScript/AtomicNETScript.json

@@ -0,0 +1,5 @@
+{
+	"name" : "AtomicNETScript",
+	"sources" : ["Source/AtomicNET/NETScript"],
+	"classes" : ["NETScriptObject", "CSComponent", "CSComponentAssembly"]
+}

+ 8 - 0
Script/Packages/AtomicNETScript/Package.json

@@ -0,0 +1,8 @@
+
+{
+  "name" : "AtomicNETScript",
+  "namespace" : "Atomic",
+  "dependencies" : ["Script/Packages/Atomic"],
+  "modules" : ["AtomicNETScript"],
+  "platforms" : ["WINDOWS", "MACOSX","LINUX"]
+}

+ 1 - 1
Script/Packages/ToolCore/ToolCore.json

@@ -8,7 +8,7 @@
 							 "PlatformWindows", "PlatformAndroid", "PlatformIOS", "Command", "PlayCmd", "OpenAssetImporter",
 							 "Asset", "AssetDatabase", "AssetImporter", "AudioImporter", "ModelImporter", "MaterialImporter", "AnimationImportInfo",
 							 "PrefabImporter", "JavascriptImporter", "JSONImporter",
-							 "TextureImporter", "SpriterImporter", "PEXImporter",
+							 "TextureImporter", "SpriterImporter", "PEXImporter", "NETAssemblyImporter",
 							 "LicenseSystem",
 						 	 "ProjectUserPrefs", "ProjectBuildSettings",
 						 	 "BuildBase", "BuildSystem", "BuildMac", "BuildWeb", "BuildWindows", "BuildAndroid", "BuildIOS",

+ 3 - 0
Script/tsconfig.json

@@ -39,9 +39,11 @@
         "./AtomicEditor/ui/EditorUI.ts",
         "./AtomicEditor/ui/frames/HierarchyFrame.ts",
         "./AtomicEditor/ui/frames/inspector/ArrayEditWidget.ts",
+        "./AtomicEditor/ui/frames/inspector/AssemblyInspector.ts",
         "./AtomicEditor/ui/frames/inspector/AttributeInfoEdit.ts",
         "./AtomicEditor/ui/frames/inspector/ComponentAttributeUI.ts",
         "./AtomicEditor/ui/frames/inspector/CreateComponentButton.ts",
+        "./AtomicEditor/ui/frames/inspector/CSComponentClassSelector.ts",
         "./AtomicEditor/ui/frames/inspector/InspectorFrame.ts",
         "./AtomicEditor/ui/frames/inspector/InspectorUtils.ts",
         "./AtomicEditor/ui/frames/inspector/InspectorWidget.ts",
@@ -104,6 +106,7 @@
         "./AtomicEditor/ui/Shortcuts.ts",
         "./AtomicEditor/ui/UIEvents.ts",
         "./TypeScript/Atomic.d.ts",
+        "./TypeScript/AtomicNETScript.d.ts",
         "./TypeScript/AtomicPlayer.d.ts",
         "./TypeScript/AtomicWork.d.ts",
         "./TypeScript/duktape.d.ts",

+ 2 - 1
Source/Atomic/CMakeLists.txt

@@ -100,7 +100,8 @@ GroupSources("Resource")
 GroupSources("Scene")
 GroupSources("UI")
 GroupSources("Web")
+GroupSources("Script")
 
 add_library(Atomic ${SOURCE_FILES})
 
-include(AtomicDoc)
+include(AtomicDoc)

+ 3 - 0
Source/Atomic/Graphics/Direct3D9/D3D9Texture.h

@@ -38,6 +38,9 @@ class XMLFile;
 /// Base class for texture resources.
 class ATOMIC_API Texture : public Resource, public GPUObject
 {
+    OBJECT(Texture)
+    BASEOBJECT(Resource)
+
 public:
     /// Construct.
     Texture(Context* context);

+ 3 - 0
Source/Atomic/Graphics/OpenGL/OGLTexture.h

@@ -38,6 +38,9 @@ class XMLFile;
 /// Base class for texture resources.
 class ATOMIC_API Texture : public Resource, public GPUObject
 {
+    OBJECT(Texture)
+    BASEOBJECT(Resource)
+
 public:
     /// Construct.
     Texture(Context* context);

+ 72 - 5
Source/Atomic/IPC/IPC.cpp

@@ -91,20 +91,87 @@ bool IPC::InitWorker(unsigned id, IPCHandle fd1, IPCHandle fd2)
 #ifndef ATOMIC_PLATFORM_WINDOWS
     // close server fd
     close(fd1);
-	worker_ = new IPCWorker(context_, fd2, id);
+    worker_ = new IPCWorker(context_, fd2, id);
 #else
-	worker_ = new IPCWorker(context_, fd1, fd2, id);
+    worker_ = new IPCWorker(context_, fd1, fd2, id);
 #endif
 
-
-
-	worker_->Run();
+    worker_->Run();
 
     SendEventToBroker(E_IPCWORKERSTART);
 
     return true;
 }
 
+bool IPC::ProcessArguments(const Vector<String>& arguments, int& id, IPCHandle& fd0, IPCHandle& fd1)
+{
+    id = -1;
+    fd0 = INVALID_IPCHANDLE_VALUE;
+    fd1 = INVALID_IPCHANDLE_VALUE;
+
+    for (unsigned i = 0; i < arguments.Size(); ++i)
+    {
+        if (arguments[i].Length() > 1)
+        {
+            String argument = arguments[i].ToLower();
+
+            if (argument.StartsWith("--ipc-id="))
+            {
+                Vector<String> idc = argument.Split(argument.CString(), '=');
+                if (idc.Size() == 2)
+
+                    id = ToInt(idc[1].CString());
+            }
+
+            else if (argument.StartsWith("--ipc-server=") || argument.StartsWith("--ipc-client="))
+            {
+                LOGINFOF("Starting IPCWorker %s", argument.CString());
+
+                Vector<String> ipc = argument.Split(argument.CString(), '=');
+
+                if (ipc.Size() == 2)
+                {
+                    if (argument.StartsWith("--ipc-server="))
+                    {
+#ifdef ATOMIC_PLATFORM_WINDOWS
+                        // clientRead
+                        WString wipc(ipc[1]);
+                        HANDLE pipe = reinterpret_cast<HANDLE>(_wtoi64(wipc.CString()));
+                        fd0 = pipe;
+#else
+                        int fd = ToInt(ipc[1].CString());
+                        fd0 = fd;
+#endif
+                    }
+                    else
+                    {
+#ifdef ATOMIC_PLATFORM_WINDOWS
+                        // clientWrite
+                        WString wipc(ipc[1]);
+                        HANDLE pipe = reinterpret_cast<HANDLE>(_wtoi64(wipc.CString()));
+                        fd1 = pipe;
+#else
+                        int fd = ToInt(ipc[1].CString());
+                        fd1 = fd;
+#endif
+                    }
+
+                }
+
+            }
+
+        }
+    }
+
+    if (id > 0 && fd0 != INVALID_IPCHANDLE_VALUE && fd1 != INVALID_IPCHANDLE_VALUE)
+    {
+        return true;
+    }
+
+    return false;
+
+}
+
 IPCBroker* IPC::SpawnWorker(const String& command, const Vector<String>& args, const String& initialDirectory)
 {
     SharedPtr<IPCBroker> broker(new IPCBroker(context_));

+ 3 - 0
Source/Atomic/IPC/IPC.h

@@ -65,6 +65,9 @@ public:
     void SendEventToBroker(StringHash eventType);
     void SendEventToBroker(StringHash eventType, VariantMap& eventData);
 
+    // Processes arg strings looking for ipc server/client handles, returns true if an IPC subprocess
+    static bool ProcessArguments(const Vector<String>& arguments, int& id, IPCHandle& fd1, IPCHandle& fd2);
+
 #ifdef ATOMIC_PLATFORM_WINDOWS
     IPCHandle GetJobHandle() const { return jobHandle_; }
 #endif

+ 219 - 0
Source/Atomic/IPC/IPCServer.cpp

@@ -0,0 +1,219 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/FileSystem.h>
+
+#include <Atomic/IPC/IPC.h>
+#include <Atomic/IPC/IPCEvents.h>
+#include <Atomic/IPC/IPCBroker.h>
+
+#include <Atomic/Core/CoreEvents.h>
+
+#include "IPCServer.h"
+
+namespace Atomic
+{
+
+
+    unsigned IPCServer::cmdID_ = 1;
+
+    IPCResultHandler::IPCResultHandler(Context* context) :
+        Object(context)
+    {
+
+    }
+
+    IPCResultHandler::~IPCResultHandler()
+    {
+
+    }
+
+    IPCServer::IPCServer(Context* context) :
+        Object(context),
+        brokerEnabled_(false)
+    {
+
+    }
+
+    IPCServer::~IPCServer()
+    {
+
+    }
+
+    void IPCServer::HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData)
+    {
+        VariantMap startupData;
+        serverBroker_->PostMessage(E_IPCINITIALIZE, startupData);
+        brokerEnabled_ = true;
+
+        SubscribeToEvent(E_UPDATE, HANDLER(IPCServer, HandleUpdate));
+
+        SubscribeToEvent(serverBroker_, E_IPCCMDRESULT, HANDLER(IPCServer, HandleIPCCmdResult));
+    }
+
+    void IPCServer::HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData)
+    {
+        if (eventData[IPCWorkerExit::P_BROKER] == serverBroker_)
+        {
+            serverBroker_ = 0;
+            brokerEnabled_ = false;
+        }
+    }
+
+    void IPCServer::HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace IPCWorkerLog;
+
+        // convert to a server log
+
+        VariantMap serverLogData;
+
+        serverLogData["message"] = eventData[P_MESSAGE].GetString();
+        serverLogData["level"] = eventData[P_LEVEL].GetInt();
+
+        SendEvent("IPCServerLog", serverLogData);
+
+    }
+
+    bool IPCServer::StartInternal(const String& exec, const Vector<String>& args)
+    {
+
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+        clientExecutable_ = exec;
+
+        if (!clientExecutable_.Length() || !fileSystem->FileExists(clientExecutable_))
+        {
+            LOGERRORF("IPCServer::Start - Client Executable does not exist: %s", clientExecutable_.CString());
+            return false;
+        }
+
+        String dump;
+        dump.Join(args, " ");
+
+        LOGDEBUGF("Launching Broker %s %s", clientExecutable_.CString(), dump.CString());
+
+        IPC* ipc = GetSubsystem<IPC>();
+        serverBroker_ = ipc->SpawnWorker(clientExecutable_, args);
+
+        if (serverBroker_)
+        {
+            SubscribeToEvent(serverBroker_, E_IPCWORKERSTART, HANDLER(IPCServer, HandleIPCWorkerStarted));
+            SubscribeToEvent(serverBroker_, E_IPCWORKEREXIT, HANDLER(IPCServer, HandleIPCWorkerExit));
+            SubscribeToEvent(serverBroker_, E_IPCWORKERLOG, HANDLER(IPCServer, HandleIPCWorkerLog));
+        }
+        else
+        {
+            LOGERRORF("Error Spawning Broker %s %s", clientExecutable_.CString(), dump.CString());
+        }
+
+        return serverBroker_.NotNull();
+
+    }
+
+    bool IPCServer::GetBrokerEnabled() const
+    {
+        return brokerEnabled_;
+    }
+
+    void IPCServer::HandleIPCCmdResult(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace IPCCmdResult;
+
+        unsigned id = eventData[P_ID].GetUInt();
+
+        List<IPCCommand>::Iterator itr = cmdProcess_.Begin();
+
+        bool found = false;
+        while (itr != cmdProcess_.End())
+        {
+            if ((*itr).id_ == id)
+            {
+                IPCCommand cmd = *itr;
+
+                cmdProcess_.Erase(itr);
+
+                found = true;
+
+                if (cmd.handler_.Expired())
+                {
+                    LOGERROR("IPCServer::HandleIPCNETCmdResult - IPCNETResult for expired client");
+                    break;
+                }
+
+                cmd.handler_->HandleResult(cmd.id_, eventData);
+
+                break;
+            }
+
+            itr++;
+
+        }
+
+        if (!found)
+        {
+            LOGERRORF("IPCServer::HandleIPCNETCmdResult - IPCNETResult command %u not found in process queue", id);
+        }
+
+    }
+
+
+    unsigned IPCServer::QueueCommand(IPCResultHandler* handler, const VariantMap& cmdMap)
+    {
+        IPCCommand cmd;
+
+        cmd.id_ = cmdID_++;
+        cmd.handler_ = handler;
+        cmd.cmdMap_ = cmdMap;
+        cmd.cmdMap_[IPCCmd::P_ID] = cmd.id_;
+
+        cmdQueue_.Push(cmd);
+
+        return cmd.id_;
+    }
+
+    void IPCServer::HandleUpdate(StringHash eventType, VariantMap& eventData)
+    {
+
+        if (!cmdQueue_.Size())
+            return;
+
+        IPCCommand cmd = cmdQueue_.Front();
+        cmdQueue_.PopFront();
+
+        String cmdString = cmd.cmdMap_["command"].GetString();
+
+        if (!serverBroker_)
+        {
+            LOGERRORF("IPCServer::HandleUpdate - null player broker for command: %s", cmdString.CString());
+            return;
+        }
+
+        cmdProcess_.Push(cmd);
+
+        serverBroker_->PostMessage(E_IPCCMD, cmd.cmdMap_);
+
+    }
+
+
+}

+ 110 - 0
Source/Atomic/IPC/IPCServer.h

@@ -0,0 +1,110 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include <Atomic/Core/Object.h>
+#include <Atomic/Container/List.h>
+
+namespace Atomic
+{
+    EVENT(E_IPCCMD, IPCCmd)
+    {
+        PARAM(P_COMMAND, Command);
+        PARAM(P_ID, ID); // unsigned
+    }
+
+    EVENT(E_IPCCMDRESULT, IPCCmdResult)
+    {
+        PARAM(P_COMMAND, Command);
+        PARAM(P_ID, ID); // unsigned
+    }
+
+    class IPCBroker;
+
+    /// IPCResultHandler
+    class IPCResultHandler : public Object
+    {
+        OBJECT(IPCResultHandler)
+
+    public:
+        /// Construct.
+        IPCResultHandler(Context* context);
+        /// Destruct.
+        virtual ~IPCResultHandler();
+
+        virtual void HandleResult(unsigned cmdID, const VariantMap& cmdResult) = 0;
+
+    private:
+
+    };
+
+    /// IPCServer
+    class IPCServer : public Object
+    {
+        OBJECT(IPCServer)
+
+    public:
+        /// Construct.
+        IPCServer(Context* context);
+        /// Destruct.
+        virtual ~IPCServer();
+
+        virtual bool Start() = 0;
+
+        unsigned QueueCommand(IPCResultHandler* handler, const VariantMap& cmdMap);
+        bool GetBrokerEnabled() const;
+
+    protected:
+
+        bool StartInternal(const String& exec, const Vector<String>& args);
+
+    private:
+
+        struct IPCCommand
+        {
+            unsigned id_;
+            WeakPtr<IPCResultHandler> handler_;
+            VariantMap cmdMap_;
+        };
+
+        void HandleUpdate(StringHash eventType, VariantMap & eventData);
+
+        void HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData);
+        void HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData);
+        void HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData);
+
+        void HandleIPCCmdResult(StringHash eventType, VariantMap& eventData);
+
+        String clientExecutable_;
+
+        SharedPtr<IPCBroker> serverBroker_;
+        bool brokerEnabled_;
+
+        List<IPCCommand> cmdQueue_;
+        List<IPCCommand> cmdProcess_;
+
+        static unsigned cmdID_;
+
+    };
+
+}

+ 4 - 0
Source/Atomic/Resource/JSONValue.h

@@ -22,9 +22,13 @@
 
 #pragma once
 
+#include <Atomic/Core/Variant.h>
+
 namespace Atomic
 {
 
+class Context;
+
 /// JSON value type.
 enum JSONValueType
 {

+ 4 - 1
Source/Atomic/Script/ScriptSystem.cpp

@@ -5,16 +5,19 @@
 namespace Atomic
 {
 
+WeakPtr<Context> ScriptSystem::scriptContext_;
+
 void RegisterScriptLibrary(Context* context);
 
 ScriptSystem::ScriptSystem(Context* context) : Object(context)
 {
     RegisterScriptLibrary(context);
+    scriptContext_ = context;
 }
 
 ScriptSystem::~ScriptSystem()
 {
-
+    scriptContext_ = nullptr;
 }
 
 void RegisterScriptLibrary(Context* context)

+ 18 - 9
Source/Atomic/Script/ScriptSystem.h

@@ -1,20 +1,29 @@
 
+#include "../Core/Context.h"
 #include "../Core/Object.h"
 
 #pragma once
 
 namespace Atomic
 {
-  class ScriptSystem : public Object
-  {
-      OBJECT(ScriptSystem);
 
-  public:
+class ScriptSystem : public Object
+{
+    OBJECT(ScriptSystem);
+
+public:
+
+    /// Construct.
+    ScriptSystem(Context* context);
+    /// Destruct.
+    virtual ~ScriptSystem();
+
+    static Context* GetContext() { return scriptContext_; }
+
+private:
+
+    static WeakPtr<Context> scriptContext_;
 
-      /// Construct.
-      ScriptSystem(Context* context);
-      /// Destruct.
-      virtual ~ScriptSystem();
-  };
+};
 
 }

+ 9 - 0
Source/Atomic/Script/ScriptVariantMap.cpp

@@ -0,0 +1,9 @@
+
+#include "ScriptVariantMap.h"
+
+namespace Atomic
+{
+
+
+
+}

+ 188 - 0
Source/Atomic/Script/ScriptVariantMap.h

@@ -0,0 +1,188 @@
+
+#pragma once
+
+#include <Atomic/Core/Variant.h>
+#include <Atomic/Resource/ResourceCache.h>
+
+#include "ScriptSystem.h"
+
+namespace Atomic
+{
+
+/// Wraps a VariantMap as a RefCounted so we can easily send it to script code
+/// For performance sensitive code, specialized marshaling should be used instead (for example physics event data)
+class ScriptVariantMap : public RefCounted
+{
+    REFCOUNTED(ScriptVariantMap)
+
+public:
+
+    ScriptVariantMap() : RefCounted()
+    {
+
+    }
+
+    virtual ~ScriptVariantMap()
+    {
+
+    }
+
+    bool GetBool(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return 0;
+
+        return variant->GetBool();
+
+    }
+
+    int GetInt(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return 0;
+
+        return variant->GetInt();
+
+    }
+
+    unsigned GetUInt(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return 0;
+
+        return variant->GetUInt();
+
+    }
+
+    float GetFloat(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return 0;
+
+        return variant->GetFloat();
+
+    }
+
+    const Vector3& GetVector3(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return Vector3::ZERO;
+
+        return variant->GetVector3();
+
+    }
+
+    const Quaternion& GetQuaternion(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return Quaternion::IDENTITY;
+
+        return variant->GetQuaternion();
+
+    }
+
+    void* GetVoidPtr(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return nullptr;
+
+        return variant->GetVoidPtr();
+
+    }
+
+    RefCounted* GetPtr(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return 0;
+
+        return variant->GetPtr();
+
+    }
+
+    const String& GetString(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return String::EMPTY;
+
+        return variant->GetString();
+
+    }
+
+    VariantType GetVariantType(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (!variant)
+            return VAR_NONE;
+
+        return variant->GetType();
+    }
+
+    Resource* GetResourceFromRef(StringHash key) const
+    {
+        Variant* variant = vmap_[key];
+
+        if (variant && variant->GetType() == VAR_RESOURCEREF)
+        {
+            const ResourceRef& ref = variant->GetResourceRef();
+
+            if (!ref.name_.Length())
+                return 0;
+
+            return ScriptSystem::GetContext()->GetSubsystem<ResourceCache>()->GetResource(ref.type_, ref.name_);
+
+        }
+
+        return 0;
+
+    }
+
+    void SetUInt(StringHash key, unsigned value)
+    {
+        vmap_[key] = value;
+    }
+
+    void SetString(StringHash key, String value)
+    {
+        vmap_[key] = value;
+    }
+
+    void Clear()
+    {
+        vmap_.Clear();
+    }
+
+    bool Contains(StringHash key) const
+    {
+        return vmap_.Contains(key);
+    }
+
+    void CopySourceVariantMap(const VariantMap& src) { vmap_ = src; }
+
+    VariantMap& GetVariantMap() { return vmap_; }
+
+private:
+
+    VariantMap vmap_;
+
+};
+
+}

+ 3 - 1
Source/Atomic/UI/UI.cpp

@@ -408,7 +408,9 @@ void UI::Render(bool resetRenderTargets)
     SetVertexData(vertexBuffer_, vertexData_);
     Render(vertexBuffer_, batches_, 0, batches_.Size());
 
-    GetSubsystem<SystemUI::SystemUI>()->Render();
+    SystemUI::SystemUI* systemUI = GetSubsystem<SystemUI::SystemUI>();
+    if (systemUI)
+        systemUI->Render();
 }
 
 void UI::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)

+ 182 - 0
Source/AtomicApp/AppBase.cpp

@@ -0,0 +1,182 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/IOEvents.h>
+#include <Atomic/Engine/Engine.h>
+#include <Atomic/Engine/EngineConfig.h>
+
+#include <Atomic/Script/ScriptSystem.h>
+#include <AtomicJS/Javascript/Javascript.h>
+
+// Move me!
+#include <Atomic/Environment/Environment.h>
+
+#include "AppBase.h"
+
+namespace Atomic
+{
+
+    Vector<String> AppBase::engineConfigSearchPaths_;
+
+    AppBase::AppBase(Context* context) :
+        Application(context)
+    {
+        // Copy arguments
+        arguments_ = GetArguments();
+    }
+
+    AppBase::~AppBase()
+    {
+
+    }
+
+    void AppBase::ProcessArguments()
+    {
+        for (unsigned i = 0; i < arguments_.Size(); ++i)
+        {
+            if (arguments_[i].Length() > 1)
+            {
+                String argument = arguments_[i].ToLower();
+                String value = i + 1 < arguments_.Size() ? arguments_[i + 1] : String::EMPTY;
+
+                if (argument == "--log-std")
+                {
+                    SubscribeToEvent(E_LOGMESSAGE, HANDLER(AppBase, HandleLogMessage));
+                }
+            }
+        }
+    }
+
+    void AppBase::Setup()
+    {
+        Application::Setup();
+
+#ifdef ATOMIC_3D
+        // Move me!
+        RegisterEnvironmentLibrary(context_);
+#endif
+
+        ProcessArguments();
+
+        // Read the engine configuration
+        ReadEngineConfig();
+
+        context_->RegisterSubsystem(new ScriptSystem(context_));
+
+        // Instantiate and register the Javascript subsystem
+        Javascript* javascript = new Javascript(context_);
+        context_->RegisterSubsystem(javascript);
+
+        SubscribeToEvent(E_JSERROR, HANDLER(AppBase, HandleJSError));
+
+    }
+
+    void AppBase::Start()
+    {
+        Application::Start();
+
+        Javascript* javascript = GetSubsystem<Javascript>();
+        vm_ = javascript->InstantiateVM("MainVM");
+        vm_->InitJSContext();
+
+    }
+
+    void AppBase::Stop()
+    {
+
+        vm_ = 0;
+        context_->RemoveSubsystem<Javascript>();
+        // make sure JSVM is really down and no outstanding refs
+        // as if not, will hold on engine subsystems, which is bad
+        assert(!JSVM::GetJSVM(0));
+
+        Application::Stop();
+
+    }
+
+    void AppBase::ReadEngineConfig()
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+        for (unsigned i = 0; i < engineConfigSearchPaths_.Size(); i++)
+        {
+            const String& path = engineConfigSearchPaths_[i];
+
+            if (!fileSystem->DirExists(path))
+                continue;
+
+            String filename = AddTrailingSlash(path) + "Engine.json";
+
+            if (!fileSystem->FileExists(filename))
+                return;
+
+            if (EngineConfig::LoadFromFile(context_, filename))
+            {
+                EngineConfig::ApplyConfig(engineParameters_);
+            }
+        }
+
+    }
+
+    // Handlers
+
+    void AppBase::HandleLogMessage(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace LogMessage;
+
+        int level = eventData[P_LEVEL].GetInt();
+        // The message may be multi-line, so split to rows in that case
+        Vector<String> rows = eventData[P_MESSAGE].GetString().Split('\n');
+
+        for (unsigned i = 0; i < rows.Size(); ++i)
+        {
+            if (level == LOG_ERROR)
+            {
+                fprintf(stderr, "%s\n", rows[i].CString());
+            }
+            else
+            {
+                fprintf(stdout, "%s\n", rows[i].CString());
+            }
+        }
+
+    }
+
+    void AppBase::HandleJSError(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace JSError;
+
+        String errMessage = eventData[P_ERRORMESSAGE].GetString();
+        String errFilename = eventData[P_ERRORFILENAME].GetString();
+        int errLineNumber = eventData[P_ERRORLINENUMBER].GetInt();
+
+        String errorString = ToString("%s - %s - Line: %i",
+            errFilename.CString(), errMessage.CString(), errLineNumber);
+
+        LOGERROR(errorString);
+
+    }
+
+}
+

+ 70 - 0
Source/AtomicApp/AppBase.h

@@ -0,0 +1,70 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include <Atomic/Engine/Application.h>
+
+namespace Atomic
+{
+
+    class JSVM;
+
+    class AppBase : public Application
+    {
+        OBJECT(AppBase)
+
+    public:
+        /// Construct.
+        AppBase(Context* context);
+        virtual ~AppBase();
+
+        /// Setup before engine initialization. 
+        virtual void Setup();
+        /// Setup after engine initialization. L
+        virtual void Start();
+        /// Cleanup after the main loop. 
+        virtual void Stop();
+
+        void AddArgument(const String& argument) { arguments_.Push(argument); }
+
+        virtual void ProcessArguments();
+
+        static void AddEngineConfigSearchPath(const String& path) { engineConfigSearchPaths_.Push(path); }
+
+    protected:
+
+        void ReadEngineConfig();
+
+        Vector<String> arguments_;
+        static Vector<String> engineConfigSearchPaths_;
+
+        SharedPtr<JSVM> vm_;
+
+    private:
+
+        void HandleLogMessage(StringHash eventType, VariantMap& eventData);
+        void HandleJSError(StringHash eventType, VariantMap& eventData);
+
+    };
+
+}

+ 11 - 0
Source/AtomicApp/CMakeLists.txt

@@ -0,0 +1,11 @@
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty )
+
+file (GLOB_RECURSE SOURCE_FILES *.cpp *.h)
+
+add_library(AtomicApp ${SOURCE_FILES})
+
+add_dependencies(AtomicApp AtomicToolCheckScripts)
+
+GroupSources("Player")

+ 98 - 0
Source/AtomicApp/IPCClientApp.cpp

@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <Atomic/IO/IOEvents.h>
+#include <Atomic/IO/Log.h>
+#include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/Core/CoreEvents.h>
+#include <Atomic/IPC/IPCEvents.h>
+#include <Atomic/IPC/IPCWorker.h>
+
+#include "IPCClientApp.h"
+
+#ifdef ATOMIC_PLATFORM_WINDOWS
+#include <windows.h>
+#endif
+
+namespace Atomic
+{
+
+    IPCClientApp::IPCClientApp(Context* context) :
+        AppBase(context),
+        brokerActive_(false)
+    {
+        fd_[0] = INVALID_IPCHANDLE_VALUE;
+        fd_[1] = INVALID_IPCHANDLE_VALUE;
+    }
+
+    IPCClientApp::~IPCClientApp()
+    {
+    }
+
+    void IPCClientApp::Setup()
+    {
+        AppBase::Setup();
+
+        ipc_ = new IPC(context_);
+        context_->RegisterSubsystem(ipc_);
+
+        SubscribeToEvent(E_LOGMESSAGE, HANDLER(IPCClientApp, HandleLogMessage));
+    }
+
+    void IPCClientApp::HandleIPCInitialize(StringHash eventType, VariantMap& eventData)
+    {
+        brokerActive_ = true;
+    }
+
+    bool IPCClientApp::Initialize(const Vector<String>& arguments)
+    {
+
+        int id = -1;
+        if (!IPC::ProcessArguments(arguments, id, fd_[0], fd_[1]))
+            return false;
+
+        SubscribeToEvent(E_IPCINITIALIZE, HANDLER(IPCClientApp, HandleIPCInitialize));
+        ipc_->InitWorker((unsigned)id, fd_[0], fd_[1]);
+
+        return true;
+    }
+
+
+    void IPCClientApp::HandleLogMessage(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace LogMessage;
+
+        if (brokerActive_)
+        {
+
+            if (ipc_.Null())
+                return;
+
+            VariantMap logEvent;
+            logEvent[IPCWorkerLog::P_LEVEL] = eventData[P_LEVEL].GetInt();
+            logEvent[IPCWorkerLog::P_MESSAGE] = eventData[P_MESSAGE].GetString();
+            ipc_->SendEventToBroker(E_IPCWORKERLOG, logEvent);
+        }
+
+    }
+
+}

+ 57 - 0
Source/AtomicApp/IPCClientApp.h

@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include <Atomic/IPC/IPC.h>
+
+#include "AppBase.h"
+
+namespace Atomic
+{
+    
+    class IPCClientApp : public AppBase
+    {
+
+        OBJECT(IPCClientApp)
+
+    public:
+        /// Construct.
+        IPCClientApp(Context* context);
+        /// Destruct.
+        virtual ~IPCClientApp();
+
+        virtual void Setup();
+
+        bool Initialize(const Vector<String>& arguments);
+
+    private:
+
+        void HandleLogMessage(StringHash eventType, VariantMap& eventData);
+        void HandleIPCInitialize(StringHash eventType, VariantMap& eventData);
+
+        IPCHandle fd_[2];
+        WeakPtr<IPC> ipc_;
+        bool brokerActive_;
+    };
+
+}

+ 282 - 0
Source/AtomicApp/Player/IPCPlayerApp.cpp

@@ -0,0 +1,282 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <Atomic/Core/CoreEvents.h>//
+#include <Atomic/IO/IOEvents.h>
+#include <Atomic/Input/InputEvents.h>
+#include <Atomic/Graphics/Graphics.h>
+#include <Atomic/Graphics/GraphicsEvents.h>
+#include <Atomic/IPC/IPCEvents.h>
+#include <AtomicJS/Javascript/JSIPCEvents.h>
+#include "IPCPlayerAppEvents.h"
+
+#include <Atomic/Engine/Engine.h>
+#include <Atomic/IPC/IPC.h>
+#include <AtomicJS/Javascript/Javascript.h>
+#include <Atomic/UI/SystemUI/DebugHud.h>
+
+#include "IPCPlayerApp.h"
+
+namespace Atomic
+{
+
+    IPCPlayerApp::IPCPlayerApp(Context* context) :
+        PlayerApp(context),
+        subprocess_(false),
+        debugPlayer_(false),
+        brokerActive_(false)
+    {
+        fd_[0] = INVALID_IPCHANDLE_VALUE;
+        fd_[1] = INVALID_IPCHANDLE_VALUE;        
+    }
+
+    IPCPlayerApp::~IPCPlayerApp()
+    {
+
+    }
+
+    void IPCPlayerApp::Setup()
+    {
+        PlayerApp::Setup();
+
+        // This should be configurable
+        engineParameters_.InsertNew("LogLevel", LOG_DEBUG);
+
+        ipc_ = new IPC(context_);
+        context_->RegisterSubsystem(ipc_);
+    }
+
+    void IPCPlayerApp::ProcessArguments()
+    {
+        PlayerApp::ProcessArguments();
+
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+        if (!fileSystem)
+        {
+            ErrorExit("IPCPlayerApp::ProcessArguments FileSystem subsystem does not exist");
+        }
+
+        for (unsigned i = 0; i < arguments_.Size(); ++i)
+        {
+            if (arguments_[i].Length() > 1)
+            {
+                String argument = arguments_[i].ToLower();
+                String value = i + 1 < arguments_.Size() ? arguments_[i + 1] : String::EMPTY;
+
+                if (argument.StartsWith("--ipc-server=") || argument.StartsWith("--ipc-client="))
+                {
+                    subprocess_ = true;
+                }
+                else if (argument == "--debug")
+                {
+                    debugPlayer_ = true;
+                }
+                else if (argument == "--project" && value.Length())
+                {
+                    engineParameters_["ResourcePrefixPath"] = "";
+
+                    value = AddTrailingSlash(value);
+
+                    AddEngineConfigSearchPath(value + "Settings/");
+
+                    // check that cache exists
+                    if (!fileSystem->DirExists(value + "Cache"))
+                    {
+                        ErrorExit("Project cache folder does not exist, projects must be loaded into the Atomic Editor at least once before using the --player command line mode");
+                        return;
+                    }
+
+#ifdef ATOMIC_DEV_BUILD
+
+                    String resourcePaths = ToString("%s/Resources/CoreData;%s/Resources/PlayerData;%sResources;%s;%sCache",
+                        ATOMIC_ROOT_SOURCE_DIR, ATOMIC_ROOT_SOURCE_DIR, value.CString(), value.CString(), value.CString());
+
+#else
+
+#ifdef __APPLE__
+                    engineParameters_["ResourcePrefixPath"] = "../Resources";
+#else
+                    engineParameters_["ResourcePrefixPath"] = fileSystem->GetProgramDir() + "Resources";
+#endif
+
+                    String resourcePaths = ToString("CoreData;PlayerData;%s/;%s/Resources;%s;%sCache",
+                        value.CString(), value.CString(), value.CString(), value.CString());
+#endif
+
+                    LOGINFOF("Adding ResourcePaths: %s", resourcePaths.CString());
+
+                    engineParameters_["ResourcePaths"] = resourcePaths;
+
+                }
+            }
+        }
+
+        // IPC client player should not auto exit if a subprocess
+        if (subprocess_)
+            engine_->SetAutoExit(false);
+
+    }
+
+    void IPCPlayerApp::Start()
+    {
+
+        if (subprocess_)
+        {
+            // do not execute main in the player app
+            executeJSMain_ = false;
+        }
+
+        PlayerApp::Start();
+
+        int id = -1;
+
+        if (IPC::ProcessArguments(arguments_, id, fd_[0], fd_[1]))
+        {
+            SubscribeToEvent(E_IPCINITIALIZE, HANDLER(IPCPlayerApp, HandleIPCInitialize));
+            SubscribeToEvent(E_LOGMESSAGE, HANDLER(IPCPlayerApp, HandleLogMessage));
+            SubscribeToEvent(E_JSERROR, HANDLER(IPCPlayerApp, HandleJSError));
+            SubscribeToEvent(E_EXITREQUESTED, HANDLER(IPCPlayerApp, HandleExitRequest));
+            SubscribeToEvent(E_SCREENMODE, HANDLER(IPCPlayerApp, HandlePlayerWindowChanged));
+            SubscribeToEvent(E_WINDOWPOS, HANDLER(IPCPlayerApp, HandlePlayerWindowChanged));
+            SubscribeToEvent(E_UPDATESPAUSEDRESUMED, HANDLER(IPCPlayerApp, HandleUpdatesPausedResumed));
+
+            if (ipc_->InitWorker((unsigned)id, fd_[0], fd_[1]))
+            {
+                brokerActive_ = true;
+            }
+            else if (subprocess_)
+            {
+                LOGERROR("IPCPlayerApp::Start() - Unable to initialize IPC Worker");
+            }
+        }
+
+        if (subprocess_)
+        {
+            JSVM* vm = JSVM::GetJSVM(0);
+
+            if (!vm->ExecuteMain())
+            {
+                SendEvent(E_EXITREQUESTED);
+            }
+
+            SubscribeToEvent(E_PLAYERQUIT, HANDLER(IPCPlayerApp, HandleQuit));
+        }
+
+        
+
+    }
+
+    void IPCPlayerApp::HandleQuit(StringHash eventType, VariantMap& eventData)
+    {
+        engine_->Exit();
+    }
+
+    void IPCPlayerApp::Stop()
+    {
+        PlayerApp::Stop();
+    }
+
+    void IPCPlayerApp::HandleIPCInitialize(StringHash eventType, VariantMap& eventData)
+    {
+        brokerActive_ = true;
+
+        SystemUI::DebugHud* debugHud = GetSubsystem<SystemUI::DebugHud>();
+        if (debugHud)
+            debugHud->SetMode(eventData["debugHudMode"].GetUInt());
+
+    }
+
+    void IPCPlayerApp::HandleJSError(StringHash eventType, VariantMap& eventData)
+    {
+        if (brokerActive_)
+        {
+            if (ipc_.Null())
+                return;
+
+            String errName = eventData[JSError::P_ERRORNAME].GetString();
+            String errStack = eventData[JSError::P_ERRORSTACK].GetString();
+            String errMessage = eventData[JSError::P_ERRORMESSAGE].GetString();
+            String errFilename = eventData[JSError::P_ERRORFILENAME].GetString();
+            int errLineNumber = eventData[JSError::P_ERRORLINENUMBER].GetInt();
+
+            VariantMap ipcErrorData;
+            ipcErrorData[IPCJSError::P_ERRORNAME] = errName;
+            ipcErrorData[IPCJSError::P_ERRORSTACK] = errStack;
+            ipcErrorData[IPCJSError::P_ERRORMESSAGE] = errMessage;
+            ipcErrorData[IPCJSError::P_ERRORFILENAME] = errFilename;
+            ipcErrorData[IPCJSError::P_ERRORLINENUMBER] = errLineNumber;
+
+            ipc_->SendEventToBroker(E_IPCJSERROR, ipcErrorData);
+
+            LOGERROR("SENDING E_IPCJSERROR");
+
+        }
+
+    }
+
+    void IPCPlayerApp::HandlePlayerWindowChanged(StringHash eventType, VariantMap& eventData)
+    {
+        Graphics* graphics = GetSubsystem<Graphics>();
+        using namespace IPCPlayerWindowChanged;
+        VariantMap data;
+        data[P_POSX] = graphics->GetWindowPosition().x_;
+        data[P_POSY] = graphics->GetWindowPosition().y_;
+        data[P_WIDTH] = graphics->GetWidth();
+        data[P_HEIGHT] = graphics->GetHeight();
+        data[P_MONITOR] = graphics->GetCurrentMonitor();
+        data[P_MAXIMIZED] = graphics->GetMaximized();
+        ipc_->SendEventToBroker(E_IPCPLAYERWINDOWCHANGED, data);
+    }
+
+    void IPCPlayerApp::HandleUpdatesPausedResumed(StringHash eventType, VariantMap& eventData)
+    {
+        ipc_->SendEventToBroker(E_IPCPLAYERUPDATESPAUSEDRESUMED, eventData);
+    }
+
+    void IPCPlayerApp::HandleExitRequest(StringHash eventType, VariantMap& eventData)
+    {
+        UnsubscribeFromEvent(E_LOGMESSAGE);
+        SendEvent(E_PLAYERQUIT);
+    }
+
+
+    void IPCPlayerApp::HandleLogMessage(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace LogMessage;
+
+        if (brokerActive_)
+        {
+
+            if (ipc_.Null())
+                return;
+
+            VariantMap logEvent;
+            logEvent[IPCWorkerLog::P_LEVEL] = eventData[P_LEVEL].GetInt();
+            logEvent[IPCWorkerLog::P_MESSAGE] = eventData[P_MESSAGE].GetString();
+            ipc_->SendEventToBroker(E_IPCWORKERLOG, logEvent);
+        }
+
+    }
+
+}
+
+

+ 72 - 0
Source/AtomicApp/Player/IPCPlayerApp.h

@@ -0,0 +1,72 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "PlayerApp.h"
+#include <Atomic/IPC/IPC.h>
+
+namespace Atomic
+{
+    class IPC;
+
+    class IPCPlayerApp : public PlayerApp
+    {
+        OBJECT(IPCPlayerApp)
+
+    public:
+        /// Construct.
+        IPCPlayerApp(Context* context);
+        virtual ~IPCPlayerApp();
+
+        /// Setup before engine initialization. 
+        virtual void Setup();
+        /// Setup after engine initialization. L
+        virtual void Start();
+        /// Cleanup after the main loop. 
+        virtual void Stop();
+
+        virtual void ProcessArguments();
+
+    protected:
+
+    private:
+        
+        void HandleIPCInitialize(StringHash eventType, VariantMap& eventData);
+        void HandleLogMessage(StringHash eventType, VariantMap& eventData);
+        void HandleJSError(StringHash eventType, VariantMap& eventData);
+
+        void HandlePlayerWindowChanged(StringHash eventType, VariantMap& eventData);
+        void HandleUpdatesPausedResumed(StringHash eventType, VariantMap& eventData);
+        void HandleQuit(StringHash eventType, VariantMap& eventData);
+        void HandleExitRequest(StringHash eventType, VariantMap& eventData);
+
+        /// true if we're launched as a subprocess, otherwise top level process (generally for debugging)
+        bool subprocess_;
+        bool debugPlayer_;
+
+        IPCHandle fd_[2];
+        WeakPtr<IPC> ipc_;
+        bool brokerActive_;
+    };
+
+}

+ 65 - 0
Source/AtomicApp/Player/IPCPlayerAppEvents.h

@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include <Atomic/Core/Object.h>
+
+namespace Atomic
+{
+
+    EVENT(E_IPCPLAYERPAUSERESUMEREQUEST, IPCPlayerPauseResumeRequest)
+    {
+
+    }
+
+    EVENT(E_IPCPLAYERUPDATESPAUSEDRESUMED, IPCPlayerUpdatesPausedResumed)
+    {
+        PARAM(P_PAUSED, Paused);            // bool
+    }
+
+    EVENT(E_IPCPLAYERPAUSESTEPREQUEST, IPCPlayerPauseStepRequest)
+    {
+
+    }
+
+    EVENT(E_IPCPLAYEREXITREQUEST, IPCPlayerExitRequest)
+    {
+
+    }
+
+    EVENT(E_IPCPLAYERWINDOWCHANGED, IPCPlayerWindowChanged)
+    {
+        PARAM(P_POSX, PosX);
+        PARAM(P_POSY, PosY);
+        PARAM(P_WIDTH, Width);
+        PARAM(P_HEIGHT, Height);
+        PARAM(P_MONITOR, Monitor);
+        PARAM(P_MAXIMIZED, Maximized);
+    }
+
+    EVENT(E_PLAYERQUIT, PlayerQuit)
+    {
+
+    }
+
+}

+ 176 - 0
Source/AtomicApp/Player/PlayerApp.cpp

@@ -0,0 +1,176 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+
+#include <Atomic/Input/InputEvents.h>
+#include <Atomic/Engine/Engine.h>
+#include <Atomic/Graphics/Graphics.h>
+#include <Atomic/UI/UI.h>
+#include <AtomicJS/Javascript/Javascript.h>
+
+#include <AtomicPlayer/Player.h>
+
+#include "PlayerApp.h"
+
+namespace AtomicPlayer
+{
+    extern void jsapi_init_atomicplayer(JSVM* vm);
+}
+
+namespace Atomic
+{
+
+    PlayerApp::PlayerApp(Context* context) :
+        AppBase(context),
+        executeJSMain_(true)
+    {
+
+    }
+
+    PlayerApp::~PlayerApp()
+    {
+
+    }
+
+    void PlayerApp::Setup()
+    {
+        AppBase::Setup();
+
+        engineParameters_.InsertNew("WindowTitle", "AtomicPlayer");
+
+#if (ATOMIC_PLATFORM_ANDROID)
+        engineParameters_.InsertNew("FullScreen", true);
+        engineParameters_.InsertNew("ResourcePaths", "CoreData;PlayerData;Cache;AtomicResources");
+#elif ATOMIC_PLATFORM_WEB
+        engineParameters_.InsertNew("FullScreen", false);
+        engineParameters_.InsertNew("ResourcePaths", "AtomicResources");
+        // engineParameters_.InsertNew("WindowWidth", 1280);
+        // engineParameters_.InsertNew("WindowHeight", 720);
+#elif ATOMIC_PLATFORM_IOS
+        engineParameters_.InsertNew("FullScreen", false);
+        engineParameters_.InsertNew("ResourcePaths", "AtomicResources");
+#else
+        engineParameters_.InsertNew("FullScreen", false);
+        engineParameters_.InsertNew("WindowWidth", 1280);
+        engineParameters_.InsertNew("WindowHeight", 720);
+        engineParameters_.InsertNew("ResourcePaths", "AtomicResources");
+#endif
+
+#if ATOMIC_PLATFORM_WINDOWS || ATOMIC_PLATFORM_LINUX
+
+        engineParameters_.InsertNew("WindowIcon", "Images/AtomicLogo32.png");
+        engineParameters_.InsertNew("ResourcePrefixPath", "AtomicPlayer_Resources");
+
+#elif ATOMIC_PLATFORM_ANDROID
+        //engineParameters_.InsertNew("ResourcePrefixPath"], "assets");
+#elif ATOMIC_PLATFORM_OSX
+        engineParameters_.InsertNew("ResourcePrefixPath", "../Resources");
+#endif
+
+        // Setup player log
+        FileSystem *filesystem = GetSubsystem<FileSystem>();
+        engineParameters_.InsertNew("LogName", filesystem->GetAppPreferencesDir("AtomicPlayer", "Logs") + "AtomicPlayer.log");
+
+    }
+
+    void PlayerApp::Start()
+    {
+        AppBase::Start();
+
+        UI* ui = GetSubsystem<UI>();
+        ui->Initialize("DefaultUI/language/lng_en.tb.txt");
+        ui->LoadDefaultPlayerSkin();
+
+        vm_->SetModuleSearchPaths("Modules");    
+
+        // Instantiate and register the Player subsystem
+        context_->RegisterSubsystem(new AtomicPlayer::Player(context_));
+        AtomicPlayer::jsapi_init_atomicplayer(vm_);
+
+        if (executeJSMain_)
+        {
+
+            JSVM* vm = JSVM::GetJSVM(0);
+
+            if (!vm->ExecuteMain())
+            {
+                SendEvent(E_EXITREQUESTED);
+            }
+
+        }
+
+        GetSubsystem<Graphics>()->RaiseWindow();
+
+    }
+
+    void PlayerApp::Stop()
+    {
+
+        AppBase::Stop();
+
+    }
+
+    void PlayerApp::ProcessArguments()
+    {
+
+        AppBase::ProcessArguments();
+
+        for (unsigned i = 0; i < arguments_.Size(); ++i)
+        {
+            if (arguments_[i].Length() > 1)
+            {
+                String argument = arguments_[i].ToLower();
+                String value = i + 1 < arguments_.Size() ? arguments_[i + 1] : String::EMPTY;
+
+                if (argument == "--windowposx" && value.Length())
+                {
+                    engineParameters_["WindowPositionX"] = atoi(value.CString());
+                }
+                else if (argument == "--windowposy" && value.Length())
+                {
+                    engineParameters_["WindowPositionY"] = atoi(value.CString());
+                }
+                else if (argument == "--windowwidth" && value.Length())
+                {
+                    engineParameters_["WindowWidth"] = atoi(value.CString());
+                }
+                else if (argument == "--windowheight" && value.Length())
+                {
+                    engineParameters_["WindowHeight"] = atoi(value.CString());
+                }
+                else if (argument == "--resizable")
+                {
+                    engineParameters_["WindowResizable"] = true;
+                }
+                else if (argument == "--maximize")
+                {
+                    engineParameters_["WindowMaximized"] = true;
+                }
+            }
+        }
+    }
+
+
+
+}
+
+

+ 56 - 0
Source/AtomicApp/Player/PlayerApp.h

@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "../AppBase.h"
+
+namespace Atomic
+{
+
+    class PlayerApp : public AppBase
+    {
+        OBJECT(PlayerApp)
+
+    public:
+        /// Construct.
+        PlayerApp(Context* context);
+        virtual ~PlayerApp();
+
+        /// Setup before engine initialization. 
+        virtual void Setup();
+        /// Setup after engine initialization. L
+        virtual void Start();
+        /// Cleanup after the main loop. 
+        virtual void Stop();
+
+        virtual void ProcessArguments();
+
+    protected:
+
+        bool executeJSMain_;
+
+    private:
+
+    };
+
+}

+ 116 - 77
Source/AtomicEditor/Application/AEEditorApp.cpp

@@ -20,141 +20,180 @@
 // THE SOFTWARE.
 //
 
-#include <Atomic/Core/StringUtils.h>
-#include <Atomic/Engine/Engine.h>
-#include <Atomic/IO/FileSystem.h>
 #include <Atomic/Input/Input.h>
-#include <Atomic/Resource/ResourceCache.h>
-#include <Atomic/Graphics/Graphics.h>
-#include <Atomic/Atomic3D/AnimatedModel.h>
-
 #include <Atomic/UI/UI.h>
-
 #include <AtomicJS/Javascript/Javascript.h>
+#include <Atomic/IPC/IPC.h>
+
+// This can be removed once bone hack is fixed
+#include <Atomic/Atomic3D/AnimatedModel.h>
 
-#include <ToolCore/ToolEnvironment.h>
-#include <ToolCore/License/LicenseEvents.h>
 #include <ToolCore/License/LicenseSystem.h>
+#include <ToolCore/ToolSystem.h>
+#include <ToolCore/ToolEnvironment.h>
 
 #include "../EditorMode/AEEditorMode.h"
+#include "../EditorMode/AEEditorNETService.h"
+
+#include "../Components/EditorComponents.h"
 
+#include "AEEditorPrefs.h"
 #include "AEEditorApp.h"
 
 using namespace ToolCore;
 
-namespace AtomicEditor
+// Fix these externs
+namespace Atomic
 {
+    void jsapi_init_webview(JSVM* vm, const VariantMap& engineParameters);
+    extern void jsb_package_atomicnetscript_init(JSVM* vm);
+}
 
-extern void jsapi_init_editor(JSVM* vm);
-
-AEEditorApp::AEEditorApp(Context* context) :
-    AEEditorCommon(context)
+namespace ToolCore
 {
-
+    extern void jsapi_init_toolcore(JSVM* vm);
 }
 
-void AEEditorApp::Start()
-{
-    AEEditorCommon::Start();
+using namespace ToolCore;
 
-    context_->RegisterSubsystem(new EditorMode(context_));
+namespace AtomicEditor
+{
 
-    vm_->SetModuleSearchPaths("AtomicEditor/JavaScript;AtomicEditor/EditorScripts;AtomicEditor/EditorScripts/AtomicEditor");
+    extern void jsapi_init_editor(JSVM* vm);
 
-    // Do not create bone structure by default when in the editor
-    // this can be toggled temporarily, for example to setup an animation preview
-    AnimatedModel::SetBoneCreationEnabled(false);
+    AEEditorApp::AEEditorApp(Context* context) :
+        AppBase(context)
+    {
 
-    // move UI initialization to JS
-    UI* ui = GetSubsystem<UI>();
-    ui->Initialize("AtomicEditor/resources/language/lng_en.tb.txt");
+    }
 
-    SubscribeToEvent(E_JSERROR, HANDLER(AEEditorApp, HandleJSError));
+    AEEditorApp::~AEEditorApp()
+    {
 
-    jsapi_init_editor(vm_);
+    }
 
-    duk_get_global_string(vm_->GetJSContext(), "require");
-    duk_push_string(vm_->GetJSContext(), "main");
-    if (duk_pcall(vm_->GetJSContext(), 1) != 0)
+    void AEEditorApp::Setup()
     {
-        vm_->SendJSErrorEvent();
-        ErrorExit("Error executing main.js");
-    }
+        context_->RegisterSubsystem(new AEEditorPrefs(context_));
 
-    GetSubsystem<LicenseSystem>()->Initialize();
+        context_->SetEditorContext(true);
 
-}
+        AppBase::Setup();
 
-void AEEditorApp::Setup()
-{
-    context_->SetEditorContext(true);
+        RegisterEditorComponentLibrary(context_);
+
+        // Register IPC system
+        context_->RegisterSubsystem(new IPC(context_));
 
-    AEEditorCommon::Setup();
+        ToolEnvironment* env = new ToolEnvironment(context_);
+        context_->RegisterSubsystem(env);
 
-    // Ensure exclusive fullscreen is disabled in Editor application
-    Input* input = GetSubsystem<Input>();
-    input->SetToggleFullscreen(false);
+#ifdef ATOMIC_DEV_BUILD
+
+        if (!env->InitFromJSON())
+        {
+            ErrorExit(ToString("Unable to initialize tool environment from %s", env->GetDevConfigFilename().CString()));
+            return;
+        }
+#else
 
+        env->InitFromPackage();
 
-    ToolEnvironment* env = GetSubsystem<ToolEnvironment>();
+#endif
+
+        ToolSystem* system = new ToolSystem(context_);
+        context_->RegisterSubsystem(system);
 
-    engineParameters_["WindowTitle"] = "AtomicEditor";
-    engineParameters_["WindowResizable"] = true;
-    engineParameters_["FullScreen"] = false;
-    engineParameters_["LogLevel"] = LOG_DEBUG;
+        engineParameters_["WindowTitle"] = "AtomicEditor";
+        engineParameters_["WindowResizable"] = true;
+        engineParameters_["FullScreen"] = false;
+        engineParameters_["LogLevel"] = LOG_DEBUG;
 
-    FileSystem* filesystem = GetSubsystem<FileSystem>();
-    engineParameters_["LogName"] = filesystem->GetAppPreferencesDir("AtomicEditor", "Logs") + "AtomicEditor.log";
+        FileSystem* filesystem = GetSubsystem<FileSystem>();
+        engineParameters_["LogName"] = filesystem->GetAppPreferencesDir("AtomicEditor", "Logs") + "AtomicEditor.log";
 
 #ifdef ATOMIC_PLATFORM_OSX
-    engineParameters_["WindowIcon"] = "Images/AtomicLogo32.png";
+        engineParameters_["WindowIcon"] = "Images/AtomicLogo32.png";
 #endif
 
 #ifdef ATOMIC_DEV_BUILD
-    engineParameters_["ResourcePrefixPath"] = "";
-    String resourcePaths = env->GetCoreDataDir() + ";" + env->GetEditorDataDir();
-    // for dev builds, add the compile editor scripts from artifacts
-    resourcePaths += ";" + env->GetRootSourceDir() + "Artifacts/Build/Resources/EditorData/";
-    engineParameters_["ResourcePaths"] = resourcePaths;
+        engineParameters_["ResourcePrefixPath"] = "";
+        String resourcePaths = env->GetCoreDataDir() + ";" + env->GetEditorDataDir();
+        // for dev builds, add the compile editor scripts from artifacts
+        resourcePaths += ";" + env->GetRootSourceDir() + "Artifacts/Build/Resources/EditorData/";
+        engineParameters_["ResourcePaths"] = resourcePaths;
 #else
 
 #ifdef ATOMIC_PLATFORM_OSX
-    engineParameters_["ResourcePrefixPath"] = "../Resources";
+        engineParameters_["ResourcePrefixPath"] = "../Resources";
 
 #else
-    engineParameters_["ResourcePrefixPath"] = filesystem->GetProgramDir() + "Resources";
+        engineParameters_["ResourcePrefixPath"] = filesystem->GetProgramDir() + "Resources";
 #endif
 
-    engineParameters_["ResourcePaths"] = "CoreData;EditorData";
+        engineParameters_["ResourcePaths"] = "CoreData;EditorData";
 
 #endif // ATOMIC_DEV_BUILD
 
-    ReadPreferences();
+        GetSubsystem<AEEditorPrefs>()->ReadPreferences(engineParameters_);
+    }
+
+    void AEEditorApp::Start()
+    {
+        // Do not create bone structure by default when in the editor
+        // this can be toggled temporarily, for example to setup an animation preview
+        AnimatedModel::SetBoneCreationEnabled(false);
 
-}
+        AppBase::Start();
 
-void AEEditorApp::Stop()
-{
-    AEEditorCommon::Stop();
-}
+        GetSubsystem<AEEditorPrefs>()->ValidateWindow();
 
-void AEEditorApp::HandleJSError(StringHash eventType, VariantMap& eventData)
-{
-    using namespace JSError;
-    //String errName = eventData[P_ERRORNAME].GetString();
-    String errMessage = eventData[P_ERRORMESSAGE].GetString();
-    String errFilename = eventData[P_ERRORFILENAME].GetString();
-    //String errStack = eventData[P_ERRORSTACK].GetString();
-    int errLineNumber = vm_->GetRealLineNumber(errFilename, eventData[P_ERRORLINENUMBER].GetInt());
+        jsapi_init_toolcore(vm_);
 
-    String errorString = ToString("%s - %s - Line: %i", errFilename.CString(), errMessage.CString(), errLineNumber);
+#ifdef ATOMIC_WEBVIEW
+        // Initialize in Start so window already exists    
+        jsapi_init_webview(vm_, engineParameters_);
+#endif
 
+        context_->RegisterSubsystem(new EditorMode(context_));
+        context_->RegisterSubsystem(new EditorNETService(context_));
 
-    ErrorExit(errorString);
+        vm_->SetModuleSearchPaths("AtomicEditor/JavaScript;AtomicEditor/EditorScripts;AtomicEditor/EditorScripts/AtomicEditor");
 
-}
+        // move UI initialization to JS
+        UI* ui = GetSubsystem<UI>();
+        ui->Initialize("AtomicEditor/resources/language/lng_en.tb.txt");
+
+        jsapi_init_editor(vm_);
+        jsb_package_atomicnetscript_init(vm_);
+
+        duk_get_global_string(vm_->GetJSContext(), "require");
+        duk_push_string(vm_->GetJSContext(), "main");
+        if (duk_pcall(vm_->GetJSContext(), 1) != 0)
+        {
+            vm_->SendJSErrorEvent();
+            ErrorExit("Error executing main.js");
+        }
+
+        GetSubsystem<LicenseSystem>()->Initialize();
+
+        Input* input = GetSubsystem<Input>();
+        // Ensure exclusive fullscreen is disabled in Editor application
+        input->SetToggleFullscreen(false);
+        input->SetMouseVisible(true);
 
+    }
+
+    void AEEditorApp::Stop()
+    {
+        context_->RemoveSubsystem<IPC>();
 
+        AppBase::Stop();
+    }
 
+    void AEEditorApp::ProcessArguments()
+    {
+        AppBase::ProcessArguments();
+    }
 
 }

+ 18 - 23
Source/AtomicEditor/Application/AEEditorApp.h

@@ -22,39 +22,34 @@
 
 #pragma once
 
-#include "AEEditorCommon.h"
+#include <AtomicApp/AppBase.h>
 
 using namespace Atomic;
 
-namespace Atomic
-{
-    class JSVM;
-}
-
 namespace AtomicEditor
 {
+    class AEEditorApp : public AppBase
+    {
+        OBJECT(AEEditorApp)
 
-class AEEditorApp : public AEEditorCommon
-{
-    OBJECT(AEEditorApp);
-
-public:
-    /// Construct.
-    AEEditorApp(Context* context);
+    public:
+        /// Construct.
+        AEEditorApp(Context* context);
+        virtual ~AEEditorApp();
 
-    /// Setup before engine initialization. Verify that a script file has been specified.
-    virtual void Setup();
-    /// Setup after engine initialization. Load the script and execute its start function.
-    virtual void Start();
-    /// Cleanup after the main loop. Run the script's stop function if it exists.
-    virtual void Stop();
+        /// Setup before engine initialization. 
+        virtual void Setup();
+        /// Setup after engine initialization. L
+        virtual void Start();
+        /// Cleanup after the main loop. 
+        virtual void Stop();
 
-private:
+        virtual void ProcessArguments();
 
-    void HandleExitRequested(StringHash eventType, VariantMap& eventData);
-    void HandleJSError(StringHash eventType, VariantMap& eventData);
+    protected:
 
+    private:
 
-};
+    };
 
 }

+ 0 - 307
Source/AtomicEditor/Application/AEEditorCommon.cpp

@@ -1,307 +0,0 @@
-//
-// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#include <Atomic/Engine/Engine.h>
-#include <Atomic/Input/Input.h>
-#include <Atomic/Graphics/Graphics.h>
-
-#include <Atomic/IPC/IPC.h>
-
-// Move me to Engine
-#include <Atomic/Environment/Environment.h>
-
-#include <Atomic/Script/ScriptSystem.h>
-#include <AtomicJS/Javascript/Javascript.h>
-
-#include <ToolCore/ToolSystem.h>
-#include <ToolCore/ToolEnvironment.h>
-
-#include <Atomic/IO/File.h>
-
-#ifdef ATOMIC_WEBVIEW
-#include <AtomicWebView/WebBrowserHost.h>
-#endif
-
-#include "../Components/EditorComponents.h"
-
-#include "AEEditorCommon.h"
-
-namespace Atomic
-{
-    void jsapi_init_webview(JSVM* vm, const VariantMap& engineParameters);
-}
-
-using namespace ToolCore;
-
-namespace ToolCore
-{
-    extern void jsapi_init_toolcore(JSVM* vm);
-}
-
-
-namespace AtomicEditor
-{
-
-AEEditorCommon::AEEditorCommon(Context* context) :
-    Application(context)
-{
-
-}
-
-void AEEditorCommon::Start()
-{
-    ValidateWindow();
-
-    Input* input = GetSubsystem<Input>();
-    input->SetMouseVisible(true);
-
-    Javascript* javascript = GetSubsystem<Javascript>();
-    vm_ = javascript->InstantiateVM("MainVM");
-    vm_->InitJSContext();
-
-    jsapi_init_toolcore(vm_);
-
-#ifdef ATOMIC_WEBVIEW
-    // Initialize in Start so window already exists    
-    jsapi_init_webview(vm_, engineParameters_);
-#endif
-
-}
-
-void AEEditorCommon::Setup()
-{
-
-#ifdef ATOMIC_3D
-    RegisterEnvironmentLibrary(context_);
-#endif
-
-    RegisterEditorComponentLibrary(context_);
-
-    // Register IPC system
-    context_->RegisterSubsystem(new IPC(context_));
-
-    context_->RegisterSubsystem(new ScriptSystem(context_));
-
-    // Instantiate and register the Javascript subsystem
-    Javascript* javascript = new Javascript(context_);
-    context_->RegisterSubsystem(javascript);
-
-    ToolEnvironment* env = new ToolEnvironment(context_);
-    context_->RegisterSubsystem(env);
-
-#ifdef ATOMIC_DEV_BUILD
-
-    if (!env->InitFromJSON())
-    {
-        ErrorExit(ToString("Unable to initialize tool environment from %s", env->GetDevConfigFilename().CString()));
-        return;
-    }
-#else
-
-    env->InitFromPackage();
-
-#endif
-
-    ToolSystem* system = new ToolSystem(context_);
-    context_->RegisterSubsystem(system);
-
-}
-
-void AEEditorCommon::Stop()
-{
-
-    context_->RemoveSubsystem<IPC>();
-
-    vm_ = 0;
-    context_->RemoveSubsystem<Javascript>();
-    // make sure JSVM is really down and no outstanding refs
-    // as if not, will hold on engine subsystems, which is bad
-    assert(!JSVM::GetJSVM(0));
-
-}
-
-bool AEEditorCommon::CreateDefaultPreferences(String& path, JSONValue& prefs)
-{
-    // Note there is some duplication here with the editor's
-    // TypeScript preference code, this is due to the preferences for
-    // the editor window needing to be available at window creation time
-    // It could be better to split this all out to a native, scriptable
-    // preferences object
-
-    LOGINFOF("Creating default Atomic Editor preferences: %s", path.CString());
-
-    SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
-
-    JSONValue& root = jsonFile->GetRoot();
-
-    root.Clear();
-    root["recentProjects"] = JSONArray();
-
-    JSONValue editorWindow;
-    GetDefaultWindowPreferences(editorWindow, true);
-
-    JSONValue playerWindow;
-    GetDefaultWindowPreferences(playerWindow, false);
-
-    root["editorWindow"] = editorWindow;
-    root["playerWindow"] = playerWindow;
-
-    prefs = root;
-
-    SavePreferences(prefs);
-
-    return true;
-}
-
-bool AEEditorCommon::ReadPreferences()
-{
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
-    String path = GetPreferencesPath();
-
-    JSONValue prefs;
-
-    LoadPreferences(prefs);
-
-    if (!prefs.IsObject() || !prefs["editorWindow"].IsObject())
-    {
-        if (!CreateDefaultPreferences(path, prefs))
-            return false;
-    }
-
-    JSONValue& editorWindow = prefs["editorWindow"];
-
-    engineParameters_["WindowPositionX"] = editorWindow["x"].GetUInt();
-    engineParameters_["WindowPositionY"] = editorWindow["y"].GetUInt();
-    engineParameters_["WindowWidth"] = editorWindow["width"].GetUInt();
-    engineParameters_["WindowHeight"] = editorWindow["height"].GetUInt();
-    engineParameters_["WindowMaximized"] = editorWindow["maximized"].GetBool();
-
-    return true;
-}
-
-void AEEditorCommon::ValidateWindow()
-{
-    Graphics* graphics = GetSubsystem<Graphics>();
-    IntVector2 windowPosition = graphics->GetWindowPosition();
-    int monitors = graphics->GetNumMonitors();
-    IntVector2 maxResolution;
-
-    for (int i = 0; i < monitors; i++)
-    {
-        IntVector2 monitorResolution = graphics->GetMonitorResolution(i);
-        maxResolution += monitorResolution;
-    }
-
-    if (windowPosition.x_ >= maxResolution.x_ || windowPosition.y_ >= maxResolution.y_ || (windowPosition.x_ + graphics->GetWidth()) < 0 || (windowPosition.y_ + graphics->GetHeight()) < 0)
-    {
-        JSONValue prefs;
-
-        if (!LoadPreferences(prefs))
-            return;
-
-        bool editor = context_->GetEditorContext();
-
-        JSONValue window;
-        GetDefaultWindowPreferences(window, editor);
-
-        prefs[editor ? "editorWindow" : "playerWindow"] = window;
-
-        //Setting the mode to 0 width/height will use engine defaults for window size and layout
-        graphics->SetMode(0, 0, graphics->GetFullscreen(), graphics->GetBorderless(), graphics->GetResizable(), graphics->GetVSync(), graphics->GetTripleBuffer(), graphics->GetMultiSample(), editor);
-
-        SavePreferences(prefs);
-    }
-}
-
-void AEEditorCommon::GetDefaultWindowPreferences(JSONValue& windowPrefs, bool maximized)
-{
-    windowPrefs["x"] = 0;
-    windowPrefs["y"] = 0;
-    windowPrefs["width"] = 0;
-    windowPrefs["height"] = 0;
-    windowPrefs["monitor"] = 0;
-    windowPrefs["maximized"] = maximized;
-}
-
-String AEEditorCommon::GetPreferencesPath()
-{
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
-    String path = fileSystem->GetAppPreferencesDir("AtomicEditor", "Preferences");
-    path += "prefs.json";
-    return path;
-}
-
-bool AEEditorCommon::LoadPreferences(JSONValue& prefs)
-{
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
-    String path = GetPreferencesPath();
-
-    if (!fileSystem->FileExists(path))
-    {
-        if (!CreateDefaultPreferences(path, prefs))
-            return false;
-    }
-    else
-    {
-        SharedPtr<File> file(new File(context_, path, FILE_READ));
-        SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
-
-        if (!jsonFile->BeginLoad(*file))
-        {
-            file->Close();
-            if (!CreateDefaultPreferences(path, prefs))
-                return false;
-        }
-        else
-        {
-            prefs = jsonFile->GetRoot();
-        }
-
-        file->Close();
-    }
-
-    return true;
-}
-
-bool AEEditorCommon::SavePreferences(JSONValue& prefs)
-{
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
-    String path = GetPreferencesPath();
-
-    SharedPtr<File> file(new File(context_, path, FILE_WRITE));
-    SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
-
-    jsonFile->GetRoot() = prefs;
-
-    if (!file->IsOpen())
-    {
-        LOGERRORF("Unable to open Atomic Editor preferences for writing: %s", path.CString());
-        return false;
-    }
-
-    jsonFile->Save(*file, "   ");
-    file->Close();
-
-    return true;
-}
-
-}

+ 210 - 0
Source/AtomicEditor/Application/AEEditorPrefs.cpp

@@ -0,0 +1,210 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <Atomic/Core/Context.h>
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/File.h>
+#include <Atomic/IO/FileSystem.h>
+#include <Atomic/Graphics/Graphics.h>
+
+#include "AEEditorPrefs.h"
+
+namespace AtomicEditor
+{
+
+    AEEditorPrefs::AEEditorPrefs(Context* context) :
+        Object(context)
+    {
+
+    }
+
+    AEEditorPrefs::~AEEditorPrefs()
+    {
+
+    }
+
+    bool AEEditorPrefs::CreateDefaultPreferences(String& path, JSONValue& prefs)
+    {
+        // Note there is some duplication here with the editor's
+        // TypeScript preference code, this is due to the preferences for
+        // the editor window needing to be available at window creation time
+        // It could be better to split this all out to a native, scriptable
+        // preferences object
+
+        LOGINFOF("Creating default Atomic Editor preferences: %s", path.CString());
+
+        SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
+
+        JSONValue& root = jsonFile->GetRoot();
+
+        root.Clear();
+        root["recentProjects"] = JSONArray();
+
+        JSONValue editorWindow;
+        GetDefaultWindowPreferences(editorWindow, true);
+
+        JSONValue playerWindow;
+        GetDefaultWindowPreferences(playerWindow, false);
+
+        root["editorWindow"] = editorWindow;
+        root["playerWindow"] = playerWindow;
+
+        prefs = root;
+
+        SavePreferences(prefs);
+
+        return true;
+    }
+
+    bool AEEditorPrefs::ReadPreferences(VariantMap& engineParameters)
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        String path = GetPreferencesPath();
+
+        JSONValue prefs;
+
+        LoadPreferences(prefs);
+
+        if (!prefs.IsObject() || !prefs["editorWindow"].IsObject())
+        {
+            if (!CreateDefaultPreferences(path, prefs))
+                return false;
+        }
+
+        JSONValue& editorWindow = prefs["editorWindow"];
+
+        engineParameters["WindowPositionX"] = editorWindow["x"].GetUInt();
+        engineParameters["WindowPositionY"] = editorWindow["y"].GetUInt();
+        engineParameters["WindowWidth"] = editorWindow["width"].GetUInt();
+        engineParameters["WindowHeight"] = editorWindow["height"].GetUInt();
+        engineParameters["WindowMaximized"] = editorWindow["maximized"].GetBool();
+
+        return true;
+    }
+
+    void AEEditorPrefs::ValidateWindow()
+    {
+        Graphics* graphics = GetSubsystem<Graphics>();
+        IntVector2 windowPosition = graphics->GetWindowPosition();
+        int monitors = graphics->GetNumMonitors();
+        IntVector2 maxResolution;
+
+        for (int i = 0; i < monitors; i++)
+        {
+            IntVector2 monitorResolution = graphics->GetMonitorResolution(i);
+            maxResolution += monitorResolution;
+        }
+
+        if (windowPosition.x_ >= maxResolution.x_ || windowPosition.y_ >= maxResolution.y_ || (windowPosition.x_ + graphics->GetWidth()) < 0 || (windowPosition.y_ + graphics->GetHeight()) < 0)
+        {
+            JSONValue prefs;
+
+            if (!LoadPreferences(prefs))
+                return;
+
+            bool editor = context_->GetEditorContext();
+
+            JSONValue window;
+            GetDefaultWindowPreferences(window, editor);
+
+            prefs[editor ? "editorWindow" : "playerWindow"] = window;
+
+            //Setting the mode to 0 width/height will use engine defaults for window size and layout
+            graphics->SetMode(0, 0, graphics->GetFullscreen(), graphics->GetBorderless(), graphics->GetResizable(), graphics->GetVSync(), graphics->GetTripleBuffer(), graphics->GetMultiSample(), editor);
+
+            SavePreferences(prefs);
+        }
+    }
+
+    void AEEditorPrefs::GetDefaultWindowPreferences(JSONValue& windowPrefs, bool maximized)
+    {
+        windowPrefs["x"] = 0;
+        windowPrefs["y"] = 0;
+        windowPrefs["width"] = 0;
+        windowPrefs["height"] = 0;
+        windowPrefs["monitor"] = 0;
+        windowPrefs["maximized"] = maximized;
+    }
+
+    String AEEditorPrefs::GetPreferencesPath()
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        String path = fileSystem->GetAppPreferencesDir("AtomicEditor", "Preferences");
+        path += "prefs.json";
+        return path;
+    }
+
+    bool AEEditorPrefs::LoadPreferences(JSONValue& prefs)
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        String path = GetPreferencesPath();
+
+        if (!fileSystem->FileExists(path))
+        {
+            if (!CreateDefaultPreferences(path, prefs))
+                return false;
+        }
+        else
+        {
+            SharedPtr<File> file(new File(context_, path, FILE_READ));
+            SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
+
+            if (!jsonFile->BeginLoad(*file))
+            {
+                file->Close();
+                if (!CreateDefaultPreferences(path, prefs))
+                    return false;
+            }
+            else
+            {
+                prefs = jsonFile->GetRoot();
+            }
+
+            file->Close();
+        }
+
+        return true;
+    }
+
+    bool AEEditorPrefs::SavePreferences(JSONValue& prefs)
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        String path = GetPreferencesPath();
+
+        SharedPtr<File> file(new File(context_, path, FILE_WRITE));
+        SharedPtr<JSONFile> jsonFile(new JSONFile(context_));
+
+        jsonFile->GetRoot() = prefs;
+
+        if (!file->IsOpen())
+        {
+            LOGERRORF("Unable to open Atomic Editor preferences for writing: %s", path.CString());
+            return false;
+        }
+
+        jsonFile->Save(*file, "   ");
+        file->Close();
+
+        return true;
+    }
+
+}

+ 19 - 35
Source/AtomicEditor/Application/AEEditorCommon.h → Source/AtomicEditor/Application/AEEditorPrefs.h

@@ -22,47 +22,31 @@
 
 #pragma once
 
-#include <Atomic/Engine/Application.h>
 #include <Atomic/Resource/JSONFile.h>
 
 using namespace Atomic;
 
-namespace Atomic
-{
-    class JSVM;
-}
-
 namespace AtomicEditor
 {
 
-class AEEditorCommon : public Application
-{
-    OBJECT(AEEditorCommon);
-
-public:
-    /// Construct.
-    AEEditorCommon(Context* context);
-
-    /// Setup before engine initialization. Verify that a script file has been specified.
-    virtual void Setup();
-    /// Setup after engine initialization. Load the script and execute its start function.
-    virtual void Start();
-    /// Cleanup after the main loop. Run the script's stop function if it exists.
-    virtual void Stop();
-
-protected:
-
-    bool CreateDefaultPreferences(String& path, JSONValue& prefs);
-    bool ReadPreferences();
-    void ValidateWindow();
-
-    SharedPtr<JSVM> vm_;
-
-private:
-    void GetDefaultWindowPreferences(JSONValue& windowPrefs, bool maximized);
-    String GetPreferencesPath();
-    bool LoadPreferences(JSONValue& prefs);
-    bool SavePreferences(JSONValue& prefs);
-};
+    class AEEditorPrefs : public Object
+    {
+        OBJECT(AEEditorPrefs)
+
+    public:
+        /// Construct.
+        AEEditorPrefs(Context* context);
+        virtual ~AEEditorPrefs();
+        
+        bool ReadPreferences(VariantMap& engineParameters);
+        void ValidateWindow();
+
+        bool CreateDefaultPreferences(String& path, JSONValue& prefs);
+        void GetDefaultWindowPreferences(JSONValue& windowPrefs, bool maximized);
+
+        String GetPreferencesPath();
+        bool LoadPreferences(JSONValue& prefs);
+        bool SavePreferences(JSONValue& prefs);
+    };
 
 }

+ 22 - 292
Source/AtomicEditor/Application/AEPlayerApp.cpp

@@ -20,326 +20,56 @@
 // THE SOFTWARE.
 //
 
-#include <Atomic/Atomic.h>
-#include <Atomic/Engine/Engine.h>
-#include <Atomic/Engine/EngineConfig.h>
-#include <Atomic/IO/FileSystem.h>
-#include <Atomic/IO/Log.h>
-#include <Atomic/IO/IOEvents.h>
-#include <Atomic/Input/InputEvents.h>
-#include <Atomic/Core/Main.h>
-#include <Atomic/Core/ProcessUtils.h>
-#include <Atomic/Resource/ResourceCache.h>
-#include <Atomic/Resource/ResourceEvents.h>
-#include <Atomic/UI/UI.h>
-
-// Move me
-#include <Atomic/Environment/Environment.h>
-
-#include <AtomicJS/Javascript/Javascript.h>
-
-#include "../PlayerMode/AEPlayerMode.h"
-#include <AtomicPlayer/Player.h>
-
-#include "../PlayerMode/AEPlayerEvents.h"
-
+#include "AEEditorPrefs.h"
 #include "AEPlayerApp.h"
 
-#include <Atomic/DebugNew.h>
-
-#ifdef __APPLE__
-#include <unistd.h>
-#endif
-
-namespace AtomicPlayer
+namespace Atomic
 {
-    extern void jsapi_init_atomicplayer(JSVM* vm);
+    void jsapi_init_webview(JSVM* vm, const VariantMap& engineParameters);
 }
 
 namespace AtomicEditor
 {
-
-AEPlayerApplication::AEPlayerApplication(Context* context) :
-    AEEditorCommon(context),
-    debugPlayer_(false),
-    launchedByEditor_(false)
-{
-}
-
-void AEPlayerApplication::Setup()
-{
-    AEEditorCommon::Setup();
-
-    // Read the project engine configuration
-    ReadEngineConfig();
-
-    engine_->SetAutoExit(false);
-
-    engineParameters_.InsertNew("WindowTitle", "AtomicPlayer");
-
-    // Set defaults not already set from config
-#if (ATOMIC_PLATFORM_ANDROID)
-    engineParameters_.InsertNew("FullScreen", true);
-    engineParameters_.InsertNew("ResourcePaths", "CoreData;AtomicResources");
-#elif ATOMIC_PLATFORM_WEB
-    engineParameters_.InsertNew("FullScreen", false);
-    engineParameters_.InsertNew("ResourcePaths", "AtomicResources");
-    // engineParameters_.InsertNew("WindowWidth", 1280);
-    // engineParameters_.InsertNew("WindowHeight", 720);
-#elif ATOMIC_PLATFORM_IOS
-    engineParameters_.InsertNew("FullScreen", false);
-    engineParameters_.InsertNew("ResourcePaths", "AtomicResources)";
-#else
-    engineParameters_.InsertNew("FullScreen", false);
-    engineParameters_.InsertNew("WindowWidth", 1280);
-    engineParameters_.InsertNew("WindowHeight", 720);
-#endif
-
-    engineParameters_.InsertNew("LogLevel", LOG_DEBUG);
-
-#if ATOMIC_PLATFORM_WINDOWS || ATOMIC_PLATFORM_LINUX
-    engineParameters_.InsertNew("WindowIcon", "Images/AtomicLogo32.png");
-    engineParameters_.InsertNew("ResourcePrefixPath", "AtomicPlayer_Resources");
-#elif ATOMIC_PLATFORM_ANDROID
-    //engineParameters_.InsertNew("ResourcePrefixPath", "assets");
-#elif ATOMIC_PLATFORM_OSX
-    engineParameters_.InsertNew("ResourcePrefixPath", "../Resources");
-#endif
-
-    // Read command line arguments, potentially overwriting project settings
-    ReadCommandLineArguments();
-
-    // Re-apply project settings if running from editor play button
-    if (launchedByEditor_)
+    AEPlayerApplication::AEPlayerApplication(Context* context) :
+        IPCPlayerApp(context)
     {
-        EngineConfig::ApplyConfig(engineParameters_, true);
-    }
-
-    // Use the script file name as the base name for the log file
-    engineParameters_["LogName"] = GetSubsystem<FileSystem>()->GetAppPreferencesDir("AtomicPlayer", "Logs") + "AtomicPlayer.log";
-}
-
-void AEPlayerApplication::ReadEngineConfig()
-{
-    // find the project path from the command line args
 
-    String projectPath;
-    const Vector<String>& arguments = GetArguments();
+    }
 
-    for (unsigned i = 0; i < arguments.Size(); ++i)
+    AEPlayerApplication::~AEPlayerApplication()
     {
-        if (arguments[i].Length() > 1)
-        {
-            String argument = arguments[i].ToLower();
-            String value = i + 1 < arguments.Size() ? arguments[i + 1] : String::EMPTY;
-
-            if (argument == "--project" && value.Length())
-            {
-                projectPath = AddTrailingSlash(value);
-                break;
-            }
 
-        }
     }
 
-    if (!projectPath.Length())
-        return;
-
-    String filename = projectPath + "Settings/Engine.json";
-
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
-    if (!fileSystem->FileExists(filename))
-        return;
-
-    if (EngineConfig::LoadFromFile(context_, filename))
+    void AEPlayerApplication::Setup()
     {
-        EngineConfig::ApplyConfig(engineParameters_);
-    }
-
-}
+        IPCPlayerApp::Setup();
 
-void AEPlayerApplication::ReadCommandLineArguments()
-{
-    const Vector<String>& arguments = GetArguments();
-    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        AEEditorPrefs* prefs = new AEEditorPrefs(context_);
+        context_->RegisterSubsystem(prefs);
+    }
 
-    for (unsigned i = 0; i < arguments.Size(); ++i)
+    void AEPlayerApplication::Start()
     {
-        if (arguments[i].Length() > 1)
-        {
-            String argument = arguments[i].ToLower();
-            String value = i + 1 < arguments.Size() ? arguments[i + 1] : String::EMPTY;
-
-            if (argument == "--log-std")
-            {
-                SubscribeToEvent(E_LOGMESSAGE, HANDLER(AEPlayerApplication, HandleLogMessage));
-            }
-            else if (argument.StartsWith("--ipc-server=") || argument.StartsWith("--ipc-client="))
-            {
-                // If we have IPC server/client we're being launched from the Editor
-                // TODO: Unify this with AEPlayerMode handling
-                launchedByEditor_ = true;
-            }
-            else if (argument == "--debug")
-            {
-                debugPlayer_ = true;
-            }
-            else if (argument == "--project" && value.Length())
-            {
-                engineParameters_["ResourcePrefixPath"] = "";
-
-                value = AddTrailingSlash(value);
-
-                // check that cache exists
-                if (!fileSystem->DirExists(value + "Cache"))
-                {
-                    ErrorExit("Project cache folder does not exist, projects must be loaded into the Atomic Editor at least once before using the --player command line mode");
-                    return;
-                }
-
-#ifdef ATOMIC_DEV_BUILD
-
-                String resourcePaths = ToString("%s/Resources/CoreData;%s/Resources/PlayerData;%sResources;%s;%sCache",
-                    ATOMIC_ROOT_SOURCE_DIR, ATOMIC_ROOT_SOURCE_DIR, value.CString(), value.CString(), value.CString());
+        IPCPlayerApp::Start();
 
-#else
+        GetSubsystem<AEEditorPrefs>()->ValidateWindow();
 
-#ifdef __APPLE__
-                engineParameters_["ResourcePrefixPath"] = "../Resources";
-#else
-                engineParameters_["ResourcePrefixPath"] = fileSystem->GetProgramDir() + "Resources";
+#ifdef ATOMIC_WEBVIEW
+        // Initialize in Start so window already exists    
+        jsapi_init_webview(vm_, engineParameters_);
 #endif
 
-                String resourcePaths = ToString("CoreData;PlayerData;%s/;%s/Resources;%s;%sCache",
-                    value.CString(), value.CString(), value.CString(), value.CString());
-#endif
-
-                LOGINFOF("Adding ResourcePaths: %s", resourcePaths.CString());
-
-                engineParameters_["ResourcePaths"] = resourcePaths;
-
-            }
-            else if (argument == "--windowposx" && value.Length())
-            {
-                engineParameters_["WindowPositionX"] = atoi(value.CString());
-            }
-            else if (argument == "--windowposy" && value.Length())
-            {
-                engineParameters_["WindowPositionY"] = atoi(value.CString());
-            }
-            else if (argument == "--windowwidth" && value.Length())
-            {
-                engineParameters_["WindowWidth"] = atoi(value.CString());
-            }
-            else if (argument == "--windowheight" && value.Length())
-            {
-                engineParameters_["WindowHeight"] = atoi(value.CString());
-            }
-            else if (argument == "--resizable")
-            {
-                engineParameters_["WindowResizable"] = true;
-            }
-            else if (argument == "--maximize")
-            {
-                engineParameters_["WindowMaximized"] = true;
-            }
-        }
     }
-}
-
-void AEPlayerApplication::Start()
-{
-    AEEditorCommon::Start();
-
-    UI* ui = GetSubsystem<UI>();
-    ui->Initialize("DefaultUI/language/lng_en.tb.txt");
-    ui->LoadDefaultPlayerSkin();
-
-    context_->RegisterSubsystem(new PlayerMode(context_));
-    PlayerMode* playerMode = GetSubsystem<PlayerMode>();
-    playerMode->ProcessArguments();
-
-    SubscribeToEvent(E_JSERROR, HANDLER(AEPlayerApplication, HandleJSError));
-
-    vm_->SetModuleSearchPaths("Modules");
 
-    // Instantiate and register the Player subsystem
-    context_->RegisterSubsystem(new AtomicPlayer::Player(context_));
-    AtomicPlayer::jsapi_init_atomicplayer(vm_);
-
-    if (!playerMode->launchedByEditor())
+    void AEPlayerApplication::Stop()
     {
-        JSVM* vm = JSVM::GetJSVM(0);
-
-        if (!vm->ExecuteMain())
-        {
-            SendEvent(E_EXITREQUESTED);
-        }
+        IPCPlayerApp::Stop();
     }
 
-    SubscribeToEvent(E_PLAYERQUIT, HANDLER(AEPlayerApplication, HandleQuit));
-
-    return;
-}
-
-void AEPlayerApplication::HandleQuit(StringHash eventType, VariantMap& eventData)
-{
-    engine_->Exit();
-}
-
-void AEPlayerApplication::Stop()
-{
-    AEEditorCommon::Stop();
-}
-
-void AEPlayerApplication::HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData)
-{
-}
-
-void AEPlayerApplication::HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData)
-{
-}
-
-void AEPlayerApplication::HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData)
-{
-    ErrorExit();
-}
-
-void AEPlayerApplication::HandleLogMessage(StringHash eventType, VariantMap& eventData)
-{
-    using namespace LogMessage;
-
-    int level = eventData[P_LEVEL].GetInt();
-    // The message may be multi-line, so split to rows in that case
-    Vector<String> rows = eventData[P_MESSAGE].GetString().Split('\n');
-
-    for (unsigned i = 0; i < rows.Size(); ++i)
+    void AEPlayerApplication::ProcessArguments()
     {
-        if (level == LOG_ERROR)
-        {
-            fprintf(stderr, "%s\n", rows[i].CString());
-        }
-        else
-        {
-            fprintf(stdout, "%s\n", rows[i].CString());
-        }
+        IPCPlayerApp::ProcessArguments();
     }
 
 }
-
-void AEPlayerApplication::HandleJSError(StringHash eventType, VariantMap& eventData)
-{
-    using namespace JSError;
-    //String errName = eventData[P_ERRORNAME].GetString();
-    //String errStack = eventData[P_ERRORSTACK].GetString();
-    String errMessage = eventData[P_ERRORMESSAGE].GetString();
-    String errFilename = eventData[P_ERRORFILENAME].GetString();
-    int errLineNumber = eventData[P_ERRORLINENUMBER].GetInt();
-
-    String errorString = ToString("%s - %s - Line: %i",
-                                  errFilename.CString(), errMessage.CString(), errLineNumber);
-
-}
-
-
-}

+ 18 - 34
Source/AtomicEditor/Application/AEPlayerApp.h

@@ -22,50 +22,34 @@
 
 #pragma once
 
-#include "AEEditorCommon.h"
+#include <AtomicApp/Player/IPCPlayerApp.h>
 
 using namespace Atomic;
 
 namespace AtomicEditor
 {
+    class AEPlayerApplication : public IPCPlayerApp
+    {
+        OBJECT(AEPlayerApplication)
 
-class AEPlayerApplication : public AEEditorCommon
-{
-    OBJECT(AEPlayerApplication);
-
-public:
-    /// Construct.
-    AEPlayerApplication(Context* context);
-
-    /// Setup before engine initialization. Verify that a script file has been specified.
-    virtual void Setup();
-    /// Setup after engine initialization. Load the script and execute its start function.
-    virtual void Start();
-    /// Cleanup after the main loop. Run the script's stop function if it exists.
-    virtual void Stop();
-
-private:
-    /// Handle reload start of the script file.
-    void HandleScriptReloadStarted(StringHash eventType, VariantMap& eventData);
-    /// Handle reload success of the script file.
-    void HandleScriptReloadFinished(StringHash eventType, VariantMap& eventData);
-    /// Handle reload failure of the script file.
-    void HandleScriptReloadFailed(StringHash eventType, VariantMap& eventData);
-
-    void HandleJSError(StringHash eventType, VariantMap& eventData);
-
-    void HandleLogMessage(StringHash eventType, VariantMap& eventData);
-
-    void HandleQuit(StringHash eventType, VariantMap& eventData);
+    public:
+        /// Construct.
+        AEPlayerApplication(Context* context);
+        virtual ~AEPlayerApplication();
 
-    void ReadEngineConfig();
+        /// Setup before engine initialization. 
+        virtual void Setup();
+        /// Setup after engine initialization. L
+        virtual void Start();
+        /// Cleanup after the main loop. 
+        virtual void Stop();
 
-    void ReadCommandLineArguments();
+        virtual void ProcessArguments();
 
-    bool debugPlayer_;
+    protected:
 
-    bool launchedByEditor_;
+    private:
 
-};
+    };
 
 }

+ 1 - 1
Source/AtomicEditor/CMakeLists.txt

@@ -168,7 +168,7 @@ endif()
 
 endif(ATOMIC_WEBVIEW)
 
-target_link_libraries(${CEF_TARGET} ToolCore AtomicWebView AtomicJS AtomicPlayerJS ToolCoreJS Poco nativefiledialog ${ATOMIC_LINK_LIBRARIES})
+target_link_libraries(${CEF_TARGET} ToolCore AtomicApp AtomicWebView AtomicJS AtomicPlayerJS ToolCoreJS AtomicNETScriptBindings AtomicNETScript Poco nativefiledialog ${ATOMIC_LINK_LIBRARIES})
 
 
 if (APPLE)

+ 21 - 7
Source/AtomicEditor/EditorMode/AEEditorMode.cpp

@@ -38,7 +38,7 @@
 
 #include <Atomic/UI/SystemUI/DebugHud.h>
 
-#include "../PlayerMode/AEPlayerEvents.h"
+#include <AtomicApp/Player/IPCPlayerAppEvents.h>
 
 #include "AEEditorMode.h"
 
@@ -50,16 +50,11 @@ namespace AtomicEditor
 EditorMode::EditorMode(Context* context) :
     Object(context)
 {
-    SubscribeToEvent(E_IPCWORKERSTART, HANDLER(EditorMode, HandleIPCWorkerStarted));
-    SubscribeToEvent(E_IPCPLAYERPAUSERESUMEREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseResumeRequest));
-    SubscribeToEvent(E_IPCPLAYERUPDATESPAUSEDRESUMED, HANDLER(EditorMode, HandleIPCPlayerUpdatesPausedResumed));
-    SubscribeToEvent(E_IPCPLAYERPAUSESTEPREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseStepRequest));
-    SubscribeToEvent(E_IPCPLAYEREXITREQUEST, HANDLER(EditorMode, HandleIPCPlayerExitRequest));
+
 }
 
 EditorMode::~EditorMode()
 {
-
 }
 
 void EditorMode::HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData)
@@ -95,8 +90,19 @@ void EditorMode::HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData
     {
         playerBroker_ = 0;
         playerEnabled_ = false;
+
+        UnsubscribeFromEvent(E_IPCWORKERSTART);
+        UnsubscribeFromEvent(E_IPCPLAYERPAUSERESUMEREQUEST);
+        UnsubscribeFromEvent(E_IPCPLAYERUPDATESPAUSEDRESUMED);
+        UnsubscribeFromEvent(E_IPCPLAYERPAUSESTEPREQUEST);
+        UnsubscribeFromEvent(E_IPCPLAYEREXITREQUEST);
+
         SendEvent(E_EDITORPLAYERSTOPPED);
     }
+    else
+    {
+        LOGERROR("EditorMode::HandleIPCWorkerExit - Unknown Broker");
+    }
 }
 
 void EditorMode::HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData)
@@ -164,6 +170,14 @@ bool EditorMode::PlayProject(String addArgs, bool debug)
 
     if (playerBroker_)
     {
+        SubscribeToEvent(playerBroker_, E_IPCWORKERSTART, HANDLER(EditorMode, HandleIPCWorkerStarted));
+
+        SubscribeToEvent(E_IPCPLAYERPAUSERESUMEREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseResumeRequest));
+        SubscribeToEvent(E_IPCPLAYERUPDATESPAUSEDRESUMED, HANDLER(EditorMode, HandleIPCPlayerUpdatesPausedResumed));
+        SubscribeToEvent(E_IPCPLAYERPAUSESTEPREQUEST, HANDLER(EditorMode, HandleIPCPlayerPauseStepRequest));
+        SubscribeToEvent(E_IPCPLAYEREXITREQUEST, HANDLER(EditorMode, HandleIPCPlayerExitRequest));
+    
+
         SubscribeToEvent(playerBroker_, E_IPCJSERROR, HANDLER(EditorMode, HandleIPCJSError));
         SubscribeToEvent(playerBroker_, E_IPCWORKEREXIT, HANDLER(EditorMode, HandleIPCWorkerExit));
         SubscribeToEvent(playerBroker_, E_IPCWORKERLOG, HANDLER(EditorMode, HandleIPCWorkerLog));

+ 1 - 1
Source/AtomicEditor/EditorMode/AEEditorMode.h

@@ -39,7 +39,7 @@ namespace AtomicEditor
 /// EditorMode subsystem
 class EditorMode : public Object
 {
-    OBJECT(EditorMode);
+    OBJECT(EditorMode)
 
 public:
     /// Construct.

+ 66 - 0
Source/AtomicEditor/EditorMode/AEEditorNETService.cpp

@@ -0,0 +1,66 @@
+//
+// Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <Atomic/Core/Context.h>
+#include <Atomic/IO/Log.h>
+
+#include <AtomicNET/NETScript/NETScript.h>
+
+
+#include <ToolCore/NETTools/AtomicNETService.h>
+#include "AEEditorNETService.h"
+
+namespace AtomicEditor
+{
+    
+    EditorNETService::EditorNETService(Context* context) : Object(context)
+    {
+
+        Initialize();
+
+    }
+
+
+    EditorNETService::~EditorNETService()
+    {
+
+    }
+
+    bool EditorNETService::Initialize()
+    {
+        RegisterNETScriptLibrary(context_);
+
+        netService_ = new AtomicNETService(context_);
+
+        if (!netService_->Start())
+        {
+            netService_ = nullptr;
+            LOGERRORF("Unable to start AtomicNETService");
+            return false;
+        }
+
+        context_->RegisterSubsystem(netService_);
+
+        return true;
+    }
+
+}

+ 19 - 28
Source/AtomicEditor/PlayerMode/AEPlayerEvents.h → Source/AtomicEditor/EditorMode/AEEditorNETService.h

@@ -24,44 +24,35 @@
 
 #include <Atomic/Core/Object.h>
 
-using namespace Atomic;
-
-namespace AtomicEditor
+namespace ToolCore
 {
+    class AtomicNETService;
+}
 
-EVENT(E_IPCPLAYERPAUSERESUMEREQUEST, IPCPlayerPauseResumeRequest)
-{
+using namespace Atomic;
+using namespace ToolCore;
 
-}
 
-EVENT(E_IPCPLAYERUPDATESPAUSEDRESUMED, IPCPlayerUpdatesPausedResumed)
+namespace AtomicEditor
 {
-    PARAM(P_PAUSED, Paused);            // bool
-}
 
-EVENT(E_IPCPLAYERPAUSESTEPREQUEST, IPCPlayerPauseStepRequest)
-{
+    class EditorNETService : public Object
+    {
+        OBJECT(EditorNETService)
 
-}
+    public:
 
-EVENT(E_IPCPLAYEREXITREQUEST, IPCPlayerExitRequest)
-{
+        /// Construct.
+        EditorNETService(Context* context);
+        /// Destruct.
+        virtual ~EditorNETService();
 
-}
+        bool Initialize();
 
-EVENT(E_IPCPLAYERWINDOWCHANGED, IPCPlayerWindowChanged)
-{
-    PARAM(P_POSX, PosX);
-    PARAM(P_POSY, PosY);
-    PARAM(P_WIDTH, Width);
-    PARAM(P_HEIGHT, Height);
-    PARAM(P_MONITOR, Monitor);
-    PARAM(P_MAXIMIZED, Maximized);
-}
+    private:
 
-EVENT(E_PLAYERQUIT, PlayerQuit)
-{
+        WeakPtr<AtomicNETService> netService_;
 
-}
+    };
 
-}
+}

+ 1 - 1
Source/AtomicEditor/PlayerMode/AEPlayerMode.cpp

@@ -38,7 +38,7 @@
 #include <AtomicJS/Javascript/JSEvents.h>
 #include <AtomicJS/Javascript/JSIPCEvents.h>
 
-#include "AEPlayerEvents.h"
+#include <AtomicApp/Player/IPCPlayerAppEvents.h>
 
 #include "AEPlayerMode.h"
 

+ 3 - 0
Source/AtomicNET/CMakeLists.txt

@@ -0,0 +1,3 @@
+
+add_subdirectory(NETScript)
+add_subdirectory(NETNative)

+ 36 - 0
Source/AtomicNET/NETNative/CMakeLists.txt

@@ -0,0 +1,36 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty/rapidjson/include
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty/kNet/include
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty/FreeType/include
+                    ${CMAKE_SOURCE_DIR}/Source/ThirdParty/Box2D)
+
+set (CSATOMICDIR "${CMAKE_SOURCE_DIR}/Artifacts/Build/Source/Generated/${JAVASCRIPT_BINDINGS_PLATFORM}/CSharp/Packages/")
+
+file (GLOB CSHARP_BINDINGS_SOURCE ${CSATOMICDIR}/Atomic/Native/*.cpp ${CSATOMICDIR}/Atomic/Native/*.h
+                                  ${CSATOMICDIR}/AtomicNETNative/Native/*.cpp ${CSATOMICDIR}/AtomicNETNative/Native/*.h
+                                  ${CSATOMICDIR}/AtomicNETScript/Native/*.cpp ${CSATOMICDIR}/AtomicNETScript/Native/*.h
+                                  ${CSATOMICDIR}/AtomicApp/Native/*.cpp ${CSATOMICDIR}/AtomicApp/Native/*.h
+                                  ${CSATOMICDIR}/AtomicPlayer/Native/*.cpp ${CSATOMICDIR}/AtomicPlayer/Native/*.h )
+
+file (GLOB_RECURSE SOURCE_FILES *.cpp *.h)
+
+add_library(AtomicNETNative SHARED ${SOURCE_FILES}  ${CSHARP_BINDINGS_SOURCE})
+
+add_dependencies(AtomicNETNative AtomicToolCheckScripts)
+
+target_link_libraries(AtomicNETNative AtomicNETScriptBindings AtomicNETScript AtomicJS AtomicPlayerLib AtomicPlayerJS AtomicApp ${ATOMIC_LINK_LIBRARIES})
+
+if (APPLE)
+
+    if (NOT IOS)
+
+        target_link_libraries( AtomicNETNative "-stdlib=libc++ -framework AudioUnit -framework Carbon -framework Cocoa -framework CoreAudio -framework ForceFeedback -framework IOKit -framework OpenGL -framework CoreServices -framework Security")
+
+    endif()
+
+endif()
+
+add_custom_command( TARGET AtomicNETNative POST_BUILD
+                    COMMAND "${CMAKE_COMMAND}" ARGS -E make_directory \"${CMAKE_SOURCE_DIR}/Artifacts/AtomicNET/$<$<CONFIG:debug>:Debug>$<$<CONFIG:release>:Release>\"
+                    COMMAND "${CMAKE_COMMAND}" ARGS -E copy_if_different \"$<TARGET_FILE:AtomicNETNative>\" \"${CMAKE_SOURCE_DIR}/Artifacts/AtomicNET/$<$<CONFIG:debug>:Debug>$<$<CONFIG:release>:Release>\" )

+ 95 - 0
Source/AtomicNET/NETNative/NETCInterop.cpp

@@ -0,0 +1,95 @@
+#include <Atomic/Script/ScriptVariantMap.h>
+#include <Atomic/IPC/IPC.h>
+
+#include "NETCore.h"
+
+#ifdef ATOMIC_PLATFORM_WINDOWS
+#define ATOMIC_EXPORT_API __declspec(dllexport)
+#else
+#define ATOMIC_EXPORT_API
+#endif
+
+namespace Atomic
+{
+
+    extern "C"
+    {
+
+        ATOMIC_EXPORT_API ClassID csb_Atomic_RefCounted_GetClassID(RefCounted* refCounted)
+        {
+            if (!refCounted)
+                return 0;
+
+            return refCounted->GetClassID();
+        }
+
+        ATOMIC_EXPORT_API void csb_Atomic_AObject_SendEvent(Object* obj, const char* eventType, ScriptVariantMap* vmap)
+        {
+            obj->SendEvent(eventType, vmap ? vmap->GetVariantMap() : obj->GetEventDataMap());
+        }
+
+        ATOMIC_EXPORT_API ClassID csb_Atomic_NETCore_Initialize(NETCoreDelegates* delegates)
+        {
+            Context* context = new Context();
+            NETCore* netCore = new NETCore(context, delegates);
+            context->RegisterSubsystem(netCore);
+            return netCore;
+        }
+
+        ATOMIC_EXPORT_API unsigned csb_Atomic_AtomicNET_StringToStringHash(const char* str)
+        {
+            unsigned hash = 0;
+
+            if (!str)
+                return hash;
+
+            while (*str)
+            {
+                // Perform the actual hashing as case-insensitive
+                char c = *str;
+                hash = SDBMHash(hash, (unsigned char)tolower(c));
+                ++str;
+            }
+
+            return hash;
+        }
+
+        ATOMIC_EXPORT_API void csb_Atomic_AtomicNET_ScriptVariantMapCopyVariantMap(ScriptVariantMap* svm, VariantMap* vm)
+        {
+            if (!svm)
+                return;
+
+            if (!vm)
+            {
+                svm->CopySourceVariantMap(Variant::emptyVariantMap);
+                return;
+            }
+
+            svm->CopySourceVariantMap(*vm);
+
+        }
+
+        ATOMIC_EXPORT_API void* csb_Atomic_AtomicNET_ScriptVariantMap_GetVoidPtr(ScriptVariantMap* svm, const char* key)
+        {
+            if (!svm || !key || !strlen(key))
+                return nullptr;
+
+            return svm->GetVoidPtr(key);
+
+        }
+
+        // IPC
+        ATOMIC_EXPORT_API void csb_Atomic_IPC_SendEventToBrokerWithEventData(IPC* ipc, const char* eventType, ScriptVariantMap* variantMap)
+        {
+            if (variantMap)
+                ipc->SendEventToBroker(eventType, variantMap->GetVariantMap());
+            else
+                ipc->SendEventToBroker(eventType);
+
+        }
+
+    }
+}
+
+
+

部分文件因为文件数量过多而无法显示