Browse Source

Added C# Texture3D and TextureCube

Marko Pintera 11 years ago
parent
commit
e29349d061

+ 2 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -115,6 +115,8 @@
     <Compile Include="Math\Vector2.cs" />
     <Compile Include="Math\Vector3.cs" />
     <Compile Include="Math\Vector4.cs" />
+    <Compile Include="Texture3D.cs" />
+    <Compile Include="TextureCube.cs" />
     <Compile Include="VirtualInput.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

+ 59 - 0
MBansheeEngine/Texture3D.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    public sealed class Texture3D : Texture
+    {
+        public int Depth
+        {
+            get
+            {
+                int value;
+                Internal_GetDepth(mCachedPtr, out value);
+                return value;
+            }
+        }
+
+        // For internal use by the runtime
+        private Texture3D()
+        { }
+
+        public Texture3D(PixelFormat format, int width, int height, int depth, TextureUsage usage = TextureUsage.Default, 
+            bool hasMipmaps = false, bool gammaCorrection = false)
+        {
+            Internal_CreateInstance(this, format, width, height, depth, usage, hasMipmaps, gammaCorrection);
+        }
+
+        public PixelData GetPixels(int mipLevel = 0)
+        {
+            return Internal_GetPixels(mCachedPtr, mipLevel);
+        }
+
+        public void SetPixels(PixelData data, int mipLevel = 0)
+        {
+            Internal_SetPixels(mCachedPtr, data, mipLevel);
+        }
+
+        public AsyncOp GetGPUPixels(int mipLevel = 0)
+        {
+            return Internal_GetGPUPixels(mCachedPtr, mipLevel);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(Texture3D instance, PixelFormat format, int width,
+            int height, int depth, TextureUsage usage, bool hasMipmaps, bool gammaCorrection);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetDepth(IntPtr thisPtr, out int value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern PixelData Internal_GetPixels(IntPtr thisPtr, int mipLevel);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern AsyncOp Internal_GetGPUPixels(IntPtr thisPtr, int mipLevel);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPixels(IntPtr thisPtr, PixelData data, int mipLevel);
+    }
+}

+ 56 - 0
MBansheeEngine/TextureCube.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    public sealed class TextureCube : Texture
+    {
+        // For internal use by the runtime
+        private TextureCube()
+        { }
+
+        public TextureCube(PixelFormat format, int width, int height, TextureUsage usage = TextureUsage.Default,
+            int numSamples = 1, bool hasMipmaps = false, bool gammaCorrection = false)
+        {
+            Internal_CreateInstance(this, format, width, height, usage, numSamples, hasMipmaps, gammaCorrection);
+        }
+
+        public PixelData GetPixels(CubeFace face = CubeFace.PositiveX, int mipLevel = 0)
+        {
+            return Internal_GetPixels(mCachedPtr, face, mipLevel);
+        }
+
+        public void SetPixels(PixelData data, CubeFace face = CubeFace.PositiveX, int mipLevel = 0)
+        {
+            Internal_SetPixels(mCachedPtr, data, face, mipLevel);
+        }
+
+        public AsyncOp GetGPUPixels(CubeFace face = CubeFace.PositiveX, int mipLevel = 0)
+        {
+            return Internal_GetGPUPixels(mCachedPtr, face, mipLevel);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(TextureCube instance, PixelFormat format, int width,
+            int height, TextureUsage usage, int numSamples, bool hasMipmaps, bool gammaCorrection);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern PixelData Internal_GetPixels(IntPtr thisPtr, CubeFace face, int mipLevel);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern AsyncOp Internal_GetGPUPixels(IntPtr thisPtr, CubeFace face, int mipLevel);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPixels(IntPtr thisPtr, PixelData data, CubeFace face, int mipLevel);
+    }
+
+    public enum CubeFace
+    {
+        PositiveX = 0,
+        NegativeX = 1,
+        PositiveY = 2,
+        NegativeY = 3,
+        PositiveZ = 4,
+        NegativeZ = 5,
+    }
+}

+ 2 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -25,6 +25,8 @@ namespace BansheeEngine
 	class ScriptFont;
 	class ScriptSpriteTexture;
 	class ScriptTexture2D;
+	class ScriptTexture3D;
+	class ScriptTextureCube;
 	class ScriptGUIElementStyle;
 	class ScriptGUIElementStateStyle;
 	class ScriptGUIPanel;

+ 24 - 0
SBansheeEngine/Include/BsScriptResourceManager.h

@@ -17,12 +17,36 @@ namespace BansheeEngine
 		 */
 		ScriptTexture2D* createScriptTexture2D(const HTexture& resourceHandle);
 
+		/**
+		* @note Throws an exception if resource for the handle already exists.
+		* 		 Creates a new managed instance of the object.
+		*/
+		ScriptTexture3D* createScriptTexture3D(const HTexture& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Creates a new managed instance of the object.
+		 */
+		ScriptTextureCube* createScriptTextureCube(const HTexture& resourceHandle);
+
 		/**
 		 * @note Throws an exception if resource for the handle already exists.
 		 * 		 Initializes the ScriptResource with an existing managed instance.
 		 */
 		ScriptTexture2D* createScriptTexture2D(MonoObject* existingInstance, const HTexture& resourceHandle);
 
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptTexture3D* createScriptTexture3D(MonoObject* existingInstance, const HTexture& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptTextureCube* createScriptTextureCube(MonoObject* existingInstance, const HTexture& resourceHandle);
+
 		/**
 		 * @note Throws an exception if resource for the handle already exists.
 		 * 		 Creates a new managed instance of the object.

+ 34 - 0
SBansheeEngine/Include/BsScriptTexture3D.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptTexture.h"
+#include "BsScriptObject.h"
+#include "BsTexture.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptTexture3D : public ScriptObject <ScriptTexture3D, ScriptTextureBase>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "Texture3D")
+
+		void* getNativeRaw() const { return mTexture.get(); }
+
+		HResource getNativeHandle() const { return mTexture; }
+		void setNativeHandle(const HResource& resource);
+	private:
+		friend class ScriptResourceManager;
+
+		static void internal_createInstance(MonoObject* instance, PixelFormat format, UINT32 width,
+			UINT32 height, UINT32 depth, TextureUsage usage, bool hasMipmaps, bool gammaCorrection);
+		static MonoObject* internal_getPixels(ScriptTexture3D* thisPtr, UINT32 mipLevel);
+		static MonoObject* internal_getGPUPixels(ScriptTexture3D* thisPtr, UINT32 mipLevel);
+		static void internal_setPixels(ScriptTexture3D* thisPtr, MonoObject* data, UINT32 mipLevel);
+
+		ScriptTexture3D(MonoObject* instance, const HTexture& texture);
+
+		void _onManagedInstanceDeleted();
+
+		HTexture mTexture;
+	};
+}

+ 34 - 0
SBansheeEngine/Include/BsScriptTextureCube.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptTexture.h"
+#include "BsScriptObject.h"
+#include "BsTexture.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptTextureCube : public ScriptObject <ScriptTextureCube, ScriptTextureBase>
+	{
+	public:
+		SCRIPT_OBJ(BansheeEngineAssemblyName, "BansheeEngine", "TextureCube")
+
+		void* getNativeRaw() const { return mTexture.get(); }
+
+		HResource getNativeHandle() const { return mTexture; }
+		void setNativeHandle(const HResource& resource);
+	private:
+		friend class ScriptResourceManager;
+
+		static void internal_createInstance(MonoObject* instance, PixelFormat format, UINT32 width,
+			UINT32 height, TextureUsage usage, UINT32 numSamples, bool hasMipmaps, bool gammaCorrection);
+		static MonoObject* internal_getPixels(ScriptTextureCube* thisPtr, UINT32 face, UINT32 mipLevel);
+		static MonoObject* internal_getGPUPixels(ScriptTextureCube* thisPtr, UINT32 face, UINT32 mipLevel);
+		static void internal_setPixels(ScriptTextureCube* thisPtr, MonoObject* data, UINT32 face, UINT32 mipLevel);
+
+		ScriptTextureCube(MonoObject* instance, const HTexture& texture);
+
+		void _onManagedInstanceDeleted();
+
+		HTexture mTexture;
+	};
+}

+ 4 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -295,6 +295,8 @@
     <ClInclude Include="Include\BsScriptTexture2D.h" />
     <ClInclude Include="Include\BsScriptGUIContent.h" />
     <ClInclude Include="Include\BsManagedSerializableObjectInfo.h" />
+    <ClInclude Include="Include\BsScriptTexture3D.h" />
+    <ClInclude Include="Include\BsScriptTextureCube.h" />
     <ClInclude Include="Include\BsScriptVector2I.h" />
     <ClInclude Include="Include\BsScriptVirtualButton.h" />
     <ClInclude Include="Include\BsScriptVirtualInput.h" />
@@ -357,6 +359,8 @@
     <ClCompile Include="Source\BsScriptTexture.cpp" />
     <ClCompile Include="Source\BsScriptTexture2D.cpp" />
     <ClCompile Include="Source\BsScriptGUIContent.cpp" />
+    <ClCompile Include="Source\BsScriptTexture3D.cpp" />
+    <ClCompile Include="Source\BsScriptTextureCube.cpp" />
     <ClCompile Include="Source\BsScriptVector2I.cpp" />
     <ClCompile Include="Source\BsScriptVirtualInput.cpp" />
     <ClCompile Include="Source\BsScriptVirtualButton.cpp" />

+ 12 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -249,6 +249,12 @@
     <ClInclude Include="Include\BsScriptTexture.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptTextureCube.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptTexture3D.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -431,5 +437,11 @@
     <ClCompile Include="Source\BsScriptTexture.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptTextureCube.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptTexture3D.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 42 - 0
SBansheeEngine/Source/BsScriptResourceManager.cpp

@@ -3,6 +3,8 @@
 #include "BsMonoAssembly.h"
 #include "BsMonoClass.h"
 #include "BsScriptTexture2D.h"
+#include "BsScriptTexture3D.h"
+#include "BsScriptTextureCube.h"
 #include "BsScriptSpriteTexture.h"
 #include "BsScriptFont.h"
 #include "BsScriptManagedResource.h"
@@ -37,6 +39,20 @@ namespace BansheeEngine
 		return createScriptTexture2D(monoInstance, resourceHandle);
 	}
 
+	ScriptTexture3D* ScriptResourceManager::createScriptTexture3D(const HTexture& resourceHandle)
+	{
+		MonoObject* monoInstance = mTextureClass->createInstance();
+
+		return createScriptTexture3D(monoInstance, resourceHandle);
+	}
+
+	ScriptTextureCube* ScriptResourceManager::createScriptTextureCube(const HTexture& resourceHandle)
+	{
+		MonoObject* monoInstance = mTextureClass->createInstance();
+
+		return createScriptTextureCube(monoInstance, resourceHandle);
+	}
+
 	ScriptTexture2D* ScriptResourceManager::createScriptTexture2D(MonoObject* instance, const HTexture& resourceHandle)
 	{
 		const String& uuid = resourceHandle.getUUID();
@@ -50,6 +66,32 @@ namespace BansheeEngine
 		return scriptResource;
 	}
 
+	ScriptTexture3D* ScriptResourceManager::createScriptTexture3D(MonoObject* instance, const HTexture& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+#if BS_DEBUG_MODE
+		throwExceptionIfInvalidOrDuplicate(uuid);
+#endif
+
+		ScriptTexture3D* scriptResource = new (bs_alloc<ScriptTexture3D>()) ScriptTexture3D(instance, resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		return scriptResource;
+	}
+
+	ScriptTextureCube* ScriptResourceManager::createScriptTextureCube(MonoObject* instance, const HTexture& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+#if BS_DEBUG_MODE
+		throwExceptionIfInvalidOrDuplicate(uuid);
+#endif
+
+		ScriptTextureCube* scriptResource = new (bs_alloc<ScriptTextureCube>()) ScriptTextureCube(instance, resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		return scriptResource;
+	}
+
 	ScriptSpriteTexture* ScriptResourceManager::createScriptSpriteTexture(const HSpriteTexture& resourceHandle)
 	{
 		MonoObject* monoInstance = mSpriteTextureClass->createInstance();

+ 97 - 0
SBansheeEngine/Source/BsScriptTexture3D.cpp

@@ -0,0 +1,97 @@
+#include "BsScriptTexture3D.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsTexture.h"
+#include "BsPixelUtil.h"
+#include "BsException.h"
+#include "BsScriptPixelData.h"
+#include "BsScriptAsyncOp.h"
+#include "BsCoreThread.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptTexture3D::ScriptTexture3D(MonoObject* instance, const HTexture& texture)
+		:ScriptObject(instance), mTexture(texture)
+	{
+
+	}
+
+	void ScriptTexture3D::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptTexture3D::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetPixels", &ScriptTexture3D::internal_getPixels);
+		metaData.scriptClass->addInternalCall("Internal_GetGPUPixels", &ScriptTexture3D::internal_getGPUPixels);
+		metaData.scriptClass->addInternalCall("Internal_SetPixels", &ScriptTexture3D::internal_setPixels);
+	}
+
+	void ScriptTexture3D::internal_createInstance(MonoObject* instance, PixelFormat format, UINT32 width,
+		UINT32 height, UINT32 depth, TextureUsage usage, bool hasMipmaps, bool gammaCorrection)
+	{
+		int numMips = 0;
+		if (hasMipmaps)
+			numMips = PixelUtil::getMaxMipmaps(width, height, depth, format);
+
+		HTexture texture = Texture::create(TEX_TYPE_3D, width, height, depth, numMips, format, usage, gammaCorrection);
+
+		ScriptResourceManager::instance().createScriptTexture3D(instance, texture);
+	}
+
+	MonoObject* ScriptTexture3D::internal_getPixels(ScriptTexture3D* thisPtr, UINT32 mipLevel)
+	{
+		HTexture texture = thisPtr->mTexture;
+		UINT32 subresourceIdx = texture->mapToSubresourceIdx(0, mipLevel);
+
+		PixelDataPtr pixelData = thisPtr->mTexture->allocateSubresourceBuffer(subresourceIdx);
+
+		thisPtr->mTexture->readDataSim(*pixelData, mipLevel);
+
+		return ScriptPixelData::create(pixelData);
+	}
+
+	MonoObject* ScriptTexture3D::internal_getGPUPixels(ScriptTexture3D* thisPtr, UINT32 mipLevel)
+	{
+		HTexture texture = thisPtr->mTexture;
+		UINT32 subresourceIdx = texture->mapToSubresourceIdx(0, mipLevel);
+
+		PixelDataPtr readData = texture->allocateSubresourceBuffer(subresourceIdx);
+
+		AsyncOp asyncOp = gCoreAccessor().readSubresource(texture.getInternalPtr(), subresourceIdx, readData);
+
+		std::function<MonoObject*(const AsyncOp&, const PixelDataPtr&)> asyncOpToMono =
+			[&](const AsyncOp& op, const PixelDataPtr& returnValue)
+		{
+			return ScriptPixelData::create(returnValue);
+		};
+
+		return ScriptAsyncOp::create(asyncOp, std::bind(asyncOpToMono, _1, readData));
+	}
+
+	void ScriptTexture3D::internal_setPixels(ScriptTexture3D* thisPtr, MonoObject* data, UINT32 mipLevel)
+	{
+		ScriptPixelData* scriptPixelData = ScriptPixelData::toNative(data);
+
+		if (scriptPixelData != nullptr)
+		{
+			HTexture texture = thisPtr->mTexture;
+			UINT32 subresourceIdx = texture->mapToSubresourceIdx(0, mipLevel);
+
+			gCoreAccessor().writeSubresource(texture.getInternalPtr(), subresourceIdx, scriptPixelData->getInternalValue());
+		}
+	}
+
+	void ScriptTexture3D::_onManagedInstanceDeleted()
+	{
+		mManagedInstance = nullptr;
+		ScriptResourceManager::instance().destroyScriptResource(this);
+	}
+
+	void ScriptTexture3D::setNativeHandle(const HResource& resource)
+	{
+		mTexture = static_resource_cast<Texture>(resource);
+	}
+}

+ 97 - 0
SBansheeEngine/Source/BsScriptTextureCube.cpp

@@ -0,0 +1,97 @@
+#include "BsScriptTextureCube.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsTexture.h"
+#include "BsPixelUtil.h"
+#include "BsException.h"
+#include "BsScriptPixelData.h"
+#include "BsScriptAsyncOp.h"
+#include "BsCoreThread.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	ScriptTextureCube::ScriptTextureCube(MonoObject* instance, const HTexture& texture)
+		:ScriptObject(instance), mTexture(texture)
+	{
+
+	}
+
+	void ScriptTextureCube::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptTextureCube::internal_createInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetPixels", &ScriptTextureCube::internal_getPixels);
+		metaData.scriptClass->addInternalCall("Internal_GetGPUPixels", &ScriptTextureCube::internal_getGPUPixels);
+		metaData.scriptClass->addInternalCall("Internal_SetPixels", &ScriptTextureCube::internal_setPixels);
+	}
+
+	void ScriptTextureCube::internal_createInstance(MonoObject* instance, PixelFormat format, UINT32 width,
+		UINT32 height, TextureUsage usage, UINT32 numSamples, bool hasMipmaps, bool gammaCorrection)
+	{
+		int numMips = 0;
+		if (hasMipmaps)
+			numMips = PixelUtil::getMaxMipmaps(width, height, 1, format);
+
+		HTexture texture = Texture::create(TEX_TYPE_CUBE_MAP, width, height, numMips, format, usage, gammaCorrection, numSamples);
+
+		ScriptResourceManager::instance().createScriptTextureCube(instance, texture);
+	}
+
+	MonoObject* ScriptTextureCube::internal_getPixels(ScriptTextureCube* thisPtr, UINT32 face, UINT32 mipLevel)
+	{
+		HTexture texture = thisPtr->mTexture;
+		UINT32 subresourceIdx = texture->mapToSubresourceIdx(face, mipLevel);
+
+		PixelDataPtr pixelData = thisPtr->mTexture->allocateSubresourceBuffer(subresourceIdx);
+
+		thisPtr->mTexture->readDataSim(*pixelData, mipLevel, face);
+
+		return ScriptPixelData::create(pixelData);
+	}
+
+	MonoObject* ScriptTextureCube::internal_getGPUPixels(ScriptTextureCube* thisPtr, UINT32 face, UINT32 mipLevel)
+	{
+		HTexture texture = thisPtr->mTexture;
+		UINT32 subresourceIdx = texture->mapToSubresourceIdx(face, mipLevel);
+
+		PixelDataPtr readData = texture->allocateSubresourceBuffer(subresourceIdx);
+
+		AsyncOp asyncOp = gCoreAccessor().readSubresource(texture.getInternalPtr(), subresourceIdx, readData);
+
+		std::function<MonoObject*(const AsyncOp&, const PixelDataPtr&)> asyncOpToMono =
+			[&](const AsyncOp& op, const PixelDataPtr& returnValue)
+		{
+			return ScriptPixelData::create(returnValue);
+		};
+
+		return ScriptAsyncOp::create(asyncOp, std::bind(asyncOpToMono, _1, readData));
+	}
+
+	void ScriptTextureCube::internal_setPixels(ScriptTextureCube* thisPtr, MonoObject* data, UINT32 face, UINT32 mipLevel)
+	{
+		ScriptPixelData* scriptPixelData = ScriptPixelData::toNative(data);
+
+		if (scriptPixelData != nullptr)
+		{
+			HTexture texture = thisPtr->mTexture;
+			UINT32 subresourceIdx = texture->mapToSubresourceIdx(face, mipLevel);
+
+			gCoreAccessor().writeSubresource(texture.getInternalPtr(), subresourceIdx, scriptPixelData->getInternalValue());
+		}
+	}
+
+	void ScriptTextureCube::_onManagedInstanceDeleted()
+	{
+		mManagedInstance = nullptr;
+		ScriptResourceManager::instance().destroyScriptResource(this);
+	}
+
+	void ScriptTextureCube::setNativeHandle(const HResource& resource)
+	{
+		mTexture = static_resource_cast<Texture>(resource);
+	}
+}

+ 0 - 1
TODO.txt

@@ -21,7 +21,6 @@ Refactor GizmoManager and HandleManager so they accept a CameraHandler
  - Delete SceneViewLocator, I don't think it's used anywhere
 
 Port SceneCameraController to C#
- - Will need a C# Cursor
 Port RenderTexture to C# and likely extend Texture2D so it accepts renderable flags. While at it add TextureCube and Texture3D as well.
  - Actually Texture2D doesn't seem to be implemented at all. Will also need to add PixelData wrapper.
  - Will I need to add support for readable textures? e.g. what happens when you try to read a texture from C#?