Browse Source

WIP VS project generation

Marko Pintera 10 years ago
parent
commit
e366d25700

+ 1 - 0
BansheeCore/BansheeCore.vcxproj

@@ -280,6 +280,7 @@
   <ItemGroup>
     <ClInclude Include="Include\BsCoreObjectCore.h" />
     <ClInclude Include="Include\BsDrawList.h" />
+    <ClInclude Include="Include\BsGpuProgIncludeRTTI.h" />
     <ClInclude Include="Include\BsIResourceListener.h" />
     <ClInclude Include="Include\BsMaterialParam.h" />
     <ClInclude Include="Include\BsRenderStats.h" />

+ 3 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -527,6 +527,9 @@
     <ClInclude Include="Include\Win32\BsWin32Platform.h">
       <Filter>Header Files\Platform</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsGpuProgIncludeRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">

+ 8 - 0
BansheeCore/Include/BsGpuProgInclude.h

@@ -31,5 +31,13 @@ namespace BansheeEngine
 		GpuProgInclude(const String& includeString);
 
 		String mString;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class GpuProgIncludeRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
 	};
 }

+ 1 - 1
BansheeCore/Include/BsGpuProgIncludeImporter.h

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 	/**
 	 * @brief	Importer using for importing GPU program (i.e. shader) include files.
-	 * 			Include files are just text files ending with ".gpuproginc" extension.
+	 * 			Include files are just text files ending with ".gpuinc" extension.
 	 */
 	class BS_CORE_EXPORT GpuProgIncludeImporter : public SpecificImporter
 	{

+ 36 - 0
BansheeCore/Include/BsGpuProgIncludeRTTI.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsGpuProgInclude.h"
+
+namespace BansheeEngine
+{
+	class BS_CORE_EXPORT GpuProgIncludeRTTI : public RTTIType <GpuProgInclude, Resource, GpuProgIncludeRTTI>
+	{
+	private:
+		String& getString(GpuProgInclude* obj) { return obj->mString; }
+		void setString(GpuProgInclude* obj, String& val) { obj->mString = val; }
+	public:
+		GpuProgIncludeRTTI()
+		{
+			addPlainField("mString", 0, &GpuProgIncludeRTTI::getString, &GpuProgIncludeRTTI::setString);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "GpuProgInclude";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_GpuProgramInclude;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return GpuProgInclude::_createPtr(""); // Initial string doesn't matter, it'll get overwritten
+		}
+	};
+}

+ 11 - 0
BansheeCore/Source/BsGpuProgInclude.cpp

@@ -1,5 +1,6 @@
 #include "BsGpuProgInclude.h"
 #include "BsResources.h"
+#include "BsGpuProgIncludeRTTI.h"
 
 namespace BansheeEngine
 {
@@ -23,4 +24,14 @@ namespace BansheeEngine
 
 		return gpuProgIncludePtr;
 	}
+
+	RTTITypeBase* GpuProgInclude::getRTTIStatic()
+	{
+		return GpuProgIncludeRTTI::instance();
+	}
+
+	RTTITypeBase* GpuProgInclude::getRTTI() const
+	{
+		return GpuProgInclude::getRTTIStatic();
+	}
 }

+ 1 - 1
BansheeCore/Source/BsGpuProgIncludeImporter.cpp

@@ -22,7 +22,7 @@ namespace BansheeEngine
 		WString lowerCaseExt = ext;
 		StringUtil::toLowerCase(lowerCaseExt);
 
-		return lowerCaseExt == L"gpuproginc";
+		return lowerCaseExt == L"gpuinc";
 	}
 
 	bool GpuProgIncludeImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const

+ 195 - 5
BansheeEditor/Source/Win32/BsVSCodeEditor.cpp

@@ -1,6 +1,7 @@
 #include "Win32/BsVSCodeEditor.h"
 #include <windows.h>
 #include <atlbase.h>
+#include "BsUtil.h"
 
 // Import EnvDTE
 #import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
@@ -34,10 +35,21 @@ namespace BansheeEngine
 		WString GUID;
 		WString name;
 		Path path;
-	}
+	};
 
 	class VisualStudio
 	{
+	private:
+		static const WString SLN_TEMPLATE;
+		static const WString PROJ_ENTRY_TEMPLATE;
+		static const WString PROJ_PLATFORM_TEMPLATE;
+
+		static const WString PROJ_TEMPLATE;
+		static const WString REFERENCE_ENTRY_TEMPLATE;
+		static const WString REFERENCE_PATH_ENTRY_TEMPLATE;
+		static const WString CODE_ENTRY_TEMPLATE;
+		static const WString NON_CODE_ENTRY_TEMPLATE;
+
 	public:
 		static CComPtr<EnvDTE::_DTE> findRunningInstance(const CLSID& clsID, const Path& solutionPath)
 		{
@@ -164,16 +176,194 @@ namespace BansheeEngine
 			return true;
 		}
 
-		static WString writeSolution(VisualStudioVersion version, const WString& solutionGUID, const Vector<VSProjectInfo>& projects)
+		static String getSolutionGUID(const WString& solutionName)
+		{
+			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
+			String hash = md5(L"SLN_" + solutionName);
+
+			return StringUtil::format(guidTemplate, hash.substr(0, 8), hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
+		}
+
+		static String getProjectGUID(const WString& projectName)
+		{
+			static const String guidTemplate = "{0}-{1}-{2}-{3}-{4}";
+			String hash = md5(L"PRJ_" + projectName);
+
+			return StringUtil::format(guidTemplate, hash.substr(0, 8), hash.substr(8, 4), hash.substr(12, 4), hash.substr(16, 4), hash.substr(20, 12));
+		}
+
+		static WString writeSolution(VisualStudioVersion version, const WString& name, const Vector<VSProjectInfo>& projects)
 		{
-			WStringStream stream;
+			struct VersionData
+			{
+				WString formatVersion;
+			};
 
+			Map<VisualStudioVersion, VersionData> versionData =
+			{
+				{ VisualStudioVersion::VS2008, { L"10.0" } },
+				{ VisualStudioVersion::VS2010, { L"11.0" } },
+				{ VisualStudioVersion::VS2012, { L"12.0" } },
+				{ VisualStudioVersion::VS2013, { L"12.0" } },
+				{ VisualStudioVersion::VS2015, { L"12.0" } }
+			};
+
+			String solutionGUID = getSolutionGUID(name);
+
+			WStringStream projectEntriesStream;
+			WStringStream projectPlatformsStream;
+			for (auto& project : projects)
+			{
+				projectEntriesStream << StringUtil::format(PROJ_ENTRY_TEMPLATE, toWString(solutionGUID), project.name, project.path.toWString(), project.GUID) << std::endl;
+				projectPlatformsStream << StringUtil::format(PROJ_PLATFORM_TEMPLATE, project.GUID) << std::endl;
+			}
 
-			const WString header;
-			
+			WString projectEntries = projectEntriesStream.str();
+			WString projectPlatforms = projectPlatformsStream.str();
+
+			return StringUtil::format(SLN_TEMPLATE, versionData[version].formatVersion, projectEntries, projectPlatforms);
+		}
+
+		static WString writeProject(VisualStudioVersion version, const CodeProjectData& projectData)
+		{
+			struct VersionData
+			{
+				WString toolsVersion;
+			};
+
+			Map<VisualStudioVersion, VersionData> versionData =
+			{
+				{ VisualStudioVersion::VS2008, { L"3.5" } },
+				{ VisualStudioVersion::VS2010, { L"4.0" } },
+				{ VisualStudioVersion::VS2012, { L"4.0" } },
+				{ VisualStudioVersion::VS2013, { L"12.0" } },
+				{ VisualStudioVersion::VS2015, { L"13.0" } }
+			};
+
+			WStringStream tempStream;
+			for (auto& codeEntry : projectData.codeFiles)
+				tempStream << StringUtil::format(CODE_ENTRY_TEMPLATE, codeEntry.toWString()) << std::endl;
+
+			WString codeEntries = tempStream.str();
+			tempStream.str(L"");
+			tempStream.clear();
+
+			for (auto& nonCodeEntry : projectData.nonCodeFiles)
+				tempStream << StringUtil::format(NON_CODE_ENTRY_TEMPLATE, nonCodeEntry.toWString()) << std::endl;
+
+			WString nonCodeEntries = tempStream.str();
+			tempStream.str(L"");
+			tempStream.clear();
+
+			for (auto& referenceEntry : projectData.references)
+			{
+				if (referenceEntry.path.isEmpty())
+					tempStream << StringUtil::format(REFERENCE_ENTRY_TEMPLATE, referenceEntry.name) << std::endl;
+				else
+					tempStream << StringUtil::format(REFERENCE_PATH_ENTRY_TEMPLATE, referenceEntry.name, referenceEntry.path.toWString()) << std::endl;
+			}
+
+			WString referenceEntries = tempStream.str();
+			tempStream.str(L"");
+			tempStream.clear();
+
+			for (auto& define : projectData.defines)
+				tempStream << define << L";";
+
+			WString defines = tempStream.str();
+			WString projectGUID = toWString(getProjectGUID(projectData.name));
+
+			return StringUtil::format(PROJ_ENTRY_TEMPLATE, versionData[version].toolsVersion, projectGUID, 
+				projectData.name, defines, referenceEntries, codeEntries, nonCodeEntries);
 		}
 	};
 
+	const WString VisualStudio::SLN_TEMPLATE =
+		LR"(Microsoft Visual Studio Solution File, Format Version {0}
+{1}
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2}
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal)";
+
+	const WString VisualStudio::PROJ_ENTRY_TEMPLATE =
+		LR"(Project("\{{0}\}") = "{1}", "{2}", "\{{3}\}"
+EndProject)";
+
+	const WString VisualStudio::PROJ_PLATFORM_TEMPLATE =
+		LR"(\{{0}\}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		\{{0}\}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		\{{0}\}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		\{{0}\}.Release|Any CPU.Build.0 = Release|Any CPU)";
+
+	const WString VisualStudio::PROJ_TEMPLATE =
+		LR"literal(<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="{0}" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition = " '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition = " '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>\{{1}\}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace></RootNamespace>
+    <AssemblyName>{2}</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <BaseDirectory>Resources</BaseDirectory>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+    <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>Internal\Temp\Assemblies\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;{3}</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel >
+  </PropertyGroup>
+  <PropertyGroup Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>Internal\Temp\Assemblies\Release\</OutputPath>
+    <DefineConstants>TRACE;{3}</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+{4}
+  </ItemGroup>
+  <ItemGroup>
+{5}
+  </ItemGroup>
+  <ItemGroup>
+{6}
+  </ItemGroup>
+  <Import Project = "$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>
+</Project>)literal";
+
+	const WString VisualStudio::REFERENCE_ENTRY_TEMPLATE =
+		LR"(    <Reference Include="{0}"/>)";
+
+	const WString VisualStudio::REFERENCE_PATH_ENTRY_TEMPLATE =
+		LR"(    <Reference Include="{0}">
+      <HintPath>{1}</HintPath>
+    </Reference>)";
+
+	const WString VisualStudio::CODE_ENTRY_TEMPLATE =
+		LR"(    <Compile Include="{0}"/>)";
+
+	const WString VisualStudio::NO_CODE_ENTRY_TEMPLATE =
+		LR"(    <None Include="{0}"/>)";
+
 	VSCodeEditor::VSCodeEditor(const Path& execPath, const WString& CLSID)
 		:mCLSID(CLSID), mExecPath(execPath)
 	{

+ 10 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -241,10 +241,14 @@
     <ClCompile Include="Source\BsGUISlider.cpp" />
     <ClCompile Include="Source\BsGUISpace.cpp" />
     <ClCompile Include="Source\BsInputConfiguration.cpp" />
+    <ClCompile Include="Source\BsPlainText.cpp" />
+    <ClCompile Include="Source\BsPlainTextImporter.cpp" />
     <ClCompile Include="Source\BsRenderableController.cpp" />
     <ClCompile Include="Source\BsRenderableHandler.cpp" />
     <ClCompile Include="Source\BsRenderer.cpp" />
     <ClCompile Include="Source\BsRenderQueue.cpp" />
+    <ClCompile Include="Source\BsScriptCode.cpp" />
+    <ClCompile Include="Source\BsScriptCodeImporter.cpp" />
     <ClCompile Include="Source\BsVirtualInput.cpp" />
     <ClInclude Include="Include\BsApplication.h" />
     <ClInclude Include="Include\BsCameraHandler.h" />
@@ -254,10 +258,16 @@
     <ClInclude Include="Include\BsGUILayoutExplicit.h" />
     <ClInclude Include="Include\BsGUIProgressBar.h" />
     <ClInclude Include="Include\BsGUISlider.h" />
+    <ClInclude Include="Include\BsPlainText.h" />
+    <ClInclude Include="Include\BsPlainTextImporter.h" />
+    <ClInclude Include="Include\BsPlainTextRTTI.h" />
     <ClInclude Include="Include\BsRenderableElement.h" />
     <ClInclude Include="Include\BsRenderableHandler.h" />
     <ClInclude Include="Include\BsRenderableHandlerRTTI.h" />
     <ClInclude Include="Include\BsRenderer.h" />
+    <ClInclude Include="Include\BsScriptCode.h" />
+    <ClInclude Include="Include\BsScriptCodeImporter.h" />
+    <ClInclude Include="Include\BsScriptCodeRTTI.h" />
     <ClInclude Include="Include\BsShapeMeshes3D.h" />
     <ClInclude Include="Include\BsDragAndDropManager.h" />
     <ClInclude Include="Include\BsShapeMeshes2D.h" />

+ 30 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -293,6 +293,24 @@
     <ClInclude Include="Include\BsGUILayoutExplicit.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsPlainText.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsPlainTextImporter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptCode.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptCodeImporter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsPlainTextRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptCodeRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -508,5 +526,17 @@
     <ClCompile Include="Source\BsGUISpace.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsPlainText.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptCode.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsPlainTextImporter.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptCodeImporter.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 43 - 0
BansheeEngine/Include/BsPlainText.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsResource.h"
+
+namespace BansheeEngine
+{
+	/**
+	* @brief	Raw text resource.
+	*/
+	class BS_EXPORT PlainText : public Resource
+	{
+	public:
+		/**
+		 * @brief	Text contained in the file.
+		 */
+		const WString& getString() const { return mString; }
+
+		/**
+		 * @brief	Creates a new text file resource with the specified string.
+		 */
+		static HPlainText create(const WString& data);
+
+		/**
+		 * @brief	Creates an include file resource with the specified include string.
+		 *
+		 * @note	Internal method. Use "create" for normal use.
+		 */
+		static PlainTextPtr _createPtr(const WString& data);
+	private:
+		PlainText(const WString& data);
+
+		WString mString;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class PlainTextRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+	};
+}

+ 28 - 0
BansheeEngine/Include/BsPlainTextImporter.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsSpecificImporter.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Imports plain text files (.txt, .xml, .json).
+	 */
+	class BS_EXPORT PlainTextImporter : public SpecificImporter
+	{
+	public:
+		PlainTextImporter();
+		virtual ~PlainTextImporter();
+
+		/** @copydoc SpecificImporter::isExtensionSupported */
+		virtual bool isExtensionSupported(const WString& ext) const;
+
+		/** @copydoc SpecificImporter::isMagicNumberSupported */
+		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const;
+
+		/** @copydoc SpecificImporter::import */
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
+
+		static const WString DEFAULT_EXTENSION;
+	};
+}

+ 36 - 0
BansheeEngine/Include/BsPlainTextRTTI.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsPlainText.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT PlainTextRTTI : public RTTIType <PlainText, Resource, PlainTextRTTI>
+	{
+	private:
+		WString& getString(PlainText* obj) { return obj->mString; }
+		void setString(PlainText* obj, WString& val) { obj->mString = val; }
+	public:
+		PlainTextRTTI()
+		{
+			addPlainField("mString", 0, &PlainTextRTTI::getString, &PlainTextRTTI::setString);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "PlainText";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_PlainText;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return PlainText::_createPtr(L""); // Initial string doesn't matter, it'll get overwritten
+		}
+	};
+}

+ 9 - 1
BansheeEngine/Include/BsPrerequisites.h

@@ -89,6 +89,8 @@ namespace BansheeEngine
 	class RenderableHandler;
 	class CameraHandlerCore;
 	class RenderableHandlerCore;
+	class PlainText;
+	class ScriptCode;
 
 	// 2D
 	class TextSprite;
@@ -110,6 +112,8 @@ namespace BansheeEngine
 	typedef std::shared_ptr<CameraHandler> CameraHandlerPtr;
 	typedef std::shared_ptr<RenderableHandler> RenderableHandlerPtr;
 	typedef std::shared_ptr<InputConfiguration> InputConfigurationPtr;
+	typedef std::shared_ptr<PlainText> PlainTextPtr;
+	typedef std::shared_ptr<ScriptCode> ScriptCodePtr;
 
 	typedef GameObjectHandle<GUIWidget> HGUIWidget;
 	typedef GameObjectHandle<Camera> HCamera;
@@ -117,6 +121,8 @@ namespace BansheeEngine
 	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
 
 	typedef ResourceHandle<SpriteTexture> HSpriteTexture;
+	typedef ResourceHandle<PlainText> HPlainText;
+	typedef ResourceHandle<ScriptCode> HScriptCode;
 
 	/**
 	 * @brief	RTTI types.
@@ -127,6 +133,8 @@ namespace BansheeEngine
 		TID_Renderable = 30001,
 		TID_SpriteTexture = 30002,
 		TID_CameraHandler = 30003,
-		TID_RenderableHandler = 30004
+		TID_RenderableHandler = 30004,
+		TID_PlainText = 30005,
+		TID_ScriptCode = 30006
 	};
 }

+ 43 - 0
BansheeEngine/Include/BsScriptCode.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsResource.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Resource containing script source code.
+	 */
+	class BS_EXPORT ScriptCode : public Resource
+	{
+	public:
+		/**
+		 * @brief	Returns the source code contained in the resource.
+		 */
+		const WString& getString() const { return mString; }
+
+		/**
+		 * @brief	Creates a new script code resource with the specified source code.
+		 */
+		static HScriptCode create(const WString& data);
+
+		/**
+		 * @brief	Creates an include file resource with the specified include string.
+		 *
+		 * @note	Internal method. Use "create" for normal use.
+		 */
+		static ScriptCodePtr _createPtr(const WString& data);
+	private:
+		ScriptCode(const WString& data);
+
+		WString mString;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class ScriptCodeRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+	};
+}

+ 28 - 0
BansheeEngine/Include/BsScriptCodeImporter.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsSpecificImporter.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Imports C# script source code files (.cs).
+	 */
+	class BS_EXPORT ScriptCodeImporter : public SpecificImporter
+	{
+	public:
+		ScriptCodeImporter();
+		virtual ~ScriptCodeImporter();
+
+		/** @copydoc SpecificImporter::isExtensionSupported */
+		virtual bool isExtensionSupported(const WString& ext) const;
+
+		/** @copydoc SpecificImporter::isMagicNumberSupported */
+		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const;
+
+		/** @copydoc SpecificImporter::import */
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
+
+		static const WString DEFAULT_EXTENSION;
+	};
+}

+ 36 - 0
BansheeEngine/Include/BsScriptCodeRTTI.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsScriptCode.h"
+
+namespace BansheeEngine
+{
+	class BS_EXPORT ScriptCodeRTTI : public RTTIType <ScriptCode, Resource, ScriptCodeRTTI>
+	{
+	private:
+		WString& getString(ScriptCode* obj) { return obj->mString; }
+		void setString(ScriptCode* obj, WString& val) { obj->mString = val; }
+	public:
+		ScriptCodeRTTI()
+		{
+			addPlainField("mString", 0, &ScriptCodeRTTI::getString, &ScriptCodeRTTI::setString);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "ScriptCode";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_ScriptCode;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return ScriptCode::_createPtr(L""); // Initial string doesn't matter, it'll get overwritten
+		}
+	};
+}

+ 37 - 0
BansheeEngine/Source/BsPlainText.cpp

@@ -0,0 +1,37 @@
+#include "BsPlainText.h"
+#include "BsResources.h"
+#include "BsPlainTextRTTI.h"
+
+namespace BansheeEngine
+{
+	PlainText::PlainText(const WString& data)
+		:Resource(false), mString(data)
+	{
+
+	}
+
+	HPlainText PlainText::create(const WString& data)
+	{
+		return static_resource_cast<PlainText>(gResources()._createResourceHandle(_createPtr(data)));
+	}
+
+	PlainTextPtr PlainText::_createPtr(const WString& data)
+	{
+		PlainTextPtr plainTextPtr = bs_core_ptr<PlainText, PoolAlloc>(
+			new (bs_alloc<PlainText, PoolAlloc>()) PlainText(data));
+		plainTextPtr->_setThisPtr(plainTextPtr);
+		plainTextPtr->initialize();
+
+		return plainTextPtr;
+	}
+
+	RTTITypeBase* PlainText::getRTTIStatic()
+	{
+		return PlainTextRTTI::instance();
+	}
+
+	RTTITypeBase* PlainText::getRTTI() const
+	{
+		return PlainText::getRTTIStatic();
+	}
+}

+ 45 - 0
BansheeEngine/Source/BsPlainTextImporter.cpp

@@ -0,0 +1,45 @@
+#include "BsPlainTextImporter.h"
+#include "BsPlainText.h"
+#include "BsPath.h"
+#include "BsDataStream.h"
+#include "BsFileSystem.h"
+
+namespace BansheeEngine
+{
+	PlainTextImporter::PlainTextImporter()
+		:SpecificImporter()
+	{
+
+	}
+
+	PlainTextImporter::~PlainTextImporter()
+	{
+
+	}
+
+	bool PlainTextImporter::isExtensionSupported(const WString& ext) const
+	{
+		WString lowerCaseExt = ext;
+		StringUtil::toLowerCase(lowerCaseExt);
+
+		return lowerCaseExt == L"txt" || lowerCaseExt == L"xml" || lowerCaseExt == L"json";
+	}
+
+	bool PlainTextImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
+	{
+		return true; // Plain-text so we don't even check for magic number
+	}
+
+	ResourcePtr PlainTextImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
+	{
+		DataStreamPtr stream = FileSystem::openFile(filePath);
+		WString textData = stream->getAsWString();
+
+		PlainTextPtr plainText = PlainText::_createPtr(textData);
+
+		WString fileName = filePath.getWFilename(false);
+		plainText->setName(fileName);
+
+		return plainText;
+	}
+}

+ 37 - 0
BansheeEngine/Source/BsScriptCode.cpp

@@ -0,0 +1,37 @@
+#include "BsScriptCode.h"
+#include "BsResources.h"
+#include "BsScriptCodeRTTI.h"
+
+namespace BansheeEngine
+{
+	ScriptCode::ScriptCode(const WString& data)
+		:Resource(false), mString(data)
+	{
+
+	}
+
+	HScriptCode ScriptCode::create(const WString& data)
+	{
+		return static_resource_cast<ScriptCode>(gResources()._createResourceHandle(_createPtr(data)));
+	}
+
+	ScriptCodePtr ScriptCode::_createPtr(const WString& data)
+	{
+		ScriptCodePtr scriptCodePtr = bs_core_ptr<ScriptCode, PoolAlloc>(
+			new (bs_alloc<ScriptCode, PoolAlloc>()) ScriptCode(data));
+		scriptCodePtr->_setThisPtr(scriptCodePtr);
+		scriptCodePtr->initialize();
+
+		return scriptCodePtr;
+	}
+
+	RTTITypeBase* ScriptCode::getRTTIStatic()
+	{
+		return ScriptCodeRTTI::instance();
+	}
+
+	RTTITypeBase* ScriptCode::getRTTI() const
+	{
+		return ScriptCode::getRTTIStatic();
+	}
+}

+ 45 - 0
BansheeEngine/Source/BsScriptCodeImporter.cpp

@@ -0,0 +1,45 @@
+#include "BsScriptCodeImporter.h"
+#include "BsScriptCode.h"
+#include "BsPath.h"
+#include "BsDataStream.h"
+#include "BsFileSystem.h"
+
+namespace BansheeEngine
+{
+	ScriptCodeImporter::ScriptCodeImporter()
+		:SpecificImporter()
+	{
+
+	}
+
+	ScriptCodeImporter::~ScriptCodeImporter()
+	{
+
+	}
+
+	bool ScriptCodeImporter::isExtensionSupported(const WString& ext) const
+	{
+		WString lowerCaseExt = ext;
+		StringUtil::toLowerCase(lowerCaseExt);
+
+		return lowerCaseExt == L"cs";
+	}
+
+	bool ScriptCodeImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
+	{
+		return true; // Plain-text so we don't even check for magic number
+	}
+
+	ResourcePtr ScriptCodeImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
+	{
+		DataStreamPtr stream = FileSystem::openFile(filePath);
+		WString textData = stream->getAsWString();
+
+		ScriptCodePtr scriptCode = ScriptCode::_createPtr(textData);
+
+		WString fileName = filePath.getWFilename(false);
+		scriptCode->setName(fileName);
+
+		return scriptCode;
+	}
+}

+ 3 - 0
BansheeUtility/BansheeUtility.vcxproj

@@ -270,6 +270,7 @@
     <ClCompile Include="Source\BsPath.cpp" />
     <ClCompile Include="Source\BsRect2.cpp" />
     <ClCompile Include="Source\BsTorus.cpp" />
+    <ClCompile Include="Source\BsUtil.cpp" />
     <ClCompile Include="Source\BsVector2I.cpp" />
     <ClCompile Include="Source\BsManagedDataBlock.cpp" />
     <ClCompile Include="Source\BsMemoryAllocator.cpp" />
@@ -280,6 +281,7 @@
     <ClCompile Include="Source\BsSphere.cpp" />
     <ClCompile Include="Source\BsStringTable.cpp" />
     <ClCompile Include="Source\BsTexAtlasGenerator.cpp" />
+    <ClCompile Include="Source\ThirdParty\md5.cpp" />
     <ClCompile Include="Source\Win32\BsFileSystem.cpp" />
     <ClCompile Include="Source\Win32\BsTimer.cpp" />
     <ClInclude Include="Include\BsAny.h" />
@@ -363,6 +365,7 @@
     <ClCompile Include="Source\BsRTTIType.cpp" />
     <ClInclude Include="Include\BsTexAtlasGenerator.h" />
     <ClCompile Include="Source\BsHString.cpp" />
+    <ClInclude Include="Include\ThirdParty\md5.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsColor.cpp" />

+ 15 - 0
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -45,6 +45,12 @@
     <Filter Include="Header Files\Localization">
       <UniqueIdentifier>{bbd99250-46cb-4299-bbfa-34addc87b878}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\ThirdParty">
+      <UniqueIdentifier>{e0b74f43-dbb4-4e2a-8000-6d9f29dda203}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\ThirdParty">
+      <UniqueIdentifier>{8087a3d9-e6ce-4730-9dd6-7550c08cbd3f}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Include\BsThreadPool.h">
@@ -272,6 +278,9 @@
     <ClInclude Include="Include\BsStringFormat.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\ThirdParty\md5.h">
+      <Filter>Header Files\ThirdParty</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsThreadPool.cpp">
@@ -436,5 +445,11 @@
     <ClCompile Include="Source\BsMessageHandler.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\ThirdParty\md5.cpp">
+      <Filter>Source Files\ThirdParty</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsUtil.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 9 - 0
BansheeUtility/Include/BsString.h

@@ -185,6 +185,15 @@ namespace BansheeEngine
          */
 		static const WString replaceAll(const WString& source, const WString& replaceWhat, const WString& replaceWithWhat);
 
+		/**
+		 * @copydoc	StringFormat::format
+		 */
+		template<class T, class... Args>
+		static BasicString<T> format(const BasicString<T>& source, Args&& ...args)
+		{
+			return StringFormat::format(source.c_str(), std::forward<Args>(args)...);
+		}
+
 		/**
 		 * @copydoc	StringFormat::format
 		 */

+ 38 - 2
BansheeUtility/Include/BsStringFormat.h

@@ -181,6 +181,42 @@ namespace BansheeEngine
 			return (UINT32)wcstoul(buffer, nullptr, 10);
 		}
 
+		/**
+		 * @brief	Helper method for converting any data type to a narrow string.
+		 */
+		template<class T> static std::string toString(const T&& param) { return std::to_string(param); }
+
+		/**
+		 * @brief	Helper method that "converts" a narrow string to a narrow string (simply a pass through)
+		 */
+		template<> static std::string toString<std::string>(const std::string&& param) { return param; }
+
+		/**
+		 * @brief	Helper method that converts a Banshee narrow string to a standard narrow string.
+		 */
+		template<> static std::string toString<String>(const String&& param)
+		{
+			return std::string(param.c_str());
+		}
+
+		/**
+		 * @brief	Helper method for converting any data type to a wide string.
+		 */
+		template<class T> static std::wstring toWString(const T&& param) { return std::to_wstring(param); }
+
+		/**
+		 * @brief	Helper method that "converts" a wide string to a wide string (simply a pass through)
+		 */
+		template<> static std::wstring toWString<std::wstring>(const std::wstring&& param) { return param; }
+
+		/**
+		 * @brief	Helper method that converts a Banshee wide string to a standard wide string.
+		 */
+		template<> static std::wstring toWString<WString>(const WString&& param)
+		{
+			return std::wstring(param.c_str());
+		}
+
 		/**
 		 * @brief	Converts all the provided parameters into string representations and populates the provided
 		 *			"parameter" array.
@@ -191,7 +227,7 @@ namespace BansheeEngine
 			if (idx >= MAX_PARAMS)
 				return;
 
-			std::basic_string<char> sourceParam = std::to_string(param);
+			std::basic_string<char> sourceParam = toString(param);
 			parameters[idx].buffer = (char*)bs_alloc(sourceParam.size() * sizeof(char));
 			parameters[idx].size = (UINT32)sourceParam.size();
 
@@ -210,7 +246,7 @@ namespace BansheeEngine
 			if (idx >= MAX_PARAMS)
 				return;
 
-			std::basic_string<wchar_t> sourceParam = std::to_wstring(param);
+			std::basic_string<wchar_t> sourceParam = toWString(param);
 			parameters[idx].buffer = (wchar_t*)bs_alloc(sourceParam.size() * sizeof(wchar_t));
 			parameters[idx].size = (UINT32)sourceParam.size();
 			

+ 10 - 0
BansheeUtility/Include/BsUtil.h

@@ -14,4 +14,14 @@ namespace BansheeEngine
 		std::hash<T> hasher;
 		seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
 	}
+
+	/**
+	 * @brief	Generates an MD5 hash string for the provided source string.
+	 */
+	String md5(const WString& source);
+
+	/**
+	 * @brief	Generates an MD5 hash string for the provided source string.
+	 */
+	String md5(const String& source);
 }

+ 96 - 0
BansheeUtility/Include/ThirdParty/md5.h

@@ -0,0 +1,96 @@
+/* MD5
+Slightly modified version for the purposes of Banshee Engine by Marko Pintera.
+
+converted to C++ class by Frank Thilo ([email protected])
+for bzflag (http://www.bzflag.org)
+
+based on:
+
+md5.h and md5.c
+reference implementation of RFC 1321
+
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#ifndef BZF_MD5_H
+#define BZF_MD5_H
+
+#include <cstring>
+#include <iostream>
+
+
+// a small class for calculating MD5 hashes of strings or byte arrays
+// it is not meant to be fast or secure
+//
+// usage: 1) feed it blocks of uchars with update()
+//      2) finalize()
+//      3) get hexdigest() string
+//      or
+//      MD5(std::string).hexdigest()
+//
+// assumes that char is 8 bit and int is 32 bit
+class MD5
+{
+public:
+	typedef unsigned int size_type; // must be 32bit
+
+	MD5();
+	MD5(const std::string& text);
+	void update(const unsigned char *buf, size_type length);
+	void update(const char *buf, size_type length);
+	MD5& finalize();
+	std::string hexdigest() const;
+	void decdigest(unsigned char* buf, size_type length);
+	friend std::ostream& operator<<(std::ostream&, MD5 md5);
+
+private:
+	void init();
+	typedef unsigned char uint1; //  8bit
+	typedef unsigned int uint4;  // 32bit
+	enum { blocksize = 64 }; // VC6 won't eat a const static int here
+
+	void transform(const uint1 block[blocksize]);
+	static void decode(uint4 output[], const uint1 input[], size_type len);
+	static void encode(uint1 output[], const uint4 input[], size_type len);
+
+	bool finalized;
+	uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
+	uint4 count[2];   // 64bit counter for number of bits (lo, hi)
+	uint4 state[4];   // digest so far
+	uint1 digest[16]; // the result
+
+	// low level logic operations
+	static inline uint4 F(uint4 x, uint4 y, uint4 z);
+	static inline uint4 G(uint4 x, uint4 y, uint4 z);
+	static inline uint4 H(uint4 x, uint4 y, uint4 z);
+	static inline uint4 I(uint4 x, uint4 y, uint4 z);
+	static inline uint4 rotate_left(uint4 x, int n);
+	static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+	static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+	static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+	static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
+};
+
+std::string md5(const std::string str);
+
+#endif

+ 35 - 0
BansheeUtility/Source/BsUtil.cpp

@@ -0,0 +1,35 @@
+#include "BsUtil.h"
+#include "ThirdParty/md5.h"
+
+namespace BansheeEngine
+{
+	String md5(const WString& source)
+	{
+		MD5 md5;
+		md5.update((UINT8*)source.c_str(), (UINT32)source.length());
+		md5.finalize();
+
+		UINT8* digest = (UINT8*)bs_alloc(16);
+		md5.decdigest(digest, 16);
+
+		String output((char*)digest);
+		bs_free(digest);
+
+		return output;
+	}
+
+	String md5(const String& source)
+	{
+		MD5 md5;
+		md5.update((UINT8*)source.c_str(), (UINT32)source.length());
+		md5.finalize();
+
+		UINT8* digest = (UINT8*)bs_alloc(16);
+		md5.decdigest(digest, 16);
+
+		String output((char*)digest);
+		bs_free(digest);
+
+		return output;
+	}
+}

+ 371 - 0
BansheeUtility/Source/ThirdParty/md5.cpp

@@ -0,0 +1,371 @@
+/* MD5
+converted to C++ class by Frank Thilo ([email protected])
+for bzflag (http://www.bzflag.org)
+
+based on:
+
+md5.h and md5.c
+reference implemantion of RFC 1321
+
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+/* interface header */
+#include "ThirdParty/md5.h"
+
+/* system implementation headers */
+#include <cstdio>
+#include <assert.h>
+
+
+// Constants for MD5Transform routine.
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+///////////////////////////////////////////////
+
+// F, G, H and I are basic MD5 functions.
+inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
+	return x&y | ~x&z;
+}
+
+inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
+	return x&z | y&~z;
+}
+
+inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
+	return x^y^z;
+}
+
+inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
+	return y ^ (x | ~z);
+}
+
+// rotate_left rotates x left n bits.
+inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
+	return (x << n) | (x >> (32 - n));
+}
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+	a = rotate_left(a + F(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+	a = rotate_left(a + G(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+	a = rotate_left(a + H(b, c, d) + x + ac, s) + b;
+}
+
+inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
+	a = rotate_left(a + I(b, c, d) + x + ac, s) + b;
+}
+
+//////////////////////////////////////////////
+
+// default ctor, just initailize
+MD5::MD5()
+{
+	init();
+}
+
+//////////////////////////////////////////////
+
+// nifty shortcut ctor, compute MD5 for string and finalize it right away
+MD5::MD5(const std::string &text)
+{
+	init();
+	update(text.c_str(), text.length());
+	finalize();
+}
+
+//////////////////////////////
+
+void MD5::init()
+{
+	finalized = false;
+
+	count[0] = 0;
+	count[1] = 0;
+
+	// load magic initialization constants.
+	state[0] = 0x67452301;
+	state[1] = 0xefcdab89;
+	state[2] = 0x98badcfe;
+	state[3] = 0x10325476;
+}
+
+//////////////////////////////
+
+// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
+void MD5::decode(uint4 output[], const uint1 input[], size_type len)
+{
+	for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
+		output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) |
+		(((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24);
+}
+
+//////////////////////////////
+
+// encodes input (uint4) into output (unsigned char). Assumes len is
+// a multiple of 4.
+void MD5::encode(uint1 output[], const uint4 input[], size_type len)
+{
+	for (size_type i = 0, j = 0; j < len; i++, j += 4) {
+		output[j] = input[i] & 0xff;
+		output[j + 1] = (input[i] >> 8) & 0xff;
+		output[j + 2] = (input[i] >> 16) & 0xff;
+		output[j + 3] = (input[i] >> 24) & 0xff;
+	}
+}
+
+//////////////////////////////
+
+// apply MD5 algo on a block
+void MD5::transform(const uint1 block[blocksize])
+{
+	uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+	decode(x, block, blocksize);
+
+	/* Round 1 */
+	FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+	FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+	FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+	FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+	FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+	FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+	FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+	FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+	FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+	FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+	FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+	FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+	FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+	FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+	FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+	FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+	/* Round 2 */
+	GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+	GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+	GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+	GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+	GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+	GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+	GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+	GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+	GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+	GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+	GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+	GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+	GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+	GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+	GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+	GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+	/* Round 3 */
+	HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+	HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+	HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+	HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+	HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+	HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+	HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+	HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+	HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+	HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+	HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+	HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+	HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+	HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+	HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+	HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+	/* Round 4 */
+	II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+	II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+	II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+	II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+	II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+	II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+	II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+	II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+	II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+	II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+	II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+	II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+	II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+	II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+	II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+	II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+
+	// Zeroize sensitive information.
+	memset(x, 0, sizeof x);
+}
+
+//////////////////////////////
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block
+void MD5::update(const unsigned char input[], size_type length)
+{
+	// compute number of bytes mod 64
+	size_type index = count[0] / 8 % blocksize;
+
+	// Update number of bits
+	if ((count[0] += (length << 3)) < (length << 3))
+		count[1]++;
+	count[1] += (length >> 29);
+
+	// number of bytes we need to fill in buffer
+	size_type firstpart = 64 - index;
+
+	size_type i;
+
+	// transform as many times as possible.
+	if (length >= firstpart)
+	{
+		// fill buffer first, transform
+		memcpy(&buffer[index], input, firstpart);
+		transform(buffer);
+
+		// transform chunks of blocksize (64 bytes)
+		for (i = firstpart; i + blocksize <= length; i += blocksize)
+			transform(&input[i]);
+
+		index = 0;
+	}
+	else
+		i = 0;
+
+	// buffer remaining input
+	memcpy(&buffer[index], &input[i], length - i);
+}
+
+//////////////////////////////
+
+// for convenience provide a verson with signed char
+void MD5::update(const char input[], size_type length)
+{
+	update((const unsigned char*)input, length);
+}
+
+//////////////////////////////
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+MD5& MD5::finalize()
+{
+	static unsigned char padding[64] = {
+		0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+
+	if (!finalized) {
+		// Save number of bits
+		unsigned char bits[8];
+		encode(bits, count, 8);
+
+		// pad out to 56 mod 64.
+		size_type index = count[0] / 8 % 64;
+		size_type padLen = (index < 56) ? (56 - index) : (120 - index);
+		update(padding, padLen);
+
+		// Append length (before padding)
+		update(bits, 8);
+
+		// Store state in digest
+		encode(digest, state, 16);
+
+		// Zeroize sensitive information.
+		memset(buffer, 0, sizeof buffer);
+		memset(count, 0, sizeof count);
+
+		finalized = true;
+	}
+
+	return *this;
+}
+
+//////////////////////////////
+
+// return hex representation of digest as string
+std::string MD5::hexdigest() const
+{
+	if (!finalized)
+		return "";
+
+	char buf[33];
+	for (int i = 0; i<16; i++)
+		sprintf(buf + i * 2, "%02x", digest[i]);
+	buf[32] = 0;
+
+	return std::string(buf);
+}
+
+// return a copy of the digest in the provided buffer
+void MD5::decdigest(unsigned char* buf, size_type length)
+{
+	assert(length == 16);
+
+	memcpy(buf, digest, length);
+}
+
+//////////////////////////////
+
+std::ostream& operator<<(std::ostream& out, MD5 md5)
+{
+	return out << md5.hexdigest();
+}
+
+//////////////////////////////
+
+std::string md5(const std::string str)
+{
+	MD5 md5 = MD5(str);
+
+	return md5.hexdigest();
+}

+ 22 - 0
TODO.txt

@@ -38,6 +38,27 @@ Open visual studio at a specific file/line
      - Use normal shell command?
       - devenv /edit FILE_PATH /command "edit.goto FILE_LINE"
 
+CodeEditorManager
+ - sync()
+ - finds all code and non-code script files using ProjectLibrary
+ - sets up references to the two default BansheeEngine and BansheeEditor assemblies (read from EditorApplication or somewhere?)
+    - their paths need to be retrieved as well. Perhaps EditorApplication::getBuiltinAssemblyPath()
+    - this should be working dir/../../Assemblies (but passed as an absolute path)
+ - sets up references to the two generated assemblies
+    - this should be project dir (EditorApplication::getProjectPath())/Internal/Assemblies
+    - They're names also need to be hardcoded somewhere. ScriptEngine, ScriptEditor
+
+code:
+.cs
+
+text:
+.gpuprog
+.gpuinc
+.txt
+.xml
+.json
+
+
 None of the new VS functionality has been tested
 
 ----------------------------------------------------------------------
@@ -93,6 +114,7 @@ Other simple stuff:
  - VS integration (open VS project on doubleclick, generate project files, open on specific line)
  - C# wrapper for GUISkin (and a way to assign the current skin to a window)
  - Need to add IsPointerDoubleClicked to Input (C++ and C#)
+ - Move all the code files into subfolders so their hierarchy is similar to VS filters
 
 ----------------------------------------------------------------------
 Handles